1#
2# This file is part of pyasn1 software.
3#
4# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
5# License: http://snmplabs.com/pyasn1/license.html
6#
7import sys
8
9try:
10    import platform
11
12    implementation = platform.python_implementation()
13
14except (ImportError, AttributeError):
15    implementation = 'CPython'
16
17from pyasn1.compat.octets import oct2int, null, ensureString
18
19if sys.version_info[0:2] < (3, 2) or implementation != 'CPython':
20    from binascii import a2b_hex, b2a_hex
21
22    if sys.version_info[0] > 2:
23        long = int
24
25    def from_bytes(octets, signed=False):
26        if not octets:
27            return 0
28
29        value = long(b2a_hex(ensureString(octets)), 16)
30
31        if signed and oct2int(octets[0]) & 0x80:
32            return value - (1 << len(octets) * 8)
33
34        return value
35
36    def to_bytes(value, signed=False, length=0):
37        if value < 0:
38            if signed:
39                bits = bitLength(value)
40
41                # two's complement form
42                maxValue = 1 << bits
43                valueToEncode = (value + maxValue) % maxValue
44
45            else:
46                raise OverflowError('can\'t convert negative int to unsigned')
47        elif value == 0 and length == 0:
48            return null
49        else:
50            bits = 0
51            valueToEncode = value
52
53        hexValue = hex(valueToEncode)[2:]
54        if hexValue.endswith('L'):
55            hexValue = hexValue[:-1]
56
57        if len(hexValue) & 1:
58            hexValue = '0' + hexValue
59
60        # padding may be needed for two's complement encoding
61        if value != valueToEncode or length:
62            hexLength = len(hexValue) * 4
63
64            padLength = max(length, bits)
65
66            if padLength > hexLength:
67                hexValue = '00' * ((padLength - hexLength - 1) // 8 + 1) + hexValue
68            elif length and hexLength - length > 7:
69                raise OverflowError('int too big to convert')
70
71        firstOctet = int(hexValue[:2], 16)
72
73        if signed:
74            if firstOctet & 0x80:
75                if value >= 0:
76                    hexValue = '00' + hexValue
77            elif value < 0:
78                hexValue = 'ff' + hexValue
79
80        octets_value = a2b_hex(hexValue)
81
82        return octets_value
83
84    def bitLength(number):
85        # bits in unsigned number
86        hexValue = hex(abs(number))
87        bits = len(hexValue) - 2
88        if hexValue.endswith('L'):
89            bits -= 1
90        if bits & 1:
91            bits += 1
92        bits *= 4
93        # TODO: strip lhs zeros
94        return bits
95
96else:
97
98    def from_bytes(octets, signed=False):
99        return int.from_bytes(bytes(octets), 'big', signed=signed)
100
101    def to_bytes(value, signed=False, length=0):
102        length = max(value.bit_length(), length)
103
104        if signed and length % 8 == 0:
105            length += 1
106
107        return value.to_bytes(length // 8 + (length % 8 and 1 or 0), 'big', signed=signed)
108
109    def bitLength(number):
110        return int(number).bit_length()
111