summaryrefslogtreecommitdiff
path: root/pyasn1/codec/ber/encoder.py
diff options
context:
space:
mode:
Diffstat (limited to 'pyasn1/codec/ber/encoder.py')
-rw-r--r--pyasn1/codec/ber/encoder.py166
1 files changed, 134 insertions, 32 deletions
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py
index f213d5b..142e167 100644
--- a/pyasn1/codec/ber/encoder.py
+++ b/pyasn1/codec/ber/encoder.py
@@ -33,29 +33,39 @@ class AbstractItemEncoder(object):
encodedTag = tagClass | tagFormat
if isConstructed:
encodedTag |= tag.tagFormatConstructed
+
if tagId < 31:
return encodedTag | tagId,
+
else:
substrate = tagId & 0x7f,
+
tagId >>= 7
+
while tagId:
substrate = (0x80 | (tagId & 0x7f),) + substrate
tagId >>= 7
+
return (encodedTag | 0x1F,) + substrate
def encodeLength(self, length, defMode):
if not defMode and self.supportIndefLenMode:
return (0x80,)
+
if length < 0x80:
return length,
+
else:
substrate = ()
while length:
substrate = (length & 0xff,) + substrate
length >>= 8
+
substrateLen = len(substrate)
+
if substrateLen > 126:
raise error.PyAsn1Error('Length octets overflow (%d)' % substrateLen)
+
return (0x80 | substrateLen,) + substrate
def encodeValue(self, value, asn1Spec, encodeFun, **options):
@@ -87,16 +97,32 @@ class AbstractItemEncoder(object):
value, asn1Spec, encodeFun, **options
)
+ if LOG:
+ LOG('encoded %svalue %s into %s' % (
+ isConstructed and 'constructed ' or '', value, substrate
+ ))
+
if not substrate and isConstructed and options.get('ifNotEmpty', False):
return substrate
- # primitive form implies definite mode
if not isConstructed:
defModeOverride = True
+ if LOG:
+ LOG('overridden encoding mode into definitive for primitive type')
+
header = self.encodeTag(singleTag, isConstructed)
+
+ if LOG:
+ LOG('encoded %stag %s into %s' % (isConstructed and 'constructed ' or '',
+ singleTag, debug.hexdump(header)))
+
header += self.encodeLength(len(substrate), defModeOverride)
+ if LOG:
+ LOG('encoded %s octets (tag + payload) into %s' % (
+ len(substrate), debug.hexdump(header)))
+
if isOctets:
substrate = ints2octs(header) + substrate
@@ -133,6 +159,11 @@ class IntegerEncoder(AbstractItemEncoder):
def encodeValue(self, value, asn1Spec, encodeFun, **options):
if value == 0:
+ if LOG:
+ LOG('encoding %spayload for zero INTEGER' % (
+ self.supportCompactZero and 'no ' or ''
+ ))
+
# de-facto way to encode zero
if self.supportCompactZero:
return (), False, False
@@ -159,11 +190,15 @@ class BitStringEncoder(AbstractItemEncoder):
substrate = alignedValue.asOctets()
return int2oct(len(substrate) * 8 - valueLength) + substrate, False, True
+ if LOG:
+ LOG('encoding into up to %s-octet chunks' % maxChunkSize)
+
baseTag = value.tagSet.baseTag
# strip off explicit tags
if baseTag:
tagSet = tag.TagSet(baseTag, baseTag)
+
else:
tagSet = tag.TagSet()
@@ -197,44 +232,47 @@ class OctetStringEncoder(AbstractItemEncoder):
if not maxChunkSize or len(substrate) <= maxChunkSize:
return substrate, False, True
- else:
+ if LOG:
+ LOG('encoding into up to %s-octet chunks' % maxChunkSize)
- # strip off explicit tags for inner chunks
+ # strip off explicit tags for inner chunks
- if asn1Spec is None:
- baseTag = value.tagSet.baseTag
+ if asn1Spec is None:
+ baseTag = value.tagSet.baseTag
- # strip off explicit tags
- if baseTag:
- tagSet = tag.TagSet(baseTag, baseTag)
- else:
- tagSet = tag.TagSet()
+ # strip off explicit tags
+ if baseTag:
+ tagSet = tag.TagSet(baseTag, baseTag)
- asn1Spec = value.clone(tagSet=tagSet)
+ else:
+ tagSet = tag.TagSet()
+
+ asn1Spec = value.clone(tagSet=tagSet)
- elif not isOctetsType(value):
- baseTag = asn1Spec.tagSet.baseTag
+ elif not isOctetsType(value):
+ baseTag = asn1Spec.tagSet.baseTag
- # strip off explicit tags
- if baseTag:
- tagSet = tag.TagSet(baseTag, baseTag)
- else:
- tagSet = tag.TagSet()
+ # strip off explicit tags
+ if baseTag:
+ tagSet = tag.TagSet(baseTag, baseTag)
+
+ else:
+ tagSet = tag.TagSet()
- asn1Spec = asn1Spec.clone(tagSet=tagSet)
+ asn1Spec = asn1Spec.clone(tagSet=tagSet)
- pos = 0
- substrate = null
+ pos = 0
+ substrate = null
- while True:
- chunk = value[pos:pos + maxChunkSize]
- if not chunk:
- break
+ while True:
+ chunk = value[pos:pos + maxChunkSize]
+ if not chunk:
+ break
- substrate += encodeFun(chunk, asn1Spec, **options)
- pos += maxChunkSize
+ substrate += encodeFun(chunk, asn1Spec, **options)
+ pos += maxChunkSize
- return substrate, True, True
+ return substrate, True, True
class NullEncoder(AbstractItemEncoder):
@@ -270,8 +308,10 @@ class ObjectIdentifierEncoder(AbstractItemEncoder):
oid = (second + 80,) + oid[2:]
else:
raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,))
+
elif first == 2:
oid = (second + 80,) + oid[2:]
+
else:
raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,))
@@ -282,15 +322,19 @@ class ObjectIdentifierEncoder(AbstractItemEncoder):
if 0 <= subOid <= 127:
# Optimize for the common case
octets += (subOid,)
+
elif subOid > 127:
# Pack large Sub-Object IDs
res = (subOid & 0x7f,)
subOid >>= 7
+
while subOid:
res = (0x80 | (subOid & 0x7f),) + res
subOid >>= 7
+
# Add packed Sub-Object ID to resulted Object ID
octets += res
+
else:
raise error.PyAsn1Error('Negative OID arc %s at %s' % (subOid, value))
@@ -306,12 +350,16 @@ class RealEncoder(AbstractItemEncoder):
ms, es = 1, 1
if m < 0:
ms = -1 # mantissa sign
+
if e < 0:
es = -1 # exponent sign
+
m *= ms
+
if encbase == 8:
m *= 2 ** (abs(e) % 3 * es)
e = abs(e) // 3 * es
+
elif encbase == 16:
m *= 2 ** (abs(e) % 4 * es)
e = abs(e) // 4 * es
@@ -322,6 +370,7 @@ class RealEncoder(AbstractItemEncoder):
e -= 1
continue
break
+
return ms, int(m), encbase, e
def _chooseEncBase(self, value):
@@ -329,23 +378,32 @@ class RealEncoder(AbstractItemEncoder):
encBase = [2, 8, 16]
if value.binEncBase in encBase:
return self._dropFloatingPoint(m, value.binEncBase, e)
+
elif self.binEncBase in encBase:
return self._dropFloatingPoint(m, self.binEncBase, e)
- # auto choosing base 2/8/16
+
+ # auto choosing base 2/8/16
mantissa = [m, m, m]
exponent = [e, e, e]
sign = 1
encbase = 2
e = float('inf')
+
for i in range(3):
(sign,
mantissa[i],
encBase[i],
exponent[i]) = self._dropFloatingPoint(mantissa[i], encBase[i], exponent[i])
+
if abs(exponent[i]) < abs(e) or (abs(exponent[i]) == abs(e) and mantissa[i] < m):
e = exponent[i]
m = int(mantissa[i])
encbase = encBase[i]
+
+ if LOG:
+ LOG('automatically chosen REAL encoding base %s, sign %s, mantissa %s, '
+ 'exponent %s' % (encbase, sign, m, e))
+
return sign, m, encbase, e
def encodeValue(self, value, asn1Spec, encodeFun, **options):
@@ -354,69 +412,98 @@ class RealEncoder(AbstractItemEncoder):
if value.isPlusInf:
return (0x40,), False, False
+
if value.isMinusInf:
return (0x41,), False, False
+
m, b, e = value
+
if not m:
return null, False, True
+
if b == 10:
+ if LOG:
+ LOG('encoding REAL into character form')
+
return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), False, True
+
elif b == 2:
fo = 0x80 # binary encoding
ms, m, encbase, e = self._chooseEncBase(value)
+
if ms < 0: # mantissa sign
fo |= 0x40 # sign bit
+
# exponent & mantissa normalization
if encbase == 2:
while m & 0x1 == 0:
m >>= 1
e += 1
+
elif encbase == 8:
while m & 0x7 == 0:
m >>= 3
e += 1
fo |= 0x10
+
else: # encbase = 16
while m & 0xf == 0:
m >>= 4
e += 1
fo |= 0x20
+
sf = 0 # scale factor
+
while m & 0x1 == 0:
m >>= 1
sf += 1
+
if sf > 3:
raise error.PyAsn1Error('Scale factor overflow') # bug if raised
+
fo |= sf << 2
eo = null
if e == 0 or e == -1:
eo = int2oct(e & 0xff)
+
else:
while e not in (0, -1):
eo = int2oct(e & 0xff) + eo
e >>= 8
+
if e == 0 and eo and oct2int(eo[0]) & 0x80:
eo = int2oct(0) + eo
+
if e == -1 and eo and not (oct2int(eo[0]) & 0x80):
eo = int2oct(0xff) + eo
+
n = len(eo)
if n > 0xff:
raise error.PyAsn1Error('Real exponent overflow')
+
if n == 1:
pass
+
elif n == 2:
fo |= 1
+
elif n == 3:
fo |= 2
+
else:
fo |= 3
eo = int2oct(n & 0xff) + eo
+
po = null
+
while m:
po = int2oct(m & 0xff) + po
m >>= 8
+
substrate = int2oct(fo) + eo + po
+
return substrate, False, True
+
else:
raise error.PyAsn1Error('Prohibited Real base %s' % b)
@@ -441,10 +528,14 @@ class SequenceEncoder(AbstractItemEncoder):
namedType = namedTypes[idx]
if namedType.isOptional and not component.isValue:
- continue
+ if LOG:
+ LOG('not encoding OPTIONAL component %r' % (namedType,))
+ continue
if namedType.isDefaulted and component == namedType.asn1Object:
- continue
+ if LOG:
+ LOG('not encoding DEFAULT component %r' % (namedType,))
+ continue
if self.omitEmptyOptionals:
options.update(ifNotEmpty=namedType.isOptional)
@@ -457,6 +548,9 @@ class SequenceEncoder(AbstractItemEncoder):
if wrapType.tagSet and not wrapType.isSameTypeWith(component):
chunk = encodeFun(chunk, wrapType, **options)
+ if LOG:
+ LOG('wrapped open type with wrap type %r' % (wrapType,))
+
substrate += chunk
else:
@@ -467,12 +561,17 @@ class SequenceEncoder(AbstractItemEncoder):
component = value[namedType.name]
except KeyError:
- raise error.PyAsn1Error('Component name "%s" not found in %r' % (namedType.name, value))
+ raise error.PyAsn1Error('Component name "%s" not found in %r' % (
+ namedType.name, value))
if namedType.isOptional and namedType.name not in value:
+ if LOG:
+ LOG('not encoding OPTIONAL component %r' % (namedType,))
continue
if namedType.isDefaulted and component == namedType.asn1Object:
+ if LOG:
+ LOG('not encoding DEFAULT component %r' % (namedType,))
continue
if self.omitEmptyOptionals:
@@ -486,6 +585,9 @@ class SequenceEncoder(AbstractItemEncoder):
if wrapType.tagSet and not wrapType.isSameTypeWith(component):
chunk = encodeFun(chunk, wrapType, **options)
+ if LOG:
+ LOG('wrapped open type with wrap type %r' % (wrapType,))
+
substrate += chunk
return substrate, True, True