Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unpack 6 bytes as single integer using struct in Python

Tags:

python

struct

I have the following 8 bytes:

b'\x05\x00\x00\x00\x00\x00\x05\x00'

I'm trying to get two integers using struct.unpack: one for the first 2 bytes, and one for the last 6. Getting the first two is easy using:

struct.unpack("<H6B")

But, that returns

(5, 0, 0, 0, 0, 5, 0)

I want it to return the following:

(5, 5)

How do I get the integer value of the last 6 bytes? I do not want each byte individually.

like image 933
Aaron Hampton Avatar asked Oct 31 '11 04:10

Aaron Hampton


2 Answers

struct does not support integers with non-power-of-two size. This is common. C doesn't support such integers on your platform either (well, bitfields, but you can't make an array of those).

def unpack48(x):
    x1, x2, x3 = struct.unpack('<HHI', x)
    return x1, x2 | (x3 << 16)
like image 50
Dietrich Epp Avatar answered Sep 23 '22 23:09

Dietrich Epp


The standard struct module doesn't support all possible sizes so you either have to join some bits together yourself (see Dietrich's answer), or you can use external modules such as bitstring.

>>> from bitstring import BitArray
>>> b = BitArray(bytes=b'\x05\x00\x00\x00\x00\x00\x05\x00')
>>> b.unpack('<H6B')
[5, 0, 0, 0, 0, 5, 0]

which is the same as the standard struct.unpack. But now we can instead unpack the second item as a 6 byte (48 bit) little-endian unsigned integer:

>>> b.unpack('<H, uintle:48')
[5, 21474836480]                   

which gives you the same result as Dietrich's answer and also shows that you've got something the wrong way round in your question! What you need in this case is:

>>> b.unpack('uintle:48, <H')
[5, 5]

Note that you could also write <H as uintle:16 if you wanted more consistent notation.

like image 31
Scott Griffiths Avatar answered Sep 20 '22 23:09

Scott Griffiths