diff options
Diffstat (limited to 'pyasn1/codec/der/encoder.py')
-rw-r--r-- | pyasn1/codec/der/encoder.py | 79 |
1 files changed, 62 insertions, 17 deletions
diff --git a/pyasn1/codec/der/encoder.py b/pyasn1/codec/der/encoder.py index d2992a9..c23b49f 100644 --- a/pyasn1/codec/der/encoder.py +++ b/pyasn1/codec/der/encoder.py @@ -2,31 +2,56 @@ # This file is part of pyasn1 software. # # Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com> -# License: http://pyasn1.sf.net/license.html +# License: http://snmplabs.com/pyasn1/license.html # from pyasn1.type import univ from pyasn1.codec.cer import encoder +from pyasn1 import error __all__ = ['encode'] -class SetOfEncoder(encoder.SetOfEncoder): +class SetEncoder(encoder.SetEncoder): @staticmethod - def _sortComponents(components): - # sort by tags depending on the actual Choice value (dynamic sort) - return sorted(components, key=lambda x: isinstance(x, univ.Choice) and x.getComponent().tagSet or x.tagSet) + def _componentSortKey(componentAndType): + """Sort SET components by tag + + Sort depending on the actual Choice value (dynamic sort) + """ + component, asn1Spec = componentAndType + + if asn1Spec is None: + compType = component + else: + compType = asn1Spec + + if compType.typeId == univ.Choice.typeId and not compType.tagSet: + if asn1Spec is None: + return component.getComponent().tagSet + else: + # TODO: move out of sorting key function + names = [namedType.name for namedType in asn1Spec.componentType.namedTypes + if namedType.name in component] + if len(names) != 1: + raise error.PyAsn1Error( + '%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', component)) + + # TODO: support nested CHOICE ordering + return asn1Spec[names[0]].tagSet + + else: + return compType.tagSet tagMap = encoder.tagMap.copy() tagMap.update({ # Set & SetOf have same tags - univ.SetOf.tagSet: SetOfEncoder() + univ.Set.tagSet: SetEncoder() }) typeMap = encoder.typeMap.copy() typeMap.update({ # Set & SetOf have same tags - univ.Set.typeId: SetOfEncoder(), - univ.SetOf.typeId: SetOfEncoder() + univ.Set.typeId: SetEncoder() }) @@ -41,22 +66,42 @@ class Encoder(encoder.Encoder): #: #: Parameters #: ---------- -# value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) -#: A pyasn1 object to encode -#: -#: defMode: :py:class:`bool` -#: If `False`, produces indefinite length encoding +#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) +#: A Python or pyasn1 object to encode. If Python object is given, `asnSpec` +#: parameter is required to guide the encoding process. #: -#: maxChunkSize: :py:class:`int` -#: Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size) +#: Keyword Args +#: ------------ +#: asn1Spec: +#: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative #: #: Returns #: ------- #: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) -#: Given ASN.1 object encoded into BER octetstream +#: Given ASN.1 object encoded into BER octet-stream #: #: Raises #: ------ -#: : :py:class:`pyasn1.error.PyAsn1Error` +#: :py:class:`~pyasn1.error.PyAsn1Error` #: On encoding errors +#: +#: Examples +#: -------- +#: Encode Python value into DER with ASN.1 schema +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> encode([1, 2, 3], asn1Spec=seq) +#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' +#: +#: Encode ASN.1 value object into DER +#: +#: .. code-block:: pycon +#: +#: >>> seq = SequenceOf(componentType=Integer()) +#: >>> seq.extend([1, 2, 3]) +#: >>> encode(seq) +#: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' +#: encode = Encoder(tagMap, typeMap) |