This file is indexed.

/usr/lib/python3/dist-packages/bitstruct.py is in python3-bitstruct 3.4.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
from __future__ import print_function

import re
import struct

__version__ = "3.4.0"


def _parse_format(fmt):
    if fmt[-1] in [">", "<"]:
        byte_order = fmt[-1]
        fmt = fmt[:-1]
    else:
        byte_order = ">"

    parsed_infos = re.findall(r'([<>]?)([a-zA-Z])(\d+)', fmt)

    # Use big endian as default and use the endianness of the previous
    # value if none is given for the current value.
    infos = []
    endianness = ">"

    for info in parsed_infos:
        if info[0] != "":
            endianness = info[0]

        infos.append((info[1], int(info[2]), endianness))

    return infos, byte_order


def _pack_integer(size, arg):
    value = int(arg)

    if value < 0:
        value = ((1 << size) + value)

    return '{{:0{}b}}'.format(size).format(value)


def _pack_boolean(size, arg):
    value = bool(arg)

    return _pack_integer(size, int(value))


def _pack_float(size, arg):
    value = float(arg)

    if size == 32:
        value = struct.pack('>f', value)
    elif size == 64:
        value = struct.pack('>d', value)
    else:
        raise ValueError('expected float size of 32 of 64 bits (got {})'.format(
            size))

    return ''.join('{:08b}'.format(b)
                   for b in bytearray(value))


def _pack_bytearray(size, arg):
    value = bytearray(arg)
    bits = ''.join('{:08b}'.format(b)
                   for b in value)

    return bits[0:size]


def _pack_text(size, arg):
    value = arg.encode('utf-8')

    return _pack_bytearray(size, bytearray(value))


def _unpack_integer(type_, bits):
    value = int(bits, 2)

    if type_ == 's':
        if bits[0] == '1':
            value -= (1 << len(bits))

    return value


def _unpack_boolean(bits):
    value = _unpack_integer('u', bits)

    return bool(value)


def _unpack_float(size, bits):
    packed = _unpack_bytearray(size, bits)

    if size == 32:
        value = struct.unpack('>f', packed)[0]
    elif size == 64:
        value = struct.unpack('>d', packed)[0]
    else:
        raise ValueError('expected float size of 32 of 64 bits (got {})'.format(
            size))

    return value


def _unpack_bytearray(size, bits):
    value = bytearray()
    for i in range(size // 8):
        value.append(int(bits[8*i:8*i+8], 2))
    rest = size % 8
    if rest > 0:
        value.append(int(bits[size-rest:], 2) << (8-rest))
    return value


def _unpack_text(size, bits):
    return _unpack_bytearray(size, bits).decode('utf-8')


def pack(fmt, *args):
    """Return a byte string containing the values v1, v2, ... packed
    according to the given format. If the total number of bits are not
    a multiple of 8, padding will be added at the end of the last
    byte.

    :param fmt: Bitstruct format string. See format description below.
    :param args: Variable argument list of values to pack.
    :returns: A byte string of the packed values.

    `fmt` is a string of bitorder-type-length groups, and optionally a
    byteorder identifier afer the groups. Bitorder and byteorder may
    be omitted.

    Bitorder is either ">" or "<", where ">" means MSB first and "<"
    means LSB first. If bitorder is omitted, the previous values'
    bitorder is used for the current value. For example, in the format
    string "u1<u2u3" u1 is MSB first and both u2 and u3 are LSB first.

    Byteorder is either ">" or "<", where ">" means most significant
    byte first and "<" means least significant byte first. If
    byteorder is omitted, most significant byte first is used.

    There are seven types; 'u', 's', 'f', 'b', 't', 'r' and 'p'.

    - 'u' -- unsigned integer
    - 's' -- signed integer
    - 'f' -- floating point number of 32 or 64 bits
    - 'b' -- boolean
    - 't' -- text (ascii or utf-8)
    - 'r' -- raw, bytes
    - 'p' -- padding, ignore

    Length is the number of bits to pack the value into.

    Example format string with default bit and byte ordering: 'u1u3p7s16'

    Same format string, but with least significant byte first:
    'u1u3p7s16<'

    Same format string, but with LSB first ('<' prefix) and least
    significant byte first ('<' suffix): '<u1u3p7s16<'

    """

    bits = ''
    infos, byte_order = _parse_format(fmt)
    i = 0

    # Sanity check of the number of arguments.
    number_of_arguments = 0

    for info in infos:
        if info[0] != 'p':
            number_of_arguments += 1

    if number_of_arguments > len(args):
        raise ValueError("pack expected {} item(s) for packing "
                         "(got {})".format(number_of_arguments, len(args)))

    for type_, size, endianness in infos:
        if type_ == 'p':
            bits += size * '0'
        else:
            if type_ in 'us':
                value_bits = _pack_integer(size, args[i])
            elif type_ == 'f':
                value_bits = _pack_float(size, args[i])
            elif type_ == 'b':
                value_bits = _pack_boolean(size, args[i])
            elif type_ == 't':
                value_bits = _pack_text(size, args[i])
            elif type_ == 'r':
                value_bits = _pack_bytearray(size, bytearray(args[i]))
            else:
                raise ValueError("bad type '{}' in format".format(type_))

            # reverse the bit order in little endian values
            if endianness == "<":
                value_bits = value_bits[::-1]

            # reverse bytes order for least significant byte first
            if byte_order == ">":
                bits += value_bits
            else:
                aligned_offset = len(value_bits) - (8 - (len(bits) % 8))

                while aligned_offset > 0:
                    bits += value_bits[aligned_offset:]
                    value_bits = value_bits[:aligned_offset]
                    aligned_offset -= 8

                bits += value_bits

            i += 1

    # padding of last byte
    tail = len(bits) % 8
    if tail != 0:
        bits += (8 - tail) * '0'

    return bytes(bytearray([int(''.join(bits[i:i+8]), 2)
                            for i in range(0, len(bits), 8)]))


def unpack(fmt, data):
    """Unpack `data` (byte string, bytearray or list of integers)
    according to the given format. The result is a tuple even if it
    contains exactly one item.

    :param fmt: Bitstruct format string. See pack() for details.
    :param data: Byte string of values to unpack.
    :returns: A tuple of the unpacked values.

    """

    bits = ''.join(['{:08b}'.format(b) for b in bytearray(data)])
    infos, byte_order = _parse_format(fmt)

    # Sanity check.
    number_of_bits_to_unpack = sum([size for _, size, _ in infos])

    if number_of_bits_to_unpack > len(bits):
        raise ValueError("unpack requires at least {} bits to unpack "
                         "(got {})".format(number_of_bits_to_unpack,
                                           len(bits)))

    res = []
    offset = 0

    for type_, size, endianness in infos:
        if type_ == 'p':
            pass
        else:
            # reverse bytes order for least significant byte first
            if byte_order == ">":
                value_bits = bits[offset:offset+size]
            else:
                value_bits_tmp = bits[offset:offset+size]
                aligned_offset = (size - ((offset + size) % 8))
                value_bits = ''

                while aligned_offset > 0:
                    value_bits += value_bits_tmp[aligned_offset:aligned_offset+8]
                    value_bits_tmp = value_bits_tmp[:aligned_offset]
                    aligned_offset -= 8

                value_bits += value_bits_tmp

            # reverse the bit order in little endian values
            if endianness == "<":
                value_bits = value_bits[::-1]

            if type_ in 'us':
                value = _unpack_integer(type_, value_bits)
            elif type_ == 'f':
                value = _unpack_float(size, value_bits)
            elif type_ == 'b':
                value = _unpack_boolean(value_bits)
            elif type_ == 't':
                value = _unpack_text(size, value_bits)
            elif type_ == 'r':
                value = bytes(_unpack_bytearray(size, value_bits))
            else:
                raise ValueError("bad type '{}' in format".format(type_))

            res.append(value)

        offset += size

    return tuple(res)


def calcsize(fmt):
    """Calculate the number of bits in given format.

    :param fmt: Bitstruct format string.
    :returns: Number of bits in format string.

    """

    return sum([size for _, size, _ in _parse_format(fmt)[0]])


def byteswap(fmt, data, offset = 0):
    """Swap bytes in `data` according to `fmt`, starting at byte
    `offset`. `fmt` must be an iterable, iterating over number of
    bytes to swap. For example, the format string "24" applied to the
    byte string b'\x00\x11\x22\x33\x44\x55' will produce the result
    b'\x11\x00\x55\x44\x33\x22'.

    :param fmt: Swap format string.
    :param data: Byte string of data to swap.
    :param offset: Start offset into `data`.
    :returns: Byte string of swapped bytes.

    """

    i = offset
    data_swapped = b''

    for f in fmt:
        length = int(f)
        value = data[i:i+length]
        data_swapped += value[::-1]
        i += length

    return data_swapped