You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
5.8 KiB
188 lines
5.8 KiB
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)
|