#622: update brotli to 1.0.9, woff2 to tip
This commit is contained in:
parent
cbcbd24be8
commit
7c24b77e7b
|
@ -1,9 +1,6 @@
|
||||||
This is the Brotli data compression library from
|
This is the Brotli data compression library from
|
||||||
https://github.com/google/brotli.
|
https://github.com/google/brotli.
|
||||||
|
|
||||||
Currently, we import only the Brotli decoder (the /dec/ subdirectory), not the
|
|
||||||
encoder (/enc/ subdirectory).
|
|
||||||
|
|
||||||
Upstream code can be viewed at
|
Upstream code can be viewed at
|
||||||
https://github.com/google/brotli/tree/master/dec
|
https://github.com/google/brotli/tree/master/dec
|
||||||
|
|
||||||
|
@ -14,4 +11,4 @@ The in-tree copy is updated by running
|
||||||
sh update.sh
|
sh update.sh
|
||||||
from within the modules/brotli directory.
|
from within the modules/brotli directory.
|
||||||
|
|
||||||
Current version: [commit 5b4769990dc14a2bd466d2599c946c5652cba4b2].
|
Current version: [commit e61745a6b7add50d380cfd7d3883dd6c62fc2c71].
|
||||||
|
|
|
@ -4,9 +4,18 @@
|
||||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Common constants used in decoder and encoder API.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef BROTLI_COMMON_CONSTANTS_H_
|
#ifndef BROTLI_COMMON_CONSTANTS_H_
|
||||||
#define BROTLI_COMMON_CONSTANTS_H_
|
#define BROTLI_COMMON_CONSTANTS_H_
|
||||||
|
|
||||||
|
#include "./platform.h"
|
||||||
|
#include <brotli/port.h>
|
||||||
|
#include <brotli/types.h>
|
||||||
|
|
||||||
/* Specification: 7.3. Encoding of the context map */
|
/* Specification: 7.3. Encoding of the context map */
|
||||||
#define BROTLI_CONTEXT_MAP_MAX_RLE 16
|
#define BROTLI_CONTEXT_MAP_MAX_RLE 16
|
||||||
|
|
||||||
|
@ -28,19 +37,58 @@
|
||||||
/* "code length of 8 is repeated" */
|
/* "code length of 8 is repeated" */
|
||||||
#define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8
|
#define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8
|
||||||
|
|
||||||
|
/* "Large Window Brotli" */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The theoretical maximum number of distance bits specified for large window
|
||||||
|
* brotli, for 64-bit encoders and decoders. Even when in practice 32-bit
|
||||||
|
* encoders and decoders only support up to 30 max distance bits, the value is
|
||||||
|
* set to 62 because it affects the large window brotli file format.
|
||||||
|
* Specifically, it affects the encoding of simple huffman tree for distances,
|
||||||
|
* see Specification RFC 7932 chapter 3.4.
|
||||||
|
*/
|
||||||
|
#define BROTLI_LARGE_MAX_DISTANCE_BITS 62U
|
||||||
|
#define BROTLI_LARGE_MIN_WBITS 10
|
||||||
|
/**
|
||||||
|
* The maximum supported large brotli window bits by the encoder and decoder.
|
||||||
|
* Large window brotli allows up to 62 bits, however the current encoder and
|
||||||
|
* decoder, designed for 32-bit integers, only support up to 30 bits maximum.
|
||||||
|
*/
|
||||||
|
#define BROTLI_LARGE_MAX_WBITS 30
|
||||||
|
|
||||||
/* Specification: 4. Encoding of distances */
|
/* Specification: 4. Encoding of distances */
|
||||||
#define BROTLI_NUM_DISTANCE_SHORT_CODES 16
|
#define BROTLI_NUM_DISTANCE_SHORT_CODES 16
|
||||||
|
/**
|
||||||
|
* Maximal number of "postfix" bits.
|
||||||
|
*
|
||||||
|
* Number of "postfix" bits is stored as 2 bits in meta-block header.
|
||||||
|
*/
|
||||||
#define BROTLI_MAX_NPOSTFIX 3
|
#define BROTLI_MAX_NPOSTFIX 3
|
||||||
#define BROTLI_MAX_NDIRECT 120
|
#define BROTLI_MAX_NDIRECT 120
|
||||||
#define BROTLI_MAX_DISTANCE_BITS 24U
|
#define BROTLI_MAX_DISTANCE_BITS 24U
|
||||||
/* BROTLI_NUM_DISTANCE_SYMBOLS == 520 */
|
#define BROTLI_DISTANCE_ALPHABET_SIZE(NPOSTFIX, NDIRECT, MAXNBITS) ( \
|
||||||
#define BROTLI_NUM_DISTANCE_SYMBOLS (BROTLI_NUM_DISTANCE_SHORT_CODES + \
|
BROTLI_NUM_DISTANCE_SHORT_CODES + (NDIRECT) + \
|
||||||
BROTLI_MAX_NDIRECT + \
|
((MAXNBITS) << ((NPOSTFIX) + 1)))
|
||||||
(BROTLI_MAX_DISTANCE_BITS << \
|
/* BROTLI_NUM_DISTANCE_SYMBOLS == 1128 */
|
||||||
(BROTLI_MAX_NPOSTFIX + 1)))
|
#define BROTLI_NUM_DISTANCE_SYMBOLS \
|
||||||
/* Distance that is guaranteed to be representable in any stream. */
|
BROTLI_DISTANCE_ALPHABET_SIZE( \
|
||||||
|
BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS)
|
||||||
|
|
||||||
|
/* ((1 << 26) - 4) is the maximal distance that can be expressed in RFC 7932
|
||||||
|
brotli stream using NPOSTFIX = 0 and NDIRECT = 0. With other NPOSTFIX and
|
||||||
|
NDIRECT values distances up to ((1 << 29) + 88) could be expressed. */
|
||||||
#define BROTLI_MAX_DISTANCE 0x3FFFFFC
|
#define BROTLI_MAX_DISTANCE 0x3FFFFFC
|
||||||
|
|
||||||
|
/* ((1 << 31) - 4) is the safe distance limit. Using this number as a limit
|
||||||
|
allows safe distance calculation without overflows, given the distance
|
||||||
|
alphabet size is limited to corresponding size
|
||||||
|
(see kLargeWindowDistanceCodeLimits). */
|
||||||
|
#define BROTLI_MAX_ALLOWED_DISTANCE 0x7FFFFFFC
|
||||||
|
|
||||||
|
|
||||||
|
/* Specification: 4. Encoding of Literal Insertion Lengths and Copy Lengths */
|
||||||
|
#define BROTLI_NUM_INS_COPY_CODES 24
|
||||||
|
|
||||||
/* 7.1. Context modes and context ID lookup for literals */
|
/* 7.1. Context modes and context ID lookup for literals */
|
||||||
/* "context IDs for literals are in the range of 0..63" */
|
/* "context IDs for literals are in the range of 0..63" */
|
||||||
#define BROTLI_LITERAL_CONTEXT_BITS 6
|
#define BROTLI_LITERAL_CONTEXT_BITS 6
|
||||||
|
@ -54,4 +102,99 @@
|
||||||
#define BROTLI_WINDOW_GAP 16
|
#define BROTLI_WINDOW_GAP 16
|
||||||
#define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP)
|
#define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP)
|
||||||
|
|
||||||
|
typedef struct BrotliDistanceCodeLimit {
|
||||||
|
uint32_t max_alphabet_size;
|
||||||
|
uint32_t max_distance;
|
||||||
|
} BrotliDistanceCodeLimit;
|
||||||
|
|
||||||
|
/* This function calculates maximal size of distance alphabet, such that the
|
||||||
|
distances greater than the given values can not be represented.
|
||||||
|
|
||||||
|
This limits are designed to support fast and safe 32-bit decoders.
|
||||||
|
"32-bit" means that signed integer values up to ((1 << 31) - 1) could be
|
||||||
|
safely expressed.
|
||||||
|
|
||||||
|
Brotli distance alphabet symbols do not represent consecutive distance
|
||||||
|
ranges. Each distance alphabet symbol (excluding direct distances and short
|
||||||
|
codes), represent interleaved (for NPOSTFIX > 0) range of distances.
|
||||||
|
A "group" of consecutive (1 << NPOSTFIX) symbols represent non-interleaved
|
||||||
|
range. Two consecutive groups require the same amount of "extra bits".
|
||||||
|
|
||||||
|
It is important that distance alphabet represents complete "groups".
|
||||||
|
To avoid complex logic on encoder side about interleaved ranges
|
||||||
|
it was decided to restrict both sides to complete distance code "groups".
|
||||||
|
*/
|
||||||
|
BROTLI_UNUSED_FUNCTION BrotliDistanceCodeLimit BrotliCalculateDistanceCodeLimit(
|
||||||
|
uint32_t max_distance, uint32_t npostfix, uint32_t ndirect) {
|
||||||
|
BrotliDistanceCodeLimit result;
|
||||||
|
/* Marking this function as unused, because not all files
|
||||||
|
including "constants.h" use it -> compiler warns about that. */
|
||||||
|
BROTLI_UNUSED(&BrotliCalculateDistanceCodeLimit);
|
||||||
|
if (max_distance <= ndirect) {
|
||||||
|
/* This case never happens / exists only for the sake of completeness. */
|
||||||
|
result.max_alphabet_size = max_distance + BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||||
|
result.max_distance = max_distance;
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
/* The first prohibited value. */
|
||||||
|
uint32_t forbidden_distance = max_distance + 1;
|
||||||
|
/* Subtract "directly" encoded region. */
|
||||||
|
uint32_t offset = forbidden_distance - ndirect - 1;
|
||||||
|
uint32_t ndistbits = 0;
|
||||||
|
uint32_t tmp;
|
||||||
|
uint32_t half;
|
||||||
|
uint32_t group;
|
||||||
|
/* Postfix for the last dcode in the group. */
|
||||||
|
uint32_t postfix = (1u << npostfix) - 1;
|
||||||
|
uint32_t extra;
|
||||||
|
uint32_t start;
|
||||||
|
/* Remove postfix and "head-start". */
|
||||||
|
offset = (offset >> npostfix) + 4;
|
||||||
|
/* Calculate the number of distance bits. */
|
||||||
|
tmp = offset / 2;
|
||||||
|
/* Poor-man's log2floor, to avoid extra dependencies. */
|
||||||
|
while (tmp != 0) {ndistbits++; tmp = tmp >> 1;}
|
||||||
|
/* One bit is covered with subrange addressing ("half"). */
|
||||||
|
ndistbits--;
|
||||||
|
/* Find subrange. */
|
||||||
|
half = (offset >> ndistbits) & 1;
|
||||||
|
/* Calculate the "group" part of dcode. */
|
||||||
|
group = ((ndistbits - 1) << 1) | half;
|
||||||
|
/* Calculated "group" covers the prohibited distance value. */
|
||||||
|
if (group == 0) {
|
||||||
|
/* This case is added for correctness; does not occur for limit > 128. */
|
||||||
|
result.max_alphabet_size = ndirect + BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||||
|
result.max_distance = ndirect;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/* Decrement "group", so it is the last permitted "group". */
|
||||||
|
group--;
|
||||||
|
/* After group was decremented, ndistbits and half must be recalculated. */
|
||||||
|
ndistbits = (group >> 1) + 1;
|
||||||
|
/* The last available distance in the subrange has all extra bits set. */
|
||||||
|
extra = (1u << ndistbits) - 1;
|
||||||
|
/* Calculate region start. NB: ndistbits >= 1. */
|
||||||
|
start = (1u << (ndistbits + 1)) - 4;
|
||||||
|
/* Move to subregion. */
|
||||||
|
start += (group & 1) << ndistbits;
|
||||||
|
/* Calculate the alphabet size. */
|
||||||
|
result.max_alphabet_size = ((group << npostfix) | postfix) + ndirect +
|
||||||
|
BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
|
||||||
|
/* Calculate the maximal distance representable by alphabet. */
|
||||||
|
result.max_distance = ((start + extra) << npostfix) + postfix + ndirect + 1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Represents the range of values belonging to a prefix code:
|
||||||
|
[offset, offset + 2^nbits) */
|
||||||
|
typedef struct {
|
||||||
|
uint16_t offset;
|
||||||
|
uint8_t nbits;
|
||||||
|
} BrotliPrefixCodeRange;
|
||||||
|
|
||||||
|
/* "Soft-private", it is exported, but not "advertised" as API. */
|
||||||
|
BROTLI_COMMON_API extern const BrotliPrefixCodeRange
|
||||||
|
_kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
|
||||||
|
|
||||||
#endif /* BROTLI_COMMON_CONSTANTS_H_ */
|
#endif /* BROTLI_COMMON_CONSTANTS_H_ */
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "./dictionary.h"
|
#include "./dictionary.h"
|
||||||
|
#include "./platform.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BROTLI_EXTERNAL_DICTIONARY_DATA
|
#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||||
static const uint8_t kBrotliDictionaryData[] =
|
static const uint8_t kBrotliDictionaryData[] =
|
||||||
{
|
{
|
||||||
116,105,109,101,100,111,119,110,108,105,102,101,108,101,102,116,98,97,99,107,99,
|
116,105,109,101,100,111,119,110,108,105,102,101,108,101,102,116,98,97,99,107,99,
|
||||||
|
@ -5862,7 +5863,11 @@ static const uint8_t kBrotliDictionaryData[] =
|
||||||
;
|
;
|
||||||
#endif /* !BROTLI_EXTERNAL_DICTIONARY_DATA */
|
#endif /* !BROTLI_EXTERNAL_DICTIONARY_DATA */
|
||||||
|
|
||||||
|
#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||||
|
static const BrotliDictionary kBrotliDictionary = {
|
||||||
|
#else
|
||||||
static BrotliDictionary kBrotliDictionary = {
|
static BrotliDictionary kBrotliDictionary = {
|
||||||
|
#endif
|
||||||
/* size_bits_by_length */
|
/* size_bits_by_length */
|
||||||
{
|
{
|
||||||
0, 0, 0, 0, 10, 10, 11, 11,
|
0, 0, 0, 0, 10, 10, 11, 11,
|
||||||
|
@ -5883,7 +5888,7 @@ static BrotliDictionary kBrotliDictionary = {
|
||||||
122784,
|
122784,
|
||||||
|
|
||||||
/* data */
|
/* data */
|
||||||
#ifdef BROTLI_EXTERNAL_DICTIONARY_DATA
|
#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||||
NULL
|
NULL
|
||||||
#else
|
#else
|
||||||
kBrotliDictionaryData
|
kBrotliDictionaryData
|
||||||
|
@ -5895,9 +5900,13 @@ const BrotliDictionary* BrotliGetDictionary() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliSetDictionaryData(const uint8_t* data) {
|
void BrotliSetDictionaryData(const uint8_t* data) {
|
||||||
|
#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||||
if (!!data && !kBrotliDictionary.data) {
|
if (!!data && !kBrotliDictionary.data) {
|
||||||
kBrotliDictionary.data = data;
|
kBrotliDictionary.data = data;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
BROTLI_UNUSED(data); // Appease -Werror=unused-parameter
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
|
|
@ -27,13 +27,13 @@ typedef struct BrotliDictionary {
|
||||||
* Dictionary consists of words with length of [4..24] bytes.
|
* Dictionary consists of words with length of [4..24] bytes.
|
||||||
* Values at [0..3] and [25..31] indices should not be addressed.
|
* Values at [0..3] and [25..31] indices should not be addressed.
|
||||||
*/
|
*/
|
||||||
const uint8_t size_bits_by_length[32];
|
uint8_t size_bits_by_length[32];
|
||||||
|
|
||||||
/* assert(offset[i + 1] == offset[i] + (bits[i] ? (i << bits[i]) : 0)) */
|
/* assert(offset[i + 1] == offset[i] + (bits[i] ? (i << bits[i]) : 0)) */
|
||||||
const uint32_t offsets_by_length[32];
|
uint32_t offsets_by_length[32];
|
||||||
|
|
||||||
/* assert(data_size == offsets_by_length[31]) */
|
/* assert(data_size == offsets_by_length[31]) */
|
||||||
const size_t data_size;
|
size_t data_size;
|
||||||
|
|
||||||
/* Data array is not bound, and should obey to size_bits_by_length values.
|
/* Data array is not bound, and should obey to size_bits_by_length values.
|
||||||
Specified size matches default (RFC 7932) dictionary. Its size is
|
Specified size matches default (RFC 7932) dictionary. Its size is
|
||||||
|
@ -41,7 +41,7 @@ typedef struct BrotliDictionary {
|
||||||
const uint8_t* data;
|
const uint8_t* data;
|
||||||
} BrotliDictionary;
|
} BrotliDictionary;
|
||||||
|
|
||||||
BROTLI_COMMON_API extern const BrotliDictionary* BrotliGetDictionary(void);
|
BROTLI_COMMON_API const BrotliDictionary* BrotliGetDictionary(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets dictionary data.
|
* Sets dictionary data.
|
||||||
|
|
|
@ -14,6 +14,13 @@
|
||||||
BrotliEncoderVersion methods. */
|
BrotliEncoderVersion methods. */
|
||||||
|
|
||||||
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
|
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
|
||||||
#define BROTLI_VERSION 0x1000001
|
#define BROTLI_VERSION 0x1000009
|
||||||
|
|
||||||
|
/* This macro is used by build system to produce Libtool-friendly soname. See
|
||||||
|
https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */
|
||||||
|
#define BROTLI_ABI_VERSION 0x1009000
|
||||||
|
|
||||||
#endif /* BROTLI_COMMON_VERSION_H_ */
|
#endif /* BROTLI_COMMON_VERSION_H_ */
|
||||||
|
|
|
@ -8,13 +8,24 @@
|
||||||
|
|
||||||
#include "./bit_reader.h"
|
#include "./bit_reader.h"
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const uint32_t kBrotliBitMask[33] = { 0x00000000,
|
||||||
|
0x00000001, 0x00000003, 0x00000007, 0x0000000F,
|
||||||
|
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
|
||||||
|
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
|
||||||
|
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
|
||||||
|
0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
|
||||||
|
0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
|
||||||
|
0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
|
||||||
|
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
void BrotliInitBitReader(BrotliBitReader* const br) {
|
void BrotliInitBitReader(BrotliBitReader* const br) {
|
||||||
br->val_ = 0;
|
br->val_ = 0;
|
||||||
br->bit_pos_ = sizeof(br->val_) << 3;
|
br->bit_pos_ = sizeof(br->val_) << 3;
|
||||||
|
@ -43,6 +54,23 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
|
||||||
return BROTLI_TRUE;
|
return BROTLI_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* const br,
|
||||||
|
uint32_t n_bits, uint32_t* val) {
|
||||||
|
uint32_t low_val;
|
||||||
|
uint32_t high_val;
|
||||||
|
BrotliBitReaderState memento;
|
||||||
|
BROTLI_DCHECK(n_bits <= 32);
|
||||||
|
BROTLI_DCHECK(n_bits > 24);
|
||||||
|
BrotliBitReaderSaveState(br, &memento);
|
||||||
|
if (!BrotliSafeReadBits(br, 16, &low_val) ||
|
||||||
|
!BrotliSafeReadBits(br, n_bits - 16, &high_val)) {
|
||||||
|
BrotliBitReaderRestoreState(br, &memento);
|
||||||
|
return BROTLI_FALSE;
|
||||||
|
}
|
||||||
|
*val = low_val | (high_val << 16);
|
||||||
|
return BROTLI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,45 +11,37 @@
|
||||||
|
|
||||||
#include <string.h> /* memcpy */
|
#include <string.h> /* memcpy */
|
||||||
|
|
||||||
|
#include "../common/constants.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(reg_t) >> 1)
|
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1)
|
||||||
|
|
||||||
static const uint32_t kBitMask[33] = { 0x0000,
|
BROTLI_INTERNAL extern const uint32_t kBrotliBitMask[33];
|
||||||
0x00000001, 0x00000003, 0x00000007, 0x0000000F,
|
|
||||||
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
|
|
||||||
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
|
|
||||||
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
|
|
||||||
0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
|
|
||||||
0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
|
|
||||||
0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
|
|
||||||
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
|
|
||||||
};
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
|
static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
|
||||||
if (IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
|
if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
|
||||||
/* Masking with this expression turns to a single
|
/* Masking with this expression turns to a single
|
||||||
"Unsigned Bit Field Extract" UBFX instruction on ARM. */
|
"Unsigned Bit Field Extract" UBFX instruction on ARM. */
|
||||||
return ~((0xffffffffU) << n);
|
return ~((0xFFFFFFFFu) << n);
|
||||||
} else {
|
} else {
|
||||||
return kBitMask[n];
|
return kBrotliBitMask[n];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
reg_t val_; /* pre-fetched bits */
|
brotli_reg_t val_; /* pre-fetched bits */
|
||||||
uint32_t bit_pos_; /* current bit-reading position in val_ */
|
uint32_t bit_pos_; /* current bit-reading position in val_ */
|
||||||
const uint8_t* next_in; /* the byte we're reading from */
|
const uint8_t* next_in; /* the byte we're reading from */
|
||||||
size_t avail_in;
|
size_t avail_in;
|
||||||
} BrotliBitReader;
|
} BrotliBitReader;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
reg_t val_;
|
brotli_reg_t val_;
|
||||||
uint32_t bit_pos_;
|
uint32_t bit_pos_;
|
||||||
const uint8_t* next_in;
|
const uint8_t* next_in;
|
||||||
size_t avail_in;
|
size_t avail_in;
|
||||||
|
@ -58,12 +50,19 @@ typedef struct {
|
||||||
/* Initializes the BrotliBitReader fields. */
|
/* Initializes the BrotliBitReader fields. */
|
||||||
BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
|
BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
|
||||||
|
|
||||||
/* Ensures that accumulator is not empty. May consume one byte of input.
|
/* Ensures that accumulator is not empty.
|
||||||
Returns 0 if data is required but there is no input available.
|
May consume up to sizeof(brotli_reg_t) - 1 bytes of input.
|
||||||
|
Returns BROTLI_FALSE if data is required but there is no input available.
|
||||||
For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned
|
For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned
|
||||||
reading. */
|
reading. */
|
||||||
BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br);
|
BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br);
|
||||||
|
|
||||||
|
/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden
|
||||||
|
the main code-path. Never called for RFC brotli streams, required only for
|
||||||
|
"large-window" mode and other extensions. */
|
||||||
|
BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow(
|
||||||
|
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val);
|
||||||
|
|
||||||
static BROTLI_INLINE void BrotliBitReaderSaveState(
|
static BROTLI_INLINE void BrotliBitReaderSaveState(
|
||||||
BrotliBitReader* const from, BrotliBitReaderState* to) {
|
BrotliBitReader* const from, BrotliBitReaderState* to) {
|
||||||
to->val_ = from->val_;
|
to->val_ = from->val_;
|
||||||
|
@ -86,8 +85,11 @@ static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns amount of unread bytes the bit reader still has buffered from the
|
/* Returns amount of unread bytes the bit reader still has buffered from the
|
||||||
BrotliInput, including whole bytes in br->val_. */
|
BrotliInput, including whole bytes in br->val_. Result is capped with
|
||||||
|
maximal ring-buffer size (larger number won't be utilized anyway). */
|
||||||
static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
|
static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
|
||||||
|
static const size_t kCap = (size_t)1 << BROTLI_LARGE_MAX_WBITS;
|
||||||
|
if (br->avail_in > kCap) return kCap;
|
||||||
return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
|
return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,94 +100,27 @@ static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount(
|
||||||
return TO_BROTLI_BOOL(br->avail_in >= num);
|
return TO_BROTLI_BOOL(br->avail_in >= num);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint16_t BrotliLoad16LE(const uint8_t* in) {
|
/* Guarantees that there are at least |n_bits| + 1 bits in accumulator.
|
||||||
#if __ppc__
|
|
||||||
uint16_t v;
|
|
||||||
__asm__("lhbrx %0, %y1" : "=r"(v) : "Z"(*in));
|
|
||||||
return v;
|
|
||||||
#else
|
|
||||||
if (BROTLI_LITTLE_ENDIAN) {
|
|
||||||
return *((const uint16_t*)in);
|
|
||||||
} else if (BROTLI_BIG_ENDIAN) {
|
|
||||||
uint16_t value = *((const uint16_t*)in);
|
|
||||||
return (uint16_t)(((value & 0xFFU) << 8) | ((value & 0xFF00U) >> 8));
|
|
||||||
} else {
|
|
||||||
return (uint16_t)(in[0] | (in[1] << 8));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t BrotliLoad32LE(const uint8_t* in) {
|
|
||||||
#if __ppc__
|
|
||||||
uint32_t v;
|
|
||||||
__asm__("lwbrx %0, %y1" : "=r"(v) : "Z"(*in));
|
|
||||||
return v;
|
|
||||||
#else
|
|
||||||
if (BROTLI_LITTLE_ENDIAN) {
|
|
||||||
return *((const uint32_t*)in);
|
|
||||||
} else if (BROTLI_BIG_ENDIAN) {
|
|
||||||
uint32_t value = *((const uint32_t*)in);
|
|
||||||
return ((value & 0xFFU) << 24) | ((value & 0xFF00U) << 8) |
|
|
||||||
((value & 0xFF0000U) >> 8) | ((value & 0xFF000000U) >> 24);
|
|
||||||
} else {
|
|
||||||
uint32_t value = (uint32_t)(*(in++));
|
|
||||||
value |= (uint32_t)(*(in++)) << 8;
|
|
||||||
value |= (uint32_t)(*(in++)) << 16;
|
|
||||||
value |= (uint32_t)(*(in++)) << 24;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (BROTLI_64_BITS)
|
|
||||||
static BROTLI_INLINE uint64_t BrotliLoad64LE(const uint8_t* in) {
|
|
||||||
if (BROTLI_LITTLE_ENDIAN) {
|
|
||||||
return *((const uint64_t*)in);
|
|
||||||
} else if (BROTLI_BIG_ENDIAN) {
|
|
||||||
uint64_t value = *((const uint64_t*)in);
|
|
||||||
return
|
|
||||||
((value & 0xFFU) << 56) |
|
|
||||||
((value & 0xFF00U) << 40) |
|
|
||||||
((value & 0xFF0000U) << 24) |
|
|
||||||
((value & 0xFF000000U) << 8) |
|
|
||||||
((value & 0xFF00000000U) >> 8) |
|
|
||||||
((value & 0xFF0000000000U) >> 24) |
|
|
||||||
((value & 0xFF000000000000U) >> 40) |
|
|
||||||
((value & 0xFF00000000000000U) >> 56);
|
|
||||||
} else {
|
|
||||||
uint64_t value = (uint64_t)(*(in++));
|
|
||||||
value |= (uint64_t)(*(in++)) << 8;
|
|
||||||
value |= (uint64_t)(*(in++)) << 16;
|
|
||||||
value |= (uint64_t)(*(in++)) << 24;
|
|
||||||
value |= (uint64_t)(*(in++)) << 32;
|
|
||||||
value |= (uint64_t)(*(in++)) << 40;
|
|
||||||
value |= (uint64_t)(*(in++)) << 48;
|
|
||||||
value |= (uint64_t)(*(in++)) << 56;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Guarantees that there are at least n_bits + 1 bits in accumulator.
|
|
||||||
Precondition: accumulator contains at least 1 bit.
|
Precondition: accumulator contains at least 1 bit.
|
||||||
n_bits should be in the range [1..24] for regular build. For portable
|
|n_bits| should be in the range [1..24] for regular build. For portable
|
||||||
non-64-bit little-endian build only 16 bits are safe to request. */
|
non-64-bit little-endian build only 16 bits are safe to request. */
|
||||||
static BROTLI_INLINE void BrotliFillBitWindow(
|
static BROTLI_INLINE void BrotliFillBitWindow(
|
||||||
BrotliBitReader* const br, uint32_t n_bits) {
|
BrotliBitReader* const br, uint32_t n_bits) {
|
||||||
#if (BROTLI_64_BITS)
|
#if (BROTLI_64_BITS)
|
||||||
if (!BROTLI_ALIGNED_READ && IS_CONSTANT(n_bits) && (n_bits <= 8)) {
|
if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) {
|
||||||
if (br->bit_pos_ >= 56) {
|
if (br->bit_pos_ >= 56) {
|
||||||
br->val_ >>= 56;
|
br->val_ >>= 56;
|
||||||
br->bit_pos_ ^= 56; /* here same as -= 56 because of the if condition */
|
br->bit_pos_ ^= 56; /* here same as -= 56 because of the if condition */
|
||||||
br->val_ |= BrotliLoad64LE(br->next_in) << 8;
|
br->val_ |= BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 8;
|
||||||
br->avail_in -= 7;
|
br->avail_in -= 7;
|
||||||
br->next_in += 7;
|
br->next_in += 7;
|
||||||
}
|
}
|
||||||
} else if (!BROTLI_ALIGNED_READ && IS_CONSTANT(n_bits) && (n_bits <= 16)) {
|
} else if (
|
||||||
|
!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 16)) {
|
||||||
if (br->bit_pos_ >= 48) {
|
if (br->bit_pos_ >= 48) {
|
||||||
br->val_ >>= 48;
|
br->val_ >>= 48;
|
||||||
br->bit_pos_ ^= 48; /* here same as -= 48 because of the if condition */
|
br->bit_pos_ ^= 48; /* here same as -= 48 because of the if condition */
|
||||||
br->val_ |= BrotliLoad64LE(br->next_in) << 16;
|
br->val_ |= BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 16;
|
||||||
br->avail_in -= 6;
|
br->avail_in -= 6;
|
||||||
br->next_in += 6;
|
br->next_in += 6;
|
||||||
}
|
}
|
||||||
|
@ -193,34 +128,30 @@ static BROTLI_INLINE void BrotliFillBitWindow(
|
||||||
if (br->bit_pos_ >= 32) {
|
if (br->bit_pos_ >= 32) {
|
||||||
br->val_ >>= 32;
|
br->val_ >>= 32;
|
||||||
br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
|
br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
|
||||||
br->val_ |= ((uint64_t)BrotliLoad32LE(br->next_in)) << 32;
|
br->val_ |= ((uint64_t)BROTLI_UNALIGNED_LOAD32LE(br->next_in)) << 32;
|
||||||
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||||
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#ifndef __ppc__
|
if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) {
|
||||||
if (!BROTLI_ALIGNED_READ && IS_CONSTANT(n_bits) && (n_bits <= 8)) {
|
|
||||||
if (br->bit_pos_ >= 24) {
|
if (br->bit_pos_ >= 24) {
|
||||||
br->val_ >>= 24;
|
br->val_ >>= 24;
|
||||||
br->bit_pos_ ^= 24; /* here same as -= 24 because of the if condition */
|
br->bit_pos_ ^= 24; /* here same as -= 24 because of the if condition */
|
||||||
br->val_ |= BrotliLoad32LE(br->next_in) << 8;
|
br->val_ |= BROTLI_UNALIGNED_LOAD32LE(br->next_in) << 8;
|
||||||
br->avail_in -= 3;
|
br->avail_in -= 3;
|
||||||
br->next_in += 3;
|
br->next_in += 3;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#endif
|
|
||||||
if (br->bit_pos_ >= 16) {
|
if (br->bit_pos_ >= 16) {
|
||||||
br->val_ >>= 16;
|
br->val_ >>= 16;
|
||||||
br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
|
br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
|
||||||
br->val_ |= ((uint32_t)BrotliLoad16LE(br->next_in)) << 16;
|
br->val_ |= ((uint32_t)BROTLI_UNALIGNED_LOAD16LE(br->next_in)) << 16;
|
||||||
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||||
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||||
}
|
}
|
||||||
#ifndef __ppc__
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mostly like BrotliFillBitWindow, but guarantees only 16 bits and reads no
|
/* Mostly like BrotliFillBitWindow, but guarantees only 16 bits and reads no
|
||||||
|
@ -229,7 +160,8 @@ static BROTLI_INLINE void BrotliFillBitWindow16(BrotliBitReader* const br) {
|
||||||
BrotliFillBitWindow(br, 17);
|
BrotliFillBitWindow(br, 17);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pulls one byte of input to accumulator. */
|
/* Tries to pull one byte of input to accumulator.
|
||||||
|
Returns BROTLI_FALSE if there is no input available. */
|
||||||
static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) {
|
static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) {
|
||||||
if (br->avail_in == 0) {
|
if (br->avail_in == 0) {
|
||||||
return BROTLI_FALSE;
|
return BROTLI_FALSE;
|
||||||
|
@ -248,7 +180,8 @@ static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) {
|
||||||
|
|
||||||
/* Returns currently available bits.
|
/* Returns currently available bits.
|
||||||
The number of valid bits could be calculated by BrotliGetAvailableBits. */
|
The number of valid bits could be calculated by BrotliGetAvailableBits. */
|
||||||
static BROTLI_INLINE reg_t BrotliGetBitsUnmasked(BrotliBitReader* const br) {
|
static BROTLI_INLINE brotli_reg_t BrotliGetBitsUnmasked(
|
||||||
|
BrotliBitReader* const br) {
|
||||||
return br->val_ >> br->bit_pos_;
|
return br->val_ >> br->bit_pos_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,15 +193,16 @@ static BROTLI_INLINE uint32_t BrotliGet16BitsUnmasked(
|
||||||
return (uint32_t)BrotliGetBitsUnmasked(br);
|
return (uint32_t)BrotliGetBitsUnmasked(br);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the specified number of bits from |br| without advancing bit pos. */
|
/* Returns the specified number of bits from |br| without advancing bit
|
||||||
|
position. */
|
||||||
static BROTLI_INLINE uint32_t BrotliGetBits(
|
static BROTLI_INLINE uint32_t BrotliGetBits(
|
||||||
BrotliBitReader* const br, uint32_t n_bits) {
|
BrotliBitReader* const br, uint32_t n_bits) {
|
||||||
BrotliFillBitWindow(br, n_bits);
|
BrotliFillBitWindow(br, n_bits);
|
||||||
return (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
return (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tries to peek the specified amount of bits. Returns 0, if there is not
|
/* Tries to peek the specified amount of bits. Returns BROTLI_FALSE, if there
|
||||||
enough input. */
|
is not enough input. */
|
||||||
static BROTLI_INLINE BROTLI_BOOL BrotliSafeGetBits(
|
static BROTLI_INLINE BROTLI_BOOL BrotliSafeGetBits(
|
||||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||||
|
@ -280,7 +214,7 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeGetBits(
|
||||||
return BROTLI_TRUE;
|
return BROTLI_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advances the bit pos by n_bits. */
|
/* Advances the bit pos by |n_bits|. */
|
||||||
static BROTLI_INLINE void BrotliDropBits(
|
static BROTLI_INLINE void BrotliDropBits(
|
||||||
BrotliBitReader* const br, uint32_t n_bits) {
|
BrotliBitReader* const br, uint32_t n_bits) {
|
||||||
br->bit_pos_ += n_bits;
|
br->bit_pos_ += n_bits;
|
||||||
|
@ -300,19 +234,21 @@ static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reads the specified number of bits from |br| and advances the bit pos.
|
/* Reads the specified number of bits from |br| and advances the bit pos.
|
||||||
Precondition: accumulator MUST contain at least n_bits. */
|
Precondition: accumulator MUST contain at least |n_bits|. */
|
||||||
static BROTLI_INLINE void BrotliTakeBits(
|
static BROTLI_INLINE void BrotliTakeBits(
|
||||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||||
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||||
BROTLI_LOG(("[BrotliReadBits] %d %d %d val: %6x\n",
|
BROTLI_LOG(("[BrotliTakeBits] %d %d %d val: %6x\n",
|
||||||
(int)br->avail_in, (int)br->bit_pos_, n_bits, (int)*val));
|
(int)br->avail_in, (int)br->bit_pos_, (int)n_bits, (int)*val));
|
||||||
BrotliDropBits(br, n_bits);
|
BrotliDropBits(br, n_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reads the specified number of bits from |br| and advances the bit pos.
|
/* Reads the specified number of bits from |br| and advances the bit pos.
|
||||||
Assumes that there is enough input to perform BrotliFillBitWindow. */
|
Assumes that there is enough input to perform BrotliFillBitWindow.
|
||||||
static BROTLI_INLINE uint32_t BrotliReadBits(
|
Up to 24 bits are allowed to be requested from this method. */
|
||||||
|
static BROTLI_INLINE uint32_t BrotliReadBits24(
|
||||||
BrotliBitReader* const br, uint32_t n_bits) {
|
BrotliBitReader* const br, uint32_t n_bits) {
|
||||||
|
BROTLI_DCHECK(n_bits <= 24);
|
||||||
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
BrotliFillBitWindow(br, n_bits);
|
BrotliFillBitWindow(br, n_bits);
|
||||||
|
@ -329,10 +265,32 @@ static BROTLI_INLINE uint32_t BrotliReadBits(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tries to read the specified amount of bits. Returns 0, if there is not
|
/* Same as BrotliReadBits24, but allows reading up to 32 bits. */
|
||||||
enough input. n_bits MUST be positive. */
|
static BROTLI_INLINE uint32_t BrotliReadBits32(
|
||||||
|
BrotliBitReader* const br, uint32_t n_bits) {
|
||||||
|
BROTLI_DCHECK(n_bits <= 32);
|
||||||
|
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
||||||
|
uint32_t val;
|
||||||
|
BrotliFillBitWindow(br, n_bits);
|
||||||
|
BrotliTakeBits(br, n_bits, &val);
|
||||||
|
return val;
|
||||||
|
} else {
|
||||||
|
uint32_t low_val;
|
||||||
|
uint32_t high_val;
|
||||||
|
BrotliFillBitWindow(br, 16);
|
||||||
|
BrotliTakeBits(br, 16, &low_val);
|
||||||
|
BrotliFillBitWindow(br, 16);
|
||||||
|
BrotliTakeBits(br, n_bits - 16, &high_val);
|
||||||
|
return low_val | (high_val << 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tries to read the specified amount of bits. Returns BROTLI_FALSE, if there
|
||||||
|
is not enough input. |n_bits| MUST be positive.
|
||||||
|
Up to 24 bits are allowed to be requested from this method. */
|
||||||
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
|
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
|
||||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||||
|
BROTLI_DCHECK(n_bits <= 24);
|
||||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||||
if (!BrotliPullByte(br)) {
|
if (!BrotliPullByte(br)) {
|
||||||
return BROTLI_FALSE;
|
return BROTLI_FALSE;
|
||||||
|
@ -342,6 +300,23 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
|
||||||
return BROTLI_TRUE;
|
return BROTLI_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */
|
||||||
|
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32(
|
||||||
|
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||||
|
BROTLI_DCHECK(n_bits <= 32);
|
||||||
|
if (BROTLI_64_BITS || (n_bits <= 24)) {
|
||||||
|
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||||
|
if (!BrotliPullByte(br)) {
|
||||||
|
return BROTLI_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BrotliTakeBits(br, n_bits, val);
|
||||||
|
return BROTLI_TRUE;
|
||||||
|
} else {
|
||||||
|
return BrotliSafeReadBits32Slow(br, n_bits, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Advances the bit reader position to the next byte boundary and verifies
|
/* Advances the bit reader position to the next byte boundary and verifies
|
||||||
that any skipped bits are set to zero. */
|
that any skipped bits are set to zero. */
|
||||||
static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
||||||
|
@ -354,7 +329,7 @@ static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copies remaining input bytes stored in the bit reader to the output. Value
|
/* 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
|
|num| may not be larger than BrotliGetRemainingBytes. The bit reader must be
|
||||||
warmed up again after this. */
|
warmed up again after this. */
|
||||||
static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
|
static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
|
||||||
BrotliBitReader* br, size_t num) {
|
BrotliBitReader* br, size_t num) {
|
||||||
|
|
|
@ -1,251 +0,0 @@
|
||||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
Distributed under MIT license.
|
|
||||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Lookup table to map the previous two bytes to a context id.
|
|
||||||
|
|
||||||
There are four different context modeling modes defined here:
|
|
||||||
CONTEXT_LSB6: context id is the least significant 6 bits of the last byte,
|
|
||||||
CONTEXT_MSB6: context id is the most significant 6 bits of the last byte,
|
|
||||||
CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text,
|
|
||||||
CONTEXT_SIGNED: second-order context model tuned for signed integers.
|
|
||||||
|
|
||||||
The context id for the UTF8 context model is calculated as follows. If p1
|
|
||||||
and p2 are the previous two bytes, we calculate the context as
|
|
||||||
|
|
||||||
context = kContextLookup[p1] | kContextLookup[p2 + 256].
|
|
||||||
|
|
||||||
If the previous two bytes are ASCII characters (i.e. < 128), this will be
|
|
||||||
equivalent to
|
|
||||||
|
|
||||||
context = 4 * context1(p1) + context2(p2),
|
|
||||||
|
|
||||||
where context1 is based on the previous byte in the following way:
|
|
||||||
|
|
||||||
0 : non-ASCII control
|
|
||||||
1 : \t, \n, \r
|
|
||||||
2 : space
|
|
||||||
3 : other punctuation
|
|
||||||
4 : " '
|
|
||||||
5 : %
|
|
||||||
6 : ( < [ {
|
|
||||||
7 : ) > ] }
|
|
||||||
8 : , ; :
|
|
||||||
9 : .
|
|
||||||
10 : =
|
|
||||||
11 : number
|
|
||||||
12 : upper-case vowel
|
|
||||||
13 : upper-case consonant
|
|
||||||
14 : lower-case vowel
|
|
||||||
15 : lower-case consonant
|
|
||||||
|
|
||||||
and context2 is based on the second last byte:
|
|
||||||
|
|
||||||
0 : control, space
|
|
||||||
1 : punctuation
|
|
||||||
2 : upper-case letter, number
|
|
||||||
3 : lower-case letter
|
|
||||||
|
|
||||||
If the last byte is ASCII, and the second last byte is not (in a valid UTF8
|
|
||||||
stream it will be a continuation byte, value between 128 and 191), the
|
|
||||||
context is the same as if the second last byte was an ASCII control or space.
|
|
||||||
|
|
||||||
If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
|
|
||||||
be a continuation byte and the context id is 2 or 3 depending on the LSB of
|
|
||||||
the last byte and to a lesser extent on the second last byte if it is ASCII.
|
|
||||||
|
|
||||||
If the last byte is a UTF8 continuation byte, the second last byte can be:
|
|
||||||
- continuation byte: the next byte is probably ASCII or lead byte (assuming
|
|
||||||
4-byte UTF8 characters are rare) and the context id is 0 or 1.
|
|
||||||
- lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
|
|
||||||
- lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
|
|
||||||
|
|
||||||
The possible value combinations of the previous two bytes, the range of
|
|
||||||
context ids and the type of the next byte is summarized in the table below:
|
|
||||||
|
|
||||||
|--------\-----------------------------------------------------------------|
|
|
||||||
| \ Last byte |
|
|
||||||
| Second \---------------------------------------------------------------|
|
|
||||||
| last byte \ ASCII | cont. byte | lead byte |
|
|
||||||
| \ (0-127) | (128-191) | (192-) |
|
|
||||||
|=============|===================|=====================|==================|
|
|
||||||
| ASCII | next: ASCII/lead | not valid | next: cont. |
|
|
||||||
| (0-127) | context: 4 - 63 | | context: 2 - 3 |
|
|
||||||
|-------------|-------------------|---------------------|------------------|
|
|
||||||
| cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
|
|
||||||
| (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
|
|
||||||
|-------------|-------------------|---------------------|------------------|
|
|
||||||
| lead byte | not valid | next: ASCII/lead | not valid |
|
|
||||||
| (192-207) | | context: 0 - 1 | |
|
|
||||||
|-------------|-------------------|---------------------|------------------|
|
|
||||||
| lead byte | not valid | next: cont. | not valid |
|
|
||||||
| (208-) | | context: 2 - 3 | |
|
|
||||||
|-------------|-------------------|---------------------|------------------|
|
|
||||||
|
|
||||||
The context id for the signed context mode is calculated as:
|
|
||||||
|
|
||||||
context = (kContextLookup[512 + p1] << 3) | kContextLookup[512 + p2].
|
|
||||||
|
|
||||||
For any context modeling modes, the context ids can be calculated by |-ing
|
|
||||||
together two lookups from one table using context model dependent offsets:
|
|
||||||
|
|
||||||
context = kContextLookup[offset1 + p1] | kContextLookup[offset2 + p2].
|
|
||||||
|
|
||||||
where offset1 and offset2 are dependent on the context mode.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BROTLI_DEC_CONTEXT_H_
|
|
||||||
#define BROTLI_DEC_CONTEXT_H_
|
|
||||||
|
|
||||||
#include <brotli/types.h>
|
|
||||||
|
|
||||||
enum ContextType {
|
|
||||||
CONTEXT_LSB6 = 0,
|
|
||||||
CONTEXT_MSB6 = 1,
|
|
||||||
CONTEXT_UTF8 = 2,
|
|
||||||
CONTEXT_SIGNED = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Common context lookup table for all context modes. */
|
|
||||||
static const uint8_t kContextLookup[1792] = {
|
|
||||||
/* CONTEXT_UTF8, last byte. */
|
|
||||||
/* ASCII range. */
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
|
|
||||||
44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
|
|
||||||
12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
|
|
||||||
52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
|
|
||||||
12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
|
|
||||||
60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0,
|
|
||||||
/* UTF8 continuation byte range. */
|
|
||||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
|
||||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
|
||||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
|
||||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
|
||||||
/* UTF8 lead byte range. */
|
|
||||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
|
||||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
|
||||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
|
||||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
|
||||||
/* CONTEXT_UTF8 second last byte. */
|
|
||||||
/* ASCII range. */
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
|
|
||||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
|
|
||||||
/* UTF8 continuation byte range. */
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
/* UTF8 lead byte range. */
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
/* CONTEXT_SIGNED, second last byte. */
|
|
||||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
|
|
||||||
/* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
|
|
||||||
0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
||||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
|
||||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
|
||||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
|
||||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
|
||||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
|
||||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
|
||||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
|
||||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
|
||||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
|
||||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
|
||||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
|
||||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
|
||||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
|
||||||
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
|
||||||
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
|
|
||||||
/* CONTEXT_LSB6, last byte. */
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
||||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
|
||||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
|
||||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
||||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
|
||||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
|
||||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
||||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
|
||||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
|
||||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
||||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
|
||||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
|
||||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
|
||||||
/* CONTEXT_MSB6, last byte. */
|
|
||||||
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
|
|
||||||
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
|
||||||
8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
|
|
||||||
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
|
|
||||||
16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
|
|
||||||
20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
|
|
||||||
24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
|
|
||||||
28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
|
|
||||||
32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
|
|
||||||
36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
|
|
||||||
40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
|
|
||||||
44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
|
|
||||||
48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
|
|
||||||
52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
|
|
||||||
56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
|
|
||||||
60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
|
|
||||||
/* CONTEXT_{M,L}SB6, second last byte, */
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int kContextLookupOffsets[8] = {
|
|
||||||
/* CONTEXT_LSB6 */
|
|
||||||
1024, 1536,
|
|
||||||
/* CONTEXT_MSB6 */
|
|
||||||
1280, 1536,
|
|
||||||
/* CONTEXT_UTF8 */
|
|
||||||
0, 256,
|
|
||||||
/* CONTEXT_SIGNED */
|
|
||||||
768, 512,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* BROTLI_DEC_CONTEXT_H_ */
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,8 +11,8 @@
|
||||||
#include <string.h> /* memcpy, memset */
|
#include <string.h> /* memcpy, memset */
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -20,9 +20,9 @@ extern "C" {
|
||||||
|
|
||||||
#define BROTLI_REVERSE_BITS_MAX 8
|
#define BROTLI_REVERSE_BITS_MAX 8
|
||||||
|
|
||||||
#ifdef BROTLI_RBIT
|
#if defined(BROTLI_RBIT)
|
||||||
#define BROTLI_REVERSE_BITS_BASE \
|
#define BROTLI_REVERSE_BITS_BASE \
|
||||||
((sizeof(reg_t) << 3) - BROTLI_REVERSE_BITS_MAX)
|
((sizeof(brotli_reg_t) << 3) - BROTLI_REVERSE_BITS_MAX)
|
||||||
#else
|
#else
|
||||||
#define BROTLI_REVERSE_BITS_BASE 0
|
#define BROTLI_REVERSE_BITS_BASE 0
|
||||||
static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
|
static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
|
||||||
|
@ -62,13 +62,13 @@ static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
|
||||||
#endif /* BROTLI_RBIT */
|
#endif /* BROTLI_RBIT */
|
||||||
|
|
||||||
#define BROTLI_REVERSE_BITS_LOWEST \
|
#define BROTLI_REVERSE_BITS_LOWEST \
|
||||||
((reg_t)1 << (BROTLI_REVERSE_BITS_MAX - 1 + BROTLI_REVERSE_BITS_BASE))
|
((brotli_reg_t)1 << (BROTLI_REVERSE_BITS_MAX - 1 + BROTLI_REVERSE_BITS_BASE))
|
||||||
|
|
||||||
/* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX),
|
/* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX),
|
||||||
where reverse(value, len) is the bit-wise reversal of the len least
|
where reverse(value, len) is the bit-wise reversal of the len least
|
||||||
significant bits of value. */
|
significant bits of value. */
|
||||||
static BROTLI_INLINE reg_t BrotliReverseBits(reg_t num) {
|
static BROTLI_INLINE brotli_reg_t BrotliReverseBits(brotli_reg_t num) {
|
||||||
#ifdef BROTLI_RBIT
|
#if defined(BROTLI_RBIT)
|
||||||
return BROTLI_RBIT(num);
|
return BROTLI_RBIT(num);
|
||||||
#else
|
#else
|
||||||
return kReverseBits[num];
|
return kReverseBits[num];
|
||||||
|
@ -86,9 +86,9 @@ static BROTLI_INLINE void ReplicateValue(HuffmanCode* table,
|
||||||
} while (end > 0);
|
} while (end > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the table width of the next 2nd level table. count is the histogram
|
/* Returns the table width of the next 2nd level table. |count| is the histogram
|
||||||
of bit lengths for the remaining symbols, len is the code length of the next
|
of bit lengths for the remaining symbols, |len| is the code length of the
|
||||||
processed symbol */
|
next processed symbol. */
|
||||||
static BROTLI_INLINE int NextTableBitSize(const uint16_t* const count,
|
static BROTLI_INLINE int NextTableBitSize(const uint16_t* const count,
|
||||||
int len, int root_bits) {
|
int len, int root_bits) {
|
||||||
int left = 1 << (len - root_bits);
|
int left = 1 << (len - root_bits);
|
||||||
|
@ -104,12 +104,12 @@ static BROTLI_INLINE int NextTableBitSize(const uint16_t* const count,
|
||||||
void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||||
const uint8_t* const code_lengths,
|
const uint8_t* const code_lengths,
|
||||||
uint16_t* count) {
|
uint16_t* count) {
|
||||||
HuffmanCode code; /* current table entry */
|
HuffmanCode code; /* current table entry */
|
||||||
int symbol; /* symbol index in original or sorted table */
|
int symbol; /* symbol index in original or sorted table */
|
||||||
reg_t key; /* prefix code */
|
brotli_reg_t key; /* prefix code */
|
||||||
reg_t key_step; /* prefix code addend */
|
brotli_reg_t key_step; /* prefix code addend */
|
||||||
int step; /* step size to replicate values in current table */
|
int step; /* step size to replicate values in current table */
|
||||||
int table_size; /* size of current table */
|
int table_size; /* size of current table */
|
||||||
int sorted[BROTLI_CODE_LENGTH_CODES]; /* symbols sorted by code length */
|
int sorted[BROTLI_CODE_LENGTH_CODES]; /* symbols sorted by code length */
|
||||||
/* offsets in sorted table for each length */
|
/* offsets in sorted table for each length */
|
||||||
int offset[BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1];
|
int offset[BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1];
|
||||||
|
@ -118,7 +118,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||||
BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH <=
|
BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH <=
|
||||||
BROTLI_REVERSE_BITS_MAX);
|
BROTLI_REVERSE_BITS_MAX);
|
||||||
|
|
||||||
/* generate offsets into sorted symbol table by code length */
|
/* Generate offsets into sorted symbol table by code length. */
|
||||||
symbol = -1;
|
symbol = -1;
|
||||||
bits = 1;
|
bits = 1;
|
||||||
BROTLI_REPEAT(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH, {
|
BROTLI_REPEAT(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH, {
|
||||||
|
@ -129,7 +129,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||||
/* Symbols with code length 0 are placed after all other symbols. */
|
/* Symbols with code length 0 are placed after all other symbols. */
|
||||||
offset[0] = BROTLI_CODE_LENGTH_CODES - 1;
|
offset[0] = BROTLI_CODE_LENGTH_CODES - 1;
|
||||||
|
|
||||||
/* sort symbols by length, by symbol order within each length */
|
/* Sort symbols by length, by symbol order within each length. */
|
||||||
symbol = BROTLI_CODE_LENGTH_CODES;
|
symbol = BROTLI_CODE_LENGTH_CODES;
|
||||||
do {
|
do {
|
||||||
BROTLI_REPEAT(6, {
|
BROTLI_REPEAT(6, {
|
||||||
|
@ -142,24 +142,22 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
||||||
|
|
||||||
/* Special case: all symbols but one have 0 code length. */
|
/* Special case: all symbols but one have 0 code length. */
|
||||||
if (offset[0] == 0) {
|
if (offset[0] == 0) {
|
||||||
code.bits = 0;
|
code = ConstructHuffmanCode(0, (uint16_t)sorted[0]);
|
||||||
code.value = (uint16_t)sorted[0];
|
for (key = 0; key < (brotli_reg_t)table_size; ++key) {
|
||||||
for (key = 0; key < (reg_t)table_size; ++key) {
|
|
||||||
table[key] = code;
|
table[key] = code;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fill in table */
|
/* Fill in table. */
|
||||||
key = 0;
|
key = 0;
|
||||||
key_step = BROTLI_REVERSE_BITS_LOWEST;
|
key_step = BROTLI_REVERSE_BITS_LOWEST;
|
||||||
symbol = 0;
|
symbol = 0;
|
||||||
bits = 1;
|
bits = 1;
|
||||||
step = 2;
|
step = 2;
|
||||||
do {
|
do {
|
||||||
code.bits = (uint8_t)bits;
|
|
||||||
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
|
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
|
||||||
code.value = (uint16_t)sorted[symbol++];
|
code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)sorted[symbol++]);
|
||||||
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
|
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
|
||||||
key += key_step;
|
key += key_step;
|
||||||
}
|
}
|
||||||
|
@ -172,18 +170,18 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||||
int root_bits,
|
int root_bits,
|
||||||
const uint16_t* const symbol_lists,
|
const uint16_t* const symbol_lists,
|
||||||
uint16_t* count) {
|
uint16_t* count) {
|
||||||
HuffmanCode code; /* current table entry */
|
HuffmanCode code; /* current table entry */
|
||||||
HuffmanCode* table; /* next available space in table */
|
HuffmanCode* table; /* next available space in table */
|
||||||
int len; /* current code length */
|
int len; /* current code length */
|
||||||
int symbol; /* symbol index in original or sorted table */
|
int symbol; /* symbol index in original or sorted table */
|
||||||
reg_t key; /* prefix code */
|
brotli_reg_t key; /* prefix code */
|
||||||
reg_t key_step; /* prefix code addend */
|
brotli_reg_t key_step; /* prefix code addend */
|
||||||
reg_t sub_key; /* 2nd level table prefix code */
|
brotli_reg_t sub_key; /* 2nd level table prefix code */
|
||||||
reg_t sub_key_step; /* 2nd level table prefix code addend */
|
brotli_reg_t sub_key_step; /* 2nd level table prefix code addend */
|
||||||
int step; /* step size to replicate values in current table */
|
int step; /* step size to replicate values in current table */
|
||||||
int table_bits; /* key length of current table */
|
int table_bits; /* key length of current table */
|
||||||
int table_size; /* size of current table */
|
int table_size; /* size of current table */
|
||||||
int total_size; /* sum of root table size and 2nd level table sizes */
|
int total_size; /* sum of root table size and 2nd level table sizes */
|
||||||
int max_length = -1;
|
int max_length = -1;
|
||||||
int bits;
|
int bits;
|
||||||
int bits_count;
|
int bits_count;
|
||||||
|
@ -200,9 +198,8 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||||
table_size = 1 << table_bits;
|
table_size = 1 << table_bits;
|
||||||
total_size = table_size;
|
total_size = table_size;
|
||||||
|
|
||||||
/* fill in root table */
|
/* Fill in the root table. Reduce the table size to if possible,
|
||||||
/* let's reduce the table size to a smaller size if possible, and */
|
and create the repetitions by memcpy. */
|
||||||
/* create the repetitions by memcpy if possible in the coming loop */
|
|
||||||
if (table_bits > max_length) {
|
if (table_bits > max_length) {
|
||||||
table_bits = max_length;
|
table_bits = max_length;
|
||||||
table_size = 1 << table_bits;
|
table_size = 1 << table_bits;
|
||||||
|
@ -212,11 +209,10 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||||
bits = 1;
|
bits = 1;
|
||||||
step = 2;
|
step = 2;
|
||||||
do {
|
do {
|
||||||
code.bits = (uint8_t)bits;
|
|
||||||
symbol = bits - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
|
symbol = bits - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
|
||||||
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
|
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
|
||||||
symbol = symbol_lists[symbol];
|
symbol = symbol_lists[symbol];
|
||||||
code.value = (uint16_t)symbol;
|
code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)symbol);
|
||||||
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
|
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
|
||||||
key += key_step;
|
key += key_step;
|
||||||
}
|
}
|
||||||
|
@ -224,15 +220,14 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||||
key_step >>= 1;
|
key_step >>= 1;
|
||||||
} while (++bits <= table_bits);
|
} while (++bits <= table_bits);
|
||||||
|
|
||||||
/* if root_bits != table_bits we only created one fraction of the */
|
/* If root_bits != table_bits then replicate to fill the remaining slots. */
|
||||||
/* table, and we need to replicate it now. */
|
|
||||||
while (total_size != table_size) {
|
while (total_size != table_size) {
|
||||||
memcpy(&table[table_size], &table[0],
|
memcpy(&table[table_size], &table[0],
|
||||||
(size_t)table_size * sizeof(table[0]));
|
(size_t)table_size * sizeof(table[0]));
|
||||||
table_size <<= 1;
|
table_size <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fill in 2nd level tables and add pointers to root table */
|
/* Fill in 2nd level tables and add pointers to root table. */
|
||||||
key_step = BROTLI_REVERSE_BITS_LOWEST >> (root_bits - 1);
|
key_step = BROTLI_REVERSE_BITS_LOWEST >> (root_bits - 1);
|
||||||
sub_key = (BROTLI_REVERSE_BITS_LOWEST << 1);
|
sub_key = (BROTLI_REVERSE_BITS_LOWEST << 1);
|
||||||
sub_key_step = BROTLI_REVERSE_BITS_LOWEST;
|
sub_key_step = BROTLI_REVERSE_BITS_LOWEST;
|
||||||
|
@ -246,14 +241,13 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||||
total_size += table_size;
|
total_size += table_size;
|
||||||
sub_key = BrotliReverseBits(key);
|
sub_key = BrotliReverseBits(key);
|
||||||
key += key_step;
|
key += key_step;
|
||||||
root_table[sub_key].bits = (uint8_t)(table_bits + root_bits);
|
root_table[sub_key] = ConstructHuffmanCode(
|
||||||
root_table[sub_key].value =
|
(uint8_t)(table_bits + root_bits),
|
||||||
(uint16_t)(((size_t)(table - root_table)) - sub_key);
|
(uint16_t)(((size_t)(table - root_table)) - sub_key));
|
||||||
sub_key = 0;
|
sub_key = 0;
|
||||||
}
|
}
|
||||||
code.bits = (uint8_t)(len - root_bits);
|
|
||||||
symbol = symbol_lists[symbol];
|
symbol = symbol_lists[symbol];
|
||||||
code.value = (uint16_t)symbol;
|
code = ConstructHuffmanCode((uint8_t)(len - root_bits), (uint16_t)symbol);
|
||||||
ReplicateValue(
|
ReplicateValue(
|
||||||
&table[BrotliReverseBits(sub_key)], step, table_size, code);
|
&table[BrotliReverseBits(sub_key)], step, table_size, code);
|
||||||
sub_key += sub_key_step;
|
sub_key += sub_key_step;
|
||||||
|
@ -272,35 +266,28 @@ uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||||
const uint32_t goal_size = 1U << root_bits;
|
const uint32_t goal_size = 1U << root_bits;
|
||||||
switch (num_symbols) {
|
switch (num_symbols) {
|
||||||
case 0:
|
case 0:
|
||||||
table[0].bits = 0;
|
table[0] = ConstructHuffmanCode(0, val[0]);
|
||||||
table[0].value = val[0];
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
table[0].bits = 1;
|
|
||||||
table[1].bits = 1;
|
|
||||||
if (val[1] > val[0]) {
|
if (val[1] > val[0]) {
|
||||||
table[0].value = val[0];
|
table[0] = ConstructHuffmanCode(1, val[0]);
|
||||||
table[1].value = val[1];
|
table[1] = ConstructHuffmanCode(1, val[1]);
|
||||||
} else {
|
} else {
|
||||||
table[0].value = val[1];
|
table[0] = ConstructHuffmanCode(1, val[1]);
|
||||||
table[1].value = val[0];
|
table[1] = ConstructHuffmanCode(1, val[0]);
|
||||||
}
|
}
|
||||||
table_size = 2;
|
table_size = 2;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
table[0].bits = 1;
|
table[0] = ConstructHuffmanCode(1, val[0]);
|
||||||
table[0].value = val[0];
|
table[2] = ConstructHuffmanCode(1, val[0]);
|
||||||
table[2].bits = 1;
|
|
||||||
table[2].value = val[0];
|
|
||||||
if (val[2] > val[1]) {
|
if (val[2] > val[1]) {
|
||||||
table[1].value = val[1];
|
table[1] = ConstructHuffmanCode(2, val[1]);
|
||||||
table[3].value = val[2];
|
table[3] = ConstructHuffmanCode(2, val[2]);
|
||||||
} else {
|
} else {
|
||||||
table[1].value = val[2];
|
table[1] = ConstructHuffmanCode(2, val[2]);
|
||||||
table[3].value = val[1];
|
table[3] = ConstructHuffmanCode(2, val[1]);
|
||||||
}
|
}
|
||||||
table[1].bits = 2;
|
|
||||||
table[3].bits = 2;
|
|
||||||
table_size = 4;
|
table_size = 4;
|
||||||
break;
|
break;
|
||||||
case 3: {
|
case 3: {
|
||||||
|
@ -314,33 +301,27 @@ uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < 4; ++i) {
|
table[0] = ConstructHuffmanCode(2, val[0]);
|
||||||
table[i].bits = 2;
|
table[2] = ConstructHuffmanCode(2, val[1]);
|
||||||
}
|
table[1] = ConstructHuffmanCode(2, val[2]);
|
||||||
table[0].value = val[0];
|
table[3] = ConstructHuffmanCode(2, val[3]);
|
||||||
table[2].value = val[1];
|
|
||||||
table[1].value = val[2];
|
|
||||||
table[3].value = val[3];
|
|
||||||
table_size = 4;
|
table_size = 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4: {
|
case 4: {
|
||||||
int i;
|
|
||||||
if (val[3] < val[2]) {
|
if (val[3] < val[2]) {
|
||||||
uint16_t t = val[3];
|
uint16_t t = val[3];
|
||||||
val[3] = val[2];
|
val[3] = val[2];
|
||||||
val[2] = t;
|
val[2] = t;
|
||||||
}
|
}
|
||||||
for (i = 0; i < 7; ++i) {
|
table[0] = ConstructHuffmanCode(1, val[0]);
|
||||||
table[i].value = val[0];
|
table[1] = ConstructHuffmanCode(2, val[1]);
|
||||||
table[i].bits = (uint8_t)(1 + (i & 1));
|
table[2] = ConstructHuffmanCode(1, val[0]);
|
||||||
}
|
table[3] = ConstructHuffmanCode(3, val[2]);
|
||||||
table[1].value = val[1];
|
table[4] = ConstructHuffmanCode(1, val[0]);
|
||||||
table[3].value = val[2];
|
table[5] = ConstructHuffmanCode(2, val[1]);
|
||||||
table[5].value = val[1];
|
table[6] = ConstructHuffmanCode(1, val[0]);
|
||||||
table[7].value = val[3];
|
table[7] = ConstructHuffmanCode(3, val[3]);
|
||||||
table[3].bits = 3;
|
|
||||||
table[7].bits = 3;
|
|
||||||
table_size = 8;
|
table_size = 8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
#ifndef BROTLI_DEC_HUFFMAN_H_
|
#ifndef BROTLI_DEC_HUFFMAN_H_
|
||||||
#define BROTLI_DEC_HUFFMAN_H_
|
#define BROTLI_DEC_HUFFMAN_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -18,11 +18,6 @@ extern "C" {
|
||||||
|
|
||||||
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15
|
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15
|
||||||
|
|
||||||
/* 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};
|
|
||||||
/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
|
/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
|
||||||
#define BROTLI_HUFFMAN_MAX_SIZE_26 396
|
#define BROTLI_HUFFMAN_MAX_SIZE_26 396
|
||||||
/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
|
/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
|
||||||
|
@ -32,32 +27,90 @@ static const uint16_t kMaxHuffmanTableSize[] = {
|
||||||
|
|
||||||
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH 5
|
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH 5
|
||||||
|
|
||||||
|
#if ((defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_32)) && \
|
||||||
|
BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0))
|
||||||
|
#define BROTLI_HUFFMAN_CODE_FAST_LOAD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BROTLI_HUFFMAN_CODE_FAST_LOAD)
|
||||||
|
/* Do not create this struct directly - use the ConstructHuffmanCode
|
||||||
|
* constructor below! */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t bits; /* number of bits used for this symbol */
|
uint8_t bits; /* number of bits used for this symbol */
|
||||||
uint16_t value; /* symbol value or table offset */
|
uint16_t value; /* symbol value or table offset */
|
||||||
} HuffmanCode;
|
} HuffmanCode;
|
||||||
|
|
||||||
|
static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
|
||||||
|
const uint16_t value) {
|
||||||
|
HuffmanCode h;
|
||||||
|
h.bits = bits;
|
||||||
|
h.value = value;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Please use the following macros to optimize HuffmanCode accesses in hot
|
||||||
|
* paths.
|
||||||
|
*
|
||||||
|
* For example, assuming |table| contains a HuffmanCode pointer:
|
||||||
|
*
|
||||||
|
* BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
|
||||||
|
* BROTLI_HC_ADJUST_TABLE_INDEX(table, index_into_table);
|
||||||
|
* *bits = BROTLI_HC_GET_BITS(table);
|
||||||
|
* *value = BROTLI_HC_GET_VALUE(table);
|
||||||
|
* BROTLI_HC_ADJUST_TABLE_INDEX(table, offset);
|
||||||
|
* *bits2 = BROTLI_HC_GET_BITS(table);
|
||||||
|
* *value2 = BROTLI_HC_GET_VALUE(table);
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H)
|
||||||
|
#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V)
|
||||||
|
|
||||||
|
/* These must be given a HuffmanCode pointer! */
|
||||||
|
#define BROTLI_HC_FAST_LOAD_BITS(H) (H->bits)
|
||||||
|
#define BROTLI_HC_FAST_LOAD_VALUE(H) (H->value)
|
||||||
|
|
||||||
|
#else /* BROTLI_HUFFMAN_CODE_FAST_LOAD */
|
||||||
|
|
||||||
|
typedef BROTLI_ALIGNED(4) uint32_t HuffmanCode;
|
||||||
|
|
||||||
|
static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
|
||||||
|
const uint16_t value) {
|
||||||
|
return (HuffmanCode) ((value & 0xFFFF) << 16) | (bits & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H)
|
||||||
|
#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V); __fastload_##H = (*H)
|
||||||
|
|
||||||
|
/* These must be given a HuffmanCode pointer! */
|
||||||
|
#define BROTLI_HC_FAST_LOAD_BITS(H) ((__fastload_##H) & 0xFF)
|
||||||
|
#define BROTLI_HC_FAST_LOAD_VALUE(H) ((__fastload_##H) >> 16)
|
||||||
|
#endif /* BROTLI_HUFFMAN_CODE_FAST_LOAD */
|
||||||
|
|
||||||
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
|
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
|
||||||
BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
|
BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
|
||||||
const uint8_t* const code_lengths, uint16_t* count);
|
const uint8_t* const code_lengths, uint16_t* count);
|
||||||
|
|
||||||
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
|
/* Builds Huffman lookup table assuming code lengths are in symbol order.
|
||||||
/* Returns size of resulting table. */
|
Returns size of resulting table. */
|
||||||
BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||||
int root_bits, const uint16_t* const symbol_lists, uint16_t* count_arg);
|
int root_bits, const uint16_t* const symbol_lists, uint16_t* count);
|
||||||
|
|
||||||
/* Builds a simple Huffman table. The num_symbols parameter is to be */
|
/* Builds a simple Huffman table. The |num_symbols| parameter is to be
|
||||||
/* interpreted as follows: 0 means 1 symbol, 1 means 2 symbols, 2 means 3 */
|
interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
|
||||||
/* symbols, 3 means 4 symbols with lengths 2,2,2,2, 4 means 4 symbols with */
|
2 means 3 symbols, 3 means 4 symbols with lengths [2, 2, 2, 2],
|
||||||
/* lengths 1,2,3,3. */
|
4 means 4 symbols with lengths [1, 2, 3, 3]. */
|
||||||
BROTLI_INTERNAL uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
BROTLI_INTERNAL uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
||||||
int root_bits, uint16_t* symbols, uint32_t num_symbols);
|
int root_bits, uint16_t* symbols, uint32_t num_symbols);
|
||||||
|
|
||||||
/* Contains a collection of Huffman trees with the same alphabet size. */
|
/* Contains a collection of Huffman trees with the same alphabet size. */
|
||||||
|
/* alphabet_size_limit is needed due to simple codes, since
|
||||||
|
log2(alphabet_size_max) could be greater than log2(alphabet_size_limit). */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HuffmanCode** htrees;
|
HuffmanCode** htrees;
|
||||||
HuffmanCode* codes;
|
HuffmanCode* codes;
|
||||||
uint16_t alphabet_size;
|
uint16_t alphabet_size_max;
|
||||||
|
uint16_t alphabet_size_limit;
|
||||||
uint16_t num_htrees;
|
uint16_t num_htrees;
|
||||||
} HuffmanTreeGroup;
|
} HuffmanTreeGroup;
|
||||||
|
|
||||||
|
|
|
@ -1,177 +0,0 @@
|
||||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
Distributed under MIT license.
|
|
||||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Macros for compiler / platform specific features and build options.
|
|
||||||
|
|
||||||
Build options are:
|
|
||||||
* BROTLI_BUILD_32_BIT disables 64-bit optimizations
|
|
||||||
* BROTLI_BUILD_64_BIT forces to use 64-bit optimizations
|
|
||||||
* BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations
|
|
||||||
* BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware optimizations
|
|
||||||
* BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations
|
|
||||||
* BROTLI_BUILD_MODERN_COMPILER forces to use modern compilers built-ins,
|
|
||||||
features and attributes
|
|
||||||
* BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned
|
|
||||||
read and overlapping memcpy; this reduces decompression speed by 5%
|
|
||||||
* BROTLI_BUILD_NO_RBIT disables "rbit" optimization for ARM CPUs
|
|
||||||
* BROTLI_DEBUG dumps file name and line number when decoder detects stream
|
|
||||||
or memory error
|
|
||||||
* BROTLI_ENABLE_LOG enables asserts and dumps various state information
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BROTLI_DEC_PORT_H_
|
|
||||||
#define BROTLI_DEC_PORT_H_
|
|
||||||
|
|
||||||
#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <brotli/port.h>
|
|
||||||
|
|
||||||
#if defined(__arm__) || defined(__thumb__) || \
|
|
||||||
defined(_M_ARM) || defined(_M_ARMT) || defined(__ARM64_ARCH_8__)
|
|
||||||
#define BROTLI_TARGET_ARM
|
|
||||||
#if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \
|
|
||||||
(defined(M_ARM) && (M_ARM == 7))
|
|
||||||
#define BROTLI_TARGET_ARMV7
|
|
||||||
#endif /* ARMv7 */
|
|
||||||
#if defined(__aarch64__) || defined(__ARM64_ARCH_8__)
|
|
||||||
#define BROTLI_TARGET_ARMV8
|
|
||||||
#endif /* ARMv8 */
|
|
||||||
#endif /* ARM */
|
|
||||||
|
|
||||||
#if defined(__i386) || defined(_M_IX86)
|
|
||||||
#define BROTLI_TARGET_X86
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__x86_64__) || defined(_M_X64)
|
|
||||||
#define BROTLI_TARGET_X64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__PPC64__)
|
|
||||||
#define BROTLI_TARGET_POWERPC64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BROTLI_BUILD_PORTABLE
|
|
||||||
#define BROTLI_ALIGNED_READ (!!1)
|
|
||||||
#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
|
|
||||||
defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8)
|
|
||||||
/* Allow unaligned read only for white-listed CPUs. */
|
|
||||||
#define BROTLI_ALIGNED_READ (!!0)
|
|
||||||
#else
|
|
||||||
#define BROTLI_ALIGNED_READ (!!1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* IS_CONSTANT macros returns true for compile-time constant expressions. */
|
|
||||||
#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_constant_p)
|
|
||||||
#define IS_CONSTANT(x) (!!__builtin_constant_p(x))
|
|
||||||
#else
|
|
||||||
#define IS_CONSTANT(x) (!!0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BROTLI_ENABLE_LOG
|
|
||||||
#define BROTLI_DCHECK(x) assert(x)
|
|
||||||
#define BROTLI_LOG(x) printf x
|
|
||||||
#else
|
|
||||||
#define BROTLI_DCHECK(x)
|
|
||||||
#define BROTLI_LOG(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
|
|
||||||
static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
|
|
||||||
fprintf(stderr, "%s:%d (%s)\n", f, l, fn);
|
|
||||||
fflush(stderr);
|
|
||||||
}
|
|
||||||
#define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__)
|
|
||||||
#else
|
|
||||||
#define BROTLI_DUMP() (void)(0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(BROTLI_BUILD_64_BIT)
|
|
||||||
#define BROTLI_64_BITS 1
|
|
||||||
#elif defined(BROTLI_BUILD_32_BIT)
|
|
||||||
#define BROTLI_64_BITS 0
|
|
||||||
#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8) || \
|
|
||||||
defined(BROTLI_TARGET_POWERPC64)
|
|
||||||
#define BROTLI_64_BITS 1
|
|
||||||
#else
|
|
||||||
#define BROTLI_64_BITS 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (BROTLI_64_BITS)
|
|
||||||
#define reg_t uint64_t
|
|
||||||
#else
|
|
||||||
#define reg_t uint32_t
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(BROTLI_BUILD_BIG_ENDIAN)
|
|
||||||
#define BROTLI_LITTLE_ENDIAN 0
|
|
||||||
#define BROTLI_BIG_ENDIAN 1
|
|
||||||
#elif defined(BROTLI_BUILD_LITTLE_ENDIAN)
|
|
||||||
#define BROTLI_LITTLE_ENDIAN 1
|
|
||||||
#define BROTLI_BIG_ENDIAN 0
|
|
||||||
#elif defined(BROTLI_BUILD_ENDIAN_NEUTRAL)
|
|
||||||
#define BROTLI_LITTLE_ENDIAN 0
|
|
||||||
#define BROTLI_BIG_ENDIAN 0
|
|
||||||
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
|
||||||
#define BROTLI_LITTLE_ENDIAN 1
|
|
||||||
#define BROTLI_BIG_ENDIAN 0
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
/* Win32 can currently always be assumed to be little endian */
|
|
||||||
#define BROTLI_LITTLE_ENDIAN 1
|
|
||||||
#define BROTLI_BIG_ENDIAN 0
|
|
||||||
#else
|
|
||||||
#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
|
||||||
#define BROTLI_BIG_ENDIAN 1
|
|
||||||
#else
|
|
||||||
#define BROTLI_BIG_ENDIAN 0
|
|
||||||
#endif
|
|
||||||
#define BROTLI_LITTLE_ENDIAN 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BROTLI_REPEAT(N, X) { \
|
|
||||||
if ((N & 1) != 0) {X;} \
|
|
||||||
if ((N & 2) != 0) {X; X;} \
|
|
||||||
if ((N & 4) != 0) {X; X; X; X;} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (BROTLI_MODERN_COMPILER || defined(__llvm__)) && \
|
|
||||||
!defined(BROTLI_BUILD_NO_RBIT)
|
|
||||||
#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8)
|
|
||||||
/* TODO: detect ARMv6T2 and enable this code for it. */
|
|
||||||
static BROTLI_INLINE reg_t BrotliRBit(reg_t input) {
|
|
||||||
reg_t output;
|
|
||||||
__asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
#define BROTLI_RBIT(x) BrotliRBit(x)
|
|
||||||
#endif /* armv7 */
|
|
||||||
#endif /* gcc || clang */
|
|
||||||
|
|
||||||
#if defined(BROTLI_TARGET_ARM)
|
|
||||||
#define BROTLI_HAS_UBFX (!!1)
|
|
||||||
#else
|
|
||||||
#define BROTLI_HAS_UBFX (!!0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BROTLI_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
|
|
||||||
|
|
||||||
#define BROTLI_FREE(S, X) { \
|
|
||||||
S->free_func(S->memory_manager_opaque, X); \
|
|
||||||
X = NULL; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(__i386) && !defined(__x86_64__)
|
|
||||||
#if (BROTLI_BIG_ENDIAN == 0)
|
|
||||||
#error not compiling big endian
|
|
||||||
#endif
|
|
||||||
#if (BROTLI_64_BIT == 1)
|
|
||||||
#error not compiling 32 bit
|
|
||||||
#endif
|
|
||||||
#endif /* !defined(__i386) && !defined(__x86_64__) */
|
|
||||||
|
|
||||||
#endif /* BROTLI_DEC_PORT_H_ */
|
|
|
@ -5,8 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Lookup tables to map prefix codes to value ranges. This is used during
|
/* Lookup tables to map prefix codes to value ranges. This is used during
|
||||||
decoding of the block lengths, literal insertion lengths and copy lengths.
|
decoding of the block lengths, literal insertion lengths and copy lengths. */
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BROTLI_DEC_PREFIX_H_
|
#ifndef BROTLI_DEC_PREFIX_H_
|
||||||
#define BROTLI_DEC_PREFIX_H_
|
#define BROTLI_DEC_PREFIX_H_
|
||||||
|
@ -14,24 +13,6 @@
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
|
|
||||||
/* Represents the range of values belonging to a prefix code: */
|
|
||||||
/* [offset, offset + 2^nbits) */
|
|
||||||
struct PrefixCodeRange {
|
|
||||||
uint16_t offset;
|
|
||||||
uint8_t nbits;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct PrefixCodeRange
|
|
||||||
kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
|
|
||||||
{ 1, 2}, { 5, 2}, { 9, 2}, { 13, 2},
|
|
||||||
{ 17, 3}, { 25, 3}, { 33, 3}, { 41, 3},
|
|
||||||
{ 49, 4}, { 65, 4}, { 81, 4}, { 97, 4},
|
|
||||||
{ 113, 5}, { 145, 5}, { 177, 5}, { 209, 5},
|
|
||||||
{ 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
|
|
||||||
{ 753, 9}, { 1265, 10}, {2289, 11}, {4337, 12},
|
|
||||||
{8433, 13}, {16625, 24}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CmdLutElement {
|
typedef struct CmdLutElement {
|
||||||
uint8_t insert_len_extra_bits;
|
uint8_t insert_len_extra_bits;
|
||||||
uint8_t copy_len_extra_bits;
|
uint8_t copy_len_extra_bits;
|
||||||
|
|
|
@ -15,25 +15,11 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void* DefaultAllocFunc(void* opaque, size_t size) {
|
BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||||
BROTLI_UNUSED(opaque);
|
|
||||||
return malloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DefaultFreeFunc(void* opaque, void* address) {
|
|
||||||
BROTLI_UNUSED(opaque);
|
|
||||||
free(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrotliDecoderStateInit(BrotliDecoderState* s) {
|
|
||||||
BrotliDecoderStateInitWithCustomAllocators(s, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrotliDecoderStateInitWithCustomAllocators(BrotliDecoderState* s,
|
|
||||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||||
if (!alloc_func) {
|
if (!alloc_func) {
|
||||||
s->alloc_func = DefaultAllocFunc;
|
s->alloc_func = BrotliDefaultAllocFunc;
|
||||||
s->free_func = DefaultFreeFunc;
|
s->free_func = BrotliDefaultFreeFunc;
|
||||||
s->memory_manager_opaque = 0;
|
s->memory_manager_opaque = 0;
|
||||||
} else {
|
} else {
|
||||||
s->alloc_func = alloc_func;
|
s->alloc_func = alloc_func;
|
||||||
|
@ -45,16 +31,12 @@ void BrotliDecoderStateInitWithCustomAllocators(BrotliDecoderState* s,
|
||||||
|
|
||||||
BrotliInitBitReader(&s->br);
|
BrotliInitBitReader(&s->br);
|
||||||
s->state = BROTLI_STATE_UNINITED;
|
s->state = BROTLI_STATE_UNINITED;
|
||||||
|
s->large_window = 0;
|
||||||
s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
|
s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE;
|
||||||
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
|
|
||||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
|
|
||||||
s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
|
s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE;
|
||||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
|
||||||
s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
|
s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
|
||||||
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
|
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
|
||||||
|
|
||||||
s->dictionary = BrotliGetDictionary();
|
|
||||||
|
|
||||||
s->buffer_length = 0;
|
s->buffer_length = 0;
|
||||||
s->loop_counter = 0;
|
s->loop_counter = 0;
|
||||||
s->pos = 0;
|
s->pos = 0;
|
||||||
|
@ -74,8 +56,6 @@ void BrotliDecoderStateInitWithCustomAllocators(BrotliDecoderState* s,
|
||||||
s->context_map_slice = NULL;
|
s->context_map_slice = NULL;
|
||||||
s->dist_context_map_slice = NULL;
|
s->dist_context_map_slice = NULL;
|
||||||
|
|
||||||
s->sub_loop_counter = 0;
|
|
||||||
|
|
||||||
s->literal_hgroup.codes = NULL;
|
s->literal_hgroup.codes = NULL;
|
||||||
s->literal_hgroup.htrees = NULL;
|
s->literal_hgroup.htrees = NULL;
|
||||||
s->insert_copy_hgroup.codes = NULL;
|
s->insert_copy_hgroup.codes = NULL;
|
||||||
|
@ -99,17 +79,19 @@ void BrotliDecoderStateInitWithCustomAllocators(BrotliDecoderState* s,
|
||||||
s->block_type_trees = NULL;
|
s->block_type_trees = NULL;
|
||||||
s->block_len_trees = NULL;
|
s->block_len_trees = NULL;
|
||||||
|
|
||||||
/* Make small negative indexes addressable. */
|
|
||||||
s->symbol_lists = &s->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
|
|
||||||
|
|
||||||
s->mtf_upper_bound = 63;
|
s->mtf_upper_bound = 63;
|
||||||
|
|
||||||
|
s->dictionary = BrotliGetDictionary();
|
||||||
|
s->transforms = BrotliGetTransforms();
|
||||||
|
|
||||||
|
return BROTLI_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) {
|
void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) {
|
||||||
s->meta_block_remaining_len = 0;
|
s->meta_block_remaining_len = 0;
|
||||||
s->block_length[0] = 1U << 28;
|
s->block_length[0] = 1U << 24;
|
||||||
s->block_length[1] = 1U << 28;
|
s->block_length[1] = 1U << 24;
|
||||||
s->block_length[2] = 1U << 28;
|
s->block_length[2] = 1U << 24;
|
||||||
s->num_block_types[0] = 1;
|
s->num_block_types[0] = 1;
|
||||||
s->num_block_types[1] = 1;
|
s->num_block_types[1] = 1;
|
||||||
s->num_block_types[2] = 1;
|
s->num_block_types[2] = 1;
|
||||||
|
@ -126,8 +108,7 @@ void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) {
|
||||||
s->literal_htree = NULL;
|
s->literal_htree = NULL;
|
||||||
s->dist_context_map_slice = NULL;
|
s->dist_context_map_slice = NULL;
|
||||||
s->dist_htree_index = 0;
|
s->dist_htree_index = 0;
|
||||||
s->context_lookup1 = NULL;
|
s->context_lookup = NULL;
|
||||||
s->context_lookup2 = NULL;
|
|
||||||
s->literal_hgroup.codes = NULL;
|
s->literal_hgroup.codes = NULL;
|
||||||
s->literal_hgroup.htrees = NULL;
|
s->literal_hgroup.htrees = NULL;
|
||||||
s->insert_copy_hgroup.codes = NULL;
|
s->insert_copy_hgroup.codes = NULL;
|
||||||
|
@ -137,30 +118,36 @@ void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliDecoderStateCleanupAfterMetablock(BrotliDecoderState* s) {
|
void BrotliDecoderStateCleanupAfterMetablock(BrotliDecoderState* s) {
|
||||||
BROTLI_FREE(s, s->context_modes);
|
BROTLI_DECODER_FREE(s, s->context_modes);
|
||||||
BROTLI_FREE(s, s->context_map);
|
BROTLI_DECODER_FREE(s, s->context_map);
|
||||||
BROTLI_FREE(s, s->dist_context_map);
|
BROTLI_DECODER_FREE(s, s->dist_context_map);
|
||||||
BROTLI_FREE(s, s->literal_hgroup.htrees);
|
BROTLI_DECODER_FREE(s, s->literal_hgroup.htrees);
|
||||||
BROTLI_FREE(s, s->insert_copy_hgroup.htrees);
|
BROTLI_DECODER_FREE(s, s->insert_copy_hgroup.htrees);
|
||||||
BROTLI_FREE(s, s->distance_hgroup.htrees);
|
BROTLI_DECODER_FREE(s, s->distance_hgroup.htrees);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliDecoderStateCleanup(BrotliDecoderState* s) {
|
void BrotliDecoderStateCleanup(BrotliDecoderState* s) {
|
||||||
BrotliDecoderStateCleanupAfterMetablock(s);
|
BrotliDecoderStateCleanupAfterMetablock(s);
|
||||||
|
|
||||||
BROTLI_FREE(s, s->ringbuffer);
|
BROTLI_DECODER_FREE(s, s->ringbuffer);
|
||||||
BROTLI_FREE(s, s->block_type_trees);
|
BROTLI_DECODER_FREE(s, s->block_type_trees);
|
||||||
}
|
}
|
||||||
|
|
||||||
BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s,
|
BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s,
|
||||||
HuffmanTreeGroup* group, uint32_t alphabet_size, uint32_t ntrees) {
|
HuffmanTreeGroup* group, uint32_t alphabet_size_max,
|
||||||
/* Pack two allocations into one */
|
uint32_t alphabet_size_limit, uint32_t ntrees) {
|
||||||
const size_t max_table_size = kMaxHuffmanTableSize[(alphabet_size + 31) >> 5];
|
/* 376 = 256 (1-st level table) + 4 + 7 + 15 + 31 + 63 (2-nd level mix-tables)
|
||||||
|
This number is discovered "unlimited" "enough" calculator; it is actually
|
||||||
|
a wee bigger than required in several cases (especially for alphabets with
|
||||||
|
less than 16 symbols). */
|
||||||
|
const size_t max_table_size = alphabet_size_limit + 376;
|
||||||
const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size;
|
const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size;
|
||||||
const size_t htree_size = sizeof(HuffmanCode*) * ntrees;
|
const size_t htree_size = sizeof(HuffmanCode*) * ntrees;
|
||||||
/* Pointer alignment is, hopefully, wider than sizeof(HuffmanCode). */
|
/* Pointer alignment is, hopefully, wider than sizeof(HuffmanCode). */
|
||||||
HuffmanCode** p = (HuffmanCode**)BROTLI_ALLOC(s, code_size + htree_size);
|
HuffmanCode** p = (HuffmanCode**)BROTLI_DECODER_ALLOC(s,
|
||||||
group->alphabet_size = (uint16_t)alphabet_size;
|
code_size + htree_size);
|
||||||
|
group->alphabet_size_max = (uint16_t)alphabet_size_max;
|
||||||
|
group->alphabet_size_limit = (uint16_t)alphabet_size_limit;
|
||||||
group->num_htrees = (uint16_t)ntrees;
|
group->num_htrees = (uint16_t)ntrees;
|
||||||
group->htrees = p;
|
group->htrees = p;
|
||||||
group->codes = (HuffmanCode*)(&p[ntrees]);
|
group->codes = (HuffmanCode*)(&p[ntrees]);
|
||||||
|
|
|
@ -11,17 +11,109 @@
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
#include "../common/dictionary.h"
|
#include "../common/dictionary.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
|
#include "../common/transform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./bit_reader.h"
|
#include "./bit_reader.h"
|
||||||
#include "./huffman.h"
|
#include "./huffman.h"
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Graphviz diagram that describes state transitions:
|
||||||
|
|
||||||
|
digraph States {
|
||||||
|
graph [compound=true]
|
||||||
|
concentrate=true
|
||||||
|
node [shape="box"]
|
||||||
|
|
||||||
|
UNINITED -> {LARGE_WINDOW_BITS -> INITIALIZE}
|
||||||
|
subgraph cluster_metablock_workflow {
|
||||||
|
style="rounded"
|
||||||
|
label=< <B>METABLOCK CYCLE</B> >
|
||||||
|
METABLOCK_BEGIN -> METABLOCK_HEADER
|
||||||
|
METABLOCK_HEADER:sw -> METADATA
|
||||||
|
METABLOCK_HEADER:s -> UNCOMPRESSED
|
||||||
|
METABLOCK_HEADER:se -> METABLOCK_DONE:ne
|
||||||
|
METADATA:s -> METABLOCK_DONE:w
|
||||||
|
UNCOMPRESSED:s -> METABLOCK_DONE:n
|
||||||
|
METABLOCK_DONE:e -> METABLOCK_BEGIN:e [constraint="false"]
|
||||||
|
}
|
||||||
|
INITIALIZE -> METABLOCK_BEGIN
|
||||||
|
METABLOCK_DONE -> DONE
|
||||||
|
|
||||||
|
subgraph cluster_compressed_metablock {
|
||||||
|
style="rounded"
|
||||||
|
label=< <B>COMPRESSED METABLOCK</B> >
|
||||||
|
|
||||||
|
subgraph cluster_command {
|
||||||
|
style="rounded"
|
||||||
|
label=< <B>HOT LOOP</B> >
|
||||||
|
|
||||||
|
_METABLOCK_DONE_PORT_ [shape=point style=invis]
|
||||||
|
|
||||||
|
{
|
||||||
|
// Set different shape for nodes returning from "compressed metablock".
|
||||||
|
node [shape=invhouse]; CMD_INNER CMD_POST_DECODE_LITERALS;
|
||||||
|
CMD_POST_WRAP_COPY; CMD_INNER_WRITE; CMD_POST_WRITE_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMD_BEGIN -> CMD_INNER -> CMD_POST_DECODE_LITERALS -> CMD_POST_WRAP_COPY
|
||||||
|
|
||||||
|
// IO ("write") nodes are not in the hot loop!
|
||||||
|
CMD_INNER_WRITE [style=dashed]
|
||||||
|
CMD_INNER -> CMD_INNER_WRITE
|
||||||
|
CMD_POST_WRITE_1 [style=dashed]
|
||||||
|
CMD_POST_DECODE_LITERALS -> CMD_POST_WRITE_1
|
||||||
|
CMD_POST_WRITE_2 [style=dashed]
|
||||||
|
CMD_POST_WRAP_COPY -> CMD_POST_WRITE_2
|
||||||
|
|
||||||
|
CMD_POST_WRITE_1 -> CMD_BEGIN:s [constraint="false"]
|
||||||
|
CMD_INNER_WRITE -> {CMD_INNER CMD_POST_DECODE_LITERALS}
|
||||||
|
[constraint="false"]
|
||||||
|
CMD_BEGIN:ne -> CMD_POST_DECODE_LITERALS [constraint="false"]
|
||||||
|
CMD_POST_WRAP_COPY -> CMD_BEGIN [constraint="false"]
|
||||||
|
CMD_POST_DECODE_LITERALS -> CMD_BEGIN:ne [constraint="false"]
|
||||||
|
CMD_POST_WRITE_2 -> CMD_POST_WRAP_COPY [constraint="false"]
|
||||||
|
{rank=same; CMD_BEGIN; CMD_INNER; CMD_POST_DECODE_LITERALS;
|
||||||
|
CMD_POST_WRAP_COPY}
|
||||||
|
{rank=same; CMD_INNER_WRITE; CMD_POST_WRITE_1; CMD_POST_WRITE_2}
|
||||||
|
|
||||||
|
{CMD_INNER CMD_POST_DECODE_LITERALS CMD_POST_WRAP_COPY} ->
|
||||||
|
_METABLOCK_DONE_PORT_ [style=invis]
|
||||||
|
{CMD_INNER_WRITE CMD_POST_WRITE_1} -> _METABLOCK_DONE_PORT_
|
||||||
|
[constraint="false" style=invis]
|
||||||
|
}
|
||||||
|
|
||||||
|
BEFORE_COMPRESSED_METABLOCK_HEADER:s -> HUFFMAN_CODE_0:n
|
||||||
|
HUFFMAN_CODE_0 -> HUFFMAN_CODE_1 -> HUFFMAN_CODE_2 -> HUFFMAN_CODE_3
|
||||||
|
HUFFMAN_CODE_0 -> METABLOCK_HEADER_2 -> CONTEXT_MODES -> CONTEXT_MAP_1
|
||||||
|
CONTEXT_MAP_1 -> CONTEXT_MAP_2 -> TREE_GROUP
|
||||||
|
TREE_GROUP -> BEFORE_COMPRESSED_METABLOCK_BODY:e
|
||||||
|
BEFORE_COMPRESSED_METABLOCK_BODY:s -> CMD_BEGIN:n
|
||||||
|
|
||||||
|
HUFFMAN_CODE_3:e -> HUFFMAN_CODE_0:ne [constraint="false"]
|
||||||
|
{rank=same; HUFFMAN_CODE_0; HUFFMAN_CODE_1; HUFFMAN_CODE_2; HUFFMAN_CODE_3}
|
||||||
|
{rank=same; METABLOCK_HEADER_2; CONTEXT_MODES; CONTEXT_MAP_1; CONTEXT_MAP_2;
|
||||||
|
TREE_GROUP}
|
||||||
|
}
|
||||||
|
METABLOCK_HEADER:e -> BEFORE_COMPRESSED_METABLOCK_HEADER:n
|
||||||
|
|
||||||
|
_METABLOCK_DONE_PORT_ -> METABLOCK_DONE:se
|
||||||
|
[constraint="false" ltail=cluster_command]
|
||||||
|
|
||||||
|
UNINITED [shape=Mdiamond];
|
||||||
|
DONE [shape=Msquare];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BROTLI_STATE_UNINITED,
|
BROTLI_STATE_UNINITED,
|
||||||
|
BROTLI_STATE_LARGE_WINDOW_BITS,
|
||||||
|
BROTLI_STATE_INITIALIZE,
|
||||||
BROTLI_STATE_METABLOCK_BEGIN,
|
BROTLI_STATE_METABLOCK_BEGIN,
|
||||||
BROTLI_STATE_METABLOCK_HEADER,
|
BROTLI_STATE_METABLOCK_HEADER,
|
||||||
BROTLI_STATE_METABLOCK_HEADER_2,
|
BROTLI_STATE_METABLOCK_HEADER_2,
|
||||||
|
@ -36,6 +128,7 @@ typedef enum {
|
||||||
BROTLI_STATE_METABLOCK_DONE,
|
BROTLI_STATE_METABLOCK_DONE,
|
||||||
BROTLI_STATE_COMMAND_POST_WRITE_1,
|
BROTLI_STATE_COMMAND_POST_WRITE_1,
|
||||||
BROTLI_STATE_COMMAND_POST_WRITE_2,
|
BROTLI_STATE_COMMAND_POST_WRITE_2,
|
||||||
|
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER,
|
||||||
BROTLI_STATE_HUFFMAN_CODE_0,
|
BROTLI_STATE_HUFFMAN_CODE_0,
|
||||||
BROTLI_STATE_HUFFMAN_CODE_1,
|
BROTLI_STATE_HUFFMAN_CODE_1,
|
||||||
BROTLI_STATE_HUFFMAN_CODE_2,
|
BROTLI_STATE_HUFFMAN_CODE_2,
|
||||||
|
@ -43,6 +136,7 @@ typedef enum {
|
||||||
BROTLI_STATE_CONTEXT_MAP_1,
|
BROTLI_STATE_CONTEXT_MAP_1,
|
||||||
BROTLI_STATE_CONTEXT_MAP_2,
|
BROTLI_STATE_CONTEXT_MAP_2,
|
||||||
BROTLI_STATE_TREE_GROUP,
|
BROTLI_STATE_TREE_GROUP,
|
||||||
|
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY,
|
||||||
BROTLI_STATE_DONE
|
BROTLI_STATE_DONE
|
||||||
} BrotliRunningState;
|
} BrotliRunningState;
|
||||||
|
|
||||||
|
@ -95,6 +189,50 @@ typedef enum {
|
||||||
BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
|
BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
|
||||||
} BrotliRunningReadBlockLengthState;
|
} BrotliRunningReadBlockLengthState;
|
||||||
|
|
||||||
|
typedef struct BrotliMetablockHeaderArena {
|
||||||
|
BrotliRunningTreeGroupState substate_tree_group;
|
||||||
|
BrotliRunningContextMapState substate_context_map;
|
||||||
|
BrotliRunningHuffmanState substate_huffman;
|
||||||
|
|
||||||
|
uint32_t sub_loop_counter;
|
||||||
|
|
||||||
|
uint32_t repeat_code_len;
|
||||||
|
uint32_t prev_code_len;
|
||||||
|
|
||||||
|
/* For ReadHuffmanCode. */
|
||||||
|
uint32_t symbol;
|
||||||
|
uint32_t repeat;
|
||||||
|
uint32_t space;
|
||||||
|
|
||||||
|
/* Huffman table for "histograms". */
|
||||||
|
HuffmanCode table[32];
|
||||||
|
/* List of heads of symbol chains. */
|
||||||
|
uint16_t* symbol_lists;
|
||||||
|
/* Storage from symbol_lists. */
|
||||||
|
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
|
||||||
|
BROTLI_NUM_COMMAND_SYMBOLS];
|
||||||
|
/* Tails of symbol chains. */
|
||||||
|
int next_symbol[32];
|
||||||
|
uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
|
||||||
|
/* Population counts for the code lengths. */
|
||||||
|
uint16_t code_length_histo[16];
|
||||||
|
|
||||||
|
/* For HuffmanTreeGroupDecode. */
|
||||||
|
int htree_index;
|
||||||
|
HuffmanCode* next;
|
||||||
|
|
||||||
|
/* For DecodeContextMap. */
|
||||||
|
uint32_t context_index;
|
||||||
|
uint32_t max_run_length_prefix;
|
||||||
|
uint32_t code;
|
||||||
|
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
|
||||||
|
} BrotliMetablockHeaderArena;
|
||||||
|
|
||||||
|
typedef struct BrotliMetablockBodyArena {
|
||||||
|
uint8_t dist_extra_bits[544];
|
||||||
|
uint32_t dist_offset[544];
|
||||||
|
} BrotliMetablockBodyArena;
|
||||||
|
|
||||||
struct BrotliDecoderStateStruct {
|
struct BrotliDecoderStateStruct {
|
||||||
BrotliRunningState state;
|
BrotliRunningState state;
|
||||||
|
|
||||||
|
@ -107,7 +245,8 @@ struct BrotliDecoderStateStruct {
|
||||||
brotli_free_func free_func;
|
brotli_free_func free_func;
|
||||||
void* memory_manager_opaque;
|
void* memory_manager_opaque;
|
||||||
|
|
||||||
/* Temporary storage for remaining input. */
|
/* Temporary storage for remaining input. Brotli stream format is designed in
|
||||||
|
a way, that 64 bits are enough to make progress in decoding. */
|
||||||
union {
|
union {
|
||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
uint8_t u8[8];
|
uint8_t u8[8];
|
||||||
|
@ -122,27 +261,25 @@ struct BrotliDecoderStateStruct {
|
||||||
int dist_rb_idx;
|
int dist_rb_idx;
|
||||||
int dist_rb[4];
|
int dist_rb[4];
|
||||||
int error_code;
|
int error_code;
|
||||||
uint32_t sub_loop_counter;
|
|
||||||
uint8_t* ringbuffer;
|
uint8_t* ringbuffer;
|
||||||
uint8_t* ringbuffer_end;
|
uint8_t* ringbuffer_end;
|
||||||
HuffmanCode* htree_command;
|
HuffmanCode* htree_command;
|
||||||
const uint8_t* context_lookup1;
|
const uint8_t* context_lookup;
|
||||||
const uint8_t* context_lookup2;
|
|
||||||
uint8_t* context_map_slice;
|
uint8_t* context_map_slice;
|
||||||
uint8_t* dist_context_map_slice;
|
uint8_t* dist_context_map_slice;
|
||||||
|
|
||||||
/* This ring buffer holds a few past copy distances that will be used by */
|
/* This ring buffer holds a few past copy distances that will be used by
|
||||||
/* some special distance codes. */
|
some special distance codes. */
|
||||||
HuffmanTreeGroup literal_hgroup;
|
HuffmanTreeGroup literal_hgroup;
|
||||||
HuffmanTreeGroup insert_copy_hgroup;
|
HuffmanTreeGroup insert_copy_hgroup;
|
||||||
HuffmanTreeGroup distance_hgroup;
|
HuffmanTreeGroup distance_hgroup;
|
||||||
HuffmanCode* block_type_trees;
|
HuffmanCode* block_type_trees;
|
||||||
HuffmanCode* block_len_trees;
|
HuffmanCode* block_len_trees;
|
||||||
/* This is true if the literal context map histogram type always matches the
|
/* This is true if the literal context map histogram type always matches the
|
||||||
block type. It is then not needed to keep the context (faster decoding). */
|
block type. It is then not needed to keep the context (faster decoding). */
|
||||||
int trivial_literal_context;
|
int trivial_literal_context;
|
||||||
/* Distance context is actual after command is decoded and before distance
|
/* Distance context is actual after command is decoded and before distance is
|
||||||
is computed. After distance computation it is used as a temporary variable. */
|
computed. After distance computation it is used as a temporary variable. */
|
||||||
int distance_context;
|
int distance_context;
|
||||||
int meta_block_remaining_len;
|
int meta_block_remaining_len;
|
||||||
uint32_t block_length_index;
|
uint32_t block_length_index;
|
||||||
|
@ -151,59 +288,27 @@ struct BrotliDecoderStateStruct {
|
||||||
uint32_t block_type_rb[6];
|
uint32_t block_type_rb[6];
|
||||||
uint32_t distance_postfix_bits;
|
uint32_t distance_postfix_bits;
|
||||||
uint32_t num_direct_distance_codes;
|
uint32_t num_direct_distance_codes;
|
||||||
int distance_postfix_mask;
|
|
||||||
uint32_t num_dist_htrees;
|
uint32_t num_dist_htrees;
|
||||||
uint8_t* dist_context_map;
|
uint8_t* dist_context_map;
|
||||||
HuffmanCode* literal_htree;
|
HuffmanCode* literal_htree;
|
||||||
uint8_t dist_htree_index;
|
uint8_t dist_htree_index;
|
||||||
uint32_t repeat_code_len;
|
|
||||||
uint32_t prev_code_len;
|
|
||||||
|
|
||||||
int copy_length;
|
int copy_length;
|
||||||
int distance_code;
|
int distance_code;
|
||||||
|
|
||||||
/* For partial write operations */
|
/* For partial write operations. */
|
||||||
size_t rb_roundtrips; /* How many times we went around the ring-buffer */
|
size_t rb_roundtrips; /* how many times we went around the ring-buffer */
|
||||||
size_t partial_pos_out; /* How much output to the user in total */
|
size_t partial_pos_out; /* how much output to the user in total */
|
||||||
|
|
||||||
/* For ReadHuffmanCode */
|
/* For InverseMoveToFrontTransform. */
|
||||||
uint32_t symbol;
|
|
||||||
uint32_t repeat;
|
|
||||||
uint32_t space;
|
|
||||||
|
|
||||||
HuffmanCode table[32];
|
|
||||||
/* List of heads of symbol chains. */
|
|
||||||
uint16_t* symbol_lists;
|
|
||||||
/* Storage from symbol_lists. */
|
|
||||||
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
|
|
||||||
BROTLI_NUM_COMMAND_SYMBOLS];
|
|
||||||
/* Tails of symbol chains. */
|
|
||||||
int next_symbol[32];
|
|
||||||
uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
|
|
||||||
/* Population counts for the code lengths */
|
|
||||||
uint16_t code_length_histo[16];
|
|
||||||
|
|
||||||
/* For HuffmanTreeGroupDecode */
|
|
||||||
int htree_index;
|
|
||||||
HuffmanCode* next;
|
|
||||||
|
|
||||||
/* For DecodeContextMap */
|
|
||||||
uint32_t context_index;
|
|
||||||
uint32_t max_run_length_prefix;
|
|
||||||
uint32_t code;
|
|
||||||
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
|
|
||||||
|
|
||||||
/* For InverseMoveToFrontTransform */
|
|
||||||
uint32_t mtf_upper_bound;
|
uint32_t mtf_upper_bound;
|
||||||
uint32_t mtf[64 + 1];
|
uint32_t mtf[64 + 1];
|
||||||
|
|
||||||
/* less used attributes are in the end of this struct */
|
/* Less used attributes are at the end of this struct. */
|
||||||
/* States inside function calls */
|
|
||||||
|
/* States inside function calls. */
|
||||||
BrotliRunningMetablockHeaderState substate_metablock_header;
|
BrotliRunningMetablockHeaderState substate_metablock_header;
|
||||||
BrotliRunningTreeGroupState substate_tree_group;
|
|
||||||
BrotliRunningContextMapState substate_context_map;
|
|
||||||
BrotliRunningUncompressedState substate_uncompressed;
|
BrotliRunningUncompressedState substate_uncompressed;
|
||||||
BrotliRunningHuffmanState substate_huffman;
|
|
||||||
BrotliRunningDecodeUint8State substate_decode_uint8;
|
BrotliRunningDecodeUint8State substate_decode_uint8;
|
||||||
BrotliRunningReadBlockLengthState substate_read_block_length;
|
BrotliRunningReadBlockLengthState substate_read_block_length;
|
||||||
|
|
||||||
|
@ -212,6 +317,7 @@ struct BrotliDecoderStateStruct {
|
||||||
unsigned int is_metadata : 1;
|
unsigned int is_metadata : 1;
|
||||||
unsigned int should_wrap_ringbuffer : 1;
|
unsigned int should_wrap_ringbuffer : 1;
|
||||||
unsigned int canny_ringbuffer_allocation : 1;
|
unsigned int canny_ringbuffer_allocation : 1;
|
||||||
|
unsigned int large_window : 1;
|
||||||
unsigned int size_nibbles : 8;
|
unsigned int size_nibbles : 8;
|
||||||
uint32_t window_bits;
|
uint32_t window_bits;
|
||||||
|
|
||||||
|
@ -220,25 +326,37 @@ struct BrotliDecoderStateStruct {
|
||||||
uint32_t num_literal_htrees;
|
uint32_t num_literal_htrees;
|
||||||
uint8_t* context_map;
|
uint8_t* context_map;
|
||||||
uint8_t* context_modes;
|
uint8_t* context_modes;
|
||||||
|
|
||||||
const BrotliDictionary* dictionary;
|
const BrotliDictionary* dictionary;
|
||||||
|
const BrotliTransforms* transforms;
|
||||||
|
|
||||||
uint32_t trivial_literal_contexts[8]; /* 256 bits */
|
uint32_t trivial_literal_contexts[8]; /* 256 bits */
|
||||||
|
|
||||||
|
union {
|
||||||
|
BrotliMetablockHeaderArena header;
|
||||||
|
BrotliMetablockBodyArena body;
|
||||||
|
} arena;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal;
|
typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal;
|
||||||
#define BrotliDecoderState BrotliDecoderStateInternal
|
#define BrotliDecoderState BrotliDecoderStateInternal
|
||||||
|
|
||||||
BROTLI_INTERNAL void BrotliDecoderStateInit(BrotliDecoderState* s);
|
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||||
BROTLI_INTERNAL void BrotliDecoderStateInitWithCustomAllocators(
|
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
|
||||||
BrotliDecoderState* s, brotli_alloc_func alloc_func,
|
|
||||||
brotli_free_func free_func, void* opaque);
|
|
||||||
BROTLI_INTERNAL void BrotliDecoderStateCleanup(BrotliDecoderState* s);
|
BROTLI_INTERNAL void BrotliDecoderStateCleanup(BrotliDecoderState* s);
|
||||||
BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s);
|
BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s);
|
||||||
BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock(
|
BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock(
|
||||||
BrotliDecoderState* s);
|
BrotliDecoderState* s);
|
||||||
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
|
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
|
||||||
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size,
|
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size_max,
|
||||||
uint32_t ntrees);
|
uint32_t alphabet_size_limit, uint32_t ntrees);
|
||||||
|
|
||||||
|
#define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
|
||||||
|
|
||||||
|
#define BROTLI_DECODER_FREE(S, X) { \
|
||||||
|
S->free_func(S->memory_manager_opaque, X); \
|
||||||
|
X = NULL; \
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|
|
@ -1,300 +0,0 @@
|
||||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
Distributed under MIT license.
|
|
||||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Transformations on dictionary words. */
|
|
||||||
|
|
||||||
#ifndef BROTLI_DEC_TRANSFORM_H_
|
|
||||||
#define BROTLI_DEC_TRANSFORM_H_
|
|
||||||
|
|
||||||
#include <brotli/types.h>
|
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum WordTransformType {
|
|
||||||
kIdentity = 0,
|
|
||||||
kOmitLast1 = 1,
|
|
||||||
kOmitLast2 = 2,
|
|
||||||
kOmitLast3 = 3,
|
|
||||||
kOmitLast4 = 4,
|
|
||||||
kOmitLast5 = 5,
|
|
||||||
kOmitLast6 = 6,
|
|
||||||
kOmitLast7 = 7,
|
|
||||||
kOmitLast8 = 8,
|
|
||||||
kOmitLast9 = 9,
|
|
||||||
kUppercaseFirst = 10,
|
|
||||||
kUppercaseAll = 11,
|
|
||||||
kOmitFirst1 = 12,
|
|
||||||
kOmitFirst2 = 13,
|
|
||||||
kOmitFirst3 = 14,
|
|
||||||
kOmitFirst4 = 15,
|
|
||||||
kOmitFirst5 = 16,
|
|
||||||
kOmitFirst6 = 17,
|
|
||||||
kOmitFirst7 = 18,
|
|
||||||
kOmitFirst8 = 19,
|
|
||||||
kOmitFirst9 = 20
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const uint8_t prefix_id;
|
|
||||||
const uint8_t transform;
|
|
||||||
const uint8_t suffix_id;
|
|
||||||
} Transform;
|
|
||||||
|
|
||||||
static const char kPrefixSuffix[208] =
|
|
||||||
"\0 \0, \0 of the \0 of \0s \0.\0 and \0 in \0\"\0 to \0\">\0\n\0. \0]\0"
|
|
||||||
" for \0 a \0 that \0\'\0 with \0 from \0 by \0(\0. The \0 on \0 as \0"
|
|
||||||
" is \0ing \0\n\t\0:\0ed \0=\"\0 at \0ly \0,\0=\'\0.com/\0. This \0"
|
|
||||||
" not \0er \0al \0ful \0ive \0less \0est \0ize \0\xc2\xa0\0ous ";
|
|
||||||
|
|
||||||
enum {
|
|
||||||
/* EMPTY = ""
|
|
||||||
SP = " "
|
|
||||||
DQUOT = "\""
|
|
||||||
SQUOT = "'"
|
|
||||||
CLOSEBR = "]"
|
|
||||||
OPEN = "("
|
|
||||||
SLASH = "/"
|
|
||||||
NBSP = non-breaking space "\0xc2\xa0"
|
|
||||||
*/
|
|
||||||
kPFix_EMPTY = 0,
|
|
||||||
kPFix_SP = 1,
|
|
||||||
kPFix_COMMASP = 3,
|
|
||||||
kPFix_SPofSPtheSP = 6,
|
|
||||||
kPFix_SPtheSP = 9,
|
|
||||||
kPFix_eSP = 12,
|
|
||||||
kPFix_SPofSP = 15,
|
|
||||||
kPFix_sSP = 20,
|
|
||||||
kPFix_DOT = 23,
|
|
||||||
kPFix_SPandSP = 25,
|
|
||||||
kPFix_SPinSP = 31,
|
|
||||||
kPFix_DQUOT = 36,
|
|
||||||
kPFix_SPtoSP = 38,
|
|
||||||
kPFix_DQUOTGT = 43,
|
|
||||||
kPFix_NEWLINE = 46,
|
|
||||||
kPFix_DOTSP = 48,
|
|
||||||
kPFix_CLOSEBR = 51,
|
|
||||||
kPFix_SPforSP = 53,
|
|
||||||
kPFix_SPaSP = 59,
|
|
||||||
kPFix_SPthatSP = 63,
|
|
||||||
kPFix_SQUOT = 70,
|
|
||||||
kPFix_SPwithSP = 72,
|
|
||||||
kPFix_SPfromSP = 79,
|
|
||||||
kPFix_SPbySP = 86,
|
|
||||||
kPFix_OPEN = 91,
|
|
||||||
kPFix_DOTSPTheSP = 93,
|
|
||||||
kPFix_SPonSP = 100,
|
|
||||||
kPFix_SPasSP = 105,
|
|
||||||
kPFix_SPisSP = 110,
|
|
||||||
kPFix_ingSP = 115,
|
|
||||||
kPFix_NEWLINETAB = 120,
|
|
||||||
kPFix_COLON = 123,
|
|
||||||
kPFix_edSP = 125,
|
|
||||||
kPFix_EQDQUOT = 129,
|
|
||||||
kPFix_SPatSP = 132,
|
|
||||||
kPFix_lySP = 137,
|
|
||||||
kPFix_COMMA = 141,
|
|
||||||
kPFix_EQSQUOT = 143,
|
|
||||||
kPFix_DOTcomSLASH = 146,
|
|
||||||
kPFix_DOTSPThisSP = 152,
|
|
||||||
kPFix_SPnotSP = 160,
|
|
||||||
kPFix_erSP = 166,
|
|
||||||
kPFix_alSP = 170,
|
|
||||||
kPFix_fulSP = 174,
|
|
||||||
kPFix_iveSP = 179,
|
|
||||||
kPFix_lessSP = 184,
|
|
||||||
kPFix_estSP = 190,
|
|
||||||
kPFix_izeSP = 195,
|
|
||||||
kPFix_NBSP = 200,
|
|
||||||
kPFix_ousSP = 203
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Transform kTransforms[] = {
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SP },
|
|
||||||
{ kPFix_SP, kIdentity, kPFix_SP },
|
|
||||||
{ kPFix_EMPTY, kOmitFirst1, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_SP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPtheSP },
|
|
||||||
{ kPFix_SP, kIdentity, kPFix_EMPTY },
|
|
||||||
{ kPFix_sSP, kIdentity, kPFix_SP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPofSP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPandSP },
|
|
||||||
{ kPFix_EMPTY, kOmitFirst2, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kOmitLast1, kPFix_EMPTY },
|
|
||||||
{ kPFix_COMMASP, kIdentity, kPFix_SP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_COMMASP },
|
|
||||||
{ kPFix_SP, kUppercaseFirst, kPFix_SP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPinSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPtoSP },
|
|
||||||
{ kPFix_eSP, kIdentity, kPFix_SP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_DQUOT },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_DOT },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_DQUOTGT },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_NEWLINE },
|
|
||||||
{ kPFix_EMPTY, kOmitLast3, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_CLOSEBR },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPforSP },
|
|
||||||
{ kPFix_EMPTY, kOmitFirst3, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kOmitLast2, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPaSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPthatSP },
|
|
||||||
{ kPFix_SP, kUppercaseFirst, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_DOTSP },
|
|
||||||
{ kPFix_DOT, kIdentity, kPFix_EMPTY },
|
|
||||||
{ kPFix_SP, kIdentity, kPFix_COMMASP },
|
|
||||||
{ kPFix_EMPTY, kOmitFirst4, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPwithSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SQUOT },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPfromSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPbySP },
|
|
||||||
{ kPFix_EMPTY, kOmitFirst5, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kOmitFirst6, kPFix_EMPTY },
|
|
||||||
{ kPFix_SPtheSP, kIdentity, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kOmitLast4, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_DOTSPTheSP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPonSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPasSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPisSP },
|
|
||||||
{ kPFix_EMPTY, kOmitLast7, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kOmitLast1, kPFix_ingSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_NEWLINETAB },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_COLON },
|
|
||||||
{ kPFix_SP, kIdentity, kPFix_DOTSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_edSP },
|
|
||||||
{ kPFix_EMPTY, kOmitFirst9, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kOmitFirst7, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kOmitLast6, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_OPEN },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_COMMASP },
|
|
||||||
{ kPFix_EMPTY, kOmitLast8, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPatSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_lySP },
|
|
||||||
{ kPFix_SPtheSP, kIdentity, kPFix_SPofSP },
|
|
||||||
{ kPFix_EMPTY, kOmitLast5, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kOmitLast9, kPFix_EMPTY },
|
|
||||||
{ kPFix_SP, kUppercaseFirst, kPFix_COMMASP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_DQUOT },
|
|
||||||
{ kPFix_DOT, kIdentity, kPFix_OPEN },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_SP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_DQUOTGT },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_EQDQUOT },
|
|
||||||
{ kPFix_SP, kIdentity, kPFix_DOT },
|
|
||||||
{ kPFix_DOTcomSLASH, kIdentity, kPFix_EMPTY },
|
|
||||||
{ kPFix_SPtheSP, kIdentity, kPFix_SPofSPtheSP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_SQUOT },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_DOTSPThisSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_COMMA },
|
|
||||||
{ kPFix_DOT, kIdentity, kPFix_SP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_OPEN },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_DOT },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_SPnotSP },
|
|
||||||
{ kPFix_SP, kIdentity, kPFix_EQDQUOT },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_erSP },
|
|
||||||
{ kPFix_SP, kUppercaseAll, kPFix_SP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_alSP },
|
|
||||||
{ kPFix_SP, kUppercaseAll, kPFix_EMPTY },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_EQSQUOT },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_DQUOT },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_DOTSP },
|
|
||||||
{ kPFix_SP, kIdentity, kPFix_OPEN },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_fulSP },
|
|
||||||
{ kPFix_SP, kUppercaseFirst, kPFix_DOTSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_iveSP },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_lessSP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_SQUOT },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_estSP },
|
|
||||||
{ kPFix_SP, kUppercaseFirst, kPFix_DOT },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_DQUOTGT },
|
|
||||||
{ kPFix_SP, kIdentity, kPFix_EQSQUOT },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_COMMA },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_izeSP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_DOT },
|
|
||||||
{ kPFix_NBSP, kIdentity, kPFix_EMPTY },
|
|
||||||
{ kPFix_SP, kIdentity, kPFix_COMMA },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_EQDQUOT },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_EQDQUOT },
|
|
||||||
{ kPFix_EMPTY, kIdentity, kPFix_ousSP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_COMMASP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseFirst, kPFix_EQSQUOT },
|
|
||||||
{ kPFix_SP, kUppercaseFirst, kPFix_COMMA },
|
|
||||||
{ kPFix_SP, kUppercaseAll, kPFix_EQDQUOT },
|
|
||||||
{ kPFix_SP, kUppercaseAll, kPFix_COMMASP },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_COMMA },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_OPEN },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_DOTSP },
|
|
||||||
{ kPFix_SP, kUppercaseAll, kPFix_DOT },
|
|
||||||
{ kPFix_EMPTY, kUppercaseAll, kPFix_EQSQUOT },
|
|
||||||
{ kPFix_SP, kUppercaseAll, kPFix_DOTSP },
|
|
||||||
{ kPFix_SP, kUppercaseFirst, kPFix_EQDQUOT },
|
|
||||||
{ kPFix_SP, kUppercaseAll, kPFix_EQSQUOT },
|
|
||||||
{ kPFix_SP, kUppercaseFirst, kPFix_EQSQUOT },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int kNumTransforms = sizeof(kTransforms) / sizeof(kTransforms[0]);
|
|
||||||
|
|
||||||
static int ToUpperCase(uint8_t* p) {
|
|
||||||
if (p[0] < 0xc0) {
|
|
||||||
if (p[0] >= 'a' && p[0] <= 'z') {
|
|
||||||
p[0] ^= 32;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* An overly simplified uppercasing model for UTF-8. */
|
|
||||||
if (p[0] < 0xe0) {
|
|
||||||
p[1] ^= 32;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
/* An arbitrary transform for three byte characters. */
|
|
||||||
p[2] ^= 5;
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BROTLI_NOINLINE int TransformDictionaryWord(
|
|
||||||
uint8_t* dst, const uint8_t* word, int len, int transform) {
|
|
||||||
int idx = 0;
|
|
||||||
{
|
|
||||||
const char* prefix = &kPrefixSuffix[kTransforms[transform].prefix_id];
|
|
||||||
while (*prefix) { dst[idx++] = (uint8_t)*prefix++; }
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const int t = kTransforms[transform].transform;
|
|
||||||
int i = 0;
|
|
||||||
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++]; }
|
|
||||||
if (t == kUppercaseFirst) {
|
|
||||||
ToUpperCase(&dst[idx - len]);
|
|
||||||
} else if (t == kUppercaseAll) {
|
|
||||||
uint8_t* uppercase = &dst[idx - len];
|
|
||||||
while (len > 0) {
|
|
||||||
int step = ToUpperCase(uppercase);
|
|
||||||
uppercase += step;
|
|
||||||
len -= step;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const char* suffix = &kPrefixSuffix[kTransforms[transform].suffix_id];
|
|
||||||
while (*suffix) { dst[idx++] = (uint8_t)*suffix++; }
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* BROTLI_DEC_TRANSFORM_H_ */
|
|
|
@ -9,12 +9,13 @@
|
||||||
#include "./backward_references.h"
|
#include "./backward_references.h"
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/context.h"
|
||||||
#include "../common/dictionary.h"
|
#include "../common/dictionary.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./command.h"
|
#include "./command.h"
|
||||||
#include "./dictionary_hash.h"
|
#include "./dictionary_hash.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./quality.h"
|
#include "./quality.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -49,6 +50,7 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
|
||||||
#define CAT(a, b) a ## b
|
#define CAT(a, b) a ## b
|
||||||
#define FN(X) EXPAND_CAT(X, HASHER())
|
#define FN(X) EXPAND_CAT(X, HASHER())
|
||||||
#define EXPORT_FN(X) EXPAND_CAT(X, EXPAND_CAT(PREFIX(), HASHER()))
|
#define EXPORT_FN(X) EXPAND_CAT(X, EXPAND_CAT(PREFIX(), HASHER()))
|
||||||
|
|
||||||
#define PREFIX() N
|
#define PREFIX() N
|
||||||
|
|
||||||
#define HASHER() H2
|
#define HASHER() H2
|
||||||
|
@ -96,30 +98,39 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
|
||||||
#include "./backward_references_inc.h"
|
#include "./backward_references_inc.h"
|
||||||
#undef HASHER
|
#undef HASHER
|
||||||
|
|
||||||
|
#define HASHER() H35
|
||||||
|
/* NOLINTNEXTLINE(build/include) */
|
||||||
|
#include "./backward_references_inc.h"
|
||||||
|
#undef HASHER
|
||||||
|
|
||||||
|
#define HASHER() H55
|
||||||
|
/* NOLINTNEXTLINE(build/include) */
|
||||||
|
#include "./backward_references_inc.h"
|
||||||
|
#undef HASHER
|
||||||
|
|
||||||
|
#define HASHER() H65
|
||||||
|
/* NOLINTNEXTLINE(build/include) */
|
||||||
|
#include "./backward_references_inc.h"
|
||||||
|
#undef HASHER
|
||||||
|
|
||||||
#undef PREFIX
|
#undef PREFIX
|
||||||
|
|
||||||
#undef EXPORT_FN
|
#undef EXPORT_FN
|
||||||
#undef FN
|
#undef FN
|
||||||
#undef CAT
|
#undef CAT
|
||||||
#undef EXPAND_CAT
|
#undef EXPAND_CAT
|
||||||
|
|
||||||
void BrotliCreateBackwardReferences(const BrotliDictionary* dictionary,
|
void BrotliCreateBackwardReferences(size_t num_bytes,
|
||||||
size_t num_bytes,
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||||
size_t position,
|
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||||
const uint8_t* ringbuffer,
|
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||||
size_t ringbuffer_mask,
|
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||||
const BrotliEncoderParams* params,
|
|
||||||
HasherHandle hasher,
|
|
||||||
int* dist_cache,
|
|
||||||
size_t* last_insert_len,
|
|
||||||
Command* commands,
|
|
||||||
size_t* num_commands,
|
|
||||||
size_t* num_literals) {
|
|
||||||
switch (params->hasher.type) {
|
switch (params->hasher.type) {
|
||||||
#define CASE_(N) \
|
#define CASE_(N) \
|
||||||
case N: \
|
case N: \
|
||||||
CreateBackwardReferencesNH ## N(dictionary, \
|
CreateBackwardReferencesNH ## N(num_bytes, \
|
||||||
kStaticDictionaryHash, num_bytes, position, ringbuffer, \
|
position, ringbuffer, ringbuffer_mask, \
|
||||||
ringbuffer_mask, params, hasher, dist_cache, \
|
literal_context_lut, params, hasher, dist_cache, \
|
||||||
last_insert_len, commands, num_commands, num_literals); \
|
last_insert_len, commands, num_commands, num_literals); \
|
||||||
return;
|
return;
|
||||||
FOR_GENERIC_HASHERS(CASE_)
|
FOR_GENERIC_HASHERS(CASE_)
|
||||||
|
|
|
@ -10,11 +10,12 @@
|
||||||
#define BROTLI_ENC_BACKWARD_REFERENCES_H_
|
#define BROTLI_ENC_BACKWARD_REFERENCES_H_
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/context.h"
|
||||||
#include "../common/dictionary.h"
|
#include "../common/dictionary.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./command.h"
|
#include "./command.h"
|
||||||
#include "./hash.h"
|
#include "./hash.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./quality.h"
|
#include "./quality.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -25,12 +26,11 @@ extern "C" {
|
||||||
initially the total amount of commands output by previous
|
initially the total amount of commands output by previous
|
||||||
CreateBackwardReferences calls, and must be incremented by the amount written
|
CreateBackwardReferences calls, and must be incremented by the amount written
|
||||||
by this call. */
|
by this call. */
|
||||||
BROTLI_INTERNAL void BrotliCreateBackwardReferences(
|
BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes,
|
||||||
const BrotliDictionary* dictionary, size_t num_bytes, size_t position,
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||||
const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||||
const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
|
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||||
size_t* last_insert_len, Command* commands, size_t* num_commands,
|
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||||
size_t* num_literals);
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|
|
@ -11,13 +11,15 @@
|
||||||
#include <string.h> /* memcpy, memset */
|
#include <string.h> /* memcpy, memset */
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/context.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./command.h"
|
#include "./command.h"
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
#include "./find_match_length.h"
|
#include "./find_match_length.h"
|
||||||
#include "./literal_cost.h"
|
#include "./literal_cost.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
#include "./params.h"
|
||||||
#include "./prefix.h"
|
#include "./prefix.h"
|
||||||
#include "./quality.h"
|
#include "./quality.h"
|
||||||
|
|
||||||
|
@ -25,6 +27,9 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
|
||||||
|
#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
|
||||||
|
|
||||||
static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */
|
static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */
|
||||||
|
|
||||||
static const uint32_t kDistanceCacheIndex[] = {
|
static const uint32_t kDistanceCacheIndex[] = {
|
||||||
|
@ -39,40 +44,41 @@ void BrotliInitZopfliNodes(ZopfliNode* array, size_t length) {
|
||||||
size_t i;
|
size_t i;
|
||||||
stub.length = 1;
|
stub.length = 1;
|
||||||
stub.distance = 0;
|
stub.distance = 0;
|
||||||
stub.insert_length = 0;
|
stub.dcode_insert_length = 0;
|
||||||
stub.u.cost = kInfinity;
|
stub.u.cost = kInfinity;
|
||||||
for (i = 0; i < length; ++i) array[i] = stub;
|
for (i = 0; i < length; ++i) array[i] = stub;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) {
|
static BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) {
|
||||||
return self->length & 0xffffff;
|
return self->length & 0x1FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) {
|
static BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) {
|
||||||
const uint32_t modifier = self->length >> 24;
|
const uint32_t modifier = self->length >> 25;
|
||||||
return ZopfliNodeCopyLength(self) + 9u - modifier;
|
return ZopfliNodeCopyLength(self) + 9u - modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) {
|
static BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) {
|
||||||
return self->distance & 0x1ffffff;
|
return self->distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) {
|
static BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) {
|
||||||
const uint32_t short_code = self->distance >> 25;
|
const uint32_t short_code = self->dcode_insert_length >> 27;
|
||||||
return short_code == 0 ?
|
return short_code == 0 ?
|
||||||
ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 :
|
ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 :
|
||||||
short_code - 1;
|
short_code - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
|
static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
|
||||||
return ZopfliNodeCopyLength(self) + self->insert_length;
|
return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Histogram based cost model for zopflification. */
|
/* Histogram based cost model for zopflification. */
|
||||||
typedef struct ZopfliCostModel {
|
typedef struct ZopfliCostModel {
|
||||||
/* The insert and copy length symbols. */
|
/* The insert and copy length symbols. */
|
||||||
float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS];
|
float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||||
float cost_dist_[BROTLI_NUM_DISTANCE_SYMBOLS];
|
float* cost_dist_;
|
||||||
|
uint32_t distance_histogram_size;
|
||||||
/* Cumulative costs of literals per position in the stream. */
|
/* Cumulative costs of literals per position in the stream. */
|
||||||
float* literal_costs_;
|
float* literal_costs_;
|
||||||
float min_cost_cmd_;
|
float min_cost_cmd_;
|
||||||
|
@ -80,28 +86,41 @@ typedef struct ZopfliCostModel {
|
||||||
} ZopfliCostModel;
|
} ZopfliCostModel;
|
||||||
|
|
||||||
static void InitZopfliCostModel(
|
static void InitZopfliCostModel(
|
||||||
MemoryManager* m, ZopfliCostModel* self, size_t num_bytes) {
|
MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
|
||||||
|
size_t num_bytes) {
|
||||||
self->num_bytes_ = num_bytes;
|
self->num_bytes_ = num_bytes;
|
||||||
self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
|
self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
|
||||||
|
self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
|
||||||
|
self->distance_histogram_size = dist->alphabet_size_limit;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) {
|
static void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) {
|
||||||
BROTLI_FREE(m, self->literal_costs_);
|
BROTLI_FREE(m, self->literal_costs_);
|
||||||
|
BROTLI_FREE(m, self->cost_dist_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetCost(const uint32_t* histogram, size_t histogram_size,
|
static void SetCost(const uint32_t* histogram, size_t histogram_size,
|
||||||
float* cost) {
|
BROTLI_BOOL literal_histogram, float* cost) {
|
||||||
size_t sum = 0;
|
size_t sum = 0;
|
||||||
|
size_t missing_symbol_sum;
|
||||||
float log2sum;
|
float log2sum;
|
||||||
|
float missing_symbol_cost;
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < histogram_size; i++) {
|
for (i = 0; i < histogram_size; i++) {
|
||||||
sum += histogram[i];
|
sum += histogram[i];
|
||||||
}
|
}
|
||||||
log2sum = (float)FastLog2(sum);
|
log2sum = (float)FastLog2(sum);
|
||||||
|
missing_symbol_sum = sum;
|
||||||
|
if (!literal_histogram) {
|
||||||
|
for (i = 0; i < histogram_size; i++) {
|
||||||
|
if (histogram[i] == 0) missing_symbol_sum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
missing_symbol_cost = (float)FastLog2(missing_symbol_sum) + 2;
|
||||||
for (i = 0; i < histogram_size; i++) {
|
for (i = 0; i < histogram_size; i++) {
|
||||||
if (histogram[i] == 0) {
|
if (histogram[i] == 0) {
|
||||||
cost[i] = log2sum + 2;
|
cost[i] = missing_symbol_cost;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +141,7 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||||
size_t last_insert_len) {
|
size_t last_insert_len) {
|
||||||
uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||||
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
|
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||||
uint32_t histogram_dist[BROTLI_NUM_DISTANCE_SYMBOLS];
|
uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
|
||||||
float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||||
size_t pos = position - last_insert_len;
|
size_t pos = position - last_insert_len;
|
||||||
float min_cost_cmd = kInfinity;
|
float min_cost_cmd = kInfinity;
|
||||||
|
@ -136,7 +155,7 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||||
for (i = 0; i < num_commands; i++) {
|
for (i = 0; i < num_commands; i++) {
|
||||||
size_t inslength = commands[i].insert_len_;
|
size_t inslength = commands[i].insert_len_;
|
||||||
size_t copylength = CommandCopyLen(&commands[i]);
|
size_t copylength = CommandCopyLen(&commands[i]);
|
||||||
size_t distcode = commands[i].dist_prefix_;
|
size_t distcode = commands[i].dist_prefix_ & 0x3FF;
|
||||||
size_t cmdcode = commands[i].cmd_prefix_;
|
size_t cmdcode = commands[i].cmd_prefix_;
|
||||||
size_t j;
|
size_t j;
|
||||||
|
|
||||||
|
@ -150,9 +169,12 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||||
pos += inslength + copylength;
|
pos += inslength + copylength;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, cost_literal);
|
SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
|
||||||
SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, cost_cmd);
|
cost_literal);
|
||||||
SetCost(histogram_dist, BROTLI_NUM_DISTANCE_SYMBOLS, self->cost_dist_);
|
SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
|
||||||
|
cost_cmd);
|
||||||
|
SetCost(histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
|
||||||
|
self->cost_dist_);
|
||||||
|
|
||||||
for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
|
for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
|
||||||
min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]);
|
min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]);
|
||||||
|
@ -161,11 +183,14 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||||
|
|
||||||
{
|
{
|
||||||
float* literal_costs = self->literal_costs_;
|
float* literal_costs = self->literal_costs_;
|
||||||
|
float literal_carry = 0.0;
|
||||||
size_t num_bytes = self->num_bytes_;
|
size_t num_bytes = self->num_bytes_;
|
||||||
literal_costs[0] = 0.0;
|
literal_costs[0] = 0.0;
|
||||||
for (i = 0; i < num_bytes; ++i) {
|
for (i = 0; i < num_bytes; ++i) {
|
||||||
literal_costs[i + 1] = literal_costs[i] +
|
literal_carry +=
|
||||||
cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
||||||
|
literal_costs[i + 1] = literal_costs[i] + literal_carry;
|
||||||
|
literal_carry -= literal_costs[i + 1] - literal_costs[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,6 +200,7 @@ static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
|
||||||
const uint8_t* ringbuffer,
|
const uint8_t* ringbuffer,
|
||||||
size_t ringbuffer_mask) {
|
size_t ringbuffer_mask) {
|
||||||
float* literal_costs = self->literal_costs_;
|
float* literal_costs = self->literal_costs_;
|
||||||
|
float literal_carry = 0.0;
|
||||||
float* cost_dist = self->cost_dist_;
|
float* cost_dist = self->cost_dist_;
|
||||||
float* cost_cmd = self->cost_cmd_;
|
float* cost_cmd = self->cost_cmd_;
|
||||||
size_t num_bytes = self->num_bytes_;
|
size_t num_bytes = self->num_bytes_;
|
||||||
|
@ -183,12 +209,14 @@ static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
|
||||||
ringbuffer, &literal_costs[1]);
|
ringbuffer, &literal_costs[1]);
|
||||||
literal_costs[0] = 0.0;
|
literal_costs[0] = 0.0;
|
||||||
for (i = 0; i < num_bytes; ++i) {
|
for (i = 0; i < num_bytes; ++i) {
|
||||||
literal_costs[i + 1] += literal_costs[i];
|
literal_carry += literal_costs[i + 1];
|
||||||
|
literal_costs[i + 1] = literal_costs[i] + literal_carry;
|
||||||
|
literal_carry -= literal_costs[i + 1] - literal_costs[i];
|
||||||
}
|
}
|
||||||
for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
|
for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
|
||||||
cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i);
|
cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i);
|
||||||
}
|
}
|
||||||
for (i = 0; i < BROTLI_NUM_DISTANCE_SYMBOLS; ++i) {
|
for (i = 0; i < self->distance_histogram_size; ++i) {
|
||||||
cost_dist[i] = (float)FastLog2(20 + (uint32_t)i);
|
cost_dist[i] = (float)FastLog2(20 + (uint32_t)i);
|
||||||
}
|
}
|
||||||
self->min_cost_cmd_ = (float)FastLog2(11);
|
self->min_cost_cmd_ = (float)FastLog2(11);
|
||||||
|
@ -221,9 +249,10 @@ static BROTLI_INLINE void UpdateZopfliNode(ZopfliNode* nodes, size_t pos,
|
||||||
size_t start_pos, size_t len, size_t len_code, size_t dist,
|
size_t start_pos, size_t len, size_t len_code, size_t dist,
|
||||||
size_t short_code, float cost) {
|
size_t short_code, float cost) {
|
||||||
ZopfliNode* next = &nodes[pos + len];
|
ZopfliNode* next = &nodes[pos + len];
|
||||||
next->length = (uint32_t)(len | ((len + 9u - len_code) << 24));
|
next->length = (uint32_t)(len | ((len + 9u - len_code) << 25));
|
||||||
next->distance = (uint32_t)(dist | (short_code << 25));
|
next->distance = (uint32_t)dist;
|
||||||
next->insert_length = (uint32_t)(pos - start_pos);
|
next->dcode_insert_length = (uint32_t)(
|
||||||
|
(short_code << 27) | (pos - start_pos));
|
||||||
next->u.cost = cost;
|
next->u.cost = cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,21 +328,21 @@ static size_t ComputeMinimumCopyLength(const float start_cost,
|
||||||
REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
|
REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
|
||||||
static uint32_t ComputeDistanceShortcut(const size_t block_start,
|
static uint32_t ComputeDistanceShortcut(const size_t block_start,
|
||||||
const size_t pos,
|
const size_t pos,
|
||||||
const size_t max_backward,
|
const size_t max_backward_limit,
|
||||||
const size_t gap,
|
const size_t gap,
|
||||||
const ZopfliNode* nodes) {
|
const ZopfliNode* nodes) {
|
||||||
const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
|
const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
|
||||||
const size_t ilen = nodes[pos].insert_length;
|
const size_t ilen = nodes[pos].dcode_insert_length & 0x7FFFFFF;
|
||||||
const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
|
const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
|
||||||
/* Since |block_start + pos| is the end position of the command, the copy part
|
/* Since |block_start + pos| is the end position of the command, the copy part
|
||||||
starts from |block_start + pos - clen|. Distances that are greater than
|
starts from |block_start + pos - clen|. Distances that are greater than
|
||||||
this or greater than |max_backward| are static dictionary references, and
|
this or greater than |max_backward_limit| + |gap| are static dictionary
|
||||||
do not update the last distances. Also distance code 0 (last distance)
|
references, and do not update the last distances.
|
||||||
does not update the last distances. */
|
Also distance code 0 (last distance) does not update the last distances. */
|
||||||
if (pos == 0) {
|
if (pos == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (dist + clen <= block_start + pos + gap &&
|
} else if (dist + clen <= block_start + pos + gap &&
|
||||||
dist <= max_backward + gap &&
|
dist <= max_backward_limit + gap &&
|
||||||
ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
|
ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
|
||||||
return (uint32_t)pos;
|
return (uint32_t)pos;
|
||||||
} else {
|
} else {
|
||||||
|
@ -335,7 +364,7 @@ static void ComputeDistanceCache(const size_t pos,
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
size_t p = nodes[pos].u.shortcut;
|
size_t p = nodes[pos].u.shortcut;
|
||||||
while (idx < 4 && p > 0) {
|
while (idx < 4 && p > 0) {
|
||||||
const size_t ilen = nodes[p].insert_length;
|
const size_t ilen = nodes[p].dcode_insert_length & 0x7FFFFFF;
|
||||||
const size_t clen = ZopfliNodeCopyLength(&nodes[p]);
|
const size_t clen = ZopfliNodeCopyLength(&nodes[p]);
|
||||||
const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
|
const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
|
||||||
dist_cache[idx++] = (int)dist;
|
dist_cache[idx++] = (int)dist;
|
||||||
|
@ -377,9 +406,12 @@ static size_t UpdateNodes(
|
||||||
const int* starting_dist_cache, const size_t num_matches,
|
const int* starting_dist_cache, const size_t num_matches,
|
||||||
const BackwardMatch* matches, const ZopfliCostModel* model,
|
const BackwardMatch* matches, const ZopfliCostModel* model,
|
||||||
StartPosQueue* queue, ZopfliNode* nodes) {
|
StartPosQueue* queue, ZopfliNode* nodes) {
|
||||||
|
const size_t stream_offset = params->stream_offset;
|
||||||
const size_t cur_ix = block_start + pos;
|
const size_t cur_ix = block_start + pos;
|
||||||
const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
|
const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
|
||||||
const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
|
const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
|
||||||
|
const size_t dictionary_start = BROTLI_MIN(size_t,
|
||||||
|
cur_ix + stream_offset, max_backward_limit);
|
||||||
const size_t max_len = num_bytes - pos;
|
const size_t max_len = num_bytes - pos;
|
||||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||||
const size_t max_iters = MaxZopfliCandidates(params);
|
const size_t max_iters = MaxZopfliCandidates(params);
|
||||||
|
@ -388,8 +420,8 @@ static size_t UpdateNodes(
|
||||||
size_t k;
|
size_t k;
|
||||||
size_t gap = 0;
|
size_t gap = 0;
|
||||||
|
|
||||||
EvaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache,
|
EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
|
||||||
model, queue, nodes);
|
starting_dist_cache, model, queue, nodes);
|
||||||
|
|
||||||
{
|
{
|
||||||
const PosData* posdata = StartPosQueueAt(queue, 0);
|
const PosData* posdata = StartPosQueueAt(queue, 0);
|
||||||
|
@ -422,10 +454,12 @@ static size_t UpdateNodes(
|
||||||
if (cur_ix_masked + best_len > ringbuffer_mask) {
|
if (cur_ix_masked + best_len > ringbuffer_mask) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (BROTLI_PREDICT_FALSE(backward > max_distance + gap)) {
|
if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
|
||||||
|
/* Word dictionary -> ignore. */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (backward <= max_distance) {
|
if (backward <= max_distance) {
|
||||||
|
/* Regular backward reference. */
|
||||||
if (prev_ix >= cur_ix) {
|
if (prev_ix >= cur_ix) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -439,6 +473,8 @@ static size_t UpdateNodes(
|
||||||
&ringbuffer[cur_ix_masked],
|
&ringbuffer[cur_ix_masked],
|
||||||
max_len);
|
max_len);
|
||||||
} else {
|
} else {
|
||||||
|
/* "Gray" area. It is addressable by decoder, but this encoder
|
||||||
|
instance does not have that data -> should not touch it. */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@ -473,7 +509,7 @@ static size_t UpdateNodes(
|
||||||
BackwardMatch match = matches[j];
|
BackwardMatch match = matches[j];
|
||||||
size_t dist = match.distance;
|
size_t dist = match.distance;
|
||||||
BROTLI_BOOL is_dictionary_match =
|
BROTLI_BOOL is_dictionary_match =
|
||||||
TO_BROTLI_BOOL(dist > max_distance + gap);
|
TO_BROTLI_BOOL(dist > dictionary_start + gap);
|
||||||
/* We already tried all possible last distance matches, so we can use
|
/* We already tried all possible last distance matches, so we can use
|
||||||
normal distance code here. */
|
normal distance code here. */
|
||||||
size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
|
size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
|
||||||
|
@ -482,10 +518,12 @@ static size_t UpdateNodes(
|
||||||
uint32_t distnumextra;
|
uint32_t distnumextra;
|
||||||
float dist_cost;
|
float dist_cost;
|
||||||
size_t max_match_len;
|
size_t max_match_len;
|
||||||
PrefixEncodeCopyDistance(dist_code, 0, 0, &dist_symbol, &distextra);
|
PrefixEncodeCopyDistance(
|
||||||
distnumextra = distextra >> 24;
|
dist_code, params->dist.num_direct_distance_codes,
|
||||||
|
params->dist.distance_postfix_bits, &dist_symbol, &distextra);
|
||||||
|
distnumextra = dist_symbol >> 10;
|
||||||
dist_cost = base_cost + (float)distnumextra +
|
dist_cost = base_cost + (float)distnumextra +
|
||||||
ZopfliCostModelGetDistanceCost(model, dist_symbol);
|
ZopfliCostModelGetDistanceCost(model, dist_symbol & 0x3FF);
|
||||||
|
|
||||||
/* Try all copy lengths up until the maximum copy length corresponding
|
/* Try all copy lengths up until the maximum copy length corresponding
|
||||||
to this distance. If the distance refers to the static dictionary, or
|
to this distance. If the distance refers to the static dictionary, or
|
||||||
|
@ -517,7 +555,8 @@ static size_t ComputeShortestPathFromNodes(size_t num_bytes,
|
||||||
ZopfliNode* nodes) {
|
ZopfliNode* nodes) {
|
||||||
size_t index = num_bytes;
|
size_t index = num_bytes;
|
||||||
size_t num_commands = 0;
|
size_t num_commands = 0;
|
||||||
while (nodes[index].insert_length == 0 && nodes[index].length == 1) --index;
|
while ((nodes[index].dcode_insert_length & 0x7FFFFFF) == 0 &&
|
||||||
|
nodes[index].length == 1) --index;
|
||||||
nodes[index].u.next = BROTLI_UINT32_MAX;
|
nodes[index].u.next = BROTLI_UINT32_MAX;
|
||||||
while (index != 0) {
|
while (index != 0) {
|
||||||
size_t len = ZopfliNodeCommandLength(&nodes[index]);
|
size_t len = ZopfliNodeCommandLength(&nodes[index]);
|
||||||
|
@ -530,23 +569,19 @@ static size_t ComputeShortestPathFromNodes(size_t num_bytes,
|
||||||
|
|
||||||
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
||||||
void BrotliZopfliCreateCommands(const size_t num_bytes,
|
void BrotliZopfliCreateCommands(const size_t num_bytes,
|
||||||
const size_t block_start,
|
const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
|
||||||
const size_t max_backward_limit,
|
size_t* last_insert_len, const BrotliEncoderParams* params,
|
||||||
const ZopfliNode* nodes,
|
Command* commands, size_t* num_literals) {
|
||||||
int* dist_cache,
|
const size_t stream_offset = params->stream_offset;
|
||||||
size_t* last_insert_len,
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||||
const BrotliEncoderParams* params,
|
|
||||||
Command* commands,
|
|
||||||
size_t* num_literals) {
|
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
uint32_t offset = nodes[0].u.next;
|
uint32_t offset = nodes[0].u.next;
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t gap = 0;
|
size_t gap = 0;
|
||||||
BROTLI_UNUSED(params);
|
|
||||||
for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
|
for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
|
||||||
const ZopfliNode* next = &nodes[pos + offset];
|
const ZopfliNode* next = &nodes[pos + offset];
|
||||||
size_t copy_length = ZopfliNodeCopyLength(next);
|
size_t copy_length = ZopfliNodeCopyLength(next);
|
||||||
size_t insert_length = next->insert_length;
|
size_t insert_length = next->dcode_insert_length & 0x7FFFFFF;
|
||||||
pos += insert_length;
|
pos += insert_length;
|
||||||
offset = next->u.next;
|
offset = next->u.next;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
|
@ -556,12 +591,12 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
||||||
{
|
{
|
||||||
size_t distance = ZopfliNodeCopyDistance(next);
|
size_t distance = ZopfliNodeCopyDistance(next);
|
||||||
size_t len_code = ZopfliNodeLengthCode(next);
|
size_t len_code = ZopfliNodeLengthCode(next);
|
||||||
size_t max_distance =
|
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||||
BROTLI_MIN(size_t, block_start + pos, max_backward_limit);
|
block_start + pos + stream_offset, max_backward_limit);
|
||||||
BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance + gap);
|
BROTLI_BOOL is_dictionary =
|
||||||
|
TO_BROTLI_BOOL(distance > dictionary_start + gap);
|
||||||
size_t dist_code = ZopfliNodeDistanceCode(next);
|
size_t dist_code = ZopfliNodeDistanceCode(next);
|
||||||
|
InitCommand(&commands[i], ¶ms->dist, insert_length,
|
||||||
InitCommand(&commands[i], insert_length,
|
|
||||||
copy_length, (int)len_code - (int)copy_length, dist_code);
|
copy_length, (int)len_code - (int)copy_length, dist_code);
|
||||||
|
|
||||||
if (!is_dictionary && dist_code > 0) {
|
if (!is_dictionary && dist_code > 0) {
|
||||||
|
@ -578,18 +613,13 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
||||||
*last_insert_len += num_bytes - pos;
|
*last_insert_len += num_bytes - pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZopfliIterate(size_t num_bytes,
|
static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
||||||
size_t position,
|
const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||||
const uint8_t* ringbuffer,
|
const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
|
||||||
size_t ringbuffer_mask,
|
const ZopfliCostModel* model, const uint32_t* num_matches,
|
||||||
const BrotliEncoderParams* params,
|
const BackwardMatch* matches, ZopfliNode* nodes) {
|
||||||
const size_t max_backward_limit,
|
const size_t stream_offset = params->stream_offset;
|
||||||
const size_t gap,
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||||
const int* dist_cache,
|
|
||||||
const ZopfliCostModel* model,
|
|
||||||
const uint32_t* num_matches,
|
|
||||||
const BackwardMatch* matches,
|
|
||||||
ZopfliNode* nodes) {
|
|
||||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||||
StartPosQueue queue;
|
StartPosQueue queue;
|
||||||
size_t cur_match_pos = 0;
|
size_t cur_match_pos = 0;
|
||||||
|
@ -613,8 +643,8 @@ static size_t ZopfliIterate(size_t num_bytes,
|
||||||
while (skip) {
|
while (skip) {
|
||||||
i++;
|
i++;
|
||||||
if (i + 3 >= num_bytes) break;
|
if (i + 3 >= num_bytes) break;
|
||||||
EvaluateNode(position, i, max_backward_limit, gap, dist_cache, model,
|
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
||||||
&queue, nodes);
|
dist_cache, model, &queue, nodes);
|
||||||
cur_match_pos += num_matches[i];
|
cur_match_pos += num_matches[i];
|
||||||
skip--;
|
skip--;
|
||||||
}
|
}
|
||||||
|
@ -624,28 +654,25 @@ static size_t ZopfliIterate(size_t num_bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
||||||
size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||||
const BrotliDictionary* dictionary,
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||||
size_t num_bytes,
|
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||||
size_t position,
|
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
|
||||||
const uint8_t* ringbuffer,
|
const size_t stream_offset = params->stream_offset;
|
||||||
size_t ringbuffer_mask,
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||||
const BrotliEncoderParams* params,
|
|
||||||
const size_t max_backward_limit,
|
|
||||||
const int* dist_cache,
|
|
||||||
HasherHandle hasher,
|
|
||||||
ZopfliNode* nodes) {
|
|
||||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||||
ZopfliCostModel model;
|
ZopfliCostModel model;
|
||||||
StartPosQueue queue;
|
StartPosQueue queue;
|
||||||
BackwardMatch matches[MAX_NUM_MATCHES_H10];
|
BackwardMatch matches[2 * (MAX_NUM_MATCHES_H10 + 64)];
|
||||||
const size_t store_end = num_bytes >= StoreLookaheadH10() ?
|
const size_t store_end = num_bytes >= StoreLookaheadH10() ?
|
||||||
position + num_bytes - StoreLookaheadH10() + 1 : position;
|
position + num_bytes - StoreLookaheadH10() + 1 : position;
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t gap = 0;
|
size_t gap = 0;
|
||||||
|
size_t lz_matches_offset = 0;
|
||||||
|
BROTLI_UNUSED(literal_context_lut);
|
||||||
nodes[0].length = 0;
|
nodes[0].length = 0;
|
||||||
nodes[0].u.cost = 0;
|
nodes[0].u.cost = 0;
|
||||||
InitZopfliCostModel(m, &model, num_bytes);
|
InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes);
|
||||||
if (BROTLI_IS_OOM(m)) return 0;
|
if (BROTLI_IS_OOM(m)) return 0;
|
||||||
ZopfliCostModelSetFromLiteralCosts(
|
ZopfliCostModelSetFromLiteralCosts(
|
||||||
&model, position, ringbuffer, ringbuffer_mask);
|
&model, position, ringbuffer, ringbuffer_mask);
|
||||||
|
@ -653,10 +680,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
||||||
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
|
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
|
||||||
const size_t pos = position + i;
|
const size_t pos = position + i;
|
||||||
const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
||||||
size_t num_matches = FindAllMatchesH10(hasher, dictionary, ringbuffer,
|
const size_t dictionary_start = BROTLI_MIN(size_t,
|
||||||
ringbuffer_mask, pos, num_bytes - i, max_distance, gap, params,
|
pos + stream_offset, max_backward_limit);
|
||||||
matches);
|
|
||||||
size_t skip;
|
size_t skip;
|
||||||
|
size_t num_matches;
|
||||||
|
num_matches = FindAllMatchesH10(&hasher->privat._H10,
|
||||||
|
¶ms->dictionary,
|
||||||
|
ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
|
||||||
|
dictionary_start + gap, params, &matches[lz_matches_offset]);
|
||||||
if (num_matches > 0 &&
|
if (num_matches > 0 &&
|
||||||
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
|
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
|
||||||
matches[0] = matches[num_matches - 1];
|
matches[0] = matches[num_matches - 1];
|
||||||
|
@ -671,14 +702,15 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
||||||
}
|
}
|
||||||
if (skip > 1) {
|
if (skip > 1) {
|
||||||
/* Add the tail of the copy to the hasher. */
|
/* Add the tail of the copy to the hasher. */
|
||||||
StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
|
StoreRangeH10(&hasher->privat._H10,
|
||||||
|
ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
|
||||||
size_t, pos + skip, store_end));
|
size_t, pos + skip, store_end));
|
||||||
skip--;
|
skip--;
|
||||||
while (skip) {
|
while (skip) {
|
||||||
i++;
|
i++;
|
||||||
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
|
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
|
||||||
EvaluateNode(position, i, max_backward_limit, gap, dist_cache, &model,
|
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
||||||
&queue, nodes);
|
dist_cache, &model, &queue, nodes);
|
||||||
skip--;
|
skip--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -687,32 +719,29 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
||||||
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliCreateZopfliBackwardReferences(
|
void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||||
MemoryManager* m, const BrotliDictionary* dictionary, size_t num_bytes,
|
|
||||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||||
const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
|
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||||
size_t* last_insert_len, Command* commands, size_t* num_commands,
|
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||||
size_t* num_literals) {
|
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||||
ZopfliNode* nodes;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
||||||
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
|
||||||
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
||||||
*num_commands += BrotliZopfliComputeShortestPath(m, dictionary, num_bytes,
|
*num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
|
||||||
position, ringbuffer, ringbuffer_mask, params, max_backward_limit,
|
position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
|
||||||
dist_cache, hasher, nodes);
|
dist_cache, hasher, nodes);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit, nodes,
|
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
||||||
dist_cache, last_insert_len, params, commands, num_literals);
|
last_insert_len, params, commands, num_literals);
|
||||||
BROTLI_FREE(m, nodes);
|
BROTLI_FREE(m, nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliCreateHqZopfliBackwardReferences(
|
void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||||
MemoryManager* m, const BrotliDictionary* dictionary, size_t num_bytes,
|
|
||||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||||
const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
|
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||||
size_t* last_insert_len, Command* commands, size_t* num_commands,
|
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||||
size_t* num_literals) {
|
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||||
|
const size_t stream_offset = params->stream_offset;
|
||||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||||
uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
|
uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
|
||||||
size_t matches_size = 4 * num_bytes;
|
size_t matches_size = 4 * num_bytes;
|
||||||
|
@ -728,24 +757,33 @@ void BrotliCreateHqZopfliBackwardReferences(
|
||||||
ZopfliNode* nodes;
|
ZopfliNode* nodes;
|
||||||
BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
|
BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
|
||||||
size_t gap = 0;
|
size_t gap = 0;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
size_t shadow_matches = 0;
|
||||||
|
BROTLI_UNUSED(literal_context_lut);
|
||||||
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(num_matches) ||
|
||||||
|
BROTLI_IS_NULL(matches)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
|
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
|
||||||
const size_t pos = position + i;
|
const size_t pos = position + i;
|
||||||
size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
||||||
|
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||||
|
pos + stream_offset, max_backward_limit);
|
||||||
size_t max_length = num_bytes - i;
|
size_t max_length = num_bytes - i;
|
||||||
size_t num_found_matches;
|
size_t num_found_matches;
|
||||||
size_t cur_match_end;
|
size_t cur_match_end;
|
||||||
size_t j;
|
size_t j;
|
||||||
/* Ensure that we have enough free slots. */
|
/* Ensure that we have enough free slots. */
|
||||||
BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
|
BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
|
||||||
cur_match_pos + MAX_NUM_MATCHES_H10);
|
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
num_found_matches = FindAllMatchesH10(hasher, dictionary, ringbuffer,
|
num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
|
||||||
ringbuffer_mask, pos, max_length, max_distance, gap, params,
|
¶ms->dictionary,
|
||||||
&matches[cur_match_pos]);
|
ringbuffer, ringbuffer_mask, pos, max_length,
|
||||||
|
max_distance, dictionary_start + gap, params,
|
||||||
|
&matches[cur_match_pos + shadow_matches]);
|
||||||
cur_match_end = cur_match_pos + num_found_matches;
|
cur_match_end = cur_match_pos + num_found_matches;
|
||||||
for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
|
for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
|
||||||
assert(BackwardMatchLength(&matches[j]) <=
|
BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
|
||||||
BackwardMatchLength(&matches[j + 1]));
|
BackwardMatchLength(&matches[j + 1]));
|
||||||
}
|
}
|
||||||
num_matches[i] = (uint32_t)num_found_matches;
|
num_matches[i] = (uint32_t)num_found_matches;
|
||||||
|
@ -756,7 +794,8 @@ void BrotliCreateHqZopfliBackwardReferences(
|
||||||
matches[cur_match_pos++] = matches[cur_match_end - 1];
|
matches[cur_match_pos++] = matches[cur_match_end - 1];
|
||||||
num_matches[i] = 1;
|
num_matches[i] = 1;
|
||||||
/* Add the tail of the copy to the hasher. */
|
/* Add the tail of the copy to the hasher. */
|
||||||
StoreRangeH10(hasher, ringbuffer, ringbuffer_mask, pos + 1,
|
StoreRangeH10(&hasher->privat._H10,
|
||||||
|
ringbuffer, ringbuffer_mask, pos + 1,
|
||||||
BROTLI_MIN(size_t, pos + match_len, store_end));
|
BROTLI_MIN(size_t, pos + match_len, store_end));
|
||||||
memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
|
memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
|
||||||
i += skip;
|
i += skip;
|
||||||
|
@ -770,8 +809,8 @@ void BrotliCreateHqZopfliBackwardReferences(
|
||||||
memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
|
memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
|
||||||
orig_num_commands = *num_commands;
|
orig_num_commands = *num_commands;
|
||||||
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
||||||
InitZopfliCostModel(m, &model, num_bytes);
|
InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
||||||
|
@ -788,10 +827,10 @@ void BrotliCreateHqZopfliBackwardReferences(
|
||||||
*last_insert_len = orig_last_insert_len;
|
*last_insert_len = orig_last_insert_len;
|
||||||
memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
|
memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
|
||||||
*num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
|
*num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
|
||||||
ringbuffer_mask, params, max_backward_limit, gap, dist_cache,
|
ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches,
|
||||||
&model, num_matches, matches, nodes);
|
nodes);
|
||||||
BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit,
|
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
||||||
nodes, dist_cache, last_insert_len, params, commands, num_literals);
|
last_insert_len, params, commands, num_literals);
|
||||||
}
|
}
|
||||||
CleanupZopfliCostModel(m, &model);
|
CleanupZopfliCostModel(m, &model);
|
||||||
BROTLI_FREE(m, nodes);
|
BROTLI_FREE(m, nodes);
|
||||||
|
|
|
@ -10,42 +10,42 @@
|
||||||
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/context.h"
|
||||||
#include "../common/dictionary.h"
|
#include "../common/dictionary.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./command.h"
|
#include "./command.h"
|
||||||
#include "./hash.h"
|
#include "./hash.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./quality.h"
|
#include "./quality.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(
|
BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
|
||||||
MemoryManager* m, const BrotliDictionary* dictionary, size_t num_bytes,
|
size_t num_bytes,
|
||||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||||
const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
|
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||||
size_t* last_insert_len, Command* commands, size_t* num_commands,
|
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||||
size_t* num_literals);
|
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||||
|
|
||||||
BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(
|
BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
||||||
MemoryManager* m, const BrotliDictionary* dictionary, size_t num_bytes,
|
size_t num_bytes,
|
||||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||||
const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
|
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||||
size_t* last_insert_len, Command* commands, size_t* num_commands,
|
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||||
size_t* num_literals);
|
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||||
|
|
||||||
typedef struct ZopfliNode {
|
typedef struct ZopfliNode {
|
||||||
/* best length to get up to this byte (not including this byte itself)
|
/* Best length to get up to this byte (not including this byte itself)
|
||||||
highest 8 bit is used to reconstruct the length code */
|
highest 7 bit is used to reconstruct the length code. */
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
/* distance associated with the length
|
/* Distance associated with the length. */
|
||||||
highest 7 bit contains distance short code + 1 (or zero if no short code)
|
|
||||||
*/
|
|
||||||
uint32_t distance;
|
uint32_t distance;
|
||||||
/* number of literal inserts before this copy */
|
/* Number of literal inserts before this copy; highest 5 bits contain
|
||||||
uint32_t insert_length;
|
distance short code + 1 (or zero if no short code). */
|
||||||
|
uint32_t dcode_insert_length;
|
||||||
|
|
||||||
/* This union holds information used by dynamic-programming. During forward
|
/* This union holds information used by dynamic-programming. During forward
|
||||||
pass |cost| it used to store the goal function. When node is processed its
|
pass |cost| it used to store the goal function. When node is processed its
|
||||||
|
@ -78,14 +78,13 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
|
||||||
(2) nodes[i].command_length() <= i and
|
(2) nodes[i].command_length() <= i and
|
||||||
(3) nodes[i - nodes[i].command_length()].cost < kInfinity */
|
(3) nodes[i - nodes[i].command_length()].cost < kInfinity */
|
||||||
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
|
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
|
||||||
MemoryManager* m, const BrotliDictionary* dictionary, size_t num_bytes,
|
MemoryManager* m, size_t num_bytes,
|
||||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||||
const BrotliEncoderParams* params, const size_t max_backward_limit,
|
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||||
const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes);
|
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes);
|
||||||
|
|
||||||
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
|
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
|
||||||
const size_t num_bytes, const size_t block_start,
|
const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes,
|
||||||
const size_t max_backward_limit, const ZopfliNode* nodes,
|
|
||||||
int* dist_cache, size_t* last_insert_len, const BrotliEncoderParams* params,
|
int* dist_cache, size_t* last_insert_len, const BrotliEncoderParams* params,
|
||||||
Command* commands, size_t* num_literals);
|
Command* commands, size_t* num_literals);
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,15 @@
|
||||||
/* template parameters: EXPORT_FN, FN */
|
/* template parameters: EXPORT_FN, FN */
|
||||||
|
|
||||||
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||||
const BrotliDictionary* dictionary,
|
size_t num_bytes, size_t position,
|
||||||
const uint16_t* dictionary_hash, size_t num_bytes, size_t position,
|
|
||||||
const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||||
const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
|
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||||
size_t* last_insert_len, Command* commands, size_t* num_commands,
|
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||||
size_t* num_literals) {
|
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||||
|
HASHER()* privat = &hasher->privat.FN(_);
|
||||||
/* Set maximum distance, see section 9.1. of the spec. */
|
/* Set maximum distance, see section 9.1. of the spec. */
|
||||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||||
|
const size_t position_offset = params->stream_offset;
|
||||||
|
|
||||||
const Command* const orig_commands = commands;
|
const Command* const orig_commands = commands;
|
||||||
size_t insert_length = *last_insert_len;
|
size_t insert_length = *last_insert_len;
|
||||||
|
@ -32,19 +33,23 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||||
/* Minimum score to accept a backward reference. */
|
/* Minimum score to accept a backward reference. */
|
||||||
const score_t kMinScore = BROTLI_SCORE_BASE + 100;
|
const score_t kMinScore = BROTLI_SCORE_BASE + 100;
|
||||||
|
|
||||||
FN(PrepareDistanceCache)(hasher, dist_cache);
|
BROTLI_UNUSED(literal_context_lut);
|
||||||
|
|
||||||
|
FN(PrepareDistanceCache)(privat, dist_cache);
|
||||||
|
|
||||||
while (position + FN(HashTypeLength)() < pos_end) {
|
while (position + FN(HashTypeLength)() < pos_end) {
|
||||||
size_t max_length = pos_end - position;
|
size_t max_length = pos_end - position;
|
||||||
size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
|
size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
|
||||||
|
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||||
|
position + position_offset, max_backward_limit);
|
||||||
HasherSearchResult sr;
|
HasherSearchResult sr;
|
||||||
sr.len = 0;
|
sr.len = 0;
|
||||||
sr.len_code_delta = 0;
|
sr.len_code_delta = 0;
|
||||||
sr.distance = 0;
|
sr.distance = 0;
|
||||||
sr.score = kMinScore;
|
sr.score = kMinScore;
|
||||||
FN(FindLongestMatch)(hasher, dictionary, dictionary_hash, ringbuffer,
|
FN(FindLongestMatch)(privat, ¶ms->dictionary,
|
||||||
ringbuffer_mask, dist_cache, position,
|
ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
|
||||||
max_length, max_distance, gap, &sr);
|
max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
|
||||||
if (sr.score > kMinScore) {
|
if (sr.score > kMinScore) {
|
||||||
/* Found a match. Let's look for something even better ahead. */
|
/* Found a match. Let's look for something even better ahead. */
|
||||||
int delayed_backward_references_in_row = 0;
|
int delayed_backward_references_in_row = 0;
|
||||||
|
@ -58,9 +63,13 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||||
sr2.distance = 0;
|
sr2.distance = 0;
|
||||||
sr2.score = kMinScore;
|
sr2.score = kMinScore;
|
||||||
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
|
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
|
||||||
FN(FindLongestMatch)(hasher, dictionary, dictionary_hash, ringbuffer,
|
dictionary_start = BROTLI_MIN(size_t,
|
||||||
ringbuffer_mask, dist_cache, position + 1,
|
position + 1 + position_offset, max_backward_limit);
|
||||||
max_length, max_distance, gap, &sr2);
|
FN(FindLongestMatch)(privat,
|
||||||
|
¶ms->dictionary,
|
||||||
|
ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
|
||||||
|
max_distance, dictionary_start + gap, params->dist.max_distance,
|
||||||
|
&sr2);
|
||||||
if (sr2.score >= sr.score + cost_diff_lazy) {
|
if (sr2.score >= sr.score + cost_diff_lazy) {
|
||||||
/* Ok, let's just write one byte for now and start a match from the
|
/* Ok, let's just write one byte for now and start a match from the
|
||||||
next byte. */
|
next byte. */
|
||||||
|
@ -76,21 +85,22 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||||
}
|
}
|
||||||
apply_random_heuristics =
|
apply_random_heuristics =
|
||||||
position + 2 * sr.len + random_heuristics_window_size;
|
position + 2 * sr.len + random_heuristics_window_size;
|
||||||
max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
|
dictionary_start = BROTLI_MIN(size_t,
|
||||||
|
position + position_offset, max_backward_limit);
|
||||||
{
|
{
|
||||||
/* The first 16 codes are special short-codes,
|
/* The first 16 codes are special short-codes,
|
||||||
and the minimum offset is 1. */
|
and the minimum offset is 1. */
|
||||||
size_t distance_code =
|
size_t distance_code = ComputeDistanceCode(
|
||||||
ComputeDistanceCode(sr.distance, max_distance + gap, dist_cache);
|
sr.distance, dictionary_start + gap, dist_cache);
|
||||||
if ((sr.distance <= (max_distance + gap)) && distance_code > 0) {
|
if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
|
||||||
dist_cache[3] = dist_cache[2];
|
dist_cache[3] = dist_cache[2];
|
||||||
dist_cache[2] = dist_cache[1];
|
dist_cache[2] = dist_cache[1];
|
||||||
dist_cache[1] = dist_cache[0];
|
dist_cache[1] = dist_cache[0];
|
||||||
dist_cache[0] = (int)sr.distance;
|
dist_cache[0] = (int)sr.distance;
|
||||||
FN(PrepareDistanceCache)(hasher, dist_cache);
|
FN(PrepareDistanceCache)(privat, dist_cache);
|
||||||
}
|
}
|
||||||
InitCommand(commands++, insert_length, sr.len, sr.len_code_delta,
|
InitCommand(commands++, ¶ms->dist, insert_length,
|
||||||
distance_code);
|
sr.len, sr.len_code_delta, distance_code);
|
||||||
}
|
}
|
||||||
*num_literals += insert_length;
|
*num_literals += insert_length;
|
||||||
insert_length = 0;
|
insert_length = 0;
|
||||||
|
@ -105,7 +115,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||||
range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
|
range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
|
||||||
range_start, position + sr.len - (sr.distance << 2)));
|
range_start, position + sr.len - (sr.distance << 2)));
|
||||||
}
|
}
|
||||||
FN(StoreRange)(hasher, ringbuffer, ringbuffer_mask, range_start,
|
FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
|
||||||
range_end);
|
range_end);
|
||||||
}
|
}
|
||||||
position += sr.len;
|
position += sr.len;
|
||||||
|
@ -131,7 +141,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||||
size_t pos_jump =
|
size_t pos_jump =
|
||||||
BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
|
BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
|
||||||
for (; position < pos_jump; position += 4) {
|
for (; position < pos_jump; position += 4) {
|
||||||
FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
|
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
|
||||||
insert_length += 4;
|
insert_length += 4;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -140,7 +150,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||||
size_t pos_jump =
|
size_t pos_jump =
|
||||||
BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
|
BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
|
||||||
for (; position < pos_jump; position += 2) {
|
for (; position < pos_jump; position += 2) {
|
||||||
FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
|
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
|
||||||
insert_length += 2;
|
insert_length += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
#include "./bit_cost.h"
|
#include "./bit_cost.h"
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
#include "./histogram.h"
|
#include "./histogram.h"
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -9,20 +9,20 @@
|
||||||
#ifndef BROTLI_ENC_BIT_COST_H_
|
#ifndef BROTLI_ENC_BIT_COST_H_
|
||||||
#define BROTLI_ENC_BIT_COST_H_
|
#define BROTLI_ENC_BIT_COST_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
#include "./histogram.h"
|
#include "./histogram.h"
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static BROTLI_INLINE double ShannonEntropy(const uint32_t *population,
|
static BROTLI_INLINE double ShannonEntropy(
|
||||||
size_t size, size_t *total) {
|
const uint32_t* population, size_t size, size_t* total) {
|
||||||
size_t sum = 0;
|
size_t sum = 0;
|
||||||
double retval = 0;
|
double retval = 0;
|
||||||
const uint32_t *population_end = population + size;
|
const uint32_t* population_end = population + size;
|
||||||
size_t p;
|
size_t p;
|
||||||
if (size & 1) {
|
if (size & 1) {
|
||||||
goto odd_number_of_elements_left;
|
goto odd_number_of_elements_left;
|
||||||
|
@ -42,7 +42,7 @@ static BROTLI_INLINE double ShannonEntropy(const uint32_t *population,
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE double BitsEntropy(
|
static BROTLI_INLINE double BitsEntropy(
|
||||||
const uint32_t *population, size_t size) {
|
const uint32_t* population, size_t size) {
|
||||||
size_t sum;
|
size_t sum;
|
||||||
double retval = ShannonEntropy(population, size, &sum);
|
double retval = ShannonEntropy(population, size, &sum);
|
||||||
if (retval < sum) {
|
if (retval < sum) {
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
stream. */
|
stream. */
|
||||||
static void FN(BuildAndStoreEntropyCodes)(MemoryManager* m, BlockEncoder* self,
|
static void FN(BuildAndStoreEntropyCodes)(MemoryManager* m, BlockEncoder* self,
|
||||||
const HistogramType* histograms, const size_t histograms_size,
|
const HistogramType* histograms, const size_t histograms_size,
|
||||||
HuffmanTree* tree, size_t* storage_ix, uint8_t* storage) {
|
const size_t alphabet_size, HuffmanTree* tree,
|
||||||
const size_t alphabet_size = self->alphabet_size_;
|
size_t* storage_ix, uint8_t* storage) {
|
||||||
const size_t table_size = histograms_size * alphabet_size;
|
const size_t table_size = histograms_size * self->histogram_length_;
|
||||||
self->depths_ = BROTLI_ALLOC(m, uint8_t, table_size);
|
self->depths_ = BROTLI_ALLOC(m, uint8_t, table_size);
|
||||||
self->bits_ = BROTLI_ALLOC(m, uint16_t, table_size);
|
self->bits_ = BROTLI_ALLOC(m, uint16_t, table_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
|
@ -23,9 +23,10 @@ static void FN(BuildAndStoreEntropyCodes)(MemoryManager* m, BlockEncoder* self,
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < histograms_size; ++i) {
|
for (i = 0; i < histograms_size; ++i) {
|
||||||
size_t ix = i * alphabet_size;
|
size_t ix = i * self->histogram_length_;
|
||||||
BuildAndStoreHuffmanTree(&histograms[i].data_[0], alphabet_size, tree,
|
BuildAndStoreHuffmanTree(&histograms[i].data_[0], self->histogram_length_,
|
||||||
&self->depths_[ix], &self->bits_[ix], storage_ix, storage);
|
alphabet_size, tree, &self->depths_[ix], &self->bits_[ix],
|
||||||
|
storage_ix, storage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,16 +8,15 @@
|
||||||
|
|
||||||
#include "./block_splitter.h"
|
#include "./block_splitter.h"
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h> /* memcpy, memset */
|
#include <string.h> /* memcpy, memset */
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include "./bit_cost.h"
|
#include "./bit_cost.h"
|
||||||
#include "./cluster.h"
|
#include "./cluster.h"
|
||||||
#include "./command.h"
|
#include "./command.h"
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
#include "./histogram.h"
|
#include "./histogram.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./quality.h"
|
#include "./quality.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -133,7 +132,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||||
{
|
{
|
||||||
size_t literals_count = CountLiterals(cmds, num_commands);
|
size_t literals_count = CountLiterals(cmds, num_commands);
|
||||||
uint8_t* literals = BROTLI_ALLOC(m, uint8_t, literals_count);
|
uint8_t* literals = BROTLI_ALLOC(m, uint8_t, literals_count);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literals)) return;
|
||||||
/* Create a continuous array of literals. */
|
/* Create a continuous array of literals. */
|
||||||
CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
|
CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
|
||||||
/* Create the block split on the array of literals.
|
/* Create the block split on the array of literals.
|
||||||
|
@ -151,7 +150,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||||
/* Compute prefix codes for commands. */
|
/* Compute prefix codes for commands. */
|
||||||
uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands);
|
uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands);
|
||||||
size_t i;
|
size_t i;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(insert_and_copy_codes)) return;
|
||||||
for (i = 0; i < num_commands; ++i) {
|
for (i = 0; i < num_commands; ++i) {
|
||||||
insert_and_copy_codes[i] = cmds[i].cmd_prefix_;
|
insert_and_copy_codes[i] = cmds[i].cmd_prefix_;
|
||||||
}
|
}
|
||||||
|
@ -171,11 +170,11 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||||
uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands);
|
uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands);
|
||||||
size_t j = 0;
|
size_t j = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_prefixes)) return;
|
||||||
for (i = 0; i < num_commands; ++i) {
|
for (i = 0; i < num_commands; ++i) {
|
||||||
const Command* cmd = &cmds[i];
|
const Command* cmd = &cmds[i];
|
||||||
if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
|
if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
|
||||||
distance_prefixes[j++] = cmd->dist_prefix_;
|
distance_prefixes[j++] = cmd->dist_prefix_ & 0x3FF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Create the block split on the array of distance prefixes. */
|
/* Create the block split on the array of distance prefixes. */
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
#ifndef BROTLI_ENC_BLOCK_SPLITTER_H_
|
#ifndef BROTLI_ENC_BLOCK_SPLITTER_H_
|
||||||
#define BROTLI_ENC_BLOCK_SPLITTER_H_
|
#define BROTLI_ENC_BLOCK_SPLITTER_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./command.h"
|
#include "./command.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./quality.h"
|
#include "./quality.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
|
|
@ -70,13 +70,13 @@ static size_t FN(FindBlocks)(const DataType* data, const size_t length,
|
||||||
double* insert_cost,
|
double* insert_cost,
|
||||||
double* cost,
|
double* cost,
|
||||||
uint8_t* switch_signal,
|
uint8_t* switch_signal,
|
||||||
uint8_t *block_id) {
|
uint8_t* block_id) {
|
||||||
const size_t data_size = FN(HistogramDataSize)();
|
const size_t data_size = FN(HistogramDataSize)();
|
||||||
const size_t bitmaplen = (num_histograms + 7) >> 3;
|
const size_t bitmaplen = (num_histograms + 7) >> 3;
|
||||||
size_t num_blocks = 1;
|
size_t num_blocks = 1;
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t j;
|
size_t j;
|
||||||
assert(num_histograms <= 256);
|
BROTLI_DCHECK(num_histograms <= 256);
|
||||||
if (num_histograms <= 1) {
|
if (num_histograms <= 1) {
|
||||||
for (i = 0; i < length; ++i) {
|
for (i = 0; i < length; ++i) {
|
||||||
block_id[i] = 0;
|
block_id[i] = 0;
|
||||||
|
@ -126,7 +126,7 @@ static size_t FN(FindBlocks)(const DataType* data, const size_t length,
|
||||||
if (cost[k] >= block_switch_cost) {
|
if (cost[k] >= block_switch_cost) {
|
||||||
const uint8_t mask = (uint8_t)(1u << (k & 7));
|
const uint8_t mask = (uint8_t)(1u << (k & 7));
|
||||||
cost[k] = block_switch_cost;
|
cost[k] = block_switch_cost;
|
||||||
assert((k >> 3) < bitmaplen);
|
BROTLI_DCHECK((k >> 3) < bitmaplen);
|
||||||
switch_signal[ix + (k >> 3)] |= mask;
|
switch_signal[ix + (k >> 3)] |= mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ static size_t FN(FindBlocks)(const DataType* data, const size_t length,
|
||||||
uint8_t cur_id = block_id[byte_ix];
|
uint8_t cur_id = block_id[byte_ix];
|
||||||
while (byte_ix > 0) {
|
while (byte_ix > 0) {
|
||||||
const uint8_t mask = (uint8_t)(1u << (cur_id & 7));
|
const uint8_t mask = (uint8_t)(1u << (cur_id & 7));
|
||||||
assert(((size_t)cur_id >> 3) < bitmaplen);
|
BROTLI_DCHECK(((size_t)cur_id >> 3) < bitmaplen);
|
||||||
--byte_ix;
|
--byte_ix;
|
||||||
ix -= bitmaplen;
|
ix -= bitmaplen;
|
||||||
if (switch_signal[ix + (cur_id >> 3)] & mask) {
|
if (switch_signal[ix + (cur_id >> 3)] & mask) {
|
||||||
|
@ -161,16 +161,16 @@ static size_t FN(RemapBlockIds)(uint8_t* block_ids, const size_t length,
|
||||||
new_id[i] = kInvalidId;
|
new_id[i] = kInvalidId;
|
||||||
}
|
}
|
||||||
for (i = 0; i < length; ++i) {
|
for (i = 0; i < length; ++i) {
|
||||||
assert(block_ids[i] < num_histograms);
|
BROTLI_DCHECK(block_ids[i] < num_histograms);
|
||||||
if (new_id[block_ids[i]] == kInvalidId) {
|
if (new_id[block_ids[i]] == kInvalidId) {
|
||||||
new_id[block_ids[i]] = next_id++;
|
new_id[block_ids[i]] = next_id++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < length; ++i) {
|
for (i = 0; i < length; ++i) {
|
||||||
block_ids[i] = (uint8_t)new_id[block_ids[i]];
|
block_ids[i] = (uint8_t)new_id[block_ids[i]];
|
||||||
assert(block_ids[i] < num_histograms);
|
BROTLI_DCHECK(block_ids[i] < num_histograms);
|
||||||
}
|
}
|
||||||
assert(next_id <= num_histograms);
|
BROTLI_DCHECK(next_id <= num_histograms);
|
||||||
return next_id;
|
return next_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,20 +219,25 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||||
uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 };
|
uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||||
uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 };
|
uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||||
|
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) ||
|
||||||
|
BROTLI_IS_NULL(block_lengths) || BROTLI_IS_NULL(all_histograms) ||
|
||||||
|
BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) ||
|
||||||
|
BROTLI_IS_NULL(pairs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memset(block_lengths, 0, num_blocks * sizeof(uint32_t));
|
memset(block_lengths, 0, num_blocks * sizeof(uint32_t));
|
||||||
|
|
||||||
{
|
{
|
||||||
size_t block_idx = 0;
|
size_t block_idx = 0;
|
||||||
for (i = 0; i < length; ++i) {
|
for (i = 0; i < length; ++i) {
|
||||||
assert(block_idx < num_blocks);
|
BROTLI_DCHECK(block_idx < num_blocks);
|
||||||
++block_lengths[block_idx];
|
++block_lengths[block_idx];
|
||||||
if (i + 1 == length || block_ids[i] != block_ids[i + 1]) {
|
if (i + 1 == length || block_ids[i] != block_ids[i + 1]) {
|
||||||
++block_idx;
|
++block_idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(block_idx == num_blocks);
|
BROTLI_DCHECK(block_idx == num_blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < num_blocks; i += HISTOGRAMS_PER_BATCH) {
|
for (i = 0; i < num_blocks; i += HISTOGRAMS_PER_BATCH) {
|
||||||
|
@ -268,8 +273,8 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||||
histogram_symbols[i + j] = (uint32_t)num_clusters + remap[symbols[j]];
|
histogram_symbols[i + j] = (uint32_t)num_clusters + remap[symbols[j]];
|
||||||
}
|
}
|
||||||
num_clusters += num_new_clusters;
|
num_clusters += num_new_clusters;
|
||||||
assert(num_clusters == cluster_size_size);
|
BROTLI_DCHECK(num_clusters == cluster_size_size);
|
||||||
assert(num_clusters == all_histograms_size);
|
BROTLI_DCHECK(num_clusters == all_histograms_size);
|
||||||
}
|
}
|
||||||
BROTLI_FREE(m, histograms);
|
BROTLI_FREE(m, histograms);
|
||||||
|
|
||||||
|
@ -278,11 +283,11 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||||
if (pairs_capacity < max_num_pairs + 1) {
|
if (pairs_capacity < max_num_pairs + 1) {
|
||||||
BROTLI_FREE(m, pairs);
|
BROTLI_FREE(m, pairs);
|
||||||
pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1);
|
pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
clusters = BROTLI_ALLOC(m, uint32_t, num_clusters);
|
clusters = BROTLI_ALLOC(m, uint32_t, num_clusters);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return;
|
||||||
for (i = 0; i < num_clusters; ++i) {
|
for (i = 0; i < num_clusters; ++i) {
|
||||||
clusters[i] = (uint32_t)i;
|
clusters[i] = (uint32_t)i;
|
||||||
}
|
}
|
||||||
|
@ -294,7 +299,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||||
BROTLI_FREE(m, cluster_size);
|
BROTLI_FREE(m, cluster_size);
|
||||||
|
|
||||||
new_index = BROTLI_ALLOC(m, uint32_t, num_clusters);
|
new_index = BROTLI_ALLOC(m, uint32_t, num_clusters);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return;
|
||||||
for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex;
|
for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex;
|
||||||
pos = 0;
|
pos = 0;
|
||||||
{
|
{
|
||||||
|
@ -386,7 +391,7 @@ static void FN(SplitByteVector)(MemoryManager* m,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
histograms = BROTLI_ALLOC(m, HistogramType, num_histograms);
|
histograms = BROTLI_ALLOC(m, HistogramType, num_histograms);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return;
|
||||||
/* Find good entropy codes. */
|
/* Find good entropy codes. */
|
||||||
FN(InitialEntropyCodes)(data, length,
|
FN(InitialEntropyCodes)(data, length,
|
||||||
sampling_stride_length,
|
sampling_stride_length,
|
||||||
|
@ -405,7 +410,11 @@ static void FN(SplitByteVector)(MemoryManager* m,
|
||||||
uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms);
|
uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms);
|
||||||
const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
|
const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
|
||||||
size_t i;
|
size_t i;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(block_ids) ||
|
||||||
|
BROTLI_IS_NULL(insert_cost) || BROTLI_IS_NULL(cost) ||
|
||||||
|
BROTLI_IS_NULL(switch_signal) || BROTLI_IS_NULL(new_id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (i = 0; i < iters; ++i) {
|
for (i = 0; i < iters; ++i) {
|
||||||
num_blocks = FN(FindBlocks)(data, length,
|
num_blocks = FN(FindBlocks)(data, length,
|
||||||
block_switch_cost,
|
block_switch_cost,
|
||||||
|
|
|
@ -13,13 +13,14 @@
|
||||||
#include <string.h> /* memcpy, memset */
|
#include <string.h> /* memcpy, memset */
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/context.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./context.h"
|
|
||||||
#include "./entropy_encode.h"
|
#include "./entropy_encode.h"
|
||||||
#include "./entropy_encode_static.h"
|
#include "./entropy_encode_static.h"
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
|
#include "./histogram.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./write_bits.h"
|
#include "./write_bits.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -27,40 +28,24 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_HUFFMAN_TREE_SIZE (2 * BROTLI_NUM_COMMAND_SYMBOLS + 1)
|
#define MAX_HUFFMAN_TREE_SIZE (2 * BROTLI_NUM_COMMAND_SYMBOLS + 1)
|
||||||
/* The size of Huffman dictionary for distances assuming that NPOSTFIX = 0 and
|
/* The maximum size of Huffman dictionary for distances assuming that
|
||||||
NDIRECT = 0. */
|
NPOSTFIX = 0 and NDIRECT = 0. */
|
||||||
#define SIMPLE_DISTANCE_ALPHABET_SIZE (BROTLI_NUM_DISTANCE_SHORT_CODES + \
|
#define MAX_SIMPLE_DISTANCE_ALPHABET_SIZE \
|
||||||
(2 * BROTLI_MAX_DISTANCE_BITS))
|
BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_LARGE_MAX_DISTANCE_BITS)
|
||||||
/* SIMPLE_DISTANCE_ALPHABET_SIZE == 64 */
|
/* MAX_SIMPLE_DISTANCE_ALPHABET_SIZE == 140 */
|
||||||
#define SIMPLE_DISTANCE_ALPHABET_BITS 6
|
|
||||||
|
|
||||||
/* Represents the range of values belonging to a prefix code:
|
|
||||||
[offset, offset + 2^nbits) */
|
|
||||||
typedef struct PrefixCodeRange {
|
|
||||||
uint32_t offset;
|
|
||||||
uint32_t nbits;
|
|
||||||
} PrefixCodeRange;
|
|
||||||
|
|
||||||
static const PrefixCodeRange
|
|
||||||
kBlockLengthPrefixCode[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
|
|
||||||
{ 1, 2}, { 5, 2}, { 9, 2}, {13, 2}, {17, 3}, { 25, 3}, { 33, 3},
|
|
||||||
{41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4}, {113, 5}, {145, 5},
|
|
||||||
{177, 5}, { 209, 5}, { 241, 6}, { 305, 6}, { 369, 7}, { 497, 8},
|
|
||||||
{753, 9}, {1265, 10}, {2289, 11}, {4337, 12}, {8433, 13}, {16625, 24}
|
|
||||||
};
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t BlockLengthPrefixCode(uint32_t len) {
|
static BROTLI_INLINE uint32_t BlockLengthPrefixCode(uint32_t len) {
|
||||||
uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0);
|
uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0);
|
||||||
while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) &&
|
while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) &&
|
||||||
len >= kBlockLengthPrefixCode[code + 1].offset) ++code;
|
len >= _kBrotliPrefixCodeRanges[code + 1].offset) ++code;
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void GetBlockLengthPrefixCode(uint32_t len, size_t* code,
|
static BROTLI_INLINE void GetBlockLengthPrefixCode(uint32_t len, size_t* code,
|
||||||
uint32_t* n_extra, uint32_t* extra) {
|
uint32_t* n_extra, uint32_t* extra) {
|
||||||
*code = BlockLengthPrefixCode(len);
|
*code = BlockLengthPrefixCode(len);
|
||||||
*n_extra = kBlockLengthPrefixCode[*code].nbits;
|
*n_extra = _kBrotliPrefixCodeRanges[*code].nbits;
|
||||||
*extra = len - kBlockLengthPrefixCode[*code].offset;
|
*extra = len - _kBrotliPrefixCodeRanges[*code].offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct BlockTypeCodeCalculator {
|
typedef struct BlockTypeCodeCalculator {
|
||||||
|
@ -89,9 +74,9 @@ static void BrotliEncodeMlen(size_t length, uint64_t* bits,
|
||||||
size_t* numbits, uint64_t* nibblesbits) {
|
size_t* numbits, uint64_t* nibblesbits) {
|
||||||
size_t lg = (length == 1) ? 1 : Log2FloorNonZero((uint32_t)(length - 1)) + 1;
|
size_t lg = (length == 1) ? 1 : Log2FloorNonZero((uint32_t)(length - 1)) + 1;
|
||||||
size_t mnibbles = (lg < 16 ? 16 : (lg + 3)) / 4;
|
size_t mnibbles = (lg < 16 ? 16 : (lg + 3)) / 4;
|
||||||
assert(length > 0);
|
BROTLI_DCHECK(length > 0);
|
||||||
assert(length <= (1 << 24));
|
BROTLI_DCHECK(length <= (1 << 24));
|
||||||
assert(lg <= 24);
|
BROTLI_DCHECK(lg <= 24);
|
||||||
*nibblesbits = mnibbles - 4;
|
*nibblesbits = mnibbles - 4;
|
||||||
*numbits = mnibbles * 4;
|
*numbits = mnibbles * 4;
|
||||||
*bits = length - 1;
|
*bits = length - 1;
|
||||||
|
@ -258,7 +243,7 @@ static void StoreSimpleHuffmanTree(const uint8_t* depths,
|
||||||
size_t symbols[4],
|
size_t symbols[4],
|
||||||
size_t num_symbols,
|
size_t num_symbols,
|
||||||
size_t max_bits,
|
size_t max_bits,
|
||||||
size_t *storage_ix, uint8_t *storage) {
|
size_t* storage_ix, uint8_t* storage) {
|
||||||
/* value of 1 indicates a simple Huffman code */
|
/* value of 1 indicates a simple Huffman code */
|
||||||
BrotliWriteBits(2, 1, storage_ix, storage);
|
BrotliWriteBits(2, 1, storage_ix, storage);
|
||||||
BrotliWriteBits(2, num_symbols - 1, storage_ix, storage); /* NSYM - 1 */
|
BrotliWriteBits(2, num_symbols - 1, storage_ix, storage); /* NSYM - 1 */
|
||||||
|
@ -297,7 +282,7 @@ static void StoreSimpleHuffmanTree(const uint8_t* depths,
|
||||||
depths = symbol depths */
|
depths = symbol depths */
|
||||||
void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||||
HuffmanTree* tree,
|
HuffmanTree* tree,
|
||||||
size_t *storage_ix, uint8_t *storage) {
|
size_t* storage_ix, uint8_t* storage) {
|
||||||
/* Write the Huffman tree into the brotli-representation.
|
/* Write the Huffman tree into the brotli-representation.
|
||||||
The command alphabet is the largest, so this allocation will fit all
|
The command alphabet is the largest, so this allocation will fit all
|
||||||
alphabets. */
|
alphabets. */
|
||||||
|
@ -311,7 +296,7 @@ void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||||
int num_codes = 0;
|
int num_codes = 0;
|
||||||
size_t code = 0;
|
size_t code = 0;
|
||||||
|
|
||||||
assert(num <= BROTLI_NUM_COMMAND_SYMBOLS);
|
BROTLI_DCHECK(num <= BROTLI_NUM_COMMAND_SYMBOLS);
|
||||||
|
|
||||||
BrotliWriteHuffmanTree(depths, num, &huffman_tree_size, huffman_tree,
|
BrotliWriteHuffmanTree(depths, num, &huffman_tree_size, huffman_tree,
|
||||||
huffman_tree_extra_bits);
|
huffman_tree_extra_bits);
|
||||||
|
@ -360,8 +345,9 @@ void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||||
|
|
||||||
/* Builds a Huffman tree from histogram[0:length] into depth[0:length] and
|
/* Builds a Huffman tree from histogram[0:length] into depth[0:length] and
|
||||||
bits[0:length] and stores the encoded tree to the bit stream. */
|
bits[0:length] and stores the encoded tree to the bit stream. */
|
||||||
static void BuildAndStoreHuffmanTree(const uint32_t *histogram,
|
static void BuildAndStoreHuffmanTree(const uint32_t* histogram,
|
||||||
const size_t length,
|
const size_t histogram_length,
|
||||||
|
const size_t alphabet_size,
|
||||||
HuffmanTree* tree,
|
HuffmanTree* tree,
|
||||||
uint8_t* depth,
|
uint8_t* depth,
|
||||||
uint16_t* bits,
|
uint16_t* bits,
|
||||||
|
@ -371,7 +357,7 @@ static void BuildAndStoreHuffmanTree(const uint32_t *histogram,
|
||||||
size_t s4[4] = { 0 };
|
size_t s4[4] = { 0 };
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t max_bits = 0;
|
size_t max_bits = 0;
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < histogram_length; i++) {
|
||||||
if (histogram[i]) {
|
if (histogram[i]) {
|
||||||
if (count < 4) {
|
if (count < 4) {
|
||||||
s4[count] = i;
|
s4[count] = i;
|
||||||
|
@ -383,7 +369,7 @@ static void BuildAndStoreHuffmanTree(const uint32_t *histogram,
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
size_t max_bits_counter = length - 1;
|
size_t max_bits_counter = alphabet_size - 1;
|
||||||
while (max_bits_counter) {
|
while (max_bits_counter) {
|
||||||
max_bits_counter >>= 1;
|
max_bits_counter >>= 1;
|
||||||
++max_bits;
|
++max_bits;
|
||||||
|
@ -398,14 +384,14 @@ static void BuildAndStoreHuffmanTree(const uint32_t *histogram,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(depth, 0, length * sizeof(depth[0]));
|
memset(depth, 0, histogram_length * sizeof(depth[0]));
|
||||||
BrotliCreateHuffmanTree(histogram, length, 15, tree, depth);
|
BrotliCreateHuffmanTree(histogram, histogram_length, 15, tree, depth);
|
||||||
BrotliConvertBitDepthsToSymbols(depth, length, bits);
|
BrotliConvertBitDepthsToSymbols(depth, histogram_length, bits);
|
||||||
|
|
||||||
if (count <= 4) {
|
if (count <= 4) {
|
||||||
StoreSimpleHuffmanTree(depth, s4, count, max_bits, storage_ix, storage);
|
StoreSimpleHuffmanTree(depth, s4, count, max_bits, storage_ix, storage);
|
||||||
} else {
|
} else {
|
||||||
BrotliStoreHuffmanTree(depth, length, tree, storage_ix, storage);
|
BrotliStoreHuffmanTree(depth, histogram_length, tree, storage_ix, storage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,7 +435,7 @@ void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
|
||||||
const size_t max_tree_size = 2 * length + 1;
|
const size_t max_tree_size = 2 * length + 1;
|
||||||
HuffmanTree* tree = BROTLI_ALLOC(m, HuffmanTree, max_tree_size);
|
HuffmanTree* tree = BROTLI_ALLOC(m, HuffmanTree, max_tree_size);
|
||||||
uint32_t count_limit;
|
uint32_t count_limit;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
|
||||||
for (count_limit = 1; ; count_limit *= 2) {
|
for (count_limit = 1; ; count_limit *= 2) {
|
||||||
HuffmanTree* node = tree;
|
HuffmanTree* node = tree;
|
||||||
size_t l;
|
size_t l;
|
||||||
|
@ -619,7 +605,7 @@ static void MoveToFrontTransform(const uint32_t* BROTLI_RESTRICT v_in,
|
||||||
for (i = 1; i < v_size; ++i) {
|
for (i = 1; i < v_size; ++i) {
|
||||||
if (v_in[i] > max_value) max_value = v_in[i];
|
if (v_in[i] > max_value) max_value = v_in[i];
|
||||||
}
|
}
|
||||||
assert(max_value < 256u);
|
BROTLI_DCHECK(max_value < 256u);
|
||||||
for (i = 0; i <= max_value; ++i) {
|
for (i = 0; i <= max_value; ++i) {
|
||||||
mtf[i] = (uint8_t)i;
|
mtf[i] = (uint8_t)i;
|
||||||
}
|
}
|
||||||
|
@ -627,7 +613,7 @@ static void MoveToFrontTransform(const uint32_t* BROTLI_RESTRICT v_in,
|
||||||
size_t mtf_size = max_value + 1;
|
size_t mtf_size = max_value + 1;
|
||||||
for (i = 0; i < v_size; ++i) {
|
for (i = 0; i < v_size; ++i) {
|
||||||
size_t index = IndexOf(mtf, mtf_size, (uint8_t)v_in[i]);
|
size_t index = IndexOf(mtf, mtf_size, (uint8_t)v_in[i]);
|
||||||
assert(index < mtf_size);
|
BROTLI_DCHECK(index < mtf_size);
|
||||||
v_out[i] = (uint32_t)index;
|
v_out[i] = (uint32_t)index;
|
||||||
MoveToFront(mtf, index);
|
MoveToFront(mtf, index);
|
||||||
}
|
}
|
||||||
|
@ -659,7 +645,7 @@ static void RunLengthCodeZeros(const size_t in_size,
|
||||||
*max_run_length_prefix = max_prefix;
|
*max_run_length_prefix = max_prefix;
|
||||||
*out_size = 0;
|
*out_size = 0;
|
||||||
for (i = 0; i < in_size;) {
|
for (i = 0; i < in_size;) {
|
||||||
assert(*out_size <= i);
|
BROTLI_DCHECK(*out_size <= i);
|
||||||
if (v[i] != 0) {
|
if (v[i] != 0) {
|
||||||
v[*out_size] = v[i] + *max_run_length_prefix;
|
v[*out_size] = v[i] + *max_run_length_prefix;
|
||||||
++i;
|
++i;
|
||||||
|
@ -713,7 +699,7 @@ static void EncodeContextMap(MemoryManager* m,
|
||||||
}
|
}
|
||||||
|
|
||||||
rle_symbols = BROTLI_ALLOC(m, uint32_t, context_map_size);
|
rle_symbols = BROTLI_ALLOC(m, uint32_t, context_map_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(rle_symbols)) return;
|
||||||
MoveToFrontTransform(context_map, context_map_size, rle_symbols);
|
MoveToFrontTransform(context_map, context_map_size, rle_symbols);
|
||||||
RunLengthCodeZeros(context_map_size, rle_symbols,
|
RunLengthCodeZeros(context_map_size, rle_symbols,
|
||||||
&num_rle_symbols, &max_run_length_prefix);
|
&num_rle_symbols, &max_run_length_prefix);
|
||||||
|
@ -729,6 +715,7 @@ static void EncodeContextMap(MemoryManager* m,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BuildAndStoreHuffmanTree(histogram, num_clusters + max_run_length_prefix,
|
BuildAndStoreHuffmanTree(histogram, num_clusters + max_run_length_prefix,
|
||||||
|
num_clusters + max_run_length_prefix,
|
||||||
tree, depths, bits, storage_ix, storage);
|
tree, depths, bits, storage_ix, storage);
|
||||||
for (i = 0; i < num_rle_symbols; ++i) {
|
for (i = 0; i < num_rle_symbols; ++i) {
|
||||||
const uint32_t rle_symbol = rle_symbols[i] & kSymbolMask;
|
const uint32_t rle_symbol = rle_symbols[i] & kSymbolMask;
|
||||||
|
@ -788,10 +775,11 @@ static void BuildAndStoreBlockSplitCode(const uint8_t* types,
|
||||||
}
|
}
|
||||||
StoreVarLenUint8(num_types - 1, storage_ix, storage);
|
StoreVarLenUint8(num_types - 1, storage_ix, storage);
|
||||||
if (num_types > 1) { /* TODO: else? could StoreBlockSwitch occur? */
|
if (num_types > 1) { /* TODO: else? could StoreBlockSwitch occur? */
|
||||||
BuildAndStoreHuffmanTree(&type_histo[0], num_types + 2, tree,
|
BuildAndStoreHuffmanTree(&type_histo[0], num_types + 2, num_types + 2, tree,
|
||||||
&code->type_depths[0], &code->type_bits[0],
|
&code->type_depths[0], &code->type_bits[0],
|
||||||
storage_ix, storage);
|
storage_ix, storage);
|
||||||
BuildAndStoreHuffmanTree(&length_histo[0], BROTLI_NUM_BLOCK_LEN_SYMBOLS,
|
BuildAndStoreHuffmanTree(&length_histo[0], BROTLI_NUM_BLOCK_LEN_SYMBOLS,
|
||||||
|
BROTLI_NUM_BLOCK_LEN_SYMBOLS,
|
||||||
tree, &code->length_depths[0],
|
tree, &code->length_depths[0],
|
||||||
&code->length_bits[0], storage_ix, storage);
|
&code->length_bits[0], storage_ix, storage);
|
||||||
StoreBlockSwitch(code, lengths[0], types[0], 1, storage_ix, storage);
|
StoreBlockSwitch(code, lengths[0], types[0], 1, storage_ix, storage);
|
||||||
|
@ -822,8 +810,8 @@ static void StoreTrivialContextMap(size_t num_types,
|
||||||
for (i = context_bits; i < alphabet_size; ++i) {
|
for (i = context_bits; i < alphabet_size; ++i) {
|
||||||
histogram[i] = 1;
|
histogram[i] = 1;
|
||||||
}
|
}
|
||||||
BuildAndStoreHuffmanTree(histogram, alphabet_size, tree,
|
BuildAndStoreHuffmanTree(histogram, alphabet_size, alphabet_size,
|
||||||
depths, bits, storage_ix, storage);
|
tree, depths, bits, storage_ix, storage);
|
||||||
for (i = 0; i < num_types; ++i) {
|
for (i = 0; i < num_types; ++i) {
|
||||||
size_t code = (i == 0 ? 0 : i + context_bits - 1);
|
size_t code = (i == 0 ? 0 : i + context_bits - 1);
|
||||||
BrotliWriteBits(depths[code], bits[code], storage_ix, storage);
|
BrotliWriteBits(depths[code], bits[code], storage_ix, storage);
|
||||||
|
@ -838,7 +826,7 @@ static void StoreTrivialContextMap(size_t num_types,
|
||||||
|
|
||||||
/* Manages the encoding of one block category (literal, command or distance). */
|
/* Manages the encoding of one block category (literal, command or distance). */
|
||||||
typedef struct BlockEncoder {
|
typedef struct BlockEncoder {
|
||||||
size_t alphabet_size_;
|
size_t histogram_length_;
|
||||||
size_t num_block_types_;
|
size_t num_block_types_;
|
||||||
const uint8_t* block_types_; /* Not owned. */
|
const uint8_t* block_types_; /* Not owned. */
|
||||||
const uint32_t* block_lengths_; /* Not owned. */
|
const uint32_t* block_lengths_; /* Not owned. */
|
||||||
|
@ -851,10 +839,10 @@ typedef struct BlockEncoder {
|
||||||
uint16_t* bits_;
|
uint16_t* bits_;
|
||||||
} BlockEncoder;
|
} BlockEncoder;
|
||||||
|
|
||||||
static void InitBlockEncoder(BlockEncoder* self, size_t alphabet_size,
|
static void InitBlockEncoder(BlockEncoder* self, size_t histogram_length,
|
||||||
size_t num_block_types, const uint8_t* block_types,
|
size_t num_block_types, const uint8_t* block_types,
|
||||||
const uint32_t* block_lengths, const size_t num_blocks) {
|
const uint32_t* block_lengths, const size_t num_blocks) {
|
||||||
self->alphabet_size_ = alphabet_size;
|
self->histogram_length_ = histogram_length;
|
||||||
self->num_block_types_ = num_block_types;
|
self->num_block_types_ = num_block_types;
|
||||||
self->block_types_ = block_types;
|
self->block_types_ = block_types;
|
||||||
self->block_lengths_ = block_lengths;
|
self->block_lengths_ = block_lengths;
|
||||||
|
@ -890,7 +878,7 @@ static void StoreSymbol(BlockEncoder* self, size_t symbol, size_t* storage_ix,
|
||||||
uint32_t block_len = self->block_lengths_[block_ix];
|
uint32_t block_len = self->block_lengths_[block_ix];
|
||||||
uint8_t block_type = self->block_types_[block_ix];
|
uint8_t block_type = self->block_types_[block_ix];
|
||||||
self->block_len_ = block_len;
|
self->block_len_ = block_len;
|
||||||
self->entropy_ix_ = block_type * self->alphabet_size_;
|
self->entropy_ix_ = block_type * self->histogram_length_;
|
||||||
StoreBlockSwitch(&self->block_split_code_, block_len, block_type, 0,
|
StoreBlockSwitch(&self->block_split_code_, block_len, block_type, 0,
|
||||||
storage_ix, storage);
|
storage_ix, storage);
|
||||||
}
|
}
|
||||||
|
@ -919,7 +907,7 @@ static void StoreSymbolWithContext(BlockEncoder* self, size_t symbol,
|
||||||
--self->block_len_;
|
--self->block_len_;
|
||||||
{
|
{
|
||||||
size_t histo_ix = context_map[self->entropy_ix_ + context];
|
size_t histo_ix = context_map[self->entropy_ix_ + context];
|
||||||
size_t ix = histo_ix * self->alphabet_size_ + symbol;
|
size_t ix = histo_ix * self->histogram_length_ + symbol;
|
||||||
BrotliWriteBits(self->depths_[ix], self->bits_[ix], storage_ix, storage);
|
BrotliWriteBits(self->depths_[ix], self->bits_[ix], storage_ix, storage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -945,42 +933,36 @@ static void JumpToByteBoundary(size_t* storage_ix, uint8_t* storage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliStoreMetaBlock(MemoryManager* m,
|
void BrotliStoreMetaBlock(MemoryManager* m,
|
||||||
const uint8_t* input,
|
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||||
size_t start_pos,
|
uint8_t prev_byte, uint8_t prev_byte2, BROTLI_BOOL is_last,
|
||||||
size_t length,
|
const BrotliEncoderParams* params, ContextType literal_context_mode,
|
||||||
size_t mask,
|
const Command* commands, size_t n_commands, const MetaBlockSplit* mb,
|
||||||
uint8_t prev_byte,
|
size_t* storage_ix, uint8_t* storage) {
|
||||||
uint8_t prev_byte2,
|
|
||||||
BROTLI_BOOL is_last,
|
|
||||||
uint32_t num_direct_distance_codes,
|
|
||||||
uint32_t distance_postfix_bits,
|
|
||||||
ContextType literal_context_mode,
|
|
||||||
const Command *commands,
|
|
||||||
size_t n_commands,
|
|
||||||
const MetaBlockSplit* mb,
|
|
||||||
size_t *storage_ix,
|
|
||||||
uint8_t *storage) {
|
|
||||||
size_t pos = start_pos;
|
size_t pos = start_pos;
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t num_distance_codes =
|
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||||
BROTLI_NUM_DISTANCE_SHORT_CODES + num_direct_distance_codes +
|
uint32_t num_effective_distance_symbols = params->dist.alphabet_size_limit;
|
||||||
(48u << distance_postfix_bits);
|
|
||||||
HuffmanTree* tree;
|
HuffmanTree* tree;
|
||||||
|
ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
|
||||||
BlockEncoder literal_enc;
|
BlockEncoder literal_enc;
|
||||||
BlockEncoder command_enc;
|
BlockEncoder command_enc;
|
||||||
BlockEncoder distance_enc;
|
BlockEncoder distance_enc;
|
||||||
|
const BrotliDistanceParams* dist = ¶ms->dist;
|
||||||
|
BROTLI_DCHECK(
|
||||||
|
num_effective_distance_symbols <= BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS);
|
||||||
|
|
||||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||||
|
|
||||||
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
|
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
|
||||||
InitBlockEncoder(&literal_enc, 256, mb->literal_split.num_types,
|
InitBlockEncoder(&literal_enc, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||||
mb->literal_split.types, mb->literal_split.lengths,
|
mb->literal_split.num_types, mb->literal_split.types,
|
||||||
mb->literal_split.num_blocks);
|
mb->literal_split.lengths, mb->literal_split.num_blocks);
|
||||||
InitBlockEncoder(&command_enc, BROTLI_NUM_COMMAND_SYMBOLS,
|
InitBlockEncoder(&command_enc, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||||
mb->command_split.num_types, mb->command_split.types,
|
mb->command_split.num_types, mb->command_split.types,
|
||||||
mb->command_split.lengths, mb->command_split.num_blocks);
|
mb->command_split.lengths, mb->command_split.num_blocks);
|
||||||
InitBlockEncoder(&distance_enc, num_distance_codes,
|
InitBlockEncoder(&distance_enc, num_effective_distance_symbols,
|
||||||
mb->distance_split.num_types, mb->distance_split.types,
|
mb->distance_split.num_types, mb->distance_split.types,
|
||||||
mb->distance_split.lengths, mb->distance_split.num_blocks);
|
mb->distance_split.lengths, mb->distance_split.num_blocks);
|
||||||
|
|
||||||
|
@ -989,9 +971,10 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||||
BuildAndStoreBlockSwitchEntropyCodes(
|
BuildAndStoreBlockSwitchEntropyCodes(
|
||||||
&distance_enc, tree, storage_ix, storage);
|
&distance_enc, tree, storage_ix, storage);
|
||||||
|
|
||||||
BrotliWriteBits(2, distance_postfix_bits, storage_ix, storage);
|
BrotliWriteBits(2, dist->distance_postfix_bits, storage_ix, storage);
|
||||||
BrotliWriteBits(4, num_direct_distance_codes >> distance_postfix_bits,
|
BrotliWriteBits(
|
||||||
storage_ix, storage);
|
4, dist->num_direct_distance_codes >> dist->distance_postfix_bits,
|
||||||
|
storage_ix, storage);
|
||||||
for (i = 0; i < mb->literal_split.num_types; ++i) {
|
for (i = 0; i < mb->literal_split.num_types; ++i) {
|
||||||
BrotliWriteBits(2, literal_context_mode, storage_ix, storage);
|
BrotliWriteBits(2, literal_context_mode, storage_ix, storage);
|
||||||
}
|
}
|
||||||
|
@ -1017,13 +1000,16 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildAndStoreEntropyCodesLiteral(m, &literal_enc, mb->literal_histograms,
|
BuildAndStoreEntropyCodesLiteral(m, &literal_enc, mb->literal_histograms,
|
||||||
mb->literal_histograms_size, tree, storage_ix, storage);
|
mb->literal_histograms_size, BROTLI_NUM_LITERAL_SYMBOLS, tree,
|
||||||
|
storage_ix, storage);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
BuildAndStoreEntropyCodesCommand(m, &command_enc, mb->command_histograms,
|
BuildAndStoreEntropyCodesCommand(m, &command_enc, mb->command_histograms,
|
||||||
mb->command_histograms_size, tree, storage_ix, storage);
|
mb->command_histograms_size, BROTLI_NUM_COMMAND_SYMBOLS, tree,
|
||||||
|
storage_ix, storage);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
BuildAndStoreEntropyCodesDistance(m, &distance_enc, mb->distance_histograms,
|
BuildAndStoreEntropyCodesDistance(m, &distance_enc, mb->distance_histograms,
|
||||||
mb->distance_histograms_size, tree, storage_ix, storage);
|
mb->distance_histograms_size, num_distance_symbols, tree,
|
||||||
|
storage_ix, storage);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
BROTLI_FREE(m, tree);
|
BROTLI_FREE(m, tree);
|
||||||
|
|
||||||
|
@ -1041,7 +1027,8 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||||
} else {
|
} else {
|
||||||
size_t j;
|
size_t j;
|
||||||
for (j = cmd.insert_len_; j != 0; --j) {
|
for (j = cmd.insert_len_; j != 0; --j) {
|
||||||
size_t context = Context(prev_byte, prev_byte2, literal_context_mode);
|
size_t context =
|
||||||
|
BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
|
||||||
uint8_t literal = input[pos & mask];
|
uint8_t literal = input[pos & mask];
|
||||||
StoreSymbolWithContext(&literal_enc, literal, context,
|
StoreSymbolWithContext(&literal_enc, literal, context,
|
||||||
mb->literal_context_map, storage_ix, storage,
|
mb->literal_context_map, storage_ix, storage,
|
||||||
|
@ -1056,9 +1043,9 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||||
prev_byte2 = input[(pos - 2) & mask];
|
prev_byte2 = input[(pos - 2) & mask];
|
||||||
prev_byte = input[(pos - 1) & mask];
|
prev_byte = input[(pos - 1) & mask];
|
||||||
if (cmd.cmd_prefix_ >= 128) {
|
if (cmd.cmd_prefix_ >= 128) {
|
||||||
size_t dist_code = cmd.dist_prefix_;
|
size_t dist_code = cmd.dist_prefix_ & 0x3FF;
|
||||||
uint32_t distnumextra = cmd.dist_extra_ >> 24;
|
uint32_t distnumextra = cmd.dist_prefix_ >> 10;
|
||||||
uint64_t distextra = cmd.dist_extra_ & 0xffffff;
|
uint64_t distextra = cmd.dist_extra_;
|
||||||
if (mb->distance_context_map_size == 0) {
|
if (mb->distance_context_map_size == 0) {
|
||||||
StoreSymbol(&distance_enc, dist_code, storage_ix, storage);
|
StoreSymbol(&distance_enc, dist_code, storage_ix, storage);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1082,7 +1069,7 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||||
static void BuildHistograms(const uint8_t* input,
|
static void BuildHistograms(const uint8_t* input,
|
||||||
size_t start_pos,
|
size_t start_pos,
|
||||||
size_t mask,
|
size_t mask,
|
||||||
const Command *commands,
|
const Command* commands,
|
||||||
size_t n_commands,
|
size_t n_commands,
|
||||||
HistogramLiteral* lit_histo,
|
HistogramLiteral* lit_histo,
|
||||||
HistogramCommand* cmd_histo,
|
HistogramCommand* cmd_histo,
|
||||||
|
@ -1099,7 +1086,7 @@ static void BuildHistograms(const uint8_t* input,
|
||||||
}
|
}
|
||||||
pos += CommandCopyLen(&cmd);
|
pos += CommandCopyLen(&cmd);
|
||||||
if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) {
|
if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) {
|
||||||
HistogramAddDistance(dist_histo, cmd.dist_prefix_);
|
HistogramAddDistance(dist_histo, cmd.dist_prefix_ & 0x3FF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1107,7 +1094,7 @@ static void BuildHistograms(const uint8_t* input,
|
||||||
static void StoreDataWithHuffmanCodes(const uint8_t* input,
|
static void StoreDataWithHuffmanCodes(const uint8_t* input,
|
||||||
size_t start_pos,
|
size_t start_pos,
|
||||||
size_t mask,
|
size_t mask,
|
||||||
const Command *commands,
|
const Command* commands,
|
||||||
size_t n_commands,
|
size_t n_commands,
|
||||||
const uint8_t* lit_depth,
|
const uint8_t* lit_depth,
|
||||||
const uint16_t* lit_bits,
|
const uint16_t* lit_bits,
|
||||||
|
@ -1134,9 +1121,9 @@ static void StoreDataWithHuffmanCodes(const uint8_t* input,
|
||||||
}
|
}
|
||||||
pos += CommandCopyLen(&cmd);
|
pos += CommandCopyLen(&cmd);
|
||||||
if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) {
|
if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) {
|
||||||
const size_t dist_code = cmd.dist_prefix_;
|
const size_t dist_code = cmd.dist_prefix_ & 0x3FF;
|
||||||
const uint32_t distnumextra = cmd.dist_extra_ >> 24;
|
const uint32_t distnumextra = cmd.dist_prefix_ >> 10;
|
||||||
const uint32_t distextra = cmd.dist_extra_ & 0xffffff;
|
const uint32_t distextra = cmd.dist_extra_;
|
||||||
BrotliWriteBits(dist_depth[dist_code], dist_bits[dist_code],
|
BrotliWriteBits(dist_depth[dist_code], dist_bits[dist_code],
|
||||||
storage_ix, storage);
|
storage_ix, storage);
|
||||||
BrotliWriteBits(distnumextra, distextra, storage_ix, storage);
|
BrotliWriteBits(distnumextra, distextra, storage_ix, storage);
|
||||||
|
@ -1145,15 +1132,10 @@ static void StoreDataWithHuffmanCodes(const uint8_t* input,
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||||
const uint8_t* input,
|
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||||
size_t start_pos,
|
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||||
size_t length,
|
const Command* commands, size_t n_commands,
|
||||||
size_t mask,
|
size_t* storage_ix, uint8_t* storage) {
|
||||||
BROTLI_BOOL is_last,
|
|
||||||
const Command *commands,
|
|
||||||
size_t n_commands,
|
|
||||||
size_t *storage_ix,
|
|
||||||
uint8_t *storage) {
|
|
||||||
HistogramLiteral lit_histo;
|
HistogramLiteral lit_histo;
|
||||||
HistogramCommand cmd_histo;
|
HistogramCommand cmd_histo;
|
||||||
HistogramDistance dist_histo;
|
HistogramDistance dist_histo;
|
||||||
|
@ -1161,9 +1143,10 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||||
uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
|
uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||||
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||||
uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS];
|
uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||||
uint8_t dist_depth[SIMPLE_DISTANCE_ALPHABET_SIZE];
|
uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||||
uint16_t dist_bits[SIMPLE_DISTANCE_ALPHABET_SIZE];
|
uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||||
HuffmanTree* tree;
|
HuffmanTree* tree;
|
||||||
|
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||||
|
|
||||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||||
|
|
||||||
|
@ -1177,15 +1160,17 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||||
|
|
||||||
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
|
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
|
||||||
BuildAndStoreHuffmanTree(lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS, tree,
|
BuildAndStoreHuffmanTree(lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||||
|
BROTLI_NUM_LITERAL_SYMBOLS, tree,
|
||||||
lit_depth, lit_bits,
|
lit_depth, lit_bits,
|
||||||
storage_ix, storage);
|
storage_ix, storage);
|
||||||
BuildAndStoreHuffmanTree(cmd_histo.data_, BROTLI_NUM_COMMAND_SYMBOLS, tree,
|
BuildAndStoreHuffmanTree(cmd_histo.data_, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||||
|
BROTLI_NUM_COMMAND_SYMBOLS, tree,
|
||||||
cmd_depth, cmd_bits,
|
cmd_depth, cmd_bits,
|
||||||
storage_ix, storage);
|
storage_ix, storage);
|
||||||
BuildAndStoreHuffmanTree(dist_histo.data_, SIMPLE_DISTANCE_ALPHABET_SIZE,
|
BuildAndStoreHuffmanTree(dist_histo.data_, MAX_SIMPLE_DISTANCE_ALPHABET_SIZE,
|
||||||
tree,
|
num_distance_symbols, tree,
|
||||||
dist_depth, dist_bits,
|
dist_depth, dist_bits,
|
||||||
storage_ix, storage);
|
storage_ix, storage);
|
||||||
BROTLI_FREE(m, tree);
|
BROTLI_FREE(m, tree);
|
||||||
|
@ -1200,15 +1185,14 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliStoreMetaBlockFast(MemoryManager* m,
|
void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||||
const uint8_t* input,
|
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||||
size_t start_pos,
|
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||||
size_t length,
|
const Command* commands, size_t n_commands,
|
||||||
size_t mask,
|
size_t* storage_ix, uint8_t* storage) {
|
||||||
BROTLI_BOOL is_last,
|
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||||
const Command *commands,
|
uint32_t distance_alphabet_bits =
|
||||||
size_t n_commands,
|
Log2FloorNonZero(num_distance_symbols - 1) + 1;
|
||||||
size_t *storage_ix,
|
|
||||||
uint8_t *storage) {
|
|
||||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||||
|
|
||||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||||
|
@ -1252,8 +1236,8 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||||
uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
|
uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||||
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||||
uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS];
|
uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||||
uint8_t dist_depth[SIMPLE_DISTANCE_ALPHABET_SIZE];
|
uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||||
uint16_t dist_bits[SIMPLE_DISTANCE_ALPHABET_SIZE];
|
uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||||
HistogramClearLiteral(&lit_histo);
|
HistogramClearLiteral(&lit_histo);
|
||||||
HistogramClearCommand(&cmd_histo);
|
HistogramClearCommand(&cmd_histo);
|
||||||
HistogramClearDistance(&dist_histo);
|
HistogramClearDistance(&dist_histo);
|
||||||
|
@ -1274,7 +1258,7 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||||
BrotliBuildAndStoreHuffmanTreeFast(m, dist_histo.data_,
|
BrotliBuildAndStoreHuffmanTreeFast(m, dist_histo.data_,
|
||||||
dist_histo.total_count_,
|
dist_histo.total_count_,
|
||||||
/* max_bits = */
|
/* max_bits = */
|
||||||
SIMPLE_DISTANCE_ALPHABET_BITS,
|
distance_alphabet_bits,
|
||||||
dist_depth, dist_bits,
|
dist_depth, dist_bits,
|
||||||
storage_ix, storage);
|
storage_ix, storage);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
|
@ -1293,11 +1277,11 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||||
/* This is for storing uncompressed blocks (simple raw storage of
|
/* This is for storing uncompressed blocks (simple raw storage of
|
||||||
bytes-as-bytes). */
|
bytes-as-bytes). */
|
||||||
void BrotliStoreUncompressedMetaBlock(BROTLI_BOOL is_final_block,
|
void BrotliStoreUncompressedMetaBlock(BROTLI_BOOL is_final_block,
|
||||||
const uint8_t * BROTLI_RESTRICT input,
|
const uint8_t* BROTLI_RESTRICT input,
|
||||||
size_t position, size_t mask,
|
size_t position, size_t mask,
|
||||||
size_t len,
|
size_t len,
|
||||||
size_t * BROTLI_RESTRICT storage_ix,
|
size_t* BROTLI_RESTRICT storage_ix,
|
||||||
uint8_t * BROTLI_RESTRICT storage) {
|
uint8_t* BROTLI_RESTRICT storage) {
|
||||||
size_t masked_pos = position & mask;
|
size_t masked_pos = position & mask;
|
||||||
BrotliStoreUncompressedMetaBlockHeader(len, storage_ix, storage);
|
BrotliStoreUncompressedMetaBlockHeader(len, storage_ix, storage);
|
||||||
JumpToByteBoundary(storage_ix, storage);
|
JumpToByteBoundary(storage_ix, storage);
|
||||||
|
|
|
@ -16,13 +16,13 @@
|
||||||
#ifndef BROTLI_ENC_BROTLI_BIT_STREAM_H_
|
#ifndef BROTLI_ENC_BROTLI_BIT_STREAM_H_
|
||||||
#define BROTLI_ENC_BROTLI_BIT_STREAM_H_
|
#define BROTLI_ENC_BROTLI_BIT_STREAM_H_
|
||||||
|
|
||||||
|
#include "../common/context.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./command.h"
|
#include "./command.h"
|
||||||
#include "./context.h"
|
|
||||||
#include "./entropy_encode.h"
|
#include "./entropy_encode.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./metablock.h"
|
#include "./metablock.h"
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -32,7 +32,7 @@ extern "C" {
|
||||||
position for the current storage. */
|
position for the current storage. */
|
||||||
|
|
||||||
BROTLI_INTERNAL void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
BROTLI_INTERNAL void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||||
HuffmanTree* tree, size_t *storage_ix, uint8_t *storage);
|
HuffmanTree* tree, size_t* storage_ix, uint8_t* storage);
|
||||||
|
|
||||||
BROTLI_INTERNAL void BrotliBuildAndStoreHuffmanTreeFast(
|
BROTLI_INTERNAL void BrotliBuildAndStoreHuffmanTreeFast(
|
||||||
MemoryManager* m, const uint32_t* histogram, const size_t histogram_total,
|
MemoryManager* m, const uint32_t* histogram, const size_t histogram_total,
|
||||||
|
@ -42,59 +42,40 @@ BROTLI_INTERNAL void BrotliBuildAndStoreHuffmanTreeFast(
|
||||||
/* REQUIRES: length > 0 */
|
/* REQUIRES: length > 0 */
|
||||||
/* REQUIRES: length <= (1 << 24) */
|
/* REQUIRES: length <= (1 << 24) */
|
||||||
BROTLI_INTERNAL void BrotliStoreMetaBlock(MemoryManager* m,
|
BROTLI_INTERNAL void BrotliStoreMetaBlock(MemoryManager* m,
|
||||||
const uint8_t* input,
|
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||||
size_t start_pos,
|
uint8_t prev_byte, uint8_t prev_byte2, BROTLI_BOOL is_last,
|
||||||
size_t length,
|
const BrotliEncoderParams* params, ContextType literal_context_mode,
|
||||||
size_t mask,
|
const Command* commands, size_t n_commands, const MetaBlockSplit* mb,
|
||||||
uint8_t prev_byte,
|
size_t* storage_ix, uint8_t* storage);
|
||||||
uint8_t prev_byte2,
|
|
||||||
BROTLI_BOOL is_final_block,
|
|
||||||
uint32_t num_direct_distance_codes,
|
|
||||||
uint32_t distance_postfix_bits,
|
|
||||||
ContextType literal_context_mode,
|
|
||||||
const Command* commands,
|
|
||||||
size_t n_commands,
|
|
||||||
const MetaBlockSplit* mb,
|
|
||||||
size_t* storage_ix,
|
|
||||||
uint8_t* storage);
|
|
||||||
|
|
||||||
/* Stores the meta-block without doing any block splitting, just collects
|
/* Stores the meta-block without doing any block splitting, just collects
|
||||||
one histogram per block category and uses that for entropy coding.
|
one histogram per block category and uses that for entropy coding.
|
||||||
REQUIRES: length > 0
|
REQUIRES: length > 0
|
||||||
REQUIRES: length <= (1 << 24) */
|
REQUIRES: length <= (1 << 24) */
|
||||||
BROTLI_INTERNAL void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
BROTLI_INTERNAL void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||||
const uint8_t* input,
|
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||||
size_t start_pos,
|
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||||
size_t length,
|
const Command* commands, size_t n_commands,
|
||||||
size_t mask,
|
size_t* storage_ix, uint8_t* storage);
|
||||||
BROTLI_BOOL is_last,
|
|
||||||
const Command *commands,
|
|
||||||
size_t n_commands,
|
|
||||||
size_t* storage_ix,
|
|
||||||
uint8_t* storage);
|
|
||||||
|
|
||||||
/* Same as above, but uses static prefix codes for histograms with a only a few
|
/* Same as above, but uses static prefix codes for histograms with a only a few
|
||||||
symbols, and uses static code length prefix codes for all other histograms.
|
symbols, and uses static code length prefix codes for all other histograms.
|
||||||
REQUIRES: length > 0
|
REQUIRES: length > 0
|
||||||
REQUIRES: length <= (1 << 24) */
|
REQUIRES: length <= (1 << 24) */
|
||||||
BROTLI_INTERNAL void BrotliStoreMetaBlockFast(MemoryManager* m,
|
BROTLI_INTERNAL void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||||
const uint8_t* input,
|
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||||
size_t start_pos,
|
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||||
size_t length,
|
const Command* commands, size_t n_commands,
|
||||||
size_t mask,
|
size_t* storage_ix, uint8_t* storage);
|
||||||
BROTLI_BOOL is_last,
|
|
||||||
const Command *commands,
|
|
||||||
size_t n_commands,
|
|
||||||
size_t* storage_ix,
|
|
||||||
uint8_t* storage);
|
|
||||||
|
|
||||||
/* This is for storing uncompressed blocks (simple raw storage of
|
/* This is for storing uncompressed blocks (simple raw storage of
|
||||||
bytes-as-bytes).
|
bytes-as-bytes).
|
||||||
REQUIRES: length > 0
|
REQUIRES: length > 0
|
||||||
REQUIRES: length <= (1 << 24) */
|
REQUIRES: length <= (1 << 24) */
|
||||||
BROTLI_INTERNAL void BrotliStoreUncompressedMetaBlock(
|
BROTLI_INTERNAL void BrotliStoreUncompressedMetaBlock(
|
||||||
BROTLI_BOOL is_final_block, const uint8_t* input, size_t position,
|
BROTLI_BOOL is_final_block, const uint8_t* BROTLI_RESTRICT input,
|
||||||
size_t mask, size_t len, size_t* storage_ix, uint8_t* storage);
|
size_t position, size_t mask, size_t len,
|
||||||
|
size_t* BROTLI_RESTRICT storage_ix, uint8_t* BROTLI_RESTRICT storage);
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
#include "./cluster.h"
|
#include "./cluster.h"
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./bit_cost.h" /* BrotliPopulationCost */
|
#include "./bit_cost.h" /* BrotliPopulationCost */
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
#include "./histogram.h"
|
#include "./histogram.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
#ifndef BROTLI_ENC_CLUSTER_H_
|
#ifndef BROTLI_ENC_CLUSTER_H_
|
||||||
#define BROTLI_ENC_CLUSTER_H_
|
#define BROTLI_ENC_CLUSTER_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./histogram.h"
|
#include "./histogram.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -215,7 +215,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
|
||||||
uint32_t next_index;
|
uint32_t next_index;
|
||||||
HistogramType* tmp;
|
HistogramType* tmp;
|
||||||
size_t i;
|
size_t i;
|
||||||
if (BROTLI_IS_OOM(m)) return 0;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0;
|
||||||
for (i = 0; i < length; ++i) {
|
for (i = 0; i < length; ++i) {
|
||||||
new_index[i] = kInvalidIndex;
|
new_index[i] = kInvalidIndex;
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
|
||||||
/* TODO: by using idea of "cycle-sort" we can avoid allocation of
|
/* TODO: by using idea of "cycle-sort" we can avoid allocation of
|
||||||
tmp and reduce the number of copying by the factor of 2. */
|
tmp and reduce the number of copying by the factor of 2. */
|
||||||
tmp = BROTLI_ALLOC(m, HistogramType, next_index);
|
tmp = BROTLI_ALLOC(m, HistogramType, next_index);
|
||||||
if (BROTLI_IS_OOM(m)) return 0;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0;
|
||||||
next_index = 0;
|
next_index = 0;
|
||||||
for (i = 0; i < length; ++i) {
|
for (i = 0; i < length; ++i) {
|
||||||
if (new_index[symbols[i]] == next_index) {
|
if (new_index[symbols[i]] == next_index) {
|
||||||
|
@ -259,7 +259,10 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
||||||
HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
|
HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) ||
|
||||||
|
BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < in_size; ++i) {
|
for (i = 0; i < in_size; ++i) {
|
||||||
cluster_size[i] = 1;
|
cluster_size[i] = 1;
|
||||||
|
|
|
@ -10,23 +10,24 @@
|
||||||
#define BROTLI_ENC_COMMAND_H_
|
#define BROTLI_ENC_COMMAND_H_
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
#include <brotli/port.h>
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
|
#include "./params.h"
|
||||||
#include "./prefix.h"
|
#include "./prefix.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint32_t kInsBase[] = { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50,
|
BROTLI_INTERNAL extern const uint32_t
|
||||||
66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 };
|
kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES];
|
||||||
static uint32_t kInsExtra[] = { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
|
BROTLI_INTERNAL extern const uint32_t
|
||||||
5, 5, 6, 7, 8, 9, 10, 12, 14, 24 };
|
kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES];
|
||||||
static uint32_t kCopyBase[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30,
|
BROTLI_INTERNAL extern const uint32_t
|
||||||
38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118 };
|
kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES];
|
||||||
static uint32_t kCopyExtra[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
|
BROTLI_INTERNAL extern const uint32_t
|
||||||
4, 4, 5, 5, 6, 7, 8, 9, 10, 24 };
|
kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES];
|
||||||
|
|
||||||
static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
|
static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
|
||||||
if (insertlen < 6) {
|
if (insertlen < 6) {
|
||||||
|
@ -61,21 +62,21 @@ static BROTLI_INLINE uint16_t GetCopyLengthCode(size_t copylen) {
|
||||||
static BROTLI_INLINE uint16_t CombineLengthCodes(
|
static BROTLI_INLINE uint16_t CombineLengthCodes(
|
||||||
uint16_t inscode, uint16_t copycode, BROTLI_BOOL use_last_distance) {
|
uint16_t inscode, uint16_t copycode, BROTLI_BOOL use_last_distance) {
|
||||||
uint16_t bits64 =
|
uint16_t bits64 =
|
||||||
(uint16_t)((copycode & 0x7u) | ((inscode & 0x7u) << 3));
|
(uint16_t)((copycode & 0x7u) | ((inscode & 0x7u) << 3u));
|
||||||
if (use_last_distance && inscode < 8 && copycode < 16) {
|
if (use_last_distance && inscode < 8u && copycode < 16u) {
|
||||||
return (copycode < 8) ? bits64 : (bits64 | 64);
|
return (copycode < 8u) ? bits64 : (bits64 | 64u);
|
||||||
} else {
|
} else {
|
||||||
/* Specification: 5 Encoding of ... (last table) */
|
/* Specification: 5 Encoding of ... (last table) */
|
||||||
/* offset = 2 * index, where index is in range [0..8] */
|
/* offset = 2 * index, where index is in range [0..8] */
|
||||||
int offset = 2 * ((copycode >> 3) + 3 * (inscode >> 3));
|
uint32_t offset = 2u * ((copycode >> 3u) + 3u * (inscode >> 3u));
|
||||||
/* All values in specification are K * 64,
|
/* All values in specification are K * 64,
|
||||||
where K = [2, 3, 6, 4, 5, 8, 7, 9, 10],
|
where K = [2, 3, 6, 4, 5, 8, 7, 9, 10],
|
||||||
i + 1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
|
i + 1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
K - i - 1 = [1, 1, 3, 0, 0, 2, 0, 1, 2] = D.
|
K - i - 1 = [1, 1, 3, 0, 0, 2, 0, 1, 2] = D.
|
||||||
All values in D require only 2 bits to encode.
|
All values in D require only 2 bits to encode.
|
||||||
Magic constant is shifted 6 bits left, to avoid final multiplication. */
|
Magic constant is shifted 6 bits left, to avoid final multiplication. */
|
||||||
offset = (offset << 5) + 0x40 + ((0x520D40 >> offset) & 0xC0);
|
offset = (offset << 5u) + 0x40u + ((0x520D40u >> offset) & 0xC0u);
|
||||||
return (uint16_t)offset | bits64;
|
return (uint16_t)(offset | bits64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,70 +89,78 @@ static BROTLI_INLINE void GetLengthCode(size_t insertlen, size_t copylen,
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) {
|
static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) {
|
||||||
return kInsBase[inscode];
|
return kBrotliInsBase[inscode];
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) {
|
static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) {
|
||||||
return kInsExtra[inscode];
|
return kBrotliInsExtra[inscode];
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) {
|
static BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) {
|
||||||
return kCopyBase[copycode];
|
return kBrotliCopyBase[copycode];
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) {
|
static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) {
|
||||||
return kCopyExtra[copycode];
|
return kBrotliCopyExtra[copycode];
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct Command {
|
typedef struct Command {
|
||||||
uint32_t insert_len_;
|
uint32_t insert_len_;
|
||||||
/* Stores copy_len in low 24 bits and copy_len XOR copy_code in high 8 bit. */
|
/* Stores copy_len in low 25 bits and copy_code - copy_len in high 7 bit. */
|
||||||
uint32_t copy_len_;
|
uint32_t copy_len_;
|
||||||
|
/* Stores distance extra bits. */
|
||||||
uint32_t dist_extra_;
|
uint32_t dist_extra_;
|
||||||
uint16_t cmd_prefix_;
|
uint16_t cmd_prefix_;
|
||||||
|
/* Stores distance code in low 10 bits
|
||||||
|
and number of extra bits in high 6 bits. */
|
||||||
uint16_t dist_prefix_;
|
uint16_t dist_prefix_;
|
||||||
} Command;
|
} Command;
|
||||||
|
|
||||||
/* distance_code is e.g. 0 for same-as-last short code, or 16 for offset 1. */
|
/* distance_code is e.g. 0 for same-as-last short code, or 16 for offset 1. */
|
||||||
static BROTLI_INLINE void InitCommand(Command* self, size_t insertlen,
|
static BROTLI_INLINE void InitCommand(Command* self,
|
||||||
|
const BrotliDistanceParams* dist, size_t insertlen,
|
||||||
size_t copylen, int copylen_code_delta, size_t distance_code) {
|
size_t copylen, int copylen_code_delta, size_t distance_code) {
|
||||||
/* Don't rely on signed int representation, use honest casts. */
|
/* Don't rely on signed int representation, use honest casts. */
|
||||||
uint32_t delta = (uint8_t)((int8_t)copylen_code_delta);
|
uint32_t delta = (uint8_t)((int8_t)copylen_code_delta);
|
||||||
self->insert_len_ = (uint32_t)insertlen;
|
self->insert_len_ = (uint32_t)insertlen;
|
||||||
self->copy_len_ = (uint32_t)(copylen | (delta << 24));
|
self->copy_len_ = (uint32_t)(copylen | (delta << 25));
|
||||||
/* The distance prefix and extra bits are stored in this Command as if
|
/* The distance prefix and extra bits are stored in this Command as if
|
||||||
npostfix and ndirect were 0, they are only recomputed later after the
|
npostfix and ndirect were 0, they are only recomputed later after the
|
||||||
clustering if needed. */
|
clustering if needed. */
|
||||||
PrefixEncodeCopyDistance(
|
PrefixEncodeCopyDistance(
|
||||||
distance_code, 0, 0, &self->dist_prefix_, &self->dist_extra_);
|
distance_code, dist->num_direct_distance_codes,
|
||||||
|
dist->distance_postfix_bits, &self->dist_prefix_, &self->dist_extra_);
|
||||||
GetLengthCode(
|
GetLengthCode(
|
||||||
insertlen, (size_t)((int)copylen + copylen_code_delta),
|
insertlen, (size_t)((int)copylen + copylen_code_delta),
|
||||||
TO_BROTLI_BOOL(self->dist_prefix_ == 0), &self->cmd_prefix_);
|
TO_BROTLI_BOOL((self->dist_prefix_ & 0x3FF) == 0), &self->cmd_prefix_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void InitInsertCommand(Command* self, size_t insertlen) {
|
static BROTLI_INLINE void InitInsertCommand(Command* self, size_t insertlen) {
|
||||||
self->insert_len_ = (uint32_t)insertlen;
|
self->insert_len_ = (uint32_t)insertlen;
|
||||||
self->copy_len_ = 4 << 24;
|
self->copy_len_ = 4 << 25;
|
||||||
self->dist_extra_ = 0;
|
self->dist_extra_ = 0;
|
||||||
self->dist_prefix_ = BROTLI_NUM_DISTANCE_SHORT_CODES;
|
self->dist_prefix_ = BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||||
GetLengthCode(insertlen, 4, BROTLI_FALSE, &self->cmd_prefix_);
|
GetLengthCode(insertlen, 4, BROTLI_FALSE, &self->cmd_prefix_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t CommandRestoreDistanceCode(const Command* self) {
|
static BROTLI_INLINE uint32_t CommandRestoreDistanceCode(
|
||||||
if (self->dist_prefix_ < BROTLI_NUM_DISTANCE_SHORT_CODES) {
|
const Command* self, const BrotliDistanceParams* dist) {
|
||||||
return self->dist_prefix_;
|
if ((self->dist_prefix_ & 0x3FFu) <
|
||||||
|
BROTLI_NUM_DISTANCE_SHORT_CODES + dist->num_direct_distance_codes) {
|
||||||
|
return self->dist_prefix_ & 0x3FFu;
|
||||||
} else {
|
} else {
|
||||||
uint32_t nbits = self->dist_extra_ >> 24;
|
uint32_t dcode = self->dist_prefix_ & 0x3FFu;
|
||||||
uint32_t extra = self->dist_extra_ & 0xffffff;
|
uint32_t nbits = self->dist_prefix_ >> 10;
|
||||||
/* It is assumed that the distance was first encoded with NPOSTFIX = 0 and
|
uint32_t extra = self->dist_extra_;
|
||||||
NDIRECT = 0, so the code itself is of this form:
|
uint32_t postfix_mask = (1U << dist->distance_postfix_bits) - 1U;
|
||||||
BROTLI_NUM_DISTANCE_SHORT_CODES + 2 * (nbits - 1) + prefix_bit
|
uint32_t hcode = (dcode - dist->num_direct_distance_codes -
|
||||||
Therefore, the following expression results in (2 + prefix_bit). */
|
BROTLI_NUM_DISTANCE_SHORT_CODES) >>
|
||||||
uint32_t prefix =
|
dist->distance_postfix_bits;
|
||||||
self->dist_prefix_ + 4u - BROTLI_NUM_DISTANCE_SHORT_CODES - 2u * nbits;
|
uint32_t lcode = (dcode - dist->num_direct_distance_codes -
|
||||||
/* Subtract 4 for offset (Chapter 4.) and
|
BROTLI_NUM_DISTANCE_SHORT_CODES) & postfix_mask;
|
||||||
increase by BROTLI_NUM_DISTANCE_SHORT_CODES - 1 */
|
uint32_t offset = ((2U + (hcode & 1U)) << nbits) - 4U;
|
||||||
return (prefix << nbits) + extra + BROTLI_NUM_DISTANCE_SHORT_CODES - 4u;
|
return ((offset + extra) << dist->distance_postfix_bits) + lcode +
|
||||||
|
dist->num_direct_distance_codes + BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,12 +174,13 @@ static BROTLI_INLINE uint32_t CommandDistanceContext(const Command* self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t CommandCopyLen(const Command* self) {
|
static BROTLI_INLINE uint32_t CommandCopyLen(const Command* self) {
|
||||||
return self->copy_len_ & 0xFFFFFF;
|
return self->copy_len_ & 0x1FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t CommandCopyLenCode(const Command* self) {
|
static BROTLI_INLINE uint32_t CommandCopyLenCode(const Command* self) {
|
||||||
int32_t delta = (int8_t)((uint8_t)(self->copy_len_ >> 24));
|
uint32_t modifier = self->copy_len_ >> 25;
|
||||||
return (uint32_t)((int32_t)(self->copy_len_ & 0xFFFFFF) + delta);
|
int32_t delta = (int8_t)((uint8_t)(modifier | ((modifier & 0x40) << 1)));
|
||||||
|
return (uint32_t)((int32_t)(self->copy_len_ & 0x1FFFFFF) + delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
|
|
@ -17,16 +17,15 @@
|
||||||
#include <string.h> /* memcmp, memcpy, memset */
|
#include <string.h> /* memcmp, memcpy, memset */
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./brotli_bit_stream.h"
|
#include "./brotli_bit_stream.h"
|
||||||
#include "./entropy_encode.h"
|
#include "./entropy_encode.h"
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
#include "./find_match_length.h"
|
#include "./find_match_length.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./write_bits.h"
|
#include "./write_bits.h"
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -39,7 +38,7 @@ extern "C" {
|
||||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||||
for this use.
|
for this use.
|
||||||
* The number has been tuned heuristically against compression benchmarks. */
|
* The number has been tuned heuristically against compression benchmarks. */
|
||||||
static const uint32_t kHashMul32 = 0x1e35a7bd;
|
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t Hash(const uint8_t* p, size_t shift) {
|
static BROTLI_INLINE uint32_t Hash(const uint8_t* p, size_t shift) {
|
||||||
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(p) << 24) * kHashMul32;
|
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(p) << 24) * kHashMul32;
|
||||||
|
@ -48,8 +47,8 @@ static BROTLI_INLINE uint32_t Hash(const uint8_t* p, size_t shift) {
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t HashBytesAtOffset(
|
static BROTLI_INLINE uint32_t HashBytesAtOffset(
|
||||||
uint64_t v, int offset, size_t shift) {
|
uint64_t v, int offset, size_t shift) {
|
||||||
assert(offset >= 0);
|
BROTLI_DCHECK(offset >= 0);
|
||||||
assert(offset <= 3);
|
BROTLI_DCHECK(offset <= 3);
|
||||||
{
|
{
|
||||||
const uint64_t h = ((v >> (8 * offset)) << 24) * kHashMul32;
|
const uint64_t h = ((v >> (8 * offset)) << 24) * kHashMul32;
|
||||||
return (uint32_t)(h >> shift);
|
return (uint32_t)(h >> shift);
|
||||||
|
@ -58,7 +57,7 @@ static BROTLI_INLINE uint32_t HashBytesAtOffset(
|
||||||
|
|
||||||
static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2) {
|
static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2) {
|
||||||
return TO_BROTLI_BOOL(
|
return TO_BROTLI_BOOL(
|
||||||
BROTLI_UNALIGNED_LOAD32(p1) == BROTLI_UNALIGNED_LOAD32(p2) &&
|
BrotliUnalignedRead32(p1) == BrotliUnalignedRead32(p2) &&
|
||||||
p1[4] == p2[4]);
|
p1[4] == p2[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +202,7 @@ static BROTLI_INLINE void EmitInsertLen(size_t insertlen,
|
||||||
} else {
|
} else {
|
||||||
BrotliWriteBits(depth[61], bits[61], storage_ix, storage);
|
BrotliWriteBits(depth[61], bits[61], storage_ix, storage);
|
||||||
BrotliWriteBits(12, insertlen - 2114, storage_ix, storage);
|
BrotliWriteBits(12, insertlen - 2114, storage_ix, storage);
|
||||||
++histo[21];
|
++histo[61];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,11 +215,11 @@ static BROTLI_INLINE void EmitLongInsertLen(size_t insertlen,
|
||||||
if (insertlen < 22594) {
|
if (insertlen < 22594) {
|
||||||
BrotliWriteBits(depth[62], bits[62], storage_ix, storage);
|
BrotliWriteBits(depth[62], bits[62], storage_ix, storage);
|
||||||
BrotliWriteBits(14, insertlen - 6210, storage_ix, storage);
|
BrotliWriteBits(14, insertlen - 6210, storage_ix, storage);
|
||||||
++histo[22];
|
++histo[62];
|
||||||
} else {
|
} else {
|
||||||
BrotliWriteBits(depth[63], bits[63], storage_ix, storage);
|
BrotliWriteBits(depth[63], bits[63], storage_ix, storage);
|
||||||
BrotliWriteBits(24, insertlen - 22594, storage_ix, storage);
|
BrotliWriteBits(24, insertlen - 22594, storage_ix, storage);
|
||||||
++histo[23];
|
++histo[63];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +251,7 @@ static BROTLI_INLINE void EmitCopyLen(size_t copylen,
|
||||||
} else {
|
} else {
|
||||||
BrotliWriteBits(depth[39], bits[39], storage_ix, storage);
|
BrotliWriteBits(depth[39], bits[39], storage_ix, storage);
|
||||||
BrotliWriteBits(24, copylen - 2118, storage_ix, storage);
|
BrotliWriteBits(24, copylen - 2118, storage_ix, storage);
|
||||||
++histo[47];
|
++histo[39];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +293,7 @@ static BROTLI_INLINE void EmitCopyLenLastDistance(size_t copylen,
|
||||||
BrotliWriteBits(depth[39], bits[39], storage_ix, storage);
|
BrotliWriteBits(depth[39], bits[39], storage_ix, storage);
|
||||||
BrotliWriteBits(24, copylen - 2120, storage_ix, storage);
|
BrotliWriteBits(24, copylen - 2120, storage_ix, storage);
|
||||||
BrotliWriteBits(depth[64], bits[64], storage_ix, storage);
|
BrotliWriteBits(depth[64], bits[64], storage_ix, storage);
|
||||||
++histo[47];
|
++histo[39];
|
||||||
++histo[64];
|
++histo[64];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,7 +343,7 @@ static void BrotliStoreMetaBlockHeader(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateBits(size_t n_bits, uint32_t bits, size_t pos,
|
static void UpdateBits(size_t n_bits, uint32_t bits, size_t pos,
|
||||||
uint8_t *array) {
|
uint8_t* array) {
|
||||||
while (n_bits > 0) {
|
while (n_bits > 0) {
|
||||||
size_t byte_pos = pos >> 3;
|
size_t byte_pos = pos >> 3;
|
||||||
size_t n_unchanged_bits = pos & 7;
|
size_t n_unchanged_bits = pos & 7;
|
||||||
|
@ -522,12 +521,12 @@ static BROTLI_INLINE void BrotliCompressFragmentFastImpl(
|
||||||
|
|
||||||
const uint8_t* next_ip = ip;
|
const uint8_t* next_ip = ip;
|
||||||
const uint8_t* candidate;
|
const uint8_t* candidate;
|
||||||
assert(next_emit < ip);
|
BROTLI_DCHECK(next_emit < ip);
|
||||||
trawl:
|
trawl:
|
||||||
do {
|
do {
|
||||||
uint32_t hash = next_hash;
|
uint32_t hash = next_hash;
|
||||||
uint32_t bytes_between_hash_lookups = skip++ >> 5;
|
uint32_t bytes_between_hash_lookups = skip++ >> 5;
|
||||||
assert(hash == Hash(next_ip, shift));
|
BROTLI_DCHECK(hash == Hash(next_ip, shift));
|
||||||
ip = next_ip;
|
ip = next_ip;
|
||||||
next_ip = ip + bytes_between_hash_lookups;
|
next_ip = ip + bytes_between_hash_lookups;
|
||||||
if (BROTLI_PREDICT_FALSE(next_ip > ip_limit)) {
|
if (BROTLI_PREDICT_FALSE(next_ip > ip_limit)) {
|
||||||
|
@ -542,8 +541,8 @@ trawl:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
candidate = base_ip + table[hash];
|
candidate = base_ip + table[hash];
|
||||||
assert(candidate >= base_ip);
|
BROTLI_DCHECK(candidate >= base_ip);
|
||||||
assert(candidate < ip);
|
BROTLI_DCHECK(candidate < ip);
|
||||||
|
|
||||||
table[hash] = (int)(ip - base_ip);
|
table[hash] = (int)(ip - base_ip);
|
||||||
} while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate)));
|
} while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate)));
|
||||||
|
@ -566,7 +565,7 @@ trawl:
|
||||||
int distance = (int)(base - candidate); /* > 0 */
|
int distance = (int)(base - candidate); /* > 0 */
|
||||||
size_t insert = (size_t)(base - next_emit);
|
size_t insert = (size_t)(base - next_emit);
|
||||||
ip += matched;
|
ip += matched;
|
||||||
assert(0 == memcmp(base, candidate, matched));
|
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||||
if (BROTLI_PREDICT_TRUE(insert < 6210)) {
|
if (BROTLI_PREDICT_TRUE(insert < 6210)) {
|
||||||
EmitInsertLen(insert, cmd_depth, cmd_bits, cmd_histo,
|
EmitInsertLen(insert, cmd_depth, cmd_bits, cmd_histo,
|
||||||
storage_ix, storage);
|
storage_ix, storage);
|
||||||
|
@ -626,7 +625,7 @@ trawl:
|
||||||
if (ip - candidate > MAX_DISTANCE) break;
|
if (ip - candidate > MAX_DISTANCE) break;
|
||||||
ip += matched;
|
ip += matched;
|
||||||
last_distance = (int)(base - candidate); /* > 0 */
|
last_distance = (int)(base - candidate); /* > 0 */
|
||||||
assert(0 == memcmp(base, candidate, matched));
|
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||||
EmitCopyLen(matched, cmd_depth, cmd_bits, cmd_histo,
|
EmitCopyLen(matched, cmd_depth, cmd_bits, cmd_histo,
|
||||||
storage_ix, storage);
|
storage_ix, storage);
|
||||||
EmitDistance((size_t)last_distance, cmd_depth, cmd_bits,
|
EmitDistance((size_t)last_distance, cmd_depth, cmd_bits,
|
||||||
|
@ -659,7 +658,7 @@ trawl:
|
||||||
}
|
}
|
||||||
|
|
||||||
emit_remainder:
|
emit_remainder:
|
||||||
assert(next_emit <= ip_end);
|
BROTLI_DCHECK(next_emit <= ip_end);
|
||||||
input += block_size;
|
input += block_size;
|
||||||
input_size -= block_size;
|
input_size -= block_size;
|
||||||
block_size = BROTLI_MIN(size_t, input_size, kMergeBlockSize);
|
block_size = BROTLI_MIN(size_t, input_size, kMergeBlockSize);
|
||||||
|
@ -669,7 +668,7 @@ trawl:
|
||||||
if (input_size > 0 &&
|
if (input_size > 0 &&
|
||||||
total_block_size + block_size <= (1 << 20) &&
|
total_block_size + block_size <= (1 << 20) &&
|
||||||
ShouldMergeBlock(input, block_size, lit_depth)) {
|
ShouldMergeBlock(input, block_size, lit_depth)) {
|
||||||
assert(total_block_size > (1 << 16));
|
BROTLI_DCHECK(total_block_size > (1 << 16));
|
||||||
/* Update the size of the current meta-block and continue emitting commands.
|
/* Update the size of the current meta-block and continue emitting commands.
|
||||||
We can do this because the current size and the new size both have 5
|
We can do this because the current size and the new size both have 5
|
||||||
nibbles. */
|
nibbles. */
|
||||||
|
@ -752,7 +751,7 @@ void BrotliCompressFragmentFast(
|
||||||
const size_t table_bits = Log2FloorNonZero(table_size);
|
const size_t table_bits = Log2FloorNonZero(table_size);
|
||||||
|
|
||||||
if (input_size == 0) {
|
if (input_size == 0) {
|
||||||
assert(is_last);
|
BROTLI_DCHECK(is_last);
|
||||||
BrotliWriteBits(1, 1, storage_ix, storage); /* islast */
|
BrotliWriteBits(1, 1, storage_ix, storage); /* islast */
|
||||||
BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */
|
BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */
|
||||||
*storage_ix = (*storage_ix + 7u) & ~7u;
|
*storage_ix = (*storage_ix + 7u) & ~7u;
|
||||||
|
@ -768,7 +767,7 @@ void BrotliCompressFragmentFast(
|
||||||
break;
|
break;
|
||||||
FOR_TABLE_BITS_(CASE_)
|
FOR_TABLE_BITS_(CASE_)
|
||||||
#undef CASE_
|
#undef CASE_
|
||||||
default: assert(0); break;
|
default: BROTLI_DCHECK(0); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If output is larger than single uncompressed block, rewrite it. */
|
/* If output is larger than single uncompressed block, rewrite it. */
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_H_
|
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_H_
|
||||||
#define BROTLI_ENC_COMPRESS_FRAGMENT_H_
|
#define BROTLI_ENC_COMPRESS_FRAGMENT_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <string.h> /* memcmp, memcpy, memset */
|
#include <string.h> /* memcmp, memcpy, memset */
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./bit_cost.h"
|
#include "./bit_cost.h"
|
||||||
#include "./brotli_bit_stream.h"
|
#include "./brotli_bit_stream.h"
|
||||||
|
@ -22,10 +23,8 @@
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
#include "./find_match_length.h"
|
#include "./find_match_length.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./write_bits.h"
|
#include "./write_bits.h"
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -38,28 +37,31 @@ extern "C" {
|
||||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||||
for this use.
|
for this use.
|
||||||
* The number has been tuned heuristically against compression benchmarks. */
|
* The number has been tuned heuristically against compression benchmarks. */
|
||||||
static const uint32_t kHashMul32 = 0x1e35a7bd;
|
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t Hash(const uint8_t* p, size_t shift) {
|
static BROTLI_INLINE uint32_t Hash(const uint8_t* p,
|
||||||
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(p) << 16) * kHashMul32;
|
size_t shift, size_t length) {
|
||||||
|
const uint64_t h =
|
||||||
|
(BROTLI_UNALIGNED_LOAD64LE(p) << ((8 - length) * 8)) * kHashMul32;
|
||||||
return (uint32_t)(h >> shift);
|
return (uint32_t)(h >> shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t HashBytesAtOffset(
|
static BROTLI_INLINE uint32_t HashBytesAtOffset(uint64_t v, size_t offset,
|
||||||
uint64_t v, int offset, size_t shift) {
|
size_t shift, size_t length) {
|
||||||
assert(offset >= 0);
|
BROTLI_DCHECK(offset <= 8 - length);
|
||||||
assert(offset <= 2);
|
|
||||||
{
|
{
|
||||||
const uint64_t h = ((v >> (8 * offset)) << 16) * kHashMul32;
|
const uint64_t h = ((v >> (8 * offset)) << ((8 - length) * 8)) * kHashMul32;
|
||||||
return (uint32_t)(h >> shift);
|
return (uint32_t)(h >> shift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2) {
|
static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2,
|
||||||
return TO_BROTLI_BOOL(
|
size_t length) {
|
||||||
BROTLI_UNALIGNED_LOAD32(p1) == BROTLI_UNALIGNED_LOAD32(p2) &&
|
if (BrotliUnalignedRead32(p1) == BrotliUnalignedRead32(p2)) {
|
||||||
p1[4] == p2[4] &&
|
if (length == 4) return BROTLI_TRUE;
|
||||||
p1[5] == p2[5]);
|
return TO_BROTLI_BOOL(p1[4] == p2[4] && p1[5] == p2[5]);
|
||||||
|
}
|
||||||
|
return BROTLI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
|
/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
|
||||||
|
@ -236,7 +238,8 @@ static void BrotliStoreMetaBlockHeader(
|
||||||
|
|
||||||
static BROTLI_INLINE void CreateCommands(const uint8_t* input,
|
static BROTLI_INLINE void CreateCommands(const uint8_t* input,
|
||||||
size_t block_size, size_t input_size, const uint8_t* base_ip, int* table,
|
size_t block_size, size_t input_size, const uint8_t* base_ip, int* table,
|
||||||
size_t table_bits, uint8_t** literals, uint32_t** commands) {
|
size_t table_bits, size_t min_match,
|
||||||
|
uint8_t** literals, uint32_t** commands) {
|
||||||
/* "ip" is the input pointer. */
|
/* "ip" is the input pointer. */
|
||||||
const uint8_t* ip = input;
|
const uint8_t* ip = input;
|
||||||
const size_t shift = 64u - table_bits;
|
const size_t shift = 64u - table_bits;
|
||||||
|
@ -248,19 +251,18 @@ static BROTLI_INLINE void CreateCommands(const uint8_t* input,
|
||||||
|
|
||||||
int last_distance = -1;
|
int last_distance = -1;
|
||||||
const size_t kInputMarginBytes = BROTLI_WINDOW_GAP;
|
const size_t kInputMarginBytes = BROTLI_WINDOW_GAP;
|
||||||
const size_t kMinMatchLen = 6;
|
|
||||||
|
|
||||||
if (BROTLI_PREDICT_TRUE(block_size >= kInputMarginBytes)) {
|
if (BROTLI_PREDICT_TRUE(block_size >= kInputMarginBytes)) {
|
||||||
/* For the last block, we need to keep a 16 bytes margin so that we can be
|
/* For the last block, we need to keep a 16 bytes margin so that we can be
|
||||||
sure that all distances are at most window size - 16.
|
sure that all distances are at most window size - 16.
|
||||||
For all other blocks, we only need to keep a margin of 5 bytes so that
|
For all other blocks, we only need to keep a margin of 5 bytes so that
|
||||||
we don't go over the block size with a copy. */
|
we don't go over the block size with a copy. */
|
||||||
const size_t len_limit = BROTLI_MIN(size_t, block_size - kMinMatchLen,
|
const size_t len_limit = BROTLI_MIN(size_t, block_size - min_match,
|
||||||
input_size - kInputMarginBytes);
|
input_size - kInputMarginBytes);
|
||||||
const uint8_t* ip_limit = input + len_limit;
|
const uint8_t* ip_limit = input + len_limit;
|
||||||
|
|
||||||
uint32_t next_hash;
|
uint32_t next_hash;
|
||||||
for (next_hash = Hash(++ip, shift); ; ) {
|
for (next_hash = Hash(++ip, shift, min_match); ; ) {
|
||||||
/* Step 1: Scan forward in the input looking for a 6-byte-long match.
|
/* Step 1: Scan forward in the input looking for a 6-byte-long match.
|
||||||
If we get close to exhausting the input then goto emit_remainder.
|
If we get close to exhausting the input then goto emit_remainder.
|
||||||
|
|
||||||
|
@ -281,31 +283,31 @@ static BROTLI_INLINE void CreateCommands(const uint8_t* input,
|
||||||
const uint8_t* next_ip = ip;
|
const uint8_t* next_ip = ip;
|
||||||
const uint8_t* candidate;
|
const uint8_t* candidate;
|
||||||
|
|
||||||
assert(next_emit < ip);
|
BROTLI_DCHECK(next_emit < ip);
|
||||||
trawl:
|
trawl:
|
||||||
do {
|
do {
|
||||||
uint32_t hash = next_hash;
|
uint32_t hash = next_hash;
|
||||||
uint32_t bytes_between_hash_lookups = skip++ >> 5;
|
uint32_t bytes_between_hash_lookups = skip++ >> 5;
|
||||||
ip = next_ip;
|
ip = next_ip;
|
||||||
assert(hash == Hash(ip, shift));
|
BROTLI_DCHECK(hash == Hash(ip, shift, min_match));
|
||||||
next_ip = ip + bytes_between_hash_lookups;
|
next_ip = ip + bytes_between_hash_lookups;
|
||||||
if (BROTLI_PREDICT_FALSE(next_ip > ip_limit)) {
|
if (BROTLI_PREDICT_FALSE(next_ip > ip_limit)) {
|
||||||
goto emit_remainder;
|
goto emit_remainder;
|
||||||
}
|
}
|
||||||
next_hash = Hash(next_ip, shift);
|
next_hash = Hash(next_ip, shift, min_match);
|
||||||
candidate = ip - last_distance;
|
candidate = ip - last_distance;
|
||||||
if (IsMatch(ip, candidate)) {
|
if (IsMatch(ip, candidate, min_match)) {
|
||||||
if (BROTLI_PREDICT_TRUE(candidate < ip)) {
|
if (BROTLI_PREDICT_TRUE(candidate < ip)) {
|
||||||
table[hash] = (int)(ip - base_ip);
|
table[hash] = (int)(ip - base_ip);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
candidate = base_ip + table[hash];
|
candidate = base_ip + table[hash];
|
||||||
assert(candidate >= base_ip);
|
BROTLI_DCHECK(candidate >= base_ip);
|
||||||
assert(candidate < ip);
|
BROTLI_DCHECK(candidate < ip);
|
||||||
|
|
||||||
table[hash] = (int)(ip - base_ip);
|
table[hash] = (int)(ip - base_ip);
|
||||||
} while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate)));
|
} while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate, min_match)));
|
||||||
|
|
||||||
/* Check copy distance. If candidate is not feasible, continue search.
|
/* Check copy distance. If candidate is not feasible, continue search.
|
||||||
Checking is done outside of hot loop to reduce overhead. */
|
Checking is done outside of hot loop to reduce overhead. */
|
||||||
|
@ -320,12 +322,13 @@ trawl:
|
||||||
/* We have a 6-byte match at ip, and we need to emit bytes in
|
/* We have a 6-byte match at ip, and we need to emit bytes in
|
||||||
[next_emit, ip). */
|
[next_emit, ip). */
|
||||||
const uint8_t* base = ip;
|
const uint8_t* base = ip;
|
||||||
size_t matched = 6 + FindMatchLengthWithLimit(
|
size_t matched = min_match + FindMatchLengthWithLimit(
|
||||||
candidate + 6, ip + 6, (size_t)(ip_end - ip) - 6);
|
candidate + min_match, ip + min_match,
|
||||||
|
(size_t)(ip_end - ip) - min_match);
|
||||||
int distance = (int)(base - candidate); /* > 0 */
|
int distance = (int)(base - candidate); /* > 0 */
|
||||||
int insert = (int)(base - next_emit);
|
int insert = (int)(base - next_emit);
|
||||||
ip += matched;
|
ip += matched;
|
||||||
assert(0 == memcmp(base, candidate, matched));
|
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||||
EmitInsertLen((uint32_t)insert, commands);
|
EmitInsertLen((uint32_t)insert, commands);
|
||||||
memcpy(*literals, next_emit, (size_t)insert);
|
memcpy(*literals, next_emit, (size_t)insert);
|
||||||
*literals += insert;
|
*literals += insert;
|
||||||
|
@ -346,35 +349,50 @@ trawl:
|
||||||
/* We could immediately start working at ip now, but to improve
|
/* We could immediately start working at ip now, but to improve
|
||||||
compression we first update "table" with the hashes of some
|
compression we first update "table" with the hashes of some
|
||||||
positions within the last copy. */
|
positions within the last copy. */
|
||||||
uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 5);
|
uint64_t input_bytes;
|
||||||
uint32_t prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
|
|
||||||
uint32_t cur_hash;
|
uint32_t cur_hash;
|
||||||
table[prev_hash] = (int)(ip - base_ip - 5);
|
uint32_t prev_hash;
|
||||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift);
|
if (min_match == 4) {
|
||||||
table[prev_hash] = (int)(ip - base_ip - 4);
|
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3);
|
||||||
prev_hash = HashBytesAtOffset(input_bytes, 2, shift);
|
cur_hash = HashBytesAtOffset(input_bytes, 3, shift, min_match);
|
||||||
table[prev_hash] = (int)(ip - base_ip - 3);
|
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||||
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 2);
|
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||||
cur_hash = HashBytesAtOffset(input_bytes, 2, shift);
|
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
|
table[prev_hash] = (int)(ip - base_ip - 2);
|
||||||
table[prev_hash] = (int)(ip - base_ip - 2);
|
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift);
|
table[prev_hash] = (int)(ip - base_ip - 1);
|
||||||
table[prev_hash] = (int)(ip - base_ip - 1);
|
} else {
|
||||||
|
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 5);
|
||||||
|
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||||
|
table[prev_hash] = (int)(ip - base_ip - 5);
|
||||||
|
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||||
|
table[prev_hash] = (int)(ip - base_ip - 4);
|
||||||
|
prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
|
||||||
|
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||||
|
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 2);
|
||||||
|
cur_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
|
||||||
|
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||||
|
table[prev_hash] = (int)(ip - base_ip - 2);
|
||||||
|
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||||
|
table[prev_hash] = (int)(ip - base_ip - 1);
|
||||||
|
}
|
||||||
|
|
||||||
candidate = base_ip + table[cur_hash];
|
candidate = base_ip + table[cur_hash];
|
||||||
table[cur_hash] = (int)(ip - base_ip);
|
table[cur_hash] = (int)(ip - base_ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ip - candidate <= MAX_DISTANCE && IsMatch(ip, candidate)) {
|
while (ip - candidate <= MAX_DISTANCE &&
|
||||||
|
IsMatch(ip, candidate, min_match)) {
|
||||||
/* We have a 6-byte match at ip, and no need to emit any
|
/* We have a 6-byte match at ip, and no need to emit any
|
||||||
literal bytes prior to ip. */
|
literal bytes prior to ip. */
|
||||||
const uint8_t* base = ip;
|
const uint8_t* base = ip;
|
||||||
size_t matched = 6 + FindMatchLengthWithLimit(
|
size_t matched = min_match + FindMatchLengthWithLimit(
|
||||||
candidate + 6, ip + 6, (size_t)(ip_end - ip) - 6);
|
candidate + min_match, ip + min_match,
|
||||||
|
(size_t)(ip_end - ip) - min_match);
|
||||||
ip += matched;
|
ip += matched;
|
||||||
last_distance = (int)(base - candidate); /* > 0 */
|
last_distance = (int)(base - candidate); /* > 0 */
|
||||||
assert(0 == memcmp(base, candidate, matched));
|
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||||
EmitCopyLen(matched, commands);
|
EmitCopyLen(matched, commands);
|
||||||
EmitDistance((uint32_t)last_distance, commands);
|
EmitDistance((uint32_t)last_distance, commands);
|
||||||
|
|
||||||
|
@ -386,32 +404,45 @@ trawl:
|
||||||
/* We could immediately start working at ip now, but to improve
|
/* We could immediately start working at ip now, but to improve
|
||||||
compression we first update "table" with the hashes of some
|
compression we first update "table" with the hashes of some
|
||||||
positions within the last copy. */
|
positions within the last copy. */
|
||||||
uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 5);
|
uint64_t input_bytes;
|
||||||
uint32_t prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
|
|
||||||
uint32_t cur_hash;
|
uint32_t cur_hash;
|
||||||
table[prev_hash] = (int)(ip - base_ip - 5);
|
uint32_t prev_hash;
|
||||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift);
|
if (min_match == 4) {
|
||||||
table[prev_hash] = (int)(ip - base_ip - 4);
|
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3);
|
||||||
prev_hash = HashBytesAtOffset(input_bytes, 2, shift);
|
cur_hash = HashBytesAtOffset(input_bytes, 3, shift, min_match);
|
||||||
table[prev_hash] = (int)(ip - base_ip - 3);
|
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||||
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 2);
|
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||||
cur_hash = HashBytesAtOffset(input_bytes, 2, shift);
|
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||||
prev_hash = HashBytesAtOffset(input_bytes, 0, shift);
|
table[prev_hash] = (int)(ip - base_ip - 2);
|
||||||
table[prev_hash] = (int)(ip - base_ip - 2);
|
prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
|
||||||
prev_hash = HashBytesAtOffset(input_bytes, 1, shift);
|
table[prev_hash] = (int)(ip - base_ip - 1);
|
||||||
table[prev_hash] = (int)(ip - base_ip - 1);
|
} else {
|
||||||
|
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 5);
|
||||||
|
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||||
|
table[prev_hash] = (int)(ip - base_ip - 5);
|
||||||
|
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||||
|
table[prev_hash] = (int)(ip - base_ip - 4);
|
||||||
|
prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
|
||||||
|
table[prev_hash] = (int)(ip - base_ip - 3);
|
||||||
|
input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 2);
|
||||||
|
cur_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match);
|
||||||
|
prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match);
|
||||||
|
table[prev_hash] = (int)(ip - base_ip - 2);
|
||||||
|
prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match);
|
||||||
|
table[prev_hash] = (int)(ip - base_ip - 1);
|
||||||
|
}
|
||||||
|
|
||||||
candidate = base_ip + table[cur_hash];
|
candidate = base_ip + table[cur_hash];
|
||||||
table[cur_hash] = (int)(ip - base_ip);
|
table[cur_hash] = (int)(ip - base_ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next_hash = Hash(++ip, shift);
|
next_hash = Hash(++ip, shift, min_match);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit_remainder:
|
emit_remainder:
|
||||||
assert(next_emit <= ip_end);
|
BROTLI_DCHECK(next_emit <= ip_end);
|
||||||
/* Emit the remaining bytes as literals. */
|
/* Emit the remaining bytes as literals. */
|
||||||
if (next_emit < ip_end) {
|
if (next_emit < ip_end) {
|
||||||
const uint32_t insert = (uint32_t)(ip_end - next_emit);
|
const uint32_t insert = (uint32_t)(ip_end - next_emit);
|
||||||
|
@ -457,7 +488,7 @@ static void StoreCommands(MemoryManager* m,
|
||||||
|
|
||||||
for (i = 0; i < num_commands; ++i) {
|
for (i = 0; i < num_commands; ++i) {
|
||||||
const uint32_t code = commands[i] & 0xFF;
|
const uint32_t code = commands[i] & 0xFF;
|
||||||
assert(code < 128);
|
BROTLI_DCHECK(code < 128);
|
||||||
++cmd_histo[code];
|
++cmd_histo[code];
|
||||||
}
|
}
|
||||||
cmd_histo[1] += 1;
|
cmd_histo[1] += 1;
|
||||||
|
@ -471,7 +502,7 @@ static void StoreCommands(MemoryManager* m,
|
||||||
const uint32_t cmd = commands[i];
|
const uint32_t cmd = commands[i];
|
||||||
const uint32_t code = cmd & 0xFF;
|
const uint32_t code = cmd & 0xFF;
|
||||||
const uint32_t extra = cmd >> 8;
|
const uint32_t extra = cmd >> 8;
|
||||||
assert(code < 128);
|
BROTLI_DCHECK(code < 128);
|
||||||
BrotliWriteBits(cmd_depths[code], cmd_bits[code], storage_ix, storage);
|
BrotliWriteBits(cmd_depths[code], cmd_bits[code], storage_ix, storage);
|
||||||
BrotliWriteBits(kNumExtraBits[code], extra, storage_ix, storage);
|
BrotliWriteBits(kNumExtraBits[code], extra, storage_ix, storage);
|
||||||
if (code < 24) {
|
if (code < 24) {
|
||||||
|
@ -493,7 +524,7 @@ static void StoreCommands(MemoryManager* m,
|
||||||
static BROTLI_BOOL ShouldCompress(
|
static BROTLI_BOOL ShouldCompress(
|
||||||
const uint8_t* input, size_t input_size, size_t num_literals) {
|
const uint8_t* input, size_t input_size, size_t num_literals) {
|
||||||
double corpus_size = (double)input_size;
|
double corpus_size = (double)input_size;
|
||||||
if (num_literals < MIN_RATIO * corpus_size) {
|
if ((double)num_literals < MIN_RATIO * corpus_size) {
|
||||||
return BROTLI_TRUE;
|
return BROTLI_TRUE;
|
||||||
} else {
|
} else {
|
||||||
uint32_t literal_histo[256] = { 0 };
|
uint32_t literal_histo[256] = { 0 };
|
||||||
|
@ -526,7 +557,8 @@ static void EmitUncompressedMetaBlock(const uint8_t* input, size_t input_size,
|
||||||
static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
|
static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
|
||||||
MemoryManager* m, const uint8_t* input, size_t input_size,
|
MemoryManager* m, const uint8_t* input, size_t input_size,
|
||||||
BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf,
|
BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf,
|
||||||
int* table, size_t table_bits, size_t* storage_ix, uint8_t* storage) {
|
int* table, size_t table_bits, size_t min_match,
|
||||||
|
size_t* storage_ix, uint8_t* storage) {
|
||||||
/* Save the start of the first block for position and distance computations.
|
/* Save the start of the first block for position and distance computations.
|
||||||
*/
|
*/
|
||||||
const uint8_t* base_ip = input;
|
const uint8_t* base_ip = input;
|
||||||
|
@ -538,8 +570,8 @@ static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
|
||||||
uint32_t* commands = command_buf;
|
uint32_t* commands = command_buf;
|
||||||
uint8_t* literals = literal_buf;
|
uint8_t* literals = literal_buf;
|
||||||
size_t num_literals;
|
size_t num_literals;
|
||||||
CreateCommands(input, block_size, input_size, base_ip, table, table_bits,
|
CreateCommands(input, block_size, input_size, base_ip, table,
|
||||||
&literals, &commands);
|
table_bits, min_match, &literals, &commands);
|
||||||
num_literals = (size_t)(literals - literal_buf);
|
num_literals = (size_t)(literals - literal_buf);
|
||||||
if (ShouldCompress(input, block_size, num_literals)) {
|
if (ShouldCompress(input, block_size, num_literals)) {
|
||||||
const size_t num_commands = (size_t)(commands - command_buf);
|
const size_t num_commands = (size_t)(commands - command_buf);
|
||||||
|
@ -568,8 +600,9 @@ static BROTLI_NOINLINE void BrotliCompressFragmentTwoPassImpl ## B( \
|
||||||
MemoryManager* m, const uint8_t* input, size_t input_size, \
|
MemoryManager* m, const uint8_t* input, size_t input_size, \
|
||||||
BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf, \
|
BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf, \
|
||||||
int* table, size_t* storage_ix, uint8_t* storage) { \
|
int* table, size_t* storage_ix, uint8_t* storage) { \
|
||||||
|
size_t min_match = (B <= 15) ? 4 : 6; \
|
||||||
BrotliCompressFragmentTwoPassImpl(m, input, input_size, is_last, command_buf,\
|
BrotliCompressFragmentTwoPassImpl(m, input, input_size, is_last, command_buf,\
|
||||||
literal_buf, table, B, storage_ix, storage); \
|
literal_buf, table, B, min_match, storage_ix, storage); \
|
||||||
}
|
}
|
||||||
FOR_TABLE_BITS_(BAKE_METHOD_PARAM_)
|
FOR_TABLE_BITS_(BAKE_METHOD_PARAM_)
|
||||||
#undef BAKE_METHOD_PARAM_
|
#undef BAKE_METHOD_PARAM_
|
||||||
|
@ -589,7 +622,7 @@ void BrotliCompressFragmentTwoPass(
|
||||||
break;
|
break;
|
||||||
FOR_TABLE_BITS_(CASE_)
|
FOR_TABLE_BITS_(CASE_)
|
||||||
#undef CASE_
|
#undef CASE_
|
||||||
default: assert(0); break;
|
default: BROTLI_DCHECK(0); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If output is larger than single uncompressed block, rewrite it. */
|
/* If output is larger than single uncompressed block, rewrite it. */
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
|
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
|
||||||
#define BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
|
#define BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -1,184 +0,0 @@
|
||||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
Distributed under MIT license.
|
|
||||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Functions to map previous bytes into a context id. */
|
|
||||||
|
|
||||||
#ifndef BROTLI_ENC_CONTEXT_H_
|
|
||||||
#define BROTLI_ENC_CONTEXT_H_
|
|
||||||
|
|
||||||
#include <brotli/port.h>
|
|
||||||
#include <brotli/types.h>
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Second-order context lookup table for UTF8 byte streams.
|
|
||||||
|
|
||||||
If p1 and p2 are the previous two bytes, we calculate the context as
|
|
||||||
|
|
||||||
context = kUTF8ContextLookup[p1] | kUTF8ContextLookup[p2 + 256].
|
|
||||||
|
|
||||||
If the previous two bytes are ASCII characters (i.e. < 128), this will be
|
|
||||||
equivalent to
|
|
||||||
|
|
||||||
context = 4 * context1(p1) + context2(p2),
|
|
||||||
|
|
||||||
where context1 is based on the previous byte in the following way:
|
|
||||||
|
|
||||||
0 : non-ASCII control
|
|
||||||
1 : \t, \n, \r
|
|
||||||
2 : space
|
|
||||||
3 : other punctuation
|
|
||||||
4 : " '
|
|
||||||
5 : %
|
|
||||||
6 : ( < [ {
|
|
||||||
7 : ) > ] }
|
|
||||||
8 : , ; :
|
|
||||||
9 : .
|
|
||||||
10 : =
|
|
||||||
11 : number
|
|
||||||
12 : upper-case vowel
|
|
||||||
13 : upper-case consonant
|
|
||||||
14 : lower-case vowel
|
|
||||||
15 : lower-case consonant
|
|
||||||
|
|
||||||
and context2 is based on the second last byte:
|
|
||||||
|
|
||||||
0 : control, space
|
|
||||||
1 : punctuation
|
|
||||||
2 : upper-case letter, number
|
|
||||||
3 : lower-case letter
|
|
||||||
|
|
||||||
If the last byte is ASCII, and the second last byte is not (in a valid UTF8
|
|
||||||
stream it will be a continuation byte, value between 128 and 191), the
|
|
||||||
context is the same as if the second last byte was an ASCII control or space.
|
|
||||||
|
|
||||||
If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
|
|
||||||
be a continuation byte and the context id is 2 or 3 depending on the LSB of
|
|
||||||
the last byte and to a lesser extent on the second last byte if it is ASCII.
|
|
||||||
|
|
||||||
If the last byte is a UTF8 continuation byte, the second last byte can be:
|
|
||||||
- continuation byte: the next byte is probably ASCII or lead byte (assuming
|
|
||||||
4-byte UTF8 characters are rare) and the context id is 0 or 1.
|
|
||||||
- lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
|
|
||||||
- lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
|
|
||||||
|
|
||||||
The possible value combinations of the previous two bytes, the range of
|
|
||||||
context ids and the type of the next byte is summarized in the table below:
|
|
||||||
|
|
||||||
|--------\-----------------------------------------------------------------|
|
|
||||||
| \ Last byte |
|
|
||||||
| Second \---------------------------------------------------------------|
|
|
||||||
| last byte \ ASCII | cont. byte | lead byte |
|
|
||||||
| \ (0-127) | (128-191) | (192-) |
|
|
||||||
|=============|===================|=====================|==================|
|
|
||||||
| ASCII | next: ASCII/lead | not valid | next: cont. |
|
|
||||||
| (0-127) | context: 4 - 63 | | context: 2 - 3 |
|
|
||||||
|-------------|-------------------|---------------------|------------------|
|
|
||||||
| cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
|
|
||||||
| (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
|
|
||||||
|-------------|-------------------|---------------------|------------------|
|
|
||||||
| lead byte | not valid | next: ASCII/lead | not valid |
|
|
||||||
| (192-207) | | context: 0 - 1 | |
|
|
||||||
|-------------|-------------------|---------------------|------------------|
|
|
||||||
| lead byte | not valid | next: cont. | not valid |
|
|
||||||
| (208-) | | context: 2 - 3 | |
|
|
||||||
|-------------|-------------------|---------------------|------------------|
|
|
||||||
*/
|
|
||||||
static const uint8_t kUTF8ContextLookup[512] = {
|
|
||||||
/* Last byte. */
|
|
||||||
/* */
|
|
||||||
/* ASCII range. */
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
|
|
||||||
44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
|
|
||||||
12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
|
|
||||||
52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
|
|
||||||
12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
|
|
||||||
60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0,
|
|
||||||
/* UTF8 continuation byte range. */
|
|
||||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
|
||||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
|
||||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
|
||||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
|
||||||
/* UTF8 lead byte range. */
|
|
||||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
|
||||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
|
||||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
|
||||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
|
|
||||||
/* Second last byte. */
|
|
||||||
/* */
|
|
||||||
/* ASCII range. */
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
|
|
||||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
|
|
||||||
/* UTF8 continuation byte range. */
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
/* UTF8 lead byte range. */
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Context lookup table for small signed integers. */
|
|
||||||
static const uint8_t kSigned3BitContextLookup[] = {
|
|
||||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
||||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum ContextType {
|
|
||||||
CONTEXT_LSB6 = 0,
|
|
||||||
CONTEXT_MSB6 = 1,
|
|
||||||
CONTEXT_UTF8 = 2,
|
|
||||||
CONTEXT_SIGNED = 3
|
|
||||||
} ContextType;
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint8_t Context(uint8_t p1, uint8_t p2, ContextType mode) {
|
|
||||||
switch (mode) {
|
|
||||||
case CONTEXT_LSB6:
|
|
||||||
return p1 & 0x3f;
|
|
||||||
case CONTEXT_MSB6:
|
|
||||||
return (uint8_t)(p1 >> 2);
|
|
||||||
case CONTEXT_UTF8:
|
|
||||||
return kUTF8ContextLookup[p1] | kUTF8ContextLookup[p2 + 256];
|
|
||||||
case CONTEXT_SIGNED:
|
|
||||||
return (uint8_t)((kSigned3BitContextLookup[p1] << 3) +
|
|
||||||
kSigned3BitContextLookup[p2]);
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* BROTLI_ENC_CONTEXT_H_ */
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,7 +15,8 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern const uint16_t kStaticDictionaryHash[32768];
|
extern const uint16_t kStaticDictionaryHashWords[32768];
|
||||||
|
extern const uint8_t kStaticDictionaryHashLengths[32768];
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,19 +11,21 @@
|
||||||
#include <string.h> /* memset */
|
#include <string.h> /* memset */
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const size_t kBrotliShellGaps[] = {132, 57, 23, 10, 4, 1};
|
||||||
|
|
||||||
BROTLI_BOOL BrotliSetDepth(
|
BROTLI_BOOL BrotliSetDepth(
|
||||||
int p0, HuffmanTree* pool, uint8_t* depth, int max_depth) {
|
int p0, HuffmanTree* pool, uint8_t* depth, int max_depth) {
|
||||||
int stack[16];
|
int stack[16];
|
||||||
int level = 0;
|
int level = 0;
|
||||||
int p = p0;
|
int p = p0;
|
||||||
assert(max_depth <= 15);
|
BROTLI_DCHECK(max_depth <= 15);
|
||||||
stack[0] = -1;
|
stack[0] = -1;
|
||||||
while (BROTLI_TRUE) {
|
while (BROTLI_TRUE) {
|
||||||
if (pool[p].index_left_ >= 0) {
|
if (pool[p].index_left_ >= 0) {
|
||||||
|
@ -66,11 +68,11 @@ static BROTLI_INLINE BROTLI_BOOL SortHuffmanTree(
|
||||||
we are not planning to use this with extremely long blocks.
|
we are not planning to use this with extremely long blocks.
|
||||||
|
|
||||||
See http://en.wikipedia.org/wiki/Huffman_coding */
|
See http://en.wikipedia.org/wiki/Huffman_coding */
|
||||||
void BrotliCreateHuffmanTree(const uint32_t *data,
|
void BrotliCreateHuffmanTree(const uint32_t* data,
|
||||||
const size_t length,
|
const size_t length,
|
||||||
const int tree_limit,
|
const int tree_limit,
|
||||||
HuffmanTree* tree,
|
HuffmanTree* tree,
|
||||||
uint8_t *depth) {
|
uint8_t* depth) {
|
||||||
uint32_t count_limit;
|
uint32_t count_limit;
|
||||||
HuffmanTree sentinel;
|
HuffmanTree sentinel;
|
||||||
InitHuffmanTree(&sentinel, BROTLI_UINT32_MAX, -1, -1);
|
InitHuffmanTree(&sentinel, BROTLI_UINT32_MAX, -1, -1);
|
||||||
|
@ -165,7 +167,7 @@ static void BrotliWriteHuffmanTreeRepetitions(
|
||||||
size_t* tree_size,
|
size_t* tree_size,
|
||||||
uint8_t* tree,
|
uint8_t* tree,
|
||||||
uint8_t* extra_bits_data) {
|
uint8_t* extra_bits_data) {
|
||||||
assert(repetitions > 0);
|
BROTLI_DCHECK(repetitions > 0);
|
||||||
if (previous_value != value) {
|
if (previous_value != value) {
|
||||||
tree[*tree_size] = value;
|
tree[*tree_size] = value;
|
||||||
extra_bits_data[*tree_size] = 0;
|
extra_bits_data[*tree_size] = 0;
|
||||||
|
@ -371,8 +373,8 @@ void BrotliOptimizeHuffmanCountsForRle(size_t length, uint32_t* counts,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DecideOverRleUse(const uint8_t* depth, const size_t length,
|
static void DecideOverRleUse(const uint8_t* depth, const size_t length,
|
||||||
BROTLI_BOOL *use_rle_for_non_zero,
|
BROTLI_BOOL* use_rle_for_non_zero,
|
||||||
BROTLI_BOOL *use_rle_for_zero) {
|
BROTLI_BOOL* use_rle_for_zero) {
|
||||||
size_t total_reps_zero = 0;
|
size_t total_reps_zero = 0;
|
||||||
size_t total_reps_non_zero = 0;
|
size_t total_reps_non_zero = 0;
|
||||||
size_t count_reps_zero = 1;
|
size_t count_reps_zero = 1;
|
||||||
|
@ -454,26 +456,26 @@ void BrotliWriteHuffmanTree(const uint8_t* depth,
|
||||||
|
|
||||||
static uint16_t BrotliReverseBits(size_t num_bits, uint16_t bits) {
|
static uint16_t BrotliReverseBits(size_t num_bits, uint16_t bits) {
|
||||||
static const size_t kLut[16] = { /* Pre-reversed 4-bit values. */
|
static const size_t kLut[16] = { /* Pre-reversed 4-bit values. */
|
||||||
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
|
0x00, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E,
|
||||||
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
|
0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F
|
||||||
};
|
};
|
||||||
size_t retval = kLut[bits & 0xf];
|
size_t retval = kLut[bits & 0x0F];
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 4; i < num_bits; i += 4) {
|
for (i = 4; i < num_bits; i += 4) {
|
||||||
retval <<= 4;
|
retval <<= 4;
|
||||||
bits = (uint16_t)(bits >> 4);
|
bits = (uint16_t)(bits >> 4);
|
||||||
retval |= kLut[bits & 0xf];
|
retval |= kLut[bits & 0x0F];
|
||||||
}
|
}
|
||||||
retval >>= ((0 - num_bits) & 0x3);
|
retval >>= ((0 - num_bits) & 0x03);
|
||||||
return (uint16_t)retval;
|
return (uint16_t)retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 0..15 are values for bits */
|
/* 0..15 are values for bits */
|
||||||
#define MAX_HUFFMAN_BITS 16
|
#define MAX_HUFFMAN_BITS 16
|
||||||
|
|
||||||
void BrotliConvertBitDepthsToSymbols(const uint8_t *depth,
|
void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
|
||||||
size_t len,
|
size_t len,
|
||||||
uint16_t *bits) {
|
uint16_t* bits) {
|
||||||
/* In Brotli, all bit depths are [1..15]
|
/* In Brotli, all bit depths are [1..15]
|
||||||
0 bit depth means that the symbol does not exist. */
|
0 bit depth means that the symbol does not exist. */
|
||||||
uint16_t bl_count[MAX_HUFFMAN_BITS] = { 0 };
|
uint16_t bl_count[MAX_HUFFMAN_BITS] = { 0 };
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
#ifndef BROTLI_ENC_ENTROPY_ENCODE_H_
|
#ifndef BROTLI_ENC_ENTROPY_ENCODE_H_
|
||||||
#define BROTLI_ENC_ENTROPY_ENCODE_H_
|
#define BROTLI_ENC_ENTROPY_ENCODE_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -46,11 +46,11 @@ BROTLI_INTERNAL BROTLI_BOOL BrotliSetDepth(
|
||||||
be at least 2 * length + 1 long.
|
be at least 2 * length + 1 long.
|
||||||
|
|
||||||
See http://en.wikipedia.org/wiki/Huffman_coding */
|
See http://en.wikipedia.org/wiki/Huffman_coding */
|
||||||
BROTLI_INTERNAL void BrotliCreateHuffmanTree(const uint32_t *data,
|
BROTLI_INTERNAL void BrotliCreateHuffmanTree(const uint32_t* data,
|
||||||
const size_t length,
|
const size_t length,
|
||||||
const int tree_limit,
|
const int tree_limit,
|
||||||
HuffmanTree* tree,
|
HuffmanTree* tree,
|
||||||
uint8_t *depth);
|
uint8_t* depth);
|
||||||
|
|
||||||
/* Change the population counts in a way that the consequent
|
/* Change the population counts in a way that the consequent
|
||||||
Huffman tree compression, especially its RLE-part will be more
|
Huffman tree compression, especially its RLE-part will be more
|
||||||
|
@ -72,16 +72,16 @@ BROTLI_INTERNAL void BrotliWriteHuffmanTree(const uint8_t* depth,
|
||||||
uint8_t* extra_bits_data);
|
uint8_t* extra_bits_data);
|
||||||
|
|
||||||
/* Get the actual bit values for a tree of bit depths. */
|
/* Get the actual bit values for a tree of bit depths. */
|
||||||
BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t *depth,
|
BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
|
||||||
size_t len,
|
size_t len,
|
||||||
uint16_t *bits);
|
uint16_t* bits);
|
||||||
|
|
||||||
|
BROTLI_INTERNAL extern const size_t kBrotliShellGaps[6];
|
||||||
/* Input size optimized Shell sort. */
|
/* Input size optimized Shell sort. */
|
||||||
typedef BROTLI_BOOL (*HuffmanTreeComparator)(
|
typedef BROTLI_BOOL (*HuffmanTreeComparator)(
|
||||||
const HuffmanTree*, const HuffmanTree*);
|
const HuffmanTree*, const HuffmanTree*);
|
||||||
static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
|
static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
|
||||||
const size_t n, HuffmanTreeComparator comparator) {
|
const size_t n, HuffmanTreeComparator comparator) {
|
||||||
static const size_t gaps[] = {132, 57, 23, 10, 4, 1};
|
|
||||||
if (n < 13) {
|
if (n < 13) {
|
||||||
/* Insertion sort. */
|
/* Insertion sort. */
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -101,7 +101,7 @@ static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
|
||||||
/* Shell sort. */
|
/* Shell sort. */
|
||||||
int g = n < 57 ? 2 : 0;
|
int g = n < 57 ? 2 : 0;
|
||||||
for (; g < 6; ++g) {
|
for (; g < 6; ++g) {
|
||||||
size_t gap = gaps[g];
|
size_t gap = kBrotliShellGaps[g];
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = gap; i < n; ++i) {
|
for (i = gap; i < n; ++i) {
|
||||||
size_t j = i;
|
size_t j = i;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#define BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_
|
#define BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
#include <brotli/port.h>
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./write_bits.h"
|
#include "./write_bits.h"
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ static const uint32_t kCodeLengthBits[18] = {
|
||||||
static BROTLI_INLINE void StoreStaticCodeLengthCode(
|
static BROTLI_INLINE void StoreStaticCodeLengthCode(
|
||||||
size_t* storage_ix, uint8_t* storage) {
|
size_t* storage_ix, uint8_t* storage) {
|
||||||
BrotliWriteBits(
|
BrotliWriteBits(
|
||||||
40, BROTLI_MAKE_UINT64_T(0x0000ffU, 0x55555554U), storage_ix, storage);
|
40, BROTLI_MAKE_UINT64_T(0x0000FFu, 0x55555554u), storage_ix, storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
static const uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||||
|
@ -529,7 +529,7 @@ static const uint16_t kStaticDistanceCodeBits[64] = {
|
||||||
|
|
||||||
static BROTLI_INLINE void StoreStaticDistanceHuffmanTree(
|
static BROTLI_INLINE void StoreStaticDistanceHuffmanTree(
|
||||||
size_t* storage_ix, uint8_t* storage) {
|
size_t* storage_ix, uint8_t* storage) {
|
||||||
BrotliWriteBits(28, 0x0369dc03U, storage_ix, storage);
|
BrotliWriteBits(28, 0x0369DC03u, storage_ix, storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
|
|
@ -11,16 +11,16 @@
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include <brotli/port.h>
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
|
static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
|
||||||
#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_clz)
|
#if defined(BROTLI_BSR32)
|
||||||
return 31u ^ (uint32_t)__builtin_clz((uint32_t)n);
|
return BROTLI_BSR32((uint32_t)n);
|
||||||
#else
|
#else
|
||||||
uint32_t result = 0;
|
uint32_t result = 0;
|
||||||
while (n >>= 1) result++;
|
while (n >>= 1) result++;
|
||||||
|
@ -28,110 +28,31 @@ static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A lookup table for small values of log2(int) to be used in entropy
|
#define BROTLI_LOG2_TABLE_SIZE 256
|
||||||
computation.
|
|
||||||
|
|
||||||
", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
|
/* A lookup table for small values of log2(int) to be used in entropy
|
||||||
static const float kLog2Table[] = {
|
computation. */
|
||||||
0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
|
BROTLI_INTERNAL extern const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE];
|
||||||
1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
|
|
||||||
2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
|
/* Visual Studio 2012 and Android API levels < 18 do not have the log2()
|
||||||
3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f,
|
* function defined, so we use log() and a multiplication instead. */
|
||||||
3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f,
|
#if !defined(BROTLI_HAVE_LOG2)
|
||||||
3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f,
|
#if ((defined(_MSC_VER) && _MSC_VER <= 1700) || \
|
||||||
4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f,
|
(defined(__ANDROID_API__) && __ANDROID_API__ < 18))
|
||||||
4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f,
|
#define BROTLI_HAVE_LOG2 0
|
||||||
4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f,
|
#else
|
||||||
4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f,
|
#define BROTLI_HAVE_LOG2 1
|
||||||
4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f,
|
#endif
|
||||||
5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f,
|
#endif
|
||||||
5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f,
|
|
||||||
5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f,
|
|
||||||
5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f,
|
|
||||||
5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f,
|
|
||||||
5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f,
|
|
||||||
5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f,
|
|
||||||
5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f,
|
|
||||||
5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f,
|
|
||||||
5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f,
|
|
||||||
5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f,
|
|
||||||
6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f,
|
|
||||||
6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f,
|
|
||||||
6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f,
|
|
||||||
6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f,
|
|
||||||
6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f,
|
|
||||||
6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f,
|
|
||||||
6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f,
|
|
||||||
6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f,
|
|
||||||
6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f,
|
|
||||||
6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f,
|
|
||||||
6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f,
|
|
||||||
6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f,
|
|
||||||
6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f,
|
|
||||||
6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f,
|
|
||||||
6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f,
|
|
||||||
6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f,
|
|
||||||
6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f,
|
|
||||||
6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f,
|
|
||||||
6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f,
|
|
||||||
6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f,
|
|
||||||
6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f,
|
|
||||||
7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f,
|
|
||||||
7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f,
|
|
||||||
7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f,
|
|
||||||
7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f,
|
|
||||||
7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f,
|
|
||||||
7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f,
|
|
||||||
7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f,
|
|
||||||
7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f,
|
|
||||||
7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f,
|
|
||||||
7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f,
|
|
||||||
7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f,
|
|
||||||
7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f,
|
|
||||||
7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f,
|
|
||||||
7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f,
|
|
||||||
7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f,
|
|
||||||
7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f,
|
|
||||||
7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f,
|
|
||||||
7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f,
|
|
||||||
7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f,
|
|
||||||
7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f,
|
|
||||||
7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f,
|
|
||||||
7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f,
|
|
||||||
7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f,
|
|
||||||
7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f,
|
|
||||||
7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f,
|
|
||||||
7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f,
|
|
||||||
7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f,
|
|
||||||
7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f,
|
|
||||||
7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f,
|
|
||||||
7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f,
|
|
||||||
7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f,
|
|
||||||
7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f,
|
|
||||||
7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f,
|
|
||||||
7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f,
|
|
||||||
7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f,
|
|
||||||
7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f,
|
|
||||||
7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f,
|
|
||||||
7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f,
|
|
||||||
7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f,
|
|
||||||
7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f,
|
|
||||||
7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f,
|
|
||||||
7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f,
|
|
||||||
7.9943534368588578f
|
|
||||||
};
|
|
||||||
|
|
||||||
#define LOG_2_INV 1.4426950408889634
|
#define LOG_2_INV 1.4426950408889634
|
||||||
|
|
||||||
/* Faster logarithm for small integers, with the property of log2(0) == 0. */
|
/* Faster logarithm for small integers, with the property of log2(0) == 0. */
|
||||||
static BROTLI_INLINE double FastLog2(size_t v) {
|
static BROTLI_INLINE double FastLog2(size_t v) {
|
||||||
if (v < sizeof(kLog2Table) / sizeof(kLog2Table[0])) {
|
if (v < BROTLI_LOG2_TABLE_SIZE) {
|
||||||
return kLog2Table[v];
|
return kBrotliLog2Table[v];
|
||||||
}
|
}
|
||||||
#if (defined(_MSC_VER) && _MSC_VER <= 1700) || \
|
#if !(BROTLI_HAVE_LOG2)
|
||||||
(defined(__ANDROID_API__) && __ANDROID_API__ < 18)
|
|
||||||
/* Visual Studio 2012 and Android API levels < 18 do not have the log2()
|
|
||||||
* function defined, so we use log() and a multiplication instead. */
|
|
||||||
return log((double)v) * LOG_2_INV;
|
return log((double)v) * LOG_2_INV;
|
||||||
#else
|
#else
|
||||||
return log2((double)v);
|
return log2((double)v);
|
||||||
|
|
|
@ -9,16 +9,15 @@
|
||||||
#ifndef BROTLI_ENC_FIND_MATCH_LENGTH_H_
|
#ifndef BROTLI_ENC_FIND_MATCH_LENGTH_H_
|
||||||
#define BROTLI_ENC_FIND_MATCH_LENGTH_H_
|
#define BROTLI_ENC_FIND_MATCH_LENGTH_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Separate implementation for little-endian 64-bit targets, for speed. */
|
/* Separate implementation for little-endian 64-bit targets, for speed. */
|
||||||
#if defined(__GNUC__) && defined(_LP64) && defined(BROTLI_LITTLE_ENDIAN)
|
#if defined(BROTLI_TZCNT64) && BROTLI_64_BITS && BROTLI_LITTLE_ENDIAN
|
||||||
|
|
||||||
static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
|
static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
|
||||||
const uint8_t* s2,
|
const uint8_t* s2,
|
||||||
size_t limit) {
|
size_t limit) {
|
||||||
|
@ -32,7 +31,7 @@ static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
|
||||||
} else {
|
} else {
|
||||||
uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
|
uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
|
||||||
BROTLI_UNALIGNED_LOAD64LE(s1 + matched);
|
BROTLI_UNALIGNED_LOAD64LE(s1 + matched);
|
||||||
size_t matching_bits = (size_t)__builtin_ctzll(x);
|
size_t matching_bits = (size_t)BROTLI_TZCNT64(x);
|
||||||
matched += matching_bits >> 3;
|
matched += matching_bits >> 3;
|
||||||
return matched;
|
return matched;
|
||||||
}
|
}
|
||||||
|
@ -60,8 +59,8 @@ static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
|
||||||
the first non-matching bit and use that to calculate the total
|
the first non-matching bit and use that to calculate the total
|
||||||
length of the match. */
|
length of the match. */
|
||||||
while (s2_ptr <= s2_limit - 4 &&
|
while (s2_ptr <= s2_limit - 4 &&
|
||||||
BROTLI_UNALIGNED_LOAD32(s2_ptr) ==
|
BrotliUnalignedRead32(s2_ptr) ==
|
||||||
BROTLI_UNALIGNED_LOAD32(s1 + matched)) {
|
BrotliUnalignedRead32(s1 + matched)) {
|
||||||
s2_ptr += 4;
|
s2_ptr += 4;
|
||||||
matched += 4;
|
matched += 4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,12 @@
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
#include "../common/dictionary.h"
|
#include "../common/dictionary.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
|
#include "./encoder_dict.h"
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
#include "./find_match_length.h"
|
#include "./find_match_length.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./quality.h"
|
#include "./quality.h"
|
||||||
#include "./static_dict.h"
|
#include "./static_dict.h"
|
||||||
|
|
||||||
|
@ -26,32 +27,19 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Pointer to hasher data.
|
|
||||||
*
|
|
||||||
* Excluding initialization and destruction, hasher can be passed as
|
|
||||||
* HasherHandle by value.
|
|
||||||
*
|
|
||||||
* Typically hasher data consists of 3 sections:
|
|
||||||
* * HasherCommon structure
|
|
||||||
* * private structured hasher data, depending on hasher type
|
|
||||||
* * private dynamic hasher data, depending on hasher type and parameters
|
|
||||||
*/
|
|
||||||
typedef uint8_t* HasherHandle;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/* Dynamically allocated area; first member for quickest access. */
|
||||||
|
void* extra;
|
||||||
|
|
||||||
|
size_t dict_num_lookups;
|
||||||
|
size_t dict_num_matches;
|
||||||
|
|
||||||
BrotliHasherParams params;
|
BrotliHasherParams params;
|
||||||
|
|
||||||
/* False if hasher needs to be "prepared" before use. */
|
/* False if hasher needs to be "prepared" before use. */
|
||||||
BROTLI_BOOL is_prepared_;
|
BROTLI_BOOL is_prepared_;
|
||||||
|
|
||||||
size_t dict_num_lookups;
|
|
||||||
size_t dict_num_matches;
|
|
||||||
} HasherCommon;
|
} HasherCommon;
|
||||||
|
|
||||||
static BROTLI_INLINE HasherCommon* GetHasherCommon(HasherHandle handle) {
|
|
||||||
return (HasherCommon*)handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define score_t size_t
|
#define score_t size_t
|
||||||
|
|
||||||
static const uint32_t kCutoffTransformsCount = 10;
|
static const uint32_t kCutoffTransformsCount = 10;
|
||||||
|
@ -73,13 +61,13 @@ typedef struct HasherSearchResult {
|
||||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||||
for this use.
|
for this use.
|
||||||
* The number has been tuned heuristically against compression benchmarks. */
|
* The number has been tuned heuristically against compression benchmarks. */
|
||||||
static const uint32_t kHashMul32 = 0x1e35a7bd;
|
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||||
static const uint64_t kHashMul64 = BROTLI_MAKE_UINT64_T(0x1e35a7bd, 0x1e35a7bd);
|
static const uint64_t kHashMul64 = BROTLI_MAKE_UINT64_T(0x1E35A7BD, 0x1E35A7BD);
|
||||||
static const uint64_t kHashMul64Long =
|
static const uint64_t kHashMul64Long =
|
||||||
BROTLI_MAKE_UINT64_T(0x1fe35a7bU, 0xd3579bd3U);
|
BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
|
static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
|
||||||
uint32_t h = BROTLI_UNALIGNED_LOAD32(data) * kHashMul32;
|
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||||
/* The higher bits contain more mixture from the multiplication,
|
/* The higher bits contain more mixture from the multiplication,
|
||||||
so we take our results from there. */
|
so we take our results from there. */
|
||||||
return h >> (32 - 14);
|
return h >> (32 - 14);
|
||||||
|
@ -146,34 +134,31 @@ static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
|
static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
|
||||||
const BrotliDictionary* dictionary, size_t item, const uint8_t* data,
|
const BrotliEncoderDictionary* dictionary, size_t len, size_t word_idx,
|
||||||
size_t max_length, size_t max_backward, HasherSearchResult* out) {
|
const uint8_t* data, size_t max_length, size_t max_backward,
|
||||||
size_t len;
|
size_t max_distance, HasherSearchResult* out) {
|
||||||
size_t dist;
|
|
||||||
size_t offset;
|
size_t offset;
|
||||||
size_t matchlen;
|
size_t matchlen;
|
||||||
size_t backward;
|
size_t backward;
|
||||||
score_t score;
|
score_t score;
|
||||||
len = item & 0x1F;
|
offset = dictionary->words->offsets_by_length[len] + len * word_idx;
|
||||||
dist = item >> 5;
|
|
||||||
offset = dictionary->offsets_by_length[len] + len * dist;
|
|
||||||
if (len > max_length) {
|
if (len > max_length) {
|
||||||
return BROTLI_FALSE;
|
return BROTLI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
matchlen =
|
matchlen =
|
||||||
FindMatchLengthWithLimit(data, &dictionary->data[offset], len);
|
FindMatchLengthWithLimit(data, &dictionary->words->data[offset], len);
|
||||||
if (matchlen + kCutoffTransformsCount <= len || matchlen == 0) {
|
if (matchlen + dictionary->cutoffTransformsCount <= len || matchlen == 0) {
|
||||||
return BROTLI_FALSE;
|
return BROTLI_FALSE;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
size_t cut = len - matchlen;
|
size_t cut = len - matchlen;
|
||||||
size_t transform_id =
|
size_t transform_id = (cut << 2) +
|
||||||
(cut << 2) + (size_t)((kCutoffTransforms >> (cut * 6)) & 0x3F);
|
(size_t)((dictionary->cutoffTransforms >> (cut * 6)) & 0x3F);
|
||||||
backward = max_backward + dist + 1 +
|
backward = max_backward + 1 + word_idx +
|
||||||
(transform_id << dictionary->size_bits_by_length[len]);
|
(transform_id << dictionary->words->size_bits_by_length[len]);
|
||||||
}
|
}
|
||||||
if (backward >= BROTLI_MAX_DISTANCE) {
|
if (backward > max_distance) {
|
||||||
return BROTLI_FALSE;
|
return BROTLI_FALSE;
|
||||||
}
|
}
|
||||||
score = BackwardReferenceScore(matchlen, backward);
|
score = BackwardReferenceScore(matchlen, backward);
|
||||||
|
@ -188,24 +173,25 @@ static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void SearchInStaticDictionary(
|
static BROTLI_INLINE void SearchInStaticDictionary(
|
||||||
const BrotliDictionary* dictionary, const uint16_t* dictionary_hash,
|
const BrotliEncoderDictionary* dictionary,
|
||||||
HasherHandle handle, const uint8_t* data, size_t max_length,
|
HasherCommon* common, const uint8_t* data, size_t max_length,
|
||||||
size_t max_backward, HasherSearchResult* out, BROTLI_BOOL shallow) {
|
size_t max_backward, size_t max_distance,
|
||||||
|
HasherSearchResult* out, BROTLI_BOOL shallow) {
|
||||||
size_t key;
|
size_t key;
|
||||||
size_t i;
|
size_t i;
|
||||||
HasherCommon* self = GetHasherCommon(handle);
|
if (common->dict_num_matches < (common->dict_num_lookups >> 7)) {
|
||||||
if (self->dict_num_matches < (self->dict_num_lookups >> 7)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
key = Hash14(data) << 1;
|
key = Hash14(data) << 1;
|
||||||
for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) {
|
for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) {
|
||||||
size_t item = dictionary_hash[key];
|
common->dict_num_lookups++;
|
||||||
self->dict_num_lookups++;
|
if (dictionary->hash_table_lengths[key] != 0) {
|
||||||
if (item != 0) {
|
|
||||||
BROTLI_BOOL item_matches = TestStaticDictionaryItem(
|
BROTLI_BOOL item_matches = TestStaticDictionaryItem(
|
||||||
dictionary, item, data, max_length, max_backward, out);
|
dictionary, dictionary->hash_table_lengths[key],
|
||||||
|
dictionary->hash_table_words[key], data,
|
||||||
|
max_length, max_backward, max_distance, out);
|
||||||
if (item_matches) {
|
if (item_matches) {
|
||||||
self->dict_num_matches++;
|
common->dict_num_matches++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,37 +240,37 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||||
/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
|
/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
|
||||||
#define MAX_NUM_MATCHES_H10 128
|
#define MAX_NUM_MATCHES_H10 128
|
||||||
|
|
||||||
/* For BUCKET_SWEEP == 1, enabling the dictionary lookup makes compression
|
/* For BUCKET_SWEEP_BITS == 0, enabling the dictionary lookup makes compression
|
||||||
a little faster (0.5% - 1%) and it compresses 0.15% better on small text
|
a little faster (0.5% - 1%) and it compresses 0.15% better on small text
|
||||||
and HTML inputs. */
|
and HTML inputs. */
|
||||||
|
|
||||||
#define HASHER() H2
|
#define HASHER() H2
|
||||||
#define BUCKET_BITS 16
|
#define BUCKET_BITS 16
|
||||||
#define BUCKET_SWEEP 1
|
#define BUCKET_SWEEP_BITS 0
|
||||||
#define HASH_LEN 5
|
#define HASH_LEN 5
|
||||||
#define USE_DICTIONARY 1
|
#define USE_DICTIONARY 1
|
||||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||||
#undef BUCKET_SWEEP
|
#undef BUCKET_SWEEP_BITS
|
||||||
#undef USE_DICTIONARY
|
#undef USE_DICTIONARY
|
||||||
#undef HASHER
|
#undef HASHER
|
||||||
|
|
||||||
#define HASHER() H3
|
#define HASHER() H3
|
||||||
#define BUCKET_SWEEP 2
|
#define BUCKET_SWEEP_BITS 1
|
||||||
#define USE_DICTIONARY 0
|
#define USE_DICTIONARY 0
|
||||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||||
#undef USE_DICTIONARY
|
#undef USE_DICTIONARY
|
||||||
#undef BUCKET_SWEEP
|
#undef BUCKET_SWEEP_BITS
|
||||||
#undef BUCKET_BITS
|
#undef BUCKET_BITS
|
||||||
#undef HASHER
|
#undef HASHER
|
||||||
|
|
||||||
#define HASHER() H4
|
#define HASHER() H4
|
||||||
#define BUCKET_BITS 17
|
#define BUCKET_BITS 17
|
||||||
#define BUCKET_SWEEP 4
|
#define BUCKET_SWEEP_BITS 2
|
||||||
#define USE_DICTIONARY 1
|
#define USE_DICTIONARY 1
|
||||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||||
#undef USE_DICTIONARY
|
#undef USE_DICTIONARY
|
||||||
#undef HASH_LEN
|
#undef HASH_LEN
|
||||||
#undef BUCKET_SWEEP
|
#undef BUCKET_SWEEP_BITS
|
||||||
#undef BUCKET_BITS
|
#undef BUCKET_BITS
|
||||||
#undef HASHER
|
#undef HASHER
|
||||||
|
|
||||||
|
@ -328,110 +314,166 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||||
|
|
||||||
#define HASHER() H54
|
#define HASHER() H54
|
||||||
#define BUCKET_BITS 20
|
#define BUCKET_BITS 20
|
||||||
#define BUCKET_SWEEP 4
|
#define BUCKET_SWEEP_BITS 2
|
||||||
#define HASH_LEN 7
|
#define HASH_LEN 7
|
||||||
#define USE_DICTIONARY 0
|
#define USE_DICTIONARY 0
|
||||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||||
#undef USE_DICTIONARY
|
#undef USE_DICTIONARY
|
||||||
#undef HASH_LEN
|
#undef HASH_LEN
|
||||||
#undef BUCKET_SWEEP
|
#undef BUCKET_SWEEP_BITS
|
||||||
#undef BUCKET_BITS
|
#undef BUCKET_BITS
|
||||||
#undef HASHER
|
#undef HASHER
|
||||||
|
|
||||||
|
/* fast large window hashers */
|
||||||
|
|
||||||
|
#define HASHER() HROLLING_FAST
|
||||||
|
#define CHUNKLEN 32
|
||||||
|
#define JUMP 4
|
||||||
|
#define NUMBUCKETS 16777216
|
||||||
|
#define MASK ((NUMBUCKETS * 64) - 1)
|
||||||
|
#include "./hash_rolling_inc.h" /* NOLINT(build/include) */
|
||||||
|
#undef JUMP
|
||||||
|
#undef HASHER
|
||||||
|
|
||||||
|
|
||||||
|
#define HASHER() HROLLING
|
||||||
|
#define JUMP 1
|
||||||
|
#include "./hash_rolling_inc.h" /* NOLINT(build/include) */
|
||||||
|
#undef MASK
|
||||||
|
#undef NUMBUCKETS
|
||||||
|
#undef JUMP
|
||||||
|
#undef CHUNKLEN
|
||||||
|
#undef HASHER
|
||||||
|
|
||||||
|
#define HASHER() H35
|
||||||
|
#define HASHER_A H3
|
||||||
|
#define HASHER_B HROLLING_FAST
|
||||||
|
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
|
||||||
|
#undef HASHER_A
|
||||||
|
#undef HASHER_B
|
||||||
|
#undef HASHER
|
||||||
|
|
||||||
|
#define HASHER() H55
|
||||||
|
#define HASHER_A H54
|
||||||
|
#define HASHER_B HROLLING_FAST
|
||||||
|
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
|
||||||
|
#undef HASHER_A
|
||||||
|
#undef HASHER_B
|
||||||
|
#undef HASHER
|
||||||
|
|
||||||
|
#define HASHER() H65
|
||||||
|
#define HASHER_A H6
|
||||||
|
#define HASHER_B HROLLING
|
||||||
|
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
|
||||||
|
#undef HASHER_A
|
||||||
|
#undef HASHER_B
|
||||||
|
#undef HASHER
|
||||||
|
|
||||||
#undef FN
|
#undef FN
|
||||||
#undef CAT
|
#undef CAT
|
||||||
#undef EXPAND_CAT
|
#undef EXPAND_CAT
|
||||||
|
|
||||||
#define FOR_GENERIC_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)
|
#define FOR_SIMPLE_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)
|
||||||
|
#define FOR_COMPOSITE_HASHERS(H) H(35) H(55) H(65)
|
||||||
|
#define FOR_GENERIC_HASHERS(H) FOR_SIMPLE_HASHERS(H) FOR_COMPOSITE_HASHERS(H)
|
||||||
#define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10)
|
#define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10)
|
||||||
|
|
||||||
static BROTLI_INLINE void DestroyHasher(
|
typedef struct {
|
||||||
MemoryManager* m, HasherHandle* handle) {
|
HasherCommon common;
|
||||||
if (*handle == NULL) return;
|
|
||||||
BROTLI_FREE(m, *handle);
|
union {
|
||||||
|
#define MEMBER_(N) \
|
||||||
|
H ## N _H ## N;
|
||||||
|
FOR_ALL_HASHERS(MEMBER_)
|
||||||
|
#undef MEMBER_
|
||||||
|
} privat;
|
||||||
|
} Hasher;
|
||||||
|
|
||||||
|
/* MUST be invoked before any other method. */
|
||||||
|
static BROTLI_INLINE void HasherInit(Hasher* hasher) {
|
||||||
|
hasher->common.extra = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void HasherReset(HasherHandle handle) {
|
static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) {
|
||||||
if (handle == NULL) return;
|
if (hasher->common.extra == NULL) return;
|
||||||
GetHasherCommon(handle)->is_prepared_ = BROTLI_FALSE;
|
BROTLI_FREE(m, hasher->common.extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BROTLI_INLINE void HasherReset(Hasher* hasher) {
|
||||||
|
hasher->common.is_prepared_ = BROTLI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params,
|
static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params,
|
||||||
BROTLI_BOOL one_shot, const size_t input_size) {
|
BROTLI_BOOL one_shot, const size_t input_size) {
|
||||||
size_t result = sizeof(HasherCommon);
|
|
||||||
switch (params->hasher.type) {
|
switch (params->hasher.type) {
|
||||||
#define SIZE_(N) \
|
#define SIZE_(N) \
|
||||||
case N: \
|
case N: \
|
||||||
result += HashMemAllocInBytesH ## N(params, one_shot, input_size); \
|
return HashMemAllocInBytesH ## N(params, one_shot, input_size);
|
||||||
break;
|
|
||||||
FOR_ALL_HASHERS(SIZE_)
|
FOR_ALL_HASHERS(SIZE_)
|
||||||
#undef SIZE_
|
#undef SIZE_
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return result;
|
return 0; /* Default case. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void HasherSetup(MemoryManager* m, HasherHandle* handle,
|
static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher,
|
||||||
BrotliEncoderParams* params, const uint8_t* data, size_t position,
|
BrotliEncoderParams* params, const uint8_t* data, size_t position,
|
||||||
size_t input_size, BROTLI_BOOL is_last) {
|
size_t input_size, BROTLI_BOOL is_last) {
|
||||||
HasherHandle self = NULL;
|
|
||||||
HasherCommon* common = NULL;
|
|
||||||
BROTLI_BOOL one_shot = (position == 0 && is_last);
|
BROTLI_BOOL one_shot = (position == 0 && is_last);
|
||||||
if (*handle == NULL) {
|
if (hasher->common.extra == NULL) {
|
||||||
size_t alloc_size;
|
size_t alloc_size;
|
||||||
ChooseHasher(params, ¶ms->hasher);
|
ChooseHasher(params, ¶ms->hasher);
|
||||||
alloc_size = HasherSize(params, one_shot, input_size);
|
alloc_size = HasherSize(params, one_shot, input_size);
|
||||||
self = BROTLI_ALLOC(m, uint8_t, alloc_size);
|
hasher->common.extra = BROTLI_ALLOC(m, uint8_t, alloc_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra)) return;
|
||||||
*handle = self;
|
hasher->common.params = params->hasher;
|
||||||
common = GetHasherCommon(self);
|
switch (hasher->common.params.type) {
|
||||||
common->params = params->hasher;
|
#define INITIALIZE_(N) \
|
||||||
switch (common->params.type) {
|
case N: \
|
||||||
#define INITIALIZE_(N) \
|
InitializeH ## N(&hasher->common, \
|
||||||
case N: \
|
&hasher->privat._H ## N, params); \
|
||||||
InitializeH ## N(*handle, params); \
|
|
||||||
break;
|
break;
|
||||||
FOR_ALL_HASHERS(INITIALIZE_);
|
FOR_ALL_HASHERS(INITIALIZE_);
|
||||||
#undef INITIALIZE_
|
#undef INITIALIZE_
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
HasherReset(*handle);
|
HasherReset(hasher);
|
||||||
}
|
}
|
||||||
|
|
||||||
self = *handle;
|
if (!hasher->common.is_prepared_) {
|
||||||
common = GetHasherCommon(self);
|
switch (hasher->common.params.type) {
|
||||||
if (!common->is_prepared_) {
|
#define PREPARE_(N) \
|
||||||
switch (common->params.type) {
|
case N: \
|
||||||
#define PREPARE_(N) \
|
PrepareH ## N( \
|
||||||
case N: \
|
&hasher->privat._H ## N, \
|
||||||
PrepareH ## N(self, one_shot, input_size, data); \
|
one_shot, input_size, data); \
|
||||||
break;
|
break;
|
||||||
FOR_ALL_HASHERS(PREPARE_)
|
FOR_ALL_HASHERS(PREPARE_)
|
||||||
#undef PREPARE_
|
#undef PREPARE_
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
common->dict_num_lookups = 0;
|
hasher->common.dict_num_lookups = 0;
|
||||||
common->dict_num_matches = 0;
|
hasher->common.dict_num_matches = 0;
|
||||||
}
|
}
|
||||||
common->is_prepared_ = BROTLI_TRUE;
|
hasher->common.is_prepared_ = BROTLI_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void InitOrStitchToPreviousBlock(
|
static BROTLI_INLINE void InitOrStitchToPreviousBlock(
|
||||||
MemoryManager* m, HasherHandle* handle, const uint8_t* data, size_t mask,
|
MemoryManager* m, Hasher* hasher, const uint8_t* data, size_t mask,
|
||||||
BrotliEncoderParams* params, size_t position, size_t input_size,
|
BrotliEncoderParams* params, size_t position, size_t input_size,
|
||||||
BROTLI_BOOL is_last) {
|
BROTLI_BOOL is_last) {
|
||||||
HasherHandle self;
|
HasherSetup(m, hasher, params, data, position, input_size, is_last);
|
||||||
HasherSetup(m, handle, params, data, position, input_size, is_last);
|
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
self = *handle;
|
switch (hasher->common.params.type) {
|
||||||
switch (GetHasherCommon(self)->params.type) {
|
#define INIT_(N) \
|
||||||
#define INIT_(N) \
|
case N: \
|
||||||
case N: \
|
StitchToPreviousBlockH ## N( \
|
||||||
StitchToPreviousBlockH ## N(self, input_size, position, data, mask); \
|
&hasher->privat._H ## N, \
|
||||||
|
input_size, position, data, mask); \
|
||||||
break;
|
break;
|
||||||
FOR_ALL_HASHERS(INIT_)
|
FOR_ALL_HASHERS(INIT_)
|
||||||
#undef INIT_
|
#undef INIT_
|
||||||
|
|
|
@ -28,8 +28,8 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
|
||||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
|
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
|
||||||
|
|
||||||
/* HashBytes is the function that chooses the bucket to place the address in.*/
|
/* HashBytes is the function that chooses the bucket to place the address in.*/
|
||||||
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t *data) {
|
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
|
||||||
const uint32_t h = BROTLI_UNALIGNED_LOAD32(data) * kHashMul32;
|
const uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||||
/* The higher bits contain more mixture from the multiplication,
|
/* The higher bits contain more mixture from the multiplication,
|
||||||
so we take our results from there. */
|
so we take our results from there. */
|
||||||
return h >> (32 - BUCKET_BITS);
|
return h >> (32 - BUCKET_BITS);
|
||||||
|
@ -45,28 +45,56 @@ typedef struct FN(Bank) {
|
||||||
} FN(Bank);
|
} FN(Bank);
|
||||||
|
|
||||||
typedef struct HashForgetfulChain {
|
typedef struct HashForgetfulChain {
|
||||||
uint32_t addr[BUCKET_SIZE];
|
uint16_t free_slot_idx[NUM_BANKS]; /* Up to 1KiB. Move to dynamic? */
|
||||||
uint16_t head[BUCKET_SIZE];
|
|
||||||
/* Truncated hash used for quick rejection of "distance cache" candidates. */
|
|
||||||
uint8_t tiny_hash[65536];
|
|
||||||
FN(Bank) banks[NUM_BANKS];
|
|
||||||
uint16_t free_slot_idx[NUM_BANKS];
|
|
||||||
size_t max_hops;
|
size_t max_hops;
|
||||||
|
|
||||||
|
/* Shortcuts. */
|
||||||
|
void* extra;
|
||||||
|
HasherCommon* common;
|
||||||
|
|
||||||
|
/* --- Dynamic size members --- */
|
||||||
|
|
||||||
|
/* uint32_t addr[BUCKET_SIZE]; */
|
||||||
|
|
||||||
|
/* uint16_t head[BUCKET_SIZE]; */
|
||||||
|
|
||||||
|
/* Truncated hash used for quick rejection of "distance cache" candidates. */
|
||||||
|
/* uint8_t tiny_hash[65536];*/
|
||||||
|
|
||||||
|
/* FN(Bank) banks[NUM_BANKS]; */
|
||||||
} HashForgetfulChain;
|
} HashForgetfulChain;
|
||||||
|
|
||||||
static BROTLI_INLINE HashForgetfulChain* FN(Self)(HasherHandle handle) {
|
static uint32_t* FN(Addr)(void* extra) {
|
||||||
return (HashForgetfulChain*)&(GetHasherCommon(handle)[1]);
|
return (uint32_t*)extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t* FN(Head)(void* extra) {
|
||||||
|
return (uint16_t*)(&FN(Addr)(extra)[BUCKET_SIZE]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t* FN(TinyHash)(void* extra) {
|
||||||
|
return (uint8_t*)(&FN(Head)(extra)[BUCKET_SIZE]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FN(Bank)* FN(Banks)(void* extra) {
|
||||||
|
return (FN(Bank)*)(&FN(TinyHash)(extra)[65536]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FN(Initialize)(
|
static void FN(Initialize)(
|
||||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self,
|
||||||
FN(Self)(handle)->max_hops =
|
const BrotliEncoderParams* params) {
|
||||||
(params->quality > 6 ? 7u : 8u) << (params->quality - 4);
|
self->common = common;
|
||||||
|
self->extra = common->extra;
|
||||||
|
|
||||||
|
self->max_hops = (params->quality > 6 ? 7u : 8u) << (params->quality - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
static void FN(Prepare)(
|
||||||
size_t input_size, const uint8_t* data) {
|
HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||||
HashForgetfulChain* self = FN(Self)(handle);
|
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||||
|
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
|
||||||
|
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
|
||||||
|
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
|
||||||
/* Partial preparation is 100 times slower (per socket). */
|
/* Partial preparation is 100 times slower (per socket). */
|
||||||
size_t partial_prepare_threshold = BUCKET_SIZE >> 6;
|
size_t partial_prepare_threshold = BUCKET_SIZE >> 6;
|
||||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||||
|
@ -74,17 +102,17 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||||
for (i = 0; i < input_size; ++i) {
|
for (i = 0; i < input_size; ++i) {
|
||||||
size_t bucket = FN(HashBytes)(&data[i]);
|
size_t bucket = FN(HashBytes)(&data[i]);
|
||||||
/* See InitEmpty comment. */
|
/* See InitEmpty comment. */
|
||||||
self->addr[bucket] = 0xCCCCCCCC;
|
addr[bucket] = 0xCCCCCCCC;
|
||||||
self->head[bucket] = 0xCCCC;
|
head[bucket] = 0xCCCC;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
|
/* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
|
||||||
processed by hasher never reaches 3GB + 64M; this makes all new chains
|
processed by hasher never reaches 3GB + 64M; this makes all new chains
|
||||||
to be terminated after the first node. */
|
to be terminated after the first node. */
|
||||||
memset(self->addr, 0xCC, sizeof(self->addr));
|
memset(addr, 0xCC, sizeof(uint32_t) * BUCKET_SIZE);
|
||||||
memset(self->head, 0, sizeof(self->head));
|
memset(head, 0, sizeof(uint16_t) * BUCKET_SIZE);
|
||||||
}
|
}
|
||||||
memset(self->tiny_hash, 0, sizeof(self->tiny_hash));
|
memset(tiny_hash, 0, sizeof(uint8_t) * 65536);
|
||||||
memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx));
|
memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,51 +122,58 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||||
BROTLI_UNUSED(params);
|
BROTLI_UNUSED(params);
|
||||||
BROTLI_UNUSED(one_shot);
|
BROTLI_UNUSED(one_shot);
|
||||||
BROTLI_UNUSED(input_size);
|
BROTLI_UNUSED(input_size);
|
||||||
return sizeof(HashForgetfulChain);
|
return sizeof(uint32_t) * BUCKET_SIZE + sizeof(uint16_t) * BUCKET_SIZE +
|
||||||
|
sizeof(uint8_t) * 65536 + sizeof(FN(Bank)) * NUM_BANKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
|
/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
|
||||||
node to corresponding chain; also update tiny_hash for current position. */
|
node to corresponding chain; also update tiny_hash for current position. */
|
||||||
static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
|
static BROTLI_INLINE void FN(Store)(HashForgetfulChain* BROTLI_RESTRICT self,
|
||||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
||||||
HashForgetfulChain* self = FN(Self)(handle);
|
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
|
||||||
|
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
|
||||||
|
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
|
||||||
|
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
|
||||||
const size_t key = FN(HashBytes)(&data[ix & mask]);
|
const size_t key = FN(HashBytes)(&data[ix & mask]);
|
||||||
const size_t bank = key & (NUM_BANKS - 1);
|
const size_t bank = key & (NUM_BANKS - 1);
|
||||||
const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1);
|
const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1);
|
||||||
size_t delta = ix - self->addr[key];
|
size_t delta = ix - addr[key];
|
||||||
self->tiny_hash[(uint16_t)ix] = (uint8_t)key;
|
tiny_hash[(uint16_t)ix] = (uint8_t)key;
|
||||||
if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF;
|
if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF;
|
||||||
self->banks[bank].slots[idx].delta = (uint16_t)delta;
|
banks[bank].slots[idx].delta = (uint16_t)delta;
|
||||||
self->banks[bank].slots[idx].next = self->head[key];
|
banks[bank].slots[idx].next = head[key];
|
||||||
self->addr[key] = (uint32_t)ix;
|
addr[key] = (uint32_t)ix;
|
||||||
self->head[key] = (uint16_t)idx;
|
head[key] = (uint16_t)idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
static BROTLI_INLINE void FN(StoreRange)(
|
||||||
const uint8_t *data, const size_t mask, const size_t ix_start,
|
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||||
const size_t ix_end) {
|
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||||
|
const size_t ix_start, const size_t ix_end) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = ix_start; i < ix_end; ++i) {
|
for (i = ix_start; i < ix_end; ++i) {
|
||||||
FN(Store)(handle, data, mask, i);
|
FN(Store)(self, data, mask, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||||
|
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||||
size_t ring_buffer_mask) {
|
size_t ring_buffer_mask) {
|
||||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||||
/* Prepare the hashes for three last bytes of the last write.
|
/* Prepare the hashes for three last bytes of the last write.
|
||||||
These could not be calculated before, since they require knowledge
|
These could not be calculated before, since they require knowledge
|
||||||
of both the previous and the current block. */
|
of both the previous and the current block. */
|
||||||
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 3);
|
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 3);
|
||||||
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 2);
|
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 2);
|
||||||
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 1);
|
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||||
BROTLI_UNUSED(handle);
|
int* BROTLI_RESTRICT distance_cache) {
|
||||||
|
BROTLI_UNUSED(self);
|
||||||
PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK);
|
PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,13 +188,18 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||||
Does not look for matches further away than max_backward.
|
Does not look for matches further away than max_backward.
|
||||||
Writes the best match into |out|.
|
Writes the best match into |out|.
|
||||||
|out|->score is updated only if a better match is found. */
|
|out|->score is updated only if a better match is found. */
|
||||||
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||||
const BrotliDictionary* dictionary, const uint16_t* dictionary_hash,
|
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||||
|
const BrotliEncoderDictionary* dictionary,
|
||||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||||
const int* BROTLI_RESTRICT distance_cache,
|
const int* BROTLI_RESTRICT distance_cache,
|
||||||
const size_t cur_ix, const size_t max_length, const size_t max_backward,
|
const size_t cur_ix, const size_t max_length, const size_t max_backward,
|
||||||
const size_t gap, HasherSearchResult* BROTLI_RESTRICT out) {
|
const size_t dictionary_distance, const size_t max_distance,
|
||||||
HashForgetfulChain* self = FN(Self)(handle);
|
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||||
|
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
|
||||||
|
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
|
||||||
|
uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra);
|
||||||
|
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
|
||||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||||
/* Don't accept a short copy from far away. */
|
/* Don't accept a short copy from far away. */
|
||||||
score_t min_score = out->score;
|
score_t min_score = out->score;
|
||||||
|
@ -175,7 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||||
const size_t backward = (size_t)distance_cache[i];
|
const size_t backward = (size_t)distance_cache[i];
|
||||||
size_t prev_ix = (cur_ix - backward);
|
size_t prev_ix = (cur_ix - backward);
|
||||||
/* For distance code 0 we want to consider 2-byte matches. */
|
/* For distance code 0 we want to consider 2-byte matches. */
|
||||||
if (i > 0 && self->tiny_hash[(uint16_t)prev_ix] != tiny_hash) continue;
|
if (i > 0 && tiny_hashes[(uint16_t)prev_ix] != tiny_hash) continue;
|
||||||
if (prev_ix >= cur_ix || backward > max_backward) {
|
if (prev_ix >= cur_ix || backward > max_backward) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -203,16 +243,16 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||||
const size_t bank = key & (NUM_BANKS - 1);
|
const size_t bank = key & (NUM_BANKS - 1);
|
||||||
size_t backward = 0;
|
size_t backward = 0;
|
||||||
size_t hops = self->max_hops;
|
size_t hops = self->max_hops;
|
||||||
size_t delta = cur_ix - self->addr[key];
|
size_t delta = cur_ix - addr[key];
|
||||||
size_t slot = self->head[key];
|
size_t slot = head[key];
|
||||||
while (hops--) {
|
while (hops--) {
|
||||||
size_t prev_ix;
|
size_t prev_ix;
|
||||||
size_t last = slot;
|
size_t last = slot;
|
||||||
backward += delta;
|
backward += delta;
|
||||||
if (backward > max_backward || (CAPPED_CHAINS && !delta)) break;
|
if (backward > max_backward || (CAPPED_CHAINS && !delta)) break;
|
||||||
prev_ix = (cur_ix - backward) & ring_buffer_mask;
|
prev_ix = (cur_ix - backward) & ring_buffer_mask;
|
||||||
slot = self->banks[bank].slots[last].next;
|
slot = banks[bank].slots[last].next;
|
||||||
delta = self->banks[bank].slots[last].delta;
|
delta = banks[bank].slots[last].delta;
|
||||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||||
prev_ix + best_len > ring_buffer_mask ||
|
prev_ix + best_len > ring_buffer_mask ||
|
||||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||||
|
@ -237,12 +277,12 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FN(Store)(handle, data, ring_buffer_mask, cur_ix);
|
FN(Store)(self, data, ring_buffer_mask, cur_ix);
|
||||||
}
|
}
|
||||||
if (out->score == min_score) {
|
if (out->score == min_score) {
|
||||||
SearchInStaticDictionary(dictionary, dictionary_hash,
|
SearchInStaticDictionary(dictionary,
|
||||||
handle, &data[cur_ix_masked], max_length, max_backward + gap, out,
|
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||||
BROTLI_FALSE);
|
max_distance, out, BROTLI_FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
|
||||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
||||||
|
|
||||||
/* HashBytes is the function that chooses the bucket to place the address in. */
|
/* HashBytes is the function that chooses the bucket to place the address in. */
|
||||||
static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t *data,
|
static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
|
||||||
const uint64_t mask,
|
const uint64_t mask,
|
||||||
const int shift) {
|
const int shift) {
|
||||||
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long;
|
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long;
|
||||||
|
@ -42,43 +42,43 @@ typedef struct HashLongestMatch {
|
||||||
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
||||||
uint32_t block_mask_;
|
uint32_t block_mask_;
|
||||||
|
|
||||||
|
int block_bits_;
|
||||||
|
int num_last_distances_to_check_;
|
||||||
|
|
||||||
|
/* Shortcuts. */
|
||||||
|
HasherCommon* common_;
|
||||||
|
|
||||||
/* --- Dynamic size members --- */
|
/* --- Dynamic size members --- */
|
||||||
|
|
||||||
/* Number of entries in a particular bucket. */
|
/* Number of entries in a particular bucket. */
|
||||||
/* uint16_t num[bucket_size]; */
|
uint16_t* num_; /* uint16_t[bucket_size]; */
|
||||||
|
|
||||||
/* Buckets containing block_size_ of backward references. */
|
/* Buckets containing block_size_ of backward references. */
|
||||||
/* uint32_t* buckets[bucket_size * block_size]; */
|
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||||
} HashLongestMatch;
|
} HashLongestMatch;
|
||||||
|
|
||||||
static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) {
|
|
||||||
return (HashLongestMatch*)&(GetHasherCommon(handle)[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) {
|
|
||||||
return (uint16_t*)(&self[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) {
|
|
||||||
return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FN(Initialize)(
|
static void FN(Initialize)(
|
||||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||||
HasherCommon* common = GetHasherCommon(handle);
|
const BrotliEncoderParams* params) {
|
||||||
HashLongestMatch* self = FN(Self)(handle);
|
self->common_ = common;
|
||||||
|
|
||||||
BROTLI_UNUSED(params);
|
BROTLI_UNUSED(params);
|
||||||
self->hash_shift_ = 64 - common->params.bucket_bits;
|
self->hash_shift_ = 64 - common->params.bucket_bits;
|
||||||
self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
|
self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
|
||||||
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
||||||
|
self->block_bits_ = common->params.block_bits;
|
||||||
self->block_size_ = (size_t)1 << common->params.block_bits;
|
self->block_size_ = (size_t)1 << common->params.block_bits;
|
||||||
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
||||||
|
self->num_last_distances_to_check_ =
|
||||||
|
common->params.num_last_distances_to_check;
|
||||||
|
self->num_ = (uint16_t*)common->extra;
|
||||||
|
self->buckets_ = (uint32_t*)&self->num_[self->bucket_size_];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
static void FN(Prepare)(
|
||||||
size_t input_size, const uint8_t* data) {
|
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||||
HashLongestMatch* self = FN(Self)(handle);
|
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||||
uint16_t* num = FN(Num)(self);
|
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||||
/* Partial preparation is 100 times slower (per socket). */
|
/* Partial preparation is 100 times slower (per socket). */
|
||||||
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
||||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||||
|
@ -100,50 +100,52 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||||
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
||||||
BROTLI_UNUSED(one_shot);
|
BROTLI_UNUSED(one_shot);
|
||||||
BROTLI_UNUSED(input_size);
|
BROTLI_UNUSED(input_size);
|
||||||
return sizeof(HashLongestMatch) + bucket_size * (2 + 4 * block_size);
|
return sizeof(uint16_t) * bucket_size +
|
||||||
|
sizeof(uint32_t) * bucket_size * block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look at 4 bytes at &data[ix & mask].
|
/* Look at 4 bytes at &data[ix & mask].
|
||||||
Compute a hash from these, and store the value of ix at that position. */
|
Compute a hash from these, and store the value of ix at that position. */
|
||||||
static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t *data,
|
static BROTLI_INLINE void FN(Store)(
|
||||||
|
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||||
const size_t mask, const size_t ix) {
|
const size_t mask, const size_t ix) {
|
||||||
HashLongestMatch* self = FN(Self)(handle);
|
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||||
uint16_t* num = FN(Num)(self);
|
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||||
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
|
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
|
||||||
self->hash_shift_);
|
self->hash_shift_);
|
||||||
const size_t minor_ix = num[key] & self->block_mask_;
|
const size_t minor_ix = num[key] & self->block_mask_;
|
||||||
const size_t offset =
|
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||||
minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
|
|
||||||
FN(Buckets)(self)[offset] = (uint32_t)ix;
|
|
||||||
++num[key];
|
++num[key];
|
||||||
|
buckets[offset] = (uint32_t)ix;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||||
const uint8_t *data, const size_t mask, const size_t ix_start,
|
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||||
const size_t ix_end) {
|
const size_t ix_start, const size_t ix_end) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = ix_start; i < ix_end; ++i) {
|
for (i = ix_start; i < ix_end; ++i) {
|
||||||
FN(Store)(handle, data, mask, i);
|
FN(Store)(self, data, mask, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||||
|
HashLongestMatch* BROTLI_RESTRICT self,
|
||||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||||
size_t ringbuffer_mask) {
|
size_t ringbuffer_mask) {
|
||||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||||
/* Prepare the hashes for three last bytes of the last write.
|
/* Prepare the hashes for three last bytes of the last write.
|
||||||
These could not be calculated before, since they require knowledge
|
These could not be calculated before, since they require knowledge
|
||||||
of both the previous and the current block. */
|
of both the previous and the current block. */
|
||||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
|
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
|
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
|
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
HashLongestMatch* BROTLI_RESTRICT self,
|
||||||
PrepareDistanceCache(distance_cache,
|
int* BROTLI_RESTRICT distance_cache) {
|
||||||
GetHasherCommon(handle)->params.num_last_distances_to_check);
|
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find a longest backward match of &data[cur_ix] up to the length of
|
/* Find a longest backward match of &data[cur_ix] up to the length of
|
||||||
|
@ -157,16 +159,16 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||||
Does not look for matches further away than max_backward.
|
Does not look for matches further away than max_backward.
|
||||||
Writes the best match into |out|.
|
Writes the best match into |out|.
|
||||||
|out|->score is updated only if a better match is found. */
|
|out|->score is updated only if a better match is found. */
|
||||||
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||||
const BrotliDictionary* dictionary, const uint16_t* dictionary_hash,
|
HashLongestMatch* BROTLI_RESTRICT self,
|
||||||
|
const BrotliEncoderDictionary* dictionary,
|
||||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||||
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
||||||
const size_t max_length, const size_t max_backward, const size_t gap,
|
const size_t max_length, const size_t max_backward,
|
||||||
|
const size_t dictionary_distance, const size_t max_distance,
|
||||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||||
HasherCommon* common = GetHasherCommon(handle);
|
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||||
HashLongestMatch* self = FN(Self)(handle);
|
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||||
uint16_t* num = FN(Num)(self);
|
|
||||||
uint32_t* buckets = FN(Buckets)(self);
|
|
||||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||||
/* Don't accept a short copy from far away. */
|
/* Don't accept a short copy from far away. */
|
||||||
score_t min_score = out->score;
|
score_t min_score = out->score;
|
||||||
|
@ -176,7 +178,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||||
out->len = 0;
|
out->len = 0;
|
||||||
out->len_code_delta = 0;
|
out->len_code_delta = 0;
|
||||||
/* Try last distance first. */
|
/* Try last distance first. */
|
||||||
for (i = 0; i < (size_t)common->params.num_last_distances_to_check; ++i) {
|
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
||||||
const size_t backward = (size_t)distance_cache[i];
|
const size_t backward = (size_t)distance_cache[i];
|
||||||
size_t prev_ix = (size_t)(cur_ix - backward);
|
size_t prev_ix = (size_t)(cur_ix - backward);
|
||||||
if (prev_ix >= cur_ix) {
|
if (prev_ix >= cur_ix) {
|
||||||
|
@ -217,8 +219,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||||
{
|
{
|
||||||
const uint32_t key = FN(HashBytes)(
|
const uint32_t key = FN(HashBytes)(
|
||||||
&data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
|
&data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
|
||||||
uint32_t* BROTLI_RESTRICT bucket =
|
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||||
&buckets[key << common->params.block_bits];
|
|
||||||
const size_t down =
|
const size_t down =
|
||||||
(num[key] > self->block_size_) ?
|
(num[key] > self->block_size_) ?
|
||||||
(num[key] - self->block_size_) : 0u;
|
(num[key] - self->block_size_) : 0u;
|
||||||
|
@ -257,9 +258,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||||
++num[key];
|
++num[key];
|
||||||
}
|
}
|
||||||
if (min_score == out->score) {
|
if (min_score == out->score) {
|
||||||
SearchInStaticDictionary(dictionary, dictionary_hash,
|
SearchInStaticDictionary(dictionary,
|
||||||
handle, &data[cur_ix_masked], max_length, max_backward + gap, out,
|
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||||
BROTLI_FALSE);
|
max_distance, out, BROTLI_FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,9 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
|
||||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
|
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
|
||||||
|
|
||||||
/* HashBytes is the function that chooses the bucket to place the address in. */
|
/* HashBytes is the function that chooses the bucket to place the address in. */
|
||||||
static uint32_t FN(HashBytes)(const uint8_t *data, const int shift) {
|
static uint32_t FN(HashBytes)(
|
||||||
uint32_t h = BROTLI_UNALIGNED_LOAD32(data) * kHashMul32;
|
const uint8_t* BROTLI_RESTRICT data, const int shift) {
|
||||||
|
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||||
/* The higher bits contain more mixture from the multiplication,
|
/* The higher bits contain more mixture from the multiplication,
|
||||||
so we take our results from there. */
|
so we take our results from there. */
|
||||||
return (uint32_t)(h >> shift);
|
return (uint32_t)(h >> shift);
|
||||||
|
@ -38,42 +39,46 @@ typedef struct HashLongestMatch {
|
||||||
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
||||||
uint32_t block_mask_;
|
uint32_t block_mask_;
|
||||||
|
|
||||||
|
int block_bits_;
|
||||||
|
int num_last_distances_to_check_;
|
||||||
|
|
||||||
|
/* Shortcuts. */
|
||||||
|
HasherCommon* common_;
|
||||||
|
|
||||||
/* --- Dynamic size members --- */
|
/* --- Dynamic size members --- */
|
||||||
|
|
||||||
/* Number of entries in a particular bucket. */
|
/* Number of entries in a particular bucket. */
|
||||||
/* uint16_t num[bucket_size]; */
|
uint16_t* num_; /* uint16_t[bucket_size]; */
|
||||||
|
|
||||||
/* Buckets containing block_size_ of backward references. */
|
/* Buckets containing block_size_ of backward references. */
|
||||||
/* uint32_t* buckets[bucket_size * block_size]; */
|
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||||
} HashLongestMatch;
|
} HashLongestMatch;
|
||||||
|
|
||||||
static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) {
|
static BROTLI_INLINE uint16_t* FN(Num)(void* extra) {
|
||||||
return (HashLongestMatch*)&(GetHasherCommon(handle)[1]);
|
return (uint16_t*)extra;
|
||||||
}
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) {
|
|
||||||
return (uint16_t*)(&self[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) {
|
|
||||||
return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FN(Initialize)(
|
static void FN(Initialize)(
|
||||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||||
HasherCommon* common = GetHasherCommon(handle);
|
const BrotliEncoderParams* params) {
|
||||||
HashLongestMatch* self = FN(Self)(handle);
|
self->common_ = common;
|
||||||
|
|
||||||
BROTLI_UNUSED(params);
|
BROTLI_UNUSED(params);
|
||||||
self->hash_shift_ = 32 - common->params.bucket_bits;
|
self->hash_shift_ = 32 - common->params.bucket_bits;
|
||||||
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
||||||
self->block_size_ = (size_t)1 << common->params.block_bits;
|
self->block_size_ = (size_t)1 << common->params.block_bits;
|
||||||
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
||||||
|
self->num_ = (uint16_t*)common->extra;
|
||||||
|
self->buckets_ = (uint32_t*)(&self->num_[self->bucket_size_]);
|
||||||
|
self->block_bits_ = common->params.block_bits;
|
||||||
|
self->num_last_distances_to_check_ =
|
||||||
|
common->params.num_last_distances_to_check;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
static void FN(Prepare)(
|
||||||
size_t input_size, const uint8_t* data) {
|
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||||
HashLongestMatch* self = FN(Self)(handle);
|
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||||
uint16_t* num = FN(Num)(self);
|
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||||
/* Partial preparation is 100 times slower (per socket). */
|
/* Partial preparation is 100 times slower (per socket). */
|
||||||
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
||||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||||
|
@ -94,49 +99,49 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||||
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
||||||
BROTLI_UNUSED(one_shot);
|
BROTLI_UNUSED(one_shot);
|
||||||
BROTLI_UNUSED(input_size);
|
BROTLI_UNUSED(input_size);
|
||||||
return sizeof(HashLongestMatch) + bucket_size * (2 + 4 * block_size);
|
return sizeof(uint16_t) * bucket_size +
|
||||||
|
sizeof(uint32_t) * bucket_size * block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look at 4 bytes at &data[ix & mask].
|
/* Look at 4 bytes at &data[ix & mask].
|
||||||
Compute a hash from these, and store the value of ix at that position. */
|
Compute a hash from these, and store the value of ix at that position. */
|
||||||
static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t* data,
|
static BROTLI_INLINE void FN(Store)(
|
||||||
|
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||||
const size_t mask, const size_t ix) {
|
const size_t mask, const size_t ix) {
|
||||||
HashLongestMatch* self = FN(Self)(handle);
|
|
||||||
uint16_t* num = FN(Num)(self);
|
|
||||||
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
|
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
|
||||||
const size_t minor_ix = num[key] & self->block_mask_;
|
const size_t minor_ix = self->num_[key] & self->block_mask_;
|
||||||
const size_t offset =
|
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||||
minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
|
self->buckets_[offset] = (uint32_t)ix;
|
||||||
FN(Buckets)(self)[offset] = (uint32_t)ix;
|
++self->num_[key];
|
||||||
++num[key];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||||
const uint8_t *data, const size_t mask, const size_t ix_start,
|
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||||
const size_t ix_end) {
|
const size_t ix_start, const size_t ix_end) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = ix_start; i < ix_end; ++i) {
|
for (i = ix_start; i < ix_end; ++i) {
|
||||||
FN(Store)(handle, data, mask, i);
|
FN(Store)(self, data, mask, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||||
|
HashLongestMatch* BROTLI_RESTRICT self,
|
||||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||||
size_t ringbuffer_mask) {
|
size_t ringbuffer_mask) {
|
||||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||||
/* Prepare the hashes for three last bytes of the last write.
|
/* Prepare the hashes for three last bytes of the last write.
|
||||||
These could not be calculated before, since they require knowledge
|
These could not be calculated before, since they require knowledge
|
||||||
of both the previous and the current block. */
|
of both the previous and the current block. */
|
||||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
|
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
|
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
|
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
HashLongestMatch* BROTLI_RESTRICT self,
|
||||||
PrepareDistanceCache(distance_cache,
|
int* BROTLI_RESTRICT distance_cache) {
|
||||||
GetHasherCommon(handle)->params.num_last_distances_to_check);
|
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find a longest backward match of &data[cur_ix] up to the length of
|
/* Find a longest backward match of &data[cur_ix] up to the length of
|
||||||
|
@ -150,16 +155,16 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||||
Does not look for matches further away than max_backward.
|
Does not look for matches further away than max_backward.
|
||||||
Writes the best match into |out|.
|
Writes the best match into |out|.
|
||||||
|out|->score is updated only if a better match is found. */
|
|out|->score is updated only if a better match is found. */
|
||||||
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||||
const BrotliDictionary* dictionary, const uint16_t* dictionary_hash,
|
HashLongestMatch* BROTLI_RESTRICT self,
|
||||||
|
const BrotliEncoderDictionary* dictionary,
|
||||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||||
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
||||||
const size_t max_length, const size_t max_backward, const size_t gap,
|
const size_t max_length, const size_t max_backward,
|
||||||
|
const size_t dictionary_distance, const size_t max_distance,
|
||||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||||
HasherCommon* common = GetHasherCommon(handle);
|
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||||
HashLongestMatch* self = FN(Self)(handle);
|
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||||
uint16_t* num = FN(Num)(self);
|
|
||||||
uint32_t* buckets = FN(Buckets)(self);
|
|
||||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||||
/* Don't accept a short copy from far away. */
|
/* Don't accept a short copy from far away. */
|
||||||
score_t min_score = out->score;
|
score_t min_score = out->score;
|
||||||
|
@ -169,7 +174,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||||
out->len = 0;
|
out->len = 0;
|
||||||
out->len_code_delta = 0;
|
out->len_code_delta = 0;
|
||||||
/* Try last distance first. */
|
/* Try last distance first. */
|
||||||
for (i = 0; i < (size_t)common->params.num_last_distances_to_check; ++i) {
|
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
||||||
const size_t backward = (size_t)distance_cache[i];
|
const size_t backward = (size_t)distance_cache[i];
|
||||||
size_t prev_ix = (size_t)(cur_ix - backward);
|
size_t prev_ix = (size_t)(cur_ix - backward);
|
||||||
if (prev_ix >= cur_ix) {
|
if (prev_ix >= cur_ix) {
|
||||||
|
@ -210,8 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||||
{
|
{
|
||||||
const uint32_t key =
|
const uint32_t key =
|
||||||
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
||||||
uint32_t* BROTLI_RESTRICT bucket =
|
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||||
&buckets[key << common->params.block_bits];
|
|
||||||
const size_t down =
|
const size_t down =
|
||||||
(num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
|
(num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
|
||||||
for (i = num[key]; i > down;) {
|
for (i = num[key]; i > down;) {
|
||||||
|
@ -249,9 +253,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||||
++num[key];
|
++num[key];
|
||||||
}
|
}
|
||||||
if (min_score == out->score) {
|
if (min_score == out->score) {
|
||||||
SearchInStaticDictionary(dictionary, dictionary_hash,
|
SearchInStaticDictionary(dictionary,
|
||||||
handle, &data[cur_ix_masked], max_length, max_backward + gap, out,
|
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||||
BROTLI_FALSE);
|
max_distance, out, BROTLI_FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,15 +5,16 @@
|
||||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP, HASH_LEN,
|
/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP_BITS, HASH_LEN,
|
||||||
USE_DICTIONARY
|
USE_DICTIONARY
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define HashLongestMatchQuickly HASHER()
|
#define HashLongestMatchQuickly HASHER()
|
||||||
|
|
||||||
#define BUCKET_SIZE (1 << BUCKET_BITS)
|
#define BUCKET_SIZE (1 << BUCKET_BITS)
|
||||||
|
#define BUCKET_MASK (BUCKET_SIZE - 1)
|
||||||
#define HASH_MAP_SIZE (4 << BUCKET_BITS)
|
#define BUCKET_SWEEP (1 << BUCKET_SWEEP_BITS)
|
||||||
|
#define BUCKET_SWEEP_MASK ((BUCKET_SWEEP - 1) << 3)
|
||||||
|
|
||||||
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
|
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
|
||||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
||||||
|
@ -32,39 +33,50 @@ static uint32_t FN(HashBytes)(const uint8_t* data) {
|
||||||
/* A (forgetful) hash table to the data seen by the compressor, to
|
/* A (forgetful) hash table to the data seen by the compressor, to
|
||||||
help create backward references to previous data.
|
help create backward references to previous data.
|
||||||
|
|
||||||
This is a hash map of fixed size (BUCKET_SIZE). Starting from the
|
This is a hash map of fixed size (BUCKET_SIZE). */
|
||||||
given index, BUCKET_SWEEP buckets are used to store values of a key. */
|
|
||||||
typedef struct HashLongestMatchQuickly {
|
typedef struct HashLongestMatchQuickly {
|
||||||
uint32_t buckets_[BUCKET_SIZE + BUCKET_SWEEP];
|
/* Shortcuts. */
|
||||||
|
HasherCommon* common;
|
||||||
|
|
||||||
|
/* --- Dynamic size members --- */
|
||||||
|
|
||||||
|
uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
|
||||||
} HashLongestMatchQuickly;
|
} HashLongestMatchQuickly;
|
||||||
|
|
||||||
static BROTLI_INLINE HashLongestMatchQuickly* FN(Self)(HasherHandle handle) {
|
|
||||||
return (HashLongestMatchQuickly*)&(GetHasherCommon(handle)[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FN(Initialize)(
|
static void FN(Initialize)(
|
||||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
HasherCommon* common, HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||||
BROTLI_UNUSED(handle);
|
const BrotliEncoderParams* params) {
|
||||||
|
self->common = common;
|
||||||
|
|
||||||
BROTLI_UNUSED(params);
|
BROTLI_UNUSED(params);
|
||||||
|
self->buckets_ = (uint32_t*)common->extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
static void FN(Prepare)(
|
||||||
size_t input_size, const uint8_t* data) {
|
HashLongestMatchQuickly* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||||
HashLongestMatchQuickly* self = FN(Self)(handle);
|
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||||
|
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||||
/* Partial preparation is 100 times slower (per socket). */
|
/* Partial preparation is 100 times slower (per socket). */
|
||||||
size_t partial_prepare_threshold = HASH_MAP_SIZE >> 7;
|
size_t partial_prepare_threshold = BUCKET_SIZE >> 5;
|
||||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < input_size; ++i) {
|
for (i = 0; i < input_size; ++i) {
|
||||||
const uint32_t key = FN(HashBytes)(&data[i]);
|
const uint32_t key = FN(HashBytes)(&data[i]);
|
||||||
memset(&self->buckets_[key], 0, BUCKET_SWEEP * sizeof(self->buckets_[0]));
|
if (BUCKET_SWEEP == 1) {
|
||||||
|
buckets[key] = 0;
|
||||||
|
} else {
|
||||||
|
uint32_t j;
|
||||||
|
for (j = 0; j < BUCKET_SWEEP; ++j) {
|
||||||
|
buckets[(key + (j << 3)) & BUCKET_MASK] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* It is not strictly necessary to fill this buffer here, but
|
/* It is not strictly necessary to fill this buffer here, but
|
||||||
not filling will make the results of the compression stochastic
|
not filling will make the results of the compression stochastic
|
||||||
(but correct). This is because random data would cause the
|
(but correct). This is because random data would cause the
|
||||||
system to find accidentally good backward references here and there. */
|
system to find accidentally good backward references here and there. */
|
||||||
memset(&self->buckets_[0], 0, sizeof(self->buckets_));
|
memset(buckets, 0, sizeof(uint32_t) * BUCKET_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,45 +86,53 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||||
BROTLI_UNUSED(params);
|
BROTLI_UNUSED(params);
|
||||||
BROTLI_UNUSED(one_shot);
|
BROTLI_UNUSED(one_shot);
|
||||||
BROTLI_UNUSED(input_size);
|
BROTLI_UNUSED(input_size);
|
||||||
return sizeof(HashLongestMatchQuickly);
|
return sizeof(uint32_t) * BUCKET_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look at 5 bytes at &data[ix & mask].
|
/* Look at 5 bytes at &data[ix & mask].
|
||||||
Compute a hash from these, and store the value somewhere within
|
Compute a hash from these, and store the value somewhere within
|
||||||
[ix .. ix+3]. */
|
[ix .. ix+3]. */
|
||||||
static BROTLI_INLINE void FN(Store)(HasherHandle handle,
|
static BROTLI_INLINE void FN(Store)(
|
||||||
const uint8_t *data, const size_t mask, const size_t ix) {
|
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||||
|
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
||||||
const uint32_t key = FN(HashBytes)(&data[ix & mask]);
|
const uint32_t key = FN(HashBytes)(&data[ix & mask]);
|
||||||
/* Wiggle the value with the bucket sweep range. */
|
if (BUCKET_SWEEP == 1) {
|
||||||
const uint32_t off = (ix >> 3) % BUCKET_SWEEP;
|
self->buckets_[key] = (uint32_t)ix;
|
||||||
FN(Self)(handle)->buckets_[key + off] = (uint32_t)ix;
|
} else {
|
||||||
|
/* Wiggle the value with the bucket sweep range. */
|
||||||
|
const uint32_t off = ix & BUCKET_SWEEP_MASK;
|
||||||
|
self->buckets_[(key + off) & BUCKET_MASK] = (uint32_t)ix;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
static BROTLI_INLINE void FN(StoreRange)(
|
||||||
const uint8_t *data, const size_t mask, const size_t ix_start,
|
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||||
const size_t ix_end) {
|
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||||
|
const size_t ix_start, const size_t ix_end) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = ix_start; i < ix_end; ++i) {
|
for (i = ix_start; i < ix_end; ++i) {
|
||||||
FN(Store)(handle, data, mask, i);
|
FN(Store)(self, data, mask, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||||
HasherHandle handle, size_t num_bytes, size_t position,
|
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||||
|
size_t num_bytes, size_t position,
|
||||||
const uint8_t* ringbuffer, size_t ringbuffer_mask) {
|
const uint8_t* ringbuffer, size_t ringbuffer_mask) {
|
||||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||||
/* Prepare the hashes for three last bytes of the last write.
|
/* Prepare the hashes for three last bytes of the last write.
|
||||||
These could not be calculated before, since they require knowledge
|
These could not be calculated before, since they require knowledge
|
||||||
of both the previous and the current block. */
|
of both the previous and the current block. */
|
||||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
|
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
|
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
|
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||||
BROTLI_UNUSED(handle);
|
int* BROTLI_RESTRICT distance_cache) {
|
||||||
|
BROTLI_UNUSED(self);
|
||||||
BROTLI_UNUSED(distance_cache);
|
BROTLI_UNUSED(distance_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,16 +145,19 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||||
Writes the best match into |out|.
|
Writes the best match into |out|.
|
||||||
|out|->score is updated only if a better match is found. */
|
|out|->score is updated only if a better match is found. */
|
||||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||||
HasherHandle handle, const BrotliDictionary* dictionary,
|
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||||
const uint16_t* dictionary_hash, const uint8_t* BROTLI_RESTRICT data,
|
const BrotliEncoderDictionary* dictionary,
|
||||||
|
const uint8_t* BROTLI_RESTRICT data,
|
||||||
const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
|
const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
|
||||||
const size_t cur_ix, const size_t max_length, const size_t max_backward,
|
const size_t cur_ix, const size_t max_length, const size_t max_backward,
|
||||||
const size_t gap, HasherSearchResult* BROTLI_RESTRICT out) {
|
const size_t dictionary_distance, const size_t max_distance,
|
||||||
HashLongestMatchQuickly* self = FN(Self)(handle);
|
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||||
|
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||||
const size_t best_len_in = out->len;
|
const size_t best_len_in = out->len;
|
||||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||||
const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
|
||||||
int compare_char = data[cur_ix_masked + best_len_in];
|
int compare_char = data[cur_ix_masked + best_len_in];
|
||||||
|
size_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
||||||
|
size_t key_out;
|
||||||
score_t min_score = out->score;
|
score_t min_score = out->score;
|
||||||
score_t best_score = out->score;
|
score_t best_score = out->score;
|
||||||
size_t best_len = best_len_in;
|
size_t best_len = best_len_in;
|
||||||
|
@ -144,21 +167,21 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||||
if (prev_ix < cur_ix) {
|
if (prev_ix < cur_ix) {
|
||||||
prev_ix &= (uint32_t)ring_buffer_mask;
|
prev_ix &= (uint32_t)ring_buffer_mask;
|
||||||
if (compare_char == data[prev_ix + best_len]) {
|
if (compare_char == data[prev_ix + best_len]) {
|
||||||
size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
const size_t len = FindMatchLengthWithLimit(
|
||||||
&data[cur_ix_masked],
|
&data[prev_ix], &data[cur_ix_masked], max_length);
|
||||||
max_length);
|
|
||||||
if (len >= 4) {
|
if (len >= 4) {
|
||||||
const score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
const score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
||||||
if (best_score < score) {
|
if (best_score < score) {
|
||||||
best_score = score;
|
|
||||||
best_len = len;
|
|
||||||
out->len = len;
|
out->len = len;
|
||||||
out->distance = cached_backward;
|
out->distance = cached_backward;
|
||||||
out->score = best_score;
|
out->score = score;
|
||||||
compare_char = data[cur_ix_masked + best_len];
|
|
||||||
if (BUCKET_SWEEP == 1) {
|
if (BUCKET_SWEEP == 1) {
|
||||||
self->buckets_[key] = (uint32_t)cur_ix;
|
buckets[key] = (uint32_t)cur_ix;
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
best_len = len;
|
||||||
|
best_score = score;
|
||||||
|
compare_char = data[cur_ix_masked + len];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,8 +191,8 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||||
size_t backward;
|
size_t backward;
|
||||||
size_t len;
|
size_t len;
|
||||||
/* Only one to look for, don't bother to prepare for a loop. */
|
/* Only one to look for, don't bother to prepare for a loop. */
|
||||||
prev_ix = self->buckets_[key];
|
prev_ix = buckets[key];
|
||||||
self->buckets_[key] = (uint32_t)cur_ix;
|
buckets[key] = (uint32_t)cur_ix;
|
||||||
backward = cur_ix - prev_ix;
|
backward = cur_ix - prev_ix;
|
||||||
prev_ix &= (uint32_t)ring_buffer_mask;
|
prev_ix &= (uint32_t)ring_buffer_mask;
|
||||||
if (compare_char != data[prev_ix + best_len_in]) {
|
if (compare_char != data[prev_ix + best_len_in]) {
|
||||||
|
@ -191,12 +214,17 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint32_t *bucket = self->buckets_ + key;
|
size_t keys[BUCKET_SWEEP];
|
||||||
int i;
|
size_t i;
|
||||||
prev_ix = *bucket++;
|
for (i = 0; i < BUCKET_SWEEP; ++i) {
|
||||||
for (i = 0; i < BUCKET_SWEEP; ++i, prev_ix = *bucket++) {
|
keys[i] = (key + (i << 3)) & BUCKET_MASK;
|
||||||
const size_t backward = cur_ix - prev_ix;
|
}
|
||||||
|
key_out = keys[(cur_ix & BUCKET_SWEEP_MASK) >> 3];
|
||||||
|
for (i = 0; i < BUCKET_SWEEP; ++i) {
|
||||||
size_t len;
|
size_t len;
|
||||||
|
size_t backward;
|
||||||
|
prev_ix = buckets[keys[i]];
|
||||||
|
backward = cur_ix - prev_ix;
|
||||||
prev_ix &= (uint32_t)ring_buffer_mask;
|
prev_ix &= (uint32_t)ring_buffer_mask;
|
||||||
if (compare_char != data[prev_ix + best_len]) {
|
if (compare_char != data[prev_ix + best_len]) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -210,25 +238,29 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||||
if (len >= 4) {
|
if (len >= 4) {
|
||||||
const score_t score = BackwardReferenceScore(len, backward);
|
const score_t score = BackwardReferenceScore(len, backward);
|
||||||
if (best_score < score) {
|
if (best_score < score) {
|
||||||
best_score = score;
|
|
||||||
best_len = len;
|
best_len = len;
|
||||||
out->len = best_len;
|
out->len = len;
|
||||||
out->distance = backward;
|
compare_char = data[cur_ix_masked + len];
|
||||||
|
best_score = score;
|
||||||
out->score = score;
|
out->score = score;
|
||||||
compare_char = data[cur_ix_masked + best_len];
|
out->distance = backward;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (USE_DICTIONARY && min_score == out->score) {
|
if (USE_DICTIONARY && min_score == out->score) {
|
||||||
SearchInStaticDictionary(dictionary, dictionary_hash,
|
SearchInStaticDictionary(dictionary,
|
||||||
handle, &data[cur_ix_masked], max_length, max_backward + gap, out,
|
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||||
BROTLI_TRUE);
|
max_distance, out, BROTLI_TRUE);
|
||||||
|
}
|
||||||
|
if (BUCKET_SWEEP != 1) {
|
||||||
|
buckets[key_out] = (uint32_t)cur_ix;
|
||||||
}
|
}
|
||||||
self->buckets_[key + ((cur_ix >> 3) % BUCKET_SWEEP)] = (uint32_t)cur_ix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef HASH_MAP_SIZE
|
#undef BUCKET_SWEEP_MASK
|
||||||
|
#undef BUCKET_SWEEP
|
||||||
|
#undef BUCKET_MASK
|
||||||
#undef BUCKET_SIZE
|
#undef BUCKET_SIZE
|
||||||
|
|
||||||
#undef HashLongestMatchQuickly
|
#undef HashLongestMatchQuickly
|
||||||
|
|
|
@ -24,8 +24,8 @@ static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
|
||||||
return MAX_TREE_COMP_LENGTH;
|
return MAX_TREE_COMP_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t FN(HashBytes)(const uint8_t *data) {
|
static uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
|
||||||
uint32_t h = BROTLI_UNALIGNED_LOAD32(data) * kHashMul32;
|
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||||
/* The higher bits contain more mixture from the multiplication,
|
/* The higher bits contain more mixture from the multiplication,
|
||||||
so we take our results from there. */
|
so we take our results from there. */
|
||||||
return h >> (32 - BUCKET_BITS);
|
return h >> (32 - BUCKET_BITS);
|
||||||
|
@ -38,7 +38,7 @@ typedef struct HashToBinaryTree {
|
||||||
/* Hash table that maps the 4-byte hashes of the sequence to the last
|
/* Hash table that maps the 4-byte hashes of the sequence to the last
|
||||||
position where this hash was found, which is the root of the binary
|
position where this hash was found, which is the root of the binary
|
||||||
tree of sequences that share this hash bucket. */
|
tree of sequences that share this hash bucket. */
|
||||||
uint32_t buckets_[BUCKET_SIZE];
|
uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
|
||||||
|
|
||||||
/* A position used to mark a non-existent sequence, i.e. a tree is empty if
|
/* A position used to mark a non-existent sequence, i.e. a tree is empty if
|
||||||
its root is at invalid_pos_ and a node is a leaf if both its children
|
its root is at invalid_pos_ and a node is a leaf if both its children
|
||||||
|
@ -51,34 +51,30 @@ typedef struct HashToBinaryTree {
|
||||||
corresponding to a hash is a sequence starting at buckets_[hash] and
|
corresponding to a hash is a sequence starting at buckets_[hash] and
|
||||||
the left and right children of a sequence starting at pos are
|
the left and right children of a sequence starting at pos are
|
||||||
forest_[2 * pos] and forest_[2 * pos + 1]. */
|
forest_[2 * pos] and forest_[2 * pos + 1]. */
|
||||||
/* uint32_t forest[2 * num_nodes] */
|
uint32_t* forest_; /* uint32_t[2 * num_nodes] */
|
||||||
} HashToBinaryTree;
|
} HashToBinaryTree;
|
||||||
|
|
||||||
static BROTLI_INLINE HashToBinaryTree* FN(Self)(HasherHandle handle) {
|
|
||||||
return (HashToBinaryTree*)&(GetHasherCommon(handle)[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t* FN(Forest)(HashToBinaryTree* self) {
|
|
||||||
return (uint32_t*)(&self[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FN(Initialize)(
|
static void FN(Initialize)(
|
||||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
HasherCommon* common, HashToBinaryTree* BROTLI_RESTRICT self,
|
||||||
HashToBinaryTree* self = FN(Self)(handle);
|
const BrotliEncoderParams* params) {
|
||||||
|
self->buckets_ = (uint32_t*)common->extra;
|
||||||
|
self->forest_ = &self->buckets_[BUCKET_SIZE];
|
||||||
|
|
||||||
self->window_mask_ = (1u << params->lgwin) - 1u;
|
self->window_mask_ = (1u << params->lgwin) - 1u;
|
||||||
self->invalid_pos_ = (uint32_t)(0 - self->window_mask_);
|
self->invalid_pos_ = (uint32_t)(0 - self->window_mask_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
static void FN(Prepare)
|
||||||
size_t input_size, const uint8_t* data) {
|
(HashToBinaryTree* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||||
HashToBinaryTree* self = FN(Self)(handle);
|
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||||
uint32_t invalid_pos = self->invalid_pos_;
|
uint32_t invalid_pos = self->invalid_pos_;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||||
BROTLI_UNUSED(data);
|
BROTLI_UNUSED(data);
|
||||||
BROTLI_UNUSED(one_shot);
|
BROTLI_UNUSED(one_shot);
|
||||||
BROTLI_UNUSED(input_size);
|
BROTLI_UNUSED(input_size);
|
||||||
for (i = 0; i < BUCKET_SIZE; i++) {
|
for (i = 0; i < BUCKET_SIZE; i++) {
|
||||||
self->buckets_[i] = invalid_pos;
|
buckets[i] = invalid_pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,15 +85,17 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||||
if (one_shot && input_size < num_nodes) {
|
if (one_shot && input_size < num_nodes) {
|
||||||
num_nodes = input_size;
|
num_nodes = input_size;
|
||||||
}
|
}
|
||||||
return sizeof(HashToBinaryTree) + 2 * sizeof(uint32_t) * num_nodes;
|
return sizeof(uint32_t) * BUCKET_SIZE + 2 * sizeof(uint32_t) * num_nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE size_t FN(LeftChildIndex)(HashToBinaryTree* self,
|
static BROTLI_INLINE size_t FN(LeftChildIndex)(
|
||||||
|
HashToBinaryTree* BROTLI_RESTRICT self,
|
||||||
const size_t pos) {
|
const size_t pos) {
|
||||||
return 2 * (pos & self->window_mask_);
|
return 2 * (pos & self->window_mask_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE size_t FN(RightChildIndex)(HashToBinaryTree* self,
|
static BROTLI_INLINE size_t FN(RightChildIndex)(
|
||||||
|
HashToBinaryTree* BROTLI_RESTRICT self,
|
||||||
const size_t pos) {
|
const size_t pos) {
|
||||||
return 2 * (pos & self->window_mask_) + 1;
|
return 2 * (pos & self->window_mask_) + 1;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +111,7 @@ static BROTLI_INLINE size_t FN(RightChildIndex)(HashToBinaryTree* self,
|
||||||
|
|
||||||
This function must be called with increasing cur_ix positions. */
|
This function must be called with increasing cur_ix positions. */
|
||||||
static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
|
static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
|
||||||
HashToBinaryTree* self, const uint8_t* const BROTLI_RESTRICT data,
|
HashToBinaryTree* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||||
const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length,
|
const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length,
|
||||||
const size_t max_backward, size_t* const BROTLI_RESTRICT best_len,
|
const size_t max_backward, size_t* const BROTLI_RESTRICT best_len,
|
||||||
BackwardMatch* BROTLI_RESTRICT matches) {
|
BackwardMatch* BROTLI_RESTRICT matches) {
|
||||||
|
@ -123,8 +121,9 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
|
||||||
const BROTLI_BOOL should_reroot_tree =
|
const BROTLI_BOOL should_reroot_tree =
|
||||||
TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH);
|
TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH);
|
||||||
const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
||||||
uint32_t* forest = FN(Forest)(self);
|
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||||
size_t prev_ix = self->buckets_[key];
|
uint32_t* BROTLI_RESTRICT forest = self->forest_;
|
||||||
|
size_t prev_ix = buckets[key];
|
||||||
/* The forest index of the rightmost node of the left subtree of the new
|
/* The forest index of the rightmost node of the left subtree of the new
|
||||||
root, updated as we traverse and re-root the tree of the hash bucket. */
|
root, updated as we traverse and re-root the tree of the hash bucket. */
|
||||||
size_t node_left = FN(LeftChildIndex)(self, cur_ix);
|
size_t node_left = FN(LeftChildIndex)(self, cur_ix);
|
||||||
|
@ -139,7 +138,7 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
|
||||||
size_t best_len_right = 0;
|
size_t best_len_right = 0;
|
||||||
size_t depth_remaining;
|
size_t depth_remaining;
|
||||||
if (should_reroot_tree) {
|
if (should_reroot_tree) {
|
||||||
self->buckets_[key] = (uint32_t)cur_ix;
|
buckets[key] = (uint32_t)cur_ix;
|
||||||
}
|
}
|
||||||
for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) {
|
for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) {
|
||||||
const size_t backward = cur_ix - prev_ix;
|
const size_t backward = cur_ix - prev_ix;
|
||||||
|
@ -154,12 +153,13 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
|
||||||
{
|
{
|
||||||
const size_t cur_len = BROTLI_MIN(size_t, best_len_left, best_len_right);
|
const size_t cur_len = BROTLI_MIN(size_t, best_len_left, best_len_right);
|
||||||
size_t len;
|
size_t len;
|
||||||
assert(cur_len <= MAX_TREE_COMP_LENGTH);
|
BROTLI_DCHECK(cur_len <= MAX_TREE_COMP_LENGTH);
|
||||||
len = cur_len +
|
len = cur_len +
|
||||||
FindMatchLengthWithLimit(&data[cur_ix_masked + cur_len],
|
FindMatchLengthWithLimit(&data[cur_ix_masked + cur_len],
|
||||||
&data[prev_ix_masked + cur_len],
|
&data[prev_ix_masked + cur_len],
|
||||||
max_length - cur_len);
|
max_length - cur_len);
|
||||||
assert(0 == memcmp(&data[cur_ix_masked], &data[prev_ix_masked], len));
|
BROTLI_DCHECK(
|
||||||
|
0 == memcmp(&data[cur_ix_masked], &data[prev_ix_masked], len));
|
||||||
if (matches && len > *best_len) {
|
if (matches && len > *best_len) {
|
||||||
*best_len = len;
|
*best_len = len;
|
||||||
InitBackwardMatch(matches++, backward, len);
|
InitBackwardMatch(matches++, backward, len);
|
||||||
|
@ -198,11 +198,14 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
|
||||||
matches in matches[0] to matches[*num_matches - 1]. The matches will be
|
matches in matches[0] to matches[*num_matches - 1]. The matches will be
|
||||||
sorted by strictly increasing length and (non-strictly) increasing
|
sorted by strictly increasing length and (non-strictly) increasing
|
||||||
distance. */
|
distance. */
|
||||||
static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
|
static BROTLI_INLINE size_t FN(FindAllMatches)(
|
||||||
const BrotliDictionary* dictionary, const uint8_t* data,
|
HashToBinaryTree* BROTLI_RESTRICT self,
|
||||||
|
const BrotliEncoderDictionary* dictionary,
|
||||||
|
const uint8_t* BROTLI_RESTRICT data,
|
||||||
const size_t ring_buffer_mask, const size_t cur_ix,
|
const size_t ring_buffer_mask, const size_t cur_ix,
|
||||||
const size_t max_length, const size_t max_backward, const size_t gap,
|
const size_t max_length, const size_t max_backward,
|
||||||
const BrotliEncoderParams* params, BackwardMatch* matches) {
|
const size_t dictionary_distance, const BrotliEncoderParams* params,
|
||||||
|
BackwardMatch* matches) {
|
||||||
BackwardMatch* const orig_matches = matches;
|
BackwardMatch* const orig_matches = matches;
|
||||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||||
size_t best_len = 1;
|
size_t best_len = 1;
|
||||||
|
@ -234,7 +237,7 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (best_len < max_length) {
|
if (best_len < max_length) {
|
||||||
matches = FN(StoreAndFindMatches)(FN(Self)(handle), data, cur_ix,
|
matches = FN(StoreAndFindMatches)(self, data, cur_ix,
|
||||||
ring_buffer_mask, max_length, max_backward, &best_len, matches);
|
ring_buffer_mask, max_length, max_backward, &best_len, matches);
|
||||||
}
|
}
|
||||||
for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) {
|
for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) {
|
||||||
|
@ -250,8 +253,8 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
|
||||||
for (l = minlen; l <= maxlen; ++l) {
|
for (l = minlen; l <= maxlen; ++l) {
|
||||||
uint32_t dict_id = dict_matches[l];
|
uint32_t dict_id = dict_matches[l];
|
||||||
if (dict_id < kInvalidMatch) {
|
if (dict_id < kInvalidMatch) {
|
||||||
size_t distance = max_backward + gap + (dict_id >> 5) + 1;
|
size_t distance = dictionary_distance + (dict_id >> 5) + 1;
|
||||||
if (distance < BROTLI_MAX_DISTANCE) {
|
if (distance <= params->dist.max_distance) {
|
||||||
InitDictionaryBackwardMatch(matches++, distance, l, dict_id & 31);
|
InitDictionaryBackwardMatch(matches++, distance, l, dict_id & 31);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,18 +267,18 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
|
||||||
/* Stores the hash of the next 4 bytes and re-roots the binary tree at the
|
/* Stores the hash of the next 4 bytes and re-roots the binary tree at the
|
||||||
current sequence, without returning any matches.
|
current sequence, without returning any matches.
|
||||||
REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */
|
REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */
|
||||||
static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t *data,
|
static BROTLI_INLINE void FN(Store)(HashToBinaryTree* BROTLI_RESTRICT self,
|
||||||
|
const uint8_t* BROTLI_RESTRICT data,
|
||||||
const size_t mask, const size_t ix) {
|
const size_t mask, const size_t ix) {
|
||||||
HashToBinaryTree* self = FN(Self)(handle);
|
|
||||||
/* Maximum distance is window size - 16, see section 9.1. of the spec. */
|
/* Maximum distance is window size - 16, see section 9.1. of the spec. */
|
||||||
const size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1;
|
const size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1;
|
||||||
FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH,
|
FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH,
|
||||||
max_backward, NULL, NULL);
|
max_backward, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
static BROTLI_INLINE void FN(StoreRange)(HashToBinaryTree* BROTLI_RESTRICT self,
|
||||||
const uint8_t *data, const size_t mask, const size_t ix_start,
|
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||||
const size_t ix_end) {
|
const size_t ix_start, const size_t ix_end) {
|
||||||
size_t i = ix_start;
|
size_t i = ix_start;
|
||||||
size_t j = ix_start;
|
size_t j = ix_start;
|
||||||
if (ix_start + 63 <= ix_end) {
|
if (ix_start + 63 <= ix_end) {
|
||||||
|
@ -283,18 +286,18 @@ static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||||
}
|
}
|
||||||
if (ix_start + 512 <= i) {
|
if (ix_start + 512 <= i) {
|
||||||
for (; j < i; j += 8) {
|
for (; j < i; j += 8) {
|
||||||
FN(Store)(handle, data, mask, j);
|
FN(Store)(self, data, mask, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (; i < ix_end; ++i) {
|
for (; i < ix_end; ++i) {
|
||||||
FN(Store)(handle, data, mask, i);
|
FN(Store)(self, data, mask, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||||
|
HashToBinaryTree* BROTLI_RESTRICT self,
|
||||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||||
size_t ringbuffer_mask) {
|
size_t ringbuffer_mask) {
|
||||||
HashToBinaryTree* self = FN(Self)(handle);
|
|
||||||
if (num_bytes >= FN(HashTypeLength)() - 1 &&
|
if (num_bytes >= FN(HashTypeLength)() - 1 &&
|
||||||
position >= MAX_TREE_COMP_LENGTH) {
|
position >= MAX_TREE_COMP_LENGTH) {
|
||||||
/* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.
|
/* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
#include "./histogram.h"
|
#include "./histogram.h"
|
||||||
|
|
||||||
|
#include "../common/context.h"
|
||||||
#include "./block_splitter.h"
|
#include "./block_splitter.h"
|
||||||
#include "./command.h"
|
#include "./command.h"
|
||||||
#include "./context.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -63,13 +63,16 @@ void BrotliBuildHistogramsWithContext(
|
||||||
BlockSplitIteratorNext(&insert_and_copy_it);
|
BlockSplitIteratorNext(&insert_and_copy_it);
|
||||||
HistogramAddCommand(&insert_and_copy_histograms[insert_and_copy_it.type_],
|
HistogramAddCommand(&insert_and_copy_histograms[insert_and_copy_it.type_],
|
||||||
cmd->cmd_prefix_);
|
cmd->cmd_prefix_);
|
||||||
|
/* TODO: unwrap iterator blocks. */
|
||||||
for (j = cmd->insert_len_; j != 0; --j) {
|
for (j = cmd->insert_len_; j != 0; --j) {
|
||||||
size_t context;
|
size_t context;
|
||||||
BlockSplitIteratorNext(&literal_it);
|
BlockSplitIteratorNext(&literal_it);
|
||||||
context = context_modes ?
|
context = literal_it.type_;
|
||||||
((literal_it.type_ << BROTLI_LITERAL_CONTEXT_BITS) +
|
if (context_modes) {
|
||||||
Context(prev_byte, prev_byte2, context_modes[literal_it.type_])) :
|
ContextLut lut = BROTLI_CONTEXT_LUT(context_modes[context]);
|
||||||
literal_it.type_;
|
context = (context << BROTLI_LITERAL_CONTEXT_BITS) +
|
||||||
|
BROTLI_CONTEXT(prev_byte, prev_byte2, lut);
|
||||||
|
}
|
||||||
HistogramAddLiteral(&literal_histograms[context],
|
HistogramAddLiteral(&literal_histograms[context],
|
||||||
ringbuffer[pos & mask]);
|
ringbuffer[pos & mask]);
|
||||||
prev_byte2 = prev_byte;
|
prev_byte2 = prev_byte;
|
||||||
|
@ -86,7 +89,7 @@ void BrotliBuildHistogramsWithContext(
|
||||||
context = (dist_it.type_ << BROTLI_DISTANCE_CONTEXT_BITS) +
|
context = (dist_it.type_ << BROTLI_DISTANCE_CONTEXT_BITS) +
|
||||||
CommandDistanceContext(cmd);
|
CommandDistanceContext(cmd);
|
||||||
HistogramAddDistance(©_dist_histograms[context],
|
HistogramAddDistance(©_dist_histograms[context],
|
||||||
cmd->dist_prefix_);
|
cmd->dist_prefix_ & 0x3FF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,16 +12,19 @@
|
||||||
#include <string.h> /* memset */
|
#include <string.h> /* memset */
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/context.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./block_splitter.h"
|
#include "./block_splitter.h"
|
||||||
#include "./command.h"
|
#include "./command.h"
|
||||||
#include "./context.h"
|
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* The distance symbols effectively used by "Large Window Brotli" (32-bit). */
|
||||||
|
#define BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS 544
|
||||||
|
|
||||||
#define FN(X) X ## Literal
|
#define FN(X) X ## Literal
|
||||||
#define DATA_SIZE BROTLI_NUM_LITERAL_SYMBOLS
|
#define DATA_SIZE BROTLI_NUM_LITERAL_SYMBOLS
|
||||||
#define DataType uint8_t
|
#define DataType uint8_t
|
||||||
|
@ -38,7 +41,7 @@ extern "C" {
|
||||||
#undef FN
|
#undef FN
|
||||||
|
|
||||||
#define FN(X) X ## Distance
|
#define FN(X) X ## Distance
|
||||||
#define DATA_SIZE BROTLI_NUM_DISTANCE_SYMBOLS
|
#define DATA_SIZE BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS
|
||||||
#include "./histogram_inc.h" /* NOLINT(build/include) */
|
#include "./histogram_inc.h" /* NOLINT(build/include) */
|
||||||
#undef DataType
|
#undef DataType
|
||||||
#undef DATA_SIZE
|
#undef DATA_SIZE
|
||||||
|
|
|
@ -33,7 +33,7 @@ static BROTLI_INLINE void FN(HistogramAdd)(FN(Histogram)* self, size_t val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void FN(HistogramAddVector)(FN(Histogram)* self,
|
static BROTLI_INLINE void FN(HistogramAddVector)(FN(Histogram)* self,
|
||||||
const DataType *p, size_t n) {
|
const DataType* p, size_t n) {
|
||||||
self->total_count_ += n;
|
self->total_count_ += n;
|
||||||
n += 1;
|
n += 1;
|
||||||
while (--n) ++self->data_[*p++];
|
while (--n) ++self->data_[*p++];
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
|
|
||||||
#include "./literal_cost.h"
|
#include "./literal_cost.h"
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./utf8_util.h"
|
#include "./utf8_util.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -25,7 +25,7 @@ static size_t UTF8Position(size_t last, size_t c, size_t clamp) {
|
||||||
return BROTLI_MIN(size_t, 1, clamp);
|
return BROTLI_MIN(size_t, 1, clamp);
|
||||||
} else {
|
} else {
|
||||||
/* Let's decide over the last byte if this ends the sequence. */
|
/* Let's decide over the last byte if this ends the sequence. */
|
||||||
if (last < 0xe0) {
|
if (last < 0xE0) {
|
||||||
return 0; /* Completed two or three byte coding. */
|
return 0; /* Completed two or three byte coding. */
|
||||||
} else { /* Next one is the 'Byte 3' of utf-8 encoding. */
|
} else { /* Next one is the 'Byte 3' of utf-8 encoding. */
|
||||||
return BROTLI_MIN(size_t, 2, clamp);
|
return BROTLI_MIN(size_t, 2, clamp);
|
||||||
|
@ -34,7 +34,7 @@ static size_t UTF8Position(size_t last, size_t c, size_t clamp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t DecideMultiByteStatsLevel(size_t pos, size_t len, size_t mask,
|
static size_t DecideMultiByteStatsLevel(size_t pos, size_t len, size_t mask,
|
||||||
const uint8_t *data) {
|
const uint8_t* data) {
|
||||||
size_t counts[3] = { 0 };
|
size_t counts[3] = { 0 };
|
||||||
size_t max_utf8 = 1; /* should be 2, but 1 compresses better. */
|
size_t max_utf8 = 1; /* should be 2, but 1 compresses better. */
|
||||||
size_t last_c = 0;
|
size_t last_c = 0;
|
||||||
|
@ -54,7 +54,7 @@ static size_t DecideMultiByteStatsLevel(size_t pos, size_t len, size_t mask,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
|
static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
|
||||||
const uint8_t *data, float *cost) {
|
const uint8_t* data, float* cost) {
|
||||||
/* max_utf8 is 0 (normal ASCII single byte modeling),
|
/* max_utf8 is 0 (normal ASCII single byte modeling),
|
||||||
1 (for 2-byte UTF-8 modeling), or 2 (for 3-byte UTF-8 modeling). */
|
1 (for 2-byte UTF-8 modeling), or 2 (for 3-byte UTF-8 modeling). */
|
||||||
const size_t max_utf8 = DecideMultiByteStatsLevel(pos, len, mask, data);
|
const size_t max_utf8 = DecideMultiByteStatsLevel(pos, len, mask, data);
|
||||||
|
@ -125,7 +125,7 @@ static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliEstimateBitCostsForLiterals(size_t pos, size_t len, size_t mask,
|
void BrotliEstimateBitCostsForLiterals(size_t pos, size_t len, size_t mask,
|
||||||
const uint8_t *data, float *cost) {
|
const uint8_t* data, float* cost) {
|
||||||
if (BrotliIsMostlyUTF8(data, pos, mask, len, kMinUTF8Ratio)) {
|
if (BrotliIsMostlyUTF8(data, pos, mask, len, kMinUTF8Ratio)) {
|
||||||
EstimateBitCostsForLiteralsUTF8(pos, len, mask, data, cost);
|
EstimateBitCostsForLiteralsUTF8(pos, len, mask, data, cost);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#ifndef BROTLI_ENC_LITERAL_COST_H_
|
#ifndef BROTLI_ENC_LITERAL_COST_H_
|
||||||
#define BROTLI_ENC_LITERAL_COST_H_
|
#define BROTLI_ENC_LITERAL_COST_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -21,7 +21,7 @@ extern "C" {
|
||||||
ring-buffer (data, mask) will take entropy coded and writes these estimates
|
ring-buffer (data, mask) will take entropy coded and writes these estimates
|
||||||
to the cost[0..len) array. */
|
to the cost[0..len) array. */
|
||||||
BROTLI_INTERNAL void BrotliEstimateBitCostsForLiterals(
|
BROTLI_INTERNAL void BrotliEstimateBitCostsForLiterals(
|
||||||
size_t pos, size_t len, size_t mask, const uint8_t *data, float *cost);
|
size_t pos, size_t len, size_t mask, const uint8_t* data, float* cost);
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|
|
@ -9,12 +9,11 @@
|
||||||
|
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h> /* exit, free, malloc */
|
#include <stdlib.h> /* exit, free, malloc */
|
||||||
#include <string.h> /* memcpy */
|
#include <string.h> /* memcpy */
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -28,22 +27,12 @@ extern "C" {
|
||||||
#define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED
|
#define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED
|
||||||
#define NEW_FREED_OFFSET (MAX_PERM_ALLOCATED + MAX_NEW_ALLOCATED)
|
#define NEW_FREED_OFFSET (MAX_PERM_ALLOCATED + MAX_NEW_ALLOCATED)
|
||||||
|
|
||||||
static void* DefaultAllocFunc(void* opaque, size_t size) {
|
|
||||||
BROTLI_UNUSED(opaque);
|
|
||||||
return malloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DefaultFreeFunc(void* opaque, void* address) {
|
|
||||||
BROTLI_UNUSED(opaque);
|
|
||||||
free(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BrotliInitMemoryManager(
|
void BrotliInitMemoryManager(
|
||||||
MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func,
|
MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func,
|
||||||
void* opaque) {
|
void* opaque) {
|
||||||
if (!alloc_func) {
|
if (!alloc_func) {
|
||||||
m->alloc_func = DefaultAllocFunc;
|
m->alloc_func = BrotliDefaultAllocFunc;
|
||||||
m->free_func = DefaultFreeFunc;
|
m->free_func = BrotliDefaultFreeFunc;
|
||||||
m->opaque = 0;
|
m->opaque = 0;
|
||||||
} else {
|
} else {
|
||||||
m->alloc_func = alloc_func;
|
m->alloc_func = alloc_func;
|
||||||
|
@ -132,11 +121,11 @@ static void CollectGarbagePointers(MemoryManager* m) {
|
||||||
m->pointers + NEW_FREED_OFFSET, m->new_freed);
|
m->pointers + NEW_FREED_OFFSET, m->new_freed);
|
||||||
m->perm_allocated -= annihilated;
|
m->perm_allocated -= annihilated;
|
||||||
m->new_freed -= annihilated;
|
m->new_freed -= annihilated;
|
||||||
assert(m->new_freed == 0);
|
BROTLI_DCHECK(m->new_freed == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m->new_allocated != 0) {
|
if (m->new_allocated != 0) {
|
||||||
assert(m->perm_allocated + m->new_allocated <= MAX_PERM_ALLOCATED);
|
BROTLI_DCHECK(m->perm_allocated + m->new_allocated <= MAX_PERM_ALLOCATED);
|
||||||
memcpy(m->pointers + PERM_ALLOCATED_OFFSET + m->perm_allocated,
|
memcpy(m->pointers + PERM_ALLOCATED_OFFSET + m->perm_allocated,
|
||||||
m->pointers + NEW_ALLOCATED_OFFSET,
|
m->pointers + NEW_ALLOCATED_OFFSET,
|
||||||
sizeof(void*) * m->new_allocated);
|
sizeof(void*) * m->new_allocated);
|
||||||
|
|
|
@ -9,8 +9,10 @@
|
||||||
#ifndef BROTLI_ENC_MEMORY_H_
|
#ifndef BROTLI_ENC_MEMORY_H_
|
||||||
#define BROTLI_ENC_MEMORY_H_
|
#define BROTLI_ENC_MEMORY_H_
|
||||||
|
|
||||||
|
#include <string.h> /* memcpy */
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -54,8 +56,57 @@ BROTLI_INTERNAL void BrotliFree(MemoryManager* m, void* p);
|
||||||
#define BROTLI_IS_OOM(M) (!!(M)->is_oom)
|
#define BROTLI_IS_OOM(M) (!!(M)->is_oom)
|
||||||
#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
|
#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
|
||||||
|
|
||||||
|
/*
|
||||||
|
BROTLI_IS_NULL is a fake check, BROTLI_IS_OOM does the heavy lifting.
|
||||||
|
The only purpose of it is to explain static analyzers the state of things.
|
||||||
|
NB: use ONLY together with BROTLI_IS_OOM
|
||||||
|
AND ONLY for allocations in the current scope.
|
||||||
|
*/
|
||||||
|
#if defined(__clang_analyzer__) && !defined(BROTLI_ENCODER_EXIT_ON_OOM)
|
||||||
|
#define BROTLI_IS_NULL(A) ((A) == nullptr)
|
||||||
|
#else /* defined(__clang_analyzer__) */
|
||||||
|
#define BROTLI_IS_NULL(A) (!!0)
|
||||||
|
#endif /* defined(__clang_analyzer__) */
|
||||||
|
|
||||||
BROTLI_INTERNAL void BrotliWipeOutMemoryManager(MemoryManager* m);
|
BROTLI_INTERNAL void BrotliWipeOutMemoryManager(MemoryManager* m);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dynamically grows array capacity to at least the requested size
|
||||||
|
M: MemoryManager
|
||||||
|
T: data type
|
||||||
|
A: array
|
||||||
|
C: capacity
|
||||||
|
R: requested size
|
||||||
|
*/
|
||||||
|
#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) { \
|
||||||
|
if (C < (R)) { \
|
||||||
|
size_t _new_size = (C == 0) ? (R) : C; \
|
||||||
|
T* new_array; \
|
||||||
|
while (_new_size < (R)) _new_size *= 2; \
|
||||||
|
new_array = BROTLI_ALLOC((M), T, _new_size); \
|
||||||
|
if (!BROTLI_IS_OOM(M) && !BROTLI_IS_NULL(new_array) && C != 0) \
|
||||||
|
memcpy(new_array, A, C * sizeof(T)); \
|
||||||
|
BROTLI_FREE((M), A); \
|
||||||
|
A = new_array; \
|
||||||
|
C = _new_size; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Appends value and dynamically grows array capacity when needed
|
||||||
|
M: MemoryManager
|
||||||
|
T: data type
|
||||||
|
A: array
|
||||||
|
C: array capacity
|
||||||
|
S: array size
|
||||||
|
V: value to append
|
||||||
|
*/
|
||||||
|
#define BROTLI_ENSURE_CAPACITY_APPEND(M, T, A, C, S, V) { \
|
||||||
|
(S)++; \
|
||||||
|
BROTLI_ENSURE_CAPACITY(M, T, A, C, S); \
|
||||||
|
A[(S) - 1] = (V); \
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,29 +10,127 @@
|
||||||
#include "./metablock.h"
|
#include "./metablock.h"
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
|
#include "../common/context.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./bit_cost.h"
|
#include "./bit_cost.h"
|
||||||
#include "./block_splitter.h"
|
#include "./block_splitter.h"
|
||||||
#include "./cluster.h"
|
#include "./cluster.h"
|
||||||
#include "./context.h"
|
|
||||||
#include "./entropy_encode.h"
|
#include "./entropy_encode.h"
|
||||||
#include "./histogram.h"
|
#include "./histogram.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./quality.h"
|
#include "./quality.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void BrotliInitDistanceParams(BrotliEncoderParams* params,
|
||||||
|
uint32_t npostfix, uint32_t ndirect) {
|
||||||
|
BrotliDistanceParams* dist_params = ¶ms->dist;
|
||||||
|
uint32_t alphabet_size_max;
|
||||||
|
uint32_t alphabet_size_limit;
|
||||||
|
uint32_t max_distance;
|
||||||
|
|
||||||
|
dist_params->distance_postfix_bits = npostfix;
|
||||||
|
dist_params->num_direct_distance_codes = ndirect;
|
||||||
|
|
||||||
|
alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||||
|
npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
|
||||||
|
alphabet_size_limit = alphabet_size_max;
|
||||||
|
max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) -
|
||||||
|
(1U << (npostfix + 2));
|
||||||
|
|
||||||
|
if (params->large_window) {
|
||||||
|
BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
|
||||||
|
BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
|
||||||
|
alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||||
|
npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
|
||||||
|
alphabet_size_limit = limit.max_alphabet_size;
|
||||||
|
max_distance = limit.max_distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
dist_params->alphabet_size_max = alphabet_size_max;
|
||||||
|
dist_params->alphabet_size_limit = alphabet_size_limit;
|
||||||
|
dist_params->max_distance = max_distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RecomputeDistancePrefixes(Command* cmds,
|
||||||
|
size_t num_commands,
|
||||||
|
const BrotliDistanceParams* orig_params,
|
||||||
|
const BrotliDistanceParams* new_params) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
|
||||||
|
orig_params->num_direct_distance_codes ==
|
||||||
|
new_params->num_direct_distance_codes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_commands; ++i) {
|
||||||
|
Command* cmd = &cmds[i];
|
||||||
|
if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
|
||||||
|
PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd, orig_params),
|
||||||
|
new_params->num_direct_distance_codes,
|
||||||
|
new_params->distance_postfix_bits,
|
||||||
|
&cmd->dist_prefix_,
|
||||||
|
&cmd->dist_extra_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BROTLI_BOOL ComputeDistanceCost(const Command* cmds,
|
||||||
|
size_t num_commands,
|
||||||
|
const BrotliDistanceParams* orig_params,
|
||||||
|
const BrotliDistanceParams* new_params,
|
||||||
|
double* cost) {
|
||||||
|
size_t i;
|
||||||
|
BROTLI_BOOL equal_params = BROTLI_FALSE;
|
||||||
|
uint16_t dist_prefix;
|
||||||
|
uint32_t dist_extra;
|
||||||
|
double extra_bits = 0.0;
|
||||||
|
HistogramDistance histo;
|
||||||
|
HistogramClearDistance(&histo);
|
||||||
|
|
||||||
|
if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
|
||||||
|
orig_params->num_direct_distance_codes ==
|
||||||
|
new_params->num_direct_distance_codes) {
|
||||||
|
equal_params = BROTLI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_commands; i++) {
|
||||||
|
const Command* cmd = &cmds[i];
|
||||||
|
if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
|
||||||
|
if (equal_params) {
|
||||||
|
dist_prefix = cmd->dist_prefix_;
|
||||||
|
} else {
|
||||||
|
uint32_t distance = CommandRestoreDistanceCode(cmd, orig_params);
|
||||||
|
if (distance > new_params->max_distance) {
|
||||||
|
return BROTLI_FALSE;
|
||||||
|
}
|
||||||
|
PrefixEncodeCopyDistance(distance,
|
||||||
|
new_params->num_direct_distance_codes,
|
||||||
|
new_params->distance_postfix_bits,
|
||||||
|
&dist_prefix,
|
||||||
|
&dist_extra);
|
||||||
|
}
|
||||||
|
HistogramAddDistance(&histo, dist_prefix & 0x3FF);
|
||||||
|
extra_bits += dist_prefix >> 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*cost = BrotliPopulationCostDistance(&histo) + extra_bits;
|
||||||
|
return BROTLI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
void BrotliBuildMetaBlock(MemoryManager* m,
|
void BrotliBuildMetaBlock(MemoryManager* m,
|
||||||
const uint8_t* ringbuffer,
|
const uint8_t* ringbuffer,
|
||||||
const size_t pos,
|
const size_t pos,
|
||||||
const size_t mask,
|
const size_t mask,
|
||||||
const BrotliEncoderParams* params,
|
BrotliEncoderParams* params,
|
||||||
uint8_t prev_byte,
|
uint8_t prev_byte,
|
||||||
uint8_t prev_byte2,
|
uint8_t prev_byte2,
|
||||||
const Command* cmds,
|
Command* cmds,
|
||||||
size_t num_commands,
|
size_t num_commands,
|
||||||
ContextType literal_context_mode,
|
ContextType literal_context_mode,
|
||||||
MetaBlockSplit* mb) {
|
MetaBlockSplit* mb) {
|
||||||
|
@ -45,6 +143,47 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
||||||
size_t distance_histograms_size;
|
size_t distance_histograms_size;
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t literal_context_multiplier = 1;
|
size_t literal_context_multiplier = 1;
|
||||||
|
uint32_t npostfix;
|
||||||
|
uint32_t ndirect_msb = 0;
|
||||||
|
BROTLI_BOOL check_orig = BROTLI_TRUE;
|
||||||
|
double best_dist_cost = 1e99;
|
||||||
|
BrotliEncoderParams orig_params = *params;
|
||||||
|
BrotliEncoderParams new_params = *params;
|
||||||
|
|
||||||
|
for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX; npostfix++) {
|
||||||
|
for (; ndirect_msb < 16; ndirect_msb++) {
|
||||||
|
uint32_t ndirect = ndirect_msb << npostfix;
|
||||||
|
BROTLI_BOOL skip;
|
||||||
|
double dist_cost;
|
||||||
|
BrotliInitDistanceParams(&new_params, npostfix, ndirect);
|
||||||
|
if (npostfix == orig_params.dist.distance_postfix_bits &&
|
||||||
|
ndirect == orig_params.dist.num_direct_distance_codes) {
|
||||||
|
check_orig = BROTLI_FALSE;
|
||||||
|
}
|
||||||
|
skip = !ComputeDistanceCost(
|
||||||
|
cmds, num_commands,
|
||||||
|
&orig_params.dist, &new_params.dist, &dist_cost);
|
||||||
|
if (skip || (dist_cost > best_dist_cost)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
best_dist_cost = dist_cost;
|
||||||
|
params->dist = new_params.dist;
|
||||||
|
}
|
||||||
|
if (ndirect_msb > 0) ndirect_msb--;
|
||||||
|
ndirect_msb /= 2;
|
||||||
|
}
|
||||||
|
if (check_orig) {
|
||||||
|
double dist_cost;
|
||||||
|
ComputeDistanceCost(cmds, num_commands,
|
||||||
|
&orig_params.dist, &orig_params.dist, &dist_cost);
|
||||||
|
if (dist_cost < best_dist_cost) {
|
||||||
|
/* NB: currently unused; uncomment when more param tuning is added. */
|
||||||
|
/* best_dist_cost = dist_cost; */
|
||||||
|
params->dist = orig_params.dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RecomputeDistancePrefixes(cmds, num_commands,
|
||||||
|
&orig_params.dist, ¶ms->dist);
|
||||||
|
|
||||||
BrotliSplitBlock(m, cmds, num_commands,
|
BrotliSplitBlock(m, cmds, num_commands,
|
||||||
ringbuffer, pos, mask, params,
|
ringbuffer, pos, mask, params,
|
||||||
|
@ -57,7 +196,7 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
||||||
literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
|
literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
|
||||||
literal_context_modes =
|
literal_context_modes =
|
||||||
BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
|
BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return;
|
||||||
for (i = 0; i < mb->literal_split.num_types; ++i) {
|
for (i = 0; i < mb->literal_split.num_types; ++i) {
|
||||||
literal_context_modes[i] = literal_context_mode;
|
literal_context_modes[i] = literal_context_mode;
|
||||||
}
|
}
|
||||||
|
@ -67,21 +206,21 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
||||||
mb->literal_split.num_types * literal_context_multiplier;
|
mb->literal_split.num_types * literal_context_multiplier;
|
||||||
literal_histograms =
|
literal_histograms =
|
||||||
BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
|
BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return;
|
||||||
ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
|
ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
|
||||||
|
|
||||||
distance_histograms_size =
|
distance_histograms_size =
|
||||||
mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
|
mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
|
||||||
distance_histograms =
|
distance_histograms =
|
||||||
BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
|
BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return;
|
||||||
ClearHistogramsDistance(distance_histograms, distance_histograms_size);
|
ClearHistogramsDistance(distance_histograms, distance_histograms_size);
|
||||||
|
|
||||||
assert(mb->command_histograms == 0);
|
BROTLI_DCHECK(mb->command_histograms == 0);
|
||||||
mb->command_histograms_size = mb->command_split.num_types;
|
mb->command_histograms_size = mb->command_split.num_types;
|
||||||
mb->command_histograms =
|
mb->command_histograms =
|
||||||
BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
|
BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return;
|
||||||
ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
|
ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
|
||||||
|
|
||||||
BrotliBuildHistogramsWithContext(cmds, num_commands,
|
BrotliBuildHistogramsWithContext(cmds, num_commands,
|
||||||
|
@ -90,18 +229,18 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
||||||
literal_histograms, mb->command_histograms, distance_histograms);
|
literal_histograms, mb->command_histograms, distance_histograms);
|
||||||
BROTLI_FREE(m, literal_context_modes);
|
BROTLI_FREE(m, literal_context_modes);
|
||||||
|
|
||||||
assert(mb->literal_context_map == 0);
|
BROTLI_DCHECK(mb->literal_context_map == 0);
|
||||||
mb->literal_context_map_size =
|
mb->literal_context_map_size =
|
||||||
mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
|
mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
|
||||||
mb->literal_context_map =
|
mb->literal_context_map =
|
||||||
BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
|
BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
|
||||||
|
|
||||||
assert(mb->literal_histograms == 0);
|
BROTLI_DCHECK(mb->literal_histograms == 0);
|
||||||
mb->literal_histograms_size = mb->literal_context_map_size;
|
mb->literal_histograms_size = mb->literal_context_map_size;
|
||||||
mb->literal_histograms =
|
mb->literal_histograms =
|
||||||
BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
|
BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return;
|
||||||
|
|
||||||
BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
|
BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
|
||||||
kMaxNumberOfHistograms, mb->literal_histograms,
|
kMaxNumberOfHistograms, mb->literal_histograms,
|
||||||
|
@ -121,18 +260,18 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(mb->distance_context_map == 0);
|
BROTLI_DCHECK(mb->distance_context_map == 0);
|
||||||
mb->distance_context_map_size =
|
mb->distance_context_map_size =
|
||||||
mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
|
mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
|
||||||
mb->distance_context_map =
|
mb->distance_context_map =
|
||||||
BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
|
BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return;
|
||||||
|
|
||||||
assert(mb->distance_histograms == 0);
|
BROTLI_DCHECK(mb->distance_histograms == 0);
|
||||||
mb->distance_histograms_size = mb->distance_context_map_size;
|
mb->distance_histograms_size = mb->distance_context_map_size;
|
||||||
mb->distance_histograms =
|
mb->distance_histograms =
|
||||||
BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
|
BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return;
|
||||||
|
|
||||||
BrotliClusterHistogramsDistance(m, distance_histograms,
|
BrotliClusterHistogramsDistance(m, distance_histograms,
|
||||||
mb->distance_context_map_size,
|
mb->distance_context_map_size,
|
||||||
|
@ -200,7 +339,7 @@ static void InitContextBlockSplitter(
|
||||||
size_t* histograms_size) {
|
size_t* histograms_size) {
|
||||||
size_t max_num_blocks = num_symbols / min_block_size + 1;
|
size_t max_num_blocks = num_symbols / min_block_size + 1;
|
||||||
size_t max_num_types;
|
size_t max_num_types;
|
||||||
assert(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
|
BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
|
||||||
|
|
||||||
self->alphabet_size_ = alphabet_size;
|
self->alphabet_size_ = alphabet_size;
|
||||||
self->num_contexts_ = num_contexts;
|
self->num_contexts_ = num_contexts;
|
||||||
|
@ -226,11 +365,11 @@ static void InitContextBlockSplitter(
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
split->num_blocks = max_num_blocks;
|
split->num_blocks = max_num_blocks;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
assert(*histograms == 0);
|
BROTLI_DCHECK(*histograms == 0);
|
||||||
*histograms_size = max_num_types * num_contexts;
|
*histograms_size = max_num_types * num_contexts;
|
||||||
*histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
|
*histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
|
||||||
self->histograms_ = *histograms;
|
self->histograms_ = *histograms;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
|
||||||
/* Clear only current histogram. */
|
/* Clear only current histogram. */
|
||||||
ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
|
ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
|
||||||
self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
|
self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
|
||||||
|
@ -280,7 +419,7 @@ static void ContextBlockSplitterFinishBlock(
|
||||||
double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
|
double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
|
||||||
double diff[2] = { 0.0 };
|
double diff[2] = { 0.0 };
|
||||||
size_t i;
|
size_t i;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return;
|
||||||
for (i = 0; i < num_contexts; ++i) {
|
for (i = 0; i < num_contexts; ++i) {
|
||||||
size_t curr_histo_ix = self->curr_histogram_ix_ + i;
|
size_t curr_histo_ix = self->curr_histogram_ix_ + i;
|
||||||
size_t j;
|
size_t j;
|
||||||
|
@ -379,12 +518,12 @@ static void MapStaticContexts(MemoryManager* m,
|
||||||
const uint32_t* static_context_map,
|
const uint32_t* static_context_map,
|
||||||
MetaBlockSplit* mb) {
|
MetaBlockSplit* mb) {
|
||||||
size_t i;
|
size_t i;
|
||||||
assert(mb->literal_context_map == 0);
|
BROTLI_DCHECK(mb->literal_context_map == 0);
|
||||||
mb->literal_context_map_size =
|
mb->literal_context_map_size =
|
||||||
mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
|
mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
|
||||||
mb->literal_context_map =
|
mb->literal_context_map =
|
||||||
BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
|
BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
|
||||||
|
|
||||||
for (i = 0; i < mb->literal_split.num_types; ++i) {
|
for (i = 0; i < mb->literal_split.num_types; ++i) {
|
||||||
uint32_t offset = (uint32_t)(i * num_contexts);
|
uint32_t offset = (uint32_t)(i * num_contexts);
|
||||||
|
@ -398,9 +537,9 @@ static void MapStaticContexts(MemoryManager* m,
|
||||||
|
|
||||||
static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
|
static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
|
||||||
MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
|
MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
|
||||||
uint8_t prev_byte, uint8_t prev_byte2, ContextType literal_context_mode,
|
uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut,
|
||||||
const size_t num_contexts, const uint32_t* static_context_map,
|
const size_t num_contexts, const uint32_t* static_context_map,
|
||||||
const Command *commands, size_t n_commands, MetaBlockSplit* mb) {
|
const Command* commands, size_t n_commands, MetaBlockSplit* mb) {
|
||||||
union {
|
union {
|
||||||
BlockSplitterLiteral plain;
|
BlockSplitterLiteral plain;
|
||||||
ContextBlockSplitter ctx;
|
ContextBlockSplitter ctx;
|
||||||
|
@ -441,7 +580,8 @@ static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
|
||||||
if (num_contexts == 1) {
|
if (num_contexts == 1) {
|
||||||
BlockSplitterAddSymbolLiteral(&lit_blocks.plain, literal);
|
BlockSplitterAddSymbolLiteral(&lit_blocks.plain, literal);
|
||||||
} else {
|
} else {
|
||||||
size_t context = Context(prev_byte, prev_byte2, literal_context_mode);
|
size_t context =
|
||||||
|
BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
|
||||||
ContextBlockSplitterAddSymbol(&lit_blocks.ctx, m, literal,
|
ContextBlockSplitterAddSymbol(&lit_blocks.ctx, m, literal,
|
||||||
static_context_map[context]);
|
static_context_map[context]);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
|
@ -455,7 +595,7 @@ static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
|
||||||
prev_byte2 = ringbuffer[(pos - 2) & mask];
|
prev_byte2 = ringbuffer[(pos - 2) & mask];
|
||||||
prev_byte = ringbuffer[(pos - 1) & mask];
|
prev_byte = ringbuffer[(pos - 1) & mask];
|
||||||
if (cmd.cmd_prefix_ >= 128) {
|
if (cmd.cmd_prefix_ >= 128) {
|
||||||
BlockSplitterAddSymbolDistance(&dist_blocks, cmd.dist_prefix_);
|
BlockSplitterAddSymbolDistance(&dist_blocks, cmd.dist_prefix_ & 0x3FF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,7 +622,7 @@ void BrotliBuildMetaBlockGreedy(MemoryManager* m,
|
||||||
size_t mask,
|
size_t mask,
|
||||||
uint8_t prev_byte,
|
uint8_t prev_byte,
|
||||||
uint8_t prev_byte2,
|
uint8_t prev_byte2,
|
||||||
ContextType literal_context_mode,
|
ContextLut literal_context_lut,
|
||||||
size_t num_contexts,
|
size_t num_contexts,
|
||||||
const uint32_t* static_context_map,
|
const uint32_t* static_context_map,
|
||||||
const Command* commands,
|
const Command* commands,
|
||||||
|
@ -490,19 +630,17 @@ void BrotliBuildMetaBlockGreedy(MemoryManager* m,
|
||||||
MetaBlockSplit* mb) {
|
MetaBlockSplit* mb) {
|
||||||
if (num_contexts == 1) {
|
if (num_contexts == 1) {
|
||||||
BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
|
BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
|
||||||
prev_byte2, literal_context_mode, 1, NULL, commands, n_commands, mb);
|
prev_byte2, literal_context_lut, 1, NULL, commands, n_commands, mb);
|
||||||
} else {
|
} else {
|
||||||
BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
|
BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
|
||||||
prev_byte2, literal_context_mode, num_contexts, static_context_map,
|
prev_byte2, literal_context_lut, num_contexts, static_context_map,
|
||||||
commands, n_commands, mb);
|
commands, n_commands, mb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrotliOptimizeHistograms(size_t num_direct_distance_codes,
|
void BrotliOptimizeHistograms(uint32_t num_distance_codes,
|
||||||
size_t distance_postfix_bits,
|
|
||||||
MetaBlockSplit* mb) {
|
MetaBlockSplit* mb) {
|
||||||
uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS];
|
uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||||
size_t num_distance_codes;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < mb->literal_histograms_size; ++i) {
|
for (i = 0; i < mb->literal_histograms_size; ++i) {
|
||||||
BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_,
|
BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_,
|
||||||
|
@ -513,9 +651,6 @@ void BrotliOptimizeHistograms(size_t num_direct_distance_codes,
|
||||||
mb->command_histograms[i].data_,
|
mb->command_histograms[i].data_,
|
||||||
good_for_rle);
|
good_for_rle);
|
||||||
}
|
}
|
||||||
num_distance_codes = BROTLI_NUM_DISTANCE_SHORT_CODES +
|
|
||||||
num_direct_distance_codes +
|
|
||||||
((2 * BROTLI_MAX_DISTANCE_BITS) << distance_postfix_bits);
|
|
||||||
for (i = 0; i < mb->distance_histograms_size; ++i) {
|
for (i = 0; i < mb->distance_histograms_size; ++i) {
|
||||||
BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
|
BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
|
||||||
mb->distance_histograms[i].data_,
|
mb->distance_histograms[i].data_,
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
#ifndef BROTLI_ENC_METABLOCK_H_
|
#ifndef BROTLI_ENC_METABLOCK_H_
|
||||||
#define BROTLI_ENC_METABLOCK_H_
|
#define BROTLI_ENC_METABLOCK_H_
|
||||||
|
|
||||||
|
#include "../common/context.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./block_splitter.h"
|
#include "./block_splitter.h"
|
||||||
#include "./command.h"
|
#include "./command.h"
|
||||||
#include "./context.h"
|
|
||||||
#include "./histogram.h"
|
#include "./histogram.h"
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./quality.h"
|
#include "./quality.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -67,15 +67,18 @@ static BROTLI_INLINE void DestroyMetaBlockSplit(
|
||||||
BROTLI_FREE(m, mb->distance_histograms);
|
BROTLI_FREE(m, mb->distance_histograms);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Uses the slow shortest-path block splitter and does context clustering. */
|
/* Uses the slow shortest-path block splitter and does context clustering.
|
||||||
|
The distance parameters are dynamically selected based on the commands
|
||||||
|
which get recomputed under the new distance parameters. The new distance
|
||||||
|
parameters are stored into *params. */
|
||||||
BROTLI_INTERNAL void BrotliBuildMetaBlock(MemoryManager* m,
|
BROTLI_INTERNAL void BrotliBuildMetaBlock(MemoryManager* m,
|
||||||
const uint8_t* ringbuffer,
|
const uint8_t* ringbuffer,
|
||||||
const size_t pos,
|
const size_t pos,
|
||||||
const size_t mask,
|
const size_t mask,
|
||||||
const BrotliEncoderParams* params,
|
BrotliEncoderParams* params,
|
||||||
uint8_t prev_byte,
|
uint8_t prev_byte,
|
||||||
uint8_t prev_byte2,
|
uint8_t prev_byte2,
|
||||||
const Command* cmds,
|
Command* cmds,
|
||||||
size_t num_commands,
|
size_t num_commands,
|
||||||
ContextType literal_context_mode,
|
ContextType literal_context_mode,
|
||||||
MetaBlockSplit* mb);
|
MetaBlockSplit* mb);
|
||||||
|
@ -85,14 +88,16 @@ BROTLI_INTERNAL void BrotliBuildMetaBlock(MemoryManager* m,
|
||||||
is the same for all block types. */
|
is the same for all block types. */
|
||||||
BROTLI_INTERNAL void BrotliBuildMetaBlockGreedy(
|
BROTLI_INTERNAL void BrotliBuildMetaBlockGreedy(
|
||||||
MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
|
MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
|
||||||
uint8_t prev_byte, uint8_t prev_byte2, ContextType literal_context_mode,
|
uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut,
|
||||||
size_t num_contexts, const uint32_t* static_context_map,
|
size_t num_contexts, const uint32_t* static_context_map,
|
||||||
const Command* commands, size_t n_commands, MetaBlockSplit* mb);
|
const Command* commands, size_t n_commands, MetaBlockSplit* mb);
|
||||||
|
|
||||||
BROTLI_INTERNAL void BrotliOptimizeHistograms(size_t num_direct_distance_codes,
|
BROTLI_INTERNAL void BrotliOptimizeHistograms(uint32_t num_distance_codes,
|
||||||
size_t distance_postfix_bits,
|
|
||||||
MetaBlockSplit* mb);
|
MetaBlockSplit* mb);
|
||||||
|
|
||||||
|
BROTLI_INTERNAL void BrotliInitDistanceParams(BrotliEncoderParams* params,
|
||||||
|
uint32_t npostfix, uint32_t ndirect);
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -67,11 +67,11 @@ static void FN(InitBlockSplitter)(
|
||||||
split->lengths, split->lengths_alloc_size, max_num_blocks);
|
split->lengths, split->lengths_alloc_size, max_num_blocks);
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m)) return;
|
||||||
self->split_->num_blocks = max_num_blocks;
|
self->split_->num_blocks = max_num_blocks;
|
||||||
assert(*histograms == 0);
|
BROTLI_DCHECK(*histograms == 0);
|
||||||
*histograms_size = max_num_types;
|
*histograms_size = max_num_types;
|
||||||
*histograms = BROTLI_ALLOC(m, HistogramType, *histograms_size);
|
*histograms = BROTLI_ALLOC(m, HistogramType, *histograms_size);
|
||||||
self->histograms_ = *histograms;
|
self->histograms_ = *histograms;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
|
||||||
/* Clear only current histogram. */
|
/* Clear only current histogram. */
|
||||||
FN(HistogramClear)(&self->histograms_[0]);
|
FN(HistogramClear)(&self->histograms_[0]);
|
||||||
self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
|
self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
|
||||||
|
|
|
@ -1,184 +0,0 @@
|
||||||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
|
||||||
|
|
||||||
Distributed under MIT license.
|
|
||||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Macros for endianness, branch prediction and unaligned loads and stores. */
|
|
||||||
|
|
||||||
#ifndef BROTLI_ENC_PORT_H_
|
|
||||||
#define BROTLI_ENC_PORT_H_
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h> /* memcpy */
|
|
||||||
|
|
||||||
#include <brotli/port.h>
|
|
||||||
#include <brotli/types.h>
|
|
||||||
|
|
||||||
#if defined OS_LINUX || defined OS_CYGWIN
|
|
||||||
#include <endian.h>
|
|
||||||
#elif defined OS_FREEBSD
|
|
||||||
#include <machine/endian.h>
|
|
||||||
#elif defined OS_MACOSX
|
|
||||||
#include <machine/endian.h>
|
|
||||||
/* Let's try and follow the Linux convention */
|
|
||||||
#define __BYTE_ORDER BYTE_ORDER
|
|
||||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* define the macro BROTLI_LITTLE_ENDIAN
|
|
||||||
using the above endian definitions from endian.h if
|
|
||||||
endian.h was included */
|
|
||||||
#ifdef __BYTE_ORDER
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
#define BROTLI_LITTLE_ENDIAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#if defined(__LITTLE_ENDIAN__)
|
|
||||||
#define BROTLI_LITTLE_ENDIAN
|
|
||||||
#endif
|
|
||||||
#endif /* __BYTE_ORDER */
|
|
||||||
|
|
||||||
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
|
||||||
#define BROTLI_LITTLE_ENDIAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Enable little-endian optimization for x64 architecture on Windows. */
|
|
||||||
#if (defined(_WIN32) || defined(_WIN64)) && defined(_M_X64)
|
|
||||||
#define BROTLI_LITTLE_ENDIAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Portable handling of unaligned loads, stores, and copies.
|
|
||||||
On some platforms, like ARM, the copy functions can be more efficient
|
|
||||||
then a load and a store. */
|
|
||||||
|
|
||||||
#if defined(BROTLI_LITTLE_ENDIAN) && (\
|
|
||||||
defined(ARCH_PIII) || defined(ARCH_ATHLON) || \
|
|
||||||
defined(ARCH_K8) || defined(_ARCH_PPC))
|
|
||||||
|
|
||||||
/* x86 and x86-64 can perform unaligned loads/stores directly;
|
|
||||||
modern PowerPC hardware can also do unaligned integer loads and stores;
|
|
||||||
but note: the FPU still sends unaligned loads and stores to a trap handler!
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define BROTLI_UNALIGNED_LOAD32(_p) (*(const uint32_t *)(_p))
|
|
||||||
#define BROTLI_UNALIGNED_LOAD64LE(_p) (*(const uint64_t *)(_p))
|
|
||||||
|
|
||||||
#define BROTLI_UNALIGNED_STORE64LE(_p, _val) \
|
|
||||||
(*(uint64_t *)(_p) = (_val))
|
|
||||||
|
|
||||||
#elif defined(BROTLI_LITTLE_ENDIAN) && defined(__arm__) && \
|
|
||||||
!defined(__ARM_ARCH_5__) && \
|
|
||||||
!defined(__ARM_ARCH_5T__) && \
|
|
||||||
!defined(__ARM_ARCH_5TE__) && \
|
|
||||||
!defined(__ARM_ARCH_5TEJ__) && \
|
|
||||||
!defined(__ARM_ARCH_6__) && \
|
|
||||||
!defined(__ARM_ARCH_6J__) && \
|
|
||||||
!defined(__ARM_ARCH_6K__) && \
|
|
||||||
!defined(__ARM_ARCH_6Z__) && \
|
|
||||||
!defined(__ARM_ARCH_6ZK__) && \
|
|
||||||
!defined(__ARM_ARCH_6T2__)
|
|
||||||
|
|
||||||
/* ARMv7 and newer support native unaligned accesses, but only of 16-bit
|
|
||||||
and 32-bit values (not 64-bit); older versions either raise a fatal signal,
|
|
||||||
do an unaligned read and rotate the words around a bit, or do the reads very
|
|
||||||
slowly (trip through kernel mode). */
|
|
||||||
|
|
||||||
#define BROTLI_UNALIGNED_LOAD32(_p) (*(const uint32_t *)(_p))
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void *p) {
|
|
||||||
uint64_t t;
|
|
||||||
memcpy(&t, p, sizeof t);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void *p, uint64_t v) {
|
|
||||||
memcpy(p, &v, sizeof v);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
/* These functions are provided for architectures that don't support */
|
|
||||||
/* unaligned loads and stores. */
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32(const void *p) {
|
|
||||||
uint32_t t;
|
|
||||||
memcpy(&t, p, sizeof t);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(BROTLI_LITTLE_ENDIAN)
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void *p) {
|
|
||||||
uint64_t t;
|
|
||||||
memcpy(&t, p, sizeof t);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void *p, uint64_t v) {
|
|
||||||
memcpy(p, &v, sizeof v);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* BROTLI_LITTLE_ENDIAN */
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void *p) {
|
|
||||||
const uint8_t* in = (const uint8_t*)p;
|
|
||||||
uint64_t value = (uint64_t)(in[0]);
|
|
||||||
value |= (uint64_t)(in[1]) << 8;
|
|
||||||
value |= (uint64_t)(in[2]) << 16;
|
|
||||||
value |= (uint64_t)(in[3]) << 24;
|
|
||||||
value |= (uint64_t)(in[4]) << 32;
|
|
||||||
value |= (uint64_t)(in[5]) << 40;
|
|
||||||
value |= (uint64_t)(in[6]) << 48;
|
|
||||||
value |= (uint64_t)(in[7]) << 56;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void *p, uint64_t v) {
|
|
||||||
uint8_t* out = (uint8_t*)p;
|
|
||||||
out[0] = (uint8_t)v;
|
|
||||||
out[1] = (uint8_t)(v >> 8);
|
|
||||||
out[2] = (uint8_t)(v >> 16);
|
|
||||||
out[3] = (uint8_t)(v >> 24);
|
|
||||||
out[4] = (uint8_t)(v >> 32);
|
|
||||||
out[5] = (uint8_t)(v >> 40);
|
|
||||||
out[6] = (uint8_t)(v >> 48);
|
|
||||||
out[7] = (uint8_t)(v >> 56);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* BROTLI_LITTLE_ENDIAN */
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TEMPLATE_(T) \
|
|
||||||
static BROTLI_INLINE T brotli_min_ ## T (T a, T b) { return a < b ? a : b; } \
|
|
||||||
static BROTLI_INLINE T brotli_max_ ## T (T a, T b) { return a > b ? a : b; }
|
|
||||||
TEMPLATE_(double) TEMPLATE_(float) TEMPLATE_(int)
|
|
||||||
TEMPLATE_(size_t) TEMPLATE_(uint32_t) TEMPLATE_(uint8_t)
|
|
||||||
#undef TEMPLATE_
|
|
||||||
#define BROTLI_MIN(T, A, B) (brotli_min_ ## T((A), (B)))
|
|
||||||
#define BROTLI_MAX(T, A, B) (brotli_max_ ## T((A), (B)))
|
|
||||||
|
|
||||||
#define BROTLI_SWAP(T, A, I, J) { \
|
|
||||||
T __brotli_swap_tmp = (A)[(I)]; \
|
|
||||||
(A)[(I)] = (A)[(J)]; \
|
|
||||||
(A)[(J)] = __brotli_swap_tmp; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) { \
|
|
||||||
if (C < (R)) { \
|
|
||||||
size_t _new_size = (C == 0) ? (R) : C; \
|
|
||||||
T* new_array; \
|
|
||||||
while (_new_size < (R)) _new_size *= 2; \
|
|
||||||
new_array = BROTLI_ALLOC((M), T, _new_size); \
|
|
||||||
if (!BROTLI_IS_OOM(m) && C != 0) \
|
|
||||||
memcpy(new_array, A, C * sizeof(T)); \
|
|
||||||
BROTLI_FREE((M), A); \
|
|
||||||
A = new_array; \
|
|
||||||
C = _new_size; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* BROTLI_ENC_PORT_H_ */
|
|
|
@ -11,7 +11,7 @@
|
||||||
#define BROTLI_ENC_PREFIX_H_
|
#define BROTLI_ENC_PREFIX_H_
|
||||||
|
|
||||||
#include "../common/constants.h"
|
#include "../common/constants.h"
|
||||||
#include <brotli/port.h>
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./fast_log.h"
|
#include "./fast_log.h"
|
||||||
|
|
||||||
|
@ -39,11 +39,10 @@ static BROTLI_INLINE void PrefixEncodeCopyDistance(size_t distance_code,
|
||||||
size_t prefix = (dist >> bucket) & 1;
|
size_t prefix = (dist >> bucket) & 1;
|
||||||
size_t offset = (2 + prefix) << bucket;
|
size_t offset = (2 + prefix) << bucket;
|
||||||
size_t nbits = bucket - postfix_bits;
|
size_t nbits = bucket - postfix_bits;
|
||||||
*code = (uint16_t)(
|
*code = (uint16_t)((nbits << 10) |
|
||||||
(BROTLI_NUM_DISTANCE_SHORT_CODES + num_direct_codes +
|
(BROTLI_NUM_DISTANCE_SHORT_CODES + num_direct_codes +
|
||||||
((2 * (nbits - 1) + prefix) << postfix_bits) + postfix));
|
((2 * (nbits - 1) + prefix) << postfix_bits) + postfix));
|
||||||
*extra_bits = (uint32_t)(
|
*extra_bits = (uint32_t)((dist - offset) >> postfix_bits);
|
||||||
(nbits << 24) | ((dist - offset) >> postfix_bits));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
#ifndef BROTLI_ENC_QUALITY_H_
|
#ifndef BROTLI_ENC_QUALITY_H_
|
||||||
#define BROTLI_ENC_QUALITY_H_
|
#define BROTLI_ENC_QUALITY_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/encode.h>
|
#include <brotli/encode.h>
|
||||||
|
#include "./params.h"
|
||||||
|
|
||||||
#define FAST_ONE_PASS_COMPRESSION_QUALITY 0
|
#define FAST_ONE_PASS_COMPRESSION_QUALITY 0
|
||||||
#define FAST_TWO_PASS_COMPRESSION_QUALITY 1
|
#define FAST_TWO_PASS_COMPRESSION_QUALITY 1
|
||||||
|
@ -19,36 +21,16 @@
|
||||||
|
|
||||||
#define MAX_QUALITY_FOR_STATIC_ENTROPY_CODES 2
|
#define MAX_QUALITY_FOR_STATIC_ENTROPY_CODES 2
|
||||||
#define MIN_QUALITY_FOR_BLOCK_SPLIT 4
|
#define MIN_QUALITY_FOR_BLOCK_SPLIT 4
|
||||||
|
#define MIN_QUALITY_FOR_NONZERO_DISTANCE_PARAMS 4
|
||||||
#define MIN_QUALITY_FOR_OPTIMIZE_HISTOGRAMS 4
|
#define MIN_QUALITY_FOR_OPTIMIZE_HISTOGRAMS 4
|
||||||
#define MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH 5
|
#define MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH 5
|
||||||
#define MIN_QUALITY_FOR_CONTEXT_MODELING 5
|
#define MIN_QUALITY_FOR_CONTEXT_MODELING 5
|
||||||
#define MIN_QUALITY_FOR_HQ_CONTEXT_MODELING 7
|
#define MIN_QUALITY_FOR_HQ_CONTEXT_MODELING 7
|
||||||
#define MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING 10
|
#define MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING 10
|
||||||
/* Only for "font" mode. */
|
|
||||||
#define MIN_QUALITY_FOR_RECOMPUTE_DISTANCE_PREFIXES 10
|
|
||||||
|
|
||||||
/* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting,
|
/* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting,
|
||||||
so we buffer at most this much literals and commands. */
|
so we buffer at most this much literals and commands. */
|
||||||
#define MAX_NUM_DELAYED_SYMBOLS 0x2fff
|
#define MAX_NUM_DELAYED_SYMBOLS 0x2FFF
|
||||||
|
|
||||||
typedef struct BrotliHasherParams {
|
|
||||||
int type;
|
|
||||||
int bucket_bits;
|
|
||||||
int block_bits;
|
|
||||||
int hash_len;
|
|
||||||
int num_last_distances_to_check;
|
|
||||||
} BrotliHasherParams;
|
|
||||||
|
|
||||||
/* Encoding parameters */
|
|
||||||
typedef struct BrotliEncoderParams {
|
|
||||||
BrotliEncoderMode mode;
|
|
||||||
int quality;
|
|
||||||
int lgwin;
|
|
||||||
int lgblock;
|
|
||||||
size_t size_hint;
|
|
||||||
BROTLI_BOOL disable_literal_context_modeling;
|
|
||||||
BrotliHasherParams hasher;
|
|
||||||
} BrotliEncoderParams;
|
|
||||||
|
|
||||||
/* Returns hash-table size for quality levels 0 and 1. */
|
/* Returns hash-table size for quality levels 0 and 1. */
|
||||||
static BROTLI_INLINE size_t MaxHashTableSize(int quality) {
|
static BROTLI_INLINE size_t MaxHashTableSize(int quality) {
|
||||||
|
@ -77,10 +59,15 @@ static BROTLI_INLINE size_t MaxZopfliCandidates(
|
||||||
static BROTLI_INLINE void SanitizeParams(BrotliEncoderParams* params) {
|
static BROTLI_INLINE void SanitizeParams(BrotliEncoderParams* params) {
|
||||||
params->quality = BROTLI_MIN(int, BROTLI_MAX_QUALITY,
|
params->quality = BROTLI_MIN(int, BROTLI_MAX_QUALITY,
|
||||||
BROTLI_MAX(int, BROTLI_MIN_QUALITY, params->quality));
|
BROTLI_MAX(int, BROTLI_MIN_QUALITY, params->quality));
|
||||||
|
if (params->quality <= MAX_QUALITY_FOR_STATIC_ENTROPY_CODES) {
|
||||||
|
params->large_window = BROTLI_FALSE;
|
||||||
|
}
|
||||||
if (params->lgwin < BROTLI_MIN_WINDOW_BITS) {
|
if (params->lgwin < BROTLI_MIN_WINDOW_BITS) {
|
||||||
params->lgwin = BROTLI_MIN_WINDOW_BITS;
|
params->lgwin = BROTLI_MIN_WINDOW_BITS;
|
||||||
} else if (params->lgwin > BROTLI_MAX_WINDOW_BITS) {
|
} else {
|
||||||
params->lgwin = BROTLI_MAX_WINDOW_BITS;
|
int max_lgwin = params->large_window ? BROTLI_LARGE_MAX_WINDOW_BITS :
|
||||||
|
BROTLI_MAX_WINDOW_BITS;
|
||||||
|
if (params->lgwin > max_lgwin) params->lgwin = max_lgwin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +142,24 @@ static BROTLI_INLINE void ChooseHasher(const BrotliEncoderParams* params,
|
||||||
hparams->num_last_distances_to_check =
|
hparams->num_last_distances_to_check =
|
||||||
params->quality < 7 ? 4 : params->quality < 9 ? 10 : 16;
|
params->quality < 7 ? 4 : params->quality < 9 ? 10 : 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params->lgwin > 24) {
|
||||||
|
/* Different hashers for large window brotli: not for qualities <= 2,
|
||||||
|
these are too fast for large window. Not for qualities >= 10: their
|
||||||
|
hasher already works well with large window. So the changes are:
|
||||||
|
H3 --> H35: for quality 3.
|
||||||
|
H54 --> H55: for quality 4 with size hint > 1MB
|
||||||
|
H6 --> H65: for qualities 5, 6, 7, 8, 9. */
|
||||||
|
if (hparams->type == 3) {
|
||||||
|
hparams->type = 35;
|
||||||
|
}
|
||||||
|
if (hparams->type == 54) {
|
||||||
|
hparams->type = 55;
|
||||||
|
}
|
||||||
|
if (hparams->type == 6) {
|
||||||
|
hparams->type = 65;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* BROTLI_ENC_QUALITY_H_ */
|
#endif /* BROTLI_ENC_QUALITY_H_ */
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
|
|
||||||
#include <string.h> /* memcpy */
|
#include <string.h> /* memcpy */
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./memory.h"
|
#include "./memory.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./quality.h"
|
#include "./quality.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -41,9 +41,9 @@ typedef struct RingBuffer {
|
||||||
uint32_t pos_;
|
uint32_t pos_;
|
||||||
/* The actual ring buffer containing the copy of the last two bytes, the data,
|
/* The actual ring buffer containing the copy of the last two bytes, the data,
|
||||||
and the copy of the beginning as a tail. */
|
and the copy of the beginning as a tail. */
|
||||||
uint8_t *data_;
|
uint8_t* data_;
|
||||||
/* The start of the ring-buffer. */
|
/* The start of the ring-buffer. */
|
||||||
uint8_t *buffer_;
|
uint8_t* buffer_;
|
||||||
} RingBuffer;
|
} RingBuffer;
|
||||||
|
|
||||||
static BROTLI_INLINE void RingBufferInit(RingBuffer* rb) {
|
static BROTLI_INLINE void RingBufferInit(RingBuffer* rb) {
|
||||||
|
@ -75,7 +75,7 @@ static BROTLI_INLINE void RingBufferInitBuffer(
|
||||||
uint8_t* new_data = BROTLI_ALLOC(
|
uint8_t* new_data = BROTLI_ALLOC(
|
||||||
m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere);
|
m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere);
|
||||||
size_t i;
|
size_t i;
|
||||||
if (BROTLI_IS_OOM(m)) return;
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_data)) return;
|
||||||
if (rb->data_) {
|
if (rb->data_) {
|
||||||
memcpy(new_data, rb->data_,
|
memcpy(new_data, rb->data_,
|
||||||
2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere);
|
2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere);
|
||||||
|
@ -91,7 +91,7 @@ static BROTLI_INLINE void RingBufferInitBuffer(
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void RingBufferWriteTail(
|
static BROTLI_INLINE void RingBufferWriteTail(
|
||||||
const uint8_t *bytes, size_t n, RingBuffer* rb) {
|
const uint8_t* bytes, size_t n, RingBuffer* rb) {
|
||||||
const size_t masked_pos = rb->pos_ & rb->mask_;
|
const size_t masked_pos = rb->pos_ & rb->mask_;
|
||||||
if (BROTLI_PREDICT_FALSE(masked_pos < rb->tail_size_)) {
|
if (BROTLI_PREDICT_FALSE(masked_pos < rb->tail_size_)) {
|
||||||
/* Just fill the tail buffer with the beginning data. */
|
/* Just fill the tail buffer with the beginning data. */
|
||||||
|
@ -103,7 +103,7 @@ static BROTLI_INLINE void RingBufferWriteTail(
|
||||||
|
|
||||||
/* Push bytes into the ring buffer. */
|
/* Push bytes into the ring buffer. */
|
||||||
static BROTLI_INLINE void RingBufferWrite(
|
static BROTLI_INLINE void RingBufferWrite(
|
||||||
MemoryManager* m, const uint8_t *bytes, size_t n, RingBuffer* rb) {
|
MemoryManager* m, const uint8_t* bytes, size_t n, RingBuffer* rb) {
|
||||||
if (rb->pos_ == 0 && n < rb->tail_size_) {
|
if (rb->pos_ == 0 && n < rb->tail_size_) {
|
||||||
/* Special case for the first write: to process the first block, we don't
|
/* Special case for the first write: to process the first block, we don't
|
||||||
need to allocate the whole ring-buffer and we don't need the tail
|
need to allocate the whole ring-buffer and we don't need the tail
|
||||||
|
@ -125,6 +125,9 @@ static BROTLI_INLINE void RingBufferWrite(
|
||||||
later when we copy the last two bytes to the first two positions. */
|
later when we copy the last two bytes to the first two positions. */
|
||||||
rb->buffer_[rb->size_ - 2] = 0;
|
rb->buffer_[rb->size_ - 2] = 0;
|
||||||
rb->buffer_[rb->size_ - 1] = 0;
|
rb->buffer_[rb->size_ - 1] = 0;
|
||||||
|
/* Initialize tail; might be touched by "best_len++" optimization when
|
||||||
|
ring buffer is "full". */
|
||||||
|
rb->buffer_[rb->size_] = 241;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const size_t masked_pos = rb->pos_ & rb->mask_;
|
const size_t masked_pos = rb->pos_ & rb->mask_;
|
||||||
|
@ -144,12 +147,16 @@ static BROTLI_INLINE void RingBufferWrite(
|
||||||
n - (rb->size_ - masked_pos));
|
n - (rb->size_ - masked_pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rb->buffer_[-2] = rb->buffer_[rb->size_ - 2];
|
{
|
||||||
rb->buffer_[-1] = rb->buffer_[rb->size_ - 1];
|
BROTLI_BOOL not_first_lap = (rb->pos_ & (1u << 31)) != 0;
|
||||||
rb->pos_ += (uint32_t)n;
|
uint32_t rb_pos_mask = (1u << 31) - 1;
|
||||||
if (rb->pos_ > (1u << 30)) {
|
rb->buffer_[-2] = rb->buffer_[rb->size_ - 2];
|
||||||
/* Wrap, but preserve not-a-first-lap feature. */
|
rb->buffer_[-1] = rb->buffer_[rb->size_ - 1];
|
||||||
rb->pos_ = (rb->pos_ & ((1u << 30) - 1)) | (1u << 30);
|
rb->pos_ = (rb->pos_ & rb_pos_mask) + (uint32_t)(n & rb_pos_mask);
|
||||||
|
if (not_first_lap) {
|
||||||
|
/* Wrap, but preserve not-a-first-lap feature. */
|
||||||
|
rb->pos_ |= 1u << 31;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,21 +7,17 @@
|
||||||
#include "./static_dict.h"
|
#include "./static_dict.h"
|
||||||
|
|
||||||
#include "../common/dictionary.h"
|
#include "../common/dictionary.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
|
#include "../common/transform.h"
|
||||||
|
#include "./encoder_dict.h"
|
||||||
#include "./find_match_length.h"
|
#include "./find_match_length.h"
|
||||||
#include "./port.h"
|
|
||||||
#include "./static_dict_lut.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const uint8_t kUppercaseFirst = 10;
|
static BROTLI_INLINE uint32_t Hash(const uint8_t* data) {
|
||||||
static const uint8_t kOmitLastNTransforms[10] = {
|
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kDictHashMul32;
|
||||||
0, 12, 27, 23, 42, 63, 56, 48, 59, 64,
|
|
||||||
};
|
|
||||||
|
|
||||||
static BROTLI_INLINE uint32_t Hash(const uint8_t *data) {
|
|
||||||
uint32_t h = BROTLI_UNALIGNED_LOAD32(data) * kDictHashMul32;
|
|
||||||
/* The higher bits contain more mixture from the multiplication,
|
/* The higher bits contain more mixture from the multiplication,
|
||||||
so we take our results from there. */
|
so we take our results from there. */
|
||||||
return h >> (32 - kDictNumBits);
|
return h >> (32 - kDictNumBits);
|
||||||
|
@ -79,32 +75,33 @@ static BROTLI_INLINE BROTLI_BOOL IsMatch(const BrotliDictionary* dictionary,
|
||||||
}
|
}
|
||||||
|
|
||||||
BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||||
const BrotliDictionary* dictionary, const uint8_t* data, size_t min_length,
|
const BrotliEncoderDictionary* dictionary, const uint8_t* data,
|
||||||
size_t max_length, uint32_t* matches) {
|
size_t min_length, size_t max_length, uint32_t* matches) {
|
||||||
BROTLI_BOOL has_found_match = BROTLI_FALSE;
|
BROTLI_BOOL has_found_match = BROTLI_FALSE;
|
||||||
{
|
{
|
||||||
size_t offset = kStaticDictionaryBuckets[Hash(data)];
|
size_t offset = dictionary->buckets[Hash(data)];
|
||||||
BROTLI_BOOL end = !offset;
|
BROTLI_BOOL end = !offset;
|
||||||
while (!end) {
|
while (!end) {
|
||||||
DictWord w = kStaticDictionaryWords[offset++];
|
DictWord w = dictionary->dict_words[offset++];
|
||||||
const size_t l = w.len & 0x1F;
|
const size_t l = w.len & 0x1F;
|
||||||
const size_t n = (size_t)1 << dictionary->size_bits_by_length[l];
|
const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l];
|
||||||
const size_t id = w.idx;
|
const size_t id = w.idx;
|
||||||
end = !!(w.len & 0x80);
|
end = !!(w.len & 0x80);
|
||||||
w.len = (uint8_t)l;
|
w.len = (uint8_t)l;
|
||||||
if (w.transform == 0) {
|
if (w.transform == 0) {
|
||||||
const size_t matchlen =
|
const size_t matchlen =
|
||||||
DictMatchLength(dictionary, data, id, l, max_length);
|
DictMatchLength(dictionary->words, data, id, l, max_length);
|
||||||
const uint8_t* s;
|
const uint8_t* s;
|
||||||
size_t minlen;
|
size_t minlen;
|
||||||
size_t maxlen;
|
size_t maxlen;
|
||||||
size_t len;
|
size_t len;
|
||||||
/* Transform "" + kIdentity + "" */
|
/* Transform "" + BROTLI_TRANSFORM_IDENTITY + "" */
|
||||||
if (matchlen == l) {
|
if (matchlen == l) {
|
||||||
AddMatch(id, l, l, matches);
|
AddMatch(id, l, l, matches);
|
||||||
has_found_match = BROTLI_TRUE;
|
has_found_match = BROTLI_TRUE;
|
||||||
}
|
}
|
||||||
/* Transforms "" + kOmitLast1 + "" and "" + kOmitLast1 + "ing " */
|
/* Transforms "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "" and
|
||||||
|
"" + BROTLI_TRANSFORM_OMIT_LAST_1 + "ing " */
|
||||||
if (matchlen >= l - 1) {
|
if (matchlen >= l - 1) {
|
||||||
AddMatch(id + 12 * n, l - 1, l, matches);
|
AddMatch(id + 12 * n, l - 1, l, matches);
|
||||||
if (l + 2 < max_length &&
|
if (l + 2 < max_length &&
|
||||||
|
@ -114,19 +111,22 @@ BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||||
}
|
}
|
||||||
has_found_match = BROTLI_TRUE;
|
has_found_match = BROTLI_TRUE;
|
||||||
}
|
}
|
||||||
/* Transform "" + kOmitLastN + "" (N = 2 .. 9) */
|
/* Transform "" + BROTLI_TRANSFORM_OMIT_LAST_# + "" (# = 2 .. 9) */
|
||||||
minlen = min_length;
|
minlen = min_length;
|
||||||
if (l > 9) minlen = BROTLI_MAX(size_t, minlen, l - 9);
|
if (l > 9) minlen = BROTLI_MAX(size_t, minlen, l - 9);
|
||||||
maxlen = BROTLI_MIN(size_t, matchlen, l - 2);
|
maxlen = BROTLI_MIN(size_t, matchlen, l - 2);
|
||||||
for (len = minlen; len <= maxlen; ++len) {
|
for (len = minlen; len <= maxlen; ++len) {
|
||||||
AddMatch(id + kOmitLastNTransforms[l - len] * n, len, l, matches);
|
size_t cut = l - len;
|
||||||
|
size_t transform_id = (cut << 2) +
|
||||||
|
(size_t)((dictionary->cutoffTransforms >> (cut * 6)) & 0x3F);
|
||||||
|
AddMatch(id + transform_id * n, len, l, matches);
|
||||||
has_found_match = BROTLI_TRUE;
|
has_found_match = BROTLI_TRUE;
|
||||||
}
|
}
|
||||||
if (matchlen < l || l + 6 >= max_length) {
|
if (matchlen < l || l + 6 >= max_length) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
s = &data[l];
|
s = &data[l];
|
||||||
/* Transforms "" + kIdentity + <suffix> */
|
/* Transforms "" + BROTLI_TRANSFORM_IDENTITY + <suffix> */
|
||||||
if (s[0] == ' ') {
|
if (s[0] == ' ') {
|
||||||
AddMatch(id + n, l + 1, l, matches);
|
AddMatch(id + n, l + 1, l, matches);
|
||||||
if (s[1] == 'a') {
|
if (s[1] == 'a') {
|
||||||
|
@ -273,12 +273,13 @@ BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Set is_all_caps=0 for kUppercaseFirst and
|
/* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and
|
||||||
is_all_caps=1 otherwise (kUppercaseAll) transform. */
|
is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)
|
||||||
|
transform. */
|
||||||
const BROTLI_BOOL is_all_caps =
|
const BROTLI_BOOL is_all_caps =
|
||||||
TO_BROTLI_BOOL(w.transform != kUppercaseFirst);
|
TO_BROTLI_BOOL(w.transform != BROTLI_TRANSFORM_UPPERCASE_FIRST);
|
||||||
const uint8_t* s;
|
const uint8_t* s;
|
||||||
if (!IsMatch(dictionary, w, data, max_length)) {
|
if (!IsMatch(dictionary->words, w, data, max_length)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Transform "" + kUppercase{First,All} + "" */
|
/* Transform "" + kUppercase{First,All} + "" */
|
||||||
|
@ -323,27 +324,29 @@ BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||||
/* Transforms with prefixes " " and "." */
|
/* Transforms with prefixes " " and "." */
|
||||||
if (max_length >= 5 && (data[0] == ' ' || data[0] == '.')) {
|
if (max_length >= 5 && (data[0] == ' ' || data[0] == '.')) {
|
||||||
BROTLI_BOOL is_space = TO_BROTLI_BOOL(data[0] == ' ');
|
BROTLI_BOOL is_space = TO_BROTLI_BOOL(data[0] == ' ');
|
||||||
size_t offset = kStaticDictionaryBuckets[Hash(&data[1])];
|
size_t offset = dictionary->buckets[Hash(&data[1])];
|
||||||
BROTLI_BOOL end = !offset;
|
BROTLI_BOOL end = !offset;
|
||||||
while (!end) {
|
while (!end) {
|
||||||
DictWord w = kStaticDictionaryWords[offset++];
|
DictWord w = dictionary->dict_words[offset++];
|
||||||
const size_t l = w.len & 0x1F;
|
const size_t l = w.len & 0x1F;
|
||||||
const size_t n = (size_t)1 << dictionary->size_bits_by_length[l];
|
const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l];
|
||||||
const size_t id = w.idx;
|
const size_t id = w.idx;
|
||||||
end = !!(w.len & 0x80);
|
end = !!(w.len & 0x80);
|
||||||
w.len = (uint8_t)l;
|
w.len = (uint8_t)l;
|
||||||
if (w.transform == 0) {
|
if (w.transform == 0) {
|
||||||
const uint8_t* s;
|
const uint8_t* s;
|
||||||
if (!IsMatch(dictionary, w, &data[1], max_length - 1)) {
|
if (!IsMatch(dictionary->words, w, &data[1], max_length - 1)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Transforms " " + kIdentity + "" and "." + kIdentity + "" */
|
/* Transforms " " + BROTLI_TRANSFORM_IDENTITY + "" and
|
||||||
|
"." + BROTLI_TRANSFORM_IDENTITY + "" */
|
||||||
AddMatch(id + (is_space ? 6 : 32) * n, l + 1, l, matches);
|
AddMatch(id + (is_space ? 6 : 32) * n, l + 1, l, matches);
|
||||||
has_found_match = BROTLI_TRUE;
|
has_found_match = BROTLI_TRUE;
|
||||||
if (l + 2 >= max_length) {
|
if (l + 2 >= max_length) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Transforms " " + kIdentity + <suffix> and "." + kIdentity + <suffix>
|
/* Transforms " " + BROTLI_TRANSFORM_IDENTITY + <suffix> and
|
||||||
|
"." + BROTLI_TRANSFORM_IDENTITY + <suffix>
|
||||||
*/
|
*/
|
||||||
s = &data[l + 1];
|
s = &data[l + 1];
|
||||||
if (s[0] == ' ') {
|
if (s[0] == ' ') {
|
||||||
|
@ -370,12 +373,13 @@ BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (is_space) {
|
} else if (is_space) {
|
||||||
/* Set is_all_caps=0 for kUppercaseFirst and
|
/* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and
|
||||||
is_all_caps=1 otherwise (kUppercaseAll) transform. */
|
is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)
|
||||||
|
transform. */
|
||||||
const BROTLI_BOOL is_all_caps =
|
const BROTLI_BOOL is_all_caps =
|
||||||
TO_BROTLI_BOOL(w.transform != kUppercaseFirst);
|
TO_BROTLI_BOOL(w.transform != BROTLI_TRANSFORM_UPPERCASE_FIRST);
|
||||||
const uint8_t* s;
|
const uint8_t* s;
|
||||||
if (!IsMatch(dictionary, w, &data[1], max_length - 1)) {
|
if (!IsMatch(dictionary->words, w, &data[1], max_length - 1)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Transforms " " + kUppercase{First,All} + "" */
|
/* Transforms " " + kUppercase{First,All} + "" */
|
||||||
|
@ -411,22 +415,22 @@ BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (max_length >= 6) {
|
if (max_length >= 6) {
|
||||||
/* Transforms with prefixes "e ", "s ", ", " and "\xc2\xa0" */
|
/* Transforms with prefixes "e ", "s ", ", " and "\xC2\xA0" */
|
||||||
if ((data[1] == ' ' &&
|
if ((data[1] == ' ' &&
|
||||||
(data[0] == 'e' || data[0] == 's' || data[0] == ',')) ||
|
(data[0] == 'e' || data[0] == 's' || data[0] == ',')) ||
|
||||||
(data[0] == 0xc2 && data[1] == 0xa0)) {
|
(data[0] == 0xC2 && data[1] == 0xA0)) {
|
||||||
size_t offset = kStaticDictionaryBuckets[Hash(&data[2])];
|
size_t offset = dictionary->buckets[Hash(&data[2])];
|
||||||
BROTLI_BOOL end = !offset;
|
BROTLI_BOOL end = !offset;
|
||||||
while (!end) {
|
while (!end) {
|
||||||
DictWord w = kStaticDictionaryWords[offset++];
|
DictWord w = dictionary->dict_words[offset++];
|
||||||
const size_t l = w.len & 0x1F;
|
const size_t l = w.len & 0x1F;
|
||||||
const size_t n = (size_t)1 << dictionary->size_bits_by_length[l];
|
const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l];
|
||||||
const size_t id = w.idx;
|
const size_t id = w.idx;
|
||||||
end = !!(w.len & 0x80);
|
end = !!(w.len & 0x80);
|
||||||
w.len = (uint8_t)l;
|
w.len = (uint8_t)l;
|
||||||
if (w.transform == 0 &&
|
if (w.transform == 0 &&
|
||||||
IsMatch(dictionary, w, &data[2], max_length - 2)) {
|
IsMatch(dictionary->words, w, &data[2], max_length - 2)) {
|
||||||
if (data[0] == 0xc2) {
|
if (data[0] == 0xC2) {
|
||||||
AddMatch(id + 102 * n, l + 2, l, matches);
|
AddMatch(id + 102 * n, l + 2, l, matches);
|
||||||
has_found_match = BROTLI_TRUE;
|
has_found_match = BROTLI_TRUE;
|
||||||
} else if (l + 2 < max_length && data[l + 2] == ' ') {
|
} else if (l + 2 < max_length && data[l + 2] == ' ') {
|
||||||
|
@ -444,17 +448,17 @@ BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||||
data[3] == 'e' && data[4] == ' ') ||
|
data[3] == 'e' && data[4] == ' ') ||
|
||||||
(data[0] == '.' && data[1] == 'c' && data[2] == 'o' &&
|
(data[0] == '.' && data[1] == 'c' && data[2] == 'o' &&
|
||||||
data[3] == 'm' && data[4] == '/')) {
|
data[3] == 'm' && data[4] == '/')) {
|
||||||
size_t offset = kStaticDictionaryBuckets[Hash(&data[5])];
|
size_t offset = dictionary->buckets[Hash(&data[5])];
|
||||||
BROTLI_BOOL end = !offset;
|
BROTLI_BOOL end = !offset;
|
||||||
while (!end) {
|
while (!end) {
|
||||||
DictWord w = kStaticDictionaryWords[offset++];
|
DictWord w = dictionary->dict_words[offset++];
|
||||||
const size_t l = w.len & 0x1F;
|
const size_t l = w.len & 0x1F;
|
||||||
const size_t n = (size_t)1 << dictionary->size_bits_by_length[l];
|
const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l];
|
||||||
const size_t id = w.idx;
|
const size_t id = w.idx;
|
||||||
end = !!(w.len & 0x80);
|
end = !!(w.len & 0x80);
|
||||||
w.len = (uint8_t)l;
|
w.len = (uint8_t)l;
|
||||||
if (w.transform == 0 &&
|
if (w.transform == 0 &&
|
||||||
IsMatch(dictionary, w, &data[5], max_length - 5)) {
|
IsMatch(dictionary->words, w, &data[5], max_length - 5)) {
|
||||||
AddMatch(id + (data[0] == ' ' ? 41 : 72) * n, l + 5, l, matches);
|
AddMatch(id + (data[0] == ' ' ? 41 : 72) * n, l + 5, l, matches);
|
||||||
has_found_match = BROTLI_TRUE;
|
has_found_match = BROTLI_TRUE;
|
||||||
if (l + 5 < max_length) {
|
if (l + 5 < max_length) {
|
||||||
|
|
|
@ -10,15 +10,16 @@
|
||||||
#define BROTLI_ENC_STATIC_DICT_H_
|
#define BROTLI_ENC_STATIC_DICT_H_
|
||||||
|
|
||||||
#include "../common/dictionary.h"
|
#include "../common/dictionary.h"
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
#include "./encoder_dict.h"
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN 37
|
#define BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN 37
|
||||||
static const uint32_t kInvalidMatch = 0xfffffff;
|
static const uint32_t kInvalidMatch = 0xFFFFFFF;
|
||||||
|
|
||||||
/* Matches data against static dictionary words, and for each length l,
|
/* Matches data against static dictionary words, and for each length l,
|
||||||
for which a match is found, updates matches[l] to be the minimum possible
|
for which a match is found, updates matches[l] to be the minimum possible
|
||||||
|
@ -28,7 +29,7 @@ static const uint32_t kInvalidMatch = 0xfffffff;
|
||||||
matches array is at least BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1 long
|
matches array is at least BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1 long
|
||||||
all elements are initialized to kInvalidMatch */
|
all elements are initialized to kInvalidMatch */
|
||||||
BROTLI_INTERNAL BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
BROTLI_INTERNAL BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||||
const BrotliDictionary* dictionary,
|
const BrotliEncoderDictionary* dictionary,
|
||||||
const uint8_t* data, size_t min_length, size_t max_length,
|
const uint8_t* data, size_t min_length, size_t max_length,
|
||||||
uint32_t* matches);
|
uint32_t* matches);
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ typedef struct DictWord {
|
||||||
} DictWord;
|
} DictWord;
|
||||||
|
|
||||||
static const int kDictNumBits = 15;
|
static const int kDictNumBits = 15;
|
||||||
static const uint32_t kDictHashMul32 = 0x1e35a7bd;
|
static const uint32_t kDictHashMul32 = 0x1E35A7BD;
|
||||||
|
|
||||||
static const uint16_t kStaticDictionaryBuckets[32768] = {
|
static const uint16_t kStaticDictionaryBuckets[32768] = {
|
||||||
1,0,0,0,0,0,0,0,0,3,6,0,0,0,0,0,20,0,0,0,21,0,22,0,0,0,0,0,0,0,0,23,0,0,25,0,29,
|
1,0,0,0,0,0,0,0,0,3,6,0,0,0,0,0,20,0,0,0,21,0,22,0,0,0,0,0,0,0,0,23,0,0,25,0,29,
|
||||||
|
|
|
@ -25,37 +25,37 @@ static size_t BrotliParseAsUTF8(
|
||||||
}
|
}
|
||||||
/* 2-byte UTF8 */
|
/* 2-byte UTF8 */
|
||||||
if (size > 1u &&
|
if (size > 1u &&
|
||||||
(input[0] & 0xe0) == 0xc0 &&
|
(input[0] & 0xE0) == 0xC0 &&
|
||||||
(input[1] & 0xc0) == 0x80) {
|
(input[1] & 0xC0) == 0x80) {
|
||||||
*symbol = (((input[0] & 0x1f) << 6) |
|
*symbol = (((input[0] & 0x1F) << 6) |
|
||||||
(input[1] & 0x3f));
|
(input[1] & 0x3F));
|
||||||
if (*symbol > 0x7f) {
|
if (*symbol > 0x7F) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* 3-byte UFT8 */
|
/* 3-byte UFT8 */
|
||||||
if (size > 2u &&
|
if (size > 2u &&
|
||||||
(input[0] & 0xf0) == 0xe0 &&
|
(input[0] & 0xF0) == 0xE0 &&
|
||||||
(input[1] & 0xc0) == 0x80 &&
|
(input[1] & 0xC0) == 0x80 &&
|
||||||
(input[2] & 0xc0) == 0x80) {
|
(input[2] & 0xC0) == 0x80) {
|
||||||
*symbol = (((input[0] & 0x0f) << 12) |
|
*symbol = (((input[0] & 0x0F) << 12) |
|
||||||
((input[1] & 0x3f) << 6) |
|
((input[1] & 0x3F) << 6) |
|
||||||
(input[2] & 0x3f));
|
(input[2] & 0x3F));
|
||||||
if (*symbol > 0x7ff) {
|
if (*symbol > 0x7FF) {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* 4-byte UFT8 */
|
/* 4-byte UFT8 */
|
||||||
if (size > 3u &&
|
if (size > 3u &&
|
||||||
(input[0] & 0xf8) == 0xf0 &&
|
(input[0] & 0xF8) == 0xF0 &&
|
||||||
(input[1] & 0xc0) == 0x80 &&
|
(input[1] & 0xC0) == 0x80 &&
|
||||||
(input[2] & 0xc0) == 0x80 &&
|
(input[2] & 0xC0) == 0x80 &&
|
||||||
(input[3] & 0xc0) == 0x80) {
|
(input[3] & 0xC0) == 0x80) {
|
||||||
*symbol = (((input[0] & 0x07) << 18) |
|
*symbol = (((input[0] & 0x07) << 18) |
|
||||||
((input[1] & 0x3f) << 12) |
|
((input[1] & 0x3F) << 12) |
|
||||||
((input[2] & 0x3f) << 6) |
|
((input[2] & 0x3F) << 6) |
|
||||||
(input[3] & 0x3f));
|
(input[3] & 0x3F));
|
||||||
if (*symbol > 0xffff && *symbol <= 0x10ffff) {
|
if (*symbol > 0xFFFF && *symbol <= 0x10FFFF) {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ BROTLI_BOOL BrotliIsMostlyUTF8(
|
||||||
i += bytes_read;
|
i += bytes_read;
|
||||||
if (symbol < 0x110000) size_utf8 += bytes_read;
|
if (symbol < 0x110000) size_utf8 += bytes_read;
|
||||||
}
|
}
|
||||||
return TO_BROTLI_BOOL(size_utf8 > min_fraction * (double)length);
|
return TO_BROTLI_BOOL((double)size_utf8 > min_fraction * (double)length);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
#ifndef BROTLI_ENC_UTF8_UTIL_H_
|
#ifndef BROTLI_ENC_UTF8_UTIL_H_
|
||||||
#define BROTLI_ENC_UTF8_UTIL_H_
|
#define BROTLI_ENC_UTF8_UTIL_H_
|
||||||
|
|
||||||
|
#include "../common/platform.h"
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -9,18 +9,13 @@
|
||||||
#ifndef BROTLI_ENC_WRITE_BITS_H_
|
#ifndef BROTLI_ENC_WRITE_BITS_H_
|
||||||
#define BROTLI_ENC_WRITE_BITS_H_
|
#define BROTLI_ENC_WRITE_BITS_H_
|
||||||
|
|
||||||
#include <assert.h>
|
#include "../common/platform.h"
|
||||||
#include <stdio.h> /* printf */
|
|
||||||
|
|
||||||
#include <brotli/types.h>
|
#include <brotli/types.h>
|
||||||
#include "./port.h"
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*#define BIT_WRITER_DEBUG */
|
|
||||||
|
|
||||||
/* This function writes bits into bytes in increasing addresses, and within
|
/* This function writes bits into bytes in increasing addresses, and within
|
||||||
a byte least-significant-bit first.
|
a byte least-significant-bit first.
|
||||||
|
|
||||||
|
@ -31,55 +26,57 @@ extern "C" {
|
||||||
|
|
||||||
0000 0RRR 0000 0000 0000 0000
|
0000 0RRR 0000 0000 0000 0000
|
||||||
|
|
||||||
Now, we could write 5 or less bits in MSB by just sifting by 3
|
Now, we could write 5 or less bits in MSB by just shifting by 3
|
||||||
and OR'ing to BYTE-0.
|
and OR'ing to BYTE-0.
|
||||||
|
|
||||||
For n bits, we take the last 5 bits, OR that with high bits in BYTE-0,
|
For n bits, we take the last 5 bits, OR that with high bits in BYTE-0,
|
||||||
and locate the rest in BYTE+1, BYTE+2, etc. */
|
and locate the rest in BYTE+1, BYTE+2, etc. */
|
||||||
static BROTLI_INLINE void BrotliWriteBits(size_t n_bits,
|
static BROTLI_INLINE void BrotliWriteBits(size_t n_bits,
|
||||||
uint64_t bits,
|
uint64_t bits,
|
||||||
size_t * BROTLI_RESTRICT pos,
|
size_t* BROTLI_RESTRICT pos,
|
||||||
uint8_t * BROTLI_RESTRICT array) {
|
uint8_t* BROTLI_RESTRICT array) {
|
||||||
#ifdef BROTLI_LITTLE_ENDIAN
|
BROTLI_LOG(("WriteBits %2d 0x%08x%08x %10d\n", (int)n_bits,
|
||||||
|
(uint32_t)(bits >> 32), (uint32_t)(bits & 0xFFFFFFFF),
|
||||||
|
(int)*pos));
|
||||||
|
BROTLI_DCHECK((bits >> n_bits) == 0);
|
||||||
|
BROTLI_DCHECK(n_bits <= 56);
|
||||||
|
#if defined(BROTLI_LITTLE_ENDIAN)
|
||||||
/* This branch of the code can write up to 56 bits at a time,
|
/* This branch of the code can write up to 56 bits at a time,
|
||||||
7 bits are lost by being perhaps already in *p and at least
|
7 bits are lost by being perhaps already in *p and at least
|
||||||
1 bit is needed to initialize the bit-stream ahead (i.e. if 7
|
1 bit is needed to initialize the bit-stream ahead (i.e. if 7
|
||||||
bits are in *p and we write 57 bits, then the next write will
|
bits are in *p and we write 57 bits, then the next write will
|
||||||
access a byte that was never initialized). */
|
access a byte that was never initialized). */
|
||||||
uint8_t *p = &array[*pos >> 3];
|
{
|
||||||
uint64_t v = *p;
|
uint8_t* p = &array[*pos >> 3];
|
||||||
#ifdef BIT_WRITER_DEBUG
|
uint64_t v = (uint64_t)(*p); /* Zero-extend 8 to 64 bits. */
|
||||||
printf("WriteBits %2d 0x%016llx %10d\n", n_bits, bits, *pos);
|
v |= bits << (*pos & 7);
|
||||||
#endif
|
BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */
|
||||||
assert((bits >> n_bits) == 0);
|
*pos += n_bits;
|
||||||
assert(n_bits <= 56);
|
}
|
||||||
v |= bits << (*pos & 7);
|
#else
|
||||||
BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */
|
/* implicit & 0xFF is assumed for uint8_t arithmetics */
|
||||||
*pos += n_bits;
|
{
|
||||||
#else
|
uint8_t* array_pos = &array[*pos >> 3];
|
||||||
/* implicit & 0xff is assumed for uint8_t arithmetics */
|
const size_t bits_reserved_in_first_byte = (*pos & 7);
|
||||||
uint8_t *array_pos = &array[*pos >> 3];
|
size_t bits_left_to_write;
|
||||||
const size_t bits_reserved_in_first_byte = (*pos & 7);
|
bits <<= bits_reserved_in_first_byte;
|
||||||
size_t bits_left_to_write;
|
*array_pos++ |= (uint8_t)bits;
|
||||||
bits <<= bits_reserved_in_first_byte;
|
for (bits_left_to_write = n_bits + bits_reserved_in_first_byte;
|
||||||
*array_pos++ |= (uint8_t)bits;
|
bits_left_to_write >= 9;
|
||||||
for (bits_left_to_write = n_bits + bits_reserved_in_first_byte;
|
bits_left_to_write -= 8) {
|
||||||
bits_left_to_write >= 9;
|
bits >>= 8;
|
||||||
bits_left_to_write -= 8) {
|
*array_pos++ = (uint8_t)bits;
|
||||||
bits >>= 8;
|
}
|
||||||
*array_pos++ = (uint8_t)bits;
|
*array_pos = 0;
|
||||||
|
*pos += n_bits;
|
||||||
}
|
}
|
||||||
*array_pos = 0;
|
|
||||||
*pos += n_bits;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void BrotliWriteBitsPrepareStorage(
|
static BROTLI_INLINE void BrotliWriteBitsPrepareStorage(
|
||||||
size_t pos, uint8_t *array) {
|
size_t pos, uint8_t* array) {
|
||||||
#ifdef BIT_WRITER_DEBUG
|
BROTLI_LOG(("WriteBitsPrepareStorage %10d\n", (int)pos));
|
||||||
printf("WriteBitsPrepareStorage %10d\n", pos);
|
BROTLI_DCHECK((pos & 7) == 0);
|
||||||
#endif
|
|
||||||
assert((pos & 7) == 0);
|
|
||||||
array[pos >> 3] = 0;
|
array[pos >> 3] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,11 @@ typedef struct BrotliDecoderStateStruct BrotliDecoderState;
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/** Decoding error, e.g. corrupted input or memory allocation problem. */
|
/** Decoding error, e.g. corrupted input or memory allocation problem. */
|
||||||
BROTLI_DECODER_RESULT_ERROR = 0,
|
BROTLI_DECODER_RESULT_ERROR = 0,
|
||||||
/** Decoding successfully completed */
|
/** Decoding successfully completed. */
|
||||||
BROTLI_DECODER_RESULT_SUCCESS = 1,
|
BROTLI_DECODER_RESULT_SUCCESS = 1,
|
||||||
/** Partially done; should be called again with more input */
|
/** Partially done; should be called again with more input. */
|
||||||
BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT = 2,
|
BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT = 2,
|
||||||
/** Partially done; should be called again with more output */
|
/** Partially done; should be called again with more output. */
|
||||||
BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT = 3
|
BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT = 3
|
||||||
} BrotliDecoderResult;
|
} BrotliDecoderResult;
|
||||||
|
|
||||||
|
@ -83,10 +83,10 @@ typedef enum {
|
||||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, WINDOW_BITS, -13) SEPARATOR \
|
BROTLI_ERROR_CODE(_ERROR_FORMAT_, WINDOW_BITS, -13) SEPARATOR \
|
||||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_1, -14) SEPARATOR \
|
BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_1, -14) SEPARATOR \
|
||||||
BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_2, -15) SEPARATOR \
|
BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_2, -15) SEPARATOR \
|
||||||
|
BROTLI_ERROR_CODE(_ERROR_FORMAT_, DISTANCE, -16) SEPARATOR \
|
||||||
\
|
\
|
||||||
/* -16..-17 codes are reserved */ \
|
/* -17..-18 codes are reserved */ \
|
||||||
\
|
\
|
||||||
BROTLI_ERROR_CODE(_ERROR_, COMPOUND_DICTIONARY, -18) SEPARATOR \
|
|
||||||
BROTLI_ERROR_CODE(_ERROR_, DICTIONARY_NOT_SET, -19) SEPARATOR \
|
BROTLI_ERROR_CODE(_ERROR_, DICTIONARY_NOT_SET, -19) SEPARATOR \
|
||||||
BROTLI_ERROR_CODE(_ERROR_, INVALID_ARGUMENTS, -20) SEPARATOR \
|
BROTLI_ERROR_CODE(_ERROR_, INVALID_ARGUMENTS, -20) SEPARATOR \
|
||||||
\
|
\
|
||||||
|
@ -135,7 +135,11 @@ typedef enum BrotliDecoderParameter {
|
||||||
* Ring buffer is allocated according to window size, despite the real size of
|
* Ring buffer is allocated according to window size, despite the real size of
|
||||||
* the content.
|
* the content.
|
||||||
*/
|
*/
|
||||||
BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION = 0
|
BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION = 0,
|
||||||
|
/**
|
||||||
|
* Flag that determines if "Large Window Brotli" is used.
|
||||||
|
*/
|
||||||
|
BROTLI_DECODER_PARAM_LARGE_WINDOW = 1
|
||||||
} BrotliDecoderParameter;
|
} BrotliDecoderParameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,10 +163,11 @@ BROTLI_DEC_API BROTLI_BOOL BrotliDecoderSetParameter(
|
||||||
*
|
*
|
||||||
* @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the
|
* @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the
|
||||||
* case they are both zero, default memory allocators are used. @p opaque is
|
* case they are both zero, default memory allocators are used. @p opaque is
|
||||||
* passed to @p alloc_func and @p free_func when they are called.
|
* passed to @p alloc_func and @p free_func when they are called. @p free_func
|
||||||
|
* has to return without doing anything when asked to free a NULL pointer.
|
||||||
*
|
*
|
||||||
* @param alloc_func custom memory allocation function
|
* @param alloc_func custom memory allocation function
|
||||||
* @param free_func custom memory fee function
|
* @param free_func custom memory free function
|
||||||
* @param opaque custom memory manager handle
|
* @param opaque custom memory manager handle
|
||||||
* @returns @c 0 if instance can not be allocated or initialized
|
* @returns @c 0 if instance can not be allocated or initialized
|
||||||
* @returns pointer to initialized ::BrotliDecoderState otherwise
|
* @returns pointer to initialized ::BrotliDecoderState otherwise
|
||||||
|
|
|
@ -27,6 +27,11 @@ extern "C" {
|
||||||
* @note equal to @c BROTLI_MAX_DISTANCE_BITS constant.
|
* @note equal to @c BROTLI_MAX_DISTANCE_BITS constant.
|
||||||
*/
|
*/
|
||||||
#define BROTLI_MAX_WINDOW_BITS 24
|
#define BROTLI_MAX_WINDOW_BITS 24
|
||||||
|
/**
|
||||||
|
* Maximal value for ::BROTLI_PARAM_LGWIN parameter
|
||||||
|
* in "Large Window Brotli" (32-bit).
|
||||||
|
*/
|
||||||
|
#define BROTLI_LARGE_MAX_WINDOW_BITS 30
|
||||||
/** Minimal value for ::BROTLI_PARAM_LGBLOCK parameter. */
|
/** Minimal value for ::BROTLI_PARAM_LGBLOCK parameter. */
|
||||||
#define BROTLI_MIN_INPUT_BLOCK_BITS 16
|
#define BROTLI_MIN_INPUT_BLOCK_BITS 16
|
||||||
/** Maximal value for ::BROTLI_PARAM_LGBLOCK parameter. */
|
/** Maximal value for ::BROTLI_PARAM_LGBLOCK parameter. */
|
||||||
|
@ -176,7 +181,43 @@ typedef enum BrotliEncoderParameter {
|
||||||
*
|
*
|
||||||
* The default value is 0, which means that the total input size is unknown.
|
* The default value is 0, which means that the total input size is unknown.
|
||||||
*/
|
*/
|
||||||
BROTLI_PARAM_SIZE_HINT = 5
|
BROTLI_PARAM_SIZE_HINT = 5,
|
||||||
|
/**
|
||||||
|
* Flag that determines if "Large Window Brotli" is used.
|
||||||
|
*/
|
||||||
|
BROTLI_PARAM_LARGE_WINDOW = 6,
|
||||||
|
/**
|
||||||
|
* Recommended number of postfix bits (NPOSTFIX).
|
||||||
|
*
|
||||||
|
* Encoder may change this value.
|
||||||
|
*
|
||||||
|
* Range is from 0 to ::BROTLI_MAX_NPOSTFIX.
|
||||||
|
*/
|
||||||
|
BROTLI_PARAM_NPOSTFIX = 7,
|
||||||
|
/**
|
||||||
|
* Recommended number of direct distance codes (NDIRECT).
|
||||||
|
*
|
||||||
|
* Encoder may change this value.
|
||||||
|
*
|
||||||
|
* Range is from 0 to (15 << NPOSTFIX) in steps of (1 << NPOSTFIX).
|
||||||
|
*/
|
||||||
|
BROTLI_PARAM_NDIRECT = 8,
|
||||||
|
/**
|
||||||
|
* Number of bytes of input stream already processed by a different instance.
|
||||||
|
*
|
||||||
|
* @note It is important to configure all the encoder instances with same
|
||||||
|
* parameters (except this one) in order to allow all the encoded parts
|
||||||
|
* obey the same restrictions implied by header.
|
||||||
|
*
|
||||||
|
* If offset is not 0, then stream header is omitted.
|
||||||
|
* In any case output start is byte aligned, so for proper streams stitching
|
||||||
|
* "predecessor" stream must be flushed.
|
||||||
|
*
|
||||||
|
* Range is not artificially limited, but all the values greater or equal to
|
||||||
|
* maximal window size have the same effect. Values greater than 2**30 are not
|
||||||
|
* allowed.
|
||||||
|
*/
|
||||||
|
BROTLI_PARAM_STREAM_OFFSET = 9
|
||||||
} BrotliEncoderParameter;
|
} BrotliEncoderParameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -209,10 +250,11 @@ BROTLI_ENC_API BROTLI_BOOL BrotliEncoderSetParameter(
|
||||||
*
|
*
|
||||||
* @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the
|
* @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the
|
||||||
* case they are both zero, default memory allocators are used. @p opaque is
|
* case they are both zero, default memory allocators are used. @p opaque is
|
||||||
* passed to @p alloc_func and @p free_func when they are called.
|
* passed to @p alloc_func and @p free_func when they are called. @p free_func
|
||||||
|
* has to return without doing anything when asked to free a NULL pointer.
|
||||||
*
|
*
|
||||||
* @param alloc_func custom memory allocation function
|
* @param alloc_func custom memory allocation function
|
||||||
* @param free_func custom memory fee function
|
* @param free_func custom memory free function
|
||||||
* @param opaque custom memory manager handle
|
* @param opaque custom memory manager handle
|
||||||
* @returns @c 0 if instance can not be allocated or initialized
|
* @returns @c 0 if instance can not be allocated or initialized
|
||||||
* @returns pointer to initialized ::BrotliEncoderState otherwise
|
* @returns pointer to initialized ::BrotliEncoderState otherwise
|
||||||
|
@ -230,10 +272,9 @@ BROTLI_ENC_API void BrotliEncoderDestroyInstance(BrotliEncoderState* state);
|
||||||
/**
|
/**
|
||||||
* Calculates the output size bound for the given @p input_size.
|
* Calculates the output size bound for the given @p input_size.
|
||||||
*
|
*
|
||||||
* @warning Result is not applicable to ::BrotliEncoderCompressStream output,
|
* @warning Result is only valid if quality is at least @c 2 and, in
|
||||||
* because every "flush" adds extra overhead bytes, and some encoder
|
* case ::BrotliEncoderCompressStream was used, no flushes
|
||||||
* settings (e.g. quality @c 0 and @c 1) might imply a "soft flush"
|
* (::BROTLI_OPERATION_FLUSH) were performed.
|
||||||
* after every chunk of input.
|
|
||||||
*
|
*
|
||||||
* @param input_size size of projected input
|
* @param input_size size of projected input
|
||||||
* @returns @c 0 if result does not fit @c size_t
|
* @returns @c 0 if result does not fit @c size_t
|
||||||
|
@ -249,6 +290,11 @@ BROTLI_ENC_API size_t BrotliEncoderMaxCompressedSize(size_t input_size);
|
||||||
* @note If ::BrotliEncoderMaxCompressedSize(@p input_size) returns non-zero
|
* @note If ::BrotliEncoderMaxCompressedSize(@p input_size) returns non-zero
|
||||||
* value, then output is guaranteed to be no longer than that.
|
* value, then output is guaranteed to be no longer than that.
|
||||||
*
|
*
|
||||||
|
* @note If @p lgwin is greater than ::BROTLI_MAX_WINDOW_BITS then resulting
|
||||||
|
* stream might be incompatible with RFC 7932; to decode such streams,
|
||||||
|
* decoder should be configured with
|
||||||
|
* ::BROTLI_DECODER_PARAM_LARGE_WINDOW = @c 1
|
||||||
|
*
|
||||||
* @param quality quality parameter value, e.g. ::BROTLI_DEFAULT_QUALITY
|
* @param quality quality parameter value, e.g. ::BROTLI_DEFAULT_QUALITY
|
||||||
* @param lgwin lgwin parameter value, e.g. ::BROTLI_DEFAULT_WINDOW
|
* @param lgwin lgwin parameter value, e.g. ::BROTLI_DEFAULT_WINDOW
|
||||||
* @param mode mode parameter value, e.g. ::BROTLI_DEFAULT_MODE
|
* @param mode mode parameter value, e.g. ::BROTLI_DEFAULT_MODE
|
||||||
|
@ -283,7 +329,7 @@ BROTLI_ENC_API BROTLI_BOOL BrotliEncoderCompress(
|
||||||
* that amount.
|
* that amount.
|
||||||
*
|
*
|
||||||
* @p total_out, if it is not a null-pointer, will be set to the number
|
* @p total_out, if it is not a null-pointer, will be set to the number
|
||||||
* of bytes decompressed since the last @p state initialization.
|
* of bytes compressed since the last @p state initialization.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
|
|
@ -4,90 +4,261 @@
|
||||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Macros for compiler / platform specific features and build options. */
|
/* Macros for compiler / platform specific API declarations. */
|
||||||
|
|
||||||
#ifndef BROTLI_COMMON_PORT_H_
|
#ifndef BROTLI_COMMON_PORT_H_
|
||||||
#define BROTLI_COMMON_PORT_H_
|
#define BROTLI_COMMON_PORT_H_
|
||||||
|
|
||||||
/* Compatibility with non-clang compilers. */
|
/* The following macros were borrowed from https://github.com/nemequ/hedley
|
||||||
#ifndef __has_builtin
|
* with permission of original author - Evan Nemerson <evan@nemerson.com> */
|
||||||
#define __has_builtin(x) 0
|
|
||||||
|
/* >>> >>> >>> hedley macros */
|
||||||
|
|
||||||
|
#define BROTLI_MAKE_VERSION(major, minor, revision) \
|
||||||
|
(((major) * 1000000) + ((minor) * 1000) + (revision))
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)
|
||||||
|
#define BROTLI_GNUC_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define BROTLI_GNUC_VERSION BROTLI_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __has_attribute
|
#if defined(BROTLI_GNUC_VERSION)
|
||||||
#define __has_attribute(x) 0
|
#define BROTLI_GNUC_VERSION_CHECK(major, minor, patch) \
|
||||||
#endif
|
(BROTLI_GNUC_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
|
||||||
|
|
||||||
#ifndef __has_feature
|
|
||||||
#define __has_feature(x) 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
|
|
||||||
#define BROTLI_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
|
||||||
#else
|
#else
|
||||||
#define BROTLI_GCC_VERSION 0
|
#define BROTLI_GNUC_VERSION_CHECK(major, minor, patch) (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__ICC)
|
#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000)
|
||||||
#define BROTLI_ICC_VERSION __ICC
|
#define BROTLI_MSVC_VERSION \
|
||||||
#else
|
BROTLI_MAKE_VERSION((_MSC_FULL_VER / 10000000), \
|
||||||
#define BROTLI_ICC_VERSION 0
|
(_MSC_FULL_VER % 10000000) / 100000, \
|
||||||
|
(_MSC_FULL_VER % 100000) / 100)
|
||||||
|
#elif defined(_MSC_FULL_VER)
|
||||||
|
#define BROTLI_MSVC_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION((_MSC_FULL_VER / 1000000), \
|
||||||
|
(_MSC_FULL_VER % 1000000) / 10000, \
|
||||||
|
(_MSC_FULL_VER % 10000) / 10)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define BROTLI_MSVC_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION(_MSC_VER / 100, _MSC_VER % 100, 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(BROTLI_BUILD_MODERN_COMPILER)
|
#if !defined(_MSC_VER)
|
||||||
#define BROTLI_MODERN_COMPILER 1
|
#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) (0)
|
||||||
#elif BROTLI_GCC_VERSION >= 304 || BROTLI_ICC_VERSION >= 1600
|
#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||||
#define BROTLI_MODERN_COMPILER 1
|
#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
|
||||||
|
#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||||
|
#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))
|
||||||
#else
|
#else
|
||||||
#define BROTLI_MODERN_COMPILER 0
|
#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(_MSC_VER >= ((major * 100) + (minor)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Define "BROTLI_PREDICT_TRUE" and "BROTLI_PREDICT_FALSE" macros for capable
|
#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE)
|
||||||
compilers.
|
#define BROTLI_INTEL_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION(__INTEL_COMPILER / 100, \
|
||||||
To apply compiler hint, enclose the branching condition into macros, like this:
|
__INTEL_COMPILER % 100, \
|
||||||
|
__INTEL_COMPILER_UPDATE)
|
||||||
if (BROTLI_PREDICT_TRUE(zero == 0)) {
|
#elif defined(__INTEL_COMPILER)
|
||||||
// main execution path
|
#define BROTLI_INTEL_VERSION \
|
||||||
} else {
|
BROTLI_MAKE_VERSION(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
|
||||||
// compiler should place this code outside of main execution path
|
|
||||||
}
|
|
||||||
|
|
||||||
OR:
|
|
||||||
|
|
||||||
if (BROTLI_PREDICT_FALSE(something_rare_or_unexpected_happens)) {
|
|
||||||
// compiler should place this code outside of main execution path
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_expect)
|
|
||||||
#define BROTLI_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
|
||||||
#define BROTLI_PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
|
||||||
#else
|
|
||||||
#define BROTLI_PREDICT_FALSE(x) (x)
|
|
||||||
#define BROTLI_PREDICT_TRUE(x) (x)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if BROTLI_MODERN_COMPILER || __has_attribute(always_inline)
|
#if defined(BROTLI_INTEL_VERSION)
|
||||||
#define BROTLI_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline))
|
#define BROTLI_INTEL_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(BROTLI_INTEL_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
|
||||||
#else
|
#else
|
||||||
#define BROTLI_ATTRIBUTE_ALWAYS_INLINE
|
#define BROTLI_INTEL_VERSION_CHECK(major, minor, patch) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__PGI) && \
|
||||||
|
defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)
|
||||||
|
#define BROTLI_PGI_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BROTLI_PGI_VERSION)
|
||||||
|
#define BROTLI_PGI_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(BROTLI_PGI_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
|
||||||
|
#else
|
||||||
|
#define BROTLI_PGI_VERSION_CHECK(major, minor, patch) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
|
||||||
|
#define BROTLI_SUNPRO_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION( \
|
||||||
|
(((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
|
||||||
|
(((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \
|
||||||
|
(__SUNPRO_C & 0xf) * 10)
|
||||||
|
#elif defined(__SUNPRO_C)
|
||||||
|
#define BROTLI_SUNPRO_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION((__SUNPRO_C >> 8) & 0xf, \
|
||||||
|
(__SUNPRO_C >> 4) & 0xf, \
|
||||||
|
(__SUNPRO_C) & 0xf)
|
||||||
|
#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
|
||||||
|
#define BROTLI_SUNPRO_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION( \
|
||||||
|
(((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
|
||||||
|
(((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \
|
||||||
|
(__SUNPRO_CC & 0xf) * 10)
|
||||||
|
#elif defined(__SUNPRO_CC)
|
||||||
|
#define BROTLI_SUNPRO_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION((__SUNPRO_CC >> 8) & 0xf, \
|
||||||
|
(__SUNPRO_CC >> 4) & 0xf, \
|
||||||
|
(__SUNPRO_CC) & 0xf)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BROTLI_SUNPRO_VERSION)
|
||||||
|
#define BROTLI_SUNPRO_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(BROTLI_SUNPRO_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
|
||||||
|
#else
|
||||||
|
#define BROTLI_SUNPRO_VERSION_CHECK(major, minor, patch) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)
|
||||||
|
#define BROTLI_ARM_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION((__ARMCOMPILER_VERSION / 1000000), \
|
||||||
|
(__ARMCOMPILER_VERSION % 1000000) / 10000, \
|
||||||
|
(__ARMCOMPILER_VERSION % 10000) / 100)
|
||||||
|
#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)
|
||||||
|
#define BROTLI_ARM_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION((__ARMCC_VERSION / 1000000), \
|
||||||
|
(__ARMCC_VERSION % 1000000) / 10000, \
|
||||||
|
(__ARMCC_VERSION % 10000) / 100)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BROTLI_ARM_VERSION)
|
||||||
|
#define BROTLI_ARM_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(BROTLI_ARM_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
|
||||||
|
#else
|
||||||
|
#define BROTLI_ARM_VERSION_CHECK(major, minor, patch) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ibmxl__)
|
||||||
|
#define BROTLI_IBM_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION(__ibmxl_version__, \
|
||||||
|
__ibmxl_release__, \
|
||||||
|
__ibmxl_modification__)
|
||||||
|
#elif defined(__xlC__) && defined(__xlC_ver__)
|
||||||
|
#define BROTLI_IBM_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)
|
||||||
|
#elif defined(__xlC__)
|
||||||
|
#define BROTLI_IBM_VERSION BROTLI_MAKE_VERSION(__xlC__ >> 8, __xlC__ & 0xff, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BROTLI_IBM_VERSION)
|
||||||
|
#define BROTLI_IBM_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(BROTLI_IBM_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
|
||||||
|
#else
|
||||||
|
#define BROTLI_IBM_VERSION_CHECK(major, minor, patch) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__TI_COMPILER_VERSION__)
|
||||||
|
#define BROTLI_TI_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION((__TI_COMPILER_VERSION__ / 1000000), \
|
||||||
|
(__TI_COMPILER_VERSION__ % 1000000) / 1000, \
|
||||||
|
(__TI_COMPILER_VERSION__ % 1000))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BROTLI_TI_VERSION)
|
||||||
|
#define BROTLI_TI_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(BROTLI_TI_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
|
||||||
|
#else
|
||||||
|
#define BROTLI_TI_VERSION_CHECK(major, minor, patch) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__IAR_SYSTEMS_ICC__)
|
||||||
|
#if __VER__ > 1000
|
||||||
|
#define BROTLI_IAR_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION((__VER__ / 1000000), \
|
||||||
|
(__VER__ / 1000) % 1000, \
|
||||||
|
(__VER__ % 1000))
|
||||||
|
#else
|
||||||
|
#define BROTLI_IAR_VERSION BROTLI_MAKE_VERSION(VER / 100, __VER__ % 100, 0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BROTLI_IAR_VERSION)
|
||||||
|
#define BROTLI_IAR_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(BROTLI_IAR_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
|
||||||
|
#else
|
||||||
|
#define BROTLI_IAR_VERSION_CHECK(major, minor, patch) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__TINYC__)
|
||||||
|
#define BROTLI_TINYC_VERSION \
|
||||||
|
BROTLI_MAKE_VERSION(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BROTLI_TINYC_VERSION)
|
||||||
|
#define BROTLI_TINYC_VERSION_CHECK(major, minor, patch) \
|
||||||
|
(BROTLI_TINYC_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
|
||||||
|
#else
|
||||||
|
#define BROTLI_TINYC_VERSION_CHECK(major, minor, patch) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__has_attribute)
|
||||||
|
#define BROTLI_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \
|
||||||
|
__has_attribute(attribute)
|
||||||
|
#else
|
||||||
|
#define BROTLI_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \
|
||||||
|
BROTLI_GNUC_VERSION_CHECK(major, minor, patch)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__has_builtin)
|
||||||
|
#define BROTLI_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \
|
||||||
|
__has_builtin(builtin)
|
||||||
|
#else
|
||||||
|
#define BROTLI_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \
|
||||||
|
BROTLI_GNUC_VERSION_CHECK(major, minor, patch)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__has_feature)
|
||||||
|
#define BROTLI_HAS_FEATURE(feature) __has_feature(feature)
|
||||||
|
#else
|
||||||
|
#define BROTLI_HAS_FEATURE(feature) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ADDRESS_SANITIZER) || BROTLI_HAS_FEATURE(address_sanitizer) || \
|
||||||
|
defined(THREAD_SANITIZER) || BROTLI_HAS_FEATURE(thread_sanitizer) || \
|
||||||
|
defined(MEMORY_SANITIZER) || BROTLI_HAS_FEATURE(memory_sanitizer)
|
||||||
|
#define BROTLI_SANITIZED 1
|
||||||
|
#else
|
||||||
|
#define BROTLI_SANITIZED 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
#define BROTLI_ATTRIBUTE_VISIBILITY_HIDDEN
|
#define BROTLI_PUBLIC
|
||||||
#elif BROTLI_MODERN_COMPILER || __has_attribute(visibility)
|
#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \
|
||||||
#define BROTLI_ATTRIBUTE_VISIBILITY_HIDDEN \
|
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
|
||||||
__attribute__ ((visibility ("hidden")))
|
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
|
||||||
|
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
|
||||||
|
BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \
|
||||||
|
BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
|
||||||
|
(BROTLI_TI_VERSION_CHECK(7, 3, 0) && \
|
||||||
|
defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__))
|
||||||
|
#define BROTLI_PUBLIC __attribute__ ((visibility ("default")))
|
||||||
#else
|
#else
|
||||||
#define BROTLI_ATTRIBUTE_VISIBILITY_HIDDEN
|
#define BROTLI_PUBLIC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BROTLI_INTERNAL
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
|
||||||
#define BROTLI_INTERNAL BROTLI_ATTRIBUTE_VISIBILITY_HIDDEN
|
!defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \
|
||||||
|
!defined(__PGI) && !defined(__PGIC__) && !defined(__TINYC__)
|
||||||
|
#define BROTLI_ARRAY_PARAM(name) (name)
|
||||||
|
#else
|
||||||
|
#define BROTLI_ARRAY_PARAM(name)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(BROTLI_SHARED_COMPILATION) && defined(_WIN32)
|
/* <<< <<< <<< end of hedley macros. */
|
||||||
|
|
||||||
|
#if defined(BROTLI_SHARED_COMPILATION)
|
||||||
|
#if defined(_WIN32)
|
||||||
#if defined(BROTLICOMMON_SHARED_COMPILATION)
|
#if defined(BROTLICOMMON_SHARED_COMPILATION)
|
||||||
#define BROTLI_COMMON_API __declspec(dllexport)
|
#define BROTLI_COMMON_API __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
|
@ -103,44 +274,15 @@ OR:
|
||||||
#else
|
#else
|
||||||
#define BROTLI_ENC_API __declspec(dllimport)
|
#define BROTLI_ENC_API __declspec(dllimport)
|
||||||
#endif /* BROTLIENC_SHARED_COMPILATION */
|
#endif /* BROTLIENC_SHARED_COMPILATION */
|
||||||
#else /* BROTLI_SHARED_COMPILATION && _WIN32 */
|
#else /* _WIN32 */
|
||||||
|
#define BROTLI_COMMON_API BROTLI_PUBLIC
|
||||||
|
#define BROTLI_DEC_API BROTLI_PUBLIC
|
||||||
|
#define BROTLI_ENC_API BROTLI_PUBLIC
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
#else /* BROTLI_SHARED_COMPILATION */
|
||||||
#define BROTLI_COMMON_API
|
#define BROTLI_COMMON_API
|
||||||
#define BROTLI_DEC_API
|
#define BROTLI_DEC_API
|
||||||
#define BROTLI_ENC_API
|
#define BROTLI_ENC_API
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \
|
|
||||||
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
|
|
||||||
#define BROTLI_INLINE inline BROTLI_ATTRIBUTE_ALWAYS_INLINE
|
|
||||||
#else
|
|
||||||
#define BROTLI_INLINE
|
|
||||||
#endif
|
|
||||||
#else /* _MSC_VER */
|
|
||||||
#define BROTLI_INLINE __forceinline
|
|
||||||
#endif /* _MSC_VER */
|
|
||||||
|
|
||||||
#if !defined(__cplusplus) && !defined(c_plusplus) && \
|
|
||||||
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
|
|
||||||
#define BROTLI_RESTRICT restrict
|
|
||||||
#elif BROTLI_GCC_VERSION > 295 || defined(__llvm__)
|
|
||||||
#define BROTLI_RESTRICT __restrict
|
|
||||||
#else
|
|
||||||
#define BROTLI_RESTRICT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if BROTLI_MODERN_COMPILER || __has_attribute(noinline)
|
|
||||||
#define BROTLI_NOINLINE __attribute__((noinline))
|
|
||||||
#else
|
|
||||||
#define BROTLI_NOINLINE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if BROTLI_MODERN_COMPILER || __has_attribute(deprecated)
|
|
||||||
#define BROTLI_DEPRECATED __attribute__((deprecated))
|
|
||||||
#else
|
|
||||||
#define BROTLI_DEPRECATED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BROTLI_UNUSED(X) (void)(X)
|
|
||||||
|
|
||||||
#endif /* BROTLI_COMMON_PORT_H_ */
|
#endif /* BROTLI_COMMON_PORT_H_ */
|
||||||
|
|
|
@ -80,11 +80,4 @@ typedef void* (*brotli_alloc_func)(void* opaque, size_t size);
|
||||||
*/
|
*/
|
||||||
typedef void (*brotli_free_func)(void* opaque, void* address);
|
typedef void (*brotli_free_func)(void* opaque, void* address);
|
||||||
|
|
||||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
|
|
||||||
!defined(__cplusplus) && !defined(__PGI)
|
|
||||||
#define BROTLI_ARRAY_PARAM(L) L
|
|
||||||
#else
|
|
||||||
#define BROTLI_ARRAY_PARAM(L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* BROTLI_COMMON_TYPES_H_ */
|
#endif /* BROTLI_COMMON_TYPES_H_ */
|
||||||
|
|
|
@ -19,7 +19,11 @@ EXPORTS.brotli += [
|
||||||
]
|
]
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
|
'common/constants.c',
|
||||||
|
'common/context.c',
|
||||||
'common/dictionary.c',
|
'common/dictionary.c',
|
||||||
|
'common/platform.c',
|
||||||
|
'common/transform.c',
|
||||||
'dec/bit_reader.c',
|
'dec/bit_reader.c',
|
||||||
'dec/decode.c',
|
'dec/decode.c',
|
||||||
'dec/huffman.c',
|
'dec/huffman.c',
|
||||||
|
@ -44,11 +48,14 @@ HOST_SOURCES += [
|
||||||
'enc/block_splitter.c',
|
'enc/block_splitter.c',
|
||||||
'enc/brotli_bit_stream.c',
|
'enc/brotli_bit_stream.c',
|
||||||
'enc/cluster.c',
|
'enc/cluster.c',
|
||||||
|
'enc/command.c',
|
||||||
'enc/compress_fragment.c',
|
'enc/compress_fragment.c',
|
||||||
'enc/compress_fragment_two_pass.c',
|
'enc/compress_fragment_two_pass.c',
|
||||||
'enc/dictionary_hash.c',
|
'enc/dictionary_hash.c',
|
||||||
'enc/encode.c',
|
'enc/encode.c',
|
||||||
|
'enc/encoder_dict.c',
|
||||||
'enc/entropy_encode.c',
|
'enc/entropy_encode.c',
|
||||||
|
'enc/fast_log.c',
|
||||||
'enc/histogram.c',
|
'enc/histogram.c',
|
||||||
'enc/literal_cost.c',
|
'enc/literal_cost.c',
|
||||||
'enc/memory.c',
|
'enc/memory.c',
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
|
|
||||||
/* Command line interface for Brotli library. */
|
/* Command line interface for Brotli library. */
|
||||||
|
|
||||||
|
/* Mute strerror/strcpy warnings. */
|
||||||
|
#if !defined(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -78,7 +83,7 @@ typedef enum {
|
||||||
COMMAND_VERSION
|
COMMAND_VERSION
|
||||||
} Command;
|
} Command;
|
||||||
|
|
||||||
#define DEFAULT_LGWIN 22
|
#define DEFAULT_LGWIN 24
|
||||||
#define DEFAULT_SUFFIX ".br"
|
#define DEFAULT_SUFFIX ".br"
|
||||||
#define MAX_OPTIONS 20
|
#define MAX_OPTIONS 20
|
||||||
|
|
||||||
|
@ -86,13 +91,14 @@ typedef struct {
|
||||||
/* Parameters */
|
/* Parameters */
|
||||||
int quality;
|
int quality;
|
||||||
int lgwin;
|
int lgwin;
|
||||||
|
int verbosity;
|
||||||
BROTLI_BOOL force_overwrite;
|
BROTLI_BOOL force_overwrite;
|
||||||
BROTLI_BOOL junk_source;
|
BROTLI_BOOL junk_source;
|
||||||
BROTLI_BOOL copy_stat;
|
BROTLI_BOOL copy_stat;
|
||||||
BROTLI_BOOL verbose;
|
|
||||||
BROTLI_BOOL write_to_stdout;
|
BROTLI_BOOL write_to_stdout;
|
||||||
BROTLI_BOOL test_integrity;
|
BROTLI_BOOL test_integrity;
|
||||||
BROTLI_BOOL decompress;
|
BROTLI_BOOL decompress;
|
||||||
|
BROTLI_BOOL large_window;
|
||||||
const char* output_path;
|
const char* output_path;
|
||||||
const char* suffix;
|
const char* suffix;
|
||||||
int not_input_indices[MAX_OPTIONS];
|
int not_input_indices[MAX_OPTIONS];
|
||||||
|
@ -111,8 +117,21 @@ typedef struct {
|
||||||
uint8_t* output;
|
uint8_t* output;
|
||||||
const char* current_input_path;
|
const char* current_input_path;
|
||||||
const char* current_output_path;
|
const char* current_output_path;
|
||||||
|
int64_t input_file_length; /* -1, if impossible to calculate */
|
||||||
FILE* fin;
|
FILE* fin;
|
||||||
FILE* fout;
|
FILE* fout;
|
||||||
|
|
||||||
|
/* I/O buffers */
|
||||||
|
size_t available_in;
|
||||||
|
const uint8_t* next_in;
|
||||||
|
size_t available_out;
|
||||||
|
uint8_t* next_out;
|
||||||
|
|
||||||
|
/* Reporting */
|
||||||
|
/* size_t would be large enough,
|
||||||
|
until 4GiB+ files are compressed / decompressed on 32-bit CPUs. */
|
||||||
|
size_t total_in;
|
||||||
|
size_t total_out;
|
||||||
} Context;
|
} Context;
|
||||||
|
|
||||||
/* Parse up to 5 decimal digits. */
|
/* Parse up to 5 decimal digits. */
|
||||||
|
@ -185,9 +204,10 @@ static Command ParseParams(Context* params) {
|
||||||
|
|
||||||
/* Too many options. The expected longest option list is:
|
/* Too many options. The expected longest option list is:
|
||||||
"-q 0 -w 10 -o f -D d -S b -d -f -k -n -v --", i.e. 16 items in total.
|
"-q 0 -w 10 -o f -D d -S b -d -f -k -n -v --", i.e. 16 items in total.
|
||||||
This check is an additinal guard that is never triggered, but provides an
|
This check is an additional guard that is never triggered, but provides
|
||||||
additional guard for future changes. */
|
a guard for future changes. */
|
||||||
if (next_option_index > (MAX_OPTIONS - 2)) {
|
if (next_option_index > (MAX_OPTIONS - 2)) {
|
||||||
|
fprintf(stderr, "too many options passed\n");
|
||||||
return COMMAND_INVALID;
|
return COMMAND_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,80 +233,135 @@ static Command ParseParams(Context* params) {
|
||||||
for (j = 1; j < arg_len; ++j) {
|
for (j = 1; j < arg_len; ++j) {
|
||||||
char c = arg[j];
|
char c = arg[j];
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
if (quality_set) return COMMAND_INVALID;
|
if (quality_set) {
|
||||||
|
fprintf(stderr, "quality already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
quality_set = BROTLI_TRUE;
|
quality_set = BROTLI_TRUE;
|
||||||
params->quality = c - '0';
|
params->quality = c - '0';
|
||||||
continue;
|
continue;
|
||||||
} else if (c == 'c') {
|
} else if (c == 'c') {
|
||||||
if (output_set) return COMMAND_INVALID;
|
if (output_set) {
|
||||||
|
fprintf(stderr, "write to standard output already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
output_set = BROTLI_TRUE;
|
output_set = BROTLI_TRUE;
|
||||||
params->write_to_stdout = BROTLI_TRUE;
|
params->write_to_stdout = BROTLI_TRUE;
|
||||||
continue;
|
continue;
|
||||||
} else if (c == 'd') {
|
} else if (c == 'd') {
|
||||||
if (command_set) return COMMAND_INVALID;
|
if (command_set) {
|
||||||
|
fprintf(stderr, "command already set when parsing -d\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
command_set = BROTLI_TRUE;
|
command_set = BROTLI_TRUE;
|
||||||
command = COMMAND_DECOMPRESS;
|
command = COMMAND_DECOMPRESS;
|
||||||
continue;
|
continue;
|
||||||
} else if (c == 'f') {
|
} else if (c == 'f') {
|
||||||
if (params->force_overwrite) return COMMAND_INVALID;
|
if (params->force_overwrite) {
|
||||||
|
fprintf(stderr, "force output overwrite already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
params->force_overwrite = BROTLI_TRUE;
|
params->force_overwrite = BROTLI_TRUE;
|
||||||
continue;
|
continue;
|
||||||
} else if (c == 'h') {
|
} else if (c == 'h') {
|
||||||
/* Don't parse further. */
|
/* Don't parse further. */
|
||||||
return COMMAND_HELP;
|
return COMMAND_HELP;
|
||||||
} else if (c == 'j' || c == 'k') {
|
} else if (c == 'j' || c == 'k') {
|
||||||
if (keep_set) return COMMAND_INVALID;
|
if (keep_set) {
|
||||||
|
fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
keep_set = BROTLI_TRUE;
|
keep_set = BROTLI_TRUE;
|
||||||
params->junk_source = TO_BROTLI_BOOL(c == 'j');
|
params->junk_source = TO_BROTLI_BOOL(c == 'j');
|
||||||
continue;
|
continue;
|
||||||
} else if (c == 'n') {
|
} else if (c == 'n') {
|
||||||
if (!params->copy_stat) return COMMAND_INVALID;
|
if (!params->copy_stat) {
|
||||||
|
fprintf(stderr, "argument --no-copy-stat / -n already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
params->copy_stat = BROTLI_FALSE;
|
params->copy_stat = BROTLI_FALSE;
|
||||||
continue;
|
continue;
|
||||||
} else if (c == 't') {
|
} else if (c == 't') {
|
||||||
if (command_set) return COMMAND_INVALID;
|
if (command_set) {
|
||||||
|
fprintf(stderr, "command already set when parsing -t\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
command_set = BROTLI_TRUE;
|
command_set = BROTLI_TRUE;
|
||||||
command = COMMAND_TEST_INTEGRITY;
|
command = COMMAND_TEST_INTEGRITY;
|
||||||
continue;
|
continue;
|
||||||
} else if (c == 'v') {
|
} else if (c == 'v') {
|
||||||
if (params->verbose) return COMMAND_INVALID;
|
if (params->verbosity > 0) {
|
||||||
params->verbose = BROTLI_TRUE;
|
fprintf(stderr, "argument --verbose / -v already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
|
params->verbosity = 1;
|
||||||
continue;
|
continue;
|
||||||
} else if (c == 'V') {
|
} else if (c == 'V') {
|
||||||
/* Don't parse further. */
|
/* Don't parse further. */
|
||||||
return COMMAND_VERSION;
|
return COMMAND_VERSION;
|
||||||
} else if (c == 'Z') {
|
} else if (c == 'Z') {
|
||||||
if (quality_set) return COMMAND_INVALID;
|
if (quality_set) {
|
||||||
|
fprintf(stderr, "quality already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
quality_set = BROTLI_TRUE;
|
quality_set = BROTLI_TRUE;
|
||||||
params->quality = 11;
|
params->quality = 11;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* o/q/w/D/S with parameter is expected */
|
/* o/q/w/D/S with parameter is expected */
|
||||||
if (c != 'o' && c != 'q' && c != 'w' && c != 'D' && c != 'S') {
|
if (c != 'o' && c != 'q' && c != 'w' && c != 'D' && c != 'S') {
|
||||||
|
fprintf(stderr, "invalid argument -%c\n", c);
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
|
if (j + 1 != arg_len) {
|
||||||
|
fprintf(stderr, "expected parameter for argument -%c\n", c);
|
||||||
return COMMAND_INVALID;
|
return COMMAND_INVALID;
|
||||||
}
|
}
|
||||||
if (j + 1 != arg_len) return COMMAND_INVALID;
|
|
||||||
i++;
|
i++;
|
||||||
if (i == argc || !argv[i] || argv[i][0] == 0) return COMMAND_INVALID;
|
if (i == argc || !argv[i] || argv[i][0] == 0) {
|
||||||
|
fprintf(stderr, "expected parameter for argument -%c\n", c);
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
params->not_input_indices[next_option_index++] = i;
|
params->not_input_indices[next_option_index++] = i;
|
||||||
if (c == 'o') {
|
if (c == 'o') {
|
||||||
if (output_set) return COMMAND_INVALID;
|
if (output_set) {
|
||||||
|
fprintf(stderr, "write to standard output already set (-o)\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
params->output_path = argv[i];
|
params->output_path = argv[i];
|
||||||
} else if (c == 'q') {
|
} else if (c == 'q') {
|
||||||
if (quality_set) return COMMAND_INVALID;
|
if (quality_set) {
|
||||||
|
fprintf(stderr, "quality already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
quality_set = ParseInt(argv[i], BROTLI_MIN_QUALITY,
|
quality_set = ParseInt(argv[i], BROTLI_MIN_QUALITY,
|
||||||
BROTLI_MAX_QUALITY, ¶ms->quality);
|
BROTLI_MAX_QUALITY, ¶ms->quality);
|
||||||
if (!quality_set) return COMMAND_INVALID;
|
if (!quality_set) {
|
||||||
|
fprintf(stderr, "error parsing quality value [%s]\n", argv[i]);
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
} else if (c == 'w') {
|
} else if (c == 'w') {
|
||||||
if (lgwin_set) return COMMAND_INVALID;
|
if (lgwin_set) {
|
||||||
|
fprintf(stderr, "lgwin parameter already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
lgwin_set = ParseInt(argv[i], 0,
|
lgwin_set = ParseInt(argv[i], 0,
|
||||||
BROTLI_MAX_WINDOW_BITS, ¶ms->lgwin);
|
BROTLI_MAX_WINDOW_BITS, ¶ms->lgwin);
|
||||||
if (!lgwin_set) return COMMAND_INVALID;
|
if (!lgwin_set) {
|
||||||
|
fprintf(stderr, "error parsing lgwin value [%s]\n", argv[i]);
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
|
if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"lgwin parameter (%d) smaller than the minimum (%d)\n",
|
||||||
|
params->lgwin, BROTLI_MIN_WINDOW_BITS);
|
||||||
return COMMAND_INVALID;
|
return COMMAND_INVALID;
|
||||||
}
|
}
|
||||||
} else if (c == 'S') {
|
} else if (c == 'S') {
|
||||||
if (suffix_set) return COMMAND_INVALID;
|
if (suffix_set) {
|
||||||
|
fprintf(stderr, "suffix already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
suffix_set = BROTLI_TRUE;
|
suffix_set = BROTLI_TRUE;
|
||||||
params->suffix = argv[i];
|
params->suffix = argv[i];
|
||||||
}
|
}
|
||||||
|
@ -294,41 +369,68 @@ static Command ParseParams(Context* params) {
|
||||||
} else { /* Double-dash. */
|
} else { /* Double-dash. */
|
||||||
arg = &arg[2];
|
arg = &arg[2];
|
||||||
if (strcmp("best", arg) == 0) {
|
if (strcmp("best", arg) == 0) {
|
||||||
if (quality_set) return COMMAND_INVALID;
|
if (quality_set) {
|
||||||
|
fprintf(stderr, "quality already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
quality_set = BROTLI_TRUE;
|
quality_set = BROTLI_TRUE;
|
||||||
params->quality = 11;
|
params->quality = 11;
|
||||||
} else if (strcmp("decompress", arg) == 0) {
|
} else if (strcmp("decompress", arg) == 0) {
|
||||||
if (command_set) return COMMAND_INVALID;
|
if (command_set) {
|
||||||
|
fprintf(stderr, "command already set when parsing --decompress\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
command_set = BROTLI_TRUE;
|
command_set = BROTLI_TRUE;
|
||||||
command = COMMAND_DECOMPRESS;
|
command = COMMAND_DECOMPRESS;
|
||||||
} else if (strcmp("force", arg) == 0) {
|
} else if (strcmp("force", arg) == 0) {
|
||||||
if (params->force_overwrite) return COMMAND_INVALID;
|
if (params->force_overwrite) {
|
||||||
|
fprintf(stderr, "force output overwrite already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
params->force_overwrite = BROTLI_TRUE;
|
params->force_overwrite = BROTLI_TRUE;
|
||||||
} else if (strcmp("help", arg) == 0) {
|
} else if (strcmp("help", arg) == 0) {
|
||||||
/* Don't parse further. */
|
/* Don't parse further. */
|
||||||
return COMMAND_HELP;
|
return COMMAND_HELP;
|
||||||
} else if (strcmp("keep", arg) == 0) {
|
} else if (strcmp("keep", arg) == 0) {
|
||||||
if (keep_set) return COMMAND_INVALID;
|
if (keep_set) {
|
||||||
|
fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
keep_set = BROTLI_TRUE;
|
keep_set = BROTLI_TRUE;
|
||||||
params->junk_source = BROTLI_FALSE;
|
params->junk_source = BROTLI_FALSE;
|
||||||
} else if (strcmp("no-copy-stat", arg) == 0) {
|
} else if (strcmp("no-copy-stat", arg) == 0) {
|
||||||
if (!params->copy_stat) return COMMAND_INVALID;
|
if (!params->copy_stat) {
|
||||||
|
fprintf(stderr, "argument --no-copy-stat / -n already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
params->copy_stat = BROTLI_FALSE;
|
params->copy_stat = BROTLI_FALSE;
|
||||||
} else if (strcmp("rm", arg) == 0) {
|
} else if (strcmp("rm", arg) == 0) {
|
||||||
if (keep_set) return COMMAND_INVALID;
|
if (keep_set) {
|
||||||
|
fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
keep_set = BROTLI_TRUE;
|
keep_set = BROTLI_TRUE;
|
||||||
params->junk_source = BROTLI_TRUE;
|
params->junk_source = BROTLI_TRUE;
|
||||||
} else if (strcmp("stdout", arg) == 0) {
|
} else if (strcmp("stdout", arg) == 0) {
|
||||||
if (output_set) return COMMAND_INVALID;
|
if (output_set) {
|
||||||
|
fprintf(stderr, "write to standard output already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
output_set = BROTLI_TRUE;
|
output_set = BROTLI_TRUE;
|
||||||
params->write_to_stdout = BROTLI_TRUE;
|
params->write_to_stdout = BROTLI_TRUE;
|
||||||
} else if (strcmp("test", arg) == 0) {
|
} else if (strcmp("test", arg) == 0) {
|
||||||
if (command_set) return COMMAND_INVALID;
|
if (command_set) {
|
||||||
|
fprintf(stderr, "command already set when parsing --test\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
command_set = BROTLI_TRUE;
|
command_set = BROTLI_TRUE;
|
||||||
command = COMMAND_TEST_INTEGRITY;
|
command = COMMAND_TEST_INTEGRITY;
|
||||||
} else if (strcmp("verbose", arg) == 0) {
|
} else if (strcmp("verbose", arg) == 0) {
|
||||||
if (params->verbose) return COMMAND_INVALID;
|
if (params->verbosity > 0) {
|
||||||
params->verbose = BROTLI_TRUE;
|
fprintf(stderr, "argument --verbose / -v already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
|
params->verbosity = 1;
|
||||||
} else if (strcmp("version", arg) == 0) {
|
} else if (strcmp("version", arg) == 0) {
|
||||||
/* Don't parse further. */
|
/* Don't parse further. */
|
||||||
return COMMAND_VERSION;
|
return COMMAND_VERSION;
|
||||||
|
@ -336,30 +438,74 @@ static Command ParseParams(Context* params) {
|
||||||
/* key=value */
|
/* key=value */
|
||||||
const char* value = strrchr(arg, '=');
|
const char* value = strrchr(arg, '=');
|
||||||
size_t key_len;
|
size_t key_len;
|
||||||
if (!value || value[1] == 0) return COMMAND_INVALID;
|
if (!value || value[1] == 0) {
|
||||||
|
fprintf(stderr, "must pass the parameter as --%s=value\n", arg);
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
key_len = (size_t)(value - arg);
|
key_len = (size_t)(value - arg);
|
||||||
value++;
|
value++;
|
||||||
if (strncmp("lgwin", arg, key_len) == 0) {
|
if (strncmp("lgwin", arg, key_len) == 0) {
|
||||||
if (lgwin_set) return COMMAND_INVALID;
|
if (lgwin_set) {
|
||||||
|
fprintf(stderr, "lgwin parameter already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
lgwin_set = ParseInt(value, 0,
|
lgwin_set = ParseInt(value, 0,
|
||||||
BROTLI_MAX_WINDOW_BITS, ¶ms->lgwin);
|
BROTLI_MAX_WINDOW_BITS, ¶ms->lgwin);
|
||||||
if (!lgwin_set) return COMMAND_INVALID;
|
if (!lgwin_set) {
|
||||||
|
fprintf(stderr, "error parsing lgwin value [%s]\n", value);
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
|
if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"lgwin parameter (%d) smaller than the minimum (%d)\n",
|
||||||
|
params->lgwin, BROTLI_MIN_WINDOW_BITS);
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
|
} else if (strncmp("large_window", arg, key_len) == 0) {
|
||||||
|
/* This option is intentionally not mentioned in help. */
|
||||||
|
if (lgwin_set) {
|
||||||
|
fprintf(stderr, "lgwin parameter already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
|
lgwin_set = ParseInt(value, 0,
|
||||||
|
BROTLI_LARGE_MAX_WINDOW_BITS, ¶ms->lgwin);
|
||||||
|
if (!lgwin_set) {
|
||||||
|
fprintf(stderr, "error parsing lgwin value [%s]\n", value);
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
|
if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"lgwin parameter (%d) smaller than the minimum (%d)\n",
|
||||||
|
params->lgwin, BROTLI_MIN_WINDOW_BITS);
|
||||||
return COMMAND_INVALID;
|
return COMMAND_INVALID;
|
||||||
}
|
}
|
||||||
} else if (strncmp("output", arg, key_len) == 0) {
|
} else if (strncmp("output", arg, key_len) == 0) {
|
||||||
if (output_set) return COMMAND_INVALID;
|
if (output_set) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"write to standard output already set (--output)\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
params->output_path = value;
|
params->output_path = value;
|
||||||
} else if (strncmp("quality", arg, key_len) == 0) {
|
} else if (strncmp("quality", arg, key_len) == 0) {
|
||||||
if (quality_set) return COMMAND_INVALID;
|
if (quality_set) {
|
||||||
|
fprintf(stderr, "quality already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
quality_set = ParseInt(value, BROTLI_MIN_QUALITY,
|
quality_set = ParseInt(value, BROTLI_MIN_QUALITY,
|
||||||
BROTLI_MAX_QUALITY, ¶ms->quality);
|
BROTLI_MAX_QUALITY, ¶ms->quality);
|
||||||
if (!quality_set) return COMMAND_INVALID;
|
if (!quality_set) {
|
||||||
|
fprintf(stderr, "error parsing quality value [%s]\n", value);
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
} else if (strncmp("suffix", arg, key_len) == 0) {
|
} else if (strncmp("suffix", arg, key_len) == 0) {
|
||||||
if (suffix_set) return COMMAND_INVALID;
|
if (suffix_set) {
|
||||||
|
fprintf(stderr, "suffix already set\n");
|
||||||
|
return COMMAND_INVALID;
|
||||||
|
}
|
||||||
suffix_set = BROTLI_TRUE;
|
suffix_set = BROTLI_TRUE;
|
||||||
params->suffix = value;
|
params->suffix = value;
|
||||||
} else {
|
} else {
|
||||||
|
fprintf(stderr, "invalid parameter: [%s]\n", arg);
|
||||||
return COMMAND_INVALID;
|
return COMMAND_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,39 +536,46 @@ static void PrintVersion(void) {
|
||||||
fprintf(stdout, "brotli %d.%d.%d\n", major, minor, patch);
|
fprintf(stdout, "brotli %d.%d.%d\n", major, minor, patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintHelp(const char* name) {
|
static void PrintHelp(const char* name, BROTLI_BOOL error) {
|
||||||
|
FILE* media = error ? stderr : stdout;
|
||||||
/* String is cut to pieces with length less than 509, to conform C90 spec. */
|
/* String is cut to pieces with length less than 509, to conform C90 spec. */
|
||||||
fprintf(stdout,
|
fprintf(media,
|
||||||
"Usage: %s [OPTION]... [FILE]...\n",
|
"Usage: %s [OPTION]... [FILE]...\n",
|
||||||
name);
|
name);
|
||||||
fprintf(stdout,
|
fprintf(media,
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -# compression level (0-9)\n"
|
" -# compression level (0-9)\n"
|
||||||
" -c, --stdout write on standard output\n"
|
" -c, --stdout write on standard output\n"
|
||||||
" -d, --decompress decompress\n"
|
" -d, --decompress decompress\n"
|
||||||
" -f, --force force output file overwrite\n"
|
" -f, --force force output file overwrite\n"
|
||||||
" -h, --help display this help and exit\n");
|
" -h, --help display this help and exit\n");
|
||||||
fprintf(stdout,
|
fprintf(media,
|
||||||
" -j, --rm remove source file(s)\n"
|
" -j, --rm remove source file(s)\n"
|
||||||
" -k, --keep keep source file(s) (default)\n"
|
" -k, --keep keep source file(s) (default)\n"
|
||||||
" -n, --no-copy-stat do not copy source file(s) attributes\n"
|
" -n, --no-copy-stat do not copy source file(s) attributes\n"
|
||||||
" -o FILE, --output=FILE output file (only if 1 input file)\n");
|
" -o FILE, --output=FILE output file (only if 1 input file)\n");
|
||||||
fprintf(stdout,
|
fprintf(media,
|
||||||
" -q NUM, --quality=NUM compression level (%d-%d)\n",
|
" -q NUM, --quality=NUM compression level (%d-%d)\n",
|
||||||
BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY);
|
BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY);
|
||||||
fprintf(stdout,
|
fprintf(media,
|
||||||
" -t, --test test compressed file integrity\n"
|
" -t, --test test compressed file integrity\n"
|
||||||
" -v, --verbose verbose mode\n");
|
" -v, --verbose verbose mode\n");
|
||||||
fprintf(stdout,
|
fprintf(media,
|
||||||
" -w NUM, --lgwin=NUM set LZ77 window size (0, %d-%d) (default:%d)\n",
|
" -w NUM, --lgwin=NUM set LZ77 window size (0, %d-%d)\n"
|
||||||
BROTLI_MIN_WINDOW_BITS, BROTLI_MAX_WINDOW_BITS, DEFAULT_LGWIN);
|
|
||||||
fprintf(stdout,
|
|
||||||
" window size = 2**NUM - 16\n"
|
" window size = 2**NUM - 16\n"
|
||||||
" 0 lets compressor choose the optimal value\n");
|
" 0 lets compressor choose the optimal value\n",
|
||||||
fprintf(stdout,
|
BROTLI_MIN_WINDOW_BITS, BROTLI_MAX_WINDOW_BITS);
|
||||||
|
fprintf(media,
|
||||||
|
" --large_window=NUM use incompatible large-window brotli\n"
|
||||||
|
" bitstream with window size (0, %d-%d)\n"
|
||||||
|
" WARNING: this format is not compatible\n"
|
||||||
|
" with brotli RFC 7932 and may not be\n"
|
||||||
|
" decodable with regular brotli decoders\n",
|
||||||
|
BROTLI_MIN_WINDOW_BITS, BROTLI_LARGE_MAX_WINDOW_BITS);
|
||||||
|
fprintf(media,
|
||||||
" -S SUF, --suffix=SUF output file suffix (default:'%s')\n",
|
" -S SUF, --suffix=SUF output file suffix (default:'%s')\n",
|
||||||
DEFAULT_SUFFIX);
|
DEFAULT_SUFFIX);
|
||||||
fprintf(stdout,
|
fprintf(media,
|
||||||
" -V, --version display version and exit\n"
|
" -V, --version display version and exit\n"
|
||||||
" -Z, --best use best compression level (11) (default)\n"
|
" -Z, --best use best compression level (11) (default)\n"
|
||||||
"Simple options could be coalesced, i.e. '-9kf' is equivalent to '-9 -k -f'.\n"
|
"Simple options could be coalesced, i.e. '-9kf' is equivalent to '-9 -k -f'.\n"
|
||||||
|
@ -473,6 +626,23 @@ static BROTLI_BOOL OpenOutputFile(const char* output_path, FILE** f,
|
||||||
return BROTLI_TRUE;
|
return BROTLI_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int64_t FileSize(const char* path) {
|
||||||
|
FILE* f = fopen(path, "rb");
|
||||||
|
int64_t retval;
|
||||||
|
if (f == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (fseek(f, 0L, SEEK_END) != 0) {
|
||||||
|
fclose(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
retval = ftell(f);
|
||||||
|
if (fclose(f) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/* Copy file times and permissions.
|
/* Copy file times and permissions.
|
||||||
TODO: this is a "best effort" implementation; honest cross-platform
|
TODO: this is a "best effort" implementation; honest cross-platform
|
||||||
fully featured implementation is way too hacky; add more hacks by request. */
|
fully featured implementation is way too hacky; add more hacks by request. */
|
||||||
|
@ -513,6 +683,8 @@ static BROTLI_BOOL NextFile(Context* context) {
|
||||||
/* Iterator points to last used arg; increment to search for the next one. */
|
/* Iterator points to last used arg; increment to search for the next one. */
|
||||||
context->iterator++;
|
context->iterator++;
|
||||||
|
|
||||||
|
context->input_file_length = -1;
|
||||||
|
|
||||||
/* No input path; read from console. */
|
/* No input path; read from console. */
|
||||||
if (context->input_count == 0) {
|
if (context->input_count == 0) {
|
||||||
if (context->iterator > 1) return BROTLI_FALSE;
|
if (context->iterator > 1) return BROTLI_FALSE;
|
||||||
|
@ -542,6 +714,7 @@ static BROTLI_BOOL NextFile(Context* context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
context->current_input_path = arg;
|
context->current_input_path = arg;
|
||||||
|
context->input_file_length = FileSize(arg);
|
||||||
context->current_output_path = context->output_path;
|
context->current_output_path = context->output_path;
|
||||||
|
|
||||||
if (context->output_path) return BROTLI_TRUE;
|
if (context->output_path) return BROTLI_TRUE;
|
||||||
|
@ -624,50 +797,111 @@ static BROTLI_BOOL CloseFiles(Context* context, BROTLI_BOOL success) {
|
||||||
return is_ok;
|
return is_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const size_t kFileBufferSize = 1 << 16;
|
static const size_t kFileBufferSize = 1 << 19;
|
||||||
|
|
||||||
|
static void InitializeBuffers(Context* context) {
|
||||||
|
context->available_in = 0;
|
||||||
|
context->next_in = NULL;
|
||||||
|
context->available_out = kFileBufferSize;
|
||||||
|
context->next_out = context->output;
|
||||||
|
context->total_in = 0;
|
||||||
|
context->total_out = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This method might give the false-negative result.
|
||||||
|
However, after an empty / incomplete read it should tell the truth. */
|
||||||
|
static BROTLI_BOOL HasMoreInput(Context* context) {
|
||||||
|
return feof(context->fin) ? BROTLI_FALSE : BROTLI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BROTLI_BOOL ProvideInput(Context* context) {
|
||||||
|
context->available_in =
|
||||||
|
fread(context->input, 1, kFileBufferSize, context->fin);
|
||||||
|
context->total_in += context->available_in;
|
||||||
|
context->next_in = context->input;
|
||||||
|
if (ferror(context->fin)) {
|
||||||
|
fprintf(stderr, "failed to read input [%s]: %s\n",
|
||||||
|
PrintablePath(context->current_input_path), strerror(errno));
|
||||||
|
return BROTLI_FALSE;
|
||||||
|
}
|
||||||
|
return BROTLI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal: should be used only in Provide-/Flush-Output. */
|
||||||
|
static BROTLI_BOOL WriteOutput(Context* context) {
|
||||||
|
size_t out_size = (size_t)(context->next_out - context->output);
|
||||||
|
context->total_out += out_size;
|
||||||
|
if (out_size == 0) return BROTLI_TRUE;
|
||||||
|
if (context->test_integrity) return BROTLI_TRUE;
|
||||||
|
|
||||||
|
fwrite(context->output, 1, out_size, context->fout);
|
||||||
|
if (ferror(context->fout)) {
|
||||||
|
fprintf(stderr, "failed to write output [%s]: %s\n",
|
||||||
|
PrintablePath(context->current_output_path), strerror(errno));
|
||||||
|
return BROTLI_FALSE;
|
||||||
|
}
|
||||||
|
return BROTLI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BROTLI_BOOL ProvideOutput(Context* context) {
|
||||||
|
if (!WriteOutput(context)) return BROTLI_FALSE;
|
||||||
|
context->available_out = kFileBufferSize;
|
||||||
|
context->next_out = context->output;
|
||||||
|
return BROTLI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BROTLI_BOOL FlushOutput(Context* context) {
|
||||||
|
if (!WriteOutput(context)) return BROTLI_FALSE;
|
||||||
|
context->available_out = 0;
|
||||||
|
return BROTLI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PrintBytes(size_t value) {
|
||||||
|
if (value < 1024) {
|
||||||
|
fprintf(stderr, "%d B", (int)value);
|
||||||
|
} else if (value < 1048576) {
|
||||||
|
fprintf(stderr, "%0.3f KiB", (double)value / 1024.0);
|
||||||
|
} else if (value < 1073741824) {
|
||||||
|
fprintf(stderr, "%0.3f MiB", (double)value / 1048576.0);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%0.3f GiB", (double)value / 1073741824.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PrintFileProcessingProgress(Context* context) {
|
||||||
|
fprintf(stderr, "[%s]: ", PrintablePath(context->current_input_path));
|
||||||
|
PrintBytes(context->total_in);
|
||||||
|
fprintf(stderr, " -> ");
|
||||||
|
PrintBytes(context->total_out);
|
||||||
|
}
|
||||||
|
|
||||||
static BROTLI_BOOL DecompressFile(Context* context, BrotliDecoderState* s) {
|
static BROTLI_BOOL DecompressFile(Context* context, BrotliDecoderState* s) {
|
||||||
size_t available_in = 0;
|
|
||||||
const uint8_t* next_in = NULL;
|
|
||||||
size_t available_out = kFileBufferSize;
|
|
||||||
uint8_t* next_out = context->output;
|
|
||||||
BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
|
BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
|
||||||
|
InitializeBuffers(context);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (next_out != context->output) {
|
|
||||||
if (!context->test_integrity) {
|
|
||||||
size_t out_size = (size_t)(next_out - context->output);
|
|
||||||
fwrite(context->output, 1, out_size, context->fout);
|
|
||||||
if (ferror(context->fout)) {
|
|
||||||
fprintf(stderr, "failed to write output [%s]: %s\n",
|
|
||||||
PrintablePath(context->current_output_path), strerror(errno));
|
|
||||||
return BROTLI_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
available_out = kFileBufferSize;
|
|
||||||
next_out = context->output;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
|
if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
|
||||||
if (feof(context->fin)) {
|
if (!HasMoreInput(context)) {
|
||||||
fprintf(stderr, "corrupt input [%s]\n",
|
fprintf(stderr, "corrupt input [%s]\n",
|
||||||
PrintablePath(context->current_input_path));
|
PrintablePath(context->current_input_path));
|
||||||
return BROTLI_FALSE;
|
return BROTLI_FALSE;
|
||||||
}
|
}
|
||||||
available_in = fread(context->input, 1, kFileBufferSize, context->fin);
|
if (!ProvideInput(context)) return BROTLI_FALSE;
|
||||||
next_in = context->input;
|
|
||||||
if (ferror(context->fin)) {
|
|
||||||
fprintf(stderr, "failed to read input [%s]: %s\n",
|
|
||||||
PrintablePath(context->current_input_path), strerror(errno));
|
|
||||||
return BROTLI_FALSE;
|
|
||||||
}
|
|
||||||
} else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
|
} else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
|
||||||
/* Nothing to do - output is already written. */
|
if (!ProvideOutput(context)) return BROTLI_FALSE;
|
||||||
} else if (result == BROTLI_DECODER_RESULT_SUCCESS) {
|
} else if (result == BROTLI_DECODER_RESULT_SUCCESS) {
|
||||||
if (available_in != 0 || !feof(context->fin)) {
|
if (!FlushOutput(context)) return BROTLI_FALSE;
|
||||||
|
int has_more_input =
|
||||||
|
(context->available_in != 0) || (fgetc(context->fin) != EOF);
|
||||||
|
if (has_more_input) {
|
||||||
fprintf(stderr, "corrupt input [%s]\n",
|
fprintf(stderr, "corrupt input [%s]\n",
|
||||||
PrintablePath(context->current_input_path));
|
PrintablePath(context->current_input_path));
|
||||||
return BROTLI_FALSE;
|
return BROTLI_FALSE;
|
||||||
}
|
}
|
||||||
|
if (context->verbosity > 0) {
|
||||||
|
fprintf(stderr, "Decompressed ");
|
||||||
|
PrintFileProcessingProgress(context);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
return BROTLI_TRUE;
|
return BROTLI_TRUE;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "corrupt input [%s]\n",
|
fprintf(stderr, "corrupt input [%s]\n",
|
||||||
|
@ -675,8 +909,8 @@ static BROTLI_BOOL DecompressFile(Context* context, BrotliDecoderState* s) {
|
||||||
return BROTLI_FALSE;
|
return BROTLI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = BrotliDecoderDecompressStream(
|
result = BrotliDecoderDecompressStream(s, &context->available_in,
|
||||||
s, &available_in, &next_in, &available_out, &next_out, 0);
|
&context->next_in, &context->available_out, &context->next_out, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,6 +922,10 @@ static BROTLI_BOOL DecompressFiles(Context* context) {
|
||||||
fprintf(stderr, "out of memory\n");
|
fprintf(stderr, "out of memory\n");
|
||||||
return BROTLI_FALSE;
|
return BROTLI_FALSE;
|
||||||
}
|
}
|
||||||
|
/* This allows decoding "large-window" streams. Though it creates
|
||||||
|
fragmentation (new builds decode streams that old builds don't),
|
||||||
|
it is better from used experience perspective. */
|
||||||
|
BrotliDecoderSetParameter(s, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1u);
|
||||||
is_ok = OpenFiles(context);
|
is_ok = OpenFiles(context);
|
||||||
if (is_ok && !context->current_input_path &&
|
if (is_ok && !context->current_input_path &&
|
||||||
!context->force_overwrite && isatty(STDIN_FILENO)) {
|
!context->force_overwrite && isatty(STDIN_FILENO)) {
|
||||||
|
@ -703,46 +941,37 @@ static BROTLI_BOOL DecompressFiles(Context* context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_BOOL CompressFile(Context* context, BrotliEncoderState* s) {
|
static BROTLI_BOOL CompressFile(Context* context, BrotliEncoderState* s) {
|
||||||
size_t available_in = 0;
|
|
||||||
const uint8_t* next_in = NULL;
|
|
||||||
size_t available_out = kFileBufferSize;
|
|
||||||
uint8_t* next_out = context->output;
|
|
||||||
BROTLI_BOOL is_eof = BROTLI_FALSE;
|
BROTLI_BOOL is_eof = BROTLI_FALSE;
|
||||||
|
InitializeBuffers(context);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (available_in == 0 && !is_eof) {
|
if (context->available_in == 0 && !is_eof) {
|
||||||
available_in = fread(context->input, 1, kFileBufferSize, context->fin);
|
if (!ProvideInput(context)) return BROTLI_FALSE;
|
||||||
next_in = context->input;
|
is_eof = !HasMoreInput(context);
|
||||||
if (ferror(context->fin)) {
|
|
||||||
fprintf(stderr, "failed to read input [%s]: %s\n",
|
|
||||||
PrintablePath(context->current_input_path), strerror(errno));
|
|
||||||
return BROTLI_FALSE;
|
|
||||||
}
|
|
||||||
is_eof = feof(context->fin) ? BROTLI_TRUE : BROTLI_FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BrotliEncoderCompressStream(s,
|
if (!BrotliEncoderCompressStream(s,
|
||||||
is_eof ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS,
|
is_eof ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS,
|
||||||
&available_in, &next_in, &available_out, &next_out, NULL)) {
|
&context->available_in, &context->next_in,
|
||||||
|
&context->available_out, &context->next_out, NULL)) {
|
||||||
/* Should detect OOM? */
|
/* Should detect OOM? */
|
||||||
fprintf(stderr, "failed to compress data [%s]\n",
|
fprintf(stderr, "failed to compress data [%s]\n",
|
||||||
PrintablePath(context->current_input_path));
|
PrintablePath(context->current_input_path));
|
||||||
return BROTLI_FALSE;
|
return BROTLI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (available_out != kFileBufferSize) {
|
if (context->available_out == 0) {
|
||||||
size_t out_size = kFileBufferSize - available_out;
|
if (!ProvideOutput(context)) return BROTLI_FALSE;
|
||||||
fwrite(context->output, 1, out_size, context->fout);
|
|
||||||
if (ferror(context->fout)) {
|
|
||||||
fprintf(stderr, "failed to write output [%s]: %s\n",
|
|
||||||
PrintablePath(context->current_output_path), strerror(errno));
|
|
||||||
return BROTLI_FALSE;
|
|
||||||
}
|
|
||||||
available_out = kFileBufferSize;
|
|
||||||
next_out = context->output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BrotliEncoderIsFinished(s)) return BROTLI_TRUE;
|
if (BrotliEncoderIsFinished(s)) {
|
||||||
|
if (!FlushOutput(context)) return BROTLI_FALSE;
|
||||||
|
if (context->verbosity > 0) {
|
||||||
|
fprintf(stderr, "Compressed ");
|
||||||
|
PrintFileProcessingProgress(context);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
return BROTLI_TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,8 +985,33 @@ static BROTLI_BOOL CompressFiles(Context* context) {
|
||||||
}
|
}
|
||||||
BrotliEncoderSetParameter(s,
|
BrotliEncoderSetParameter(s,
|
||||||
BROTLI_PARAM_QUALITY, (uint32_t)context->quality);
|
BROTLI_PARAM_QUALITY, (uint32_t)context->quality);
|
||||||
BrotliEncoderSetParameter(s,
|
if (context->lgwin > 0) {
|
||||||
BROTLI_PARAM_LGWIN, (uint32_t)context->lgwin);
|
/* Specified by user. */
|
||||||
|
/* Do not enable "large-window" extension, if not required. */
|
||||||
|
if (context->lgwin > BROTLI_MAX_WINDOW_BITS) {
|
||||||
|
BrotliEncoderSetParameter(s, BROTLI_PARAM_LARGE_WINDOW, 1u);
|
||||||
|
}
|
||||||
|
BrotliEncoderSetParameter(s,
|
||||||
|
BROTLI_PARAM_LGWIN, (uint32_t)context->lgwin);
|
||||||
|
} else {
|
||||||
|
/* 0, or not specified by user; could be chosen by compressor. */
|
||||||
|
uint32_t lgwin = DEFAULT_LGWIN;
|
||||||
|
/* Use file size to limit lgwin. */
|
||||||
|
if (context->input_file_length >= 0) {
|
||||||
|
lgwin = BROTLI_MIN_WINDOW_BITS;
|
||||||
|
while (BROTLI_MAX_BACKWARD_LIMIT(lgwin) <
|
||||||
|
(uint64_t)context->input_file_length) {
|
||||||
|
lgwin++;
|
||||||
|
if (lgwin == BROTLI_MAX_WINDOW_BITS) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, lgwin);
|
||||||
|
}
|
||||||
|
if (context->input_file_length > 0) {
|
||||||
|
uint32_t size_hint = context->input_file_length < (1 << 30) ?
|
||||||
|
(uint32_t)context->input_file_length : (1u << 30);
|
||||||
|
BrotliEncoderSetParameter(s, BROTLI_PARAM_SIZE_HINT, size_hint);
|
||||||
|
}
|
||||||
is_ok = OpenFiles(context);
|
is_ok = OpenFiles(context);
|
||||||
if (is_ok && !context->current_output_path &&
|
if (is_ok && !context->current_output_path &&
|
||||||
!context->force_overwrite && isatty(STDOUT_FILENO)) {
|
!context->force_overwrite && isatty(STDOUT_FILENO)) {
|
||||||
|
@ -779,14 +1033,15 @@ int main(int argc, char** argv) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
context.quality = 11;
|
context.quality = 11;
|
||||||
context.lgwin = DEFAULT_LGWIN;
|
context.lgwin = -1;
|
||||||
|
context.verbosity = 0;
|
||||||
context.force_overwrite = BROTLI_FALSE;
|
context.force_overwrite = BROTLI_FALSE;
|
||||||
context.junk_source = BROTLI_FALSE;
|
context.junk_source = BROTLI_FALSE;
|
||||||
context.copy_stat = BROTLI_TRUE;
|
context.copy_stat = BROTLI_TRUE;
|
||||||
context.test_integrity = BROTLI_FALSE;
|
context.test_integrity = BROTLI_FALSE;
|
||||||
context.verbose = BROTLI_FALSE;
|
|
||||||
context.write_to_stdout = BROTLI_FALSE;
|
context.write_to_stdout = BROTLI_FALSE;
|
||||||
context.decompress = BROTLI_FALSE;
|
context.decompress = BROTLI_FALSE;
|
||||||
|
context.large_window = BROTLI_FALSE;
|
||||||
context.output_path = NULL;
|
context.output_path = NULL;
|
||||||
context.suffix = DEFAULT_SUFFIX;
|
context.suffix = DEFAULT_SUFFIX;
|
||||||
for (i = 0; i < MAX_OPTIONS; ++i) context.not_input_indices[i] = 0;
|
for (i = 0; i < MAX_OPTIONS; ++i) context.not_input_indices[i] = 0;
|
||||||
|
@ -846,8 +1101,8 @@ int main(int argc, char** argv) {
|
||||||
case COMMAND_HELP:
|
case COMMAND_HELP:
|
||||||
case COMMAND_INVALID:
|
case COMMAND_INVALID:
|
||||||
default:
|
default:
|
||||||
PrintHelp(FileName(argv[0]));
|
|
||||||
is_ok = (command == COMMAND_HELP);
|
is_ok = (command == COMMAND_HELP);
|
||||||
|
PrintHelp(FileName(argv[0]), is_ok);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
# Run this within the /modules/brotli directory of the source tree.
|
# Run this within the /modules/brotli directory of the source tree.
|
||||||
|
|
||||||
MY_TEMP_DIR=`mktemp -d -t brotli_update.XXXXXX` || exit 1
|
MY_TEMP_DIR=`mktemp -d -t brotli_update.XXXXXX` || exit 1
|
||||||
|
GIT=git
|
||||||
|
|
||||||
git clone https://github.com/google/brotli ${MY_TEMP_DIR}/brotli
|
$GIT clone git://github.com/google/brotli.git ${MY_TEMP_DIR}/brotli
|
||||||
git -C ${MY_TEMP_DIR}/brotli checkout v1.0.1
|
$GIT -C ${MY_TEMP_DIR}/brotli checkout v1.0.9
|
||||||
|
|
||||||
COMMIT=$(git -C ${MY_TEMP_DIR}/brotli rev-parse HEAD)
|
COMMIT=$(${GIT} -C ${MY_TEMP_DIR}/brotli rev-parse HEAD)
|
||||||
perl -p -i -e "s/\[commit [0-9a-f]{40}\]/[commit ${COMMIT}]/" README.mozilla;
|
perl -p -i -e "s/\[commit [0-9a-f]{40}\]/[commit ${COMMIT}]/" README.mozilla;
|
||||||
|
|
||||||
DIRS="common dec enc include tools"
|
DIRS="common dec enc include tools"
|
||||||
|
@ -19,7 +20,7 @@ for d in $DIRS; do
|
||||||
done
|
done
|
||||||
rm -rf ${MY_TEMP_DIR}
|
rm -rf ${MY_TEMP_DIR}
|
||||||
|
|
||||||
hg addremove $DIRS
|
#hg addremove $DIRS
|
||||||
|
|
||||||
echo "###"
|
echo "###"
|
||||||
echo "### Updated brotli/dec to $COMMIT."
|
echo "### Updated brotli/dec to $COMMIT."
|
||||||
|
|
|
@ -11,7 +11,7 @@ The in-tree copy is updated by running
|
||||||
sh update.sh
|
sh update.sh
|
||||||
from within the modules/woff2 directory.
|
from within the modules/woff2 directory.
|
||||||
|
|
||||||
Current version: [commit e580ebc30a54becf69a75f6e6d6008536ae0c0b4].
|
Current version: [commit 3831354113db8803fb1f5ba196cf0bbb537578dd].
|
||||||
|
|
||||||
redefine-unique_ptr.patch redefines the class std::unique_ptr to workaround a
|
redefine-unique_ptr.patch redefines the class std::unique_ptr to workaround a
|
||||||
build issue with missing C++11 features.
|
build issue with missing C++11 features.
|
||||||
|
|
|
@ -131,6 +131,9 @@ bool ReadCollectionFont(Buffer* file, const uint8_t* data, size_t len,
|
||||||
(*all_tables)[table.offset] = font->FindTable(table.tag);
|
(*all_tables)[table.offset] = font->FindTable(table.tag);
|
||||||
} else {
|
} else {
|
||||||
table.reuse_of = (*all_tables)[table.offset];
|
table.reuse_of = (*all_tables)[table.offset];
|
||||||
|
if (table.tag != table.reuse_of->tag) {
|
||||||
|
return FONT_COMPRESSION_FAILURE();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,10 @@ bool MakeEditableBuffer(Font* font, int tableTag) {
|
||||||
int sz = Round4(table->length);
|
int sz = Round4(table->length);
|
||||||
table->buffer.resize(sz);
|
table->buffer.resize(sz);
|
||||||
uint8_t* buf = &table->buffer[0];
|
uint8_t* buf = &table->buffer[0];
|
||||||
memcpy(buf, table->data, sz);
|
memcpy(buf, table->data, table->length);
|
||||||
|
if (PREDICT_FALSE(sz > table->length)) {
|
||||||
|
memset(buf + table->length, 0, sz - table->length);
|
||||||
|
}
|
||||||
table->data = buf;
|
table->data = buf;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,16 @@ int WithSign(int flag, int baseval) {
|
||||||
return (flag & 1) ? baseval : -baseval;
|
return (flag & 1) ? baseval : -baseval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _SafeIntAddition(int a, int b, int* result) {
|
||||||
|
if (PREDICT_FALSE(
|
||||||
|
((a > 0) && (b > std::numeric_limits<int>::max() - a)) ||
|
||||||
|
((a < 0) && (b < std::numeric_limits<int>::min() - a)))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*result = a + b;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
|
bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
|
||||||
unsigned int n_points, Point* result, size_t* in_bytes_consumed) {
|
unsigned int n_points, Point* result, size_t* in_bytes_consumed) {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
@ -183,9 +193,12 @@ bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
|
||||||
(in[triplet_index + 2] << 8) + in[triplet_index + 3]);
|
(in[triplet_index + 2] << 8) + in[triplet_index + 3]);
|
||||||
}
|
}
|
||||||
triplet_index += n_data_bytes;
|
triplet_index += n_data_bytes;
|
||||||
// Possible overflow but coordinate values are not security sensitive
|
if (!_SafeIntAddition(x, dx, &x)) {
|
||||||
x += dx;
|
return false;
|
||||||
y += dy;
|
}
|
||||||
|
if (!_SafeIntAddition(y, dy, &y)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
*result++ = {x, y, on_curve};
|
*result++ = {x, y, on_curve};
|
||||||
}
|
}
|
||||||
*in_bytes_consumed = triplet_index;
|
*in_bytes_consumed = triplet_index;
|
||||||
|
|
|
@ -56,8 +56,11 @@ public:
|
||||||
BrotliWrapper()
|
BrotliWrapper()
|
||||||
: mTotalOut(0)
|
: mTotalOut(0)
|
||||||
, mStatus(NS_OK)
|
, mStatus(NS_OK)
|
||||||
|
, mRequest(nullptr)
|
||||||
|
, mContext(nullptr)
|
||||||
|
, mSourceOffset(0)
|
||||||
{
|
{
|
||||||
BrotliDecoderStateInit(&mState);
|
BrotliDecoderStateInit(&mState, 0, 0, 0);
|
||||||
}
|
}
|
||||||
~BrotliWrapper()
|
~BrotliWrapper()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue