|
|
|
@ -1,16 +1,218 @@
@@ -1,16 +1,218 @@
|
|
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
""" |
|
|
|
|
============================ |
|
|
|
|
Binary manipulation classes |
|
|
|
|
============================ |
|
|
|
|
|
|
|
|
|
Provides classes that assist in managing, comparing, transforming and working |
|
|
|
|
with binary data in general. |
|
|
|
|
|
|
|
|
|
----------------- |
|
|
|
|
Provided Classes |
|
|
|
|
----------------- |
|
|
|
|
|
|
|
|
|
Bit |
|
|
|
|
=== |
|
|
|
|
The Bit is the smallest representation of binary data and represents True or |
|
|
|
|
False. This class provides methods to perform binary comparisons and |
|
|
|
|
conversions between different types that can be used to represent a single |
|
|
|
|
binary value. |
|
|
|
|
|
|
|
|
|
Bits |
|
|
|
|
==== |
|
|
|
|
A Byte is the representation of 8 Bits. The Byte class provides methods to |
|
|
|
|
compare a single binary Byte to other data types. The Class also provides |
|
|
|
|
binary math functions and allows getting and setting the state of individual |
|
|
|
|
Bits. |
|
|
|
|
|
|
|
|
|
Bytes |
|
|
|
|
===== |
|
|
|
|
The Bytes class allows an arbitrary amount of binary data to be represented. |
|
|
|
|
The Bytes class provides access to each byte using the Byte class, which |
|
|
|
|
further allows all the methods to be used on the binary data provided by the |
|
|
|
|
Byte and Bit classes. Bytes can be compared and converted between several |
|
|
|
|
different data types. |
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
class Bit: |
|
|
|
|
""" |
|
|
|
|
Provide a flexible bit representation |
|
|
|
|
==== |
|
|
|
|
Bit |
|
|
|
|
==== |
|
|
|
|
|
|
|
|
|
A single binary bit representation of True or False |
|
|
|
|
|
|
|
|
|
A Bit object can be compared and converted to int, str, bool and other Bit |
|
|
|
|
objects. The Bit class is backed by a single bool variable. This backing |
|
|
|
|
bool object is converted as necessary to provide conversions and |
|
|
|
|
comparisons with other data types. Keep this in mind as converting an |
|
|
|
|
object to Bit and then attempting to convert back to the original object |
|
|
|
|
may not yield the exact same value. |
|
|
|
|
|
|
|
|
|
In the case of comparisons, the object being compared is cast as a Bit |
|
|
|
|
object, and the two Bit objects are then compared with each other and the |
|
|
|
|
result of the comparison is returned. |
|
|
|
|
|
|
|
|
|
---------------- |
|
|
|
|
Type Conversion |
|
|
|
|
---------------- |
|
|
|
|
The objects that can be converted to and from a Bit include *bool*, *int*, |
|
|
|
|
*str* and other *Bit* objects. |
|
|
|
|
|
|
|
|
|
Convert *bool* to *Bit*: |
|
|
|
|
.. code-block:: python |
|
|
|
|
|
|
|
|
|
/>/>/> a_bit = Bit(True) |
|
|
|
|
/>/>/> a_bit |
|
|
|
|
Bit(1) |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
Convert *Bit* to *bool*: |
|
|
|
|
.. code-block:: python |
|
|
|
|
|
|
|
|
|
/>/>/> a_bool = bool(Bit(True)) |
|
|
|
|
/>/>/> a_bool |
|
|
|
|
True |
|
|
|
|
/>/>/> type(a_bool) |
|
|
|
|
<class 'bool'> |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
Convert *int* to *Bit*: |
|
|
|
|
.. code-block:: python |
|
|
|
|
|
|
|
|
|
/>/>/> unset_bit = Bit(0) |
|
|
|
|
/>/>/> unset_bit |
|
|
|
|
Bit(0) |
|
|
|
|
/>/>/> set_bit = Bit(1) |
|
|
|
|
/>/>/> set_bit |
|
|
|
|
Bit(1) |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
Convert *Bit* to *int*: |
|
|
|
|
.. code-block:: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_int = int(Bit(1)) |
|
|
|
|
/>/>/> my_int |
|
|
|
|
1 |
|
|
|
|
/>/>/> type(my_int) |
|
|
|
|
<class 'int'> |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
.. note:: The only values allowed for *int* are **0** and **1** |
|
|
|
|
|
|
|
|
|
Convert *str* to *Bit*: |
|
|
|
|
.. code-block:: python |
|
|
|
|
|
|
|
|
|
/>/>/> unset_bit = Bit("0") |
|
|
|
|
/>/>/> unset_bit |
|
|
|
|
Bit(0) |
|
|
|
|
/>/>/> set_bit = Bit("1") |
|
|
|
|
/>/>/> set_bit |
|
|
|
|
Bit(1) |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
Convert *Bit* to *str*: |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_str = str(Bit(False)) |
|
|
|
|
/>/>/> my_str |
|
|
|
|
'0' |
|
|
|
|
/>/>/> type(my_str) |
|
|
|
|
<class 'str'> |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
.. note:: The only *str* characters allowed are a single **0** or **1** |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
------------ |
|
|
|
|
Comparisons |
|
|
|
|
------------ |
|
|
|
|
A Bit object can be compared to any object which can be cast to a Bit |
|
|
|
|
|
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> 0 == Bit(False) == Bit("0") == Bit(0) == False |
|
|
|
|
True |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
.. note:: Comparing an object with a value that cannot be cast to Bit will |
|
|
|
|
return a ValueError. |
|
|
|
|
|
|
|
|
|
----------------- |
|
|
|
|
Rich Comparisons |
|
|
|
|
----------------- |
|
|
|
|
Bit objects also support "rich comparisons". For example: |
|
|
|
|
|
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> Bit(False) < 1 |
|
|
|
|
True |
|
|
|
|
/>/>/> Bit(True) <= 1 |
|
|
|
|
True |
|
|
|
|
/>/>/> Bit(False) <= "1" |
|
|
|
|
True |
|
|
|
|
/>/>/> Bit(False) != True |
|
|
|
|
True |
|
|
|
|
/>/>/> Bit(True) >= False |
|
|
|
|
False |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-------- |
|
|
|
|
Methods |
|
|
|
|
-------- |
|
|
|
|
The action method `toggle` is provided for convenience. |
|
|
|
|
|
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> Bit(False).toggle() |
|
|
|
|
Bit(1) |
|
|
|
|
/>/>/> Bit(True).toggle() == False |
|
|
|
|
True |
|
|
|
|
/>/>/> int(Bit(False).toggle()) |
|
|
|
|
1 |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
The `set` and `unset` methods are also provided to explicitely set the |
|
|
|
|
value of Bit. |
|
|
|
|
|
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> a_bit = Bit(0) |
|
|
|
|
/>/>/> a_bit |
|
|
|
|
Bit(0) |
|
|
|
|
/>/>/> a_bit.set() |
|
|
|
|
/>/>/> a_bit |
|
|
|
|
Bit(1) |
|
|
|
|
/>/>/> a_bit.unset() |
|
|
|
|
/>/>/> a_bit |
|
|
|
|
Bit(0) |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
----------- |
|
|
|
|
Properties |
|
|
|
|
----------- |
|
|
|
|
The `lie` property returns the opposite value of Bit as a *bool*. Unlike |
|
|
|
|
the `toggle` method, `lie` does not change the value of the Bit. |
|
|
|
|
|
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> Bit(1).lie |
|
|
|
|
False |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, var): |
|
|
|
|
""" |
|
|
|
|
var: Any supported type |
|
|
|
|
Supported types: (bool, int, str, Bit) |
|
|
|
|
bool: True or False |
|
|
|
|
int: 0 = False, anything else = True |
|
|
|
|
str: "0" = False, anything else = True |
|
|
|
|
int: 0 = False, 1 = True |
|
|
|
|
str: "0" = False, "1" = True |
|
|
|
|
Bit: Bit = Bit |
|
|
|
|
""" |
|
|
|
|
if not isinstance(var, (bool, int, str, Bit)): |
|
|
|
@ -28,25 +230,22 @@ class Bit:
@@ -28,25 +230,22 @@ class Bit:
|
|
|
|
|
self.__bit = var |
|
|
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
|
""" |
|
|
|
|
Return "0" or "1" |
|
|
|
|
""" |
|
|
|
|
"""Return '0' or '1'""" |
|
|
|
|
return str(int(self.__bit)) |
|
|
|
|
|
|
|
|
|
def __int__(self): |
|
|
|
|
"""Return 0 or 1""" |
|
|
|
|
return int(self.__bit) |
|
|
|
|
|
|
|
|
|
def __bool__(self): |
|
|
|
|
"""Returns True or False""" |
|
|
|
|
return self.__bit |
|
|
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
|
return f'{self.__class__.__name__}({int(self.__bit)})' |
|
|
|
|
|
|
|
|
|
def __eq__(self, compare): |
|
|
|
|
""" |
|
|
|
|
compare (self) to any supported object |
|
|
|
|
""" |
|
|
|
|
# Massage compare to bool |
|
|
|
|
"""compare (self) to any supported object""" |
|
|
|
|
return bool(self) == bool(Bit(compare)) |
|
|
|
|
|
|
|
|
|
def __ne__(self, compare): |
|
|
|
@ -68,28 +267,257 @@ class Bit:
@@ -68,28 +267,257 @@ class Bit:
|
|
|
|
|
return self.__bit |
|
|
|
|
|
|
|
|
|
def __hash__(self): |
|
|
|
|
""" |
|
|
|
|
Not very useful, but provided nonetheless |
|
|
|
|
""" |
|
|
|
|
"""Not very useful, but provided nonetheless""" |
|
|
|
|
return hash(self.__bit) |
|
|
|
|
|
|
|
|
|
def toggle(self): |
|
|
|
|
""" |
|
|
|
|
(self) = Not (Self) |
|
|
|
|
""" |
|
|
|
|
"""Change the state of (self) to Not (self)""" |
|
|
|
|
self.__bit = not self.__bit |
|
|
|
|
|
|
|
|
|
def set(self): |
|
|
|
|
"""Set Bit to True""" |
|
|
|
|
self.__bit = True |
|
|
|
|
|
|
|
|
|
def unset(self): |
|
|
|
|
"""Set Bit to False""" |
|
|
|
|
self.__bit = False |
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
def lie(self): |
|
|
|
|
""" |
|
|
|
|
Return the opposite of bit, without changing the state of (self) |
|
|
|
|
""" |
|
|
|
|
"""Return the opposite of bit, without changing the state of (self)""" |
|
|
|
|
return not self.__bit |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Bits: |
|
|
|
|
""" |
|
|
|
|
Provide bit operation helpers. |
|
|
|
|
===== |
|
|
|
|
Bits |
|
|
|
|
===== |
|
|
|
|
|
|
|
|
|
A single byte of data with helper methods and properties. |
|
|
|
|
|
|
|
|
|
A Bits object provides many helpful methods for working with a byte of |
|
|
|
|
information. The backing object is a single int, from which all operations |
|
|
|
|
and conversions are performed. A Bits object can be converted and compared |
|
|
|
|
to *bytes*, *int*, *str*, *list(of Bit)*, *bool* and other *Bits* objects. |
|
|
|
|
The custom object *Bytes* can also be cast to a Bits object, as long as the |
|
|
|
|
*Bytes* object has an *int* value >= **0** and <= **255**. |
|
|
|
|
|
|
|
|
|
When comparing or operating on *Bits* objects with objects of a different |
|
|
|
|
type, the *operand* object will first be cast to a Bits object. In this |
|
|
|
|
way, any object which can be used to create a *Bits* object can also be |
|
|
|
|
used to perform operations with *Bits*. |
|
|
|
|
|
|
|
|
|
---------------- |
|
|
|
|
Type Conversion |
|
|
|
|
---------------- |
|
|
|
|
The objects that can be converted to and from *Bits* include *bytes*, |
|
|
|
|
*int*, *str*, *list*, *bool* and other *Bits* objects. When using a list, |
|
|
|
|
the length of the list must be 8 or less, each list item must be castable |
|
|
|
|
to *int*, and each item will be evaluated as either *True* or *False*. |
|
|
|
|
|
|
|
|
|
Convert *bool* to *Bits*: |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_bits = Bits(True) |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(1) |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
Convert *bytes* to *Bits*: |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_bits = Bits(b'\\xab') |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(171) |
|
|
|
|
/>/>/> my_bits = Bits(bytes([210])) |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(210) |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
Convert *int* to *Bits*: |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_bits = Bits(234) |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(234) |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
Convert *str* to *Bits*: |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_bits = Bits("01010101") |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(85) |
|
|
|
|
/>/>/> my_bits = Bits("11") |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(3) |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
Convert *list* to *Bits*: |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_bits = Bits(["0", "1", "0", "1", "0", "1", "0", "1"]) |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(85) |
|
|
|
|
/>/>/> my_bits = Bits([0, 1, 0, 1, 0, 1, 0, 1]) |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(85) |
|
|
|
|
/>/>/> my_bits = Bits([False, True, False, True, False, True]) |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(21) |
|
|
|
|
/>/>/> my_bits = Bits([True, True]) |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(3) |
|
|
|
|
/>/>/> my_bits = Bits([0, "1", False, True, "0", Bit(1), Bit(0), 127]) |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(85) |
|
|
|
|
|
|
|
|
|
.. note:: Each item in a list will be evaluated to either True or False. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
------------- |
|
|
|
|
Type Casting |
|
|
|
|
------------- |
|
|
|
|
Bits objects support casting to multiple different types. |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_bits = Bits(16) |
|
|
|
|
/>/>/> str(my_bits) |
|
|
|
|
'00010000' |
|
|
|
|
/>/>/> int(my_bits) |
|
|
|
|
16 |
|
|
|
|
/>/>/> bin(my_bits) |
|
|
|
|
'0b10000' |
|
|
|
|
/>/>/> bool(my_bits) |
|
|
|
|
True |
|
|
|
|
/>/>/> list(my_bits) |
|
|
|
|
[Bit(0), Bit(0), Bit(0), Bit(1), Bit(0), Bit(0), Bit(0), Bit(0)] |
|
|
|
|
/>/>/> bytes(my_bits) |
|
|
|
|
b'\x10' |
|
|
|
|
/>/>/> bytearray([my_bits]) |
|
|
|
|
bytearray(b'\x10') |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
------------- |
|
|
|
|
Subscripting |
|
|
|
|
------------- |
|
|
|
|
Subscripting can be used to query or modify each Bit. |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_bits = Bits('01101110') |
|
|
|
|
/>/>/> my_bits[3] |
|
|
|
|
Bit(0) |
|
|
|
|
/>/>/> my_bits[3] = True |
|
|
|
|
/>/>/> my_bits[3] |
|
|
|
|
Bit(1) |
|
|
|
|
/>/>/> str(my_bits) |
|
|
|
|
'01111110') |
|
|
|
|
/>/>/> list(my_bits) |
|
|
|
|
[Bit(0), Bit(1), Bit(1), Bit(1), Bit(1), Bit(1), Bit(1), Bit(0)] |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
------------ |
|
|
|
|
Comparisons |
|
|
|
|
------------ |
|
|
|
|
Bits objects can be compared to any object which can be cast to a Bits |
|
|
|
|
object. This goes both ways. |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_bits = Bits('01101110') |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(110) |
|
|
|
|
/>/>/> 110 == my_bits |
|
|
|
|
True |
|
|
|
|
/>/>/> 111 == my_bits |
|
|
|
|
False |
|
|
|
|
/>/>/> 111 > my_bits |
|
|
|
|
True |
|
|
|
|
/>/>/> my_bits > 112 |
|
|
|
|
False |
|
|
|
|
/>/>/> b'n' == my_bits |
|
|
|
|
True |
|
|
|
|
/>/>/> my_bits >= b'#' |
|
|
|
|
True |
|
|
|
|
/>/>/> my_bits >= '10000000' |
|
|
|
|
False |
|
|
|
|
/>/>/> '10000000' >= my_bits |
|
|
|
|
True |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-------------------- |
|
|
|
|
Bit-Masks and Flags |
|
|
|
|
-------------------- |
|
|
|
|
Bits objects support bitmask and flag operations. |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_bits = Bits('01101110') |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(110) |
|
|
|
|
/>/>/> 110 in my_bits |
|
|
|
|
True |
|
|
|
|
/>/>/> Bits('00000010') in my_bits |
|
|
|
|
True |
|
|
|
|
/>/>/> pow_2 = [0, 1, 2, 4, 8, 16, 32, 64, 128] |
|
|
|
|
/>/>/> for p2 in pow_2: |
|
|
|
|
... print(str(Bits(p2))) |
|
|
|
|
... |
|
|
|
|
00000000 |
|
|
|
|
00000001 |
|
|
|
|
00000010 |
|
|
|
|
00000100 |
|
|
|
|
00001000 |
|
|
|
|
00010000 |
|
|
|
|
00100000 |
|
|
|
|
01000000 |
|
|
|
|
10000000 |
|
|
|
|
/>/>/> for p2 in pow_2: |
|
|
|
|
... print(str(p2) + ' in Bits(110): ' + p2 in my_bits) |
|
|
|
|
... |
|
|
|
|
0 in Bits(110): True |
|
|
|
|
1 in Bits(110): False |
|
|
|
|
2 in Bits(110): True |
|
|
|
|
4 in Bits(110): True |
|
|
|
|
8 in Bits(110): True |
|
|
|
|
16 in Bits(110): False |
|
|
|
|
32 in Bits(110): True |
|
|
|
|
64 in Bits(110): True |
|
|
|
|
128 in Bits(110): False |
|
|
|
|
/>/>/> str(Bits(14)) |
|
|
|
|
'00001110' |
|
|
|
|
/>/>/> 14 in my_bits |
|
|
|
|
True |
|
|
|
|
/>/>/> (0 + 2 + 4 + 8) in my_bits |
|
|
|
|
True |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
------------------- |
|
|
|
|
Bitwise operations |
|
|
|
|
------------------- |
|
|
|
|
Binary bitwise operations are supported. |
|
|
|
|
.. code-block: python |
|
|
|
|
|
|
|
|
|
/>/>/> my_bits = Bits('01101110') |
|
|
|
|
/>/>/> my_bits |
|
|
|
|
Bits(110) |
|
|
|
|
/>/>/> str(my_bits & '0011') |
|
|
|
|
'00000010' |
|
|
|
|
/>/>/> str(my_bits >> 3) |
|
|
|
|
'00001101' |
|
|
|
|
/>/>/> str(my_bits << 1) |
|
|
|
|
'11011100' |
|
|
|
|
/>/>/> str(my_bits|'10111110') |
|
|
|
|
'11111110' |
|
|
|
|
/>/>/> str(my_bits^'10101010') |
|
|
|
|
'11000100' |
|
|
|
|
/>/>/> str(~my_bits) |
|
|
|
|
'10010001' |
|
|
|
|
/>/>/> |
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
def __init__(self, var=0, msb_last=False): |
|
|
|
@ -229,6 +657,14 @@ class Bits:
@@ -229,6 +657,14 @@ class Bits:
|
|
|
|
|
def __or__(self, other): |
|
|
|
|
return Bits(int(self) | int(Bits(other))) |
|
|
|
|
|
|
|
|
|
def __invert__(self): |
|
|
|
|
# There's probably a better way to do this... |
|
|
|
|
inv = str(self).replace('0', 'x').replace('1', '0').replace('x', '1') |
|
|
|
|
return Bits(inv) |
|
|
|
|
|
|
|
|
|
def __neg__(self): |
|
|
|
|
return ~ self |
|
|
|
|
|
|
|
|
|
def __radd__(self, other): |
|
|
|
|
return Bits(other) + self |
|
|
|
|
|
|
|
|
@ -351,27 +787,18 @@ class Bits:
@@ -351,27 +787,18 @@ class Bits:
|
|
|
|
|
set the value of self to int(var) |
|
|
|
|
""" |
|
|
|
|
self.__value = 0 |
|
|
|
|
if isinstance(var, Bits): |
|
|
|
|
self.__value = int(var) |
|
|
|
|
elif isinstance(var, int): |
|
|
|
|
if var < 0 or var > 255: |
|
|
|
|
if isinstance(var, (int, bool, Bits, Bytes, Bit)): |
|
|
|
|
var_i = int(var) |
|
|
|
|
if var_i < 0 or var_i > 255: |
|
|
|
|
raise ValueError("Integer must be between 0 and 255") |
|
|
|
|
self.__value = var |
|
|
|
|
self.__value = var_i |
|
|
|
|
elif isinstance(var, bytes): |
|
|
|
|
if len(var) == 1: |
|
|
|
|
self.__value = ord(var) |
|
|
|
|
self.__setvalue(ord(var)) |
|
|
|
|
elif len(var) > 1: |
|
|
|
|
raise ValueError("bytes must be single byte with integer" |
|
|
|
|
" value between 0 and 255") |
|
|
|
|
else: |
|
|
|
|
self.__value = 0 |
|
|
|
|
elif isinstance(var, Bytes): |
|
|
|
|
if int(var) < 256: |
|
|
|
|
self.__value = int(var) |
|
|
|
|
else: |
|
|
|
|
raise ValueError("Bytes object must be < 256") |
|
|
|
|
return list(var) |
|
|
|
|
elif (len(var) > 0) and (len(var) <=8): |
|
|
|
|
elif isinstance(var, (list, str)) and (len(var) <=8): |
|
|
|
|
# handles: "01010101" |
|
|
|
|
# ["0", "1", "0", "1", "0", "1", "0", "1"] |
|
|
|
|
# [0, 1, 0, 1, 0, 1, 0, 1] |
|
|
|
@ -382,7 +809,7 @@ class Bits:
@@ -382,7 +809,7 @@ class Bits:
|
|
|
|
|
self.__value += (int(bool(int(var[bit]))) * |
|
|
|
|
(2 ** (len(var) - 1 - bit))) |
|
|
|
|
else: |
|
|
|
|
raise TypeError("Expected object with len <= 8") |
|
|
|
|
raise TypeError("Expected compatible object") |
|
|
|
|
|
|
|
|
|
def bin(self, pad=True, reverse=False): |
|
|
|
|
""" |
|
|
|
@ -390,6 +817,12 @@ class Bits:
@@ -390,6 +817,12 @@ class Bits:
|
|
|
|
|
pad: True to include leading zeros, False to strip leading zeroes |
|
|
|
|
reverse: True to return binary string representation of self as stiB. |
|
|
|
|
""" |
|
|
|
|
if self.__value == 0: |
|
|
|
|
if pad: |
|
|
|
|
return "0" * 8 |
|
|
|
|
else: |
|
|
|
|
return "0" |
|
|
|
|
|
|
|
|
|
from math import ceil |
|
|
|
|
bitcount = self.__value.bit_length() |
|
|
|
|
ret = "" |
|
|
|
@ -488,13 +921,21 @@ class Bits:
@@ -488,13 +921,21 @@ class Bits:
|
|
|
|
|
ret.append(Bit(b)) |
|
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
def hex(self): |
|
|
|
|
""" |
|
|
|
|
Return the hex-string representation of self |
|
|
|
|
""" |
|
|
|
|
return bytes(self).hex() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Bytes: |
|
|
|
|
""" |
|
|
|
|
A colletion of Bits with convenient properties for working with binary data |
|
|
|
|
A collection of Bits with convenience methods for working with binary data |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
def __init__(self, var=None, byteorder="big"): |
|
|
|
|
import sys |
|
|
|
|
|
|
|
|
|
def __init__(self, var=None, byteorder="big", bits=None): |
|
|
|
|
""" |
|
|
|
|
var: a supported variant (object) |
|
|
|
|
byteorder: notimplemented, mostly ignored |
|
|
|
@ -502,11 +943,17 @@ class Bytes:
@@ -502,11 +943,17 @@ class Bytes:
|
|
|
|
|
self.__raw = bytearray(b'') |
|
|
|
|
self.__small = False |
|
|
|
|
self.__iter = None |
|
|
|
|
self.__list_len = None |
|
|
|
|
self.__bit_len = None |
|
|
|
|
if byteorder.lower() in ["small", "little"]: |
|
|
|
|
self.__small = True |
|
|
|
|
if var is not None: |
|
|
|
|
self.__raw = self.__to_bytearray(var) |
|
|
|
|
if bits is None: |
|
|
|
|
self.__bit_len = len(self.__raw) |
|
|
|
|
else: |
|
|
|
|
if not isinstance(bits, (int, Bytes, Bit)): |
|
|
|
|
raise TypeError(f"bits argument must be int, not {type(bits)}") |
|
|
|
|
self.__bit_len = int(bits) |
|
|
|
|
|
|
|
|
|
def __bytes__(self): |
|
|
|
|
""" |
|
|
|
@ -692,6 +1139,28 @@ class Bytes:
@@ -692,6 +1139,28 @@ class Bytes:
|
|
|
|
|
chop += 1 |
|
|
|
|
return ret + bin(i)[chop:] |
|
|
|
|
|
|
|
|
|
def hex(self, sep=None, bytes_per_sep=1): |
|
|
|
|
""" |
|
|
|
|
Return the hex-string representation of self |
|
|
|
|
""" |
|
|
|
|
hexvalue = bytes(self).hex() |
|
|
|
|
if sep is None or bytes_per_sep is None or bytes_per_sep == 0: |
|
|
|
|
return hexvalue |
|
|
|
|
else: |
|
|
|
|
if bytes_per_sep > 1: |
|
|
|
|
hexvalue = hexvalue[::-1] # reverse the hex string |
|
|
|
|
sep = sep[::-1] |
|
|
|
|
i = 0 |
|
|
|
|
retvalue = "" |
|
|
|
|
while i < len(hexvalue): |
|
|
|
|
if i > 0: |
|
|
|
|
retvalue = retvalue + sep |
|
|
|
|
retvalue = retvalue + hexvalue[i:(abs(bytes_per_sep * 2) + i)] |
|
|
|
|
i += abs(bytes_per_sep * 2) |
|
|
|
|
if bytes_per_sep > 1: |
|
|
|
|
retvalue = retvalue[::-1] |
|
|
|
|
return retvalue |
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
def bytes(self): |
|
|
|
|
return bytes(self) |