mirror of
https://github.com/google/brotli.git
synced 2024-12-28 02:31:05 +00:00
Update decoder.
* Reduce memory usage * Update API documentation * Remove deprecated API * Move non-API declatarions from decode.h * Remove streams * Add more debug logging * Fix shift in BrotliBitReaderUnload * Allocate ringbuffer at later stages * Sort / fix includes * Fix whitespaces * Eliminate dead code * Drive-by code simplifications
This commit is contained in:
parent
c788a55927
commit
92e3023914
@ -4,7 +4,7 @@ include ../shared.mk
|
||||
|
||||
CFLAGS += -Wall
|
||||
|
||||
OBJS = bit_reader.o decode.o dictionary.o huffman.o state.o streams.o
|
||||
OBJS = bit_reader.o decode.o dictionary.o huffman.o state.o
|
||||
|
||||
all : $(OBJS)
|
||||
|
||||
|
@ -6,10 +6,10 @@
|
||||
|
||||
/* Bit reading helpers */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "./bit_reader.h"
|
||||
|
||||
#include "./port.h"
|
||||
#include "./types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
@ -9,8 +9,8 @@
|
||||
#ifndef BROTLI_DEC_BIT_READER_H_
|
||||
#define BROTLI_DEC_BIT_READER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include "./port.h"
|
||||
#include "./types.h"
|
||||
|
||||
@ -283,7 +283,11 @@ static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
|
||||
uint32_t unused_bits = unused_bytes << 3;
|
||||
br->avail_in += unused_bytes;
|
||||
br->next_in -= unused_bytes;
|
||||
br->val_ <<= unused_bits;
|
||||
if (unused_bits == sizeof(br->val_) << 3) {
|
||||
br->val_ = 0;
|
||||
} else {
|
||||
br->val_ <<= unused_bits;
|
||||
}
|
||||
br->bit_pos_ += unused_bits;
|
||||
}
|
||||
|
||||
@ -349,9 +353,7 @@ static BROTLI_INLINE int BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
||||
static BROTLI_INLINE int BrotliPeekByte(BrotliBitReader* br, size_t offset) {
|
||||
uint32_t available_bits = BrotliGetAvailableBits(br);
|
||||
size_t bytes_left = available_bits >> 3;
|
||||
if (available_bits & 7) {
|
||||
return -1;
|
||||
}
|
||||
BROTLI_DCHECK((available_bits & 7) == 0);
|
||||
if (offset < bytes_left) {
|
||||
return (BrotliGetBitsUnmasked(br) >> (unsigned)(offset << 3)) & 0xFF;
|
||||
}
|
||||
|
284
dec/decode.c
284
dec/decode.c
@ -4,26 +4,42 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "./bit_reader.h"
|
||||
#include "./context.h"
|
||||
#include "./decode.h"
|
||||
#include "./dictionary.h"
|
||||
#include "./port.h"
|
||||
#include "./transform.h"
|
||||
#include "./huffman.h"
|
||||
#include "./prefix.h"
|
||||
|
||||
#ifdef __ARM_NEON__
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h> /* printf (debug output) */
|
||||
#include <stdlib.h> /* free, malloc */
|
||||
#include <string.h> /* memcpy, memset */
|
||||
|
||||
#include "./bit_reader.h"
|
||||
#include "./context.h"
|
||||
#include "./dictionary.h"
|
||||
#include "./huffman.h"
|
||||
#include "./port.h"
|
||||
#include "./prefix.h"
|
||||
#include "./transform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* BROTLI_FAILURE macro unwraps to BROTLI_RESULT_ERROR in non-debug build. */
|
||||
/* In debug build it dumps file name, line and pretty function name. */
|
||||
#if defined(_MSC_VER) || !defined(BROTLI_DEBUG)
|
||||
#define BROTLI_FAILURE() BROTLI_RESULT_ERROR
|
||||
#else
|
||||
#define BROTLI_FAILURE() \
|
||||
BrotliFailure(__FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
static inline BrotliResult BrotliFailure(const char *f, int l, const char *fn) {
|
||||
fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn);
|
||||
fflush(stderr);
|
||||
return BROTLI_RESULT_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BROTLI_DECODE_DEBUG
|
||||
#define BROTLI_LOG_UINT(name) \
|
||||
printf("[%s] %s = %lu\n", __func__, #name, (unsigned long)(name))
|
||||
@ -239,7 +255,7 @@ static BrotliResult BROTLI_NOINLINE DecodeMetaBlockLength(BrotliState* s,
|
||||
/* No break, transit to the next state. */
|
||||
|
||||
case BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED:
|
||||
if (!s->is_last_metablock && !s->is_metadata) {
|
||||
if (!s->is_last_metablock) {
|
||||
if (!BrotliSafeReadBits(br, 1, &bits)) {
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
@ -283,9 +299,9 @@ static BrotliResult BROTLI_NOINLINE DecodeMetaBlockLength(BrotliState* s,
|
||||
}
|
||||
s->meta_block_remaining_len |= (int)(bits << (i * 8));
|
||||
}
|
||||
s->substate_metablock_header =
|
||||
BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED;
|
||||
break;
|
||||
++s->meta_block_remaining_len;
|
||||
s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
|
||||
return BROTLI_RESULT_SUCCESS;
|
||||
|
||||
default:
|
||||
return BROTLI_FAILURE();
|
||||
@ -473,6 +489,8 @@ static BROTLI_INLINE void ProcessSingleCodeLength(uint32_t code_len,
|
||||
*prev_code_len = code_len;
|
||||
*space -= 32768U >> code_len;
|
||||
code_length_histo[code_len]++;
|
||||
BROTLI_LOG(("[ReadHuffmanCode] code_length[%d] = %d\n",
|
||||
*symbol, code_len));
|
||||
}
|
||||
(*symbol)++;
|
||||
}
|
||||
@ -513,6 +531,8 @@ static BROTLI_INLINE void ProcessRepeatedCodeLength(uint32_t code_len,
|
||||
*space = 0xFFFFF;
|
||||
return;
|
||||
}
|
||||
BROTLI_LOG(("[ReadHuffmanCode] code_length[%d..%d] = %d\n",
|
||||
*symbol, *symbol + repeat_delta - 1, *repeat_code_len));
|
||||
if (*repeat_code_len != 0) {
|
||||
unsigned last = *symbol + repeat_delta;
|
||||
int next = next_symbol[*repeat_code_len];
|
||||
@ -1018,9 +1038,9 @@ rleCode:
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
|
||||
return BROTLI_RESULT_SUCCESS;
|
||||
}
|
||||
default:
|
||||
return BROTLI_FAILURE();
|
||||
}
|
||||
|
||||
return BROTLI_FAILURE();
|
||||
}
|
||||
|
||||
/* Decodes a command or literal and updates block type ringbuffer.
|
||||
@ -1028,9 +1048,10 @@ rleCode:
|
||||
static BROTLI_INLINE int DecodeBlockTypeAndLength(int safe,
|
||||
BrotliState* s, int tree_type) {
|
||||
uint32_t max_block_type = s->num_block_types[tree_type];
|
||||
int tree_offset = tree_type * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
|
||||
const HuffmanCode* type_tree = &s->block_type_trees[tree_offset];
|
||||
const HuffmanCode* len_tree = &s->block_len_trees[tree_offset];
|
||||
const HuffmanCode* type_tree = &s->block_type_trees[
|
||||
tree_type * BROTLI_HUFFMAN_MAX_SIZE_258];
|
||||
const HuffmanCode* len_tree = &s->block_len_trees[
|
||||
tree_type * BROTLI_HUFFMAN_MAX_SIZE_26];
|
||||
BrotliBitReader* br = &s->br;
|
||||
uint32_t* ringbuffer = &s->block_type_rb[tree_type * 2];
|
||||
uint32_t block_type;
|
||||
@ -1152,7 +1173,7 @@ static BrotliResult WriteRingBuffer(size_t* available_out, uint8_t** next_out,
|
||||
*available_out -= num_written;
|
||||
BROTLI_LOG_UINT(to_write);
|
||||
BROTLI_LOG_UINT(num_written);
|
||||
s->partial_pos_out += (size_t)num_written;
|
||||
s->partial_pos_out += num_written;
|
||||
*total_out = s->partial_pos_out;
|
||||
if (num_written < to_write) {
|
||||
return BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
@ -1160,9 +1181,48 @@ static BrotliResult WriteRingBuffer(size_t* available_out, uint8_t** next_out,
|
||||
return BROTLI_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Allocates ringbuffer.
|
||||
|
||||
s->ringbuffer_size MUST be updated by BrotliCalculateRingBufferSize before
|
||||
this function is called.
|
||||
|
||||
Last two bytes of ringbuffer are initialized to 0, so context calculation
|
||||
could be done uniformly for the first two and all other positions.
|
||||
|
||||
Custom dictionary, if any, is copied to the end of ringbuffer.
|
||||
*/
|
||||
static int BROTLI_NOINLINE BrotliAllocateRingBuffer(BrotliState* s) {
|
||||
/* We need the slack region for the following reasons:
|
||||
- doing up to two 16-byte copies for fast backward copying
|
||||
- inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */
|
||||
static const int kRingBufferWriteAheadSlack = 42;
|
||||
s->ringbuffer = (uint8_t*)BROTLI_ALLOC(s, (size_t)(s->ringbuffer_size +
|
||||
kRingBufferWriteAheadSlack));
|
||||
if (s->ringbuffer == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->ringbuffer_end = s->ringbuffer + s->ringbuffer_size;
|
||||
|
||||
s->ringbuffer[s->ringbuffer_size - 2] = 0;
|
||||
s->ringbuffer[s->ringbuffer_size - 1] = 0;
|
||||
|
||||
if (s->custom_dict) {
|
||||
memcpy(&s->ringbuffer[(-s->custom_dict_size) & s->ringbuffer_mask],
|
||||
s->custom_dict, (size_t)s->custom_dict_size);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(
|
||||
size_t* available_out, uint8_t** next_out, size_t* total_out,
|
||||
BrotliState* s) {
|
||||
/* TODO: avoid allocation for single uncompressed block. */
|
||||
if (!s->ringbuffer && !BrotliAllocateRingBuffer(s)) {
|
||||
return BROTLI_FAILURE();
|
||||
}
|
||||
|
||||
/* State machine */
|
||||
for (;;) {
|
||||
switch (s->substate_uncompressed) {
|
||||
@ -1185,7 +1245,6 @@ static BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_WRITE;
|
||||
/*s->partial_pos_rb += (size_t)s->ringbuffer_size;*/
|
||||
/* No break, continue to next state */
|
||||
}
|
||||
case BROTLI_STATE_UNCOMPRESSED_WRITE: {
|
||||
@ -1231,21 +1290,15 @@ int BrotliDecompressedSize(size_t encoded_size,
|
||||
return (next_block_header != -1) && ((next_block_header & 3) == 3);
|
||||
}
|
||||
|
||||
/* Allocates the smallest feasible ring buffer.
|
||||
/* Calculates the smallest feasible ring buffer.
|
||||
|
||||
If we know the data size is small, do not allocate more ringbuffer
|
||||
size than needed to reduce memory usage.
|
||||
|
||||
This method is called before the first non-empty non-metadata block is
|
||||
processed. When this method is called, metablock size and flags MUST be
|
||||
decoded.
|
||||
When this method is called, metablock size and flags MUST be decoded.
|
||||
*/
|
||||
static int BROTLI_NOINLINE BrotliAllocateRingBuffer(BrotliState* s,
|
||||
static void BROTLI_NOINLINE BrotliCalculateRingBufferSize(BrotliState* s,
|
||||
BrotliBitReader* br) {
|
||||
/* We need the slack region for the following reasons:
|
||||
- doing up to two 16-byte copies for fast backward copying
|
||||
- inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */
|
||||
static const int kRingBufferWriteAheadSlack = 42;
|
||||
int is_last = s->is_last_metablock;
|
||||
s->ringbuffer_size = 1 << s->window_bits;
|
||||
|
||||
@ -1274,20 +1327,6 @@ static int BROTLI_NOINLINE BrotliAllocateRingBuffer(BrotliState* s,
|
||||
}
|
||||
|
||||
s->ringbuffer_mask = s->ringbuffer_size - 1;
|
||||
s->ringbuffer = (uint8_t*)BROTLI_ALLOC(s, (size_t)(s->ringbuffer_size +
|
||||
kRingBufferWriteAheadSlack + kBrotliMaxDictionaryWordLength));
|
||||
if (s->ringbuffer == 0) {
|
||||
return 0;
|
||||
}
|
||||
s->ringbuffer_end = s->ringbuffer + s->ringbuffer_size;
|
||||
s->ringbuffer[s->ringbuffer_size - 2] = 0;
|
||||
s->ringbuffer[s->ringbuffer_size - 1] = 0;
|
||||
if (s->custom_dict) {
|
||||
memcpy(&s->ringbuffer[(-s->custom_dict_size) & s->ringbuffer_mask],
|
||||
s->custom_dict, (size_t)s->custom_dict_size);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Reads 1..256 2-bit context modes. */
|
||||
@ -1461,13 +1500,6 @@ static BROTLI_INLINE int SafeReadCommand(BrotliState* s, BrotliBitReader* br,
|
||||
return ReadCommandInternal(1, s, br, insert_length);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE int WarmupBitReader(int safe, BrotliBitReader* const br) {
|
||||
if (safe) {
|
||||
return 1;
|
||||
}
|
||||
return BrotliWarmupBitReader(br);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE int CheckInputAmount(int safe,
|
||||
BrotliBitReader* const br, size_t num) {
|
||||
if (safe) {
|
||||
@ -1494,10 +1526,13 @@ static BROTLI_INLINE BrotliResult ProcessCommandsInternal(int safe,
|
||||
BrotliResult result = BROTLI_RESULT_SUCCESS;
|
||||
BrotliBitReader* br = &s->br;
|
||||
|
||||
if (!CheckInputAmount(safe, br, 28) || !WarmupBitReader(safe, br)) {
|
||||
if (!CheckInputAmount(safe, br, 28)) {
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
goto saveStateAndReturn;
|
||||
}
|
||||
if (!safe) {
|
||||
BROTLI_UNUSED(BrotliWarmupBitReader(br));
|
||||
}
|
||||
|
||||
/* Jump into state machine. */
|
||||
if (s->state == BROTLI_STATE_COMMAND_BEGIN) {
|
||||
@ -1527,9 +1562,8 @@ CommandBegin:
|
||||
}
|
||||
/* Read the insert/copy length in the command */
|
||||
BROTLI_SAFE(ReadCommand(s, br, &i));
|
||||
BROTLI_LOG_UINT(i);
|
||||
BROTLI_LOG_UINT(s->copy_length);
|
||||
BROTLI_LOG_UINT(s->distance_code);
|
||||
BROTLI_LOG(("[ProcessCommandsInternal] pos = %d insert = %d copy = %d\n",
|
||||
pos, i, s->copy_length));
|
||||
if (i == 0) {
|
||||
goto CommandPostDecodeLiterals;
|
||||
}
|
||||
@ -1615,6 +1649,7 @@ CommandInner:
|
||||
}
|
||||
} while (--i != 0);
|
||||
}
|
||||
BROTLI_LOG_UINT(s->meta_block_remaining_len);
|
||||
if (s->meta_block_remaining_len <= 0) {
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
goto saveStateAndReturn;
|
||||
@ -1635,7 +1670,8 @@ CommandPostDecodeLiterals:
|
||||
}
|
||||
BROTLI_SAFE(ReadDistance(s, br));
|
||||
postReadDistance:
|
||||
BROTLI_LOG_UINT(s->distance_code);
|
||||
BROTLI_LOG(("[ProcessCommandsInternal] pos = %d distance = %d\n",
|
||||
pos, s->distance_code));
|
||||
if (s->max_distance != s->max_backward_distance) {
|
||||
if (pos < s->max_backward_distance_minus_custom_dict_size) {
|
||||
s->max_distance = pos + s->custom_dict_size;
|
||||
@ -1649,7 +1685,7 @@ postReadDistance:
|
||||
if (s->distance_code > s->max_distance) {
|
||||
if (i >= kBrotliMinDictionaryWordLength &&
|
||||
i <= kBrotliMaxDictionaryWordLength) {
|
||||
int offset = kBrotliDictionaryOffsetsByLength[i];
|
||||
int offset = (int)kBrotliDictionaryOffsetsByLength[i];
|
||||
int word_id = s->distance_code - s->max_distance - 1;
|
||||
uint32_t shift = kBrotliDictionarySizeBitsByLength[i];
|
||||
int mask = (int)BitMask(shift);
|
||||
@ -1734,6 +1770,7 @@ postReadDistance:
|
||||
}
|
||||
}
|
||||
}
|
||||
BROTLI_LOG_UINT(s->meta_block_remaining_len);
|
||||
if (s->meta_block_remaining_len <= 0) {
|
||||
/* Next metablock, if any */
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
@ -1813,113 +1850,6 @@ BrotliResult BrotliDecompressBuffer(size_t encoded_size,
|
||||
return result;
|
||||
}
|
||||
|
||||
BrotliResult BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
||||
BrotliState s;
|
||||
BrotliResult result;
|
||||
BrotliStateInit(&s);
|
||||
result = BrotliDecompressStreaming(input, output, 1, &s);
|
||||
if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
|
||||
/* Not ok: it didn't finish even though this is a non-streaming function. */
|
||||
result = BROTLI_FAILURE();
|
||||
}
|
||||
BrotliStateCleanup(&s);
|
||||
return result;
|
||||
}
|
||||
|
||||
BrotliResult BrotliDecompressBufferStreaming(size_t* available_in,
|
||||
const uint8_t** next_in,
|
||||
int finish,
|
||||
size_t* available_out,
|
||||
uint8_t** next_out,
|
||||
size_t* total_out,
|
||||
BrotliState* s) {
|
||||
BrotliResult result = BrotliDecompressStream(available_in, next_in,
|
||||
available_out, next_out, total_out, s);
|
||||
if (finish && result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
|
||||
result = BROTLI_FAILURE();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
int finish, BrotliState* s) {
|
||||
const size_t kBufferSize = 65536;
|
||||
BrotliResult result;
|
||||
uint8_t* input_buffer;
|
||||
uint8_t* output_buffer;
|
||||
size_t avail_in;
|
||||
const uint8_t* next_in;
|
||||
size_t total_out;
|
||||
|
||||
if (s->legacy_input_buffer == 0) {
|
||||
s->legacy_input_buffer = (uint8_t*)BROTLI_ALLOC(s, kBufferSize);
|
||||
}
|
||||
if (s->legacy_output_buffer == 0) {
|
||||
s->legacy_output_buffer = (uint8_t*)BROTLI_ALLOC(s, kBufferSize);
|
||||
}
|
||||
if (s->legacy_input_buffer == 0 || s->legacy_output_buffer == 0) {
|
||||
return BROTLI_FAILURE();
|
||||
}
|
||||
input_buffer = s->legacy_input_buffer;
|
||||
output_buffer = s->legacy_output_buffer;
|
||||
|
||||
/* Push remaining output. */
|
||||
if (s->legacy_output_len > s->legacy_output_pos) {
|
||||
size_t to_write = s->legacy_output_len - s->legacy_output_pos;
|
||||
int num_written = BrotliWrite(
|
||||
output, output_buffer + s->legacy_output_pos, to_write);
|
||||
if (num_written < 0) {
|
||||
return BROTLI_FAILURE();
|
||||
}
|
||||
s->legacy_output_pos += (size_t)num_written;
|
||||
if ((size_t)num_written < to_write) {
|
||||
return BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
}
|
||||
}
|
||||
s->legacy_output_pos = 0;
|
||||
|
||||
avail_in = s->legacy_input_len - s->legacy_input_pos;
|
||||
next_in = input_buffer + s->legacy_input_pos;
|
||||
|
||||
while (1) {
|
||||
size_t to_write;
|
||||
int num_written;
|
||||
size_t avail_out = kBufferSize;
|
||||
uint8_t* next_out = output_buffer;
|
||||
result = BrotliDecompressStream(&avail_in, &next_in,
|
||||
&avail_out, &next_out, &total_out, s);
|
||||
s->legacy_input_pos = (size_t)(next_out - input_buffer);
|
||||
to_write = (size_t)(next_out - output_buffer);
|
||||
num_written = BrotliWrite(output, output_buffer, to_write);
|
||||
if (num_written < 0) {
|
||||
return BROTLI_FAILURE();
|
||||
}
|
||||
if ((size_t)num_written < to_write) {
|
||||
s->legacy_output_len = to_write;
|
||||
s->legacy_output_pos = (size_t)num_written;
|
||||
return BROTLI_RESULT_NEEDS_MORE_OUTPUT;
|
||||
}
|
||||
if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
|
||||
int num_read = BrotliRead(input, input_buffer, kBufferSize);
|
||||
if (num_read < 0 || (num_read == 0 && finish)) {
|
||||
return BROTLI_FAILURE();
|
||||
}
|
||||
if (num_read == 0) {
|
||||
s->legacy_input_len = 0;
|
||||
s->legacy_input_pos = 0;
|
||||
return BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
}
|
||||
avail_in = (size_t)num_read;
|
||||
next_in = input_buffer;
|
||||
s->legacy_input_len = avail_in;
|
||||
s->legacy_input_pos = 0;
|
||||
} else if (result != BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
|
||||
/* Success or failure. */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Invariant: input stream is never overconsumed:
|
||||
* invalid input implies that the whole stream is invalid -> any amount of
|
||||
input could be read and discarded
|
||||
@ -2030,13 +1960,14 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
|
||||
/* Allocate memory for both block_type_trees and block_len_trees. */
|
||||
s->block_type_trees = (HuffmanCode*)BROTLI_ALLOC(s,
|
||||
6 * BROTLI_HUFFMAN_MAX_TABLE_SIZE * sizeof(HuffmanCode));
|
||||
sizeof(HuffmanCode) * 3 *
|
||||
(BROTLI_HUFFMAN_MAX_SIZE_258 + BROTLI_HUFFMAN_MAX_SIZE_26));
|
||||
if (s->block_type_trees == 0) {
|
||||
result = BROTLI_FAILURE();
|
||||
break;
|
||||
}
|
||||
s->block_len_trees = s->block_type_trees +
|
||||
3 * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
|
||||
3 * BROTLI_HUFFMAN_MAX_SIZE_258;
|
||||
|
||||
s->state = BROTLI_STATE_METABLOCK_BEGIN;
|
||||
/* No break, continue to next state */
|
||||
@ -2069,10 +2000,7 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
break;
|
||||
}
|
||||
if (!s->ringbuffer) {
|
||||
if (!BrotliAllocateRingBuffer(s, br)) {
|
||||
result = BROTLI_FAILURE();
|
||||
break;
|
||||
}
|
||||
BrotliCalculateRingBufferSize(s, br);
|
||||
}
|
||||
if (s->is_uncompressed) {
|
||||
s->state = BROTLI_STATE_UNCOMPRESSED;
|
||||
@ -2124,7 +2052,7 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
s->state = BROTLI_STATE_HUFFMAN_CODE_1;
|
||||
/* No break, continue to next state */
|
||||
case BROTLI_STATE_HUFFMAN_CODE_1: {
|
||||
int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
|
||||
int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_258;
|
||||
result = ReadHuffmanCode(s->num_block_types[s->loop_counter] + 2,
|
||||
&s->block_type_trees[tree_offset], NULL, s);
|
||||
if (result != BROTLI_RESULT_SUCCESS) break;
|
||||
@ -2132,7 +2060,7 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
/* No break, continue to next state */
|
||||
}
|
||||
case BROTLI_STATE_HUFFMAN_CODE_2: {
|
||||
int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
|
||||
int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_26;
|
||||
result = ReadHuffmanCode(kNumBlockLengthCodes,
|
||||
&s->block_len_trees[tree_offset], NULL, s);
|
||||
if (result != BROTLI_RESULT_SUCCESS) break;
|
||||
@ -2140,7 +2068,7 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
/* No break, continue to next state */
|
||||
}
|
||||
case BROTLI_STATE_HUFFMAN_CODE_3: {
|
||||
int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
|
||||
int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_26;
|
||||
if (!SafeReadBlockLength(s, &s->block_length[s->loop_counter],
|
||||
&s->block_len_trees[tree_offset], br)) {
|
||||
result = BROTLI_RESULT_NEEDS_MORE_INPUT;
|
||||
@ -2212,7 +2140,7 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
s->num_literal_htrees);
|
||||
BrotliHuffmanTreeGroupInit(s, &s->insert_copy_hgroup,
|
||||
kNumInsertAndCopyCodes,
|
||||
s->num_block_types[1]);
|
||||
s->num_block_types[1]);
|
||||
BrotliHuffmanTreeGroupInit(s, &s->distance_hgroup, num_distance_codes,
|
||||
s->num_dist_htrees);
|
||||
if (s->literal_hgroup.codes == 0 ||
|
||||
@ -2252,6 +2180,10 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
&kContextLookup[kContextLookupOffsets[context_mode + 1]];
|
||||
s->htree_command = s->insert_copy_hgroup.htrees[0];
|
||||
s->literal_htree = s->literal_hgroup.htrees[s->literal_htree_index];
|
||||
if (!s->ringbuffer && !BrotliAllocateRingBuffer(s)) {
|
||||
result = BROTLI_FAILURE();
|
||||
break;
|
||||
}
|
||||
s->state = BROTLI_STATE_COMMAND_BEGIN;
|
||||
}
|
||||
break;
|
||||
@ -2276,7 +2208,7 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
s->max_distance = s->max_backward_distance;
|
||||
if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_1) {
|
||||
memcpy(s->ringbuffer, s->ringbuffer_end, (size_t)s->pos);
|
||||
if (s->meta_block_remaining_len <= 0) {
|
||||
if (s->meta_block_remaining_len == 0) {
|
||||
/* Next metablock, if any */
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
} else {
|
||||
@ -2287,7 +2219,7 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
s->state = BROTLI_STATE_COMMAND_POST_WRAP_COPY;
|
||||
} else { /* BROTLI_STATE_COMMAND_INNER_WRITE */
|
||||
if (s->loop_counter == 0) {
|
||||
if (s->meta_block_remaining_len <= 0) {
|
||||
if (s->meta_block_remaining_len == 0) {
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
} else {
|
||||
s->state = BROTLI_STATE_COMMAND_POST_DECODE_LITERALS;
|
||||
|
132
dec/decode.h
132
dec/decode.h
@ -10,7 +10,6 @@
|
||||
#define BROTLI_DEC_DECODE_H_
|
||||
|
||||
#include "./state.h"
|
||||
#include "./streams.h"
|
||||
#include "./types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
@ -18,126 +17,57 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
/* Decoding error, e.g. corrupt input or no memory */
|
||||
/* Decoding error, e.g. corrupt input or memory allocation problem */
|
||||
BROTLI_RESULT_ERROR = 0,
|
||||
/* Successfully completely done */
|
||||
/* Decoding successfully completed */
|
||||
BROTLI_RESULT_SUCCESS = 1,
|
||||
/* Partially done, but must be called again with more input */
|
||||
/* Partially done; should be called again with more input */
|
||||
BROTLI_RESULT_NEEDS_MORE_INPUT = 2,
|
||||
/* Partially done, but must be called again with more output */
|
||||
/* Partially done; should be called again with more output */
|
||||
BROTLI_RESULT_NEEDS_MORE_OUTPUT = 3
|
||||
} BrotliResult;
|
||||
|
||||
/* BROTLI_FAILURE macro unwraps to BROTLI_RESULT_ERROR in non-debug build. */
|
||||
/* In debug build it dumps file name, line and pretty function name. */
|
||||
#if defined(_MSC_VER) || !defined(BROTLI_DEBUG)
|
||||
#define BROTLI_FAILURE() BROTLI_RESULT_ERROR
|
||||
#else
|
||||
#define BROTLI_FAILURE() \
|
||||
BrotliFailure(__FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
static inline BrotliResult BrotliFailure(const char *f, int l, const char *fn) {
|
||||
fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn);
|
||||
fflush(stderr);
|
||||
return BROTLI_RESULT_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Creates the instance of BrotliState and initializes it. alloc_func and
|
||||
free_func MUST be both zero or both non-zero. In the case they are both zero,
|
||||
default memory allocators are used. opaque parameter is passed to alloc_func
|
||||
and free_func when they are called. */
|
||||
/* Creates the instance of BrotliState and initializes it. |alloc_func| and
|
||||
|free_func| MUST be both zero or both non-zero. In the case they are both
|
||||
zero, default memory allocators are used. |opaque| is passed to |alloc_func|
|
||||
and |free_func| when they are called. */
|
||||
BrotliState* BrotliCreateState(
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
|
||||
|
||||
/* Deinitializes and frees BrotliState instance. */
|
||||
void BrotliDestroyState(BrotliState* state);
|
||||
|
||||
/* Sets *decoded_size to the decompressed size of the given encoded stream. */
|
||||
/* This function only works if the encoded buffer has a single meta block, */
|
||||
/* or if it has two meta-blocks, where the first is uncompressed and the */
|
||||
/* second is empty. */
|
||||
/* Returns 1 on success, 0 on failure. */
|
||||
/* Sets |*decoded_size| to the decompressed size of the given encoded stream.
|
||||
This function only works if the encoded buffer has a single meta block,
|
||||
or if it has two meta-blocks, where the first is uncompressed and the
|
||||
second is empty.
|
||||
Returns 1 on success, 0 on failure. */
|
||||
int BrotliDecompressedSize(size_t encoded_size,
|
||||
const uint8_t* encoded_buffer,
|
||||
size_t* decoded_size);
|
||||
|
||||
/* Decompresses the data in encoded_buffer into decoded_buffer, and sets */
|
||||
/* *decoded_size to the decompressed length. */
|
||||
/* Decompresses the data in |encoded_buffer| into |decoded_buffer|, and sets
|
||||
|*decoded_size| to the decompressed length. */
|
||||
BrotliResult BrotliDecompressBuffer(size_t encoded_size,
|
||||
const uint8_t* encoded_buffer,
|
||||
size_t* decoded_size,
|
||||
uint8_t* decoded_buffer);
|
||||
|
||||
/* Same as above, but uses the specified input and output callbacks instead */
|
||||
/* of reading from and writing to pre-allocated memory buffers. */
|
||||
/* DEPRECATED */
|
||||
BrotliResult BrotliDecompress(BrotliInput input, BrotliOutput output);
|
||||
/* Decompresses the data. Supports partial input and output.
|
||||
|
||||
/* Same as above, but supports the caller to call the decoder repeatedly with
|
||||
partial data to support streaming. The state must be initialized with
|
||||
BrotliStateInit and reused with every call for the same stream.
|
||||
Return values:
|
||||
0: failure.
|
||||
1: success, and done.
|
||||
2: success so far, end not reached so should call again with more input.
|
||||
The finish parameter is used as follows, for a series of calls with the
|
||||
same state:
|
||||
0: Every call except the last one must be called with finish set to 0. The
|
||||
last call may have finish set to either 0 or 1. Only if finish is 0, can
|
||||
the function return 2. It may also return 0 or 1, in that case no more
|
||||
calls (even with finish 1) may be made.
|
||||
1: Only the last call may have finish set to 1. It's ok to give empty input
|
||||
if all input was already given to previous calls. It is also ok to have
|
||||
only one single call in total, with finish 1, and with all input
|
||||
available immediately. That matches the non-streaming case. If finish is
|
||||
1, the function can only return 0 or 1, never 2. After a finish, no more
|
||||
calls may be done.
|
||||
After everything is done, the state must be cleaned with BrotliStateCleanup
|
||||
to free allocated resources.
|
||||
The given BrotliOutput must always accept all output and make enough space,
|
||||
it returning a smaller value than the amount of bytes to write always results
|
||||
in an error.
|
||||
*/
|
||||
/* DEPRECATED */
|
||||
BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
|
||||
int finish, BrotliState* s);
|
||||
Must be called with an allocated input buffer in |*next_in| and an allocated
|
||||
output buffer in |*next_out|. The values |*available_in| and |*available_out|
|
||||
must specify the allocated size in |*next_in| and |*next_out| respectively.
|
||||
|
||||
/* Same as above, but with memory buffers.
|
||||
Must be called with an allocated input buffer in *next_in and an allocated
|
||||
output buffer in *next_out. The values *available_in and *available_out
|
||||
must specify the allocated size in *next_in and *next_out respectively.
|
||||
The value *total_out must be 0 initially, and will be summed with the
|
||||
amount of output bytes written after each call, so that at the end it
|
||||
gives the complete decoded size.
|
||||
After each call, *available_in will be decremented by the amount of input
|
||||
bytes consumed, and the *next_in pointer will be incremented by that amount.
|
||||
Similarly, *available_out will be decremented by the amount of output
|
||||
bytes written, and the *next_out pointer will be incremented by that
|
||||
amount.
|
||||
|
||||
The input may be partial. With each next function call, *next_in and
|
||||
*available_in must be updated to point to a next part of the compressed
|
||||
input. The current implementation will always consume all input unless
|
||||
an error occurs, so normally *available_in will always be 0 after
|
||||
calling this function and the next adjacent part of input is desired.
|
||||
|
||||
In the current implementation, the function requires that there is enough
|
||||
output buffer size to write all currently processed input, so
|
||||
*available_out must be large enough. Since the function updates *next_out
|
||||
each time, as long as the output buffer is large enough you can keep
|
||||
reusing this variable. It is also possible to update *next_out and
|
||||
*available_out yourself before a next call, e.g. to point to a new larger
|
||||
buffer.
|
||||
*/
|
||||
/* DEPRECATED */
|
||||
BrotliResult BrotliDecompressBufferStreaming(size_t* available_in,
|
||||
const uint8_t** next_in,
|
||||
int finish,
|
||||
size_t* available_out,
|
||||
uint8_t** next_out,
|
||||
size_t* total_out,
|
||||
BrotliState* s);
|
||||
After each call, |*available_in| will be decremented by the amount of input
|
||||
bytes consumed, and the |*next_in| pointer will be incremented by that
|
||||
amount. Similarly, |*available_out| will be decremented by the amount of
|
||||
output bytes written, and the |*next_out| pointer will be incremented by that
|
||||
amount. |total_out| will be set to the number of bytes decompressed since
|
||||
last state initialization.
|
||||
|
||||
Input is never overconsumed, so |next_in| and |available_in| could be passed
|
||||
to the next consumer after decoding is complete. */
|
||||
BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
const uint8_t** next_in,
|
||||
size_t* available_out,
|
||||
@ -150,10 +80,10 @@ BrotliResult BrotliDecompressStream(size_t* available_in,
|
||||
Not to be confused with the built-in transformable dictionary of Brotli.
|
||||
The dictionary must exist in memory until decoding is done and is owned by
|
||||
the caller. To use:
|
||||
-initialize state with BrotliStateInit
|
||||
-use BrotliSetCustomDictionary
|
||||
-use BrotliDecompressBufferStreaming
|
||||
-clean up with BrotliStateCleanup
|
||||
1) initialize state with BrotliStateInit
|
||||
2) use BrotliSetCustomDictionary
|
||||
3) use BrotliDecompressStream
|
||||
4) clean up with BrotliStateCleanup
|
||||
*/
|
||||
void BrotliSetCustomDictionary(
|
||||
size_t size, const uint8_t* dict, BrotliState* s);
|
||||
|
@ -17,7 +17,7 @@ extern "C" {
|
||||
|
||||
extern const uint8_t kBrotliDictionary[122784];
|
||||
|
||||
static const int kBrotliDictionaryOffsetsByLength[] = {
|
||||
static const uint32_t kBrotliDictionaryOffsetsByLength[] = {
|
||||
0, 0, 0, 0, 0, 4096, 9216, 21504, 35840, 44032,
|
||||
53248, 63488, 74752, 87040, 93696, 100864, 104704, 106752, 108928, 113536,
|
||||
115968, 118528, 119872, 121280, 122016,
|
||||
|
@ -6,11 +6,12 @@
|
||||
|
||||
/* Utilities for building Huffman decoding tables. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "./huffman.h"
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
|
||||
#include "./port.h"
|
||||
#include "./types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@ -237,7 +238,7 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
for (len = root_bits + 1, step = 2; len <= max_length; ++len) {
|
||||
symbol = len - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
|
||||
for (; count[len] != 0; --count[len]) {
|
||||
if (sub_key == (uint32_t)(BROTLI_REVERSE_BITS_LOWEST << 1)) {
|
||||
if (sub_key == (BROTLI_REVERSE_BITS_LOWEST << 1U)) {
|
||||
table += table_size;
|
||||
table_bits = NextTableBitSize(count, len, root_bits);
|
||||
table_size = 1 << table_bits;
|
||||
|
@ -20,9 +20,14 @@ extern "C" {
|
||||
/* For current format this constant equals to kNumInsertAndCopyCodes */
|
||||
#define BROTLI_HUFFMAN_MAX_CODE_LENGTHS_SIZE 704
|
||||
|
||||
/* Maximum possible Huffman table size for an alphabet size of 704, max code
|
||||
* length 15 and root table bits 8. */
|
||||
#define BROTLI_HUFFMAN_MAX_TABLE_SIZE 1080
|
||||
/* Maximum possible Huffman table size for an alphabet size of (index * 32),
|
||||
* max code length 15 and root table bits 8. */
|
||||
static const uint16_t kMaxHuffmanTableSize[] = {
|
||||
256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822,
|
||||
854, 886, 920, 952, 984, 1016, 1048, 1080};
|
||||
#define BROTLI_HUFFMAN_MAX_SIZE_26 396
|
||||
#define BROTLI_HUFFMAN_MAX_SIZE_258 632
|
||||
#define BROTLI_HUFFMAN_MAX_SIZE_272 646
|
||||
|
||||
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH 5
|
||||
|
||||
|
@ -11,6 +11,8 @@
|
||||
#ifndef BROTLI_DEC_PREFIX_H_
|
||||
#define BROTLI_DEC_PREFIX_H_
|
||||
|
||||
#include "./types.h"
|
||||
|
||||
/* Represents the range of values belonging to a prefix code: */
|
||||
/* [offset, offset + 2^nbits) */
|
||||
struct PrefixCodeRange {
|
||||
|
22
dec/state.c
22
dec/state.c
@ -4,11 +4,12 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./huffman.h"
|
||||
#include "./state.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h> /* free, malloc */
|
||||
|
||||
#include "./huffman.h"
|
||||
#include "./types.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@ -94,13 +95,6 @@ void BrotliStateInitWithCustomAllocators(BrotliState* s,
|
||||
s->symbol_lists = &s->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
|
||||
|
||||
s->mtf_upper_bound = 255;
|
||||
|
||||
s->legacy_input_buffer = 0;
|
||||
s->legacy_output_buffer = 0;
|
||||
s->legacy_input_len = 0;
|
||||
s->legacy_output_len = 0;
|
||||
s->legacy_input_pos = 0;
|
||||
s->legacy_output_pos = 0;
|
||||
}
|
||||
|
||||
void BrotliStateMetablockBegin(BrotliState* s) {
|
||||
@ -150,8 +144,6 @@ void BrotliStateCleanup(BrotliState* s) {
|
||||
|
||||
BROTLI_FREE(s, s->ringbuffer);
|
||||
BROTLI_FREE(s, s->block_type_trees);
|
||||
BROTLI_FREE(s, s->legacy_input_buffer);
|
||||
BROTLI_FREE(s, s->legacy_output_buffer);
|
||||
}
|
||||
|
||||
int BrotliStateIsStreamStart(const BrotliState* s) {
|
||||
@ -166,9 +158,9 @@ int BrotliStateIsStreamEnd(const BrotliState* s) {
|
||||
void BrotliHuffmanTreeGroupInit(BrotliState* s, HuffmanTreeGroup* group,
|
||||
uint32_t alphabet_size, uint32_t ntrees) {
|
||||
/* Pack two allocations into one */
|
||||
const size_t code_size =
|
||||
sizeof(HuffmanCode) * (size_t)(ntrees * BROTLI_HUFFMAN_MAX_TABLE_SIZE);
|
||||
const size_t htree_size = sizeof(HuffmanCode*) * (size_t)ntrees;
|
||||
const size_t max_table_size = kMaxHuffmanTableSize[(alphabet_size + 31) >> 5];
|
||||
const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size;
|
||||
const size_t htree_size = sizeof(HuffmanCode*) * ntrees;
|
||||
char *p = (char*)BROTLI_ALLOC(s, code_size + htree_size);
|
||||
group->alphabet_size = (uint16_t)alphabet_size;
|
||||
group->num_htrees = (uint16_t)ntrees;
|
||||
|
16
dec/state.h
16
dec/state.h
@ -9,7 +9,6 @@
|
||||
#ifndef BROTLI_DEC_STATE_H_
|
||||
#define BROTLI_DEC_STATE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include "./bit_reader.h"
|
||||
#include "./huffman.h"
|
||||
#include "./types.h"
|
||||
@ -95,6 +94,10 @@ typedef enum {
|
||||
|
||||
struct BrotliStateStruct {
|
||||
BrotliRunningState state;
|
||||
|
||||
/* This counter is reused for several disjoint loops. */
|
||||
int loop_counter;
|
||||
|
||||
BrotliBitReader br;
|
||||
|
||||
brotli_alloc_func alloc_func;
|
||||
@ -108,8 +111,6 @@ struct BrotliStateStruct {
|
||||
} buffer;
|
||||
uint32_t buffer_length;
|
||||
|
||||
/* This counter is reused for several disjoint loops. */
|
||||
int loop_counter;
|
||||
int pos;
|
||||
int max_backward_distance;
|
||||
int max_backward_distance_minus_custom_dict_size;
|
||||
@ -188,7 +189,7 @@ struct BrotliStateStruct {
|
||||
uint32_t context_index;
|
||||
uint32_t max_run_length_prefix;
|
||||
uint32_t code;
|
||||
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_TABLE_SIZE];
|
||||
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
|
||||
|
||||
/* For InverseMoveToFrontTransform */
|
||||
uint32_t mtf_upper_bound;
|
||||
@ -217,13 +218,6 @@ struct BrotliStateStruct {
|
||||
uint32_t num_literal_htrees;
|
||||
uint8_t* context_map;
|
||||
uint8_t* context_modes;
|
||||
|
||||
uint8_t* legacy_input_buffer;
|
||||
uint8_t* legacy_output_buffer;
|
||||
size_t legacy_input_len;
|
||||
size_t legacy_output_len;
|
||||
size_t legacy_input_pos;
|
||||
size_t legacy_output_pos;
|
||||
};
|
||||
|
||||
typedef struct BrotliStateStruct BrotliState;
|
||||
|
@ -9,8 +9,6 @@
|
||||
#ifndef BROTLI_DEC_TRANSFORM_H_
|
||||
#define BROTLI_DEC_TRANSFORM_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "./port.h"
|
||||
#include "./types.h"
|
||||
|
||||
@ -269,22 +267,19 @@ static BROTLI_NOINLINE int TransformDictionaryWord(
|
||||
}
|
||||
{
|
||||
const int t = kTransforms[transform].transform;
|
||||
int skip = t < kOmitFirst1 ? 0 : t - (kOmitFirst1 - 1);
|
||||
int i = 0;
|
||||
uint8_t* uppercase;
|
||||
if (skip > len) {
|
||||
skip = len;
|
||||
}
|
||||
word += skip;
|
||||
len -= skip;
|
||||
if (t <= kOmitLast9) {
|
||||
int skip = t - (kOmitFirst1 - 1);
|
||||
if (skip > 0) {
|
||||
word += skip;
|
||||
len -= skip;
|
||||
} else if (t <= kOmitLast9) {
|
||||
len -= t;
|
||||
}
|
||||
while (i < len) { dst[idx++] = word[i++]; }
|
||||
uppercase = &dst[idx - len];
|
||||
if (t == kUppercaseFirst) {
|
||||
ToUpperCase(uppercase);
|
||||
ToUpperCase(&dst[idx - len]);
|
||||
} else if (t == kUppercaseAll) {
|
||||
uint8_t* uppercase = &dst[idx - len];
|
||||
while (len > 0) {
|
||||
int step = ToUpperCase(uppercase);
|
||||
uppercase += step;
|
||||
|
Loading…
Reference in New Issue
Block a user