Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
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 28KB

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