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# 7try: 8 from collections import OrderedDict 9 10except ImportError: 11 OrderedDict = dict 12 13from pyasn1 import debug 14from pyasn1 import error 15from pyasn1.type import base 16from pyasn1.type import char 17from pyasn1.type import tag 18from pyasn1.type import univ 19from pyasn1.type import useful 20 21__all__ = ['encode'] 22 23 24class AbstractItemEncoder(object): 25 def encode(self, value, encodeFun, **options): 26 raise error.PyAsn1Error('Not implemented') 27 28 29class BooleanEncoder(AbstractItemEncoder): 30 def encode(self, value, encodeFun, **options): 31 return bool(value) 32 33 34class IntegerEncoder(AbstractItemEncoder): 35 def encode(self, value, encodeFun, **options): 36 return int(value) 37 38 39class BitStringEncoder(AbstractItemEncoder): 40 def encode(self, value, encodeFun, **options): 41 return str(value) 42 43 44class OctetStringEncoder(AbstractItemEncoder): 45 def encode(self, value, encodeFun, **options): 46 return value.asOctets() 47 48 49class TextStringEncoder(AbstractItemEncoder): 50 def encode(self, value, encodeFun, **options): 51 return str(value) 52 53 54class NullEncoder(AbstractItemEncoder): 55 def encode(self, value, encodeFun, **options): 56 return None 57 58 59class ObjectIdentifierEncoder(AbstractItemEncoder): 60 def encode(self, value, encodeFun, **options): 61 return str(value) 62 63 64class RealEncoder(AbstractItemEncoder): 65 def encode(self, value, encodeFun, **options): 66 return float(value) 67 68 69class SetEncoder(AbstractItemEncoder): 70 protoDict = dict 71 72 def encode(self, value, encodeFun, **options): 73 value.verifySizeSpec() 74 75 namedTypes = value.componentType 76 substrate = self.protoDict() 77 78 for idx, (key, subValue) in enumerate(value.items()): 79 if namedTypes and namedTypes[idx].isOptional and not value[idx].isValue: 80 continue 81 substrate[key] = encodeFun(subValue, **options) 82 return substrate 83 84 85class SequenceEncoder(SetEncoder): 86 protoDict = OrderedDict 87 88 89class SequenceOfEncoder(AbstractItemEncoder): 90 def encode(self, value, encodeFun, **options): 91 value.verifySizeSpec() 92 return [encodeFun(x, **options) for x in value] 93 94 95class ChoiceEncoder(SequenceEncoder): 96 pass 97 98 99class AnyEncoder(AbstractItemEncoder): 100 def encode(self, value, encodeFun, **options): 101 return value.asOctets() 102 103 104tagMap = { 105 univ.Boolean.tagSet: BooleanEncoder(), 106 univ.Integer.tagSet: IntegerEncoder(), 107 univ.BitString.tagSet: BitStringEncoder(), 108 univ.OctetString.tagSet: OctetStringEncoder(), 109 univ.Null.tagSet: NullEncoder(), 110 univ.ObjectIdentifier.tagSet: ObjectIdentifierEncoder(), 111 univ.Enumerated.tagSet: IntegerEncoder(), 112 univ.Real.tagSet: RealEncoder(), 113 # Sequence & Set have same tags as SequenceOf & SetOf 114 univ.SequenceOf.tagSet: SequenceOfEncoder(), 115 univ.SetOf.tagSet: SequenceOfEncoder(), 116 univ.Choice.tagSet: ChoiceEncoder(), 117 # character string types 118 char.UTF8String.tagSet: TextStringEncoder(), 119 char.NumericString.tagSet: TextStringEncoder(), 120 char.PrintableString.tagSet: TextStringEncoder(), 121 char.TeletexString.tagSet: TextStringEncoder(), 122 char.VideotexString.tagSet: TextStringEncoder(), 123 char.IA5String.tagSet: TextStringEncoder(), 124 char.GraphicString.tagSet: TextStringEncoder(), 125 char.VisibleString.tagSet: TextStringEncoder(), 126 char.GeneralString.tagSet: TextStringEncoder(), 127 char.UniversalString.tagSet: TextStringEncoder(), 128 char.BMPString.tagSet: TextStringEncoder(), 129 # useful types 130 useful.ObjectDescriptor.tagSet: OctetStringEncoder(), 131 useful.GeneralizedTime.tagSet: OctetStringEncoder(), 132 useful.UTCTime.tagSet: OctetStringEncoder() 133} 134 135# Type-to-codec map for ambiguous ASN.1 types 136typeMap = { 137 univ.Set.typeId: SetEncoder(), 138 univ.SetOf.typeId: SequenceOfEncoder(), 139 univ.Sequence.typeId: SequenceEncoder(), 140 univ.SequenceOf.typeId: SequenceOfEncoder(), 141 univ.Choice.typeId: ChoiceEncoder(), 142 univ.Any.typeId: AnyEncoder() 143} 144 145 146class Encoder(object): 147 148 # noinspection PyDefaultArgument 149 def __init__(self, tagMap, typeMap={}): 150 self.__tagMap = tagMap 151 self.__typeMap = typeMap 152 153 def __call__(self, value, **options): 154 if not isinstance(value, base.Asn1Item): 155 raise error.PyAsn1Error('value is not valid (should be an instance of an ASN.1 Item)') 156 157 if debug.logger & debug.flagEncoder: 158 logger = debug.logger 159 else: 160 logger = None 161 162 if logger: 163 debug.scope.push(type(value).__name__) 164 logger('encoder called for type %s <%s>' % (type(value).__name__, value.prettyPrint())) 165 166 tagSet = value.tagSet 167 168 try: 169 concreteEncoder = self.__typeMap[value.typeId] 170 171 except KeyError: 172 # use base type for codec lookup to recover untagged types 173 baseTagSet = tag.TagSet(value.tagSet.baseTag, value.tagSet.baseTag) 174 175 try: 176 concreteEncoder = self.__tagMap[baseTagSet] 177 178 except KeyError: 179 raise error.PyAsn1Error('No encoder for %s' % (value,)) 180 181 if logger: 182 logger('using value codec %s chosen by %s' % (concreteEncoder.__class__.__name__, tagSet)) 183 184 pyObject = concreteEncoder.encode(value, self, **options) 185 186 if logger: 187 logger('encoder %s produced: %s' % (type(concreteEncoder).__name__, repr(pyObject))) 188 debug.scope.pop() 189 190 return pyObject 191 192 193#: Turns ASN.1 object into a Python built-in type object(s). 194#: 195#: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) 196#: walks all its components recursively and produces a Python built-in type or a tree 197#: of those. 198#: 199#: One exception is that instead of :py:class:`dict`, the :py:class:`OrderedDict` 200#: can be produced (whenever available) to preserve ordering of the components 201#: in ASN.1 SEQUENCE. 202#: 203#: Parameters 204#: ---------- 205# asn1Value: any pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) 206#: pyasn1 object to encode (or a tree of them) 207#: 208#: Returns 209#: ------- 210#: : :py:class:`object` 211#: Python built-in type instance (or a tree of them) 212#: 213#: Raises 214#: ------ 215#: :py:class:`~pyasn1.error.PyAsn1Error` 216#: On encoding errors 217#: 218#: Examples 219#: -------- 220#: Encode ASN.1 value object into native Python types 221#: 222#: .. code-block:: pycon 223#: 224#: >>> seq = SequenceOf(componentType=Integer()) 225#: >>> seq.extend([1, 2, 3]) 226#: >>> encode(seq) 227#: [1, 2, 3] 228#: 229encode = Encoder(tagMap, typeMap) 230