summaryrefslogtreecommitdiff
path: root/pyasn1/codec/der/encoder.py
diff options
context:
space:
mode:
Diffstat (limited to 'pyasn1/codec/der/encoder.py')
-rw-r--r--pyasn1/codec/der/encoder.py79
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)