diff options
author | Ilya Etingof <etingof@gmail.com> | 2019-07-06 14:04:53 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-07-06 14:04:53 +0200 |
commit | b5e2eebe53736eb96f3baf5c17ae953261e09d6c (patch) | |
tree | dac2f96248bee477ef0a25a67fb34090bd1eca65 /pyasn1/codec/ber/encoder.py | |
parent | ba302699d8fc791760829aa9a6b014563eedbf2c (diff) | |
download | pyasn1-b5e2eebe53736eb96f3baf5c17ae953261e09d6c.tar.gz |
Add `SET|SEQUENCE OF ANY` encoding support (#165)
For example:
AttributeTypeAndValues ::= SEQUENCE {
type OBJECT IDENTIFIER,
values SET OF ANY DEFINED BY type
}
This patch adds support of the above ASN.1 syntax to BER/DER/CER
codecs.
It appears that to implement this feature properly, `SetOf`/`SequenceOf`
pyasn1 types need to have `.componentType` wrapped into something
similar to `NamedType` that `Set`/`Sequence` have. That additional
layer would then carry the open type meta information. Without it,
`Sequence`/`Set` codec needs to signal `SetOf`/`SequenceOf` codec
of the open type being processed, which is a slight hack.
A other inconvenience is that when `SetOf`/`SequenceOf` deal with
an open type component, they should not verify types on component
assignment. Without open type property in `SetOf`/`SequenceOf`,
the code checks for `Any` component type which is another hack.
The above shortcomings should be addressed in the follow up patch.
Diffstat (limited to 'pyasn1/codec/ber/encoder.py')
-rw-r--r-- | pyasn1/codec/ber/encoder.py | 88 |
1 files changed, 68 insertions, 20 deletions
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py index 325ed46..b17fca8 100644 --- a/pyasn1/codec/ber/encoder.py +++ b/pyasn1/codec/ber/encoder.py @@ -89,6 +89,8 @@ class AbstractItemEncoder(object): defMode = options.get('defMode', True) + substrate = null + for idx, singleTag in enumerate(tagSet.superTags): defModeOverride = defMode @@ -556,18 +558,32 @@ class SequenceEncoder(AbstractItemEncoder): if omitEmptyOptionals: options.update(ifNotEmpty=namedType.isOptional) - chunk = encodeFun(component, asn1Spec, **options) - # wrap open type blob if needed - if namedTypes and namedType.openType: - wrapType = namedType.asn1Object - if wrapType.tagSet and not wrapType.isSameTypeWith(component): - chunk = encodeFun(chunk, wrapType, **options) + if (namedTypes and namedType.openType + and namedType.asn1Object.tagSet): - if LOG: - LOG('wrapped open type with wrap type %r' % (wrapType,)) + if component.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + substrate += encodeFun( + component, asn1Spec, + **dict(options, openType=True)) + + else: + chunk = encodeFun(component, asn1Spec, **options) + + wrapType = namedType.asn1Object - substrate += chunk + if wrapType.isSameTypeWith(component): + substrate += chunk + + else: + substrate += encodeFun(chunk, wrapType, **options) + + if LOG: + LOG('wrapped with wrap type %r' % (wrapType,)) + + else: + substrate += encodeFun(component, asn1Spec, **options) else: # bare Python value + ASN.1 schema @@ -593,18 +609,31 @@ class SequenceEncoder(AbstractItemEncoder): if omitEmptyOptionals: options.update(ifNotEmpty=namedType.isOptional) - chunk = encodeFun(component, asn1Spec[idx], **options) - # wrap open type blob if needed - if namedType.openType: - wrapType = namedType.asn1Object - if wrapType.tagSet and not wrapType.isSameTypeWith(component): - chunk = encodeFun(chunk, wrapType, **options) + if namedType.openType and namedType.asn1Object.tagSet: - if LOG: - LOG('wrapped open type with wrap type %r' % (wrapType,)) + if component.typeId in ( + univ.SetOf.typeId, univ.SequenceOf.typeId): + substrate += encodeFun( + component, asn1Spec[idx], + **dict(options, openType=True)) + + else: + chunk = encodeFun(component, asn1Spec[idx], **options) + + wrapType = namedType.asn1Object - substrate += chunk + if wrapType.isSameTypeWith(component): + substrate += chunk + + else: + substrate += encodeFun(chunk, wrapType, **options) + + if LOG: + LOG('wrapped with wrap type %r' % (wrapType,)) + + else: + substrate += encodeFun(component, asn1Spec[idx], **options) return substrate, True, True @@ -613,13 +642,32 @@ class SequenceOfEncoder(AbstractItemEncoder): def encodeValue(self, value, asn1Spec, encodeFun, **options): if asn1Spec is None: value.verifySizeSpec() + + wrapType = value.componentType + else: - asn1Spec = asn1Spec.componentType + asn1Spec = wrapType = asn1Spec.componentType + + openType = options.pop('openType', False) substrate = null for idx, component in enumerate(value): - substrate += encodeFun(value[idx], asn1Spec, **options) + if openType: + # do not use asn1Spec even if given because it's a wrapper + chunk = encodeFun(component, **options) + + if not wrapType.isSameTypeWith(component): + # wrap encoded value with wrapper container (e.g. ANY) + chunk = encodeFun(chunk, wrapType, **options) + + if LOG: + LOG('wrapped with wrap type %r' % (wrapType,)) + + else: + chunk = encodeFun(component, asn1Spec, **options) + + substrate += chunk return substrate, True, True |