1#!/usr/bin/env python3
 2
 3"""Binary manipulation functions."""
 4
 5import logging
 6import struct
 7import sys
 8
 9logger = logging.getLogger()
10
11
12def unpack_uint8(buff, position):
13    """Retrieve an 8 bit uint from a buffer."""
14    res = buff[position]
15    return res
16
17
18def unpack_uint16_be(buff, position):
19    """Retrieve a 16 bit big endian int from a buffer."""
20    try:
21        return (buff[position] << 8) + buff[position + 1]
22    except IndexError as e:
23        raise IndexError('Cannot read 16 bits from position {p} in buffer len {l}'.format(
24            p=position, l=len(buff)))
25
26
27def unpack_uint24_be(buff, position):
28    """Retrieve a 24 bit big endian unsigned int from a buffer."""
29    return (buff[position] << 16) + (buff[position +1 ] << 8) + buff[position + 2]
30
31
32def unpack_uint22_be(buff, position):
33    """Retrieve the 22 MSB from `position` in `buffer`."""
34    return unpack_uint24_be(buff, position) >> 2
35
36
37def unpack_uint32_be(buff, position):
38    """Retrieve a 32 bit big endian unsigned int from a buffer."""
39    return ((buff[position] << 24) +
40            (buff[position + 1] << 16) +
41            (buff[position + 2] << 8) +
42            buff[position + 3])
43
44
45def unpack_int32_be(buff, position):
46    """Retrieve a 32 bit big endian int from a buffer."""
47    return struct.unpack_from('>i', buff, position)[0]
48
49
50def unpack_uint40_be(buff, position):
51    """Retrieve a 32 bit big endian int from a buffer."""
52    return ((buff[position] << 40) +
53            (buff[position + 1] << 32) +
54            (buff[position + 2] << 24) +
55            (buff[position + 3] << 16) +
56            (buff[position + 4] << 8) +
57            buff[position + 5])
58
59
60def unpack_uint64_be(buff, position):
61    """Retrieve a 64 bit big endian int from a buffer."""
62    return ((buff[position] << 56) +
63            (buff[position + 1] << 48) +
64            (buff[position + 2] << 40) +
65            (buff[position + 3] << 32) +
66            (buff[position + 4] << 24) +
67            (buff[position + 5] << 16) +
68            (buff[position + 6] << 8) +
69            buff[position + 7])
70
71
72def unpack_float64_be(buff, position):
73    """(slowly) decode a big endian double precision float from binary"""
74    return struct.unpack('>d', buff[position:position + 8])[0]
75
76
77def unpack_float32_be(buff, position):
78    """(slowly) decode a big endian single precision float from binary"""
79    return struct.unpack('>f', buff[position:position + 4])[0]
80
81
82def pack_uint16_be(buff, position, value):
83    """Store a 16 bit big endian int into a buffer."""
84    buff[position] = value >> 8
85    buff[position + 1] = value & 0xff
86
87
88def pack_uint32_be(buff, position, value):
89    """Store a 32 bit big endian int into a buffer."""
90    buff[position] = value >> 24
91    buff[position + 1] = (value >> 16) & 0xff
92    buff[position + 2] = (value >> 8) & 0xff
93    buff[position + 3] = value & 0xff