encoder.py 6.6 KB

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