diff options
author | Livio Recchia <recchialivio@libero.it> | 2020-02-10 23:06:34 +0100 |
---|---|---|
committer | Livio Recchia <recchialivio@libero.it> | 2020-02-10 23:06:34 +0100 |
commit | 9a13903a2f7d3a65fdf15a65fb59cccd622e2066 (patch) | |
tree | 9403b7dff39eb5e5d7fa0f79efb69b496add4c4b /external/construct/lib/binary.py | |
parent | 11cc316b74d5f3f283413a33e7693b314741aa4a (diff) | |
download | manachat-9a13903a2f7d3a65fdf15a65fb59cccd622e2066.tar.gz manachat-9a13903a2f7d3a65fdf15a65fb59cccd622e2066.tar.bz2 manachat-9a13903a2f7d3a65fdf15a65fb59cccd622e2066.tar.xz manachat-9a13903a2f7d3a65fdf15a65fb59cccd622e2066.zip |
Initial commit
Diffstat (limited to 'external/construct/lib/binary.py')
-rw-r--r-- | external/construct/lib/binary.py | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/external/construct/lib/binary.py b/external/construct/lib/binary.py new file mode 100644 index 0000000..c5ef9b3 --- /dev/null +++ b/external/construct/lib/binary.py @@ -0,0 +1,187 @@ +import six +from construct.lib.py3compat import int2byte + + +if six.PY3: + def int_to_bin(number, width = 32): + r""" + Convert an integer into its binary representation in a bytes object. + Width is the amount of bits to generate. If width is larger than the actual + amount of bits required to represent number in binary, sign-extension is + used. If it's smaller, the representation is trimmed to width bits. + Each "bit" is either '\x00' or '\x01'. The MSBit is first. + + Examples: + + >>> int_to_bin(19, 5) + b'\x01\x00\x00\x01\x01' + >>> int_to_bin(19, 8) + b'\x00\x00\x00\x01\x00\x00\x01\x01' + """ + number = int(number) + if number < 0: + number += 1 << width + i = width - 1 + bits = bytearray(width) + while number and i >= 0: + bits[i] = number & 1 + number >>= 1 + i -= 1 + return bytes(bits) + + # heavily optimized for performance + def bin_to_int(bits, signed = False): + r""" + Logical opposite of int_to_bin. Both '0' and '\x00' are considered zero, + and both '1' and '\x01' are considered one. Set sign to True to interpret + the number as a 2-s complement signed integer. + """ + bits = "".join("01"[b & 1] for b in bits) + if signed and bits[0] == "1": + bits = bits[1:] + bias = 1 << len(bits) + else: + bias = 0 + return int(bits, 2) - bias + + _char_to_bin = [0] * 256 + _bin_to_char = {} + for i in range(256): + ch = int2byte(i) + bin = int_to_bin(i, 8) + # Populate with for both keys i and ch, to support Python 2 & 3 + _char_to_bin[i] = bin + _bin_to_char[bin] = ord(ch) + + def encode_bin(data): + """ + Create a binary representation of the given b'' object. Assume 8-bit + ASCII. Example: + + >>> encode_bin('ab') + b"\x00\x01\x01\x00\x00\x00\x00\x01\x00\x01\x01\x00\x00\x00\x01\x00" + """ + return six.b("").join(_char_to_bin[int(ch)] for ch in data) + + def decode_bin(data): + if len(data) & 7: + raise ValueError("Data length must be a multiple of 8") + i = 0 + j = 0 + l = len(data) // 8 + arr = bytearray(l) + while j < l: + arr[j] = _bin_to_char[data[i:i+8]] + i += 8 + j += 1 + return arr + + def swap_bytes(bits, bytesize=8): + r""" + Bits is a b'' object containing a binary representation. Assuming each + bytesize bits constitute a bytes, perform a endianness byte swap. Example: + + >>> swap_bytes(b'00011011', 2) + b'11100100' + """ + i = 0 + l = len(bits) + output = [six.b("")] * ((l // bytesize) + 1) + j = len(output) - 1 + while i < l: + output[j] = bits[i : i + bytesize] + i += bytesize + j -= 1 + return six.b("").join(output) + +else: + + def int_to_bin(number, width = 32): + r""" + Convert an integer into its binary representation in a bytes object. + Width is the amount of bits to generate. If width is larger than the actual + amount of bits required to represent number in binary, sign-extension is + used. If it's smaller, the representation is trimmed to width bits. + Each "bit" is either '\x00' or '\x01'. The MSBit is first. + + Examples: + + >>> int_to_bin(19, 5) + '\x01\x00\x00\x01\x01' + >>> int_to_bin(19, 8) + '\x00\x00\x00\x01\x00\x00\x01\x01' + """ + if number < 0: + number += 1 << width + i = width - 1 + bits = ["\x00"] * width + while number and i >= 0: + bits[i] = "\x00\x01"[number & 1] + number >>= 1 + i -= 1 + return "".join(bits) + + # heavily optimized for performance + def bin_to_int(bits, signed = False): + r""" + Logical opposite of int_to_bin. Both '0' and '\x00' are considered zero, + and both '1' and '\x01' are considered one. Set sign to True to interpret + the number as a 2-s complement signed integer. + """ + bits = "".join("01"[ord(b) & 1] for b in bits) + if signed and bits[0] == "1": + bits = bits[1:] + bias = 1 << len(bits) + else: + bias = 0 + return int(bits, 2) - bias + + _char_to_bin = [0] * 256 + _bin_to_char = {} + for i in range(256): + ch = int2byte(i) + bin = int_to_bin(i, 8) + # Populate with for both keys i and ch, to support Python 2 & 3 + _char_to_bin[i] = bin + _bin_to_char[bin] = ch + + def encode_bin(data): + """ + Create a binary representation of the given b'' object. Assume 8-bit + ASCII. Example: + + >>> encode_bin('ab') + b"\x00\x01\x01\x00\x00\x00\x00\x01\x00\x01\x01\x00\x00\x00\x01\x00" + """ + return "".join(_char_to_bin[ord(ch)] for ch in data) + + def decode_bin(data): + if len(data) & 7: + raise ValueError("Data length must be a multiple of 8") + i = 0 + j = 0 + l = len(data) // 8 + chars = [""] * l + while j < l: + chars[j] = _bin_to_char[data[i:i+8]] + i += 8 + j += 1 + return "".join(chars) + + def swap_bytes(bits, bytesize=8): + r""" + Bits is a b'' object containing a binary representation. Assuming each + bytesize bits constitute a bytes, perform a endianness byte swap. Example: + + >>> swap_bytes(b'00011011', 2) + b'11100100' + """ + i = 0 + l = len(bits) + output = [""] * ((l // bytesize) + 1) + j = len(output) - 1 + while i < l: + output[j] = bits[i : i + bytesize] + i += bytesize + j -= 1 + return "".join(output) |