blob: bda4021efd3a597894677d468b8b2ba35579768f [file] [log] [blame]
Scott Bakered4efab2020-01-13 19:12:25 -08001// 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 "fmt"
9
10// bitWriter will write bits.
11// First bit will be LSB of the first byte of output.
12type bitWriter struct {
13 bitContainer uint64
14 nBits uint8
15 out []byte
16}
17
18// bitMask16 is bitmasks. Has extra to avoid bounds check.
19var bitMask16 = [32]uint16{
20 0, 1, 3, 7, 0xF, 0x1F,
21 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
22 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0xFFFF,
23 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
24 0xFFFF, 0xFFFF} /* up to 16 bits */
25
26// addBits16NC will add up to 16 bits.
27// It will not check if there is space for them,
28// so the caller must ensure that it has flushed recently.
29func (b *bitWriter) addBits16NC(value uint16, bits uint8) {
30 b.bitContainer |= uint64(value&bitMask16[bits&31]) << (b.nBits & 63)
31 b.nBits += bits
32}
33
34// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
35// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
36func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
37 b.bitContainer |= uint64(value) << (b.nBits & 63)
38 b.nBits += bits
39}
40
41// encSymbol will add up to 16 bits. value may not contain more set bits than indicated.
42// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
43func (b *bitWriter) encSymbol(ct cTable, symbol byte) {
44 enc := ct[symbol]
45 b.bitContainer |= uint64(enc.val) << (b.nBits & 63)
46 b.nBits += enc.nBits
47}
48
49// encTwoSymbols will add up to 32 bits. value may not contain more set bits than indicated.
50// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
51func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) {
52 encA := ct[av]
53 encB := ct[bv]
54 sh := b.nBits & 63
55 combined := uint64(encA.val) | (uint64(encB.val) << (encA.nBits & 63))
56 b.bitContainer |= combined << sh
57 b.nBits += encA.nBits + encB.nBits
58}
59
60// addBits16ZeroNC will add up to 16 bits.
61// It will not check if there is space for them,
62// so the caller must ensure that it has flushed recently.
63// This is fastest if bits can be zero.
64func (b *bitWriter) addBits16ZeroNC(value uint16, bits uint8) {
65 if bits == 0 {
66 return
67 }
68 value <<= (16 - bits) & 15
69 value >>= (16 - bits) & 15
70 b.bitContainer |= uint64(value) << (b.nBits & 63)
71 b.nBits += bits
72}
73
74// flush will flush all pending full bytes.
75// There will be at least 56 bits available for writing when this has been called.
76// Using flush32 is faster, but leaves less space for writing.
77func (b *bitWriter) flush() {
78 v := b.nBits >> 3
79 switch v {
80 case 0:
81 return
82 case 1:
83 b.out = append(b.out,
84 byte(b.bitContainer),
85 )
86 b.bitContainer >>= 1 << 3
87 case 2:
88 b.out = append(b.out,
89 byte(b.bitContainer),
90 byte(b.bitContainer>>8),
91 )
92 b.bitContainer >>= 2 << 3
93 case 3:
94 b.out = append(b.out,
95 byte(b.bitContainer),
96 byte(b.bitContainer>>8),
97 byte(b.bitContainer>>16),
98 )
99 b.bitContainer >>= 3 << 3
100 case 4:
101 b.out = append(b.out,
102 byte(b.bitContainer),
103 byte(b.bitContainer>>8),
104 byte(b.bitContainer>>16),
105 byte(b.bitContainer>>24),
106 )
107 b.bitContainer >>= 4 << 3
108 case 5:
109 b.out = append(b.out,
110 byte(b.bitContainer),
111 byte(b.bitContainer>>8),
112 byte(b.bitContainer>>16),
113 byte(b.bitContainer>>24),
114 byte(b.bitContainer>>32),
115 )
116 b.bitContainer >>= 5 << 3
117 case 6:
118 b.out = append(b.out,
119 byte(b.bitContainer),
120 byte(b.bitContainer>>8),
121 byte(b.bitContainer>>16),
122 byte(b.bitContainer>>24),
123 byte(b.bitContainer>>32),
124 byte(b.bitContainer>>40),
125 )
126 b.bitContainer >>= 6 << 3
127 case 7:
128 b.out = append(b.out,
129 byte(b.bitContainer),
130 byte(b.bitContainer>>8),
131 byte(b.bitContainer>>16),
132 byte(b.bitContainer>>24),
133 byte(b.bitContainer>>32),
134 byte(b.bitContainer>>40),
135 byte(b.bitContainer>>48),
136 )
137 b.bitContainer >>= 7 << 3
138 case 8:
139 b.out = append(b.out,
140 byte(b.bitContainer),
141 byte(b.bitContainer>>8),
142 byte(b.bitContainer>>16),
143 byte(b.bitContainer>>24),
144 byte(b.bitContainer>>32),
145 byte(b.bitContainer>>40),
146 byte(b.bitContainer>>48),
147 byte(b.bitContainer>>56),
148 )
149 b.bitContainer = 0
150 b.nBits = 0
151 return
152 default:
153 panic(fmt.Errorf("bits (%d) > 64", b.nBits))
154 }
155 b.nBits &= 7
156}
157
158// flush32 will flush out, so there are at least 32 bits available for writing.
159func (b *bitWriter) flush32() {
160 if b.nBits < 32 {
161 return
162 }
163 b.out = append(b.out,
164 byte(b.bitContainer),
165 byte(b.bitContainer>>8),
166 byte(b.bitContainer>>16),
167 byte(b.bitContainer>>24))
168 b.nBits -= 32
169 b.bitContainer >>= 32
170}
171
172// flushAlign will flush remaining full bytes and align to next byte boundary.
173func (b *bitWriter) flushAlign() {
174 nbBytes := (b.nBits + 7) >> 3
175 for i := uint8(0); i < nbBytes; i++ {
176 b.out = append(b.out, byte(b.bitContainer>>(i*8)))
177 }
178 b.nBits = 0
179 b.bitContainer = 0
180}
181
182// close will write the alignment bit and write the final byte(s)
183// to the output.
184func (b *bitWriter) close() error {
185 // End mark
186 b.addBits16Clean(1, 1)
187 // flush until next byte.
188 b.flushAlign()
189 return nil
190}
191
192// reset and continue writing by appending to out.
193func (b *bitWriter) reset(out []byte) {
194 b.bitContainer = 0
195 b.nBits = 0
196 b.out = out
197}