Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/bitstring/classes.py: 23%
1879 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:15 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:15 +0000
1from __future__ import annotations
3import copy
4import numbers
5import pathlib
6import sys
7import re
8import mmap
9import struct
10import array
11import io
12from collections import abc
13import functools
14import types
15from typing import Tuple, Union, List, Iterable, Any, Optional, Pattern, Dict, \
16 BinaryIO, TextIO, Callable, overload, Iterator, Type, TypeVar
17import bitarray
18import bitarray.util
19from bitstring.utils import tokenparser, BYTESWAP_STRUCT_PACK_RE, STRUCT_SPLIT_RE
20from bitstring.exceptions import CreationError, InterpretError, ReadError, Error
21from bitstring.fp8 import fp143_fmt, fp152_fmt
22from bitstring.bitstore import BitStore, _offset_slice_indices_lsb0
24# Things that can be converted to Bits when a Bits type is needed
25BitsType = Union['Bits', str, Iterable[Any], bool, BinaryIO, bytearray, bytes, memoryview, bitarray.bitarray]
27TBits = TypeVar("TBits", bound='Bits')
29byteorder: str = sys.byteorder
31# An opaque way of adding module level properties. Taken from https://peps.python.org/pep-0549/
32_bytealigned: bool = False
33_lsb0: bool = False
35# The size of various caches used to improve performance
36CACHE_SIZE = 256
39class _MyModuleType(types.ModuleType):
40 @property
41 def bytealigned(self) -> bool:
42 """Determines whether a number of methods default to working only on byte boundaries."""
43 return globals()['_bytealigned']
45 @bytealigned.setter
46 def bytealigned(self, value: bool) -> None:
47 """Determines whether a number of methods default to working only on byte boundaries."""
48 globals()['_bytealigned'] = value
50 @property
51 def lsb0(self) -> bool:
52 """If True, the least significant bit (the final bit) is indexed as bit zero."""
53 return globals()['_lsb0']
55 @lsb0.setter
56 def lsb0(self, value: bool) -> None:
57 """If True, the least significant bit (the final bit) is indexed as bit zero."""
58 value = bool(value)
59 _switch_lsb0_methods(value)
60 globals()['_lsb0'] = value
63sys.modules[__name__].__class__ = _MyModuleType
65# Maximum number of digits to use in __str__ and __repr__.
66MAX_CHARS: int = 250
69def tidy_input_string(s: str) -> str:
70 """Return string made lowercase and with all whitespace and underscores removed."""
71 try:
72 l = s.split()
73 except (AttributeError, TypeError):
74 raise ValueError(f"Expected str object but received a {type(s)} with value {s}.")
75 return ''.join(l).lower().replace('_', '')
78# Size in bytes of all the pack codes.
79PACK_CODE_SIZE: Dict[str, int] = {'b': 1, 'B': 1, 'h': 2, 'H': 2, 'l': 4, 'L': 4,
80 'q': 8, 'Q': 8, 'e': 2, 'f': 4, 'd': 8}
82_tokenname_to_initialiser: Dict[str, str] = {'hex': 'hex', '0x': 'hex', '0X': 'hex', 'oct': 'oct', '0o': 'oct',
83 '0O': 'oct', 'bin': 'bin', '0b': 'bin', '0B': 'bin', 'bits': 'bits',
84 'bytes': 'bytes', 'pad': 'pad', 'bfloat': 'bfloat',
85 'float8_143': 'float8_143', 'float8_152': 'float8_152'}
88def _str_to_bitstore(s: str, _str_to_bitstore_cache={}) -> BitStore:
89 try:
90 return _str_to_bitstore_cache[s]
91 except KeyError:
92 try:
93 _, tokens = tokenparser(s)
94 except ValueError as e:
95 raise CreationError(*e.args)
96 bs = BitStore()
97 if tokens:
98 bs = bs + _bitstore_from_token(*tokens[0])
99 for token in tokens[1:]:
100 bs = bs + _bitstore_from_token(*token)
101 bs.immutable = True
102 _str_to_bitstore_cache[s] = bs
103 if len(_str_to_bitstore_cache) > CACHE_SIZE:
104 # Remove the oldest one. FIFO.
105 del _str_to_bitstore_cache[next(iter(_str_to_bitstore_cache))]
106 return bs
109def _bin2bitstore(binstring: str) -> BitStore:
110 binstring = tidy_input_string(binstring)
111 binstring = binstring.replace('0b', '')
112 return _bin2bitstore_unsafe(binstring)
115def _bin2bitstore_unsafe(binstring: str) -> BitStore:
116 try:
117 return BitStore(binstring)
118 except ValueError:
119 raise CreationError(f"Invalid character in bin initialiser {binstring}.")
122def _hex2bitstore(hexstring: str) -> BitStore:
123 hexstring = tidy_input_string(hexstring)
124 hexstring = hexstring.replace('0x', '')
125 try:
126 ba = bitarray.util.hex2ba(hexstring)
127 except ValueError:
128 raise CreationError("Invalid symbol in hex initialiser.")
129 return BitStore(ba)
132def _oct2bitstore(octstring: str) -> BitStore:
133 octstring = tidy_input_string(octstring)
134 octstring = octstring.replace('0o', '')
135 try:
136 ba = bitarray.util.base2ba(8, octstring)
137 except ValueError:
138 raise CreationError("Invalid symbol in oct initialiser.")
139 return BitStore(ba)
142def _ue2bitstore(i: Union[str, int]) -> BitStore:
143 i = int(i)
144 if _lsb0:
145 raise CreationError("Exp-Golomb codes cannot be used in lsb0 mode.")
146 if i < 0:
147 raise CreationError("Cannot use negative initialiser for unsigned exponential-Golomb.")
148 if i == 0:
149 return BitStore('1')
150 tmp = i + 1
151 leadingzeros = -1
152 while tmp > 0:
153 tmp >>= 1
154 leadingzeros += 1
155 remainingpart = i + 1 - (1 << leadingzeros)
156 return BitStore('0' * leadingzeros + '1') + _uint2bitstore(remainingpart, leadingzeros)
159def _se2bitstore(i: Union[str, int]) -> BitStore:
160 i = int(i)
161 if i > 0:
162 u = (i * 2) - 1
163 else:
164 u = -2 * i
165 return _ue2bitstore(u)
168def _uie2bitstore(i: Union[str, int]) -> BitStore:
169 if _lsb0:
170 raise CreationError("Exp-Golomb codes cannot be used in lsb0 mode.")
171 i = int(i)
172 if i < 0:
173 raise CreationError("Cannot use negative initialiser for unsigned interleaved exponential-Golomb.")
174 return BitStore('1' if i == 0 else '0' + '0'.join(bin(i + 1)[3:]) + '1')
177def _sie2bitstore(i: Union[str, int]) -> BitStore:
178 i = int(i)
179 if _lsb0:
180 raise CreationError("Exp-Golomb codes cannot be used in lsb0 mode.")
181 if i == 0:
182 return BitStore('1')
183 else:
184 return _uie2bitstore(abs(i)) + (BitStore('1') if i < 0 else BitStore('0'))
187def _bfloat2bitstore(f: Union[str, float]) -> BitStore:
188 f = float(f)
189 try:
190 b = struct.pack('>f', f)
191 except OverflowError:
192 # For consistency we overflow to 'inf'.
193 b = struct.pack('>f', float('inf') if f > 0 else float('-inf'))
194 return BitStore(frombytes=b[0:2])
197def _bfloatle2bitstore(f: Union[str, float]) -> BitStore:
198 f = float(f)
199 try:
200 b = struct.pack('<f', f)
201 except OverflowError:
202 # For consistency we overflow to 'inf'.
203 b = struct.pack('<f', float('inf') if f > 0 else float('-inf'))
204 return BitStore(frombytes=b[2:4])
207def _float8_143_2bitstore(f: Union[str, float]) -> BitStore:
208 f = float(f)
209 u = fp143_fmt.float_to_int8(f)
210 return _uint2bitstore(u, 8)
213def _float8_152_2bitstore(f: Union[str, float]) -> BitStore:
214 f = float(f)
215 u = fp152_fmt.float_to_int8(f)
216 return _uint2bitstore(u, 8)
219def _uint2bitstore(uint: Union[str, int], length: int) -> BitStore:
220 uint = int(uint)
221 try:
222 x = BitStore(bitarray.util.int2ba(uint, length=length, endian='big', signed=False))
223 except OverflowError as e:
224 if uint >= (1 << length):
225 msg = f"{uint} is too large an unsigned integer for a bitstring of length {length}. " \
226 f"The allowed range is [0, {(1 << length) - 1}]."
227 raise CreationError(msg)
228 if uint < 0:
229 raise CreationError("uint cannot be initialised with a negative number.")
230 raise e
231 return x
234def _int2bitstore(i: Union[str, int], length: int) -> BitStore:
235 i = int(i)
236 try:
237 x = BitStore(bitarray.util.int2ba(i, length=length, endian='big', signed=True))
238 except OverflowError as e:
239 if i >= (1 << (length - 1)) or i < -(1 << (length - 1)):
240 raise CreationError(f"{i} is too large a signed integer for a bitstring of length {length}. "
241 f"The allowed range is [{-(1 << (length - 1))}, {(1 << (length - 1)) - 1}].")
242 else:
243 raise e
244 return x
247def _uintbe2bitstore(i: Union[str, int], length: int) -> BitStore:
248 if length % 8 != 0:
249 raise CreationError(f"Big-endian integers must be whole-byte. Length = {length} bits.")
250 return _uint2bitstore(i, length)
253def _intbe2bitstore(i: int, length: int) -> BitStore:
254 if length % 8 != 0:
255 raise CreationError(f"Big-endian integers must be whole-byte. Length = {length} bits.")
256 return _int2bitstore(i, length)
259def _uintle2bitstore(i: int, length: int) -> BitStore:
260 if length % 8 != 0:
261 raise CreationError(f"Little-endian integers must be whole-byte. Length = {length} bits.")
262 x = _uint2bitstore(i, length).tobytes()
263 return BitStore(frombytes=x[::-1])
266def _intle2bitstore(i: int, length: int) -> BitStore:
267 if length % 8 != 0:
268 raise CreationError(f"Little-endian integers must be whole-byte. Length = {length} bits.")
269 x = _int2bitstore(i, length).tobytes()
270 return BitStore(frombytes=x[::-1])
273def _float2bitstore(f: Union[str, float], length: int) -> BitStore:
274 f = float(f)
275 try:
276 fmt = {16: '>e', 32: '>f', 64: '>d'}[length]
277 except KeyError:
278 raise InterpretError(f"Floats can only be 16, 32 or 64 bits long, not {length} bits")
279 try:
280 b = struct.pack(fmt, f)
281 assert len(b) * 8 == length
282 except (OverflowError, struct.error) as e:
283 # If float64 doesn't fit it automatically goes to 'inf'. This reproduces that behaviour for other types.
284 if length in [16, 32]:
285 b = struct.pack(fmt, float('inf') if f > 0 else float('-inf'))
286 else:
287 raise e
288 return BitStore(frombytes=b)
291def _floatle2bitstore(f: Union[str, float], length: int) -> BitStore:
292 f = float(f)
293 try:
294 fmt = {16: '<e', 32: '<f', 64: '<d'}[length]
295 except KeyError:
296 raise InterpretError(f"Floats can only be 16, 32 or 64 bits long, not {length} bits")
297 try:
298 b = struct.pack(fmt, f)
299 assert len(b) * 8 == length
300 except (OverflowError, struct.error) as e:
301 # If float64 doesn't fit it automatically goes to 'inf'. This reproduces that behaviour for other types.
302 if length in [16, 32]:
303 b = struct.pack(fmt, float('inf') if f > 0 else float('-inf'))
304 else:
305 raise e
306 return BitStore(frombytes=b)
309# Create native-endian functions as aliases depending on the byteorder
310if byteorder == 'little':
311 _uintne2bitstore = _uintle2bitstore
312 _intne2bitstore = _intle2bitstore
313 _bfloatne2bitstore = _bfloatle2bitstore
314 _floatne2bitstore = _floatle2bitstore
315else:
316 _uintne2bitstore = _uintbe2bitstore
317 _intne2bitstore = _intbe2bitstore
318 _bfloatne2bitstore = _bfloat2bitstore
319 _floatne2bitstore = _float2bitstore
321# Given a string of the format 'name=value' get a bitstore representing it by using
322# _name2bitstore_func[name](value)
323_name2bitstore_func: Dict[str, Callable[..., BitStore]] = {
324 'hex': _hex2bitstore,
325 '0x': _hex2bitstore,
326 '0X': _hex2bitstore,
327 'bin': _bin2bitstore,
328 '0b': _bin2bitstore,
329 '0B': _bin2bitstore,
330 'oct': _oct2bitstore,
331 '0o': _oct2bitstore,
332 '0O': _oct2bitstore,
333 'se': _se2bitstore,
334 'ue': _ue2bitstore,
335 'sie': _sie2bitstore,
336 'uie': _uie2bitstore,
337 'bfloat': _bfloat2bitstore,
338 'bfloatbe': _bfloat2bitstore,
339 'bfloatle': _bfloatle2bitstore,
340 'bfloatne': _bfloatne2bitstore,
341 'float8_143': _float8_143_2bitstore,
342 'float8_152': _float8_152_2bitstore,
343}
345# Given a string of the format 'name[:]length=value' get a bitstore representing it by using
346# _name2bitstore_func_with_length[name](value, length)
347_name2bitstore_func_with_length: Dict[str, Callable[..., BitStore]] = {
348 'uint': _uint2bitstore,
349 'int': _int2bitstore,
350 'uintbe': _uintbe2bitstore,
351 'intbe': _intbe2bitstore,
352 'uintle': _uintle2bitstore,
353 'intle': _intle2bitstore,
354 'uintne': _uintne2bitstore,
355 'intne': _intne2bitstore,
356 'float': _float2bitstore,
357 'floatbe': _float2bitstore, # same as 'float'
358 'floatle': _floatle2bitstore,
359 'floatne': _floatne2bitstore,
360}
363def _bitstore_from_token(name: str, token_length: Optional[int], value: Optional[str]) -> BitStore:
364 if token_length == 0:
365 return BitStore()
366 # For pad token just return the length in zero bits
367 if name == 'pad':
368 bs = BitStore(token_length)
369 bs.setall(0)
370 return bs
371 if value is None:
372 if token_length is None:
373 raise ValueError(f"Token has no value ({name}=???).")
374 else:
375 raise ValueError(f"Token has no value ({name}:{token_length}=???).")
377 if name in _name2bitstore_func:
378 bs = _name2bitstore_func[name](value)
379 elif name in _name2bitstore_func_with_length:
380 bs = _name2bitstore_func_with_length[name](value, token_length)
381 elif name == 'bool':
382 if value in (1, 'True', '1'):
383 bs = BitStore('1')
384 elif value in (0, 'False', '0'):
385 bs = BitStore('0')
386 else:
387 raise CreationError("bool token can only be 'True' or 'False'.")
388 else:
389 raise CreationError(f"Can't parse token name {name}.")
390 if token_length is not None and len(bs) != token_length:
391 raise CreationError(f"Token with length {token_length} packed with value of length {len(bs)} "
392 f"({name}:{token_length}={value}).")
393 return bs
396class Bits:
397 """A container holding an immutable sequence of bits.
399 For a mutable container use the BitArray class instead.
401 Methods:
403 all() -- Check if all specified bits are set to 1 or 0.
404 any() -- Check if any of specified bits are set to 1 or 0.
405 copy() - Return a copy of the bitstring.
406 count() -- Count the number of bits set to 1 or 0.
407 cut() -- Create generator of constant sized chunks.
408 endswith() -- Return whether the bitstring ends with a sub-string.
409 find() -- Find a sub-bitstring in the current bitstring.
410 findall() -- Find all occurrences of a sub-bitstring in the current bitstring.
411 join() -- Join bitstrings together using current bitstring.
412 pp() -- Pretty print the bitstring.
413 rfind() -- Seek backwards to find a sub-bitstring.
414 split() -- Create generator of chunks split by a delimiter.
415 startswith() -- Return whether the bitstring starts with a sub-bitstring.
416 tobitarray() -- Return bitstring as a bitarray from the bitarray package.
417 tobytes() -- Return bitstring as bytes, padding if needed.
418 tofile() -- Write bitstring to file, padding if needed.
419 unpack() -- Interpret bits using format string.
421 Special methods:
423 Also available are the operators [], ==, !=, +, *, ~, <<, >>, &, |, ^.
425 Properties:
427 bin -- The bitstring as a binary string.
428 hex -- The bitstring as a hexadecimal string.
429 oct -- The bitstring as an octal string.
430 bytes -- The bitstring as a bytes object.
431 int -- Interpret as a two's complement signed integer.
432 uint -- Interpret as a two's complement unsigned integer.
433 float / floatbe -- Interpret as a big-endian floating point number.
434 bool -- For single bit bitstrings, interpret as True or False.
435 se -- Interpret as a signed exponential-Golomb code.
436 ue -- Interpret as an unsigned exponential-Golomb code.
437 sie -- Interpret as a signed interleaved exponential-Golomb code.
438 uie -- Interpret as an unsigned interleaved exponential-Golomb code.
439 floatle -- Interpret as a little-endian floating point number.
440 floatne -- Interpret as a native-endian floating point number.
441 bfloat / bfloatbe -- Interpret as a big-endian 16-bit bfloat type.
442 bfloatle -- Interpret as a little-endian 16-bit bfloat type.
443 bfloatne -- Interpret as a native-endian 16-bit bfloat type.
444 intbe -- Interpret as a big-endian signed integer.
445 intle -- Interpret as a little-endian signed integer.
446 intne -- Interpret as a native-endian signed integer.
447 uintbe -- Interpret as a big-endian unsigned integer.
448 uintle -- Interpret as a little-endian unsigned integer.
449 uintne -- Interpret as a native-endian unsigned integer.
451 len -- Length of the bitstring in bits.
453 """
455 @classmethod
456 def _setlsb0methods(cls, lsb0: bool) -> None:
457 if lsb0:
458 cls._find = cls._find_lsb0 # type: ignore
459 cls._rfind = cls._rfind_lsb0 # type: ignore
460 cls._findall = cls._findall_lsb0 # type: ignore
461 else:
462 cls._find = cls._find_msb0 # type: ignore
463 cls._rfind = cls._rfind_msb0 # type: ignore
464 cls._findall = cls._findall_msb0 # type: ignore
466 __slots__ = ('_bitstore')
468 # Creates dictionaries to quickly reverse single bytes
469 _int8ReversalDict: Dict[int, int] = {i: int("{0:08b}".format(i)[::-1], 2) for i in range(0x100)}
470 _byteReversalDict: Dict[int, bytes] = {i: bytes([int("{0:08b}".format(i)[::-1], 2)]) for i in range(0x100)}
472 def __init__(self, __auto: Optional[Union[BitsType, int]] = None, length: Optional[int] = None,
473 offset: Optional[int] = None, **kwargs) -> None:
474 """Either specify an 'auto' initialiser:
475 A string of comma separated tokens, an integer, a file object,
476 a bytearray, a boolean iterable, an array or another bitstring.
478 Or initialise via **kwargs with one (and only one) of:
479 bin -- binary string representation, e.g. '0b001010'.
480 hex -- hexadecimal string representation, e.g. '0x2ef'
481 oct -- octal string representation, e.g. '0o777'.
482 bytes -- raw data as a bytes object, for example read from a binary file.
483 int -- a signed integer.
484 uint -- an unsigned integer.
485 float / floatbe -- a big-endian floating point number.
486 bool -- a boolean (True or False).
487 se -- a signed exponential-Golomb code.
488 ue -- an unsigned exponential-Golomb code.
489 sie -- a signed interleaved exponential-Golomb code.
490 uie -- an unsigned interleaved exponential-Golomb code.
491 floatle -- a little-endian floating point number.
492 floatne -- a native-endian floating point number.
493 bfloat / bfloatbe - a big-endian bfloat format 16-bit floating point number.
494 bfloatle -- a little-endian bfloat format 16-bit floating point number.
495 bfloatne -- a native-endian bfloat format 16-bit floating point number.
496 intbe -- a signed big-endian whole byte integer.
497 intle -- a signed little-endian whole byte integer.
498 intne -- a signed native-endian whole byte integer.
499 uintbe -- an unsigned big-endian whole byte integer.
500 uintle -- an unsigned little-endian whole byte integer.
501 uintne -- an unsigned native-endian whole byte integer.
502 filename -- the path of a file which will be opened in binary read-only mode.
504 Other keyword arguments:
505 length -- length of the bitstring in bits, if needed and appropriate.
506 It must be supplied for all integer and float initialisers.
507 offset -- bit offset to the data. These offset bits are
508 ignored and this is mainly intended for use when
509 initialising using 'bytes' or 'filename'.
511 """
512 self._bitstore.immutable = True
514 def __new__(cls: Type[TBits], __auto: Optional[Union[BitsType, int]] = None, length: Optional[int] = None,
515 offset: Optional[int] = None, pos: Optional[int] = None, **kwargs) -> TBits:
516 x = object.__new__(cls)
517 if __auto is None and not kwargs:
518 # No initialiser so fill with zero bits up to length
519 if length is not None:
520 x._bitstore = BitStore(length)
521 x._bitstore.setall(0)
522 else:
523 x._bitstore = BitStore()
524 return x
525 x._initialise(__auto, length, offset, **kwargs)
526 return x
528 @classmethod
529 def _create_from_bitstype(cls: Type[TBits], auto: Optional[BitsType]) -> TBits:
530 b = cls()
531 if auto is None:
532 return b
533 if isinstance(auto, numbers.Integral):
534 raise TypeError(f"It's no longer possible to auto initialise a bitstring from an integer."
535 f" Use '{cls.__name__}({auto})' instead of just '{auto}' as this makes it "
536 f"clearer that a bitstring of {int(auto)} zero bits will be created.")
537 b._setauto(auto, None, None)
538 return b
540 def _initialise(self, __auto: Any, length: Optional[int], offset: Optional[int], **kwargs) -> None:
541 if length is not None and length < 0:
542 raise CreationError("bitstring length cannot be negative.")
543 if offset is not None and offset < 0:
544 raise CreationError("offset must be >= 0.")
545 if __auto is not None:
546 self._setauto(__auto, length, offset)
547 return
548 k, v = kwargs.popitem()
549 try:
550 setting_function = self._setfunc[k]
551 except KeyError:
552 if k == 'auto':
553 raise CreationError(f"The 'auto' parameter should not be given explicitly - just use the first positional argument. "
554 f"Instead of '{self.__class__.__name__}(auto=x)' use '{self.__class__.__name__}(x)'.")
555 else:
556 raise CreationError(f"Unrecognised keyword '{k}' used to initialise.")
557 setting_function(self, v, length, offset)
559 def __getattr__(self, attribute: str) -> Any:
560 # Support for arbitrary attributes like u16 or f64.
561 letter_to_getter: Dict[str, Callable[..., Union[int, float, str]]] = \
562 {'u': self._getuint,
563 'i': self._getint,
564 'f': self._getfloatbe,
565 'b': self._getbin,
566 'o': self._getoct,
567 'h': self._gethex}
568 short_token: Pattern[str] = re.compile(r'^(?P<name>[uifboh]):?(?P<len>\d+)$', re.IGNORECASE)
569 m1_short = short_token.match(attribute)
570 if m1_short:
571 length = int(m1_short.group('len'))
572 if length is not None and self.len != length:
573 raise InterpretError(f"bitstring length {self.len} doesn't match length of property {attribute}.")
574 name = m1_short.group('name')
575 f = letter_to_getter[name]
576 return f()
577 # Try to split into [name][length], then try standard properties
578 name_length_pattern: Pattern[str] = re.compile(r'^(?P<name>[a-z]+):?(?P<len>\d+)$', re.IGNORECASE)
579 name_length = name_length_pattern.match(attribute)
580 if name_length:
581 name = name_length.group('name')
582 length = int(name_length.group('len'))
583 if name == 'bytes' and length is not None:
584 length *= 8
585 if length is not None and self.len != int(length):
586 raise InterpretError(f"bitstring length {self.len} doesn't match length of property {attribute}.")
587 try:
588 return getattr(self, name)
589 except AttributeError:
590 pass
591 raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{attribute}'.")
593 def __iter__(self) -> Iterable[bool]:
594 return iter(self._bitstore)
596 def __copy__(self: TBits) -> TBits:
597 """Return a new copy of the Bits for the copy module."""
598 # Note that if you want a new copy (different ID), use _copy instead.
599 # The copy can return self as it's immutable.
600 return self
602 def __lt__(self, other: Any) -> bool:
603 # bitstrings can't really be ordered.
604 return NotImplemented
606 def __gt__(self, other: Any) -> bool:
607 return NotImplemented
609 def __le__(self, other: Any) -> bool:
610 return NotImplemented
612 def __ge__(self, other: Any) -> bool:
613 return NotImplemented
615 def __add__(self: TBits, bs: BitsType) -> TBits:
616 """Concatenate bitstrings and return new bitstring.
618 bs -- the bitstring to append.
620 """
621 bs = self.__class__._create_from_bitstype(bs)
622 if bs.len <= self.len:
623 s = self._copy()
624 s._addright(bs)
625 else:
626 s = bs._copy()
627 s = self.__class__(s)
628 s._addleft(self)
629 return s
631 def __radd__(self: TBits, bs: BitsType) -> TBits:
632 """Append current bitstring to bs and return new bitstring.
634 bs -- An object that can be 'auto' initialised as a bitstring that will be appended to.
636 """
637 bs = self.__class__._create_from_bitstype(bs)
638 return bs.__add__(self)
640 @overload
641 def __getitem__(self: TBits, key: slice) -> TBits:
642 ...
644 @overload
645 def __getitem__(self, key: int) -> bool:
646 ...
648 def __getitem__(self: TBits, key: Union[slice, int]) -> Union[TBits, bool]:
649 """Return a new bitstring representing a slice of the current bitstring.
651 Indices are in units of the step parameter (default 1 bit).
652 Stepping is used to specify the number of bits in each item.
654 >>> print(BitArray('0b00110')[1:4])
655 '0b011'
656 >>> print(BitArray('0x00112233')[1:3:8])
657 '0x1122'
659 """
660 if isinstance(key, numbers.Integral):
661 return bool(self._bitstore.getindex(key))
662 x = self._bitstore.getslice(key)
663 bs = self.__class__()
664 bs._bitstore = x
665 return bs
667 def __len__(self) -> int:
668 """Return the length of the bitstring in bits."""
669 return self._getlength()
671 def __bytes__(self) -> bytes:
672 return self.tobytes()
674 def __str__(self) -> str:
675 """Return approximate string representation of bitstring for printing.
677 Short strings will be given wholly in hexadecimal or binary. Longer
678 strings may be part hexadecimal and part binary. Very long strings will
679 be truncated with '...'.
681 """
682 length = self.len
683 if not length:
684 return ''
685 if length > MAX_CHARS * 4:
686 # Too long for hex. Truncate...
687 return ''.join(('0x', self._readhex(0, MAX_CHARS * 4), '...'))
688 # If it's quite short and we can't do hex then use bin
689 if length < 32 and length % 4 != 0:
690 return '0b' + self.bin
691 # If we can use hex then do so
692 if not length % 4:
693 return '0x' + self.hex
694 # Otherwise first we do as much as we can in hex
695 # then add on 1, 2 or 3 bits on at the end
696 bits_at_end = length % 4
697 return ''.join(('0x', self._readhex(0, length - bits_at_end),
698 ', ', '0b',
699 self._readbin(length - bits_at_end, bits_at_end)))
701 def _repr(self, classname: str, length: int, offset: int, filename: str, pos: int):
702 pos_string = f', pos={pos}' if pos else ''
703 if filename:
704 offsetstring = f', offset={offset}' if offset else ''
705 return f"{classname}(filename={repr(filename)}, length={length}{offsetstring}{pos_string})"
706 else:
707 s = self.__str__()
708 lengthstring = ''
709 if s.endswith('...'):
710 lengthstring = f' # length={length}'
711 return f"{classname}('{s}'{pos_string}){lengthstring}"
713 def __repr__(self) -> str:
714 """Return representation that could be used to recreate the bitstring.
716 If the returned string is too long it will be truncated. See __str__().
718 """
719 return self._repr(self.__class__.__name__, len(self), self._bitstore.offset, self._bitstore.filename, 0)
721 def __eq__(self, bs: Any) -> bool:
722 """Return True if two bitstrings have the same binary representation.
724 >>> BitArray('0b1110') == '0xe'
725 True
727 """
728 try:
729 bs = Bits._create_from_bitstype(bs)
730 except TypeError:
731 return False
732 return self._bitstore == bs._bitstore
734 def __ne__(self, bs: Any) -> bool:
735 """Return False if two bitstrings have the same binary representation.
737 >>> BitArray('0b111') == '0x7'
738 False
740 """
741 return not self.__eq__(bs)
743 def __invert__(self: TBits) -> TBits:
744 """Return bitstring with every bit inverted.
746 Raises Error if the bitstring is empty.
748 """
749 if not self.len:
750 raise Error("Cannot invert empty bitstring.")
751 s = self._copy()
752 s._invert_all()
753 return s
755 def __lshift__(self: TBits, n: int) -> TBits:
756 """Return bitstring with bits shifted by n to the left.
758 n -- the number of bits to shift. Must be >= 0.
760 """
761 if n < 0:
762 raise ValueError("Cannot shift by a negative amount.")
763 if not self.len:
764 raise ValueError("Cannot shift an empty bitstring.")
765 n = min(n, self.len)
766 s = self._absolute_slice(n, self.len)
767 s._addright(Bits(n))
768 return s
770 def __rshift__(self: TBits, n: int) -> TBits:
771 """Return bitstring with bits shifted by n to the right.
773 n -- the number of bits to shift. Must be >= 0.
775 """
776 if n < 0:
777 raise ValueError("Cannot shift by a negative amount.")
778 if not self.len:
779 raise ValueError("Cannot shift an empty bitstring.")
780 if not n:
781 return self._copy()
782 s = self.__class__(length=min(n, self.len))
783 n = min(n, self.len)
784 s._addright(self._absolute_slice(0, self.len - n))
785 return s
787 def __mul__(self: TBits, n: int) -> TBits:
788 """Return bitstring consisting of n concatenations of self.
790 Called for expression of the form 'a = b*3'.
791 n -- The number of concatenations. Must be >= 0.
793 """
794 if n < 0:
795 raise ValueError("Cannot multiply by a negative integer.")
796 if not n:
797 return self.__class__()
798 s = self._copy()
799 s._imul(n)
800 return s
802 def __rmul__(self: TBits, n: int) -> TBits:
803 """Return bitstring consisting of n concatenations of self.
805 Called for expressions of the form 'a = 3*b'.
806 n -- The number of concatenations. Must be >= 0.
808 """
809 return self.__mul__(n)
811 def __and__(self: TBits, bs: BitsType) -> TBits:
812 """Bit-wise 'and' between two bitstrings. Returns new bitstring.
814 bs -- The bitstring to '&' with.
816 Raises ValueError if the two bitstrings have differing lengths.
818 """
819 bs = Bits._create_from_bitstype(bs)
820 if self.len != bs.len:
821 raise ValueError("Bitstrings must have the same length for & operator.")
822 s = self._copy()
823 s._bitstore &= bs._bitstore
824 return s
826 def __rand__(self: TBits, bs: BitsType) -> TBits:
827 """Bit-wise 'and' between two bitstrings. Returns new bitstring.
829 bs -- the bitstring to '&' with.
831 Raises ValueError if the two bitstrings have differing lengths.
833 """
834 return self.__and__(bs)
836 def __or__(self: TBits, bs: BitsType) -> TBits:
837 """Bit-wise 'or' between two bitstrings. Returns new bitstring.
839 bs -- The bitstring to '|' with.
841 Raises ValueError if the two bitstrings have differing lengths.
843 """
844 bs = Bits._create_from_bitstype(bs)
845 if self.len != bs.len:
846 raise ValueError("Bitstrings must have the same length for | operator.")
847 s = self._copy()
848 s._bitstore |= bs._bitstore
849 return s
851 def __ror__(self: TBits, bs: BitsType) -> TBits:
852 """Bit-wise 'or' between two bitstrings. Returns new bitstring.
854 bs -- The bitstring to '|' with.
856 Raises ValueError if the two bitstrings have differing lengths.
858 """
859 return self.__or__(bs)
861 def __xor__(self: TBits, bs: BitsType) -> TBits:
862 """Bit-wise 'xor' between two bitstrings. Returns new bitstring.
864 bs -- The bitstring to '^' with.
866 Raises ValueError if the two bitstrings have differing lengths.
868 """
869 bs = Bits._create_from_bitstype(bs)
870 if self.len != bs.len:
871 raise ValueError("Bitstrings must have the same length for ^ operator.")
872 s = self._copy()
873 s._bitstore ^= bs._bitstore
874 return s
876 def __rxor__(self: TBits, bs: BitsType) -> TBits:
877 """Bit-wise 'xor' between two bitstrings. Returns new bitstring.
879 bs -- The bitstring to '^' with.
881 Raises ValueError if the two bitstrings have differing lengths.
883 """
884 return self.__xor__(bs)
886 def __contains__(self, bs: BitsType) -> bool:
887 """Return whether bs is contained in the current bitstring.
889 bs -- The bitstring to search for.
891 """
892 found = Bits.find(self, bs, bytealigned=False)
893 return bool(found)
895 def __hash__(self) -> int:
896 """Return an integer hash of the object."""
897 # Only requirement is that equal bitstring should return the same hash.
898 # For equal bitstrings the bytes at the start/end will be the same and they will have the same length
899 # (need to check the length as there could be zero padding when getting the bytes). We do not check any
900 # bit position inside the bitstring as that does not feature in the __eq__ operation.
901 if self.len <= 2000:
902 # Use the whole bitstring.
903 return hash((self.tobytes(), self.len))
904 else:
905 # We can't in general hash the whole bitstring (it could take hours!)
906 # So instead take some bits from the start and end.
907 return hash(((self[:800] + self[-800:]).tobytes(), self.len))
909 def __bool__(self) -> bool:
910 """Return True if any bits are set to 1, otherwise return False."""
911 return len(self) != 0
913 @classmethod
914 def _init_with_token(cls: Type[TBits], name: str, token_length: Optional[int], value: Optional[str]) -> TBits:
915 if token_length == 0:
916 return cls()
917 # For pad token just return the length in zero bits
918 if name == 'pad':
919 return cls(token_length)
920 if value is None:
921 if token_length is None:
922 raise ValueError(f"Token has no value ({name}=???).")
923 else:
924 raise ValueError(f"Token has no value ({name}:{token_length}=???).")
925 try:
926 b = cls(**{_tokenname_to_initialiser[name]: value})
927 except KeyError:
928 if name in ('se', 'ue', 'sie', 'uie'):
929 if _lsb0:
930 raise CreationError("Exp-Golomb codes cannot be used in lsb0 mode.")
931 b = cls(**{name: int(value)})
932 elif name in ('uint', 'int', 'uintbe', 'intbe', 'uintle', 'intle', 'uintne', 'intne'):
933 b = cls(**{name: int(value), 'length': token_length})
934 elif name in ('float', 'floatbe', 'floatle', 'floatne'):
935 b = cls(**{name: float(value), 'length': token_length})
936 elif name == 'bool':
937 if value in (1, 'True', '1'):
938 b = cls(bool=True)
939 elif value in (0, 'False', '0'):
940 b = cls(bool=False)
941 else:
942 raise CreationError("bool token can only be 'True' or 'False'.")
943 else:
944 raise CreationError(f"Can't parse token name {name}.")
945 if token_length is not None and b.len != token_length:
946 raise CreationError(f"Token with length {token_length} packed with value of length {b.len} "
947 f"({name}:{token_length}={value}).")
948 return b
950 def _clear(self) -> None:
951 """Reset the bitstring to an empty state."""
952 self._bitstore = BitStore()
954 def _setauto(self, s: Union[BitsType, int], length: Optional[int], offset: Optional[int]) -> None:
955 """Set bitstring from a bitstring, file, bool, integer, array, iterable or string."""
956 # As s can be so many different things it's important to do the checks
957 # in the correct order, as some types are also other allowed types.
958 # So str must be checked before Iterable
959 # and bytes/bytearray before Iterable but after str!
960 if offset is None:
961 offset = 0
962 if isinstance(s, Bits):
963 if length is None:
964 length = s._getlength() - offset
965 self._bitstore = s._bitstore.getslice(slice(offset, offset + length, None))
966 return
968 if isinstance(s, io.BytesIO):
969 if length is None:
970 length = s.seek(0, 2) * 8 - offset
971 byteoffset, offset = divmod(offset, 8)
972 bytelength = (length + byteoffset * 8 + offset + 7) // 8 - byteoffset
973 if length + byteoffset * 8 + offset > s.seek(0, 2) * 8:
974 raise CreationError("BytesIO object is not long enough for specified length and offset.")
975 self._bitstore = BitStore(frombytes=s.getvalue()[byteoffset: byteoffset + bytelength]).getslice(
976 slice(offset, offset + length))
977 return
979 if isinstance(s, io.BufferedReader):
980 m = mmap.mmap(s.fileno(), 0, access=mmap.ACCESS_READ)
981 self._bitstore = BitStore(buffer=m, offset=offset, length=length, filename=s.name, immutable=True)
982 return
984 if isinstance(s, bitarray.bitarray):
985 if length is None:
986 if offset > len(s):
987 raise CreationError(f"Offset of {offset} too large for bitarray of length {len(s)}.")
988 self._bitstore = BitStore(s[offset:])
989 else:
990 if offset + length > len(s):
991 raise CreationError(
992 f"Offset of {offset} and length of {length} too large for bitarray of length {len(s)}.")
993 self._bitstore = BitStore(s[offset: offset + length])
994 return
996 if length is not None:
997 raise CreationError("The length keyword isn't applicable to this initialiser.")
998 if offset > 0:
999 raise CreationError("The offset keyword isn't applicable to this initialiser.")
1000 if isinstance(s, str):
1001 self._bitstore = _str_to_bitstore(s)
1002 return
1003 if isinstance(s, (bytes, bytearray, memoryview)):
1004 self._bitstore = BitStore(frombytes=bytearray(s))
1005 return
1006 if isinstance(s, array.array):
1007 self._bitstore = BitStore(frombytes=bytearray(s.tobytes()))
1008 return
1009 if isinstance(s, numbers.Integral):
1010 # Initialise with s zero bits.
1011 if s < 0:
1012 raise CreationError(f"Can't create bitstring of negative length {s}.")
1013 self._bitstore = BitStore(int(s))
1014 self._bitstore.setall(0)
1015 return
1016 if isinstance(s, abc.Iterable):
1017 # Evaluate each item as True or False and set bits to 1 or 0.
1018 self._setbin_unsafe(''.join(str(int(bool(x))) for x in s))
1019 return
1020 raise TypeError(f"Cannot initialise bitstring from {type(s)}.")
1022 def _setfile(self, filename: str, length: Optional[int], offset: Optional[int]) -> None:
1023 """Use file as source of bits."""
1024 with open(pathlib.Path(filename), 'rb') as source:
1025 if offset is None:
1026 offset = 0
1027 m = mmap.mmap(source.fileno(), 0, access=mmap.ACCESS_READ)
1028 self._bitstore = BitStore(buffer=m, offset=offset, length=length, filename=source.name, immutable=True)
1030 def _setbitarray(self, ba: bitarray.bitarray, length: Optional[int], offset: Optional[int]) -> None:
1031 if offset is None:
1032 offset = 0
1033 if offset > len(ba):
1034 raise CreationError(f"Offset of {offset} too large for bitarray of length {len(ba)}.")
1035 if length is None:
1036 self._bitstore = BitStore(ba[offset:])
1037 else:
1038 if offset + length > len(ba):
1039 raise CreationError(
1040 f"Offset of {offset} and length of {length} too large for bitarray of length {len(ba)}.")
1041 self._bitstore = BitStore(ba[offset: offset + length])
1043 def _setbits(self, bs: BitsType, length: None = None, offset: None = None) -> None:
1044 bs = Bits._create_from_bitstype(bs)
1045 self._bitstore = bs._bitstore
1047 def _setfloat152(self, f: float, length: None = None, _offset: None = None):
1048 u = fp152_fmt.float_to_int8(f)
1049 self._bitstore = _uint2bitstore(u, 8)
1051 def _setfloat143(self, f: float, length: None = None, _offset: None = None):
1052 u = fp143_fmt.float_to_int8(f)
1053 self._bitstore = _uint2bitstore(u, 8)
1055 def _setbytes(self, data: Union[bytearray, bytes],
1056 length: Optional[int] = None, offset: Optional[int] = None) -> None:
1057 """Set the data from a bytes or bytearray object."""
1058 if offset is None and length is None:
1059 self._bitstore = BitStore(frombytes=bytearray(data))
1060 return
1061 data = bytearray(data)
1062 if offset is None:
1063 offset = 0
1064 if length is None:
1065 # Use to the end of the data
1066 length = len(data) * 8 - offset
1067 else:
1068 if length + offset > len(data) * 8:
1069 raise CreationError(f"Not enough data present. Need {length + offset} bits, have {len(data) * 8}.")
1070 self._bitstore = BitStore(buffer=data).getslice_msb0(slice(offset, offset + length, None))
1072 def _readbytes(self, start: int, length: int) -> bytes:
1073 """Read bytes and return them. Note that length is in bits."""
1074 assert length % 8 == 0
1075 assert start + length <= self.len
1076 return self._bitstore.getslice(slice(start, start + length, None)).tobytes()
1078 def _getbytes(self) -> bytes:
1079 """Return the data as an ordinary bytes object."""
1080 if self.len % 8:
1081 raise InterpretError("Cannot interpret as bytes unambiguously - not multiple of 8 bits.")
1082 return self._readbytes(0, self.len)
1084 _unprintable = list(range(0x00, 0x20)) # ASCII control characters
1085 _unprintable.extend(range(0x7f, 0xff)) # DEL char + non-ASCII
1087 def _getbytes_printable(self) -> str:
1088 """Return an approximation of the data as a string of printable characters."""
1089 bytes_ = self._getbytes()
1090 # For everything that isn't printable ASCII, use value from 'Latin Extended-A' unicode block.
1091 string = ''.join(chr(0x100 + x) if x in Bits._unprintable else chr(x) for x in bytes_)
1092 return string
1094 def _setuint(self, uint: int, length: Optional[int] = None, _offset: None = None) -> None:
1095 """Reset the bitstring to have given unsigned int interpretation."""
1096 # If no length given, and we've previously been given a length, use it.
1097 if length is None and hasattr(self, 'len') and self.len != 0:
1098 length = self.len
1099 if length is None or length == 0:
1100 raise CreationError("A non-zero length must be specified with a uint initialiser.")
1101 if _offset is not None:
1102 raise CreationError("An offset can't be specified with an integer initialiser.")
1103 self._bitstore = _uint2bitstore(uint, length)
1105 def _readuint(self, start: int, length: int) -> int:
1106 """Read bits and interpret as an unsigned int."""
1107 if length == 0:
1108 raise InterpretError("Cannot interpret a zero length bitstring as an integer.")
1109 ip = bitarray.util.ba2int(self._bitstore.getslice(slice(start, start + length, None)), signed=False)
1110 return ip
1112 def _getuint(self) -> int:
1113 """Return data as an unsigned int."""
1114 if self.len == 0:
1115 raise InterpretError("Cannot interpret a zero length bitstring as an integer.")
1116 bs = self._bitstore.copy() if self._bitstore.modified else self._bitstore
1117 return bitarray.util.ba2int(bs, signed=False)
1119 def _setint(self, int_: int, length: Optional[int] = None, _offset: None = None) -> None:
1120 """Reset the bitstring to have given signed int interpretation."""
1121 # If no length given, and we've previously been given a length, use it.
1122 if length is None and hasattr(self, 'len') and self.len != 0:
1123 length = self.len
1124 if length is None or length == 0:
1125 raise CreationError("A non-zero length must be specified with an int initialiser.")
1126 if _offset is not None:
1127 raise CreationError("An offset can't be specified with an integer initialiser.")
1128 self._bitstore = _int2bitstore(int_, length)
1130 def _readint(self, start: int, length: int) -> int:
1131 """Read bits and interpret as a signed int"""
1132 if length == 0:
1133 raise InterpretError("Cannot interpret a zero length bitstring as an integer.")
1134 ip = bitarray.util.ba2int(self._bitstore.getslice(slice(start, start + length, None)), signed=True)
1135 return ip
1137 def _getint(self) -> int:
1138 """Return data as a two's complement signed int."""
1139 if self.len == 0:
1140 raise InterpretError("Cannot interpret a zero length bitstring as an integer.")
1141 bs = self._bitstore.copy() if self._bitstore.modified else self._bitstore
1142 return bitarray.util.ba2int(bs, signed=True)
1144 def _setuintbe(self, uintbe: int, length: Optional[int] = None, _offset: None = None) -> None:
1145 """Set the bitstring to a big-endian unsigned int interpretation."""
1146 if length is None and hasattr(self, 'len') and self.len != 0:
1147 length = self.len
1148 if length is None or length == 0:
1149 raise CreationError("A non-zero length must be specified with a uintbe initialiser.")
1150 self._bitstore = _uintbe2bitstore(uintbe, length)
1152 def _readuintbe(self, start: int, length: int) -> int:
1153 """Read bits and interpret as a big-endian unsigned int."""
1154 if length % 8:
1155 raise InterpretError(f"Big-endian integers must be whole-byte. Length = {length} bits.")
1156 return self._readuint(start, length)
1158 def _getuintbe(self) -> int:
1159 """Return data as a big-endian two's complement unsigned int."""
1160 return self._readuintbe(0, self.len)
1162 def _setintbe(self, intbe: int, length: Optional[int] = None, _offset: None = None) -> None:
1163 """Set bitstring to a big-endian signed int interpretation."""
1164 if length is None and hasattr(self, 'len') and self.len != 0:
1165 length = self.len
1166 if length is None or length == 0:
1167 raise CreationError("A non-zero length must be specified with a intbe initialiser.")
1168 self._bitstore = _intbe2bitstore(intbe, length)
1170 def _readintbe(self, start: int, length: int) -> int:
1171 """Read bits and interpret as a big-endian signed int."""
1172 if length % 8:
1173 raise InterpretError(f"Big-endian integers must be whole-byte. Length = {length} bits.")
1174 return self._readint(start, length)
1176 def _getintbe(self) -> int:
1177 """Return data as a big-endian two's complement signed int."""
1178 return self._readintbe(0, self.len)
1180 def _setuintle(self, uintle: int, length: Optional[int] = None, _offset: None = None) -> None:
1181 if length is None and hasattr(self, 'len') and self.len != 0:
1182 length = self.len
1183 if length is None or length == 0:
1184 raise CreationError("A non-zero length must be specified with a uintle initialiser.")
1185 if _offset is not None:
1186 raise CreationError("An offset can't be specified with an integer initialiser.")
1187 self._bitstore = _uintle2bitstore(uintle, length)
1189 def _readuintle(self, start: int, length: int) -> int:
1190 """Read bits and interpret as a little-endian unsigned int."""
1191 if length % 8:
1192 raise InterpretError(f"Little-endian integers must be whole-byte. Length = {length} bits.")
1193 bs = BitStore(frombytes=self._bitstore.getslice(slice(start, start + length, None)).tobytes()[::-1])
1194 val = bitarray.util.ba2int(bs, signed=False)
1195 return val
1197 def _getuintle(self) -> int:
1198 return self._readuintle(0, self.len)
1200 def _setintle(self, intle: int, length: Optional[int] = None, _offset: None = None) -> None:
1201 if length is None and hasattr(self, 'len') and self.len != 0:
1202 length = self.len
1203 if length is None or length == 0:
1204 raise CreationError("A non-zero length must be specified with an intle initialiser.")
1205 if _offset is not None:
1206 raise CreationError("An offset can't be specified with an integer initialiser.")
1207 self._bitstore = _intle2bitstore(intle, length)
1209 def _readintle(self, start: int, length: int) -> int:
1210 """Read bits and interpret as a little-endian signed int."""
1211 if length % 8:
1212 raise InterpretError(f"Little-endian integers must be whole-byte. Length = {length} bits.")
1213 bs = BitStore(frombytes=self._bitstore.getslice(slice(start, start + length, None)).tobytes()[::-1])
1214 val = bitarray.util.ba2int(bs, signed=True)
1215 return val
1217 def _getintle(self) -> int:
1218 return self._readintle(0, self.len)
1220 def _readfloat(self, start: int, length: int, struct_dict: Dict[int, str]) -> float:
1221 """Read bits and interpret as a float."""
1222 try:
1223 fmt = struct_dict[length]
1224 except KeyError:
1225 raise InterpretError(f"Floats can only be 16, 32 or 64 bits long, not {length} bits")
1227 offset = start % 8
1228 if offset == 0:
1229 return struct.unpack(fmt, self._bitstore.getslice(slice(start, start + length, None)).tobytes())[0]
1230 else:
1231 return struct.unpack(fmt, self._readbytes(start, length))[0]
1233 def _readfloat143(self, start: int, length: int = 0) -> float:
1234 # length is ignored - it's only present to make the function signature consistent.
1235 u = self._readuint(start, length=8)
1236 return fp143_fmt.lut_int8_to_float[u]
1238 def _getfloat143(self) -> float:
1239 if len(self) != 8:
1240 raise InterpretError(f"A float8_143 must be 8 bits long, not {len(self)} bits.")
1241 return self._readfloat143(0)
1243 def _readfloat152(self, start: int, length: int = 0) -> float:
1244 # length is ignored - it's only present to make the function signature consistent.
1245 u = self._readuint(start, length=8)
1246 return fp152_fmt.lut_int8_to_float[u]
1248 def _getfloat152(self) -> float:
1249 if len(self) != 8:
1250 raise InterpretError(f"A float8_152 must be 8 bits long, not {len(self)} bits.")
1251 return self._readfloat152(start=0)
1253 def _setfloatbe(self, f: float, length: Optional[int] = None, _offset: None = None) -> None:
1254 if length is None and hasattr(self, 'len') and self.len != 0:
1255 length = self.len
1256 if length is None or length not in [16, 32, 64]:
1257 raise CreationError("A length of 16, 32, or 64 must be specified with a float initialiser.")
1258 self._bitstore = _float2bitstore(f, length)
1260 def _readfloatbe(self, start: int, length: int) -> float:
1261 """Read bits and interpret as a big-endian float."""
1262 return self._readfloat(start, length, {16: '>e', 32: '>f', 64: '>d'})
1264 def _getfloatbe(self) -> float:
1265 """Interpret the whole bitstring as a big-endian float."""
1266 return self._readfloatbe(0, self.len)
1268 def _setfloatle(self, f: float, length: Optional[int] = None, _offset: None = None) -> None:
1269 if length is None and hasattr(self, 'len') and self.len != 0:
1270 length = self.len
1271 if length is None or length not in [16, 32, 64]:
1272 raise CreationError("A length of 16, 32, or 64 must be specified with a float initialiser.")
1273 self._bitstore = _floatle2bitstore(f, length)
1275 def _readfloatle(self, start: int, length: int) -> float:
1276 """Read bits and interpret as a little-endian float."""
1277 return self._readfloat(start, length, {16: '<e', 32: '<f', 64: '<d'})
1279 def _getfloatle(self) -> float:
1280 """Interpret the whole bitstring as a little-endian float."""
1281 return self._readfloatle(0, self.len)
1283 def _getbfloatbe(self) -> float:
1284 return self._readbfloatbe(0, self.len)
1286 def _readbfloatbe(self, start: int, length: int) -> float:
1287 if length != 16:
1288 raise InterpretError(f"bfloats must be length 16, received a length of {length} bits.")
1289 two_bytes = self._slice(start, start + 16)
1290 zero_padded = two_bytes + Bits(16)
1291 return zero_padded._getfloatbe()
1293 def _setbfloatbe(self, f: Union[float, str], length: Optional[int] = None, _offset: None = None) -> None:
1294 if length is not None and length != 16:
1295 raise CreationError(f"bfloats must be length 16, received a length of {length} bits.")
1296 self._bitstore = _bfloat2bitstore(f)
1298 def _getbfloatle(self) -> float:
1299 return self._readbfloatle(0, self.len)
1301 def _readbfloatle(self, start: int, length: int) -> float:
1302 two_bytes = self._slice(start, start + 16)
1303 zero_padded = Bits(16) + two_bytes
1304 return zero_padded._getfloatle()
1306 def _setbfloatle(self, f: Union[float, str], length: Optional[int] = None, _offset: None = None) -> None:
1307 if length is not None and length != 16:
1308 raise CreationError(f"bfloats must be length 16, received a length of {length} bits.")
1309 self._bitstore = _bfloatle2bitstore(f)
1311 def _setue(self, i: int, _length: None = None, _offset: None = None) -> None:
1312 """Initialise bitstring with unsigned exponential-Golomb code for integer i.
1314 Raises CreationError if i < 0.
1316 """
1317 if _length is not None or _offset is not None:
1318 raise CreationError("Cannot specify a length of offset for exponential-Golomb codes.")
1319 self._bitstore = _ue2bitstore(i)
1321 def _readue(self, pos: int, _length: int = 0) -> Tuple[int, int]:
1322 """Return interpretation of next bits as unsigned exponential-Golomb code.
1324 Raises ReadError if the end of the bitstring is encountered while
1325 reading the code.
1327 """
1328 # _length is ignored - it's only present to make the function signature consistent.
1329 if _lsb0:
1330 raise ReadError("Exp-Golomb codes cannot be read in lsb0 mode.")
1331 oldpos = pos
1332 try:
1333 while not self[pos]:
1334 pos += 1
1335 except IndexError:
1336 raise ReadError("Read off end of bitstring trying to read code.")
1337 leadingzeros = pos - oldpos
1338 codenum = (1 << leadingzeros) - 1
1339 if leadingzeros > 0:
1340 if pos + leadingzeros + 1 > self.len:
1341 raise ReadError("Read off end of bitstring trying to read code.")
1342 codenum += self._readuint(pos + 1, leadingzeros)
1343 pos += leadingzeros + 1
1344 else:
1345 assert codenum == 0
1346 pos += 1
1347 return codenum, pos
1349 def _getue(self) -> int:
1350 """Return data as unsigned exponential-Golomb code.
1352 Raises InterpretError if bitstring is not a single exponential-Golomb code.
1354 """
1355 try:
1356 value, newpos = self._readue(0)
1357 if value is None or newpos != self.len:
1358 raise ReadError
1359 except ReadError:
1360 raise InterpretError("Bitstring is not a single exponential-Golomb code.")
1361 return value
1363 def _setse(self, i: int, _length: None = None, _offset: None = None) -> None:
1364 """Initialise bitstring with signed exponential-Golomb code for integer i."""
1365 if _length is not None or _offset is not None:
1366 raise CreationError("Cannot specify a length of offset for exponential-Golomb codes.")
1367 self._bitstore = _se2bitstore(i)
1369 def _getse(self) -> int:
1370 """Return data as signed exponential-Golomb code.
1372 Raises InterpretError if bitstring is not a single exponential-Golomb code.
1374 """
1375 try:
1376 value, newpos = self._readse(0)
1377 if value is None or newpos != self.len:
1378 raise ReadError
1379 except ReadError:
1380 raise InterpretError("Bitstring is not a single exponential-Golomb code.")
1381 return value
1383 def _readse(self, pos: int, _length: int = 0) -> Tuple[int, int]:
1384 """Return interpretation of next bits as a signed exponential-Golomb code.
1386 Advances position to after the read code.
1388 Raises ReadError if the end of the bitstring is encountered while
1389 reading the code.
1391 """
1392 codenum, pos = self._readue(pos)
1393 m = (codenum + 1) // 2
1394 if not codenum % 2:
1395 return -m, pos
1396 else:
1397 return m, pos
1399 def _setuie(self, i: int, _length: None = None, _offset: None = None) -> None:
1400 """Initialise bitstring with unsigned interleaved exponential-Golomb code for integer i.
1402 Raises CreationError if i < 0.
1404 """
1405 if _length is not None or _offset is not None:
1406 raise CreationError("Cannot specify a length of offset for exponential-Golomb codes.")
1407 self._bitstore = _uie2bitstore(i)
1409 def _readuie(self, pos: int, _length: int = 0) -> Tuple[int, int]:
1410 """Return interpretation of next bits as unsigned interleaved exponential-Golomb code.
1412 Raises ReadError if the end of the bitstring is encountered while
1413 reading the code.
1415 """
1416 # _length is ignored - it's only present to make the function signature consistent.
1417 if _lsb0:
1418 raise ReadError("Exp-Golomb codes cannot be read in lsb0 mode.")
1419 try:
1420 codenum: int = 1
1421 while not self[pos]:
1422 pos += 1
1423 codenum <<= 1
1424 codenum += self[pos]
1425 pos += 1
1426 pos += 1
1427 except IndexError:
1428 raise ReadError("Read off end of bitstring trying to read code.")
1429 codenum -= 1
1430 return codenum, pos
1432 def _getuie(self) -> int:
1433 """Return data as unsigned interleaved exponential-Golomb code.
1435 Raises InterpretError if bitstring is not a single exponential-Golomb code.
1437 """
1438 try:
1439 value, newpos = self._readuie(0)
1440 if value is None or newpos != self.len:
1441 raise ReadError
1442 except ReadError:
1443 raise InterpretError("Bitstring is not a single interleaved exponential-Golomb code.")
1444 return value
1446 def _setsie(self, i: int, _length: None = None, _offset: None = None) -> None:
1447 """Initialise bitstring with signed interleaved exponential-Golomb code for integer i."""
1448 if _length is not None or _offset is not None:
1449 raise CreationError("Cannot specify a length of offset for exponential-Golomb codes.")
1450 self._bitstore = _sie2bitstore(i)
1452 def _getsie(self) -> int:
1453 """Return data as signed interleaved exponential-Golomb code.
1455 Raises InterpretError if bitstring is not a single exponential-Golomb code.
1457 """
1458 try:
1459 value, newpos = self._readsie(0)
1460 if value is None or newpos != self.len:
1461 raise ReadError
1462 except ReadError:
1463 raise InterpretError("Bitstring is not a single interleaved exponential-Golomb code.")
1464 return value
1466 def _readsie(self, pos: int, _length: int = 0) -> Tuple[int, int]:
1467 """Return interpretation of next bits as a signed interleaved exponential-Golomb code.
1469 Advances position to after the read code.
1471 Raises ReadError if the end of the bitstring is encountered while
1472 reading the code.
1474 """
1475 codenum, pos = self._readuie(pos)
1476 if not codenum:
1477 return 0, pos
1478 try:
1479 if self[pos]:
1480 return -codenum, pos + 1
1481 else:
1482 return codenum, pos + 1
1483 except IndexError:
1484 raise ReadError("Read off end of bitstring trying to read code.")
1486 def _setbool(self, value: Union[bool, str], length: Optional[int] = None, _offset: None = None) -> None:
1487 # We deliberately don't want to have implicit conversions to bool here.
1488 # If we did then it would be difficult to deal with the 'False' string.
1489 if length is not None and length != 1:
1490 raise CreationError(f"bools must be length 1, received a length of {length} bits.")
1491 if value in (1, 'True'):
1492 self._bitstore = BitStore('1')
1493 elif value in (0, 'False'):
1494 self._bitstore = BitStore('0')
1495 else:
1496 raise CreationError(f"Cannot initialise boolean with {value}.")
1498 def _getbool(self) -> bool:
1499 if self.length != 1:
1500 raise InterpretError(f"For a bool interpretation a bitstring must be 1 bit long, not {self.length} bits.")
1501 return self[0]
1503 def _readbool(self, start: int, length: int = 0) -> int:
1504 # length is ignored - it's only present to make the function signature consistent.
1505 return self[start]
1507 def _readpad(self, _pos, _length) -> None:
1508 return None
1510 def _setbin_safe(self, binstring: str, length: None = None, _offset: None = None) -> None:
1511 """Reset the bitstring to the value given in binstring."""
1512 self._bitstore = _bin2bitstore(binstring)
1514 def _setbin_unsafe(self, binstring: str, length: None = None, _offset: None = None) -> None:
1515 """Same as _setbin_safe, but input isn't sanity checked. binstring mustn't start with '0b'."""
1516 self._bitstore = _bin2bitstore_unsafe(binstring)
1518 def _readbin(self, start: int, length: int) -> str:
1519 """Read bits and interpret as a binary string."""
1520 if length == 0:
1521 return ''
1522 return self._bitstore.getslice(slice(start, start + length, None)).to01()
1524 def _getbin(self) -> str:
1525 """Return interpretation as a binary string."""
1526 return self._readbin(0, self.len)
1528 def _setoct(self, octstring: str, length: None = None, _offset: None = None) -> None:
1529 """Reset the bitstring to have the value given in octstring."""
1530 self._bitstore = _oct2bitstore(octstring)
1532 def _readoct(self, start: int, length: int) -> str:
1533 """Read bits and interpret as an octal string."""
1534 if length % 3:
1535 raise InterpretError("Cannot convert to octal unambiguously - not multiple of 3 bits long.")
1536 s = bitarray.util.ba2base(8, self._bitstore.getslice(slice(start, start + length, None)))
1537 return s
1539 def _getoct(self) -> str:
1540 """Return interpretation as an octal string."""
1541 if self.len % 3:
1542 raise InterpretError("Cannot convert to octal unambiguously - not multiple of 3 bits long.")
1543 ba = self._bitstore.copy() if self._bitstore.modified else self._bitstore
1544 return bitarray.util.ba2base(8, ba)
1546 def _sethex(self, hexstring: str, length: None = None, _offset: None = None) -> None:
1547 """Reset the bitstring to have the value given in hexstring."""
1548 self._bitstore = _hex2bitstore(hexstring)
1550 def _readhex(self, start: int, length: int) -> str:
1551 """Read bits and interpret as a hex string."""
1552 if length % 4:
1553 raise InterpretError("Cannot convert to hex unambiguously - not a multiple of 4 bits long.")
1554 return bitarray.util.ba2hex(self._bitstore.getslice(slice(start, start + length, None)))
1556 def _gethex(self) -> str:
1557 """Return the hexadecimal representation as a string.
1559 Raises an InterpretError if the bitstring's length is not a multiple of 4.
1561 """
1562 if self.len % 4:
1563 raise InterpretError("Cannot convert to hex unambiguously - not a multiple of 4 bits long.")
1564 ba = self._bitstore.copy() if self._bitstore.modified else self._bitstore
1565 return bitarray.util.ba2hex(ba)
1567 def _getlength(self) -> int:
1568 """Return the length of the bitstring in bits."""
1569 return len(self._bitstore)
1571 def _copy(self: TBits) -> TBits:
1572 """Create and return a new copy of the Bits (always in memory)."""
1573 # Note that __copy__ may choose to return self if it's immutable. This method always makes a copy.
1574 s_copy = self.__class__()
1575 s_copy._bitstore = self._bitstore.copy()
1576 return s_copy
1578 def _slice(self: TBits, start: int, end: int) -> TBits:
1579 """Used internally to get a slice, without error checking."""
1580 bs = self.__class__()
1581 bs._bitstore = self._bitstore.getslice(slice(start, end, None))
1582 return bs
1584 def _absolute_slice(self: TBits, start: int, end: int) -> TBits:
1585 """Used internally to get a slice, without error checking.
1586 Uses MSB0 bit numbering even if LSB0 is set."""
1587 if end == start:
1588 return self.__class__()
1589 assert start < end, f"start={start}, end={end}"
1590 bs = self.__class__()
1591 bs._bitstore = self._bitstore.getslice_msb0(slice(start, end, None))
1592 return bs
1594 def _readtoken(self, name: str, pos: int, length: Optional[int]) -> Tuple[Union[float, int, str, None, Bits], int]:
1595 """Reads a token from the bitstring and returns the result."""
1596 if length is not None and length > self.length - pos:
1597 raise ReadError("Reading off the end of the data. "
1598 f"Tried to read {length} bits when only {self.length - pos} available.")
1599 try:
1600 val = self._name_to_read[name](self, pos, length)
1601 if isinstance(val, tuple):
1602 return val
1603 else:
1604 assert length is not None
1605 return val, pos + length
1606 except KeyError:
1607 raise ValueError(f"Can't parse token {name}:{length}")
1609 def _addright(self, bs: Bits) -> None:
1610 """Add a bitstring to the RHS of the current bitstring."""
1611 self._bitstore += bs._bitstore
1613 def _addleft(self, bs: Bits) -> None:
1614 """Prepend a bitstring to the current bitstring."""
1615 if bs._bitstore.immutable:
1616 self._bitstore = bs._bitstore.copy() + self._bitstore
1617 else:
1618 self._bitstore = bs._bitstore + self._bitstore
1620 def _truncateleft(self: TBits, bits: int) -> TBits:
1621 """Truncate bits from the start of the bitstring. Return the truncated bits."""
1622 assert 0 <= bits <= self.len
1623 if not bits:
1624 return self.__class__()
1625 truncated_bits = self._absolute_slice(0, bits)
1626 if bits == self.len:
1627 self._clear()
1628 return truncated_bits
1629 self._bitstore = self._bitstore.getslice_msb0(slice(bits, None, None))
1630 return truncated_bits
1632 def _truncateright(self: TBits, bits: int) -> TBits:
1633 """Truncate bits from the end of the bitstring. Return the truncated bits."""
1634 assert 0 <= bits <= self.len
1635 if bits == 0:
1636 return self.__class__()
1637 truncated_bits = self._absolute_slice(self.length - bits, self.length)
1638 if bits == self.len:
1639 self._clear()
1640 return truncated_bits
1641 self._bitstore = self._bitstore.getslice_msb0(slice(None, -bits, None))
1642 return truncated_bits
1644 def _insert(self, bs: Bits, pos: int) -> None:
1645 """Insert bs at pos."""
1646 assert 0 <= pos <= self.len
1647 self._bitstore[pos: pos] = bs._bitstore
1648 return
1650 def _overwrite(self, bs: Bits, pos: int) -> None:
1651 """Overwrite with bs at pos."""
1652 assert 0 <= pos <= self.len
1653 if bs is self:
1654 # Just overwriting with self, so do nothing.
1655 assert pos == 0
1656 return
1657 self._bitstore[pos: pos + bs.len] = bs._bitstore
1659 def _delete(self, bits: int, pos: int) -> None:
1660 """Delete bits at pos."""
1661 assert 0 <= pos <= self.len
1662 assert pos + bits <= self.len, f"pos={pos}, bits={bits}, len={self.len}"
1663 del self._bitstore[pos: pos + bits]
1664 return
1666 def _reversebytes(self, start: int, end: int) -> None:
1667 """Reverse bytes in-place."""
1668 assert (end - start) % 8 == 0
1669 self._bitstore[start:end] = BitStore(frombytes=self._bitstore.getslice(slice(start, end, None)).tobytes()[::-1])
1671 def _invert(self, pos: int) -> None:
1672 """Flip bit at pos 1<->0."""
1673 assert 0 <= pos < self.len
1674 self._bitstore.invert(pos)
1676 def _invert_all(self) -> None:
1677 """Invert every bit."""
1678 self._bitstore.invert()
1680 def _ilshift(self: TBits, n: int) -> TBits:
1681 """Shift bits by n to the left in place. Return self."""
1682 assert 0 < n <= self.len
1683 self._addright(Bits(n))
1684 self._truncateleft(n)
1685 return self
1687 def _irshift(self: TBits, n: int) -> TBits:
1688 """Shift bits by n to the right in place. Return self."""
1689 assert 0 < n <= self.len
1690 self._addleft(Bits(n))
1691 self._truncateright(n)
1692 return self
1694 def _imul(self: TBits, n: int) -> TBits:
1695 """Concatenate n copies of self in place. Return self."""
1696 assert n >= 0
1697 if not n:
1698 self._clear()
1699 return self
1700 m: int = 1
1701 old_len: int = self.len
1702 while m * 2 < n:
1703 self._addright(self)
1704 m *= 2
1705 self._addright(self[0:(n - m) * old_len])
1706 return self
1708 def _readbits(self: TBits, start: int, length: int) -> TBits:
1709 """Read some bits from the bitstring and return newly constructed bitstring."""
1710 return self._slice(start, start + length)
1712 def _validate_slice(self, start: Optional[int], end: Optional[int]) -> Tuple[int, int]:
1713 """Validate start and end and return them as positive bit positions."""
1714 if start is None:
1715 start = 0
1716 elif start < 0:
1717 start += self._getlength()
1718 if end is None:
1719 end = self._getlength()
1720 elif end < 0:
1721 end += self._getlength()
1722 if not 0 <= end <= self._getlength():
1723 raise ValueError("end is not a valid position in the bitstring.")
1724 if not 0 <= start <= self._getlength():
1725 raise ValueError("start is not a valid position in the bitstring.")
1726 if end < start:
1727 raise ValueError("end must not be less than start.")
1728 return start, end
1730 def unpack(self, fmt: Union[str, List[Union[str, int]]], **kwargs) -> List[Union[int, float, str, Bits, bool, bytes, None]]:
1731 """Interpret the whole bitstring using fmt and return list.
1733 fmt -- A single string or a list of strings with comma separated tokens
1734 describing how to interpret the bits in the bitstring. Items
1735 can also be integers, for reading new bitstring of the given length.
1736 kwargs -- A dictionary or keyword-value pairs - the keywords used in the
1737 format string will be replaced with their given value.
1739 Raises ValueError if the format is not understood. If not enough bits
1740 are available then all bits to the end of the bitstring will be used.
1742 See the docstring for 'read' for token examples.
1744 """
1745 return self._readlist(fmt, 0, **kwargs)[0]
1747 def _readlist(self, fmt: Union[str, List[Union[str, int]]], pos: int, **kwargs: int) \
1748 -> Tuple[List[Union[int, float, str, Bits, bool, bytes, None]], int]:
1749 tokens: List[Tuple[str, Optional[Union[str, int]], Optional[str]]] = []
1750 if isinstance(fmt, str):
1751 fmt = [fmt]
1752 keys: Tuple[str, ...] = tuple(sorted(kwargs.keys()))
1754 def convert_length_strings(length_: Optional[Union[str, int]]) -> Optional[int]:
1755 int_length: Optional[int] = None
1756 if isinstance(length_, str):
1757 if length_ in kwargs:
1758 int_length = kwargs[length_]
1759 if name == 'bytes':
1760 int_length *= 8
1761 else:
1762 int_length = length_
1763 return int_length
1765 has_stretchy_token = False
1766 for f_item in fmt:
1767 # Replace integers with 'bits' tokens
1768 if isinstance(f_item, numbers.Integral):
1769 tokens.append(('bits', f_item, None))
1770 else:
1771 stretchy, tkns = tokenparser(f_item, keys)
1772 if stretchy:
1773 if has_stretchy_token:
1774 raise Error("It's not possible to have more than one 'filler' token.")
1775 has_stretchy_token = True
1776 tokens.extend(tkns)
1777 if not has_stretchy_token:
1778 lst = []
1779 for name, length, _ in tokens:
1780 length = convert_length_strings(length)
1781 if name in kwargs and length is None:
1782 # Using default 'bits' - the name is really the length.
1783 value, pos = self._readtoken('bits', pos, kwargs[name])
1784 lst.append(value)
1785 continue
1786 value, pos = self._readtoken(name, pos, length)
1787 if value is not None: # Don't append pad tokens
1788 lst.append(value)
1789 return lst, pos
1790 stretchy_token: Optional[tuple] = None
1791 bits_after_stretchy_token = 0
1792 for token in tokens:
1793 name, length, _ = token
1794 length = convert_length_strings(length)
1795 if stretchy_token:
1796 if name in ('se', 'ue', 'sie', 'uie'):
1797 raise Error("It's not possible to parse a variable length token after a 'filler' token.")
1798 else:
1799 if length is None:
1800 raise Error("It's not possible to have more than one 'filler' token.")
1801 bits_after_stretchy_token += length
1802 if length is None and name not in ('se', 'ue', 'sie', 'uie'):
1803 assert not stretchy_token
1804 stretchy_token = token
1805 bits_left = self.len - pos
1806 return_values = []
1807 for token in tokens:
1808 name, length, _ = token
1809 if token is stretchy_token:
1810 # Set length to the remaining bits
1811 length = max(bits_left - bits_after_stretchy_token, 0)
1812 length = convert_length_strings(length)
1813 value, newpos = self._readtoken(name, pos, length)
1814 bits_left -= newpos - pos
1815 pos = newpos
1816 if value is not None:
1817 return_values.append(value)
1818 return return_values, pos
1820 def find(self, bs: BitsType, start: Optional[int] = None, end: Optional[int] = None,
1821 bytealigned: Optional[bool] = None) -> Union[Tuple[int], Tuple[()]]:
1822 """Find first occurrence of substring bs.
1824 Returns a single item tuple with the bit position if found, or an
1825 empty tuple if not found. The bit position (pos property) will
1826 also be set to the start of the substring if it is found.
1828 bs -- The bitstring to find.
1829 start -- The bit position to start the search. Defaults to 0.
1830 end -- The bit position one past the last bit to search.
1831 Defaults to len(self).
1832 bytealigned -- If True the bitstring will only be
1833 found on byte boundaries.
1835 Raises ValueError if bs is empty, if start < 0, if end > len(self) or
1836 if end < start.
1838 >>> BitArray('0xc3e').find('0b1111')
1839 (6,)
1841 """
1842 bs = Bits._create_from_bitstype(bs)
1843 if len(bs) == 0:
1844 raise ValueError("Cannot find an empty bitstring.")
1845 start, end = self._validate_slice(start, end)
1846 ba = _bytealigned if bytealigned is None else bytealigned
1847 p = self._find(bs, start, end, ba)
1848 return p
1850 def _find_lsb0(self, bs: Bits, start: int, end: int, bytealigned: bool) -> Union[Tuple[int], Tuple[()]]:
1851 # A forward find in lsb0 is very like a reverse find in msb0.
1852 assert start <= end
1853 assert _lsb0
1855 new_slice = _offset_slice_indices_lsb0(slice(start, end, None), len(self), 0)
1856 msb0_start, msb0_end = self._validate_slice(new_slice.start, new_slice.stop)
1857 p = self._rfind_msb0(bs, msb0_start, msb0_end, bytealigned)
1859 if p:
1860 return (self.length - p[0] - bs.length,)
1861 else:
1862 return ()
1864 def _find_msb0(self, bs: Bits, start: int, end: int, bytealigned: bool) -> Union[Tuple[int], Tuple[()]]:
1865 """Find first occurrence of a binary string."""
1866 while True:
1867 p = self._bitstore.find(bs._bitstore, start, end)
1868 if p == -1:
1869 return ()
1870 if not bytealigned or (p % 8) == 0:
1871 return (p,)
1872 # Advance to just beyond the non-byte-aligned match and try again...
1873 start = p + 1
1875 def findall(self, bs: BitsType, start: Optional[int] = None, end: Optional[int] = None, count: Optional[int] = None,
1876 bytealigned: Optional[bool] = None) -> Iterable[int]:
1877 """Find all occurrences of bs. Return generator of bit positions.
1879 bs -- The bitstring to find.
1880 start -- The bit position to start the search. Defaults to 0.
1881 end -- The bit position one past the last bit to search.
1882 Defaults to len(self).
1883 count -- The maximum number of occurrences to find.
1884 bytealigned -- If True the bitstring will only be found on
1885 byte boundaries.
1887 Raises ValueError if bs is empty, if start < 0, if end > len(self) or
1888 if end < start.
1890 Note that all occurrences of bs are found, even if they overlap.
1892 """
1893 if count is not None and count < 0:
1894 raise ValueError("In findall, count must be >= 0.")
1895 bs = Bits._create_from_bitstype(bs)
1896 start, end = self._validate_slice(start, end)
1897 ba = _bytealigned if bytealigned is None else bytealigned
1898 return self._findall(bs, start, end, count, ba)
1900 def _findall_msb0(self, bs: Bits, start: int, end: int, count: Optional[int],
1901 bytealigned: bool) -> Iterable[int]:
1902 c = 0
1903 for i in self._bitstore.getslice_msb0(slice(start, end, None)).itersearch(bs._bitstore):
1904 if count is not None and c >= count:
1905 return
1906 if bytealigned:
1907 if (start + i) % 8 == 0:
1908 c += 1
1909 yield start + i
1910 else:
1911 c += 1
1912 yield start + i
1913 return
1915 def _findall_lsb0(self, bs: Bits, start: int, end: int, count: Optional[int],
1916 bytealigned: bool) -> Iterable[int]:
1917 assert start <= end
1918 assert _lsb0
1920 new_slice = _offset_slice_indices_lsb0(slice(start, end, None), len(self), 0)
1921 msb0_start, msb0_end = self._validate_slice(new_slice.start, new_slice.stop)
1923 # Search chunks starting near the end and then moving back.
1924 c = 0
1925 increment = max(8192, bs.len * 80)
1926 buffersize = min(increment + bs.len, msb0_end - msb0_start)
1927 pos = max(msb0_start, msb0_end - buffersize)
1928 while True:
1929 found = list(self._findall_msb0(bs, start=pos, end=pos + buffersize, count=None, bytealigned=False))
1930 if not found:
1931 if pos == msb0_start:
1932 return
1933 pos = max(msb0_start, pos - increment)
1934 continue
1935 while found:
1936 if count is not None and c >= count:
1937 return
1938 c += 1
1939 lsb0_pos = self.len - found.pop() - bs.len
1940 if not bytealigned or lsb0_pos % 8 == 0:
1941 yield lsb0_pos
1943 pos = max(msb0_start, pos - increment)
1944 if pos == msb0_start:
1945 return
1947 def rfind(self, bs: BitsType, start: Optional[int] = None, end: Optional[int] = None,
1948 bytealigned: Optional[bool] = None) -> Union[Tuple[int], Tuple[()]]:
1949 """Find final occurrence of substring bs.
1951 Returns a single item tuple with the bit position if found, or an
1952 empty tuple if not found. The bit position (pos property) will
1953 also be set to the start of the substring if it is found.
1955 bs -- The bitstring to find.
1956 start -- The bit position to end the reverse search. Defaults to 0.
1957 end -- The bit position one past the first bit to reverse search.
1958 Defaults to len(self).
1959 bytealigned -- If True the bitstring will only be found on byte
1960 boundaries.
1962 Raises ValueError if bs is empty, if start < 0, if end > len(self) or
1963 if end < start.
1965 """
1966 bs = Bits._create_from_bitstype(bs)
1967 start, end = self._validate_slice(start, end)
1968 ba = _bytealigned if bytealigned is None else bytealigned
1969 if not bs.len:
1970 raise ValueError("Cannot find an empty bitstring.")
1971 p = self._rfind(bs, start, end, ba)
1972 return p
1974 def _rfind_msb0(self, bs: Bits, start: int, end: int, bytealigned: bool) -> Union[Tuple[int], Tuple[()]]:
1975 """Find final occurrence of a binary string."""
1976 increment = max(4096, len(bs) * 64)
1977 buffersize = increment + len(bs)
1978 p = end
1979 while p > start:
1980 start_pos = max(start, p - buffersize)
1981 ps = list(self._findall_msb0(bs, start_pos, p, count=None, bytealigned=False))
1982 if ps:
1983 while ps:
1984 if not bytealigned or (ps[-1] % 8 == 0):
1985 return (ps[-1],)
1986 ps.pop()
1987 p -= increment
1988 return ()
1990 def _rfind_lsb0(self, bs: Bits, start: int, end: int, bytealigned: bool) -> Union[Tuple[int], Tuple[()]]:
1991 # A reverse find in lsb0 is very like a forward find in msb0.
1992 assert start <= end
1993 assert _lsb0
1994 new_slice = _offset_slice_indices_lsb0(slice(start, end, None), len(self), 0)
1995 msb0_start, msb0_end = self._validate_slice(new_slice.start, new_slice.stop)
1997 p = self._find_msb0(bs, msb0_start, msb0_end, bytealigned)
1998 if p:
1999 return (self.len - p[0] - bs.length,)
2000 else:
2001 return ()
2003 def cut(self, bits: int, start: Optional[int] = None, end: Optional[int] = None,
2004 count: Optional[int] = None) -> Iterator[Bits]:
2005 """Return bitstring generator by cutting into bits sized chunks.
2007 bits -- The size in bits of the bitstring chunks to generate.
2008 start -- The bit position to start the first cut. Defaults to 0.
2009 end -- The bit position one past the last bit to use in the cut.
2010 Defaults to len(self).
2011 count -- If specified then at most count items are generated.
2012 Default is to cut as many times as possible.
2014 """
2015 start_, end_ = self._validate_slice(start, end)
2016 if count is not None and count < 0:
2017 raise ValueError("Cannot cut - count must be >= 0.")
2018 if bits <= 0:
2019 raise ValueError("Cannot cut - bits must be >= 0.")
2020 c = 0
2021 while count is None or c < count:
2022 c += 1
2023 nextchunk = self._slice(start_, min(start_ + bits, end_))
2024 if nextchunk.len == 0:
2025 return
2026 yield nextchunk
2027 if nextchunk._getlength() != bits:
2028 return
2029 start_ += bits
2030 return
2032 def split(self, delimiter: BitsType, start: Optional[int] = None, end: Optional[int] = None,
2033 count: Optional[int] = None, bytealigned: Optional[bool] = None) -> Iterable[Bits]:
2034 """Return bitstring generator by splitting using a delimiter.
2036 The first item returned is the initial bitstring before the delimiter,
2037 which may be an empty bitstring.
2039 delimiter -- The bitstring used as the divider.
2040 start -- The bit position to start the split. Defaults to 0.
2041 end -- The bit position one past the last bit to use in the split.
2042 Defaults to len(self).
2043 count -- If specified then at most count items are generated.
2044 Default is to split as many times as possible.
2045 bytealigned -- If True splits will only occur on byte boundaries.
2047 Raises ValueError if the delimiter is empty.
2049 """
2050 delimiter = Bits._create_from_bitstype(delimiter)
2051 if len(delimiter) == 0:
2052 raise ValueError("split delimiter cannot be empty.")
2053 start, end = self._validate_slice(start, end)
2054 bytealigned_: bool = _bytealigned if bytealigned is None else bytealigned
2055 if count is not None and count < 0:
2056 raise ValueError("Cannot split - count must be >= 0.")
2057 if count == 0:
2058 return
2059 f = functools.partial(self._find_msb0, bs=delimiter, bytealigned=bytealigned_)
2060 found = f(start=start, end=end)
2061 if not found:
2062 # Initial bits are the whole bitstring being searched
2063 yield self._slice(start, end)
2064 return
2065 # yield the bytes before the first occurrence of the delimiter, even if empty
2066 yield self._slice(start, found[0])
2067 startpos = pos = found[0]
2068 c = 1
2069 while count is None or c < count:
2070 pos += delimiter.len
2071 found = f(start=pos, end=end)
2072 if not found:
2073 # No more occurrences, so return the rest of the bitstring
2074 yield self._slice(startpos, end)
2075 return
2076 c += 1
2077 yield self._slice(startpos, found[0])
2078 startpos = pos = found[0]
2079 # Have generated count bitstrings, so time to quit.
2080 return
2082 def join(self: TBits, sequence: Iterable[Any]) -> TBits:
2083 """Return concatenation of bitstrings joined by self.
2085 sequence -- A sequence of bitstrings.
2087 """
2088 s = self.__class__()
2089 if len(self) == 0:
2090 # Optimised version that doesn't need to add self between every item
2091 for item in sequence:
2092 s._addright(Bits._create_from_bitstype(item))
2093 else:
2094 i = iter(sequence)
2095 try:
2096 s._addright(Bits._create_from_bitstype(next(i)))
2097 while True:
2098 n = next(i)
2099 s._addright(self)
2100 s._addright(Bits._create_from_bitstype(n))
2101 except StopIteration:
2102 pass
2103 return s
2105 def tobytes(self) -> bytes:
2106 """Return the bitstring as bytes, padding with zero bits if needed.
2108 Up to seven zero bits will be added at the end to byte align.
2110 """
2111 return self._bitstore.tobytes()
2113 def tobitarray(self) -> bitarray.bitarray:
2114 """Convert the bitstring to a bitarray object."""
2115 if self._bitstore.modified:
2116 # Removes the offset and truncates to length
2117 return bitarray.bitarray(self._bitstore.copy())
2118 else:
2119 return bitarray.bitarray(self._bitstore)
2121 def tofile(self, f: BinaryIO) -> None:
2122 """Write the bitstring to a file object, padding with zero bits if needed.
2124 Up to seven zero bits will be added at the end to byte align.
2126 """
2127 # If the bitstring is file based then we don't want to read it all in to memory first.
2128 chunk_size = 8 * 100 * 1024 * 1024 # 100 MiB
2129 for chunk in self.cut(chunk_size):
2130 f.write(chunk.tobytes())
2132 def startswith(self, prefix: BitsType, start: Optional[int] = None, end: Optional[int] = None) -> bool:
2133 """Return whether the current bitstring starts with prefix.
2135 prefix -- The bitstring to search for.
2136 start -- The bit position to start from. Defaults to 0.
2137 end -- The bit position to end at. Defaults to len(self).
2139 """
2140 prefix = self._create_from_bitstype(prefix)
2141 start, end = self._validate_slice(start, end)
2142 if end < start + prefix._getlength():
2143 return False
2144 end = start + prefix._getlength()
2145 return self._slice(start, end) == prefix
2147 def endswith(self, suffix: BitsType, start: Optional[int] = None, end: Optional[int] = None) -> bool:
2148 """Return whether the current bitstring ends with suffix.
2150 suffix -- The bitstring to search for.
2151 start -- The bit position to start from. Defaults to 0.
2152 end -- The bit position to end at. Defaults to len(self).
2154 """
2155 suffix = self._create_from_bitstype(suffix)
2156 start, end = self._validate_slice(start, end)
2157 if start + suffix.len > end:
2158 return False
2159 start = end - suffix._getlength()
2160 return self._slice(start, end) == suffix
2162 def all(self, value: Any, pos: Optional[Iterable[int]] = None) -> bool:
2163 """Return True if one or many bits are all set to bool(value).
2165 value -- If value is True then checks for bits set to 1, otherwise
2166 checks for bits set to 0.
2167 pos -- An iterable of bit positions. Negative numbers are treated in
2168 the same way as slice indices. Defaults to the whole bitstring.
2170 """
2171 value = bool(value)
2172 length = self.len
2173 if pos is None:
2174 if value is True:
2175 return self._bitstore.all_set()
2176 else:
2177 return not self._bitstore.any_set()
2178 for p in pos:
2179 if p < 0:
2180 p += length
2181 if not 0 <= p < length:
2182 raise IndexError(f"Bit position {p} out of range.")
2183 if not bool(self._bitstore.getindex(p)) is value:
2184 return False
2185 return True
2187 def any(self, value: Any, pos: Optional[Iterable[int]] = None) -> bool:
2188 """Return True if any of one or many bits are set to bool(value).
2190 value -- If value is True then checks for bits set to 1, otherwise
2191 checks for bits set to 0.
2192 pos -- An iterable of bit positions. Negative numbers are treated in
2193 the same way as slice indices. Defaults to the whole bitstring.
2195 """
2196 value = bool(value)
2197 length = self.len
2198 if pos is None:
2199 if value is True:
2200 return self._bitstore.any_set()
2201 else:
2202 return not self._bitstore.all_set()
2203 for p in pos:
2204 if p < 0:
2205 p += length
2206 if not 0 <= p < length:
2207 raise IndexError(f"Bit position {p} out of range.")
2208 if bool(self._bitstore.getindex(p)) is value:
2209 return True
2210 return False
2212 def count(self, value: Any) -> int:
2213 """Return count of total number of either zero or one bits.
2215 value -- If bool(value) is True then bits set to 1 are counted, otherwise bits set
2216 to 0 are counted.
2218 >>> Bits('0xef').count(1)
2219 7
2221 """
2222 # count the number of 1s (from which it's easy to work out the 0s).
2223 count = self._bitstore.count(1)
2224 return count if value else self.len - count
2226 @staticmethod
2227 def _chars_in_pp_token(fmt: str) -> Tuple[str, Optional[int]]:
2228 """
2229 bin8 -> 'bin', 8
2230 hex12 -> 'hex', 3
2231 o9 -> 'oct', 3
2232 b -> 'bin', None
2233 """
2234 bpc_dict = {'bin': 1, 'oct': 3, 'hex': 4, 'bytes': 8} # bits represented by each printed character
2235 short_token: Pattern[str] = re.compile(r'(?P<name>bytes|bin|oct|hex|b|o|h):?(?P<len>\d+)$')
2237 m1 = short_token.match(fmt)
2238 if m1:
2239 length = int(m1.group('len'))
2240 name = m1.group('name')
2241 else:
2242 length = None
2243 name = fmt
2244 aliases = {'hex': 'hex', 'oct': 'oct', 'bin': 'bin', 'bytes': 'bytes', 'b': 'bin', 'o': 'oct', 'h': 'hex'}
2245 try:
2246 name = aliases[name]
2247 except KeyError:
2248 pass # Should be dealt with in the next check
2249 if name not in bpc_dict.keys():
2250 raise ValueError(f"Pretty print formats only support {'/'.join(bpc_dict.keys())}. Received '{fmt}'.")
2251 bpc = bpc_dict[name]
2252 if length is None:
2253 return name, None
2254 if length % bpc != 0:
2255 raise ValueError(f"Bits per group must be a multiple of {bpc} for '{fmt}' format.")
2256 return name, length
2258 @staticmethod
2259 def _format_bits(bits: Bits, chars_per_group: int, bits_per_group: int, sep: str, fmt: str, getter_fn=None) -> str:
2260 if fmt in ['bin', 'oct', 'hex', 'bytes']:
2261 raw = {'bin': bits._getbin,
2262 'oct': bits._getoct,
2263 'hex': bits._gethex,
2264 'bytes': bits._getbytes_printable}[fmt]()
2265 if chars_per_group == 0:
2266 return raw
2267 formatted = sep.join(raw[i: i + chars_per_group] for i in range(0, len(raw), chars_per_group))
2268 return formatted
2270 else:
2271 if fmt == 'bits':
2272 formatted = sep.join(str(getter_fn(b, 0)) for b in bits.cut(bits_per_group))
2273 return formatted
2274 else:
2275 values = []
2276 for i in range(0, len(bits), bits_per_group):
2277 b = bits[i: i + bits_per_group]
2278 values.append(f"{getter_fn(b, 0): >{chars_per_group}}")
2279 formatted = sep.join(values)
2280 return formatted
2282 @staticmethod
2283 def _chars_per_group(bits_per_group: int, fmt: Optional[str]):
2284 if fmt is None:
2285 return 0
2286 bpc = {'bin': 1, 'oct': 3, 'hex': 4, 'bytes': 8} # bits represented by each printed character
2287 try:
2288 return bits_per_group // bpc[fmt]
2289 except KeyError:
2290 # Work out how many chars are needed for each format given the number of bits
2291 if fmt in ['uint', 'uintne', 'uintbe', 'uintle']:
2292 # How many chars is largest uint?
2293 chars_per_value = len(str((1 << bits_per_group) - 1))
2294 elif fmt in ['int', 'intne', 'intbe', 'intle']:
2295 # Use largest negative int so we get the '-' sign
2296 chars_per_value = len(str((-1 << (bits_per_group - 1))))
2297 elif fmt in ['bfloat', 'bfloatne', 'bfloatbe', 'bfloatle']:
2298 chars_per_value = 23 # Empirical value
2299 elif fmt in ['float', 'floatne', 'floatbe', 'floatle']:
2300 if bits_per_group in [16, 32]:
2301 chars_per_value = 23 # Empirical value
2302 elif bits_per_group == 64:
2303 chars_per_value = 24 # Empirical value
2304 elif fmt == 'float8_143':
2305 chars_per_value = 13 # Empirical value
2306 elif fmt == 'float8_152':
2307 chars_per_value = 19 # Empirical value
2308 elif fmt == 'bool':
2309 chars_per_value = 1 # '0' or '1'
2310 elif fmt == 'bits':
2311 temp = BitArray(bits_per_group)
2312 chars_per_value = len(str(temp))
2313 else:
2314 assert False, f"Unsupported format string {fmt}."
2315 raise ValueError(f"Unsupported format string {fmt}.")
2316 return chars_per_value
2318 def _pp(self, name1: str, name2: Optional[str], bits_per_group: int, width: int, sep: str, format_sep: str,
2319 show_offset: bool, stream: TextIO, lsb0: bool, offset_factor: int, getter_fn=None, getter_fn2=None) -> None:
2320 """Internal pretty print method."""
2322 bpc = {'bin': 1, 'oct': 3, 'hex': 4, 'bytes': 8} # bits represented by each printed character
2324 offset_width = 0
2325 offset_sep = ' :' if lsb0 else ': '
2326 if show_offset:
2327 # This could be 1 too large in some circumstances. Slightly recurrent logic needed to fix it...
2328 offset_width = len(str(len(self))) + len(offset_sep)
2329 if bits_per_group > 0:
2330 group_chars1 = Bits._chars_per_group(bits_per_group, name1)
2331 group_chars2 = Bits._chars_per_group(bits_per_group, name2)
2332 # The number of characters that get added when we add an extra group (after the first one)
2333 total_group_chars = group_chars1 + group_chars2 + len(sep) + len(sep) * bool(group_chars2)
2334 width_excluding_offset_and_final_group = width - offset_width - group_chars1 - group_chars2 - len(
2335 format_sep) * bool(group_chars2)
2336 width_excluding_offset_and_final_group = max(width_excluding_offset_and_final_group, 0)
2337 groups_per_line = 1 + width_excluding_offset_and_final_group // total_group_chars
2338 max_bits_per_line = groups_per_line * bits_per_group # Number of bits represented on each line
2339 else:
2340 assert bits_per_group == 0 # Don't divide into groups
2341 group_chars1 = group_chars2 = 0
2342 width_available = width - offset_width - len(format_sep) * (name2 is not None)
2343 width_available = max(width_available, 1)
2344 if name2 is None:
2345 max_bits_per_line = width_available * bpc[name1]
2346 else:
2347 chars_per_24_bits = 24 // bpc[name1] + 24 // bpc[name2]
2348 max_bits_per_line = 24 * (width_available // chars_per_24_bits)
2349 if max_bits_per_line == 0:
2350 max_bits_per_line = 24 # We can't fit into the width asked for. Show something small.
2351 assert max_bits_per_line > 0
2353 bitpos = 0
2354 first_fb_width = second_fb_width = None
2355 for bits in self.cut(max_bits_per_line):
2356 offset = bitpos // offset_factor
2357 if _lsb0:
2358 offset_str = f'{offset_sep}{offset: >{offset_width - len(offset_sep)}}' if show_offset else ''
2359 else:
2360 offset_str = f'{offset: >{offset_width - len(offset_sep)}}{offset_sep}' if show_offset else ''
2361 fb = Bits._format_bits(bits, group_chars1, bits_per_group, sep, name1, getter_fn)
2362 if first_fb_width is None:
2363 first_fb_width = len(fb)
2364 if len(fb) < first_fb_width: # Pad final line with spaces to align it
2365 if _lsb0:
2366 fb = ' ' * (first_fb_width - len(fb)) + fb
2367 else:
2368 fb += ' ' * (first_fb_width - len(fb))
2369 fb2 = '' if name2 is None else format_sep + Bits._format_bits(bits, group_chars2, bits_per_group, sep, name2, getter_fn2)
2370 if second_fb_width is None:
2371 second_fb_width = len(fb2)
2372 if len(fb2) < second_fb_width:
2373 if _lsb0:
2374 fb2 = ' ' * (second_fb_width - len(fb2)) + fb2
2375 else:
2376 fb2 += ' ' * (second_fb_width - len(fb2))
2377 if _lsb0 is True:
2378 line_fmt = fb + fb2 + offset_str + '\n'
2379 else:
2380 line_fmt = offset_str + fb + fb2 + '\n'
2381 stream.write(line_fmt)
2382 bitpos += len(bits)
2383 return
2385 def pp(self, fmt: Optional[str] = None, width: int = 120, sep: str = ' ',
2386 show_offset: bool = True, stream: TextIO = sys.stdout) -> None:
2387 """Pretty print the bitstring's value.
2389 fmt -- Printed data format. One or two of 'bin', 'oct', 'hex' or 'bytes'.
2390 The number of bits represented in each printed group defaults to 8 for hex and bin,
2391 12 for oct and 32 for bytes. This can be overridden with an explicit length, e.g. 'hex:64'.
2392 Use a length of 0 to not split into groups, e.g. `bin:0`.
2393 width -- Max width of printed lines. Defaults to 120. A single group will always be printed
2394 per line even if it exceeds the max width.
2395 sep -- A separator string to insert between groups. Defaults to a single space.
2396 show_offset -- If True (the default) shows the bit offset in the first column of each line.
2397 stream -- A TextIO object with a write() method. Defaults to sys.stdout.
2399 >>> s.pp('hex16')
2400 >>> s.pp('b, h', sep='_', show_offset=False)
2402 """
2403 if fmt is None:
2404 fmt = 'bin' if len(self) % 4 != 0 else 'bin, hex'
2406 bpc = {'bin': 1, 'oct': 3, 'hex': 4, 'bytes': 8} # bits represented by each printed character
2408 formats = [f.strip() for f in fmt.split(',')]
2409 if len(formats) == 1:
2410 fmt1, fmt2 = formats[0], None
2411 elif len(formats) == 2:
2412 fmt1, fmt2 = formats[0], formats[1]
2413 else:
2414 raise ValueError(f"Either 1 or 2 comma separated formats must be specified, not {len(formats)}."
2415 " Format string was {fmt}.")
2417 name1, length1 = Bits._chars_in_pp_token(fmt1)
2418 if fmt2 is not None:
2419 name2, length2 = Bits._chars_in_pp_token(fmt2)
2421 if fmt2 is not None and length2 is not None and length1 is not None:
2422 # Both lengths defined so must be equal
2423 if length1 != length2:
2424 raise ValueError(f"Differing bit lengths of {length1} and {length2} in format string '{fmt}'.")
2426 bits_per_group = None
2427 if fmt2 is not None and length2 is not None:
2428 bits_per_group = length2
2429 elif length1 is not None:
2430 bits_per_group = length1
2432 if bits_per_group is None:
2433 if fmt2 is None:
2434 bits_per_group = 8 # Default for 'bin' and 'hex'
2435 if name1 == 'oct':
2436 bits_per_group = 12
2437 elif name1 == 'bytes':
2438 bits_per_group = 32
2439 else:
2440 # Rule of thumb seems to work OK for all combinations.
2441 bits_per_group = 2 * bpc[name1] * bpc[name2]
2442 if bits_per_group >= 24:
2443 bits_per_group //= 2
2445 format_sep = " " # String to insert on each line between multiple formats
2447 self._pp(name1, name2 if fmt2 is not None else None, bits_per_group, width, sep, format_sep, show_offset, stream, _lsb0, 1)
2448 return
2450 def copy(self: TBits) -> TBits:
2451 """Return a copy of the bitstring."""
2452 return self._copy()
2454 # Create native-endian functions as aliases depending on the byteorder
2455 if byteorder == 'little':
2456 _setfloatne = _setfloatle
2457 _readfloatne = _readfloatle
2458 _getfloatne = _getfloatle
2459 _setbfloatne = _setbfloatle
2460 _readbfloatne = _readbfloatle
2461 _getbfloatne = _getbfloatle
2462 _setuintne = _setuintle
2463 _readuintne = _readuintle
2464 _getuintne = _getuintle
2465 _setintne = _setintle
2466 _readintne = _readintle
2467 _getintne = _getintle
2468 else:
2469 _setfloatne = _setfloatbe
2470 _readfloatne = _readfloatbe
2471 _getfloatne = _getfloatbe
2472 _setbfloatne = _setbfloatbe
2473 _readbfloatne = _readbfloatbe
2474 _getbfloatne = _getbfloatbe
2475 _setuintne = _setuintbe
2476 _readuintne = _readuintbe
2477 _getuintne = _getuintbe
2478 _setintne = _setintbe
2479 _readintne = _readintbe
2480 _getintne = _getintbe
2482 # Dictionary that maps token names to the function that reads them
2483 _name_to_read: Dict[str, Callable[[Bits, int, int], Any]] = {
2484 'uint': _readuint,
2485 'u': _readuint,
2486 'uintle': _readuintle,
2487 'uintbe': _readuintbe,
2488 'uintne': _readuintne,
2489 'int': _readint,
2490 'i': _readint,
2491 'intle': _readintle,
2492 'intbe': _readintbe,
2493 'intne': _readintne,
2494 'float': _readfloatbe,
2495 'f': _readfloatbe,
2496 'floatbe': _readfloatbe, # floatbe is a synonym for float
2497 'floatle': _readfloatle,
2498 'floatne': _readfloatne,
2499 'bfloat': _readbfloatbe,
2500 'bfloatbe': _readbfloatbe,
2501 'bfloatle': _readbfloatle,
2502 'bfloatne': _readbfloatne,
2503 'hex': _readhex,
2504 'h': _readhex,
2505 'oct': _readoct,
2506 'o': _readoct,
2507 'bin': _readbin,
2508 'b': _readbin,
2509 'bits': _readbits,
2510 'bytes': _readbytes,
2511 'ue': _readue,
2512 'se': _readse,
2513 'uie': _readuie,
2514 'sie': _readsie,
2515 'bool': _readbool,
2516 'pad': _readpad,
2517 'float8_143': _readfloat143,
2518 'float8_152': _readfloat152
2519 }
2521 # Mapping token names to the methods used to set them
2522 _setfunc: Dict[str, Callable[..., None]] = {
2523 'bin': _setbin_safe,
2524 'hex': _sethex,
2525 'oct': _setoct,
2526 'ue': _setue,
2527 'se': _setse,
2528 'uie': _setuie,
2529 'sie': _setsie,
2530 'bool': _setbool,
2531 'uint': _setuint,
2532 'int': _setint,
2533 'float': _setfloatbe,
2534 'bfloat': _setbfloatbe,
2535 'bfloatbe': _setbfloatbe,
2536 'bfloatle': _setbfloatle,
2537 'bfloatne': _setbfloatne,
2538 'uintbe': _setuintbe,
2539 'intbe': _setintbe,
2540 'floatbe': _setfloatbe,
2541 'uintle': _setuintle,
2542 'intle': _setintle,
2543 'floatle': _setfloatle,
2544 'uintne': _setuintne,
2545 'intne': _setintne,
2546 'floatne': _setfloatne,
2547 'bytes': _setbytes,
2548 'filename': _setfile,
2549 'bitarray': _setbitarray,
2550 'float8_152': _setfloat152,
2551 'float8_143': _setfloat143,
2552 'bits': _setbits
2553 }
2555 len = property(_getlength,
2556 doc="""The length of the bitstring in bits. Read only.
2557 """)
2558 length = property(_getlength,
2559 doc="""The length of the bitstring in bits. Read only.
2560 """)
2561 bool = property(_getbool,
2562 doc="""The bitstring as a bool (True or False). Read only.
2563 """)
2564 hex = property(_gethex,
2565 doc="""The bitstring as a hexadecimal string. Read only.
2566 """)
2567 bin = property(_getbin,
2568 doc="""The bitstring as a binary string. Read only.
2569 """)
2570 oct = property(_getoct,
2571 doc="""The bitstring as an octal string. Read only.
2572 """)
2573 bytes = property(_getbytes,
2574 doc="""The bitstring as a bytes object. Read only.
2575 """)
2576 int = property(_getint,
2577 doc="""The bitstring as a two's complement signed int. Read only.
2578 """)
2579 uint = property(_getuint,
2580 doc="""The bitstring as a two's complement unsigned int. Read only.
2581 """)
2582 float = property(_getfloatbe,
2583 doc="""The bitstring as a big-endian floating point number. Read only.
2584 """)
2585 bfloat = property(_getbfloatbe,
2586 doc="""The bitstring as a 16 bit big-endian bfloat floating point number. Read only.
2587 """)
2588 bfloatbe = property(_getbfloatbe,
2589 doc="""The bitstring as a 16 bit big-endian bfloat floating point number. Read only.
2590 """)
2591 bfloatle = property(_getbfloatle,
2592 doc="""The bitstring as a 16 bit little-endian bfloat floating point number. Read only.
2593 """)
2594 bfloatne = property(_getbfloatne,
2595 doc="""The bitstring as a 16 bit native-endian bfloat floating point number. Read only.
2596 """)
2597 intbe = property(_getintbe,
2598 doc="""The bitstring as a two's complement big-endian signed int. Read only.
2599 """)
2600 uintbe = property(_getuintbe,
2601 doc="""The bitstring as a two's complement big-endian unsigned int. Read only.
2602 """)
2603 floatbe = property(_getfloatbe,
2604 doc="""The bitstring as a big-endian floating point number. Read only.
2605 """)
2606 intle = property(_getintle,
2607 doc="""The bitstring as a two's complement little-endian signed int. Read only.
2608 """)
2609 uintle = property(_getuintle,
2610 doc="""The bitstring as a two's complement little-endian unsigned int. Read only.
2611 """)
2612 floatle = property(_getfloatle,
2613 doc="""The bitstring as a little-endian floating point number. Read only.
2614 """)
2615 intne = property(_getintne,
2616 doc="""The bitstring as a two's complement native-endian signed int. Read only.
2617 """)
2618 uintne = property(_getuintne,
2619 doc="""The bitstring as a two's complement native-endian unsigned int. Read only.
2620 """)
2621 floatne = property(_getfloatne,
2622 doc="""The bitstring as a native-endian floating point number. Read only.
2623 """)
2624 ue = property(_getue,
2625 doc="""The bitstring as an unsigned exponential-Golomb code. Read only.
2626 """)
2627 se = property(_getse,
2628 doc="""The bitstring as a signed exponential-Golomb code. Read only.
2629 """)
2630 uie = property(_getuie,
2631 doc="""The bitstring as an unsigned interleaved exponential-Golomb code. Read only.
2632 """)
2633 sie = property(_getsie,
2634 doc="""The bitstring as a signed interleaved exponential-Golomb code. Read only.
2635 """)
2636 float8_143 = property(_getfloat143,
2637 doc="""The bitstring as an 8 bit float with float8_143 format. Read only.""")
2638 float8_152 = property(_getfloat152,
2639 doc="""The bitstring as an 8 bit float with float8_152 format. Read only.""")
2641 # Some shortened aliases of the above properties
2642 i = int
2643 u = uint
2644 f = float
2645 b = bin
2646 o = oct
2647 h = hex
2650class BitArray(Bits):
2651 """A container holding a mutable sequence of bits.
2653 Subclass of the immutable Bits class. Inherits all of its
2654 methods (except __hash__) and adds mutating methods.
2656 Mutating methods:
2658 append() -- Append a bitstring.
2659 byteswap() -- Change byte endianness in-place.
2660 clear() -- Remove all bits from the bitstring.
2661 insert() -- Insert a bitstring.
2662 invert() -- Flip bit(s) between one and zero.
2663 overwrite() -- Overwrite a section with a new bitstring.
2664 prepend() -- Prepend a bitstring.
2665 replace() -- Replace occurrences of one bitstring with another.
2666 reverse() -- Reverse bits in-place.
2667 rol() -- Rotate bits to the left.
2668 ror() -- Rotate bits to the right.
2669 set() -- Set bit(s) to 1 or 0.
2671 Methods inherited from Bits:
2673 all() -- Check if all specified bits are set to 1 or 0.
2674 any() -- Check if any of specified bits are set to 1 or 0.
2675 copy() -- Return a copy of the bitstring.
2676 count() -- Count the number of bits set to 1 or 0.
2677 cut() -- Create generator of constant sized chunks.
2678 endswith() -- Return whether the bitstring ends with a sub-string.
2679 find() -- Find a sub-bitstring in the current bitstring.
2680 findall() -- Find all occurrences of a sub-bitstring in the current bitstring.
2681 join() -- Join bitstrings together using current bitstring.
2682 pp() -- Pretty print the bitstring.
2683 rfind() -- Seek backwards to find a sub-bitstring.
2684 split() -- Create generator of chunks split by a delimiter.
2685 startswith() -- Return whether the bitstring starts with a sub-bitstring.
2686 tobitarray() -- Return bitstring as a bitarray from the bitarray package.
2687 tobytes() -- Return bitstring as bytes, padding if needed.
2688 tofile() -- Write bitstring to file, padding if needed.
2689 unpack() -- Interpret bits using format string.
2691 Special methods:
2693 Mutating operators are available: [], <<=, >>=, +=, *=, &=, |= and ^=
2694 in addition to the inherited [], ==, !=, +, *, ~, <<, >>, &, | and ^.
2696 Properties:
2698 bin -- The bitstring as a binary string.
2699 hex -- The bitstring as a hexadecimal string.
2700 oct -- The bitstring as an octal string.
2701 bytes -- The bitstring as a bytes object.
2702 int -- Interpret as a two's complement signed integer.
2703 uint -- Interpret as a two's complement unsigned integer.
2704 float / floatbe -- Interpret as a big-endian floating point number.
2705 bool -- For single bit bitstrings, interpret as True or False.
2706 se -- Interpret as a signed exponential-Golomb code.
2707 ue -- Interpret as an unsigned exponential-Golomb code.
2708 sie -- Interpret as a signed interleaved exponential-Golomb code.
2709 uie -- Interpret as an unsigned interleaved exponential-Golomb code.
2710 floatle -- Interpret as a little-endian floating point number.
2711 floatne -- Interpret as a native-endian floating point number.
2712 bfloat / bfloatbe -- Interpret as a big-endian 16-bit bfloat type.
2713 bfloatle -- Interpret as a little-endian 16-bit bfloat type.
2714 bfloatne -- Interpret as a native-endian 16-bit bfloat type.
2715 intbe -- Interpret as a big-endian signed integer.
2716 intle -- Interpret as a little-endian signed integer.
2717 intne -- Interpret as a native-endian signed integer.
2718 uintbe -- Interpret as a big-endian unsigned integer.
2719 uintle -- Interpret as a little-endian unsigned integer.
2720 uintne -- Interpret as a native-endian unsigned integer.
2722 len -- Length of the bitstring in bits.
2724 """
2726 @classmethod
2727 def _setlsb0methods(cls, lsb0: bool) -> None:
2728 if lsb0:
2729 cls._ror = cls._rol_msb0 # type: ignore
2730 cls._rol = cls._ror_msb0 # type: ignore
2731 cls._append = cls._append_lsb0 # type: ignore
2732 # An LSB0 prepend is an MSB0 append
2733 cls._prepend = cls._append_msb0 # type: ignore
2734 else:
2735 cls._ror = cls._ror_msb0 # type: ignore
2736 cls._rol = cls._rol_msb0 # type: ignore
2737 cls._append = cls._append_msb0 # type: ignore
2738 cls._prepend = cls._append_lsb0 # type: ignore
2740 __slots__ = ()
2742 # As BitArray objects are mutable, we shouldn't allow them to be hashed.
2743 __hash__: None = None
2745 def __init__(self, __auto: Optional[Union[BitsType, int]] = None, length: Optional[int] = None,
2746 offset: Optional[int] = None, **kwargs) -> None:
2747 """Either specify an 'auto' initialiser:
2748 A string of comma separated tokens, an integer, a file object,
2749 a bytearray, a boolean iterable or another bitstring.
2751 Or initialise via **kwargs with one (and only one) of:
2752 bin -- binary string representation, e.g. '0b001010'.
2753 hex -- hexadecimal string representation, e.g. '0x2ef'
2754 oct -- octal string representation, e.g. '0o777'.
2755 bytes -- raw data as a bytes object, for example read from a binary file.
2756 int -- a signed integer.
2757 uint -- an unsigned integer.
2758 float / floatbe -- a big-endian floating point number.
2759 bool -- a boolean (True or False).
2760 se -- a signed exponential-Golomb code.
2761 ue -- an unsigned exponential-Golomb code.
2762 sie -- a signed interleaved exponential-Golomb code.
2763 uie -- an unsigned interleaved exponential-Golomb code.
2764 floatle -- a little-endian floating point number.
2765 floatne -- a native-endian floating point number.
2766 bfloat / bfloatbe - a big-endian bfloat format 16-bit floating point number.
2767 bfloatle -- a little-endian bfloat format 16-bit floating point number.
2768 bfloatne -- a native-endian bfloat format 16-bit floating point number.
2769 intbe -- a signed big-endian whole byte integer.
2770 intle -- a signed little-endian whole byte integer.
2771 intne -- a signed native-endian whole byte integer.
2772 uintbe -- an unsigned big-endian whole byte integer.
2773 uintle -- an unsigned little-endian whole byte integer.
2774 uintne -- an unsigned native-endian whole byte integer.
2775 filename -- the path of a file which will be opened in binary read-only mode.
2777 Other keyword arguments:
2778 length -- length of the bitstring in bits, if needed and appropriate.
2779 It must be supplied for all integer and float initialisers.
2780 offset -- bit offset to the data. These offset bits are
2781 ignored and this is intended for use when
2782 initialising using 'bytes' or 'filename'.
2784 """
2785 if self._bitstore.immutable:
2786 self._bitstore = self._bitstore.copy()
2787 self._bitstore.immutable = False
2789 _letter_to_setter: Dict[str, Callable[..., None]] = \
2790 {'u': Bits._setuint,
2791 'i': Bits._setint,
2792 'f': Bits._setfloatbe,
2793 'b': Bits._setbin_safe,
2794 'o': Bits._setoct,
2795 'h': Bits._sethex}
2797 _short_token: Pattern[str] = re.compile(r'^(?P<name>[uifboh])(?P<len>\d+)$', re.IGNORECASE)
2798 _name_length_pattern: Pattern[str] = re.compile(r'^(?P<name>[a-z]+)(?P<len>\d+)$', re.IGNORECASE)
2800 def __setattr__(self, attribute, value) -> None:
2801 try:
2802 # First try the ordinary attribute setter
2803 super().__setattr__(attribute, value)
2804 except AttributeError:
2805 m1_short = BitArray._short_token.match(attribute)
2806 if m1_short:
2807 length = int(m1_short.group('len'))
2808 name = m1_short.group('name')
2809 f = BitArray._letter_to_setter[name]
2810 try:
2811 f(self, value, length)
2812 except AttributeError:
2813 raise AttributeError(f"Can't set attribute {attribute} with value {value}.")
2815 if self.len != length:
2816 new_len = self.len
2817 raise CreationError(f"Can't initialise with value of length {new_len} bits, "
2818 f"as attribute has length of {length} bits.")
2819 return
2820 # Try to split into [name][length], then try standard properties
2821 name_length = BitArray._name_length_pattern.match(attribute)
2822 if name_length:
2823 name = name_length.group('name')
2824 length = name_length.group('len')
2825 if length is not None:
2826 length = int(length)
2827 if name == 'bytes':
2828 if len(value) != length:
2829 raise CreationError(
2830 f"Wrong amount of byte data preset - {length} bytes needed, have {len(value)} bytes.")
2831 length *= 8
2832 try:
2833 self._initialise(None, length=length, offset=None, **{name: value})
2834 return
2835 except AttributeError:
2836 pass
2837 raise AttributeError(f"Can't set attribute {attribute} with value {value}.")
2839 def __iadd__(self, bs: BitsType) -> BitArray:
2840 """Append bs to current bitstring. Return self.
2842 bs -- the bitstring to append.
2844 """
2845 self._append(bs)
2846 return self
2848 def __copy__(self) -> BitArray:
2849 """Return a new copy of the BitArray."""
2850 s_copy = BitArray()
2851 s_copy._bitstore = self._bitstore.copy()
2852 assert s_copy._bitstore.immutable is False
2853 return s_copy
2855 def _setitem_int(self, key: int, value: Union[BitsType, int]) -> None:
2856 if isinstance(value, numbers.Integral):
2857 if value == 0:
2858 self._bitstore[key] = 0
2859 return
2860 if value in (1, -1):
2861 self._bitstore[key] = 1
2862 return
2863 raise ValueError(f"Cannot set a single bit with integer {value}.")
2864 try:
2865 value = self._create_from_bitstype(value)
2866 except TypeError:
2867 raise TypeError(f"Bitstring, integer or string expected. Got {type(value)}.")
2868 positive_key = key + self.len if key < 0 else key
2869 if positive_key < 0 or positive_key >= len(self._bitstore):
2870 raise IndexError(f"Bit position {key} out of range.")
2871 self._bitstore[positive_key: positive_key + 1] = value._bitstore
2873 def _setitem_slice(self, key: slice, value: BitsType) -> None:
2874 if isinstance(value, numbers.Integral):
2875 if key.step not in [None, -1, 1]:
2876 if value in [0, 1]:
2877 self.set(value, range(*key.indices(len(self))))
2878 return
2879 else:
2880 raise ValueError("Can't assign an integer except 0 or 1 to a slice with a step value.")
2881 # To find the length we first get the slice
2882 s = self._bitstore.getslice(key)
2883 length = len(s)
2884 # Now create an int of the correct length
2885 if value >= 0:
2886 value = self.__class__(uint=value, length=length)
2887 else:
2888 value = self.__class__(int=value, length=length)
2889 else:
2890 try:
2891 value = self._create_from_bitstype(value)
2892 except TypeError:
2893 raise TypeError(f"Bitstring, integer or string expected. Got {type(value)}.")
2894 self._bitstore.__setitem__(key, value._bitstore)
2896 def __setitem__(self, key: Union[slice, int], value: BitsType) -> None:
2897 if isinstance(key, numbers.Integral):
2898 self._setitem_int(key, value)
2899 else:
2900 self._setitem_slice(key, value)
2902 def __delitem__(self, key: Union[slice, int]) -> None:
2903 """Delete item or range.
2905 >>> a = BitArray('0x001122')
2906 >>> del a[8:16]
2907 >>> print a
2908 0x0022
2910 """
2911 self._bitstore.__delitem__(key)
2912 return
2914 def __ilshift__(self: TBits, n: int) -> TBits:
2915 """Shift bits by n to the left in place. Return self.
2917 n -- the number of bits to shift. Must be >= 0.
2919 """
2920 if n < 0:
2921 raise ValueError("Cannot shift by a negative amount.")
2922 if not self.len:
2923 raise ValueError("Cannot shift an empty bitstring.")
2924 if not n:
2925 return self
2926 n = min(n, self.len)
2927 return self._ilshift(n)
2929 def __irshift__(self: TBits, n: int) -> TBits:
2930 """Shift bits by n to the right in place. Return self.
2932 n -- the number of bits to shift. Must be >= 0.
2934 """
2935 if n < 0:
2936 raise ValueError("Cannot shift by a negative amount.")
2937 if not self.len:
2938 raise ValueError("Cannot shift an empty bitstring.")
2939 if not n:
2940 return self
2941 n = min(n, self.len)
2942 return self._irshift(n)
2944 def __imul__(self: TBits, n: int) -> TBits:
2945 """Concatenate n copies of self in place. Return self.
2947 Called for expressions of the form 'a *= 3'.
2948 n -- The number of concatenations. Must be >= 0.
2950 """
2951 if n < 0:
2952 raise ValueError("Cannot multiply by a negative integer.")
2953 return self._imul(n)
2955 def __ior__(self: TBits, bs: BitsType) -> TBits:
2956 bs = self._create_from_bitstype(bs)
2957 if self.len != bs.len:
2958 raise ValueError("Bitstrings must have the same length for |= operator.")
2959 self._bitstore |= bs._bitstore
2960 return self
2962 def __iand__(self: TBits, bs: BitsType) -> TBits:
2963 bs = self._create_from_bitstype(bs)
2964 if self.len != bs.len:
2965 raise ValueError("Bitstrings must have the same length for &= operator.")
2966 self._bitstore &= bs._bitstore
2967 return self
2969 def __ixor__(self: TBits, bs: BitsType) -> TBits:
2970 bs = self._create_from_bitstype(bs)
2971 if self.len != bs.len:
2972 raise ValueError("Bitstrings must have the same length for ^= operator.")
2973 self._bitstore ^= bs._bitstore
2974 return self
2976 def _replace(self, old: Bits, new: Bits, start: int, end: int, count: int, bytealigned: Optional[bool]) -> int:
2977 if bytealigned is None:
2978 bytealigned = _bytealigned
2979 # First find all the places where we want to do the replacements
2980 starting_points: List[int] = []
2981 for x in self.findall(old, start, end, bytealigned=bytealigned):
2982 if not starting_points:
2983 starting_points.append(x)
2984 elif x >= starting_points[-1] + old.len:
2985 # Can only replace here if it hasn't already been replaced!
2986 starting_points.append(x)
2987 if count != 0 and len(starting_points) == count:
2988 break
2989 if not starting_points:
2990 return 0
2991 replacement_list = [self._bitstore.getslice(slice(0, starting_points[0], None))]
2992 for i in range(len(starting_points) - 1):
2993 replacement_list.append(new._bitstore)
2994 replacement_list.append(
2995 self._bitstore.getslice(slice(starting_points[i] + old.len, starting_points[i + 1], None)))
2996 # Final replacement
2997 replacement_list.append(new._bitstore)
2998 replacement_list.append(self._bitstore.getslice(slice(starting_points[-1] + old.len, None, None)))
2999 if _lsb0:
3000 # Addition of bitarray is always on the right, so assemble from other end
3001 replacement_list.reverse()
3002 self._bitstore.clear()
3003 for r in replacement_list:
3004 self._bitstore += r
3005 return len(starting_points)
3007 def replace(self, old: BitsType, new: BitsType, start: Optional[int] = None, end: Optional[int] = None,
3008 count: Optional[int] = None, bytealigned: Optional[bool] = None) -> int:
3009 """Replace all occurrences of old with new in place.
3011 Returns number of replacements made.
3013 old -- The bitstring to replace.
3014 new -- The replacement bitstring.
3015 start -- Any occurrences that start before this will not be replaced.
3016 Defaults to 0.
3017 end -- Any occurrences that finish after this will not be replaced.
3018 Defaults to len(self).
3019 count -- The maximum number of replacements to make. Defaults to
3020 replace all occurrences.
3021 bytealigned -- If True replacements will only be made on byte
3022 boundaries.
3024 Raises ValueError if old is empty or if start or end are
3025 out of range.
3027 """
3028 if count == 0:
3029 return 0
3030 old = self._create_from_bitstype(old)
3031 new = self._create_from_bitstype(new)
3032 if not old.len:
3033 raise ValueError("Empty bitstring cannot be replaced.")
3034 start, end = self._validate_slice(start, end)
3036 if new is self:
3037 # Prevent self assignment woes
3038 new = copy.copy(self)
3039 return self._replace(old, new, start, end, 0 if count is None else count, bytealigned)
3041 def insert(self, bs: BitsType, pos: int) -> None:
3042 """Insert bs at bit position pos.
3044 bs -- The bitstring to insert.
3045 pos -- The bit position to insert at.
3047 Raises ValueError if pos < 0 or pos > len(self).
3049 """
3050 bs = self._create_from_bitstype(bs)
3051 if not bs.len:
3052 return
3053 if bs is self:
3054 bs = self._copy()
3055 if pos < 0:
3056 pos += self._getlength()
3057 if not 0 <= pos <= self._getlength():
3058 raise ValueError("Invalid insert position.")
3059 self._insert(bs, pos)
3061 def overwrite(self, bs: BitsType, pos: int) -> None:
3062 """Overwrite with bs at bit position pos.
3064 bs -- The bitstring to overwrite with.
3065 pos -- The bit position to begin overwriting from.
3067 Raises ValueError if pos < 0 or pos > len(self).
3069 """
3070 bs = self._create_from_bitstype(bs)
3071 if not bs.len:
3072 return
3073 if pos < 0:
3074 pos += self._getlength()
3075 if pos < 0 or pos > self.len:
3076 raise ValueError("Overwrite starts outside boundary of bitstring.")
3077 self._overwrite(bs, pos)
3079 def append(self, bs: BitsType) -> None:
3080 """Append a bitstring to the current bitstring.
3082 bs -- The bitstring to append.
3084 """
3085 self._append(bs)
3087 def prepend(self, bs: BitsType) -> None:
3088 """Prepend a bitstring to the current bitstring.
3090 bs -- The bitstring to prepend.
3092 """
3093 self._prepend(bs)
3095 def _append_msb0(self, bs: BitsType) -> None:
3096 self._addright(self._create_from_bitstype(bs))
3098 def _append_lsb0(self, bs: BitsType) -> None:
3099 bs = self._create_from_bitstype(bs)
3100 self._addleft(bs)
3102 def reverse(self, start: Optional[int] = None, end: Optional[int] = None) -> None:
3103 """Reverse bits in-place.
3105 start -- Position of first bit to reverse. Defaults to 0.
3106 end -- One past the position of the last bit to reverse.
3107 Defaults to len(self).
3109 Using on an empty bitstring will have no effect.
3111 Raises ValueError if start < 0, end > len(self) or end < start.
3113 """
3114 start, end = self._validate_slice(start, end)
3115 if start == 0 and end == self.len:
3116 self._bitstore.reverse()
3117 return
3118 s = self._slice(start, end)
3119 s._bitstore.reverse()
3120 self[start:end] = s
3122 def set(self, value: Any, pos: Optional[Union[int, Iterable[int]]] = None) -> None:
3123 """Set one or many bits to 1 or 0.
3125 value -- If bool(value) is True bits are set to 1, otherwise they are set to 0.
3126 pos -- Either a single bit position or an iterable of bit positions.
3127 Negative numbers are treated in the same way as slice indices.
3128 Defaults to the entire bitstring.
3130 Raises IndexError if pos < -len(self) or pos >= len(self).
3132 """
3133 if pos is None:
3134 # Set all bits to either 1 or 0
3135 self._setint(-1 if value else 0)
3136 return
3137 if not isinstance(pos, abc.Iterable):
3138 pos = (pos,)
3139 v = 1 if value else 0
3140 if isinstance(pos, range):
3141 self._bitstore.__setitem__(slice(pos.start, pos.stop, pos.step), v)
3142 return
3143 for p in pos:
3144 self._bitstore[p] = v
3146 def invert(self, pos: Optional[Union[Iterable[int], int]] = None) -> None:
3147 """Invert one or many bits from 0 to 1 or vice versa.
3149 pos -- Either a single bit position or an iterable of bit positions.
3150 Negative numbers are treated in the same way as slice indices.
3152 Raises IndexError if pos < -len(self) or pos >= len(self).
3154 """
3155 if pos is None:
3156 self._invert_all()
3157 return
3158 if not isinstance(pos, abc.Iterable):
3159 pos = (pos,)
3160 length = self.len
3162 for p in pos:
3163 if p < 0:
3164 p += length
3165 if not 0 <= p < length:
3166 raise IndexError(f"Bit position {p} out of range.")
3167 self._invert(p)
3169 def ror(self, bits: int, start: Optional[int] = None, end: Optional[int] = None) -> None:
3170 """Rotate bits to the right in-place.
3172 bits -- The number of bits to rotate by.
3173 start -- Start of slice to rotate. Defaults to 0.
3174 end -- End of slice to rotate. Defaults to len(self).
3176 Raises ValueError if bits < 0.
3178 """
3179 if not self.len:
3180 raise Error("Cannot rotate an empty bitstring.")
3181 if bits < 0:
3182 raise ValueError("Cannot rotate by negative amount.")
3183 self._ror(bits, start, end)
3185 def _ror_msb0(self, bits: int, start: Optional[int] = None, end: Optional[int] = None) -> None:
3186 start, end = self._validate_slice(start, end) # the _slice deals with msb0/lsb0
3187 bits %= (end - start)
3188 if not bits:
3189 return
3190 rhs = self._slice(end - bits, end)
3191 self._delete(bits, end - bits)
3192 self._insert(rhs, start)
3194 def rol(self, bits: int, start: Optional[int] = None, end: Optional[int] = None) -> None:
3195 """Rotate bits to the left in-place.
3197 bits -- The number of bits to rotate by.
3198 start -- Start of slice to rotate. Defaults to 0.
3199 end -- End of slice to rotate. Defaults to len(self).
3201 Raises ValueError if bits < 0.
3203 """
3204 if not self.len:
3205 raise Error("Cannot rotate an empty bitstring.")
3206 if bits < 0:
3207 raise ValueError("Cannot rotate by negative amount.")
3208 self._rol(bits, start, end)
3210 def _rol_msb0(self, bits: int, start: Optional[int] = None, end: Optional[int] = None):
3211 start, end = self._validate_slice(start, end)
3212 bits %= (end - start)
3213 if bits == 0:
3214 return
3215 lhs = self._slice(start, start + bits)
3216 self._delete(bits, start)
3217 self._insert(lhs, end - bits)
3219 def byteswap(self, fmt: Optional[Union[int, Iterable[int], str]] = None, start: Optional[int] = None,
3220 end: Optional[int] = None, repeat: bool = True) -> int:
3221 """Change the endianness in-place. Return number of repeats of fmt done.
3223 fmt -- A compact structure string, an integer number of bytes or
3224 an iterable of integers. Defaults to 0, which byte reverses the
3225 whole bitstring.
3226 start -- Start bit position, defaults to 0.
3227 end -- End bit position, defaults to len(self).
3228 repeat -- If True (the default) the byte swapping pattern is repeated
3229 as much as possible.
3231 """
3232 start_v, end_v = self._validate_slice(start, end)
3233 if fmt is None or fmt == 0:
3234 # reverse all of the whole bytes.
3235 bytesizes = [(end_v - start_v) // 8]
3236 elif isinstance(fmt, numbers.Integral):
3237 if fmt < 0:
3238 raise ValueError(f"Improper byte length {fmt}.")
3239 bytesizes = [fmt]
3240 elif isinstance(fmt, str):
3241 m = BYTESWAP_STRUCT_PACK_RE.match(fmt)
3242 if not m:
3243 raise ValueError(f"Cannot parse format string {fmt}.")
3244 # Split the format string into a list of 'q', '4h' etc.
3245 formatlist = re.findall(STRUCT_SPLIT_RE, m.group('fmt'))
3246 # Now deal with multiplicative factors, 4h -> hhhh etc.
3247 bytesizes = []
3248 for f in formatlist:
3249 if len(f) == 1:
3250 bytesizes.append(PACK_CODE_SIZE[f])
3251 else:
3252 bytesizes.extend([PACK_CODE_SIZE[f[-1]]] * int(f[:-1]))
3253 elif isinstance(fmt, abc.Iterable):
3254 bytesizes = fmt
3255 for bytesize in bytesizes:
3256 if not isinstance(bytesize, numbers.Integral) or bytesize < 0:
3257 raise ValueError(f"Improper byte length {bytesize}.")
3258 else:
3259 raise TypeError("Format must be an integer, string or iterable.")
3261 repeats = 0
3262 totalbitsize: int = 8 * sum(bytesizes)
3263 if not totalbitsize:
3264 return 0
3265 if repeat:
3266 # Try to repeat up to the end of the bitstring.
3267 finalbit = end_v
3268 else:
3269 # Just try one (set of) byteswap(s).
3270 finalbit = start_v + totalbitsize
3271 for patternend in range(start_v + totalbitsize, finalbit + 1, totalbitsize):
3272 bytestart = patternend - totalbitsize
3273 for bytesize in bytesizes:
3274 byteend = bytestart + bytesize * 8
3275 self._reversebytes(bytestart, byteend)
3276 bytestart += bytesize * 8
3277 repeats += 1
3278 return repeats
3280 def clear(self) -> None:
3281 """Remove all bits, reset to zero length."""
3282 self._clear()
3284 int = property(Bits._getint, Bits._setint,
3285 doc="""The bitstring as a two's complement signed int. Read and write.
3286 """)
3287 uint = property(Bits._getuint, Bits._setuint,
3288 doc="""The bitstring as a two's complement unsigned int. Read and write.
3289 """)
3290 float = property(Bits._getfloatbe, Bits._setfloatbe,
3291 doc="""The bitstring as a floating point number. Read and write.
3292 """)
3293 bfloat = property(Bits._getbfloatbe, Bits._setbfloatbe,
3294 doc="""The bitstring as a 16 bit bfloat floating point number. Read and write.
3295 """)
3296 intbe = property(Bits._getintbe, Bits._setintbe,
3297 doc="""The bitstring as a two's complement big-endian signed int. Read and write.
3298 """)
3299 uintbe = property(Bits._getuintbe, Bits._setuintbe,
3300 doc="""The bitstring as a two's complement big-endian unsigned int. Read and write.
3301 """)
3302 floatbe = property(Bits._getfloatbe, Bits._setfloatbe,
3303 doc="""The bitstring as a big-endian floating point number. Read and write.
3304 """)
3305 intle = property(Bits._getintle, Bits._setintle,
3306 doc="""The bitstring as a two's complement little-endian signed int. Read and write.
3307 """)
3308 uintle = property(Bits._getuintle, Bits._setuintle,
3309 doc="""The bitstring as a two's complement little-endian unsigned int. Read and write.
3310 """)
3311 floatle = property(Bits._getfloatle, Bits._setfloatle,
3312 doc="""The bitstring as a little-endian floating point number. Read and write.
3313 """)
3314 intne = property(Bits._getintne, Bits._setintne,
3315 doc="""The bitstring as a two's complement native-endian signed int. Read and write.
3316 """)
3317 uintne = property(Bits._getuintne, Bits._setuintne,
3318 doc="""The bitstring as a two's complement native-endian unsigned int. Read and write.
3319 """)
3320 floatne = property(Bits._getfloatne, Bits._setfloatne,
3321 doc="""The bitstring as a native-endian floating point number. Read and write.
3322 """)
3323 ue = property(Bits._getue, Bits._setue,
3324 doc="""The bitstring as an unsigned exponential-Golomb code. Read and write.
3325 """)
3326 se = property(Bits._getse, Bits._setse,
3327 doc="""The bitstring as a signed exponential-Golomb code. Read and write.
3328 """)
3329 uie = property(Bits._getuie, Bits._setuie,
3330 doc="""The bitstring as an unsigned interleaved exponential-Golomb code. Read and write.
3331 """)
3332 sie = property(Bits._getsie, Bits._setsie,
3333 doc="""The bitstring as a signed interleaved exponential-Golomb code. Read and write.
3334 """)
3335 hex = property(Bits._gethex, Bits._sethex,
3336 doc="""The bitstring as a hexadecimal string. Read and write.
3337 """)
3338 bin = property(Bits._getbin, Bits._setbin_safe,
3339 doc="""The bitstring as a binary string. Read and write.
3340 """)
3341 oct = property(Bits._getoct, Bits._setoct,
3342 doc="""The bitstring as an octal string. Read and write.
3343 """)
3344 bool = property(Bits._getbool, Bits._setbool,
3345 doc="""The bitstring as a bool (True or False). Read and write.
3346 """)
3347 bytes = property(Bits._getbytes, Bits._setbytes,
3348 doc="""The bitstring as a ordinary string. Read and write.
3349 """)
3350 float8_143 = property(Bits._getfloat143, Bits._setfloat143,
3351 doc="""The bitstring as an 8 bit float with float8_143 format. Read and write.
3352 """)
3353 float8_152 = property(Bits._getfloat152, Bits._setfloat152,
3354 doc="""The bitstring as an 8 bit float with float8_152 format. Read and write.
3355 """)
3357 # Aliases for some properties
3358 f = float
3359 i = int
3360 u = uint
3361 b = bin
3362 h = hex
3363 o = oct
3366# Whether to label the Least Significant Bit as bit 0. Default is False.
3368def _switch_lsb0_methods(lsb0: bool) -> None:
3369 global _lsb0
3370 _lsb0 = lsb0
3371 Bits._setlsb0methods(lsb0)
3372 BitArray._setlsb0methods(lsb0)
3373 BitStore._setlsb0methods(lsb0)
3376# Initialise the default behaviour
3377_switch_lsb0_methods(False)