mirror of
https://github.com/google/brotli.git
synced 2024-12-01 23:40:05 +00:00
238 lines
7.8 KiB
C
238 lines
7.8 KiB
C
/* 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 */
|
|
|
|
#ifndef BROTLI_DEC_BIT_READER_H_
|
|
#define BROTLI_DEC_BIT_READER_H_
|
|
|
|
#include <string.h>
|
|
#include "./port.h"
|
|
#include "./streams.h"
|
|
#include "./types.h"
|
|
|
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define BROTLI_MAX_NUM_BIT_READ 25
|
|
#define BROTLI_READ_SIZE 1024
|
|
#define BROTLI_IBUF_SIZE (BROTLI_READ_SIZE + 128)
|
|
#define BROTLI_IBUF_MASK (BROTLI_READ_SIZE - 1)
|
|
|
|
/* Masking with this expression turns to a single "Unsigned Bit Field Extract"
|
|
UBFX instruction on ARM. */
|
|
static BROTLI_INLINE uint32_t BitMask(int n) { return ~((0xffffffff) << n); }
|
|
|
|
typedef struct {
|
|
#if (BROTLI_64_BITS_LITTLE_ENDIAN)
|
|
uint64_t val_; /* pre-fetched bits */
|
|
#else
|
|
uint32_t val_; /* pre-fetched bits */
|
|
#endif
|
|
uint32_t bit_pos_; /* current bit-reading position in val_ */
|
|
uint8_t* next_in; /* the byte we're reading from */
|
|
uint32_t avail_in;
|
|
int eos_; /* input stream is finished */
|
|
BrotliInput input_; /* input callback */
|
|
|
|
/* indicates how much bytes already read when reading partial data */
|
|
int tmp_bytes_read_;
|
|
|
|
/* Input byte buffer, consist of a ringbuffer and a "slack" region where */
|
|
/* bytes from the start of the ringbuffer are copied. */
|
|
uint8_t buf_[BROTLI_IBUF_SIZE];
|
|
} BrotliBitReader;
|
|
|
|
/* Initializes the bitreader fields. After this, BrotliReadInput then
|
|
BrotliWarmupBitReader must be used. */
|
|
void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input);
|
|
|
|
/* Initializes bit reading and bit position with the first input data available.
|
|
Requires that there is enough input available (BrotliCheckInputAmount). */
|
|
void BrotliWarmupBitReader(BrotliBitReader* const br);
|
|
|
|
/* Pulls data from the input to the the read buffer.
|
|
|
|
Returns 0 if one of:
|
|
- the input callback returned an error, or
|
|
- there is no more input and the position is past the end of the stream.
|
|
- finish is false and less than BROTLI_READ_SIZE are available - a next call
|
|
when more data is available makes it continue including the partially read
|
|
data
|
|
|
|
If finish is true and the end of the stream is reached, 128 additional zero
|
|
bytes are copied to the ringbuffer.
|
|
*/
|
|
static BROTLI_INLINE int BrotliReadInput(
|
|
BrotliBitReader* const br, int finish) {
|
|
if (PREDICT_FALSE(br->eos_)) {
|
|
return 0;
|
|
} else {
|
|
size_t i;
|
|
int bytes_read;
|
|
uint8_t* dst = br->buf_;
|
|
if (br->next_in != br->buf_) {
|
|
int num = (int)(br->avail_in);
|
|
for (i = 0; i < num; i++) {
|
|
br->buf_[i] = br->next_in[i];
|
|
}
|
|
br->next_in = br->buf_;
|
|
br->tmp_bytes_read_ = num;
|
|
}
|
|
|
|
bytes_read = BrotliRead(br->input_, dst + br->tmp_bytes_read_,
|
|
(size_t) (BROTLI_READ_SIZE - br->tmp_bytes_read_));
|
|
if (bytes_read < 0) {
|
|
return 0;
|
|
}
|
|
bytes_read += br->tmp_bytes_read_;
|
|
br->tmp_bytes_read_ = 0;
|
|
if (bytes_read < BROTLI_READ_SIZE) {
|
|
if (!finish) {
|
|
br->tmp_bytes_read_ = bytes_read;
|
|
return 0;
|
|
}
|
|
br->eos_ = 1;
|
|
/* Store 128 bytes of zero after the stream end. */
|
|
memset(dst + bytes_read, 0, 128);
|
|
bytes_read += 128;
|
|
}
|
|
br->avail_in = (uint32_t)bytes_read;
|
|
br->next_in = br->buf_;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* Returns amount of unread bytes the bit reader still has buffered from the
|
|
BrotliInput, including whole bytes in br->val_. */
|
|
static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
|
|
return br->avail_in + sizeof(br->val_) - (br->bit_pos_ >> 3);
|
|
}
|
|
|
|
/* Checks if there is at least num bytes left in the input ringbuffer (excluding
|
|
the bits remaining in br->val_). The maximum value for num is 128 bytes. */
|
|
static BROTLI_INLINE int BrotliCheckInputAmount(
|
|
BrotliBitReader* const br, size_t num) {
|
|
return br->avail_in >= num;
|
|
}
|
|
|
|
/* Guarantees that there are at least n_bits in the buffer.
|
|
n_bits should be in the range [1..24] */
|
|
static BROTLI_INLINE void BrotliFillBitWindow(
|
|
BrotliBitReader* const br, int n_bits) {
|
|
#if (BROTLI_64_BITS_LITTLE_ENDIAN)
|
|
if (br->bit_pos_ >= 32) {
|
|
br->val_ >>= 32;
|
|
br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
|
|
br->val_ |= ((uint64_t)(*(const uint32_t*)(br->next_in))) << 32;
|
|
br->avail_in -= 4;
|
|
br->next_in += 4;
|
|
}
|
|
#elif (BROTLI_LITTLE_ENDIAN)
|
|
if (br->bit_pos_ >= 16) {
|
|
br->val_ >>= 16;
|
|
br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
|
|
br->val_ |= ((uint32_t)(*(const uint16_t*)(br->next_in))) << 16;
|
|
br->avail_in -= 2;
|
|
br->next_in += 2;
|
|
}
|
|
if (!IS_CONSTANT(n_bits) || (n_bits > 16)) {
|
|
if (br->bit_pos_ >= 8) {
|
|
br->val_ >>= 8;
|
|
br->bit_pos_ ^= 8; /* here same as -= 8 because of the if condition */
|
|
br->val_ |= ((uint32_t)*br->next_in) << 24;
|
|
--br->avail_in;
|
|
++br->next_in;
|
|
}
|
|
}
|
|
#else
|
|
while (br->bit_pos_ >= 8) {
|
|
br->val_ >>= 8;
|
|
br->val_ |= ((uint32_t)*br->next_in) << 24;
|
|
br->bit_pos_ -= 8;
|
|
--br->avail_in;
|
|
++br->next_in;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Like BrotliGetBits, but does not mask the result, it is only guaranteed
|
|
that it has minimum n_bits. */
|
|
static BROTLI_INLINE uint32_t BrotliGetBitsUnmasked(
|
|
BrotliBitReader* const br, int n_bits) {
|
|
BrotliFillBitWindow(br, n_bits);
|
|
return (uint32_t)(br->val_ >> br->bit_pos_);
|
|
}
|
|
|
|
/* Returns the specified number of bits from br without advancing bit pos. */
|
|
static BROTLI_INLINE uint32_t BrotliGetBits(
|
|
BrotliBitReader* const br, int n_bits) {
|
|
BrotliFillBitWindow(br, n_bits);
|
|
return (uint32_t)(br->val_ >> br->bit_pos_) & BitMask(n_bits);
|
|
}
|
|
|
|
/* Advances the bit pos by n_bits. */
|
|
static BROTLI_INLINE void BrotliDropBits(
|
|
BrotliBitReader* const br, int n_bits) {
|
|
br->bit_pos_ += (uint32_t)n_bits;
|
|
}
|
|
|
|
/* Reads the specified number of bits from br and advances the bit pos. */
|
|
static BROTLI_INLINE uint32_t BrotliReadBits(
|
|
BrotliBitReader* const br, int n_bits) {
|
|
uint32_t val;
|
|
BrotliFillBitWindow(br, n_bits);
|
|
val = (uint32_t)(br->val_ >> br->bit_pos_) & BitMask(n_bits);
|
|
#ifdef BROTLI_DECODE_DEBUG
|
|
printf("[BrotliReadBits] %d %d %d val: %6x\n",
|
|
(int)br->avail_in, (int)br->bit_pos_, n_bits, val);
|
|
#endif
|
|
br->bit_pos_ += (uint32_t)n_bits;
|
|
return val;
|
|
}
|
|
|
|
/* Advances the bit reader position to the next byte boundary and verifies
|
|
that any skipped bits are set to zero. */
|
|
static BROTLI_INLINE int BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
|
uint32_t new_bit_pos = (br->bit_pos_ + 7) & (uint32_t)(~7UL);
|
|
uint32_t pad_bits = BrotliReadBits(br, (int)(new_bit_pos - br->bit_pos_));
|
|
return pad_bits == 0;
|
|
}
|
|
|
|
/* Copies remaining input bytes stored in the bit reader to the output. Value
|
|
num may not be larger than BrotliGetRemainingBytes. The bit reader must be
|
|
warmed up again after this. */
|
|
static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
|
|
BrotliBitReader* br, size_t num) {
|
|
while (br->bit_pos_ + 8 <= (BROTLI_64_BITS_LITTLE_ENDIAN ? 64 : 32)
|
|
&& num > 0) {
|
|
*dest = (uint8_t)(br->val_ >> br->bit_pos_);
|
|
br->bit_pos_ += 8;
|
|
++dest;
|
|
--num;
|
|
}
|
|
memcpy(dest, br->next_in, num);
|
|
br->avail_in -= (uint32_t)num;
|
|
br->next_in += num;
|
|
br->bit_pos_ = 0;
|
|
}
|
|
|
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
} /* extern "C" */
|
|
#endif
|
|
|
|
#endif /* BROTLI_DEC_BIT_READER_H_ */
|