Skip to content

Commit b283f2a

Browse files
committed
Rewrite read_bits_int_{be,le}()
See kaitai-io/kaitai_struct#949
1 parent e486e14 commit b283f2a

File tree

1 file changed

+30
-27
lines changed

1 file changed

+30
-27
lines changed

kaitaistruct.lua

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -182,34 +182,34 @@ end
182182
--=============================================================================
183183

184184
function KaitaiStream:align_to_byte()
185-
self.bits = 0
186185
self.bits_left = 0
186+
self.bits = 0
187187
end
188188

189189
function KaitaiStream:read_bits_int_be(n)
190+
local res = 0
191+
190192
local bits_needed = n - self.bits_left
193+
self.bits_left = -bits_needed % 8
194+
191195
if bits_needed > 0 then
192196
-- 1 bit => 1 byte
193197
-- 8 bits => 1 byte
194198
-- 9 bits => 2 bytes
195199
local bytes_needed = math.ceil(bits_needed / 8)
196-
local buf = self._io:read(bytes_needed)
197-
for i = 1, #buf do
198-
local byte = buf:byte(i)
199-
self.bits = self.bits << 8
200-
self.bits = self.bits | byte
201-
self.bits_left = self.bits_left + 8
200+
local buf = {self._io:read(bytes_needed):byte(1, bytes_needed)}
201+
for i = 1, bytes_needed do
202+
res = res << 8 | buf[i]
202203
end
204+
205+
local new_bits = res
206+
res = res >> self.bits_left | self.bits << bits_needed
207+
self.bits = new_bits -- will be masked at the end of the function
208+
else
209+
res = self.bits >> -bits_needed -- shift unneeded bits out
203210
end
204211

205-
-- Raw mask with required number of 1s, starting from lowest bit
206-
local mask = (1 << n) - 1
207-
-- Shift self.bits to align the highest bits with the mask & derive reading result
208-
local shift_bits = self.bits_left - n
209-
local res = (self.bits >> shift_bits) & mask
210-
-- Clear top bits that we've just read => AND with 1s
211-
self.bits_left = self.bits_left - n
212-
mask = (1 << self.bits_left) - 1
212+
local mask = (1 << self.bits_left) - 1 -- `bits_left` is in range 0..7
213213
self.bits = self.bits & mask
214214

215215
return res
@@ -225,28 +225,31 @@ function KaitaiStream:read_bits_int(n)
225225
end
226226

227227
function KaitaiStream:read_bits_int_le(n)
228+
local res = 0
228229
local bits_needed = n - self.bits_left
230+
229231
if bits_needed > 0 then
230232
-- 1 bit => 1 byte
231233
-- 8 bits => 1 byte
232234
-- 9 bits => 2 bytes
233235
local bytes_needed = math.ceil(bits_needed / 8)
234-
local buf = self._io:read(bytes_needed)
235-
for i = 1, #buf do
236-
local byte = buf:byte(i)
237-
self.bits = self.bits | (byte << self.bits_left)
238-
self.bits_left = self.bits_left + 8
236+
local buf = {self._io:read(bytes_needed):byte(1, bytes_needed)}
237+
for i = 1, bytes_needed do
238+
res = res | buf[i] << ((i - 1) * 8) -- NB: Lua uses 1-based indexing, but we need 0-based here
239239
end
240+
241+
local new_bits = res >> bits_needed
242+
res = res << self.bits_left | self.bits
243+
self.bits = new_bits
244+
else
245+
res = self.bits
246+
self.bits = self.bits >> n
240247
end
241248

242-
-- Raw mask with required number of 1s, starting from lowest bit
243-
local mask = (1 << n) - 1
244-
-- Derive reading result
245-
local res = self.bits & mask
246-
-- Remove bottom bits that we've just read by shifting
247-
self.bits = self.bits >> n
248-
self.bits_left = self.bits_left - n
249+
self.bits_left = -bits_needed % 8
249250

251+
local mask = (1 << n) - 1 -- unlike some other languages, no problem with this in Lua
252+
res = res & mask
250253
return res
251254
end
252255

0 commit comments

Comments
 (0)