diff options
author | elie <elie> | 2011-10-04 11:16:59 +0000 |
---|---|---|
committer | elie <elie> | 2011-10-04 11:16:59 +0000 |
commit | 85987e51ce099576aedc6740f0128dabe269fc81 (patch) | |
tree | 0a807d95aa36ec59b792415806ccc61fd353e8e1 | |
parent | 18592e68d1db5300a7a275d623ad92dcb5bea6fe (diff) | |
download | pyasn1-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.py | 31 | ||||
-rw-r--r-- | pyasn1/codec/ber/encoder.py | 80 | ||||
-rw-r--r-- | pyasn1/codec/cer/decoder.py | 3 | ||||
-rw-r--r-- | pyasn1/codec/cer/encoder.py | 13 | ||||
-rw-r--r-- | pyasn1/compat/__init__.py | 0 | ||||
-rw-r--r-- | pyasn1/compat/octets.py | 18 | ||||
-rw-r--r-- | pyasn1/type/univ.py | 99 |
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: |