1#
2# This file is part of pyasn1 software.
3#
4# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
5# License: http://snmplabs.com/pyasn1/license.html
6#
7from pyasn1 import debug
8from pyasn1 import error
9from pyasn1.codec.ber import eoo
10from pyasn1.compat.integer import to_bytes
11from pyasn1.compat.octets import (int2oct, oct2int, ints2octs, null,
12                                  str2octs, isOctetsType)
13from pyasn1.type import char
14from pyasn1.type import tag
15from pyasn1.type import univ
16from pyasn1.type import useful
17
18__all__ = ['encode']
19
20
21class AbstractItemEncoder(object):
22    supportIndefLenMode = True
23
24    # An outcome of otherwise legit call `encodeFun(eoo.endOfOctets)`
25    eooIntegerSubstrate = (0, 0)
26    eooOctetsSubstrate = ints2octs(eooIntegerSubstrate)
27
28    # noinspection PyMethodMayBeStatic
29    def encodeTag(self, singleTag, isConstructed):
30        tagClass, tagFormat, tagId = singleTag
31        encodedTag = tagClass | tagFormat
32        if isConstructed:
33            encodedTag |= tag.tagFormatConstructed
34        if tagId < 31:
35            return encodedTag | tagId,
36        else:
37            substrate = tagId & 0x7f,
38            tagId >>= 7
39            while tagId:
40                substrate = (0x80 | (tagId & 0x7f),) + substrate
41                tagId >>= 7
42            return (encodedTag | 0x1F,) + substrate
43
44    def encodeLength(self, length, defMode):
45        if not defMode and self.supportIndefLenMode:
46            return (0x80,)
47        if length < 0x80:
48            return length,
49        else:
50            substrate = ()
51            while length:
52                substrate = (length & 0xff,) + substrate
53                length >>= 8
54            substrateLen = len(substrate)
55            if substrateLen > 126:
56                raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen)
57            return (0x80 | substrateLen,) + substrate
58
59    def encodeValue(self, value, asn1Spec, encodeFun, **options):
60        raise error.PyAsn1Error('Not implemented')
61
62    def encode(self, value, asn1Spec=None, encodeFun=None, **options):
63
64        if asn1Spec is None:
65            tagSet = value.tagSet
66        else:
67            tagSet = asn1Spec.tagSet
68
69        # untagged item?
70        if not tagSet:
71            substrate, isConstructed, isOctets = self.encodeValue(
72                value, asn1Spec, encodeFun, **options
73            )
74            return substrate
75
76        defMode = options.get('defMode', True)
77
78        for idx, singleTag in enumerate(tagSet.superTags):
79
80            defModeOverride = defMode
81
82            # base tag?
83            if not idx:
84                substrate, isConstructed, isOctets = self.encodeValue(
85                    value, asn1Spec, encodeFun, **options
86                )
87
88                if not substrate and isConstructed and options.get('ifNotEmpty', False):
89                    return substrate
90
91                # primitive form implies definite mode
92                if not isConstructed:
93                    defModeOverride = True
94
95            header = self.encodeTag(singleTag, isConstructed)
96            header += self.encodeLength(len(substrate), defModeOverride)
97
98            if isOctets:
99                substrate = ints2octs(header) + substrate
100
101                if not defModeOverride:
102                    substrate += self.eooOctetsSubstrate
103
104            else:
105                substrate = header + substrate
106
107                if not defModeOverride:
108                    substrate += self.eooIntegerSubstrate
109
110        if not isOctets:
111            substrate = ints2octs(substrate)
112
113        return substrate
114
115
116class EndOfOctetsEncoder(AbstractItemEncoder):
117    def encodeValue(self, value, asn1Spec, encodeFun, **options):
118        return null, False, True
119
120
121class BooleanEncoder(AbstractItemEncoder):
122    supportIndefLenMode = False
123
124    def encodeValue(self, value, asn1Spec, encodeFun, **options):
125        return value and (1,) or (0,), False, False
126
127
128class IntegerEncoder(AbstractItemEncoder):
129    supportIndefLenMode = False
130    supportCompactZero = False
131
132    def encodeValue(self, value, asn1Spec, encodeFun, **options):
133        if value == 0:
134            # de-facto way to encode zero
135            if self.supportCompactZero:
136                return (), False, False
137            else:
138                return (0,), False, False
139
140        return to_bytes(int(value), signed=True), False, True
141
142
143class BitStringEncoder(AbstractItemEncoder):
144    def encodeValue(self, value, asn1Spec, encodeFun, **options):
145        if asn1Spec is not None:
146            # TODO: try to avoid ASN.1 schema instantiation
147            value = asn1Spec.clone(value)
148
149        valueLength = len(value)
150        if valueLength % 8:
151            alignedValue = value << (8 - valueLength % 8)
152        else:
153            alignedValue = value
154
155        maxChunkSize = options.get('maxChunkSize', 0)
156        if not maxChunkSize or len(alignedValue) <= maxChunkSize * 8:
157            substrate = alignedValue.asOctets()
158            return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True
159
160        baseTag = value.tagSet.baseTag
161
162        # strip off explicit tags
163        if baseTag:
164            tagSet = tag.TagSet(baseTag, baseTag)
165        else:
166            tagSet = tag.TagSet()
167
168        alignedValue = alignedValue.clone(tagSet=tagSet)
169
170        stop = 0
171        substrate = null
172        while stop < valueLength:
173            start = stop
174            stop = min(start + maxChunkSize * 8, valueLength)
175            substrate += encodeFun(alignedValue[start:stop], asn1Spec, **options)
176
177        return substrate, True, True
178
179
180class OctetStringEncoder(AbstractItemEncoder):
181
182    def encodeValue(self, value, asn1Spec, encodeFun, **options):
183
184        if asn1Spec is None:
185            substrate = value.asOctets()
186
187        elif not isOctetsType(value):
188            substrate = asn1Spec.clone(value).asOctets()
189
190        else:
191            substrate = value
192
193        maxChunkSize = options.get('maxChunkSize', 0)
194
195        if not maxChunkSize or len(substrate) <= maxChunkSize:
196            return substrate, False, True
197
198        else:
199
200            # strip off explicit tags for inner chunks
201
202            if asn1Spec is None:
203                baseTag = value.tagSet.baseTag
204
205                # strip off explicit tags
206                if baseTag:
207                    tagSet = tag.TagSet(baseTag, baseTag)
208                else:
209                    tagSet = tag.TagSet()
210
211                asn1Spec = value.clone(tagSet=tagSet)
212
213            elif not isOctetsType(value):
214                baseTag = asn1Spec.tagSet.baseTag
215
216                # strip off explicit tags
217                if baseTag:
218                    tagSet = tag.TagSet(baseTag, baseTag)
219                else:
220                    tagSet = tag.TagSet()
221
222                asn1Spec = asn1Spec.clone(tagSet=tagSet)
223
224            pos = 0
225            substrate = null
226
227            while True:
228                chunk = value[pos:pos + maxChunkSize]
229                if not chunk:
230                    break
231
232                substrate += encodeFun(chunk, asn1Spec, **options)
233                pos += maxChunkSize
234
235            return substrate, True, True
236
237
238class NullEncoder(AbstractItemEncoder):
239    supportIndefLenMode = False
240
241    def encodeValue(self, value, asn1Spec, encodeFun, **options):
242        return null, False, True
243
244
245class ObjectIdentifierEncoder(AbstractItemEncoder):
246    supportIndefLenMode = False
247
248    def encodeValue(self, value, asn1Spec, encodeFun, **options):
249        if asn1Spec is not None:
250            value = asn1Spec.clone(value)
251
252        oid = value.asTuple()
253
254        # Build the first pair
255        try:
256            first = oid[0]
257            second = oid[1]
258
259        except IndexError:
260            raise error.PyAsn1Error('Short OID %s' % (value,))
261
262        if 0 <= second <= 39:
263            if first == 1:
264                oid = (second + 40,) + oid[2:]
265            elif first == 0:
266                oid = (second,) + oid[2:]
267            elif first == 2:
268                oid = (second + 80,) + oid[2:]
269            else:
270                raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,))
271        elif first == 2:
272            oid = (second + 80,) + oid[2:]
273        else:
274            raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,))
275
276        octets = ()
277
278        # Cycle through subIds
279        for subOid in oid:
280            if 0 <= subOid <= 127:
281                # Optimize for the common case
282                octets += (subOid,)
283            elif subOid > 127:
284                # Pack large Sub-Object IDs
285                res = (subOid & 0x7f,)
286                subOid >>= 7
287                while subOid:
288                    res = (0x80 | (subOid & 0x7f),) + res
289                    subOid >>= 7
290                # Add packed Sub-Object ID to resulted Object ID
291                octets += res
292            else:
293                raise error.PyAsn1Error('Negative OID arc %s at %s' % (subOid, value))
294
295        return octets, False, False
296
297
298class RealEncoder(AbstractItemEncoder):
299    supportIndefLenMode = 0
300    binEncBase = 2  # set to None to choose encoding base automatically
301
302    @staticmethod
303    def _dropFloatingPoint(m, encbase, e):
304        ms, es = 1, 1
305        if m < 0:
306            ms = -1  # mantissa sign
307        if e < 0:
308            es = -1  # exponenta sign
309        m *= ms
310        if encbase == 8:
311            m *= 2 ** (abs(e) % 3 * es)
312            e = abs(e) // 3 * es
313        elif encbase == 16:
314            m *= 2 ** (abs(e) % 4 * es)
315            e = abs(e) // 4 * es
316
317        while True:
318            if int(m) != m:
319                m *= encbase
320                e -= 1
321                continue
322            break
323        return ms, int(m), encbase, e
324
325    def _chooseEncBase(self, value):
326        m, b, e = value
327        encBase = [2, 8, 16]
328        if value.binEncBase in encBase:
329            return self._dropFloatingPoint(m, value.binEncBase, e)
330        elif self.binEncBase in encBase:
331            return self._dropFloatingPoint(m, self.binEncBase, e)
332        # auto choosing base 2/8/16
333        mantissa = [m, m, m]
334        exponenta = [e, e, e]
335        sign = 1
336        encbase = 2
337        e = float('inf')
338        for i in range(3):
339            (sign,
340             mantissa[i],
341             encBase[i],
342             exponenta[i]) = self._dropFloatingPoint(mantissa[i], encBase[i], exponenta[i])
343            if abs(exponenta[i]) < abs(e) or (abs(exponenta[i]) == abs(e) and mantissa[i] < m):
344                e = exponenta[i]
345                m = int(mantissa[i])
346                encbase = encBase[i]
347        return sign, m, encbase, e
348
349    def encodeValue(self, value, asn1Spec, encodeFun, **options):
350        if asn1Spec is not None:
351            value = asn1Spec.clone(value)
352
353        if value.isPlusInf:
354            return (0x40,), False, False
355        if value.isMinusInf:
356            return (0x41,), False, False
357        m, b, e = value
358        if not m:
359            return null, False, True
360        if b == 10:
361            return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), False, True
362        elif b == 2:
363            fo = 0x80  # binary encoding
364            ms, m, encbase, e = self._chooseEncBase(value)
365            if ms < 0:  # mantissa sign
366                fo |= 0x40  # sign bit
367            # exponenta & mantissa normalization
368            if encbase == 2:
369                while m & 0x1 == 0:
370                    m >>= 1
371                    e += 1
372            elif encbase == 8:
373                while m & 0x7 == 0:
374                    m >>= 3
375                    e += 1
376                fo |= 0x10
377            else:  # encbase = 16
378                while m & 0xf == 0:
379                    m >>= 4
380                    e += 1
381                fo |= 0x20
382            sf = 0  # scale factor
383            while m & 0x1 == 0:
384                m >>= 1
385                sf += 1
386            if sf > 3:
387                raise error.PyAsn1Error('Scale factor overflow')  # bug if raised
388            fo |= sf << 2
389            eo = null
390            if e == 0 or e == -1:
391                eo = int2oct(e & 0xff)
392            else:
393                while e not in (0, -1):
394                    eo = int2oct(e & 0xff) + eo
395                    e >>= 8
396                if e == 0 and eo and oct2int(eo[0]) & 0x80:
397                    eo = int2oct(0) + eo
398                if e == -1 and eo and not (oct2int(eo[0]) & 0x80):
399                    eo = int2oct(0xff) + eo
400            n = len(eo)
401            if n > 0xff:
402                raise error.PyAsn1Error('Real exponent overflow')
403            if n == 1:
404                pass
405            elif n == 2:
406                fo |= 1
407            elif n == 3:
408                fo |= 2
409            else:
410                fo |= 3
411                eo = int2oct(n & 0xff) + eo
412            po = null
413            while m:
414                po = int2oct(m & 0xff) + po
415                m >>= 8
416            substrate = int2oct(fo) + eo + po
417            return substrate, False, True
418        else:
419            raise error.PyAsn1Error('Prohibited Real base %s' % b)
420
421
422class SequenceEncoder(AbstractItemEncoder):
423    omitEmptyOptionals = False
424
425    # TODO: handling three flavors of input is too much -- split over codecs
426
427    def encodeValue(self, value, asn1Spec, encodeFun, **options):
428
429        substrate = null
430
431        if asn1Spec is None:
432            # instance of ASN.1 schema
433            value.verifySizeSpec()
434
435            namedTypes = value.componentType
436
437            for idx, component in enumerate(value.values()):
438                if namedTypes:
439                    namedType = namedTypes[idx]
440
441                    if namedType.isOptional and not component.isValue:
442                            continue
443
444                    if namedType.isDefaulted and component == namedType.asn1Object:
445                            continue
446
447                    if self.omitEmptyOptionals:
448                        options.update(ifNotEmpty=namedType.isOptional)
449
450                chunk = encodeFun(component, asn1Spec, **options)
451
452                # wrap open type blob if needed
453                if namedTypes and namedType.openType:
454                    wrapType = namedType.asn1Object
455                    if wrapType.tagSet and not wrapType.isSameTypeWith(component):
456                        chunk = encodeFun(chunk, wrapType, **options)
457
458                substrate += chunk
459
460        else:
461            # bare Python value + ASN.1 schema
462            for idx, namedType in enumerate(asn1Spec.componentType.namedTypes):
463
464                try:
465                    component = value[namedType.name]
466
467                except KeyError:
468                    raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value))
469
470                if namedType.isOptional and namedType.name not in value:
471                    continue
472
473                if namedType.isDefaulted and component == namedType.asn1Object:
474                    continue
475
476                if self.omitEmptyOptionals:
477                    options.update(ifNotEmpty=namedType.isOptional)
478
479                chunk = encodeFun(component, asn1Spec[idx], **options)
480
481                # wrap open type blob if needed
482                if namedType.openType:
483                    wrapType = namedType.asn1Object
484                    if wrapType.tagSet and not wrapType.isSameTypeWith(component):
485                        chunk = encodeFun(chunk, wrapType, **options)
486
487                substrate += chunk
488
489        return substrate, True, True
490
491
492class SequenceOfEncoder(AbstractItemEncoder):
493    def encodeValue(self, value, asn1Spec, encodeFun, **options):
494        if asn1Spec is None:
495            value.verifySizeSpec()
496        else:
497            asn1Spec = asn1Spec.componentType
498
499        substrate = null
500
501        for idx, component in enumerate(value):
502            substrate += encodeFun(value[idx], asn1Spec, **options)
503
504        return substrate, True, True
505
506
507class ChoiceEncoder(AbstractItemEncoder):
508    def encodeValue(self, value, asn1Spec, encodeFun, **options):
509        if asn1Spec is None:
510            component = value.getComponent()
511        else:
512            names = [namedType.name for namedType in asn1Spec.componentType.namedTypes
513                     if namedType.name in value]
514            if len(names) != 1:
515                raise error.PyAsn1Error('%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', value))
516
517            name = names[0]
518
519            component = value[name]
520            asn1Spec = asn1Spec[name]
521
522        return encodeFun(component, asn1Spec, **options), True, True
523
524
525class AnyEncoder(OctetStringEncoder):
526    def encodeValue(self, value, asn1Spec, encodeFun, **options):
527        if asn1Spec is None:
528            value = value.asOctets()
529        elif not isOctetsType(value):
530            value = asn1Spec.clone(value).asOctets()
531
532        return value, not options.get('defMode', True), True
533
534
535tagMap = {
536    eoo.endOfOctets.tagSet: EndOfOctetsEncoder(),
537    univ.Boolean.tagSet: BooleanEncoder(),
538    univ.Integer.tagSet: IntegerEncoder(),
539    univ.BitString.tagSet: BitStringEncoder(),
540    univ.OctetString.tagSet: OctetStringEncoder(),
541    univ.Null.tagSet: NullEncoder(),
542    univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(),
543    univ.Enumerated.tagSet: IntegerEncoder(),
544    univ.Real.tagSet: RealEncoder(),
545    # Sequence & Set have same tags as SequenceOf & SetOf
546    univ.SequenceOf.tagSet: SequenceOfEncoder(),
547    univ.SetOf.tagSet: SequenceOfEncoder(),
548    univ.Choice.tagSet: ChoiceEncoder(),
549    # character string types
550    char.UTF8String.tagSet: OctetStringEncoder(),
551    char.NumericString.tagSet: OctetStringEncoder(),
552    char.PrintableString.tagSet: OctetStringEncoder(),
553    char.TeletexString.tagSet: OctetStringEncoder(),
554    char.VideotexString.tagSet: OctetStringEncoder(),
555    char.IA5String.tagSet: OctetStringEncoder(),
556    char.GraphicString.tagSet: OctetStringEncoder(),
557    char.VisibleString.tagSet: OctetStringEncoder(),
558    char.GeneralString.tagSet: OctetStringEncoder(),
559    char.UniversalString.tagSet: OctetStringEncoder(),
560    char.BMPString.tagSet: OctetStringEncoder(),
561    # useful types
562    useful.ObjectDescriptor.tagSet: OctetStringEncoder(),
563    useful.GeneralizedTime.tagSet: OctetStringEncoder(),
564    useful.UTCTime.tagSet: OctetStringEncoder()
565}
566
567# Put in ambiguous & non-ambiguous types for faster codec lookup
568typeMap = {
569    univ.Boolean.typeId: BooleanEncoder(),
570    univ.Integer.typeId: IntegerEncoder(),
571    univ.BitString.typeId: BitStringEncoder(),
572    univ.OctetString.typeId: OctetStringEncoder(),
573    univ.Null.typeId: NullEncoder(),
574    univ.ObjectIdentifier.typeId: ObjectIdentifierEncoder(),
575    univ.Enumerated.typeId: IntegerEncoder(),
576    univ.Real.typeId: RealEncoder(),
577    # Sequence & Set have same tags as SequenceOf & SetOf
578    univ.Set.typeId: SequenceEncoder(),
579    univ.SetOf.typeId: SequenceOfEncoder(),
580    univ.Sequence.typeId: SequenceEncoder(),
581    univ.SequenceOf.typeId: SequenceOfEncoder(),
582    univ.Choice.typeId: ChoiceEncoder(),
583    univ.Any.typeId: AnyEncoder(),
584    # character string types
585    char.UTF8String.typeId: OctetStringEncoder(),
586    char.NumericString.typeId: OctetStringEncoder(),
587    char.PrintableString.typeId: OctetStringEncoder(),
588    char.TeletexString.typeId: OctetStringEncoder(),
589    char.VideotexString.typeId: OctetStringEncoder(),
590    char.IA5String.typeId: OctetStringEncoder(),
591    char.GraphicString.typeId: OctetStringEncoder(),
592    char.VisibleString.typeId: OctetStringEncoder(),
593    char.GeneralString.typeId: OctetStringEncoder(),
594    char.UniversalString.typeId: OctetStringEncoder(),
595    char.BMPString.typeId: OctetStringEncoder(),
596    # useful types
597    useful.ObjectDescriptor.typeId: OctetStringEncoder(),
598    useful.GeneralizedTime.typeId: OctetStringEncoder(),
599    useful.UTCTime.typeId: OctetStringEncoder()
600}
601
602
603class Encoder(object):
604    fixedDefLengthMode = None
605    fixedChunkSize = None
606
607    # noinspection PyDefaultArgument
608    def __init__(self, tagMap, typeMap={}):
609        self.__tagMap = tagMap
610        self.__typeMap = typeMap
611
612    def __call__(self, value, asn1Spec=None, **options):
613        try:
614            if asn1Spec is None:
615                typeId = value.typeId
616            else:
617                typeId = asn1Spec.typeId
618
619        except AttributeError:
620            raise error.PyAsn1Error('Value %r is not ASN.1 type instance '
621                                    'and "asn1Spec" not given' % (value,))
622
623        if debug.logger & debug.flagEncoder:
624            logger = debug.logger
625        else:
626            logger = None
627
628        if logger:
629            logger('encoder called in %sdef mode, chunk size %s for '
630                   'type %s, value:\n%s' % (not options.get('defMode', True) and 'in' or '', options.get('maxChunkSize', 0), asn1Spec is None and value.prettyPrintType() or asn1Spec.prettyPrintType(), value))
631
632        if self.fixedDefLengthMode is not None:
633            options.update(defMode=self.fixedDefLengthMode)
634
635        if self.fixedChunkSize is not None:
636            options.update(maxChunkSize=self.fixedChunkSize)
637
638
639        try:
640            concreteEncoder = self.__typeMap[typeId]
641
642            if logger:
643                logger('using value codec %s chosen by type ID %s' % (concreteEncoder.__class__.__name__, typeId))
644
645        except KeyError:
646            if asn1Spec is None:
647                tagSet = value.tagSet
648            else:
649                tagSet = asn1Spec.tagSet
650
651            # use base type for codec lookup to recover untagged types
652            baseTagSet = tag.TagSet(tagSet.baseTag, tagSet.baseTag)
653
654            try:
655                concreteEncoder = self.__tagMap[baseTagSet]
656
657            except KeyError:
658                raise error.PyAsn1Error('No encoder for %r (%s)' % (value, tagSet))
659
660            if logger:
661                logger('using value codec %s chosen by tagSet %s' % (concreteEncoder.__class__.__name__, tagSet))
662
663        substrate = concreteEncoder.encode(value, asn1Spec, self, **options)
664
665        if logger:
666            logger('codec %s built %s octets of substrate: %s\nencoder completed' % (concreteEncoder, len(substrate), debug.hexdump(substrate)))
667
668        return substrate
669
670#: Turns ASN.1 object into BER octet stream.
671#:
672#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
673#: walks all its components recursively and produces a BER octet stream.
674#:
675#: Parameters
676#: ----------
677#: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative)
678#:     A Python or pyasn1 object to encode. If Python object is given, `asnSpec`
679#:     parameter is required to guide the encoding process.
680#:
681#: Keyword Args
682#: ------------
683#: asn1Spec:
684#:     Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative
685#:
686#: defMode: :py:class:`bool`
687#:     If `False`, produces indefinite length encoding
688#:
689#: maxChunkSize: :py:class:`int`
690#:     Maximum chunk size in chunked encoding mode (0 denotes unlimited chunk size)
691#:
692#: Returns
693#: -------
694#: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2)
695#:     Given ASN.1 object encoded into BER octetstream
696#:
697#: Raises
698#: ------
699#: :py:class:`~pyasn1.error.PyAsn1Error`
700#:     On encoding errors
701#:
702#: Examples
703#: --------
704#: Encode Python value into BER with ASN.1 schema
705#:
706#: .. code-block:: pycon
707#:
708#:    >>> seq = SequenceOf(componentType=Integer())
709#:    >>> encode([1, 2, 3], asn1Spec=seq)
710#:    b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
711#:
712#: Encode ASN.1 value object into BER
713#:
714#: .. code-block:: pycon
715#:
716#:    >>> seq = SequenceOf(componentType=Integer())
717#:    >>> seq.extend([1, 2, 3])
718#:    >>> encode(seq)
719#:    b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03'
720#:
721encode = Encoder(tagMap, typeMap)
722