Skip to content

Commit 8e4d713

Browse files
committed
Move stuff to brotli.blocks
1 parent 83718cf commit 8e4d713

File tree

6 files changed

+292
-296
lines changed

6 files changed

+292
-296
lines changed

src/brotli.bitreader.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const kBitMask = new Uint32Array([
3131
* @typedef {import('./brotli.streams.js').BrotliInput} BrotliInput
3232
* @param {BrotliInput} input
3333
*/
34-
function BrotliBitReader(input) {
34+
export function BrotliBitReader(input) {
3535
this.buf_ = new Uint8Array(BROTLI_IBUF_SIZE)
3636
this.input_ = input /* input callback */
3737

@@ -132,5 +132,3 @@ BrotliBitReader.prototype.readBits = function(n_bits) {
132132
this.bit_pos_ += n_bits
133133
return val
134134
}
135-
136-
export default BrotliBitReader

src/brotli.blocks.js

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
import { readSymbol } from './brotli.huffman.js'
2+
import { BrotliBitReader } from './brotli.bitreader.js'
3+
import { kBlockLengthPrefixCode } from './brotli.prefix.js'
4+
import { HUFFMAN_MAX_TABLE_SIZE } from './gzip.huffman.js'
5+
6+
/**
7+
* @import {HuffmanCode} from './brotli.huffman.js'
8+
* @param {number} max_block_type
9+
* @param {HuffmanCode[]} trees
10+
* @param {number} tree_type
11+
* @param {number[]} block_types
12+
* @param {number[]} ringbuffers
13+
* @param {number[]} indexes
14+
* @param {BrotliBitReader} br
15+
*/
16+
export function decodeBlockType(max_block_type, trees, tree_type, block_types, ringbuffers, indexes, br) {
17+
const ringbuffer = tree_type * 2
18+
const index = tree_type
19+
const type_code = readSymbol(trees, tree_type * HUFFMAN_MAX_TABLE_SIZE, br)
20+
let block_type
21+
if (type_code === 0) {
22+
block_type = ringbuffers[ringbuffer + (indexes[index] & 1)]
23+
} else if (type_code === 1) {
24+
block_type = ringbuffers[ringbuffer + (indexes[index] - 1 & 1)] + 1
25+
} else {
26+
block_type = type_code - 2
27+
}
28+
if (block_type >= max_block_type) {
29+
block_type -= max_block_type
30+
}
31+
block_types[tree_type] = block_type
32+
ringbuffers[ringbuffer + (indexes[index] & 1)] = block_type
33+
indexes[index]++
34+
}
35+
36+
/**
37+
* @typedef {{ input_end: number, is_metadata: boolean, meta_block_length: number, is_uncompressed: number }} MetaBlockLength
38+
* @param {BrotliBitReader} br
39+
* @returns {MetaBlockLength}
40+
*/
41+
export function decodeMetaBlockLength(br) {
42+
const out = {
43+
meta_block_length: 0,
44+
input_end: 0,
45+
is_uncompressed: 0,
46+
is_metadata: false,
47+
}
48+
49+
out.input_end = br.readBits(1)
50+
if (out.input_end && br.readBits(1)) {
51+
return out
52+
}
53+
54+
const size_nibbles = br.readBits(2) + 4
55+
if (size_nibbles === 7) {
56+
out.is_metadata = true
57+
58+
if (br.readBits(1) !== 0)
59+
throw new Error('Invalid reserved bit')
60+
61+
const size_bytes = br.readBits(2)
62+
if (size_bytes === 0)
63+
return out
64+
65+
for (let i = 0; i < size_bytes; i++) {
66+
const next_byte = br.readBits(8)
67+
if (i + 1 === size_bytes && size_bytes > 1 && next_byte === 0)
68+
throw new Error('Invalid size byte')
69+
70+
out.meta_block_length |= next_byte << i * 8
71+
}
72+
} else {
73+
for (let i = 0; i < size_nibbles; i++) {
74+
const next_nibble = br.readBits(4)
75+
if (i + 1 === size_nibbles && size_nibbles > 4 && next_nibble === 0)
76+
throw new Error('Invalid size nibble')
77+
78+
out.meta_block_length |= next_nibble << i * 4
79+
}
80+
}
81+
82+
out.meta_block_length++
83+
84+
if (!out.input_end && !out.is_metadata) {
85+
out.is_uncompressed = br.readBits(1)
86+
}
87+
88+
return out
89+
}
90+
91+
92+
/**
93+
* @import {BrotliOutput} from './brotli.streams.js'
94+
* @param {BrotliOutput} output
95+
* @param {number} len
96+
* @param {number} pos
97+
* @param {Uint8Array} ringbuffer
98+
* @param {number} ringbuffer_mask
99+
* @param {BrotliBitReader} br
100+
*/
101+
export function copyUncompressedBlockToOutput(output, len, pos, ringbuffer, ringbuffer_mask, br) {
102+
const rb_size = ringbuffer_mask + 1
103+
let rb_pos = pos & ringbuffer_mask
104+
let br_pos = br.pos_ & BrotliBitReader.IBUF_MASK
105+
106+
// For short lengths copy byte-by-byte
107+
if (len < 8 || br.bit_pos_ + (len << 3) < br.bit_end_pos_) {
108+
while (len-- > 0) {
109+
br.readMoreInput()
110+
ringbuffer[rb_pos++] = br.readBits(8)
111+
if (rb_pos === rb_size) {
112+
output.write(ringbuffer, rb_size)
113+
rb_pos = 0
114+
}
115+
}
116+
return
117+
}
118+
119+
if (br.bit_end_pos_ < 32) {
120+
throw new Error('copyUncompressedBlockToOutput: br.bit_end_pos_ < 32')
121+
}
122+
123+
// Copy remaining 0-4 bytes from br.val_ to ringbuffer
124+
while (br.bit_pos_ < 32) {
125+
ringbuffer[rb_pos] = br.val_ >>> br.bit_pos_
126+
br.bit_pos_ += 8
127+
rb_pos++
128+
len--
129+
}
130+
131+
// Copy remaining bytes from br.buf_ to ringbuffer
132+
let nbytes = br.bit_end_pos_ - br.bit_pos_ >> 3
133+
if (br_pos + nbytes > BrotliBitReader.IBUF_MASK) {
134+
const tail = BrotliBitReader.IBUF_MASK + 1 - br_pos
135+
for (let x = 0; x < tail; x++)
136+
ringbuffer[rb_pos + x] = br.buf_[br_pos + x]
137+
138+
nbytes -= tail
139+
rb_pos += tail
140+
len -= tail
141+
br_pos = 0
142+
}
143+
144+
for (let x = 0; x < nbytes; x++)
145+
ringbuffer[rb_pos + x] = br.buf_[br_pos + x]
146+
147+
rb_pos += nbytes
148+
len -= nbytes
149+
150+
// If we wrote past the logical end of the ringbuffer, copy the tail of the
151+
// ringbuffer to its beginning and flush the ringbuffer to the output
152+
if (rb_pos >= rb_size) {
153+
output.write(ringbuffer, rb_size)
154+
rb_pos -= rb_size
155+
for (let x = 0; x < rb_pos; x++)
156+
ringbuffer[x] = ringbuffer[rb_size + x]
157+
}
158+
159+
// If we have more to copy than the remaining size of the ringbuffer, then we
160+
// first fill the ringbuffer from the input and then flush the ringbuffer
161+
while (rb_pos + len >= rb_size) {
162+
nbytes = rb_size - rb_pos
163+
if (br.input_.read(ringbuffer, rb_pos, nbytes) < nbytes) {
164+
throw new Error('copyUncompressedBlockToOutput: not enough bytes')
165+
}
166+
output.write(ringbuffer, rb_size)
167+
len -= nbytes
168+
rb_pos = 0
169+
}
170+
171+
// Copy straight from the input onto the ringbuffer
172+
// Ringbuffer will be flushed to output later
173+
if (br.input_.read(ringbuffer, rb_pos, len) < len) {
174+
throw new Error('copyUncompressedBlockToOutput: not enough bytes')
175+
}
176+
177+
// Restore the state of the bit reader
178+
br.reset()
179+
}
180+
181+
/**
182+
* Decodes a number in the range [0..255], by reading 1 - 11 bits.
183+
* @param {BrotliBitReader} br
184+
* @returns {number}
185+
*/
186+
export function decodeVarLenUint8(br) {
187+
if (br.readBits(1)) {
188+
const nbits = br.readBits(3)
189+
if (nbits === 0) {
190+
return 1
191+
} else {
192+
return br.readBits(nbits) + (1 << nbits)
193+
}
194+
}
195+
return 0
196+
}
197+
198+
/**
199+
* @param {BrotliBitReader} br
200+
* @returns {number}
201+
*/
202+
export function decodeWindowBits(br) {
203+
if (br.readBits(1) === 0) return 16
204+
205+
let n = br.readBits(3)
206+
if (n > 0) return 17 + n
207+
208+
n = br.readBits(3)
209+
if (n > 0) return 8 + n
210+
211+
return 17
212+
}
213+
214+
/**
215+
* Advances the bit reader position to the next byte boundary and verifies
216+
* that any skipped bits are set to zero.
217+
* @param {BrotliBitReader} br
218+
* @returns {boolean}
219+
*/
220+
export function jumpToByteBoundary(br) {
221+
const new_bit_pos = br.bit_pos_ + 7 & ~7
222+
return !br.readBits(new_bit_pos - br.bit_pos_)
223+
}
224+
225+
/**
226+
* @param {HuffmanCode[]} table
227+
* @param {number} index
228+
* @param {BrotliBitReader} br
229+
* @returns {number}
230+
*/
231+
export function readBlockLength(table, index, br) {
232+
const code = readSymbol(table, index, br)
233+
const { offset, nbits } = kBlockLengthPrefixCode[code]
234+
return offset + br.readBits(nbits)
235+
}

src/brotli.contextmap.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import { decodeVarLenUint8 } from './brotli.blocks.js'
12
import { HuffmanCode, readHuffmanCode, readSymbol } from './brotli.huffman.js'
2-
import { decodeVarLenUint8 } from './brotli.js'
33
import { HUFFMAN_MAX_TABLE_SIZE } from './gzip.huffman.js'
44

55
/**
6+
* @import {BrotliBitReader} from './brotli.bitreader.js'
67
* @param {number} context_map_size
7-
* @param {import('./brotli.huffman.js').BrotliBitReader} br
8+
* @param {BrotliBitReader} br
89
* @returns {[number, Uint8Array]} // num_htrees, context_map
910
*/
1011
export function decodeContextMap(context_map_size, br) {

src/brotli.dictionary.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
/* Copyright 2013 Google Inc. All Rights Reserved.
22
3-
Licensed under the Apache License, Version 2.0 (the "License");
4-
you may not use this file except in compliance with the License.
5-
You may obtain a copy of the License at
6-
7-
http://www.apache.org/licenses/LICENSE-2.0
8-
9-
Unless required by applicable law or agreed to in writing, software
10-
distributed under the License is distributed on an "AS IS" BASIS,
11-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
See the License for the specific language governing permissions and
13-
limitations under the License.
14-
153
Collection of static dictionary words.
164
*/
175

0 commit comments

Comments
 (0)