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