Friday, July 24, 2009

BitString Cleanup

Finally settled on the below design for BitString. I had added, and then removed, functionality for AND, OR, and XOR because it is ambiguous as to what length to use if the operands are not the same length.

For example, it should be possible to AND
0xFFFF & 0x7
To get 0x7.

However, is that '0b0000000000000111' or '0b0111' or some other variant. Given that the values are indexes from the most-significant-bit, this creates an issue.

Anyway, here it is below. Modding PCS to use this for decoding simple values.

class  BitString(list):
'''
Creates a list containing the individual bits from a byte-string, integer,
or list of values (where each list is interpreted as 1 or 0 based on its
truth balue ).

Bits are ordered from most-significant to least-significant.

>>> import pcs
>>> x = pcs.BitString(0xDEADBEEF)
>>> x
[1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1]
>>> x[4:12]
[1, 1, 1, 0, 1, 0, 1, 0]
>>> int (x)
3735928559L
>>> hex(x)
'0xdeadbeefL'
>>> hex(x[16:32])
'0xbeef'
>>> bin(int (x))
'0b11011110101011011011111011101111'
>>> str (x)
'\xde \xad \xbe \xef '
>>> x[0:8] = 0xAA
>>> x[8:16] = [1,1,1,1,0,0,0,0]
>>> hex(x)
'0xaaf0beefL'
>>> int (x) == 0xAAF0BEEF
True
'''

def __init__(self,bytes):
# Convert integer values to their byte representation
if isinstance(bytes,int) or isinstance(bytes,long):
packString = ''
if abs(bytes) <= 0xff :
packString = '!B'
elif abs(bytes) <= 0xffff :
packString = '!H'
elif abs(bytes) <= 0xffffffff :
packString = '!I'
bytes = struct.pack(packString, bytes)

# Convert a list into a byte representation by taking each item
# and turning it into a bit.
if isinstance(bytes,list) or isinstance(bytes,tuple):
self.length = len(bytes)*8
for index,i in enumerate(bytes):
self.append(1 if i else 0 )

# For strings or string'ized integers, do bit-shifty stuff
# >>> bin(0xFF00)
# '0b1111111100000000'
if isinstance(bytes, str):
self.length = len(bytes)*8
# Do each byte in-order
for i,byte in enumerate(bytes):
# Most-significant-bit first
for bit in range(8 )[::-1 ]:
self.append(1 if ord(byte) & (1 << bit) else 0 )


def __int__(self):
intVal = 0
for index,i in enumerate(self):
intVal += self[-index-1 ] << index
return intVal

def __str__(self):
value = int(self)
formatString = "%0" + ("%s" % (len(self)/8 )) + "x"
hexstring = formatString % value
while len(hexstring) % 2 != 0 :
hexstring = '0' + hexstring
byteString = binascii.unhexlify(hexstring)

while len(byteString) < len(self)/8 :
byteString = "\x00" + byteString
return byteString

def __hex__(self):
return hex(int(self))

def __getitem__(self, x):
return list.__getitem__(self,x)

def __getslice__(self,i,j):
return BitString(list.__getslice__(self,i,j))

def __setitem__(self, i, x):
x = 1 if x else 0
list.__setitem__(self,i,x)

def __setslice__(self,i,j,x):
bs = BitString(x)
list.__setslice__(self,i,j,bs)

def __invert__(self):
return BitString([0 if x else 1 for x in self])

def __add__(self,x):
return BitString(list.__add__(self,x))

Read more...

1 comment:

  1. Have you seen the bitstring module (python-bitstring.googlecode.com)? It looks remarkably similar to your code, thought it's more fully featured. I wasn't sure if it would be helpful to you, or if this is an exercise. Cheers.

    ReplyDelete

Followers