mirror of
https://github.com/asadbek064/hyparquet-compressors.git
synced 2026-01-12 05:36:37 +00:00
137 lines
4.2 KiB
JavaScript
137 lines
4.2 KiB
JavaScript
|
|
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||
|
|
|
||
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
|
you may not use this file except in compliance with the License.
|
||
|
|
You may obtain a copy of the License at
|
||
|
|
|
||
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
|
||
|
|
Unless required by applicable law or agreed to in writing, software
|
||
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
|
See the License for the specific language governing permissions and
|
||
|
|
limitations under the License.
|
||
|
|
|
||
|
|
Bit reading helpers
|
||
|
|
*/
|
||
|
|
|
||
|
|
const BROTLI_READ_SIZE = 4096
|
||
|
|
const BROTLI_IBUF_SIZE = 2 * BROTLI_READ_SIZE + 32
|
||
|
|
const BROTLI_IBUF_MASK = 2 * BROTLI_READ_SIZE - 1
|
||
|
|
|
||
|
|
const kBitMask = new Uint32Array([
|
||
|
|
0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767,
|
||
|
|
65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215,
|
||
|
|
])
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Input byte buffer, consist of a ringbuffer and a "slack" region where
|
||
|
|
* bytes from the start of the ringbuffer are copied.
|
||
|
|
*
|
||
|
|
* @typedef {import('./brotliStreams.js').BrotliInput} BrotliInput
|
||
|
|
* @param {BrotliInput} input
|
||
|
|
*/
|
||
|
|
function BrotliBitReader(input) {
|
||
|
|
this.buf_ = new Uint8Array(BROTLI_IBUF_SIZE)
|
||
|
|
this.input_ = input /* input callback */
|
||
|
|
|
||
|
|
this.buf_ptr_ = 0 /* next input will write here */
|
||
|
|
this.val_ = 0 /* pre-fetched bits */
|
||
|
|
this.pos_ = 0 /* byte position in stream */
|
||
|
|
|
||
|
|
this.reset()
|
||
|
|
}
|
||
|
|
|
||
|
|
BrotliBitReader.READ_SIZE = BROTLI_READ_SIZE
|
||
|
|
BrotliBitReader.IBUF_MASK = BROTLI_IBUF_MASK
|
||
|
|
|
||
|
|
BrotliBitReader.prototype.reset = function() {
|
||
|
|
this.buf_ptr_ = 0 /* next input will write here */
|
||
|
|
this.val_ = 0 /* pre-fetched bits */
|
||
|
|
this.pos_ = 0 /* byte position in stream */
|
||
|
|
this.bit_pos_ = 0 /* current bit-reading position in val_ */
|
||
|
|
this.bit_end_pos_ = 0 /* bit-reading end position from LSB of val_ */
|
||
|
|
this.eos_ = 0 /* input stream is finished */
|
||
|
|
|
||
|
|
this.readMoreInput()
|
||
|
|
for (let i = 0; i < 4; i++) {
|
||
|
|
this.val_ |= this.buf_[this.pos_] << 8 * i
|
||
|
|
this.pos_++
|
||
|
|
}
|
||
|
|
|
||
|
|
return this.bit_end_pos_ > 0
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fills up the input ringbuffer by calling the input callback.
|
||
|
|
*
|
||
|
|
* Does nothing if there are at least 32 bytes present after current position.
|
||
|
|
*
|
||
|
|
* Returns 0 if either:
|
||
|
|
* - the input callback returned an error, or
|
||
|
|
* - there is no more input and the position is past the end of the stream.
|
||
|
|
*
|
||
|
|
* After encountering the end of the input stream, 32 additional zero bytes are
|
||
|
|
* copied to the ringbuffer, therefore it is safe to call this function after
|
||
|
|
* every 32 bytes of input is read.
|
||
|
|
*/
|
||
|
|
BrotliBitReader.prototype.readMoreInput = function() {
|
||
|
|
if (this.bit_end_pos_ > 256) {
|
||
|
|
// return
|
||
|
|
} else if (this.eos_) {
|
||
|
|
if (this.bit_pos_ > this.bit_end_pos_)
|
||
|
|
throw new Error('Unexpected end of input ' + this.bit_pos_ + ' ' + this.bit_end_pos_)
|
||
|
|
} else {
|
||
|
|
const dst = this.buf_ptr_
|
||
|
|
const bytes_read = this.input_.read(this.buf_, dst, BROTLI_READ_SIZE)
|
||
|
|
if (bytes_read < 0) {
|
||
|
|
throw new Error('Unexpected end of input')
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bytes_read < BROTLI_READ_SIZE) {
|
||
|
|
this.eos_ = 1
|
||
|
|
/* Store 32 bytes of zero after the stream end. */
|
||
|
|
for (let p = 0; p < 32; p++)
|
||
|
|
this.buf_[dst + bytes_read + p] = 0
|
||
|
|
}
|
||
|
|
|
||
|
|
if (dst === 0) {
|
||
|
|
/* Copy the head of the ringbuffer to the slack region. */
|
||
|
|
for (let p = 0; p < 32; p++)
|
||
|
|
this.buf_[(BROTLI_READ_SIZE << 1) + p] = this.buf_[p]
|
||
|
|
|
||
|
|
this.buf_ptr_ = BROTLI_READ_SIZE
|
||
|
|
} else {
|
||
|
|
this.buf_ptr_ = 0
|
||
|
|
}
|
||
|
|
|
||
|
|
this.bit_end_pos_ += bytes_read << 3
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Guarantees that there are at least 24 bits in the buffer. */
|
||
|
|
BrotliBitReader.prototype.fillBitWindow = function() {
|
||
|
|
while (this.bit_pos_ >= 8) {
|
||
|
|
this.val_ >>>= 8
|
||
|
|
this.val_ |= this.buf_[this.pos_ & BROTLI_IBUF_MASK] << 24
|
||
|
|
this.pos_++
|
||
|
|
this.bit_pos_ = this.bit_pos_ - 8 >>> 0
|
||
|
|
this.bit_end_pos_ = this.bit_end_pos_ - 8 >>> 0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Reads the specified number of bits from Read Buffer.
|
||
|
|
*
|
||
|
|
* @param {number} n_bits
|
||
|
|
* @returns {number}
|
||
|
|
*/
|
||
|
|
BrotliBitReader.prototype.readBits = function(n_bits) {
|
||
|
|
if (32 - this.bit_pos_ < n_bits) this.fillBitWindow()
|
||
|
|
const val = this.val_ >>> this.bit_pos_ & kBitMask[n_bits]
|
||
|
|
this.bit_pos_ += n_bits
|
||
|
|
return val
|
||
|
|
}
|
||
|
|
|
||
|
|
export default BrotliBitReader
|