| # |
| # 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 |
| try: |
| import platform |
| implementation = platform.python_implementation() |
| |
| except (ImportError, AttributeError): |
| implementation = 'CPython' |
| |
| from pyasn1.compat.octets import oct2int, null, ensureString |
| |
| if sys.version_info[0:2] < (3, 2) or implementation != 'CPython': |
| from binascii import a2b_hex, b2a_hex |
| |
| if sys.version_info[0] > 2: |
| long = int |
| |
| def from_bytes(octets, signed=False): |
| if not octets: |
| return 0 |
| |
| value = long(b2a_hex(ensureString(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() |
| |