blob: 504a7be9dae3d6bfc281f5ff6545927eda1d5f82 [file] [log] [blame]
khenaidoo7d3c5582021-08-11 18:09:44 -04001// Copyright 2018 Klaus Post. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
5
6package huff0
7
8import (
9 "encoding/binary"
10 "errors"
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053011 "fmt"
khenaidoo7d3c5582021-08-11 18:09:44 -040012 "io"
13)
14
15// bitReader reads a bitstream in reverse.
16// The last set bit indicates the start of the stream and is used
17// for aligning the input.
khenaidoo7d3c5582021-08-11 18:09:44 -040018type bitReaderBytes struct {
19 in []byte
20 off uint // next byte to read is at in[off - 1]
21 value uint64
22 bitsRead uint8
23}
24
25// init initializes and resets the bit reader.
26func (b *bitReaderBytes) init(in []byte) error {
27 if len(in) < 1 {
28 return errors.New("corrupt stream: too short")
29 }
30 b.in = in
31 b.off = uint(len(in))
32 // The highest bit of the last byte indicates where to start
33 v := in[len(in)-1]
34 if v == 0 {
35 return errors.New("corrupt stream, did not find end of stream")
36 }
37 b.bitsRead = 64
38 b.value = 0
39 if len(in) >= 8 {
40 b.fillFastStart()
41 } else {
42 b.fill()
43 b.fill()
44 }
45 b.advance(8 - uint8(highBit32(uint32(v))))
46 return nil
47}
48
49// peekBitsFast requires that at least one bit is requested every time.
50// There are no checks if the buffer is filled.
51func (b *bitReaderBytes) peekByteFast() uint8 {
52 got := uint8(b.value >> 56)
53 return got
54}
55
56func (b *bitReaderBytes) advance(n uint8) {
57 b.bitsRead += n
58 b.value <<= n & 63
59}
60
61// fillFast() will make sure at least 32 bits are available.
62// There must be at least 4 bytes available.
63func (b *bitReaderBytes) fillFast() {
64 if b.bitsRead < 32 {
65 return
66 }
67
68 // 2 bounds checks.
69 v := b.in[b.off-4 : b.off]
70 v = v[:4]
71 low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
72 b.value |= uint64(low) << (b.bitsRead - 32)
73 b.bitsRead -= 32
74 b.off -= 4
75}
76
77// fillFastStart() assumes the bitReaderBytes is empty and there is at least 8 bytes to read.
78func (b *bitReaderBytes) fillFastStart() {
79 // Do single re-slice to avoid bounds checks.
80 b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
81 b.bitsRead = 0
82 b.off -= 8
83}
84
85// fill() will make sure at least 32 bits are available.
86func (b *bitReaderBytes) fill() {
87 if b.bitsRead < 32 {
88 return
89 }
90 if b.off > 4 {
91 v := b.in[b.off-4:]
92 v = v[:4]
93 low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
94 b.value |= uint64(low) << (b.bitsRead - 32)
95 b.bitsRead -= 32
96 b.off -= 4
97 return
98 }
99 for b.off > 0 {
100 b.value |= uint64(b.in[b.off-1]) << (b.bitsRead - 8)
101 b.bitsRead -= 8
102 b.off--
103 }
104}
105
106// finished returns true if all bits have been read from the bit stream.
107func (b *bitReaderBytes) finished() bool {
108 return b.off == 0 && b.bitsRead >= 64
109}
110
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +0530111func (b *bitReaderBytes) remaining() uint {
112 return b.off*8 + uint(64-b.bitsRead)
113}
114
khenaidoo7d3c5582021-08-11 18:09:44 -0400115// close the bitstream and returns an error if out-of-buffer reads occurred.
116func (b *bitReaderBytes) close() error {
117 // Release reference.
118 b.in = nil
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +0530119 if b.remaining() > 0 {
120 return fmt.Errorf("corrupt input: %d bits remain on stream", b.remaining())
121 }
khenaidoo7d3c5582021-08-11 18:09:44 -0400122 if b.bitsRead > 64 {
123 return io.ErrUnexpectedEOF
124 }
125 return nil
126}
127
128// bitReaderShifted reads a bitstream in reverse.
129// The last set bit indicates the start of the stream and is used
130// for aligning the input.
131type bitReaderShifted struct {
132 in []byte
133 off uint // next byte to read is at in[off - 1]
134 value uint64
135 bitsRead uint8
136}
137
138// init initializes and resets the bit reader.
139func (b *bitReaderShifted) init(in []byte) error {
140 if len(in) < 1 {
141 return errors.New("corrupt stream: too short")
142 }
143 b.in = in
144 b.off = uint(len(in))
145 // The highest bit of the last byte indicates where to start
146 v := in[len(in)-1]
147 if v == 0 {
148 return errors.New("corrupt stream, did not find end of stream")
149 }
150 b.bitsRead = 64
151 b.value = 0
152 if len(in) >= 8 {
153 b.fillFastStart()
154 } else {
155 b.fill()
156 b.fill()
157 }
158 b.advance(8 - uint8(highBit32(uint32(v))))
159 return nil
160}
161
162// peekBitsFast requires that at least one bit is requested every time.
163// There are no checks if the buffer is filled.
164func (b *bitReaderShifted) peekBitsFast(n uint8) uint16 {
165 return uint16(b.value >> ((64 - n) & 63))
166}
167
168func (b *bitReaderShifted) advance(n uint8) {
169 b.bitsRead += n
170 b.value <<= n & 63
171}
172
173// fillFast() will make sure at least 32 bits are available.
174// There must be at least 4 bytes available.
175func (b *bitReaderShifted) fillFast() {
176 if b.bitsRead < 32 {
177 return
178 }
179
180 // 2 bounds checks.
181 v := b.in[b.off-4 : b.off]
182 v = v[:4]
183 low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
184 b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
185 b.bitsRead -= 32
186 b.off -= 4
187}
188
189// fillFastStart() assumes the bitReaderShifted is empty and there is at least 8 bytes to read.
190func (b *bitReaderShifted) fillFastStart() {
191 // Do single re-slice to avoid bounds checks.
192 b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
193 b.bitsRead = 0
194 b.off -= 8
195}
196
197// fill() will make sure at least 32 bits are available.
198func (b *bitReaderShifted) fill() {
199 if b.bitsRead < 32 {
200 return
201 }
202 if b.off > 4 {
203 v := b.in[b.off-4:]
204 v = v[:4]
205 low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
206 b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
207 b.bitsRead -= 32
208 b.off -= 4
209 return
210 }
211 for b.off > 0 {
212 b.value |= uint64(b.in[b.off-1]) << ((b.bitsRead - 8) & 63)
213 b.bitsRead -= 8
214 b.off--
215 }
216}
217
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +0530218func (b *bitReaderShifted) remaining() uint {
219 return b.off*8 + uint(64-b.bitsRead)
khenaidoo7d3c5582021-08-11 18:09:44 -0400220}
221
222// close the bitstream and returns an error if out-of-buffer reads occurred.
223func (b *bitReaderShifted) close() error {
224 // Release reference.
225 b.in = nil
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +0530226 if b.remaining() > 0 {
227 return fmt.Errorf("corrupt input: %d bits remain on stream", b.remaining())
228 }
khenaidoo7d3c5582021-08-11 18:09:44 -0400229 if b.bitsRead > 64 {
230 return io.ErrUnexpectedEOF
231 }
232 return nil
233}