summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelie <elie>2011-10-04 11:16:59 +0000
committerelie <elie>2011-10-04 11:16:59 +0000
commit85987e51ce099576aedc6740f0128dabe269fc81 (patch)
tree0a807d95aa36ec59b792415806ccc61fd353e8e1
parent18592e68d1db5300a7a275d623ad92dcb5bea6fe (diff)
downloadpyasn1-85987e51ce099576aedc6740f0128dabe269fc81.tar.gz
base type for encoding subsrate and OctetString type is now 'bytes' on
py3k and 'str' on py2k
-rw-r--r--pyasn1/codec/ber/decoder.py31
-rw-r--r--pyasn1/codec/ber/encoder.py80
-rw-r--r--pyasn1/codec/cer/decoder.py3
-rw-r--r--pyasn1/codec/cer/encoder.py13
-rw-r--r--pyasn1/compat/__init__.py0
-rw-r--r--pyasn1/compat/octets.py18
-rw-r--r--pyasn1/type/univ.py99
7 files changed, 151 insertions, 93 deletions
diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py
index 11d8237..e455039 100644
--- a/pyasn1/codec/ber/decoder.py
+++ b/pyasn1/codec/ber/decoder.py
@@ -1,6 +1,7 @@
# BER decoder
from pyasn1.type import tag, base, univ, char, useful, tagmap
from pyasn1.codec.ber import eoo
+from pyasn1.compat.octets import oct2int, octs2ints
from pyasn1 import error
class AbstractDecoder:
@@ -84,13 +85,13 @@ class IntegerDecoder(AbstractSimpleDecoder):
if substrate in self.precomputedValues:
value = self.precomputedValues[substrate]
else:
- firstOctet = ord(substrate[0])
+ firstOctet = oct2int(substrate[0])
if firstOctet & 0x80:
value = -1
else:
value = 0
for octet in substrate:
- value = value << 8 | ord(octet)
+ value = value << 8 | oct2int(octet)
value = self._valueFilter(value)
return self._createComponent(asn1Spec, tagSet, value), substrate
@@ -110,7 +111,7 @@ class BitStringDecoder(AbstractSimpleDecoder):
if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check?
if not substrate:
raise error.PyAsn1Error('Missing initial octet')
- trailingBits = ord(substrate[0])
+ trailingBits = oct2int(substrate[0])
if trailingBits > 7:
raise error.PyAsn1Error(
'Trailing bits overflow %s' % trailingBits
@@ -121,7 +122,7 @@ class BitStringDecoder(AbstractSimpleDecoder):
if p == l:
lsb = trailingBits
j = 7
- o = ord(substrate[p])
+ o = oct2int(substrate[p])
while j >= lsb:
b = b + ((o>>j)&0x01,)
j = j - 1
@@ -201,14 +202,14 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder):
raise error.PyAsn1Error('Empty substrate')
oid = (); index = 0
# Get the first subid
- subId = ord(substrate[index])
+ subId = oct2int(substrate[index])
oid = oid + divmod(subId, 40)
index = index + 1
substrateLen = len(substrate)
while index < substrateLen:
- subId = ord(substrate[index])
+ subId = oct2int(substrate[index])
if subId < 128:
oid = oid + (subId,)
index = index + 1
@@ -219,7 +220,7 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder):
while nextSubId >= 128 and index < substrateLen:
subId = (subId << 7) + (nextSubId & 0x7F)
index = index + 1
- nextSubId = ord(substrate[index])
+ nextSubId = oct2int(substrate[index])
if index == substrateLen:
raise error.SubstrateUnderrunError(
'Short substrate for OID %s' % oid
@@ -236,7 +237,7 @@ class RealDecoder(AbstractSimpleDecoder):
substrate = substrate[:length]
if not length:
raise error.SubstrateUnderrunError('Short substrate for Real')
- fo = ord(substrate[0]); substrate = substrate[1:]
+ fo = oct2int(substrate[0]); substrate = substrate[1:]
if fo & 0x40: # infinite value
value = fo & 0x01 and float('-inf') or float('inf')
elif fo & 0x80: # binary enoding
@@ -247,19 +248,19 @@ class RealDecoder(AbstractSimpleDecoder):
elif fo & 0x02:
n = 3
else:
- n = ord(substrate[0])
+ n = oct2int(substrate[0])
eo, substrate = substrate[:n], substrate[n:]
if not eo or not substrate:
raise error.PyAsn1Error('Real exponent screwed')
e = 0
while eo: # exponent
e <<= 8
- e |= ord(eo[0])
+ e |= oct2int(eo[0])
eo = eo[1:]
p = 0
while substrate: # value
p <<= 8
- p |= ord(substrate[0])
+ p |= oct2int(substrate[0])
substrate = substrate[1:]
if fo & 0x40: # sign bit
p = -p
@@ -564,7 +565,7 @@ class Decoder:
if firstOctet in self.__tagCache:
lastTag = self.__tagCache[firstOctet]
else:
- t = ord(firstOctet)
+ t = oct2int(firstOctet)
tagClass = t&0xC0
tagFormat = t&0x20
tagId = t&0x1F
@@ -575,7 +576,7 @@ class Decoder:
raise error.SubstrateUnderrunError(
'Short octet stream on long tag decoding'
)
- t = ord(substrate[0])
+ t = oct2int(substrate[0])
tagId = tagId << 7 | (t&0x7F)
substrate = substrate[1:]
if not t&0x80:
@@ -603,7 +604,7 @@ class Decoder:
raise error.SubstrateUnderrunError(
'Short octet stream on length decoding'
)
- firstOctet = ord(substrate[0])
+ firstOctet = oct2int(substrate[0])
if firstOctet == 128:
size = 1
length = -1
@@ -622,7 +623,7 @@ class Decoder:
(size, len(lengthString), tagSet)
)
for char in lengthString:
- length = (length << 8) | ord(char)
+ length = (length << 8) | oct2int(char)
size = size + 1
state = stGetValueDecoder
substrate = substrate[size:]
diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py
index f6425b1..e8ca6b3 100644
--- a/pyasn1/codec/ber/encoder.py
+++ b/pyasn1/codec/ber/encoder.py
@@ -1,6 +1,7 @@
# BER encoder
from pyasn1.type import base, tag, univ, char, useful
from pyasn1.codec.ber import eoo
+from pyasn1.compat.octets import int2oct, ints2octs, null, str2octs
from pyasn1 import error
class Error(Exception): pass
@@ -13,36 +14,36 @@ class AbstractItemEncoder:
if isConstructed:
v = v|tag.tagFormatConstructed
if tagId < 31:
- return chr(v|tagId)
+ return int2oct(v|tagId)
else:
- s = chr(tagId&0x7f)
+ s = int2oct(tagId&0x7f)
tagId = tagId >> 7
while tagId:
- s = chr(0x80|(tagId&0x7f)) + s
+ s = int2oct(0x80|(tagId&0x7f)) + s
tagId = tagId >> 7
- return chr(v|0x1F) + s
+ return int2oct(v|0x1F) + s
def encodeLength(self, length, defMode):
if not defMode and self.supportIndefLenMode:
- return '\x80'
+ return int2oct(0x80)
if length < 0x80:
- return chr(length)
+ return int2oct(length)
else:
- substrate = ''
+ substrate = null
while length:
- substrate = chr(length&0xff) + substrate
+ substrate = int2oct(length&0xff) + substrate
length = length >> 8
substrateLen = len(substrate)
if substrateLen > 126:
raise Error('Length octets overflow (%d)' % substrateLen)
- return chr(0x80 | substrateLen) + substrate
+ return int2oct(0x80 | substrateLen) + substrate
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
raise Error('Not implemented')
def _encodeEndOfOctets(self, encodeFun, defMode):
if defMode or not self.supportIndefLenMode:
- return ''
+ return null
else:
return encodeFun(eoo.endOfOctets, defMode)
@@ -64,7 +65,7 @@ class AbstractItemEncoder:
class EndOfOctetsEncoder(AbstractItemEncoder):
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
- return '', 0
+ return null, 0
class ExplicitlyTaggedItemEncoder(AbstractItemEncoder):
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
@@ -93,7 +94,7 @@ class IntegerEncoder(AbstractItemEncoder):
(octets[0] == 0 and octets[1] & 0x80 == 0 or \
octets[0] == 0xff and octets[1] & 0x80 != 0):
del octets[0]
- return ''.join([chr(x) for x in octets]), 0
+ return ints2octs(octets), 0
class BitStringEncoder(AbstractItemEncoder):
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
@@ -104,9 +105,9 @@ class BitStringEncoder(AbstractItemEncoder):
r[i] = r.get(i,0) | value[p]<<(7-j)
p = p + 1
keys = list(r); keys.sort()
- return chr(7-j) + ''.join([chr(r[k]) for k in keys]), 0
+ return int2oct(7-j) + ints2octs([r[k] for k in keys]), 0
else:
- pos = 0; substrate = ''
+ pos = 0; substrate = null
while 1:
# count in octets
v = value.clone(value[pos*8:pos*8+maxChunkSize*8])
@@ -119,9 +120,9 @@ class BitStringEncoder(AbstractItemEncoder):
class OctetStringEncoder(AbstractItemEncoder):
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
if not maxChunkSize or len(value) <= maxChunkSize:
- return str(value), 0
+ return value.asBytes(), 0
else:
- pos = 0; substrate = ''
+ pos = 0; substrate = null
while 1:
v = value.clone(value[pos:pos+maxChunkSize])
if not v:
@@ -133,13 +134,13 @@ class OctetStringEncoder(AbstractItemEncoder):
class NullEncoder(AbstractItemEncoder):
supportIndefLenMode = 0
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
- return '', 0
+ return null, 0
class ObjectIdentifierEncoder(AbstractItemEncoder):
supportIndefLenMode = 0
precomputedValues = {
- (1, 3, 6, 1, 2): ('+', '\x06', '\x01', '\x02'),
- (1, 3, 6, 1, 4): ('+', '\x06', '\x01', '\x04')
+ (1, 3, 6, 1, 2): (43, 6, 1, 2),
+ (1, 3, 6, 1, 4): (43, 6, 1, 4)
}
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
oid = value.asTuple()
@@ -158,42 +159,41 @@ class ObjectIdentifierEncoder(AbstractItemEncoder):
raise error.PyAsn1Error(
'Initial sub-ID overflow %s in OID %s' % (oid[index:], value)
)
- octets = (chr(subid),)
+ octets = (subid,)
index = index + 2
# Cycle through subids
for subid in oid[index:]:
if subid > -1 and subid < 128:
# Optimize for the common case
- octets = octets + (chr(subid & 0x7f),)
+ octets = octets + (subid & 0x7f,)
elif subid < 0 or subid > 0xFFFFFFFF:
raise error.PyAsn1Error(
'SubId overflow %s in %s' % (subid, value)
)
else:
# Pack large Sub-Object IDs
- res = (chr(subid & 0x7f),)
+ res = (subid & 0x7f,)
subid = subid >> 7
while subid > 0:
- res = (chr(0x80 | (subid & 0x7f)),) + res
+ res = (0x80 | (subid & 0x7f),) + res
subid = subid >> 7
- # Convert packed Sub-Object ID to string and add packed
- # it to resulted Object ID
- octets = octets + (''.join(res),)
+ # Add packed Sub-Object ID to resulted Object ID
+ octets += res
- return ''.join(octets), 0
+ return ints2octs(octets), 0
class RealEncoder(AbstractItemEncoder):
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
if value.isPlusInfinity():
- return '\x40', 0
+ return int2oct(0x40), 0
if value.isMinusInfinity():
- return '\x41', 0
+ return int2oct(0x41), 0
m, b, e = value
if not m:
- return '', 0
+ return null, 0
if b == 10:
- return '\x03%dE%s%d' % (m, e == 0 and '+' or '', e), 0
+ return str2octs('\x03%dE%s%d' % (m, e == 0 and '+' or '', e)), 0
elif b == 2:
fo = 0x80 # binary enoding
if m < 0:
@@ -205,9 +205,9 @@ class RealEncoder(AbstractItemEncoder):
while m & 0x1 == 0: # mantissa normalization
m >>= 1
e += 1
- eo = ''
+ eo = null
while e:
- eo = chr(e&0xff) + eo
+ eo = int2oct(e&0xff) + eo
e >>= 8
n = len(eo)
if n > 0xff:
@@ -220,12 +220,12 @@ class RealEncoder(AbstractItemEncoder):
fo |= 2
else:
fo |= 3
- eo = chr(n//0xff+1) + eo
- po = ''
+ eo = int2oct(n//0xff+1) + eo
+ po = null
while m:
- po = chr(m&0xff) + po
+ po = int2oct(m&0xff) + po
m >>= 8
- substrate = chr(fo) + eo + po
+ substrate = int2oct(fo) + eo + po
return substrate, 0
else:
raise error.PyAsn1Error('Prohibited Real base %s' % b)
@@ -234,7 +234,7 @@ class SequenceEncoder(AbstractItemEncoder):
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
value.setDefaultComponents()
value.verifySizeSpec()
- substrate = ''; idx = len(value)
+ substrate = null; idx = len(value)
while idx > 0:
idx = idx - 1
if value[idx] is None: # Optional component
@@ -250,7 +250,7 @@ class SequenceEncoder(AbstractItemEncoder):
class SequenceOfEncoder(AbstractItemEncoder):
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
value.verifySizeSpec()
- substrate = ''; idx = len(value)
+ substrate = null; idx = len(value)
while idx > 0:
idx = idx - 1
substrate = encodeFun(
@@ -264,7 +264,7 @@ class ChoiceEncoder(AbstractItemEncoder):
class AnyEncoder(OctetStringEncoder):
def encodeValue(self, encodeFun, value, defMode, maxChunkSize):
- return str(value), defMode == 0
+ return value.asBytes(), defMode == 0
tagMap = {
eoo.endOfOctets.tagSet: EndOfOctetsEncoder(),
diff --git a/pyasn1/codec/cer/decoder.py b/pyasn1/codec/cer/decoder.py
index 33a98cd..71395d2 100644
--- a/pyasn1/codec/cer/decoder.py
+++ b/pyasn1/codec/cer/decoder.py
@@ -1,6 +1,7 @@
# CER decoder
from pyasn1.type import univ
from pyasn1.codec.ber import decoder
+from pyasn1.compat.octets import oct2int
from pyasn1 import error
class BooleanDecoder(decoder.AbstractSimpleDecoder):
@@ -10,7 +11,7 @@ class BooleanDecoder(decoder.AbstractSimpleDecoder):
substrate = substrate[:length]
if not substrate:
raise error.PyAsn1Error('Empty substrate')
- byte = ord(substrate[0])
+ byte = oct2int(substrate[0])
if byte == 0xff:
value = 1
elif byte == 0x00:
diff --git a/pyasn1/codec/cer/encoder.py b/pyasn1/codec/cer/encoder.py
index 8fed5d1..4c05130 100644
--- a/pyasn1/codec/cer/encoder.py
+++ b/pyasn1/codec/cer/encoder.py
@@ -1,13 +1,14 @@
# CER encoder
from pyasn1.type import univ
from pyasn1.codec.ber import encoder
+from pyasn1.compat.octets import int2oct, null
class BooleanEncoder(encoder.IntegerEncoder):
def encodeValue(self, encodeFun, client, defMode, maxChunkSize):
if client == 0:
- substrate = '\000'
+ substrate = int2oct(0)
else:
- substrate = '\377'
+ substrate = int2oct(255)
return substrate, 0
class BitStringEncoder(encoder.BitStringEncoder):
@@ -32,7 +33,7 @@ class SetOfEncoder(encoder.SequenceOfEncoder):
if isinstance(client, univ.SequenceAndSetBase):
client.setDefaultComponents()
client.verifySizeSpec()
- substrate = ''; idx = len(client)
+ substrate = null; idx = len(client)
# This is certainly a hack but how else do I distinguish SetOf
# from Set if they have the same tags&constraints?
if isinstance(client, univ.SequenceAndSetBase):
@@ -48,7 +49,7 @@ class SetOfEncoder(encoder.SequenceOfEncoder):
comps.sort(key=lambda x: isinstance(x, univ.Choice) and \
x.getMinTagSet() or x.getTagSet())
for c in comps:
- substrate = substrate + encodeFun(c, defMode, maxChunkSize)
+ substrate += encodeFun(c, defMode, maxChunkSize)
else:
# SetOf
compSubs = []
@@ -58,7 +59,9 @@ class SetOfEncoder(encoder.SequenceOfEncoder):
encodeFun(client[idx], defMode, maxChunkSize)
)
compSubs.sort() # perhaps padding's not needed
- substrate = ''.join(compSubs)
+ substrate = null
+ for compSub in compSubs:
+ substrate += compSub
return substrate, 1
tagMap = encoder.tagMap.copy()
diff --git a/pyasn1/compat/__init__.py b/pyasn1/compat/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pyasn1/compat/__init__.py
diff --git a/pyasn1/compat/octets.py b/pyasn1/compat/octets.py
new file mode 100644
index 0000000..d0303ea
--- /dev/null
+++ b/pyasn1/compat/octets.py
@@ -0,0 +1,18 @@
+from sys import version_info
+
+if version_info[0] <= 2:
+ int2oct = chr
+ ints2octs = lambda s: ''.join([ int2oct(x) for x in s ])
+ null = ''
+ oct2int = ord
+ octs2ints = lambda s: [ oct2int(x) for x in s ]
+ str2octs = lambda x: x
+ octs2str = lambda x: x
+else:
+ ints2octs = bytes
+ int2oct = lambda x: ints2octs((x,))
+ null = ints2octs()
+ oct2int = lambda x: x
+ octs2ints = lambda s: [ x for x in s ]
+ str2octs = lambda x: x.encode()
+ octs2str = lambda x: x.decode()
diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py
index 97ead1e..15f998a 100644
--- a/pyasn1/type/univ.py
+++ b/pyasn1/type/univ.py
@@ -258,20 +258,51 @@ class OctetString(base.AbstractSimpleAsn1Item):
tagSet = baseTagSet = tag.initTagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04)
)
- def prettyOut(self, value): return repr(value)
- def prettyIn(self, value):
- if isinstance(value, str):
- return value
- else:
- return str(value)
+ if sys.version_info[0] <= 2:
+ def prettyIn(self, value):
+ if isinstance(value, str):
+ return value
+ elif isinstance(value, OctetString):
+ return value.asBytes()
+ else:
+ return str(value)
+ def purePrettyIn(self, value):
+ if not isinstance(value, str):
+ return str(value)
+ elif not value:
+ return value
+ else:
+ r = self.__parseBinHex(value)
+ if r is None:
+ return value
+ else:
+ return ''.join([chr(x) for x in r])
+ else:
+ def prettyIn(self, value):
+ if isinstance(value, bytes):
+ return value
+ elif isinstance(value, OctetString):
+ return value.asBytes()
+ else:
+ return str(value).encode()
+ def purePrettyIn(self, value):
+ if isinstance(value, bytes):
+ return value
+ elif isinstance(value, OctetString):
+ return value.asBytes()
+ elif not value:
+ return value.encode()
+ else:
+ value = str(value)
+ r = self.__parseBinHex(str(value))
+ if r is None:
+ return value.encode()
+ else:
+ return bytes(r)
- def purePrettyIn(self, value):
- if not isinstance(value, str):
- return str(value)
- elif not value:
- return value
- elif value[0] == '\'':
- r = ''
+ def __parseBinHex(value):
+ if value[0] == '\'':
+ r = ()
if value[-2:] == '\'B':
bitNo = 8; byte = 0
for v in value[1:-2]:
@@ -279,7 +310,7 @@ class OctetString(base.AbstractSimpleAsn1Item):
bitNo = bitNo - 1
else:
bitNo = 7
- r = r + chr(byte)
+ r = r + (byte,)
byte = 0
if v == '0':
v = 0
@@ -290,25 +321,29 @@ class OctetString(base.AbstractSimpleAsn1Item):
'Non-binary OCTET STRING initializer %s' % (v,)
)
byte = byte | (v << bitNo)
- r = r + chr(byte)
+ r = r + (byte,)
elif value[-2:] == '\'H':
- p = ''
+ p = ()
for v in value[1:-2]:
if p:
- r = r + chr(int(p+v, 16))
- p = ''
+ r = r + (int(p+v, 16),)
+ p = ()
else:
p = v
if p:
- r = r + chr(int(p+'0', 16))
+ r = r + (int(p+'0', 16),)
else:
raise error.PyAsn1Error(
'Bad OCTET STRING value notation %s' % value
)
return r
- else:
- return value
+
+ def prettyOut(self, value): return repr(value)
+ def asBytes(self): return self._value
+
+ def __str__(self): return self._value.decode()
+
# Immutable sequence object protocol
def __len__(self):
@@ -321,17 +356,17 @@ class OctetString(base.AbstractSimpleAsn1Item):
else:
return self._value[i]
- def __add__(self, value): return self.clone(self._value + value)
- def __radd__(self, value): return self.clone(value + self._value)
+ def __add__(self, value): return self.clone(self._value + self.prettyIn(value))
+ def __radd__(self, value): return self.clone(self.prettyIn(value) + self._value)
def __mul__(self, value): return self.clone(self._value * value)
def __rmul__(self, value): return self * value
class Null(OctetString):
- defaultValue = '' # This is tightly constrained
+ defaultValue = ''.encode() # This is tightly constrained
tagSet = baseTagSet = tag.initTagSet(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05)
)
- subtypeSpec = OctetString.subtypeSpec+constraint.SingleValueConstraint('')
+ subtypeSpec = OctetString.subtypeSpec+constraint.SingleValueConstraint(''.encode())
class ObjectIdentifier(base.AbstractSimpleAsn1Item):
tagSet = baseTagSet = tag.initTagSet(
@@ -405,6 +440,11 @@ class ObjectIdentifier(base.AbstractSimpleAsn1Item):
r[-1][-1] = r[-1][:-1]
return '.'.join(r)
+if sys.version_info[0] <= 2:
+ intTypes = (int, long)
+else:
+ intTypes = int
+
class Real(base.AbstractSimpleAsn1Item):
_plusInf = float('inf')
_minusInf = float('-inf')
@@ -420,15 +460,10 @@ class Real(base.AbstractSimpleAsn1Item):
e = e + 1
return m, b, e
- if sys.version_info[0] <= 2:
- _intTypes = (int, long)
- else:
- _intTypes = int
-
def prettyIn(self, value):
if isinstance(value, tuple) and len(value) == 3:
for d in value:
- if not isinstance(d, self._intTypes):
+ if not isinstance(d, intTypes):
raise error.PyAsn1Error(
'Lame Real value syntax: %s' % (value,)
)
@@ -439,7 +474,7 @@ class Real(base.AbstractSimpleAsn1Item):
if value[1] == 10:
value = self.__normalizeBase10(value)
return value
- elif isinstance(value, self._intTypes):
+ elif isinstance(value, intTypes):
return self.__normalizeBase10((value, 10, 0))
elif isinstance(value, float):
if value in self._inf: