aboutsummaryrefslogtreecommitdiff
path: root/pyasn1/codec/ber
diff options
context:
space:
mode:
Diffstat (limited to 'pyasn1/codec/ber')
-rw-r--r--pyasn1/codec/ber/decoder.py93
-rw-r--r--pyasn1/codec/ber/encoder.py115
-rw-r--r--pyasn1/codec/ber/eoo.py2
3 files changed, 166 insertions, 44 deletions
diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py
index 591bbc4..3f2d180 100644
--- a/pyasn1/codec/ber/decoder.py
+++ b/pyasn1/codec/ber/decoder.py
@@ -567,6 +567,7 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
return asn1Object, tail
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId):
@@ -670,18 +671,35 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
LOG('resolved open type %r by governing '
'value %r' % (openType, governingValue))
- component, rest = decodeFun(
- asn1Object.getComponentByPosition(idx).asOctets(),
- asn1Spec=openType
- )
+ containerValue = asn1Object.getComponentByPosition(idx)
+
+ if containerValue.typeId in (
+ univ.SetOf.typeId, univ.SequenceOf.typeId):
+
+ for pos, containerElement in enumerate(
+ containerValue):
+
+ component, rest = decodeFun(
+ containerValue[pos].asOctets(),
+ asn1Spec=openType, **options
+ )
- asn1Object.setComponentByPosition(idx, component)
+ containerValue[pos] = component
+
+ else:
+ component, rest = decodeFun(
+ asn1Object.getComponentByPosition(idx).asOctets(),
+ asn1Spec=openType, **options
+ )
+
+ asn1Object.setComponentByPosition(idx, component)
else:
asn1Object.verifySizeSpec()
else:
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
componentType = asn1Spec.componentType
@@ -723,10 +741,12 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
if asn1Spec is None:
return self._decodeComponents(
- substrate, tagSet=tagSet, decodeFun=decodeFun, allowEoo=True, **options
+ substrate, tagSet=tagSet, decodeFun=decodeFun,
+ **dict(options, allowEoo=True)
)
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
if asn1Spec.typeId in (univ.Sequence.typeId, univ.Set.typeId):
@@ -796,7 +816,7 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
if not namedTypes.requiredComponents.issubset(seenIndices):
raise error.PyAsn1Error('ASN.1 object %s has uninitialized components' % asn1Object.__class__.__name__)
- if namedTypes.hasOpenTypes:
+ if namedTypes.hasOpenTypes:
openTypes = options.get('openTypes', {})
@@ -834,19 +854,36 @@ class UniversalConstructedTypeDecoder(AbstractConstructedDecoder):
LOG('resolved open type %r by governing '
'value %r' % (openType, governingValue))
- component, rest = decodeFun(
- asn1Object.getComponentByPosition(idx).asOctets(),
- asn1Spec=openType, allowEoo=True
- )
+ containerValue = asn1Object.getComponentByPosition(idx)
- if component is not eoo.endOfOctets:
- asn1Object.setComponentByPosition(idx, component)
+ if containerValue.typeId in (
+ univ.SetOf.typeId, univ.SequenceOf.typeId):
+
+ for pos, containerElement in enumerate(
+ containerValue):
+
+ component, rest = decodeFun(
+ containerValue[pos].asOctets(),
+ asn1Spec=openType, **dict(options, allowEoo=True)
+ )
+
+ containerValue[pos] = component
+
+ else:
+ component, rest = decodeFun(
+ asn1Object.getComponentByPosition(idx).asOctets(),
+ asn1Spec=openType, **dict(options, allowEoo=True)
+ )
+
+ if component is not eoo.endOfOctets:
+ asn1Object.setComponentByPosition(idx, component)
else:
asn1Object.verifySizeSpec()
else:
asn1Object = asn1Spec.clone()
+ asn1Object.clear()
componentType = asn1Spec.componentType
@@ -1012,7 +1049,16 @@ class AnyDecoder(AbstractSimpleDecoder):
tagSet=None, length=None, state=None,
decodeFun=None, substrateFun=None,
**options):
- if asn1Spec is None or asn1Spec is not None and tagSet != asn1Spec.tagSet:
+ if asn1Spec is None:
+ isUntagged = True
+
+ elif asn1Spec.__class__ is tagmap.TagMap:
+ isUntagged = tagSet not in asn1Spec.tagMap
+
+ else:
+ isUntagged = tagSet != asn1Spec.tagSet
+
+ if isUntagged:
fullSubstrate = options['fullSubstrate']
# untagged Any container, recover inner header substrate
@@ -1034,7 +1080,16 @@ class AnyDecoder(AbstractSimpleDecoder):
tagSet=None, length=None, state=None,
decodeFun=None, substrateFun=None,
**options):
- if asn1Spec is not None and tagSet == asn1Spec.tagSet:
+ if asn1Spec is None:
+ isTagged = False
+
+ elif asn1Spec.__class__ is tagmap.TagMap:
+ isTagged = tagSet in asn1Spec.tagMap
+
+ else:
+ isTagged = tagSet == asn1Spec.tagSet
+
+ if isTagged:
# tagged Any type -- consume header substrate
header = null
@@ -1204,7 +1259,7 @@ for typeDecoder in tagMap.values():
class Decoder(object):
defaultErrorState = stErrorCondition
- # defaultErrorState = stDumpRawValue
+ #defaultErrorState = stDumpRawValue
defaultRawDecoder = AnyDecoder()
supportIndefLength = True
@@ -1505,7 +1560,9 @@ class Decoder(object):
break
if state is stTryAsExplicitTag:
- if tagSet and tagSet[0].tagFormat == tag.tagFormatConstructed and tagSet[0].tagClass != tag.tagClassUniversal:
+ if (tagSet and
+ tagSet[0].tagFormat == tag.tagFormatConstructed and
+ tagSet[0].tagClass != tag.tagClassUniversal):
# Assume explicit tagging
concreteDecoder = explicitTagDecoder
state = stDecodeValue
@@ -1563,7 +1620,7 @@ class Decoder(object):
#:
#: Raises
#: ------
-#: :py:class:`~pyasn1.error.PyAsn1Error`
+#: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError
#: On decoding errors
#:
#: Examples
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py
index 65b8514..a5d5fd3 100644
--- a/pyasn1/codec/ber/encoder.py
+++ b/pyasn1/codec/ber/encoder.py
@@ -4,6 +4,8 @@
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
+import sys
+
from pyasn1 import debug
from pyasn1 import error
from pyasn1.codec.ber import eoo
@@ -87,15 +89,23 @@ class AbstractItemEncoder(object):
defMode = options.get('defMode', True)
+ substrate = null
+
for idx, singleTag in enumerate(tagSet.superTags):
defModeOverride = defMode
# base tag?
if not idx:
- substrate, isConstructed, isOctets = self.encodeValue(
- value, asn1Spec, encodeFun, **options
- )
+ try:
+ substrate, isConstructed, isOctets = self.encodeValue(
+ value, asn1Spec, encodeFun, **options
+ )
+
+ except error.PyAsn1Error:
+ exc = sys.exc_info()
+ raise error.PyAsn1Error(
+ 'Error encoding %r: %s' % (value, exc[1]))
if LOG:
LOG('encoded %svalue %s into %s' % (
@@ -518,6 +528,13 @@ class SequenceEncoder(AbstractItemEncoder):
substrate = null
+ omitEmptyOptionals = options.get(
+ 'omitEmptyOptionals', self.omitEmptyOptionals)
+
+ if LOG:
+ LOG('%sencoding empty OPTIONAL components' % (
+ omitEmptyOptionals and 'not ' or ''))
+
if asn1Spec is None:
# instance of ASN.1 schema
value.verifySizeSpec()
@@ -538,21 +555,35 @@ class SequenceEncoder(AbstractItemEncoder):
LOG('not encoding DEFAULT component %r' % (namedType,))
continue
- if self.omitEmptyOptionals:
+ 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 LOG:
- LOG('wrapped open type with wrap type %r' % (wrapType,))
+ if wrapType.typeId in (
+ univ.SetOf.typeId, univ.SequenceOf.typeId):
+
+ substrate += encodeFun(
+ component, asn1Spec,
+ **dict(options, wrapType=wrapType.componentType))
+
+ else:
+ chunk = encodeFun(component, asn1Spec, **options)
+
+ if wrapType.isSameTypeWith(component):
+ substrate += chunk
- 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
@@ -575,38 +606,72 @@ class SequenceEncoder(AbstractItemEncoder):
LOG('not encoding DEFAULT component %r' % (namedType,))
continue
- if self.omitEmptyOptionals:
+ if omitEmptyOptionals:
options.update(ifNotEmpty=namedType.isOptional)
- chunk = encodeFun(component, asn1Spec[idx], **options)
+ componentSpec = namedType.asn1Object
# 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 LOG:
- LOG('wrapped open type with wrap type %r' % (wrapType,))
+ if componentSpec.typeId in (
+ univ.SetOf.typeId, univ.SequenceOf.typeId):
- substrate += chunk
+ substrate += encodeFun(
+ component, componentSpec,
+ **dict(options, wrapType=componentSpec.componentType))
+
+ else:
+ chunk = encodeFun(component, componentSpec, **options)
+
+ if componentSpec.isSameTypeWith(component):
+ substrate += chunk
+
+ else:
+ substrate += encodeFun(chunk, componentSpec, **options)
+
+ if LOG:
+ LOG('wrapped with wrap type %r' % (componentSpec,))
+
+ else:
+ substrate += encodeFun(component, componentSpec, **options)
return substrate, True, True
class SequenceOfEncoder(AbstractItemEncoder):
- def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ def _encodeComponents(self, value, asn1Spec, encodeFun, **options):
+
if asn1Spec is None:
value.verifySizeSpec()
+
else:
asn1Spec = asn1Spec.componentType
- substrate = null
+ chunks = []
+
+ wrapType = options.pop('wrapType', None)
for idx, component in enumerate(value):
- substrate += encodeFun(value[idx], asn1Spec, **options)
+ chunk = encodeFun(component, asn1Spec, **options)
- return substrate, True, True
+ if (wrapType is not None and
+ 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,))
+
+ chunks.append(chunk)
+
+ return chunks
+
+ def encodeValue(self, value, asn1Spec, encodeFun, **options):
+ chunks = self._encodeComponents(
+ value, asn1Spec, encodeFun, **options)
+
+ return null.join(chunks), True, True
class ChoiceEncoder(AbstractItemEncoder):
@@ -784,7 +849,7 @@ class Encoder(object):
#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
#:
#: defMode: :py:class:`bool`
-#: If `False`, produces indefinite length encoding
+#: If :obj:`False`, produces indefinite length encoding
#:
#: maxChunkSize: :py:class:`int`
#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
@@ -796,7 +861,7 @@ class Encoder(object):
#:
#: Raises
#: ------
-#: :py:class:`~pyasn1.error.PyAsn1Error`
+#: ~pyasn1.error.PyAsn1Error
#: On encoding errors
#:
#: Examples
diff --git a/pyasn1/codec/ber/eoo.py b/pyasn1/codec/ber/eoo.py
index b613b53..48eb859 100644
--- a/pyasn1/codec/ber/eoo.py
+++ b/pyasn1/codec/ber/eoo.py
@@ -10,7 +10,7 @@ from pyasn1.type import tag
__all__ = ['endOfOctets']
-class EndOfOctets(base.AbstractSimpleAsn1Item):
+class EndOfOctets(base.SimpleAsn1Type):
defaultValue = 0
tagSet = tag.initTagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00)