summaryrefslogtreecommitdiff
path: root/pyasn1/codec/der/decoder.py
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2019-09-14 18:46:08 +0200
committerIlya Etingof <etingof@gmail.com>2019-11-15 19:39:11 +0100
commit93e11a2dfded950827ba3393b5a4562270a766da (patch)
treecddf49a1daa1258d91f348bad30eabc662241bd8 /pyasn1/codec/der/decoder.py
parentfdd0bd66f66e5f7832287ff0994f4219632935a7 (diff)
downloadpyasn1-git-93e11a2dfded950827ba3393b5a4562270a766da.tar.gz
Refactor BER decoder into a suspendable coroutine
The goal of this change is to make the decoder stopping on input data starvation and resuming from where it stopped whenever the caller decides to try again (hopefully making sure that some more input becomes available). This change makes it possible for the decoder to operate on streams of data (meaning that the entire DER blob might not be immediately available on input). On top of that, the decoder yields partially reconstructed ASN.1 object on input starvation making it possible for the caller to inspect what has been decoded so far and possibly consume partial ASN.1 data. All these new feature are natively available through `StreamingDecoder` class. Previously published API is implemented as a thin wrapper on top of that ensuring backward compatibility.
Diffstat (limited to 'pyasn1/codec/der/decoder.py')
-rw-r--r--pyasn1/codec/der/decoder.py63
1 files changed, 29 insertions, 34 deletions
diff --git a/pyasn1/codec/der/decoder.py b/pyasn1/codec/der/decoder.py
index e339970..b9526c3 100644
--- a/pyasn1/codec/der/decoder.py
+++ b/pyasn1/codec/der/decoder.py
@@ -4,59 +4,59 @@
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
-from io import BytesIO
-
-from pyasn1.codec.ber.decoder import _asSeekableStream
from pyasn1.codec.cer import decoder
from pyasn1.type import univ
-__all__ = ['decode', 'decodeStream']
+__all__ = ['decode', 'StreamingDecoder']
-class BitStringDecoder(decoder.BitStringDecoder):
+class BitStringPayloadDecoder(decoder.BitStringPayloadDecoder):
supportConstructedForm = False
-class OctetStringDecoder(decoder.OctetStringDecoder):
+class OctetStringPayloadDecoder(decoder.OctetStringPayloadDecoder):
supportConstructedForm = False
+
# TODO: prohibit non-canonical encoding
-RealDecoder = decoder.RealDecoder
+RealPayloadDecoder = decoder.RealPayloadDecoder
-tagMap = decoder.tagMap.copy()
-tagMap.update(
- {univ.BitString.tagSet: BitStringDecoder(),
- univ.OctetString.tagSet: OctetStringDecoder(),
- univ.Real.tagSet: RealDecoder()}
+TAG_MAP = decoder.TAG_MAP.copy()
+TAG_MAP.update(
+ {univ.BitString.tagSet: BitStringPayloadDecoder(),
+ univ.OctetString.tagSet: OctetStringPayloadDecoder(),
+ univ.Real.tagSet: RealPayloadDecoder()}
)
-typeMap = decoder.typeMap.copy()
+TYPE_MAP = decoder.TYPE_MAP.copy()
# Put in non-ambiguous types for faster codec lookup
-for typeDecoder in tagMap.values():
+for typeDecoder in TAG_MAP.values():
if typeDecoder.protoComponent is not None:
typeId = typeDecoder.protoComponent.__class__.typeId
- if typeId is not None and typeId not in typeMap:
- typeMap[typeId] = typeDecoder
+ if typeId is not None and typeId not in TYPE_MAP:
+ TYPE_MAP[typeId] = typeDecoder
-class Decoder(decoder.Decoder):
+class SingleItemDecoder(decoder.SingleItemDecoder):
+ __doc__ = decoder.SingleItemDecoder.__doc__
+
+ TAG_MAP = TAG_MAP
+ TYPE_MAP = TYPE_MAP
+
supportIndefLength = False
-_decode = Decoder(tagMap, decoder.typeMap)
+class StreamingDecoder(decoder.StreamingDecoder):
+ __doc__ = decoder.StreamingDecoder.__doc__
+
+ SINGLE_ITEM_DECODER = SingleItemDecoder
-def decodeStream(substrate, asn1Spec=None, **kwargs):
- """Iterator of objects in a substrate."""
- # TODO: This should become `decode` after API-breaking approved
- substrate = _asSeekableStream(substrate)
- while True:
- result = _decode(substrate, asn1Spec, **kwargs)
- if result is None:
- break
- yield result
- # TODO: Check about eoo.endOfOctets?
+class Decoder(decoder.Decoder):
+ __doc__ = decoder.Decoder.__doc__
+
+ STREAMING_DECODER = StreamingDecoder
#: Turns DER octet stream into an ASN.1 object.
@@ -109,9 +109,4 @@ def decodeStream(substrate, asn1Spec=None, **kwargs):
#: SequenceOf:
#: 1 2 3
#:
-def decode(substrate, asn1Spec=None, **kwargs):
- # TODO: Temporary solution before merging with upstream
- # It preserves the original API
- substrate = _asSeekableStream(substrate)
- value = _decode(substrate, asn1Spec=asn1Spec, **kwargs)
- return value, substrate.read() \ No newline at end of file
+decode = Decoder()