aboutsummaryrefslogtreecommitdiff
path: root/pyasn1/compat
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2017-02-24 18:13:04 +0100
committerIlya Etingof <etingof@gmail.com>2017-02-24 18:13:04 +0100
commit679408903afee6d76b682376aedf0eeee496b627 (patch)
tree7e49e98eae8272e5d3482bf2b24161c8f5535857 /pyasn1/compat
parent61ceeae369e0e41b6b8e57437430200418b51bef (diff)
downloadpyasn1-679408903afee6d76b682376aedf0eeee496b627.tar.gz
BitString type and codecs reimplemented
Targeting high-performance and convenience to use. Sampling just BitString en/decoding performance -- new implementation is 100x faster. ;-\
Diffstat (limited to 'pyasn1/compat')
-rw-r--r--pyasn1/compat/integer.py96
1 files changed, 96 insertions, 0 deletions
diff --git a/pyasn1/compat/integer.py b/pyasn1/compat/integer.py
new file mode 100644
index 0000000..ae9c7e1
--- /dev/null
+++ b/pyasn1/compat/integer.py
@@ -0,0 +1,96 @@
+#
+# This file is part of pyasn1 software.
+#
+# Copyright (c) 2005-2017, Ilya Etingof <etingof@gmail.com>
+# License: http://pyasn1.sf.net/license.html
+#
+import sys
+if sys.version_info[0:2] < (3, 2):
+ from binascii import a2b_hex, b2a_hex
+from pyasn1.compat.octets import oct2int, null
+
+if sys.version_info[0:2] < (3, 2):
+ def from_bytes(octets, signed=False):
+ value = long(b2a_hex(str(octets)), 16)
+
+ if signed and oct2int(octets[0]) & 0x80:
+ return value - (1 << len(octets) * 8)
+
+ return value
+
+ def to_bytes(value, signed=False, length=0):
+ if value < 0:
+ if signed:
+ bits = bitLength(value)
+
+ # two's complement form
+ maxValue = 1 << bits
+ valueToEncode = (value + maxValue) % maxValue
+
+ else:
+ raise OverflowError('can\'t convert negative int to unsigned')
+ elif value == 0 and length == 0:
+ return null
+ else:
+ bits = 0
+ valueToEncode = value
+
+ hexValue = hex(valueToEncode)[2:]
+ if hexValue.endswith('L'):
+ hexValue = hexValue[:-1]
+
+ if len(hexValue) & 1:
+ hexValue = '0' + hexValue
+
+ # padding may be needed for two's complement encoding
+ if value != valueToEncode or length:
+ hexLength = len(hexValue) * 4
+
+ padLength = max(length, bits)
+
+ if padLength > hexLength:
+ hexValue = '00' * ((padLength - hexLength - 1) // 8 + 1) + hexValue
+ elif length and hexLength - length > 7:
+ raise OverflowError('int too big to convert')
+
+ firstOctet = int(hexValue[:2], 16)
+
+ if signed:
+ if firstOctet & 0x80:
+ if value >= 0:
+ hexValue = '00' + hexValue
+ elif value < 0:
+ hexValue = 'ff' + hexValue
+
+ octets_value = a2b_hex(hexValue)
+
+ return octets_value
+
+ def bitLength(number):
+ # bits in unsigned number
+ hexValue = hex(abs(number))
+ bits = len(hexValue) - 2
+ if hexValue.endswith('L'):
+ bits -= 1
+ if bits & 1:
+ bits += 1
+ bits *= 4
+ # TODO: strip lhs zeros
+ return bits
+
+else:
+
+ def from_bytes(octets, signed=False):
+ return int.from_bytes(bytes(octets), 'big', signed=signed)
+
+ def to_bytes(value, signed=False, length=0):
+ length = max(value.bit_length(), length)
+
+ if signed and length % 8 == 0:
+ length += 1
+
+ return value.to_bytes(length // 8 + (length % 8 and 1 or 0), 'big', signed=signed)
+
+ def bitLength(number):
+ return int(number).bit_length()
+