Skip to content

Commit 427ea19

Browse files
committed
Rewrite read_bits_int_{be,le}()
See kaitai-io/kaitai_struct#949
1 parent 25c08ec commit 427ea19

File tree

1 file changed

+35
-28
lines changed

1 file changed

+35
-28
lines changed

kaitaistruct.py

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -218,31 +218,33 @@ def read_f8le(self):
218218
# ========================================================================
219219

220220
def align_to_byte(self):
221-
self.bits = 0
222221
self.bits_left = 0
222+
self.bits = 0
223223

224224
def read_bits_int_be(self, n):
225+
res = 0
226+
225227
bits_needed = n - self.bits_left
228+
self.bits_left = -bits_needed % 8
229+
226230
if bits_needed > 0:
227231
# 1 bit => 1 byte
228232
# 8 bits => 1 byte
229233
# 9 bits => 2 bytes
230-
bytes_needed = ((bits_needed - 1) // 8) + 1
234+
bytes_needed = ((bits_needed - 1) // 8) + 1 # `ceil(bits_needed / 8)`
231235
buf = self.read_bytes(bytes_needed)
236+
if PY2:
237+
buf = bytearray(buf)
232238
for byte in buf:
233-
byte = KaitaiStream.int_from_byte(byte)
234-
self.bits <<= 8
235-
self.bits |= byte
236-
self.bits_left += 8
237-
238-
# raw mask with required number of 1s, starting from lowest bit
239-
mask = (1 << n) - 1
240-
# shift self.bits to align the highest bits with the mask & derive reading result
241-
shift_bits = self.bits_left - n
242-
res = (self.bits >> shift_bits) & mask
243-
# clear top bits that we've just read => AND with 1s
244-
self.bits_left -= n
245-
mask = (1 << self.bits_left) - 1
239+
res = res << 8 | byte
240+
241+
new_bits = res
242+
res = res >> self.bits_left | self.bits << bits_needed
243+
self.bits = new_bits # will be masked at the end of the function
244+
else:
245+
res = self.bits >> -bits_needed # shift unneeded bits out
246+
247+
mask = (1 << self.bits_left) - 1 # `bits_left` is in range 0..7
246248
self.bits &= mask
247249

248250
return res
@@ -253,26 +255,31 @@ def read_bits_int(self, n):
253255
return self.read_bits_int_be(n)
254256

255257
def read_bits_int_le(self, n):
258+
res = 0
256259
bits_needed = n - self.bits_left
260+
257261
if bits_needed > 0:
258262
# 1 bit => 1 byte
259263
# 8 bits => 1 byte
260264
# 9 bits => 2 bytes
261-
bytes_needed = ((bits_needed - 1) // 8) + 1
265+
bytes_needed = ((bits_needed - 1) // 8) + 1 # `ceil(bits_needed / 8)`
262266
buf = self.read_bytes(bytes_needed)
263-
for byte in buf:
264-
byte = KaitaiStream.int_from_byte(byte)
265-
self.bits |= (byte << self.bits_left)
266-
self.bits_left += 8
267-
268-
# raw mask with required number of 1s, starting from lowest bit
269-
mask = (1 << n) - 1
270-
# derive reading result
271-
res = self.bits & mask
272-
# remove bottom bits that we've just read by shifting
273-
self.bits >>= n
274-
self.bits_left -= n
267+
if PY2:
268+
buf = bytearray(buf)
269+
for i, byte in enumerate(buf):
270+
res |= byte << (i * 8)
271+
272+
new_bits = res >> bits_needed
273+
res = res << self.bits_left | self.bits
274+
self.bits = new_bits
275+
else:
276+
res = self.bits
277+
self.bits >>= n
278+
279+
self.bits_left = -bits_needed % 8
275280

281+
mask = (1 << n) - 1 # no problem with this in Python (arbitrary precision integers)
282+
res &= mask
276283
return res
277284

278285
# ========================================================================

0 commit comments

Comments
 (0)