Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

encoder.py 6.6KB

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