Update Brotli lib to 1.0.9.
parent
f331401355
commit
14766a6c38
|
@ -11,4 +11,4 @@ The in-tree copy is updated by running
|
|||
sh update.sh
|
||||
from within the modules/brotli directory.
|
||||
|
||||
Current version: [commit d6d98957ca8ccb1ef45922e978bb10efca0ea541].
|
||||
Current version: 1.0.9 Re-release [commit e61745a6b7add50d380cfd7d3883dd6c62fc2c71].
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./constants.h"
|
||||
|
||||
const BrotliPrefixCodeRange
|
||||
_kBrotliPrefixCodeRanges[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}};
|
|
@ -4,9 +4,18 @@
|
|||
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_
|
||||
#define BROTLI_COMMON_CONSTANTS_H_
|
||||
|
||||
#include "./platform.h"
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
|
||||
/* Specification: 7.3. Encoding of the context map */
|
||||
#define BROTLI_CONTEXT_MAP_MAX_RLE 16
|
||||
|
||||
|
@ -29,12 +38,31 @@
|
|||
#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 */
|
||||
#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_NDIRECT 120
|
||||
#define BROTLI_MAX_DISTANCE_BITS 24U
|
||||
|
@ -45,9 +73,22 @@
|
|||
#define BROTLI_NUM_DISTANCE_SYMBOLS \
|
||||
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
|
||||
|
||||
/* ((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 */
|
||||
/* "context IDs for literals are in the range of 0..63" */
|
||||
#define BROTLI_LITERAL_CONTEXT_BITS 6
|
||||
|
@ -61,4 +102,99 @@
|
|||
#define BROTLI_WINDOW_GAP 16
|
||||
#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_ */
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
#include "./context.h"
|
||||
|
||||
#include <brotli/types.h>
|
||||
|
||||
/* Common context lookup table for all context modes. */
|
||||
const uint8_t _kBrotliContextLookupTable[2048] = {
|
||||
/* 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_LSB6, 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,
|
||||
|
||||
/* 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_MSB6, 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,
|
||||
|
||||
/* 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, 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_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,
|
||||
};
|
|
@ -88,6 +88,7 @@
|
|||
#ifndef BROTLI_COMMON_CONTEXT_H_
|
||||
#define BROTLI_COMMON_CONTEXT_H_
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
|
||||
typedef enum ContextType {
|
||||
|
@ -97,163 +98,14 @@ typedef enum ContextType {
|
|||
CONTEXT_SIGNED = 3
|
||||
} ContextType;
|
||||
|
||||
/* "Soft-private", it is exported, but not "advertised" as API. */
|
||||
/* Common context lookup table for all context modes. */
|
||||
static const uint8_t kContextLookup[2048] = {
|
||||
/* 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_LSB6, 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,
|
||||
|
||||
/* 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_MSB6, 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,
|
||||
|
||||
/* 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, 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_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,
|
||||
};
|
||||
BROTLI_COMMON_API extern const uint8_t _kBrotliContextLookupTable[2048];
|
||||
|
||||
typedef const uint8_t* ContextLut;
|
||||
|
||||
/* typeof(MODE) == ContextType; returns ContextLut */
|
||||
#define BROTLI_CONTEXT_LUT(MODE) (&kContextLookup[(MODE) << 9])
|
||||
#define BROTLI_CONTEXT_LUT(MODE) (&_kBrotliContextLookupTable[(MODE) << 9])
|
||||
|
||||
/* typeof(LUT) == ContextLut */
|
||||
#define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2])
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
*/
|
||||
|
||||
#include "./dictionary.h"
|
||||
#include "./platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef BROTLI_EXTERNAL_DICTIONARY_DATA
|
||||
#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||
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,
|
||||
|
@ -5862,7 +5863,11 @@ static const uint8_t kBrotliDictionaryData[] =
|
|||
;
|
||||
#endif /* !BROTLI_EXTERNAL_DICTIONARY_DATA */
|
||||
|
||||
#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||
static const BrotliDictionary kBrotliDictionary = {
|
||||
#else
|
||||
static BrotliDictionary kBrotliDictionary = {
|
||||
#endif
|
||||
/* size_bits_by_length */
|
||||
{
|
||||
0, 0, 0, 0, 10, 10, 11, 11,
|
||||
|
@ -5895,9 +5900,13 @@ const BrotliDictionary* BrotliGetDictionary() {
|
|||
}
|
||||
|
||||
void BrotliSetDictionaryData(const uint8_t* data) {
|
||||
#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||
if (!!data && !kBrotliDictionary.data) {
|
||||
kBrotliDictionary.data = data;
|
||||
}
|
||||
#else
|
||||
BROTLI_UNUSED(data); // Appease -Werror=unused-parameter
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/* Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "./platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
/* Default brotli_alloc_func */
|
||||
void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
/* Default brotli_free_func */
|
||||
void BrotliDefaultFreeFunc(void* opaque, void* address) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
free(address);
|
||||
}
|
|
@ -24,12 +24,11 @@
|
|||
#define BROTLI_COMMON_PLATFORM_H_
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_CYGWIN)
|
||||
#if defined(OS_LINUX) || defined(OS_CYGWIN) || defined(__EMSCRIPTEN__)
|
||||
#include <endian.h>
|
||||
#elif defined(OS_FREEBSD)
|
||||
#include <machine/endian.h>
|
||||
|
@ -41,6 +40,10 @@
|
|||
#define BROTLI_X_BIG_ENDIAN BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#if BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
@ -308,8 +311,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
|||
}
|
||||
#else /* BROTLI_ALIGNED_READ */
|
||||
/* Unaligned memory access is allowed: just cast pointer to requested type. */
|
||||
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
|
||||
defined(MEMORY_SANITIZER)
|
||||
#if BROTLI_SANITIZED
|
||||
/* Consider we have an unaligned load/store of 4 bytes from address 0x...05.
|
||||
AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
|
||||
will miss a bug if 08 is the first unaddressable byte.
|
||||
|
@ -334,7 +336,7 @@ extern "C" {
|
|||
#define BrotliUnalignedRead32 __sanitizer_unaligned_load32
|
||||
#define BrotliUnalignedRead64 __sanitizer_unaligned_load64
|
||||
#define BrotliUnalignedWrite64 __sanitizer_unaligned_store64
|
||||
#else
|
||||
#else /* BROTLI_SANITIZED */
|
||||
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
|
||||
return *(const uint16_t*)p;
|
||||
}
|
||||
|
@ -356,7 +358,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
|||
typedef BROTLI_ALIGNED(1) uint64_t brotli_unaligned_uint64_t;
|
||||
|
||||
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
||||
return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0];
|
||||
return (uint64_t) ((const brotli_unaligned_uint64_t*) p)[0];
|
||||
}
|
||||
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p;
|
||||
|
@ -374,7 +376,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
|||
}
|
||||
#endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
|
||||
#endif /* BROTLI_64_BITS */
|
||||
#endif /* ASAN / TSAN / MSAN */
|
||||
#endif /* BROTLI_SANITIZED */
|
||||
#endif /* BROTLI_ALIGNED_READ */
|
||||
|
||||
#if BROTLI_LITTLE_ENDIAN
|
||||
|
@ -466,20 +468,20 @@ static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
|
|||
#endif
|
||||
|
||||
#if defined(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)
|
||||
#define BROTLI_DCHECK(x) assert(x)
|
||||
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_DCHECK(x)
|
||||
#define BROTLI_DUMP() (void)(0)
|
||||
#endif
|
||||
|
||||
|
@ -523,17 +525,41 @@ BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t)
|
|||
(A)[(J)] = __brotli_swap_tmp; \
|
||||
}
|
||||
|
||||
/* Default brotli_alloc_func */
|
||||
static void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
return malloc(size);
|
||||
#if BROTLI_64_BITS
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_ctzll, 3, 4, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
#define BROTLI_TZCNT64 __builtin_ctzll
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
|
||||
#if defined(BROTLI_TARGET_X64)
|
||||
#define BROTLI_TZCNT64 _tzcnt_u64
|
||||
#else /* BROTLI_TARGET_X64 */
|
||||
static BROTLI_INLINE uint32_t BrotliBsf64Msvc(uint64_t x) {
|
||||
uint32_t lsb;
|
||||
_BitScanForward64(&lsb, x);
|
||||
return lsb;
|
||||
}
|
||||
#define BROTLI_TZCNT64 BrotliBsf64Msvc
|
||||
#endif /* BROTLI_TARGET_X64 */
|
||||
#endif /* __builtin_ctzll */
|
||||
#endif /* BROTLI_64_BITS */
|
||||
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
#define BROTLI_BSR32(x) (31u ^ (uint32_t)__builtin_clz(x))
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
|
||||
static BROTLI_INLINE uint32_t BrotliBsr32Msvc(uint32_t x) {
|
||||
unsigned long msb;
|
||||
_BitScanReverse(&msb, x);
|
||||
return (uint32_t)msb;
|
||||
}
|
||||
#define BROTLI_BSR32 BrotliBsr32Msvc
|
||||
#endif /* __builtin_clz */
|
||||
|
||||
/* Default brotli_alloc_func */
|
||||
BROTLI_COMMON_API void* BrotliDefaultAllocFunc(void* opaque, size_t size);
|
||||
|
||||
/* Default brotli_free_func */
|
||||
static void BrotliDefaultFreeFunc(void* opaque, void* address) {
|
||||
BROTLI_UNUSED(opaque);
|
||||
free(address);
|
||||
}
|
||||
BROTLI_COMMON_API void BrotliDefaultFreeFunc(void* opaque, void* address);
|
||||
|
||||
BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
|
||||
BROTLI_UNUSED(&BrotliSuppressUnusedFunctions);
|
||||
|
|
|
@ -24,8 +24,8 @@ static const char kPrefixSuffix[217] =
|
|||
/* 8x _0 _ _3 _8 _C _E _ _1 _7 _F */
|
||||
" not \3er \3al \4ful \4ive \5less \4es"
|
||||
/* Ax _5 _9 _D _2 _7 _D */
|
||||
"t \4ize \2\xc2\xa0\4ous \5 the \2e \0";
|
||||
/* Cx _2 _7___ ___ _A _F _5 _8 */
|
||||
"t \4ize \2\xc2\xa0\4ous \5 the \2e "; /* \0 - implicit trailing zero. */
|
||||
/* Cx _2 _7___ ___ _A _F _5 _8 */
|
||||
|
||||
static const uint16_t kPrefixSuffixMap[50] = {
|
||||
0x00, 0x02, 0x05, 0x0E, 0x13, 0x16, 0x18, 0x1E, 0x23, 0x25,
|
||||
|
@ -160,12 +160,13 @@ static const uint8_t kTransformsData[] = {
|
|||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34,
|
||||
};
|
||||
|
||||
static BrotliTransforms kBrotliTransforms = {
|
||||
static const BrotliTransforms kBrotliTransforms = {
|
||||
sizeof(kPrefixSuffix),
|
||||
(const uint8_t*)kPrefixSuffix,
|
||||
kPrefixSuffixMap,
|
||||
sizeof(kTransformsData) / (3 * sizeof(kTransformsData[0])),
|
||||
kTransformsData,
|
||||
NULL, /* no extra parameters */
|
||||
{0, 12, 27, 23, 42, 63, 56, 48, 59, 64}
|
||||
};
|
||||
|
||||
|
@ -190,6 +191,48 @@ static int ToUpperCase(uint8_t* p) {
|
|||
return 3;
|
||||
}
|
||||
|
||||
static int Shift(uint8_t* word, int word_len, uint16_t parameter) {
|
||||
/* Limited sign extension: scalar < (1 << 24). */
|
||||
uint32_t scalar =
|
||||
(parameter & 0x7FFFu) + (0x1000000u - (parameter & 0x8000u));
|
||||
if (word[0] < 0x80) {
|
||||
/* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */
|
||||
scalar += (uint32_t)word[0];
|
||||
word[0] = (uint8_t)(scalar & 0x7Fu);
|
||||
return 1;
|
||||
} else if (word[0] < 0xC0) {
|
||||
/* Continuation / 10AAAAAA. */
|
||||
return 1;
|
||||
} else if (word[0] < 0xE0) {
|
||||
/* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */
|
||||
if (word_len < 2) return 1;
|
||||
scalar += (uint32_t)((word[1] & 0x3Fu) | ((word[0] & 0x1Fu) << 6u));
|
||||
word[0] = (uint8_t)(0xC0 | ((scalar >> 6u) & 0x1F));
|
||||
word[1] = (uint8_t)((word[1] & 0xC0) | (scalar & 0x3F));
|
||||
return 2;
|
||||
} else if (word[0] < 0xF0) {
|
||||
/* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */
|
||||
if (word_len < 3) return word_len;
|
||||
scalar += (uint32_t)((word[2] & 0x3Fu) | ((word[1] & 0x3Fu) << 6u) |
|
||||
((word[0] & 0x0Fu) << 12u));
|
||||
word[0] = (uint8_t)(0xE0 | ((scalar >> 12u) & 0x0F));
|
||||
word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 6u) & 0x3F));
|
||||
word[2] = (uint8_t)((word[2] & 0xC0) | (scalar & 0x3F));
|
||||
return 3;
|
||||
} else if (word[0] < 0xF8) {
|
||||
/* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */
|
||||
if (word_len < 4) return word_len;
|
||||
scalar += (uint32_t)((word[3] & 0x3Fu) | ((word[2] & 0x3Fu) << 6u) |
|
||||
((word[1] & 0x3Fu) << 12u) | ((word[0] & 0x07u) << 18u));
|
||||
word[0] = (uint8_t)(0xF0 | ((scalar >> 18u) & 0x07));
|
||||
word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 12u) & 0x3F));
|
||||
word[2] = (uint8_t)((word[2] & 0xC0) | ((scalar >> 6u) & 0x3F));
|
||||
word[3] = (uint8_t)((word[3] & 0xC0) | (scalar & 0x3F));
|
||||
return 4;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
|
||||
const BrotliTransforms* transforms, int transform_idx) {
|
||||
int idx = 0;
|
||||
|
@ -221,6 +264,19 @@ int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
|
|||
uppercase += step;
|
||||
len -= step;
|
||||
}
|
||||
} else if (t == BROTLI_TRANSFORM_SHIFT_FIRST) {
|
||||
uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
|
||||
+ (transforms->params[transform_idx * 2 + 1] << 8u));
|
||||
Shift(&dst[idx - len], len, param);
|
||||
} else if (t == BROTLI_TRANSFORM_SHIFT_ALL) {
|
||||
uint16_t param = (uint16_t)(transforms->params[transform_idx * 2]
|
||||
+ (transforms->params[transform_idx * 2 + 1] << 8u));
|
||||
uint8_t* shift = &dst[idx - len];
|
||||
while (len > 0) {
|
||||
int step = Shift(shift, len, param);
|
||||
shift += step;
|
||||
len -= step;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
|
|
|
@ -37,6 +37,8 @@ enum BrotliWordTransformType {
|
|||
BROTLI_TRANSFORM_OMIT_FIRST_7 = 18,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_8 = 19,
|
||||
BROTLI_TRANSFORM_OMIT_FIRST_9 = 20,
|
||||
BROTLI_TRANSFORM_SHIFT_FIRST = 21,
|
||||
BROTLI_TRANSFORM_SHIFT_ALL = 22,
|
||||
BROTLI_NUM_TRANSFORM_TYPES /* Counts transforms, not a transform itself. */
|
||||
};
|
||||
|
||||
|
@ -50,6 +52,9 @@ typedef struct BrotliTransforms {
|
|||
uint32_t num_transforms;
|
||||
/* Each entry is a [prefix_id, transform, suffix_id] triplet. */
|
||||
const uint8_t* transforms;
|
||||
/* Shift for BROTLI_TRANSFORM_SHIFT_FIRST and BROTLI_TRANSFORM_SHIFT_ALL,
|
||||
must be NULL if and only if no such transforms are present. */
|
||||
const uint8_t* params;
|
||||
/* Indices of transforms like ["", BROTLI_TRANSFORM_OMIT_LAST_#, ""].
|
||||
0-th element corresponds to ["", BROTLI_TRANSFORM_IDENTITY, ""].
|
||||
-1, if cut-off transform does not exist. */
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
BrotliEncoderVersion methods. */
|
||||
|
||||
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
|
||||
#define BROTLI_VERSION 0x1000007
|
||||
#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 0x1007000
|
||||
#define BROTLI_ABI_VERSION 0x1009000
|
||||
|
||||
#endif /* BROTLI_COMMON_VERSION_H_ */
|
||||
|
|
|
@ -15,6 +15,17 @@
|
|||
extern "C" {
|
||||
#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) {
|
||||
br->val_ = 0;
|
||||
br->bit_pos_ = sizeof(br->val_) << 3;
|
||||
|
@ -43,6 +54,23 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
|
|||
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)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
|
@ -20,16 +21,7 @@ extern "C" {
|
|||
|
||||
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1)
|
||||
|
||||
static const uint32_t kBitMask[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
|
||||
};
|
||||
BROTLI_INTERNAL extern const uint32_t kBrotliBitMask[33];
|
||||
|
||||
static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
|
||||
if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
|
||||
|
@ -37,7 +29,7 @@ static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
|
|||
"Unsigned Bit Field Extract" UBFX instruction on ARM. */
|
||||
return ~((0xFFFFFFFFu) << n);
|
||||
} else {
|
||||
return kBitMask[n];
|
||||
return kBrotliBitMask[n];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +57,12 @@ BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
|
|||
reading. */
|
||||
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(
|
||||
BrotliBitReader* const from, BrotliBitReaderState* to) {
|
||||
to->val_ = from->val_;
|
||||
|
@ -87,8 +85,11 @@ static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
|
|||
}
|
||||
|
||||
/* 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 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);
|
||||
}
|
||||
|
||||
|
@ -237,15 +238,17 @@ static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
|
|||
static BROTLI_INLINE void BrotliTakeBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
*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_, (int)n_bits, (int)*val));
|
||||
BrotliDropBits(br, n_bits);
|
||||
}
|
||||
|
||||
/* Reads the specified number of bits from |br| and advances the bit pos.
|
||||
Assumes that there is enough input to perform BrotliFillBitWindow. */
|
||||
static BROTLI_INLINE uint32_t BrotliReadBits(
|
||||
Assumes that there is enough input to perform BrotliFillBitWindow.
|
||||
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) {
|
||||
BROTLI_DCHECK(n_bits <= 24);
|
||||
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
||||
uint32_t val;
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
|
@ -262,10 +265,32 @@ static BROTLI_INLINE uint32_t BrotliReadBits(
|
|||
}
|
||||
}
|
||||
|
||||
/* Same as BrotliReadBits24, but allows reading up to 32 bits. */
|
||||
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. */
|
||||
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(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
BROTLI_DCHECK(n_bits <= 24);
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
return BROTLI_FALSE;
|
||||
|
@ -275,6 +300,23 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
|
|||
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
|
||||
that any skipped bits are set to zero. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
||||
|
|
|
@ -41,7 +41,8 @@ extern "C" {
|
|||
|
||||
/* We need the slack region for the following reasons:
|
||||
- doing up to two 16-byte copies for fast backward copying
|
||||
- inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */
|
||||
- inserting transformed dictionary word:
|
||||
5 prefix + 24 base + 8 suffix */
|
||||
static const uint32_t kRingBufferWriteAheadSlack = 42;
|
||||
|
||||
static const uint8_t kCodeLengthCodeOrder[BROTLI_CODE_LENGTH_CODES] = {
|
||||
|
@ -274,7 +275,8 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
|
|||
s->loop_counter = i;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if (i + 1 == s->size_nibbles && s->size_nibbles > 4 && bits == 0) {
|
||||
if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 4 &&
|
||||
bits == 0) {
|
||||
return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE);
|
||||
}
|
||||
s->meta_block_remaining_len |= (int)(bits << (i * 4));
|
||||
|
@ -323,7 +325,8 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
|
|||
s->loop_counter = i;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if (i + 1 == s->size_nibbles && s->size_nibbles > 1 && bits == 0) {
|
||||
if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 1 &&
|
||||
bits == 0) {
|
||||
return BROTLI_FAILURE(
|
||||
BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE);
|
||||
}
|
||||
|
@ -470,32 +473,34 @@ static BROTLI_INLINE uint32_t Log2Floor(uint32_t x) {
|
|||
Totally 1..4 symbols are read, 1..11 bits each.
|
||||
The list of symbols MUST NOT contain duplicates. */
|
||||
static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols(
|
||||
uint32_t alphabet_size, uint32_t max_symbol, BrotliDecoderState* s) {
|
||||
uint32_t alphabet_size_max, uint32_t alphabet_size_limit,
|
||||
BrotliDecoderState* s) {
|
||||
/* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */
|
||||
BrotliBitReader* br = &s->br;
|
||||
uint32_t max_bits = Log2Floor(alphabet_size - 1);
|
||||
uint32_t i = s->sub_loop_counter;
|
||||
uint32_t num_symbols = s->symbol;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
uint32_t max_bits = Log2Floor(alphabet_size_max - 1);
|
||||
uint32_t i = h->sub_loop_counter;
|
||||
uint32_t num_symbols = h->symbol;
|
||||
while (i <= num_symbols) {
|
||||
uint32_t v;
|
||||
if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, max_bits, &v))) {
|
||||
s->sub_loop_counter = i;
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ;
|
||||
h->sub_loop_counter = i;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if (v >= max_symbol) {
|
||||
if (v >= alphabet_size_limit) {
|
||||
return
|
||||
BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
|
||||
}
|
||||
s->symbols_lists_array[i] = (uint16_t)v;
|
||||
BROTLI_LOG_UINT(s->symbols_lists_array[i]);
|
||||
h->symbols_lists_array[i] = (uint16_t)v;
|
||||
BROTLI_LOG_UINT(h->symbols_lists_array[i]);
|
||||
++i;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_symbols; ++i) {
|
||||
uint32_t k = i + 1;
|
||||
for (; k <= num_symbols; ++k) {
|
||||
if (s->symbols_lists_array[i] == s->symbols_lists_array[k]) {
|
||||
if (h->symbols_lists_array[i] == h->symbols_lists_array[k]) {
|
||||
return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
|
||||
}
|
||||
}
|
||||
|
@ -588,27 +593,28 @@ static BROTLI_INLINE void ProcessRepeatedCodeLength(uint32_t code_len,
|
|||
static BrotliDecoderErrorCode ReadSymbolCodeLengths(
|
||||
uint32_t alphabet_size, BrotliDecoderState* s) {
|
||||
BrotliBitReader* br = &s->br;
|
||||
uint32_t symbol = s->symbol;
|
||||
uint32_t repeat = s->repeat;
|
||||
uint32_t space = s->space;
|
||||
uint32_t prev_code_len = s->prev_code_len;
|
||||
uint32_t repeat_code_len = s->repeat_code_len;
|
||||
uint16_t* symbol_lists = s->symbol_lists;
|
||||
uint16_t* code_length_histo = s->code_length_histo;
|
||||
int* next_symbol = s->next_symbol;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
uint32_t symbol = h->symbol;
|
||||
uint32_t repeat = h->repeat;
|
||||
uint32_t space = h->space;
|
||||
uint32_t prev_code_len = h->prev_code_len;
|
||||
uint32_t repeat_code_len = h->repeat_code_len;
|
||||
uint16_t* symbol_lists = h->symbol_lists;
|
||||
uint16_t* code_length_histo = h->code_length_histo;
|
||||
int* next_symbol = h->next_symbol;
|
||||
if (!BrotliWarmupBitReader(br)) {
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
while (symbol < alphabet_size && space > 0) {
|
||||
const HuffmanCode* p = s->table;
|
||||
const HuffmanCode* p = h->table;
|
||||
uint32_t code_len;
|
||||
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p);
|
||||
if (!BrotliCheckInputAmount(br, BROTLI_SHORT_FILL_BIT_WINDOW_READ)) {
|
||||
s->symbol = symbol;
|
||||
s->repeat = repeat;
|
||||
s->prev_code_len = prev_code_len;
|
||||
s->repeat_code_len = repeat_code_len;
|
||||
s->space = space;
|
||||
h->symbol = symbol;
|
||||
h->repeat = repeat;
|
||||
h->prev_code_len = prev_code_len;
|
||||
h->repeat_code_len = repeat_code_len;
|
||||
h->space = space;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
BrotliFillBitWindow16(br);
|
||||
|
@ -630,16 +636,17 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths(
|
|||
symbol_lists, code_length_histo, next_symbol);
|
||||
}
|
||||
}
|
||||
s->space = space;
|
||||
h->space = space;
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
|
||||
static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
|
||||
uint32_t alphabet_size, BrotliDecoderState* s) {
|
||||
BrotliBitReader* br = &s->br;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
BROTLI_BOOL get_byte = BROTLI_FALSE;
|
||||
while (s->symbol < alphabet_size && s->space > 0) {
|
||||
const HuffmanCode* p = s->table;
|
||||
while (h->symbol < alphabet_size && h->space > 0) {
|
||||
const HuffmanCode* p = h->table;
|
||||
uint32_t code_len;
|
||||
uint32_t available_bits;
|
||||
uint32_t bits = 0;
|
||||
|
@ -659,9 +666,9 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
|
|||
code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */
|
||||
if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
|
||||
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p));
|
||||
ProcessSingleCodeLength(code_len, &s->symbol, &s->repeat, &s->space,
|
||||
&s->prev_code_len, s->symbol_lists, s->code_length_histo,
|
||||
s->next_symbol);
|
||||
ProcessSingleCodeLength(code_len, &h->symbol, &h->repeat, &h->space,
|
||||
&h->prev_code_len, h->symbol_lists, h->code_length_histo,
|
||||
h->next_symbol);
|
||||
} else { /* code_len == 16..17, extra_bits == 2..3 */
|
||||
uint32_t extra_bits = code_len - 14U;
|
||||
uint32_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) &
|
||||
|
@ -672,9 +679,9 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
|
|||
}
|
||||
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits);
|
||||
ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size,
|
||||
&s->symbol, &s->repeat, &s->space, &s->prev_code_len,
|
||||
&s->repeat_code_len, s->symbol_lists, s->code_length_histo,
|
||||
s->next_symbol);
|
||||
&h->symbol, &h->repeat, &h->space, &h->prev_code_len,
|
||||
&h->repeat_code_len, h->symbol_lists, h->code_length_histo,
|
||||
h->next_symbol);
|
||||
}
|
||||
}
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
|
@ -684,9 +691,10 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
|
|||
Each code is 2..4 bits long. In total 30..72 bits are used. */
|
||||
static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
|
||||
BrotliBitReader* br = &s->br;
|
||||
uint32_t num_codes = s->repeat;
|
||||
unsigned space = s->space;
|
||||
uint32_t i = s->sub_loop_counter;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
uint32_t num_codes = h->repeat;
|
||||
unsigned space = h->space;
|
||||
uint32_t i = h->sub_loop_counter;
|
||||
for (; i < BROTLI_CODE_LENGTH_CODES; ++i) {
|
||||
const uint8_t code_len_idx = kCodeLengthCodeOrder[i];
|
||||
uint32_t ix;
|
||||
|
@ -699,21 +707,21 @@ static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
|
|||
ix = 0;
|
||||
}
|
||||
if (kCodeLengthPrefixLength[ix] > available_bits) {
|
||||
s->sub_loop_counter = i;
|
||||
s->repeat = num_codes;
|
||||
s->space = space;
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
|
||||
h->sub_loop_counter = i;
|
||||
h->repeat = num_codes;
|
||||
h->space = space;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
}
|
||||
v = kCodeLengthPrefixValue[ix];
|
||||
BrotliDropBits(br, kCodeLengthPrefixLength[ix]);
|
||||
s->code_length_code_lengths[code_len_idx] = (uint8_t)v;
|
||||
BROTLI_LOG_ARRAY_INDEX(s->code_length_code_lengths, code_len_idx);
|
||||
h->code_length_code_lengths[code_len_idx] = (uint8_t)v;
|
||||
BROTLI_LOG_ARRAY_INDEX(h->code_length_code_lengths, code_len_idx);
|
||||
if (v != 0) {
|
||||
space = space - (32U >> v);
|
||||
++num_codes;
|
||||
++s->code_length_histo[v];
|
||||
++h->code_length_histo[v];
|
||||
if (space - 1U >= 32U) {
|
||||
/* space is 0 or wrapped around. */
|
||||
break;
|
||||
|
@ -737,49 +745,48 @@ static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) {
|
|||
encoded with predefined entropy code. 32 - 74 bits are used.
|
||||
B.2) Decoded table is used to decode code lengths of symbols in resulting
|
||||
Huffman table. In worst case 3520 bits are read. */
|
||||
static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size,
|
||||
uint32_t max_symbol,
|
||||
static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max,
|
||||
uint32_t alphabet_size_limit,
|
||||
HuffmanCode* table,
|
||||
uint32_t* opt_table_size,
|
||||
BrotliDecoderState* s) {
|
||||
BrotliBitReader* br = &s->br;
|
||||
/* Unnecessary masking, but might be good for safety. */
|
||||
alphabet_size &= 0x7FF;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
/* State machine. */
|
||||
for (;;) {
|
||||
switch (s->substate_huffman) {
|
||||
switch (h->substate_huffman) {
|
||||
case BROTLI_STATE_HUFFMAN_NONE:
|
||||
if (!BrotliSafeReadBits(br, 2, &s->sub_loop_counter)) {
|
||||
if (!BrotliSafeReadBits(br, 2, &h->sub_loop_counter)) {
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
BROTLI_LOG_UINT(s->sub_loop_counter);
|
||||
BROTLI_LOG_UINT(h->sub_loop_counter);
|
||||
/* The value is used as follows:
|
||||
1 for simple code;
|
||||
0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */
|
||||
if (s->sub_loop_counter != 1) {
|
||||
s->space = 32;
|
||||
s->repeat = 0; /* num_codes */
|
||||
memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo[0]) *
|
||||
if (h->sub_loop_counter != 1) {
|
||||
h->space = 32;
|
||||
h->repeat = 0; /* num_codes */
|
||||
memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo[0]) *
|
||||
(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1));
|
||||
memset(&s->code_length_code_lengths[0], 0,
|
||||
sizeof(s->code_length_code_lengths));
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
|
||||
memset(&h->code_length_code_lengths[0], 0,
|
||||
sizeof(h->code_length_code_lengths));
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX;
|
||||
continue;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_HUFFMAN_SIMPLE_SIZE:
|
||||
/* Read symbols, codes & code lengths directly. */
|
||||
if (!BrotliSafeReadBits(br, 2, &s->symbol)) { /* num_symbols */
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE;
|
||||
if (!BrotliSafeReadBits(br, 2, &h->symbol)) { /* num_symbols */
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
s->sub_loop_counter = 0;
|
||||
h->sub_loop_counter = 0;
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_HUFFMAN_SIMPLE_READ: {
|
||||
BrotliDecoderErrorCode result =
|
||||
ReadSimpleHuffmanSymbols(alphabet_size, max_symbol, s);
|
||||
ReadSimpleHuffmanSymbols(alphabet_size_max, alphabet_size_limit, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
@ -788,21 +795,21 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size,
|
|||
|
||||
case BROTLI_STATE_HUFFMAN_SIMPLE_BUILD: {
|
||||
uint32_t table_size;
|
||||
if (s->symbol == 3) {
|
||||
if (h->symbol == 3) {
|
||||
uint32_t bits;
|
||||
if (!BrotliSafeReadBits(br, 1, &bits)) {
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
s->symbol += bits;
|
||||
h->symbol += bits;
|
||||
}
|
||||
BROTLI_LOG_UINT(s->symbol);
|
||||
BROTLI_LOG_UINT(h->symbol);
|
||||
table_size = BrotliBuildSimpleHuffmanTable(
|
||||
table, HUFFMAN_TABLE_BITS, s->symbols_lists_array, s->symbol);
|
||||
table, HUFFMAN_TABLE_BITS, h->symbols_lists_array, h->symbol);
|
||||
if (opt_table_size) {
|
||||
*opt_table_size = table_size;
|
||||
}
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -813,44 +820,45 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size,
|
|||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
BrotliBuildCodeLengthsHuffmanTable(s->table,
|
||||
s->code_length_code_lengths,
|
||||
s->code_length_histo);
|
||||
memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo));
|
||||
BrotliBuildCodeLengthsHuffmanTable(h->table,
|
||||
h->code_length_code_lengths,
|
||||
h->code_length_histo);
|
||||
memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo));
|
||||
for (i = 0; i <= BROTLI_HUFFMAN_MAX_CODE_LENGTH; ++i) {
|
||||
s->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
|
||||
s->symbol_lists[s->next_symbol[i]] = 0xFFFF;
|
||||
h->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
|
||||
h->symbol_lists[h->next_symbol[i]] = 0xFFFF;
|
||||
}
|
||||
|
||||
s->symbol = 0;
|
||||
s->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH;
|
||||
s->repeat = 0;
|
||||
s->repeat_code_len = 0;
|
||||
s->space = 32768;
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS;
|
||||
h->symbol = 0;
|
||||
h->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH;
|
||||
h->repeat = 0;
|
||||
h->repeat_code_len = 0;
|
||||
h->space = 32768;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS: {
|
||||
uint32_t table_size;
|
||||
BrotliDecoderErrorCode result = ReadSymbolCodeLengths(max_symbol, s);
|
||||
BrotliDecoderErrorCode result = ReadSymbolCodeLengths(
|
||||
alphabet_size_limit, s);
|
||||
if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) {
|
||||
result = SafeReadSymbolCodeLengths(max_symbol, s);
|
||||
result = SafeReadSymbolCodeLengths(alphabet_size_limit, s);
|
||||
}
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (s->space != 0) {
|
||||
BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)s->space));
|
||||
if (h->space != 0) {
|
||||
BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)h->space));
|
||||
return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE);
|
||||
}
|
||||
table_size = BrotliBuildHuffmanTable(
|
||||
table, HUFFMAN_TABLE_BITS, s->symbol_lists, s->code_length_histo);
|
||||
table, HUFFMAN_TABLE_BITS, h->symbol_lists, h->code_length_histo);
|
||||
if (opt_table_size) {
|
||||
*opt_table_size = table_size;
|
||||
}
|
||||
s->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -867,8 +875,8 @@ static BROTLI_INLINE uint32_t ReadBlockLength(const HuffmanCode* table,
|
|||
uint32_t code;
|
||||
uint32_t nbits;
|
||||
code = ReadSymbol(table, br);
|
||||
nbits = kBlockLengthPrefixCode[code].nbits; /* nbits == 2..24 */
|
||||
return kBlockLengthPrefixCode[code].offset + BrotliReadBits(br, nbits);
|
||||
nbits = _kBrotliPrefixCodeRanges[code].nbits; /* nbits == 2..24 */
|
||||
return _kBrotliPrefixCodeRanges[code].offset + BrotliReadBits24(br, nbits);
|
||||
}
|
||||
|
||||
/* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then
|
||||
|
@ -886,13 +894,14 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBlockLength(
|
|||
}
|
||||
{
|
||||
uint32_t bits;
|
||||
uint32_t nbits = kBlockLengthPrefixCode[index].nbits; /* nbits == 2..24 */
|
||||
uint32_t nbits = _kBrotliPrefixCodeRanges[index].nbits;
|
||||
uint32_t offset = _kBrotliPrefixCodeRanges[index].offset;
|
||||
if (!BrotliSafeReadBits(br, nbits, &bits)) {
|
||||
s->block_length_index = index;
|
||||
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX;
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
*result = kBlockLengthPrefixCode[index].offset + bits;
|
||||
*result = offset + bits;
|
||||
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
@ -952,22 +961,22 @@ static BROTLI_NOINLINE void InverseMoveToFrontTransform(
|
|||
/* Decodes a series of Huffman table using ReadHuffmanCode function. */
|
||||
static BrotliDecoderErrorCode HuffmanTreeGroupDecode(
|
||||
HuffmanTreeGroup* group, BrotliDecoderState* s) {
|
||||
if (s->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) {
|
||||
s->next = group->codes;
|
||||
s->htree_index = 0;
|
||||
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
if (h->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) {
|
||||
h->next = group->codes;
|
||||
h->htree_index = 0;
|
||||
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP;
|
||||
}
|
||||
while (s->htree_index < group->num_htrees) {
|
||||
while (h->htree_index < group->num_htrees) {
|
||||
uint32_t table_size;
|
||||
BrotliDecoderErrorCode result =
|
||||
ReadHuffmanCode(group->alphabet_size, group->max_symbol,
|
||||
s->next, &table_size, s);
|
||||
BrotliDecoderErrorCode result = ReadHuffmanCode(group->alphabet_size_max,
|
||||
group->alphabet_size_limit, h->next, &table_size, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) return result;
|
||||
group->htrees[s->htree_index] = s->next;
|
||||
s->next += table_size;
|
||||
++s->htree_index;
|
||||
group->htrees[h->htree_index] = h->next;
|
||||
h->next += table_size;
|
||||
++h->htree_index;
|
||||
}
|
||||
s->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
|
||||
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -985,15 +994,16 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
|
|||
BrotliDecoderState* s) {
|
||||
BrotliBitReader* br = &s->br;
|
||||
BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
|
||||
switch ((int)s->substate_context_map) {
|
||||
switch ((int)h->substate_context_map) {
|
||||
case BROTLI_STATE_CONTEXT_MAP_NONE:
|
||||
result = DecodeVarLenUint8(s, br, num_htrees);
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
(*num_htrees)++;
|
||||
s->context_index = 0;
|
||||
h->context_index = 0;
|
||||
BROTLI_LOG_UINT(context_map_size);
|
||||
BROTLI_LOG_UINT(*num_htrees);
|
||||
*context_map_arg =
|
||||
|
@ -1005,7 +1015,7 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
|
|||
memset(*context_map_arg, 0, (size_t)context_map_size);
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX;
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX;
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX: {
|
||||
|
@ -1016,38 +1026,38 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
|
|||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if ((bits & 1) != 0) { /* Use RLE for zeros. */
|
||||
s->max_run_length_prefix = (bits >> 1) + 1;
|
||||
h->max_run_length_prefix = (bits >> 1) + 1;
|
||||
BrotliDropBits(br, 5);
|
||||
} else {
|
||||
s->max_run_length_prefix = 0;
|
||||
h->max_run_length_prefix = 0;
|
||||
BrotliDropBits(br, 1);
|
||||
}
|
||||
BROTLI_LOG_UINT(s->max_run_length_prefix);
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
|
||||
BROTLI_LOG_UINT(h->max_run_length_prefix);
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_CONTEXT_MAP_HUFFMAN: {
|
||||
uint32_t alphabet_size = *num_htrees + s->max_run_length_prefix;
|
||||
uint32_t alphabet_size = *num_htrees + h->max_run_length_prefix;
|
||||
result = ReadHuffmanCode(alphabet_size, alphabet_size,
|
||||
s->context_map_table, NULL, s);
|
||||
h->context_map_table, NULL, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) return result;
|
||||
s->code = 0xFFFF;
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
|
||||
h->code = 0xFFFF;
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_CONTEXT_MAP_DECODE: {
|
||||
uint32_t context_index = s->context_index;
|
||||
uint32_t max_run_length_prefix = s->max_run_length_prefix;
|
||||
uint32_t context_index = h->context_index;
|
||||
uint32_t max_run_length_prefix = h->max_run_length_prefix;
|
||||
uint8_t* context_map = *context_map_arg;
|
||||
uint32_t code = s->code;
|
||||
uint32_t code = h->code;
|
||||
BROTLI_BOOL skip_preamble = (code != 0xFFFF);
|
||||
while (context_index < context_map_size || skip_preamble) {
|
||||
if (!skip_preamble) {
|
||||
if (!SafeReadSymbol(s->context_map_table, br, &code)) {
|
||||
s->code = 0xFFFF;
|
||||
s->context_index = context_index;
|
||||
if (!SafeReadSymbol(h->context_map_table, br, &code)) {
|
||||
h->code = 0xFFFF;
|
||||
h->context_index = context_index;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
BROTLI_LOG_UINT(code);
|
||||
|
@ -1068,8 +1078,8 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
|
|||
{
|
||||
uint32_t reps;
|
||||
if (!BrotliSafeReadBits(br, code, &reps)) {
|
||||
s->code = code;
|
||||
s->context_index = context_index;
|
||||
h->code = code;
|
||||
h->context_index = context_index;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
reps += 1U << code;
|
||||
|
@ -1089,13 +1099,13 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size,
|
|||
case BROTLI_STATE_CONTEXT_MAP_TRANSFORM: {
|
||||
uint32_t bits;
|
||||
if (!BrotliSafeReadBits(br, 1, &bits)) {
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM;
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM;
|
||||
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
}
|
||||
if (bits != 0) {
|
||||
InverseMoveToFrontTransform(*context_map_arg, context_map_size, s);
|
||||
}
|
||||
s->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
|
||||
return BROTLI_DECODER_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1457,32 +1467,28 @@ static BrotliDecoderErrorCode ReadContextModes(BrotliDecoderState* s) {
|
|||
}
|
||||
|
||||
static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliDecoderState* s) {
|
||||
if (s->distance_code == 0) {
|
||||
--s->dist_rb_idx;
|
||||
s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
|
||||
int offset = s->distance_code - 3;
|
||||
if (s->distance_code <= 3) {
|
||||
/* Compensate double distance-ring-buffer roll for dictionary items. */
|
||||
s->distance_context = 1;
|
||||
s->distance_context = 1 >> s->distance_code;
|
||||
s->distance_code = s->dist_rb[(s->dist_rb_idx - offset) & 3];
|
||||
s->dist_rb_idx -= s->distance_context;
|
||||
} else {
|
||||
int distance_code = s->distance_code << 1;
|
||||
/* kDistanceShortCodeIndexOffset has 2-bit values from LSB:
|
||||
3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */
|
||||
const uint32_t kDistanceShortCodeIndexOffset = 0xAAAFFF1B;
|
||||
/* kDistanceShortCodeValueOffset has 2-bit values from LSB:
|
||||
-0, 0,-0, 0,-1, 1,-2, 2,-3, 3,-1, 1,-2, 2,-3, 3 */
|
||||
const uint32_t kDistanceShortCodeValueOffset = 0xFA5FA500;
|
||||
int v = (s->dist_rb_idx +
|
||||
(int)(kDistanceShortCodeIndexOffset >> distance_code)) & 0x3;
|
||||
s->distance_code = s->dist_rb[v];
|
||||
v = (int)(kDistanceShortCodeValueOffset >> distance_code) & 0x3;
|
||||
if ((distance_code & 0x3) != 0) {
|
||||
s->distance_code += v;
|
||||
int index_delta = 3;
|
||||
int delta;
|
||||
int base = s->distance_code - 10;
|
||||
if (s->distance_code < 10) {
|
||||
base = s->distance_code - 4;
|
||||
} else {
|
||||
s->distance_code -= v;
|
||||
if (s->distance_code <= 0) {
|
||||
/* A huge distance will cause a BROTLI_FAILURE() soon.
|
||||
This is a little faster than failing here. */
|
||||
s->distance_code = 0x7FFFFFFF;
|
||||
}
|
||||
index_delta = 2;
|
||||
}
|
||||
/* Unpack one of six 4-bit values. */
|
||||
delta = ((0x605142 >> (4 * base)) & 0xF) - 3;
|
||||
s->distance_code = s->dist_rb[(s->dist_rb_idx + index_delta) & 0x3] + delta;
|
||||
if (s->distance_code <= 0) {
|
||||
/* A huge distance will cause a BROTLI_FAILURE() soon.
|
||||
This is a little faster than failing here. */
|
||||
s->distance_code = 0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1497,62 +1503,153 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBits(
|
|||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE BROTLI_BOOL SafeReadBits32(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
if (n_bits != 0) {
|
||||
return BrotliSafeReadBits32(br, n_bits, val);
|
||||
} else {
|
||||
*val = 0;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
RFC 7932 Section 4 with "..." shortenings and "[]" emendations.
|
||||
|
||||
Each distance ... is represented with a pair <distance code, extra bits>...
|
||||
The distance code is encoded using a prefix code... The number of extra bits
|
||||
can be 0..24... Two additional parameters: NPOSTFIX (0..3), and ...
|
||||
NDIRECT (0..120) ... are encoded in the meta-block header...
|
||||
|
||||
The first 16 distance symbols ... reference past distances... ring buffer ...
|
||||
Next NDIRECT distance symbols ... represent distances from 1 to NDIRECT...
|
||||
[For] distance symbols 16 + NDIRECT and greater ... the number of extra bits
|
||||
... is given by the following formula:
|
||||
|
||||
[ xcode = dcode - NDIRECT - 16 ]
|
||||
ndistbits = 1 + [ xcode ] >> (NPOSTFIX + 1)
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
/*
|
||||
RFC 7932 Section 9.2 with "..." shortenings and "[]" emendations.
|
||||
|
||||
... to get the actual value of the parameter NDIRECT, left-shift this
|
||||
four-bit number by NPOSTFIX bits ...
|
||||
*/
|
||||
|
||||
/* Remaining formulas from RFC 7932 Section 4 could be rewritten as following:
|
||||
|
||||
alphabet_size = 16 + NDIRECT + (max_distbits << (NPOSTFIX + 1))
|
||||
|
||||
half = ((xcode >> NPOSTFIX) & 1) << ndistbits
|
||||
postfix = xcode & ((1 << NPOSTFIX) - 1)
|
||||
range_start = 2 * (1 << ndistbits - 1 - 1)
|
||||
|
||||
distance = (range_start + half + extra) << NPOSTFIX + postfix + NDIRECT + 1
|
||||
|
||||
NB: ndistbits >= 1 -> range_start >= 0
|
||||
NB: range_start has factor 2, as the range is covered by 2 "halves"
|
||||
NB: extra -1 offset in range_start formula covers the absence of
|
||||
ndistbits = 0 case
|
||||
NB: when NPOSTFIX = 0, NDIRECT is not greater than 15
|
||||
|
||||
In other words, xcode has the following binary structure - XXXHPPP:
|
||||
- XXX represent the number of extra distance bits
|
||||
- H selects upper / lower range of distances
|
||||
- PPP represent "postfix"
|
||||
|
||||
"Regular" distance encoding has NPOSTFIX = 0; omitting the postfix part
|
||||
simplifies distance calculation.
|
||||
|
||||
Using NPOSTFIX > 0 allows cheaper encoding of regular structures, e.g. where
|
||||
most of distances have the same reminder of division by 2/4/8. For example,
|
||||
the table of int32_t values that come from different sources; if it is likely
|
||||
that 3 highest bytes of values from the same source are the same, then
|
||||
copy distance often looks like 4x + y.
|
||||
|
||||
Distance calculation could be rewritten to:
|
||||
|
||||
ndistbits = NDISTBITS(NDIRECT, NPOSTFIX)[dcode]
|
||||
distance = OFFSET(NDIRECT, NPOSTFIX)[dcode] + extra << NPOSTFIX
|
||||
|
||||
NDISTBITS and OFFSET could be pre-calculated, as NDIRECT and NPOSTFIX could
|
||||
change only once per meta-block.
|
||||
*/
|
||||
|
||||
/* Calculates distance lookup table.
|
||||
NB: it is possible to have all 64 tables precalculated. */
|
||||
static void CalculateDistanceLut(BrotliDecoderState* s) {
|
||||
BrotliMetablockBodyArena* b = &s->arena.body;
|
||||
uint32_t npostfix = s->distance_postfix_bits;
|
||||
uint32_t ndirect = s->num_direct_distance_codes;
|
||||
uint32_t alphabet_size_limit = s->distance_hgroup.alphabet_size_limit;
|
||||
uint32_t postfix = 1u << npostfix;
|
||||
uint32_t j;
|
||||
uint32_t bits = 1;
|
||||
uint32_t half = 0;
|
||||
|
||||
/* Skip short codes. */
|
||||
uint32_t i = BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||
|
||||
/* Fill direct codes. */
|
||||
for (j = 0; j < ndirect; ++j) {
|
||||
b->dist_extra_bits[i] = 0;
|
||||
b->dist_offset[i] = j + 1;
|
||||
++i;
|
||||
}
|
||||
|
||||
/* Fill regular distance codes. */
|
||||
while (i < alphabet_size_limit) {
|
||||
uint32_t base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1;
|
||||
/* Always fill the complete group. */
|
||||
for (j = 0; j < postfix; ++j) {
|
||||
b->dist_extra_bits[i] = (uint8_t)bits;
|
||||
b->dist_offset[i] = base + j;
|
||||
++i;
|
||||
}
|
||||
bits = bits + half;
|
||||
half = half ^ 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Precondition: s->distance_code < 0. */
|
||||
static BROTLI_INLINE BROTLI_BOOL ReadDistanceInternal(
|
||||
int safe, BrotliDecoderState* s, BrotliBitReader* br) {
|
||||
int distval;
|
||||
BrotliMetablockBodyArena* b = &s->arena.body;
|
||||
uint32_t code;
|
||||
uint32_t bits;
|
||||
BrotliBitReaderState memento;
|
||||
HuffmanCode* distance_tree = s->distance_hgroup.htrees[s->dist_htree_index];
|
||||
if (!safe) {
|
||||
s->distance_code = (int)ReadSymbol(distance_tree, br);
|
||||
code = ReadSymbol(distance_tree, br);
|
||||
} else {
|
||||
uint32_t code;
|
||||
BrotliBitReaderSaveState(br, &memento);
|
||||
if (!SafeReadSymbol(distance_tree, br, &code)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
s->distance_code = (int)code;
|
||||
}
|
||||
--s->block_length[2];
|
||||
/* Convert the distance code to the actual distance by possibly
|
||||
looking up past distances from the s->ringbuffer. */
|
||||
looking up past distances from the s->dist_rb. */
|
||||
s->distance_context = 0;
|
||||
if ((s->distance_code & ~0xF) == 0) {
|
||||
if ((code & ~0xFu) == 0) {
|
||||
s->distance_code = (int)code;
|
||||
TakeDistanceFromRingBuffer(s);
|
||||
--s->block_length[2];
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
distval = s->distance_code - (int)s->num_direct_distance_codes;
|
||||
if (distval >= 0) {
|
||||
uint32_t nbits;
|
||||
int postfix;
|
||||
int offset;
|
||||
if (!safe && (s->distance_postfix_bits == 0)) {
|
||||
nbits = ((uint32_t)distval >> 1) + 1;
|
||||
offset = ((2 + (distval & 1)) << nbits) - 4;
|
||||
s->distance_code = (int)s->num_direct_distance_codes + offset +
|
||||
(int)BrotliReadBits(br, nbits);
|
||||
} else {
|
||||
/* This branch also works well when s->distance_postfix_bits == 0. */
|
||||
uint32_t bits;
|
||||
postfix = distval & s->distance_postfix_mask;
|
||||
distval >>= s->distance_postfix_bits;
|
||||
nbits = ((uint32_t)distval >> 1) + 1;
|
||||
if (safe) {
|
||||
if (!SafeReadBits(br, nbits, &bits)) {
|
||||
s->distance_code = -1; /* Restore precondition. */
|
||||
BrotliBitReaderRestoreState(br, &memento);
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
} else {
|
||||
bits = BrotliReadBits(br, nbits);
|
||||
}
|
||||
offset = ((2 + (distval & 1)) << nbits) - 4;
|
||||
s->distance_code = (int)s->num_direct_distance_codes +
|
||||
((offset + (int)bits) << s->distance_postfix_bits) + postfix;
|
||||
if (!safe) {
|
||||
bits = BrotliReadBits32(br, b->dist_extra_bits[code]);
|
||||
} else {
|
||||
if (!SafeReadBits32(br, b->dist_extra_bits[code], &bits)) {
|
||||
++s->block_length[2];
|
||||
BrotliBitReaderRestoreState(br, &memento);
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
s->distance_code = s->distance_code - BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
|
||||
--s->block_length[2];
|
||||
s->distance_code =
|
||||
(int)(b->dist_offset[code] + (bits << s->distance_postfix_bits));
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1588,9 +1685,9 @@ static BROTLI_INLINE BROTLI_BOOL ReadCommandInternal(
|
|||
*insert_length = v.insert_len_offset;
|
||||
if (!safe) {
|
||||
if (BROTLI_PREDICT_FALSE(v.insert_len_extra_bits != 0)) {
|
||||
insert_len_extra = BrotliReadBits(br, v.insert_len_extra_bits);
|
||||
insert_len_extra = BrotliReadBits24(br, v.insert_len_extra_bits);
|
||||
}
|
||||
copy_length = BrotliReadBits(br, v.copy_len_extra_bits);
|
||||
copy_length = BrotliReadBits24(br, v.copy_len_extra_bits);
|
||||
} else {
|
||||
if (!SafeReadBits(br, v.insert_len_extra_bits, &insert_len_extra) ||
|
||||
!SafeReadBits(br, v.copy_len_extra_bits, ©_length)) {
|
||||
|
@ -1935,21 +2032,6 @@ static BROTLI_NOINLINE BrotliDecoderErrorCode SafeProcessCommands(
|
|||
return ProcessCommandsInternal(1, s);
|
||||
}
|
||||
|
||||
/* Returns the maximum number of distance symbols which can only represent
|
||||
distances not exceeding BROTLI_MAX_ALLOWED_DISTANCE. */
|
||||
static uint32_t BrotliMaxDistanceSymbol(uint32_t ndirect, uint32_t npostfix) {
|
||||
static const uint32_t bound[BROTLI_MAX_NPOSTFIX + 1] = {0, 4, 12, 28};
|
||||
static const uint32_t diff[BROTLI_MAX_NPOSTFIX + 1] = {73, 126, 228, 424};
|
||||
uint32_t postfix = 1U << npostfix;
|
||||
if (ndirect < bound[npostfix]) {
|
||||
return ndirect + diff[npostfix] + postfix;
|
||||
} else if (ndirect > bound[npostfix] + postfix) {
|
||||
return ndirect + diff[npostfix];
|
||||
} else {
|
||||
return bound[npostfix] + diff[npostfix] + postfix;
|
||||
}
|
||||
}
|
||||
|
||||
BrotliDecoderResult BrotliDecoderDecompress(
|
||||
size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size,
|
||||
uint8_t* decoded_buffer) {
|
||||
|
@ -2167,33 +2249,23 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
|||
s->state = BROTLI_STATE_UNCOMPRESSED;
|
||||
break;
|
||||
}
|
||||
s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER;
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER: {
|
||||
BrotliMetablockHeaderArena* h = &s->arena.header;
|
||||
s->loop_counter = 0;
|
||||
/* Initialize compressed metablock header arena. */
|
||||
h->sub_loop_counter = 0;
|
||||
/* Make small negative indexes addressable. */
|
||||
h->symbol_lists =
|
||||
&h->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1];
|
||||
h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE;
|
||||
h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE;
|
||||
s->state = BROTLI_STATE_HUFFMAN_CODE_0;
|
||||
break;
|
||||
|
||||
case BROTLI_STATE_UNCOMPRESSED: {
|
||||
result = CopyUncompressedBlockToOutput(
|
||||
available_out, next_out, total_out, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
case BROTLI_STATE_METADATA:
|
||||
for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
|
||||
uint32_t bits;
|
||||
/* Read one byte and ignore it. */
|
||||
if (!BrotliSafeReadBits(br, 8, &bits)) {
|
||||
result = BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == BROTLI_DECODER_SUCCESS) {
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
}
|
||||
break;
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_HUFFMAN_CODE_0:
|
||||
if (s->loop_counter >= 3) {
|
||||
|
@ -2247,6 +2319,30 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
|||
break;
|
||||
}
|
||||
|
||||
case BROTLI_STATE_UNCOMPRESSED: {
|
||||
result = CopyUncompressedBlockToOutput(
|
||||
available_out, next_out, total_out, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
case BROTLI_STATE_METADATA:
|
||||
for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
|
||||
uint32_t bits;
|
||||
/* Read one byte and ignore it. */
|
||||
if (!BrotliSafeReadBits(br, 8, &bits)) {
|
||||
result = BROTLI_DECODER_NEEDS_MORE_INPUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == BROTLI_DECODER_SUCCESS) {
|
||||
s->state = BROTLI_STATE_METABLOCK_DONE;
|
||||
}
|
||||
break;
|
||||
|
||||
case BROTLI_STATE_METABLOCK_HEADER_2: {
|
||||
uint32_t bits;
|
||||
if (!BrotliSafeReadBits(br, 6, &bits)) {
|
||||
|
@ -2255,11 +2351,9 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
|||
}
|
||||
s->distance_postfix_bits = bits & BitMask(2);
|
||||
bits >>= 2;
|
||||
s->num_direct_distance_codes = BROTLI_NUM_DISTANCE_SHORT_CODES +
|
||||
(bits << s->distance_postfix_bits);
|
||||
s->num_direct_distance_codes = bits << s->distance_postfix_bits;
|
||||
BROTLI_LOG_UINT(s->num_direct_distance_codes);
|
||||
BROTLI_LOG_UINT(s->distance_postfix_bits);
|
||||
s->distance_postfix_mask = (int)BitMask(s->distance_postfix_bits);
|
||||
s->context_modes =
|
||||
(uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)s->num_block_types[0]);
|
||||
if (s->context_modes == 0) {
|
||||
|
@ -2291,17 +2385,19 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
|||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_CONTEXT_MAP_2: {
|
||||
uint32_t num_direct_codes =
|
||||
s->num_direct_distance_codes - BROTLI_NUM_DISTANCE_SHORT_CODES;
|
||||
uint32_t num_distance_codes = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||
s->distance_postfix_bits, num_direct_codes,
|
||||
(s->large_window ? BROTLI_LARGE_MAX_DISTANCE_BITS :
|
||||
BROTLI_MAX_DISTANCE_BITS));
|
||||
uint32_t max_distance_symbol = (s->large_window ?
|
||||
BrotliMaxDistanceSymbol(
|
||||
num_direct_codes, s->distance_postfix_bits) :
|
||||
num_distance_codes);
|
||||
uint32_t npostfix = s->distance_postfix_bits;
|
||||
uint32_t ndirect = s->num_direct_distance_codes;
|
||||
uint32_t distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||
npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
|
||||
uint32_t distance_alphabet_size_limit = distance_alphabet_size_max;
|
||||
BROTLI_BOOL allocation_success = BROTLI_TRUE;
|
||||
if (s->large_window) {
|
||||
BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
|
||||
BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
|
||||
distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||
npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
|
||||
distance_alphabet_size_limit = limit.max_alphabet_size;
|
||||
}
|
||||
result = DecodeContextMap(
|
||||
s->num_block_types[2] << BROTLI_DISTANCE_CONTEXT_BITS,
|
||||
&s->num_dist_htrees, &s->dist_context_map, s);
|
||||
|
@ -2315,8 +2411,8 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
|||
s, &s->insert_copy_hgroup, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
BROTLI_NUM_COMMAND_SYMBOLS, s->num_block_types[1]);
|
||||
allocation_success &= BrotliDecoderHuffmanTreeGroupInit(
|
||||
s, &s->distance_hgroup, num_distance_codes,
|
||||
max_distance_symbol, s->num_dist_htrees);
|
||||
s, &s->distance_hgroup, distance_alphabet_size_max,
|
||||
distance_alphabet_size_limit, s->num_dist_htrees);
|
||||
if (!allocation_success) {
|
||||
return SaveErrorCode(s,
|
||||
BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS));
|
||||
|
@ -2338,18 +2434,24 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
|
|||
result = HuffmanTreeGroupDecode(hgroup, s);
|
||||
if (result != BROTLI_DECODER_SUCCESS) break;
|
||||
s->loop_counter++;
|
||||
if (s->loop_counter >= 3) {
|
||||
PrepareLiteralDecoding(s);
|
||||
s->dist_context_map_slice = s->dist_context_map;
|
||||
s->htree_command = s->insert_copy_hgroup.htrees[0];
|
||||
if (!BrotliEnsureRingBuffer(s)) {
|
||||
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
|
||||
break;
|
||||
}
|
||||
s->state = BROTLI_STATE_COMMAND_BEGIN;
|
||||
if (s->loop_counter < 3) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY;
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY:
|
||||
PrepareLiteralDecoding(s);
|
||||
s->dist_context_map_slice = s->dist_context_map;
|
||||
s->htree_command = s->insert_copy_hgroup.htrees[0];
|
||||
if (!BrotliEnsureRingBuffer(s)) {
|
||||
result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
|
||||
break;
|
||||
}
|
||||
CalculateDistanceLut(s);
|
||||
s->state = BROTLI_STATE_COMMAND_BEGIN;
|
||||
/* Fall through. */
|
||||
|
||||
case BROTLI_STATE_COMMAND_BEGIN:
|
||||
/* Fall through. */
|
||||
|
|
|
@ -18,12 +18,6 @@ extern "C" {
|
|||
|
||||
#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, 1112, 1144, 1176, 1208, 1240, 1272,
|
||||
1304, 1336, 1368, 1400, 1432, 1464, 1496, 1528};
|
||||
/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
|
||||
#define BROTLI_HUFFMAN_MAX_SIZE_26 396
|
||||
/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
|
||||
|
@ -82,7 +76,7 @@ typedef BROTLI_ALIGNED(4) uint32_t HuffmanCode;
|
|||
|
||||
static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
|
||||
const uint16_t value) {
|
||||
return ((value & 0xFFFF) << 16) | (bits & 0xFF);
|
||||
return (HuffmanCode) ((value & 0xFFFF) << 16) | (bits & 0xFF);
|
||||
}
|
||||
|
||||
#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H)
|
||||
|
@ -100,7 +94,7 @@ BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
|
|||
/* Builds Huffman lookup table assuming code lengths are in symbol order.
|
||||
Returns size of resulting 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
|
||||
interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
|
||||
|
@ -110,13 +104,13 @@ BROTLI_INTERNAL uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
|||
int root_bits, uint16_t* symbols, uint32_t num_symbols);
|
||||
|
||||
/* Contains a collection of Huffman trees with the same alphabet size. */
|
||||
/* max_symbol is needed due to simple codes since log2(alphabet_size) could be
|
||||
greater than log2(max_symbol). */
|
||||
/* alphabet_size_limit is needed due to simple codes, since
|
||||
log2(alphabet_size_max) could be greater than log2(alphabet_size_limit). */
|
||||
typedef struct {
|
||||
HuffmanCode** htrees;
|
||||
HuffmanCode* codes;
|
||||
uint16_t alphabet_size;
|
||||
uint16_t max_symbol;
|
||||
uint16_t alphabet_size_max;
|
||||
uint16_t alphabet_size_limit;
|
||||
uint16_t num_htrees;
|
||||
} HuffmanTreeGroup;
|
||||
|
||||
|
|
|
@ -13,24 +13,6 @@
|
|||
#include "../common/constants.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 {
|
||||
uint8_t insert_len_extra_bits;
|
||||
uint8_t copy_len_extra_bits;
|
||||
|
|
|
@ -33,10 +33,7 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
|||
s->state = BROTLI_STATE_UNINITED;
|
||||
s->large_window = 0;
|
||||
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_huffman = BROTLI_STATE_HUFFMAN_NONE;
|
||||
s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE;
|
||||
s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
|
||||
|
||||
|
@ -59,8 +56,6 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
|||
s->context_map_slice = NULL;
|
||||
s->dist_context_map_slice = NULL;
|
||||
|
||||
s->sub_loop_counter = 0;
|
||||
|
||||
s->literal_hgroup.codes = NULL;
|
||||
s->literal_hgroup.htrees = NULL;
|
||||
s->insert_copy_hgroup.codes = NULL;
|
||||
|
@ -84,9 +79,6 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
|||
s->block_type_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->dictionary = BrotliGetDictionary();
|
||||
|
@ -142,17 +134,20 @@ void BrotliDecoderStateCleanup(BrotliDecoderState* s) {
|
|||
}
|
||||
|
||||
BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s,
|
||||
HuffmanTreeGroup* group, uint32_t alphabet_size, uint32_t max_symbol,
|
||||
uint32_t ntrees) {
|
||||
/* Pack two allocations into one */
|
||||
const size_t max_table_size = kMaxHuffmanTableSize[(alphabet_size + 31) >> 5];
|
||||
HuffmanTreeGroup* group, uint32_t alphabet_size_max,
|
||||
uint32_t alphabet_size_limit, uint32_t ntrees) {
|
||||
/* 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 htree_size = sizeof(HuffmanCode*) * ntrees;
|
||||
/* Pointer alignment is, hopefully, wider than sizeof(HuffmanCode). */
|
||||
HuffmanCode** p = (HuffmanCode**)BROTLI_DECODER_ALLOC(s,
|
||||
code_size + htree_size);
|
||||
group->alphabet_size = (uint16_t)alphabet_size;
|
||||
group->max_symbol = (uint16_t)max_symbol;
|
||||
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->htrees = p;
|
||||
group->codes = (HuffmanCode*)(&p[ntrees]);
|
||||
|
|
|
@ -21,6 +21,95 @@
|
|||
extern "C" {
|
||||
#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 {
|
||||
BROTLI_STATE_UNINITED,
|
||||
BROTLI_STATE_LARGE_WINDOW_BITS,
|
||||
|
@ -39,6 +128,7 @@ typedef enum {
|
|||
BROTLI_STATE_METABLOCK_DONE,
|
||||
BROTLI_STATE_COMMAND_POST_WRITE_1,
|
||||
BROTLI_STATE_COMMAND_POST_WRITE_2,
|
||||
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER,
|
||||
BROTLI_STATE_HUFFMAN_CODE_0,
|
||||
BROTLI_STATE_HUFFMAN_CODE_1,
|
||||
BROTLI_STATE_HUFFMAN_CODE_2,
|
||||
|
@ -46,6 +136,7 @@ typedef enum {
|
|||
BROTLI_STATE_CONTEXT_MAP_1,
|
||||
BROTLI_STATE_CONTEXT_MAP_2,
|
||||
BROTLI_STATE_TREE_GROUP,
|
||||
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY,
|
||||
BROTLI_STATE_DONE
|
||||
} BrotliRunningState;
|
||||
|
||||
|
@ -98,6 +189,50 @@ typedef enum {
|
|||
BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
|
||||
} 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 {
|
||||
BrotliRunningState state;
|
||||
|
||||
|
@ -110,7 +245,8 @@ struct BrotliDecoderStateStruct {
|
|||
brotli_free_func free_func;
|
||||
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 {
|
||||
uint64_t u64;
|
||||
uint8_t u8[8];
|
||||
|
@ -125,7 +261,6 @@ struct BrotliDecoderStateStruct {
|
|||
int dist_rb_idx;
|
||||
int dist_rb[4];
|
||||
int error_code;
|
||||
uint32_t sub_loop_counter;
|
||||
uint8_t* ringbuffer;
|
||||
uint8_t* ringbuffer_end;
|
||||
HuffmanCode* htree_command;
|
||||
|
@ -153,13 +288,10 @@ struct BrotliDecoderStateStruct {
|
|||
uint32_t block_type_rb[6];
|
||||
uint32_t distance_postfix_bits;
|
||||
uint32_t num_direct_distance_codes;
|
||||
int distance_postfix_mask;
|
||||
uint32_t num_dist_htrees;
|
||||
uint8_t* dist_context_map;
|
||||
HuffmanCode* literal_htree;
|
||||
uint8_t dist_htree_index;
|
||||
uint32_t repeat_code_len;
|
||||
uint32_t prev_code_len;
|
||||
|
||||
int copy_length;
|
||||
int distance_code;
|
||||
|
@ -168,33 +300,6 @@ struct BrotliDecoderStateStruct {
|
|||
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 */
|
||||
|
||||
/* For ReadHuffmanCode. */
|
||||
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[64 + 1];
|
||||
|
@ -203,10 +308,7 @@ struct BrotliDecoderStateStruct {
|
|||
|
||||
/* States inside function calls. */
|
||||
BrotliRunningMetablockHeaderState substate_metablock_header;
|
||||
BrotliRunningTreeGroupState substate_tree_group;
|
||||
BrotliRunningContextMapState substate_context_map;
|
||||
BrotliRunningUncompressedState substate_uncompressed;
|
||||
BrotliRunningHuffmanState substate_huffman;
|
||||
BrotliRunningDecodeUint8State substate_decode_uint8;
|
||||
BrotliRunningReadBlockLengthState substate_read_block_length;
|
||||
|
||||
|
@ -229,6 +331,11 @@ struct BrotliDecoderStateStruct {
|
|||
const BrotliTransforms* transforms;
|
||||
|
||||
uint32_t trivial_literal_contexts[8]; /* 256 bits */
|
||||
|
||||
union {
|
||||
BrotliMetablockHeaderArena header;
|
||||
BrotliMetablockBodyArena body;
|
||||
} arena;
|
||||
};
|
||||
|
||||
typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal;
|
||||
|
@ -241,8 +348,8 @@ BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s);
|
|||
BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock(
|
||||
BrotliDecoderState* s);
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
|
||||
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size,
|
||||
uint32_t max_symbol, uint32_t ntrees);
|
||||
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size_max,
|
||||
uint32_t alphabet_size_limit, uint32_t ntrees);
|
||||
|
||||
#define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "./backward_references.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
@ -119,17 +120,17 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
|
|||
#undef CAT
|
||||
#undef EXPAND_CAT
|
||||
|
||||
void BrotliCreateBackwardReferences(
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
void BrotliCreateBackwardReferences(size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
switch (params->hasher.type) {
|
||||
#define CASE_(N) \
|
||||
case N: \
|
||||
CreateBackwardReferencesNH ## N( \
|
||||
num_bytes, position, ringbuffer, \
|
||||
ringbuffer_mask, params, hasher, dist_cache, \
|
||||
CreateBackwardReferencesNH ## N(num_bytes, \
|
||||
position, ringbuffer, ringbuffer_mask, \
|
||||
literal_context_lut, params, hasher, dist_cache, \
|
||||
last_insert_len, commands, num_commands, num_literals); \
|
||||
return;
|
||||
FOR_GENERIC_HASHERS(CASE_)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define BROTLI_ENC_BACKWARD_REFERENCES_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
@ -25,10 +26,10 @@ extern "C" {
|
|||
initially the total amount of commands output by previous
|
||||
CreateBackwardReferences calls, and must be incremented by the amount written
|
||||
by this call. */
|
||||
BROTLI_INTERNAL void BrotliCreateBackwardReferences(
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <string.h> /* memcpy, memset */
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
|
@ -26,6 +27,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
|
||||
#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
|
||||
|
||||
static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */
|
||||
|
@ -86,14 +88,10 @@ typedef struct ZopfliCostModel {
|
|||
static void InitZopfliCostModel(
|
||||
MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
|
||||
size_t num_bytes) {
|
||||
uint32_t distance_histogram_size = dist->alphabet_size;
|
||||
if (distance_histogram_size > BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE) {
|
||||
distance_histogram_size = BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE;
|
||||
}
|
||||
self->num_bytes_ = num_bytes;
|
||||
self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
|
||||
self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size);
|
||||
self->distance_histogram_size = distance_histogram_size;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -408,9 +406,12 @@ static size_t UpdateNodes(
|
|||
const int* starting_dist_cache, const size_t num_matches,
|
||||
const BackwardMatch* matches, const ZopfliCostModel* model,
|
||||
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_masked = cur_ix & ringbuffer_mask;
|
||||
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_zopfli_len = MaxZopfliLen(params);
|
||||
const size_t max_iters = MaxZopfliCandidates(params);
|
||||
|
@ -419,8 +420,8 @@ static size_t UpdateNodes(
|
|||
size_t k;
|
||||
size_t gap = 0;
|
||||
|
||||
EvaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache,
|
||||
model, queue, nodes);
|
||||
EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
|
||||
starting_dist_cache, model, queue, nodes);
|
||||
|
||||
{
|
||||
const PosData* posdata = StartPosQueueAt(queue, 0);
|
||||
|
@ -453,7 +454,7 @@ static size_t UpdateNodes(
|
|||
if (cur_ix_masked + best_len > ringbuffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_distance + gap)) {
|
||||
if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
|
||||
/* Word dictionary -> ignore. */
|
||||
continue;
|
||||
}
|
||||
|
@ -472,6 +473,8 @@ static size_t UpdateNodes(
|
|||
&ringbuffer[cur_ix_masked],
|
||||
max_len);
|
||||
} else {
|
||||
/* "Gray" area. It is addressable by decoder, but this encoder
|
||||
instance does not have that data -> should not touch it. */
|
||||
continue;
|
||||
}
|
||||
{
|
||||
|
@ -506,7 +509,7 @@ static size_t UpdateNodes(
|
|||
BackwardMatch match = matches[j];
|
||||
size_t dist = match.distance;
|
||||
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
|
||||
normal distance code here. */
|
||||
size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
|
||||
|
@ -569,6 +572,7 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
|||
const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
|
||||
size_t* last_insert_len, const BrotliEncoderParams* params,
|
||||
Command* 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);
|
||||
size_t pos = 0;
|
||||
uint32_t offset = nodes[0].u.next;
|
||||
|
@ -587,9 +591,10 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
|||
{
|
||||
size_t distance = ZopfliNodeCopyDistance(next);
|
||||
size_t len_code = ZopfliNodeLengthCode(next);
|
||||
size_t max_distance =
|
||||
BROTLI_MIN(size_t, block_start + pos, max_backward_limit);
|
||||
BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance + gap);
|
||||
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
block_start + pos + stream_offset, max_backward_limit);
|
||||
BROTLI_BOOL is_dictionary =
|
||||
TO_BROTLI_BOOL(distance > dictionary_start + gap);
|
||||
size_t dist_code = ZopfliNodeDistanceCode(next);
|
||||
InitCommand(&commands[i], ¶ms->dist, insert_length,
|
||||
copy_length, (int)len_code - (int)copy_length, dist_code);
|
||||
|
@ -613,6 +618,7 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
|||
const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
|
||||
const ZopfliCostModel* model, const uint32_t* num_matches,
|
||||
const BackwardMatch* matches, ZopfliNode* nodes) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||
StartPosQueue queue;
|
||||
|
@ -637,7 +643,7 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
|||
while (skip) {
|
||||
i++;
|
||||
if (i + 3 >= num_bytes) break;
|
||||
EvaluateNode(position, i, max_backward_limit, gap,
|
||||
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
||||
dist_cache, model, &queue, nodes);
|
||||
cur_match_pos += num_matches[i];
|
||||
skip--;
|
||||
|
@ -650,8 +656,9 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
|||
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
||||
size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes) {
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||
ZopfliCostModel model;
|
||||
|
@ -662,6 +669,7 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
|||
size_t i;
|
||||
size_t gap = 0;
|
||||
size_t lz_matches_offset = 0;
|
||||
BROTLI_UNUSED(literal_context_lut);
|
||||
nodes[0].length = 0;
|
||||
nodes[0].u.cost = 0;
|
||||
InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes);
|
||||
|
@ -672,12 +680,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
|||
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
|
||||
const size_t pos = position + i;
|
||||
const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
||||
const size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
pos + stream_offset, max_backward_limit);
|
||||
size_t skip;
|
||||
size_t num_matches;
|
||||
num_matches = FindAllMatchesH10(hasher,
|
||||
num_matches = FindAllMatchesH10(&hasher->privat._H10,
|
||||
¶ms->dictionary,
|
||||
ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
|
||||
gap, params, &matches[lz_matches_offset]);
|
||||
dictionary_start + gap, params, &matches[lz_matches_offset]);
|
||||
if (num_matches > 0 &&
|
||||
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
|
||||
matches[0] = matches[num_matches - 1];
|
||||
|
@ -692,13 +702,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
|||
}
|
||||
if (skip > 1) {
|
||||
/* 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));
|
||||
skip--;
|
||||
while (skip) {
|
||||
i++;
|
||||
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
|
||||
EvaluateNode(position, i, max_backward_limit, gap,
|
||||
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
||||
dist_cache, &model, &queue, nodes);
|
||||
skip--;
|
||||
}
|
||||
|
@ -710,15 +721,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
|||
|
||||
void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
ZopfliNode* nodes;
|
||||
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
||||
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
||||
*num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
|
||||
position, ringbuffer, ringbuffer_mask, params,
|
||||
position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
|
||||
dist_cache, hasher, nodes);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
||||
|
@ -728,9 +738,10 @@ void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|||
|
||||
void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
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);
|
||||
uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
|
||||
size_t matches_size = 4 * num_bytes;
|
||||
|
@ -747,10 +758,16 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|||
BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
|
||||
size_t gap = 0;
|
||||
size_t shadow_matches = 0;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
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) {
|
||||
const size_t pos = position + i;
|
||||
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 num_found_matches;
|
||||
size_t cur_match_end;
|
||||
|
@ -759,10 +776,10 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|||
BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
|
||||
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
num_found_matches = FindAllMatchesH10(hasher,
|
||||
num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
|
||||
¶ms->dictionary,
|
||||
ringbuffer, ringbuffer_mask, pos, max_length,
|
||||
max_distance, gap, params,
|
||||
max_distance, dictionary_start + gap, params,
|
||||
&matches[cur_match_pos + shadow_matches]);
|
||||
cur_match_end = cur_match_pos + num_found_matches;
|
||||
for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
|
||||
|
@ -777,7 +794,8 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|||
matches[cur_match_pos++] = matches[cur_match_end - 1];
|
||||
num_matches[i] = 1;
|
||||
/* 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));
|
||||
memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
|
||||
i += skip;
|
||||
|
@ -791,7 +809,7 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|||
memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
|
||||
orig_num_commands = *num_commands;
|
||||
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, ¶ms->dist, num_bytes);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
@ -23,15 +24,17 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||
|
||||
BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask, const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals);
|
||||
|
||||
typedef struct ZopfliNode {
|
||||
|
@ -77,8 +80,8 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
|
|||
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
|
||||
MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes);
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes);
|
||||
|
||||
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
|
||||
const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes,
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
size_t num_bytes, size_t position,
|
||||
const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
const BrotliEncoderParams* params,
|
||||
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
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. */
|
||||
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;
|
||||
size_t insert_length = *last_insert_len;
|
||||
|
@ -31,19 +33,23 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|||
/* Minimum score to accept a backward reference. */
|
||||
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) {
|
||||
size_t max_length = pos_end - position;
|
||||
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;
|
||||
sr.len = 0;
|
||||
sr.len_code_delta = 0;
|
||||
sr.distance = 0;
|
||||
sr.score = kMinScore;
|
||||
FN(FindLongestMatch)(hasher, ¶ms->dictionary,
|
||||
FN(FindLongestMatch)(privat, ¶ms->dictionary,
|
||||
ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
|
||||
max_distance, gap, params->dist.max_distance, &sr);
|
||||
max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
|
||||
if (sr.score > kMinScore) {
|
||||
/* Found a match. Let's look for something even better ahead. */
|
||||
int delayed_backward_references_in_row = 0;
|
||||
|
@ -57,10 +63,13 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|||
sr2.distance = 0;
|
||||
sr2.score = kMinScore;
|
||||
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
|
||||
FN(FindLongestMatch)(hasher,
|
||||
dictionary_start = BROTLI_MIN(size_t,
|
||||
position + 1 + position_offset, max_backward_limit);
|
||||
FN(FindLongestMatch)(privat,
|
||||
¶ms->dictionary,
|
||||
ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
|
||||
max_distance, gap, params->dist.max_distance, &sr2);
|
||||
max_distance, dictionary_start + gap, params->dist.max_distance,
|
||||
&sr2);
|
||||
if (sr2.score >= sr.score + cost_diff_lazy) {
|
||||
/* Ok, let's just write one byte for now and start a match from the
|
||||
next byte. */
|
||||
|
@ -76,18 +85,19 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|||
}
|
||||
apply_random_heuristics =
|
||||
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,
|
||||
and the minimum offset is 1. */
|
||||
size_t distance_code = ComputeDistanceCode(
|
||||
sr.distance, max_distance + gap, dist_cache);
|
||||
if ((sr.distance <= (max_distance + gap)) && distance_code > 0) {
|
||||
sr.distance, dictionary_start + gap, dist_cache);
|
||||
if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
|
||||
dist_cache[3] = dist_cache[2];
|
||||
dist_cache[2] = dist_cache[1];
|
||||
dist_cache[1] = dist_cache[0];
|
||||
dist_cache[0] = (int)sr.distance;
|
||||
FN(PrepareDistanceCache)(hasher, dist_cache);
|
||||
FN(PrepareDistanceCache)(privat, dist_cache);
|
||||
}
|
||||
InitCommand(commands++, ¶ms->dist, insert_length,
|
||||
sr.len, sr.len_code_delta, distance_code);
|
||||
|
@ -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, position + sr.len - (sr.distance << 2)));
|
||||
}
|
||||
FN(StoreRange)(hasher, ringbuffer, ringbuffer_mask, range_start,
|
||||
FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
|
||||
range_end);
|
||||
}
|
||||
position += sr.len;
|
||||
|
@ -131,7 +141,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|||
size_t pos_jump =
|
||||
BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
|
||||
for (; position < pos_jump; position += 4) {
|
||||
FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
|
||||
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
|
||||
insert_length += 4;
|
||||
}
|
||||
} else {
|
||||
|
@ -140,7 +150,7 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|||
size_t pos_jump =
|
||||
BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
|
||||
for (; position < pos_jump; position += 2) {
|
||||
FN(Store)(hasher, ringbuffer, ringbuffer_mask, position);
|
||||
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
|
||||
insert_length += 2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
|||
{
|
||||
size_t literals_count = CountLiterals(cmds, num_commands);
|
||||
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. */
|
||||
CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
|
||||
/* Create the block split on the array of literals.
|
||||
|
@ -150,7 +150,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
|||
/* Compute prefix codes for commands. */
|
||||
uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands);
|
||||
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) {
|
||||
insert_and_copy_codes[i] = cmds[i].cmd_prefix_;
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
|||
uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands);
|
||||
size_t j = 0;
|
||||
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) {
|
||||
const Command* cmd = &cmds[i];
|
||||
if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
|
||||
|
|
|
@ -219,7 +219,12 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
|||
uint32_t symbols[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));
|
||||
|
||||
|
@ -278,11 +283,11 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
|||
if (pairs_capacity < max_num_pairs + 1) {
|
||||
BROTLI_FREE(m, pairs);
|
||||
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);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return;
|
||||
for (i = 0; i < num_clusters; ++i) {
|
||||
clusters[i] = (uint32_t)i;
|
||||
}
|
||||
|
@ -294,7 +299,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
|||
BROTLI_FREE(m, cluster_size);
|
||||
|
||||
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;
|
||||
pos = 0;
|
||||
{
|
||||
|
@ -386,7 +391,7 @@ static void FN(SplitByteVector)(MemoryManager* m,
|
|||
return;
|
||||
}
|
||||
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. */
|
||||
FN(InitialEntropyCodes)(data, 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);
|
||||
const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
|
||||
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) {
|
||||
num_blocks = FN(FindBlocks)(data, length,
|
||||
block_switch_cost,
|
||||
|
|
|
@ -34,33 +34,18 @@ extern "C" {
|
|||
BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_LARGE_MAX_DISTANCE_BITS)
|
||||
/* MAX_SIMPLE_DISTANCE_ALPHABET_SIZE == 140 */
|
||||
|
||||
/* 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) {
|
||||
uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0);
|
||||
while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) &&
|
||||
len >= kBlockLengthPrefixCode[code + 1].offset) ++code;
|
||||
len >= _kBrotliPrefixCodeRanges[code + 1].offset) ++code;
|
||||
return code;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void GetBlockLengthPrefixCode(uint32_t len, size_t* code,
|
||||
uint32_t* n_extra, uint32_t* extra) {
|
||||
*code = BlockLengthPrefixCode(len);
|
||||
*n_extra = kBlockLengthPrefixCode[*code].nbits;
|
||||
*extra = len - kBlockLengthPrefixCode[*code].offset;
|
||||
*n_extra = _kBrotliPrefixCodeRanges[*code].nbits;
|
||||
*extra = len - _kBrotliPrefixCodeRanges[*code].offset;
|
||||
}
|
||||
|
||||
typedef struct BlockTypeCodeCalculator {
|
||||
|
@ -450,7 +435,7 @@ void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
|
|||
const size_t max_tree_size = 2 * length + 1;
|
||||
HuffmanTree* tree = BROTLI_ALLOC(m, HuffmanTree, max_tree_size);
|
||||
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) {
|
||||
HuffmanTree* node = tree;
|
||||
size_t l;
|
||||
|
@ -714,7 +699,7 @@ static void EncodeContextMap(MemoryManager* m,
|
|||
}
|
||||
|
||||
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);
|
||||
RunLengthCodeZeros(context_map_size, rle_symbols,
|
||||
&num_rle_symbols, &max_run_length_prefix);
|
||||
|
@ -956,23 +941,21 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
|||
|
||||
size_t pos = start_pos;
|
||||
size_t i;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size;
|
||||
uint32_t num_effective_distance_symbols = num_distance_symbols;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
uint32_t num_effective_distance_symbols = params->dist.alphabet_size_limit;
|
||||
HuffmanTree* tree;
|
||||
ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
|
||||
BlockEncoder literal_enc;
|
||||
BlockEncoder command_enc;
|
||||
BlockEncoder distance_enc;
|
||||
const BrotliDistanceParams* dist = ¶ms->dist;
|
||||
if (params->large_window &&
|
||||
num_effective_distance_symbols > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
|
||||
num_effective_distance_symbols = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
|
||||
}
|
||||
BROTLI_DCHECK(
|
||||
num_effective_distance_symbols <= BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS);
|
||||
|
||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||
|
||||
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, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
mb->literal_split.num_types, mb->literal_split.types,
|
||||
mb->literal_split.lengths, mb->literal_split.num_blocks);
|
||||
|
@ -1163,7 +1146,7 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
|||
uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
HuffmanTree* tree;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
|
||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||
|
||||
|
@ -1177,7 +1160,7 @@ void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
|||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
|
||||
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,
|
||||
BROTLI_NUM_LITERAL_SYMBOLS, tree,
|
||||
lit_depth, lit_bits,
|
||||
|
@ -1206,7 +1189,7 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
|||
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||
const Command* commands, size_t n_commands,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size;
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
uint32_t distance_alphabet_bits =
|
||||
Log2FloorNonZero(num_distance_symbols - 1) + 1;
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
|
|||
uint32_t next_index;
|
||||
HistogramType* tmp;
|
||||
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) {
|
||||
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
|
||||
tmp and reduce the number of copying by the factor of 2. */
|
||||
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;
|
||||
for (i = 0; i < length; ++i) {
|
||||
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);
|
||||
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) {
|
||||
cluster_size[i] = 1;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./command.h"
|
||||
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26,
|
||||
34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594};
|
||||
const uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24};
|
||||
const uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18,
|
||||
22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118};
|
||||
const uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24};
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
|
@ -20,14 +20,14 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
static uint32_t kInsBase[] = { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50,
|
||||
66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 };
|
||||
static uint32_t kInsExtra[] = { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
|
||||
5, 5, 6, 7, 8, 9, 10, 12, 14, 24 };
|
||||
static uint32_t kCopyBase[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30,
|
||||
38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118 };
|
||||
static uint32_t kCopyExtra[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
|
||||
4, 4, 5, 5, 6, 7, 8, 9, 10, 24 };
|
||||
BROTLI_INTERNAL extern const uint32_t
|
||||
kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const uint32_t
|
||||
kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const uint32_t
|
||||
kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const uint32_t
|
||||
kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES];
|
||||
|
||||
static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
|
||||
if (insertlen < 6) {
|
||||
|
@ -89,19 +89,19 @@ static BROTLI_INLINE void GetLengthCode(size_t insertlen, size_t copylen,
|
|||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) {
|
||||
return kInsBase[inscode];
|
||||
return kBrotliInsBase[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) {
|
||||
return kCopyBase[copycode];
|
||||
return kBrotliCopyBase[copycode];
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) {
|
||||
return kCopyExtra[copycode];
|
||||
return kBrotliCopyExtra[copycode];
|
||||
}
|
||||
|
||||
typedef struct Command {
|
||||
|
|
|
@ -524,7 +524,7 @@ static void StoreCommands(MemoryManager* m,
|
|||
static BROTLI_BOOL ShouldCompress(
|
||||
const uint8_t* input, size_t input_size, size_t num_literals) {
|
||||
double corpus_size = (double)input_size;
|
||||
if (num_literals < MIN_RATIO * corpus_size) {
|
||||
if ((double)num_literals < MIN_RATIO * corpus_size) {
|
||||
return BROTLI_TRUE;
|
||||
} else {
|
||||
uint32_t literal_histo[256] = { 0 };
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,7 +15,8 @@
|
|||
extern "C" {
|
||||
#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)
|
||||
} /* extern "C" */
|
||||
|
|
|
@ -54,12 +54,19 @@ typedef enum BrotliEncoderStreamState {
|
|||
BROTLI_STREAM_METADATA_BODY = 4
|
||||
} BrotliEncoderStreamState;
|
||||
|
||||
typedef enum BrotliEncoderFlintState {
|
||||
BROTLI_FLINT_NEEDS_2_BYTES = 2,
|
||||
BROTLI_FLINT_NEEDS_1_BYTE = 1,
|
||||
BROTLI_FLINT_WAITING_FOR_PROCESSING = 0,
|
||||
BROTLI_FLINT_WAITING_FOR_FLUSHING = -1,
|
||||
BROTLI_FLINT_DONE = -2
|
||||
} BrotliEncoderFlintState;
|
||||
|
||||
typedef struct BrotliEncoderStateStruct {
|
||||
BrotliEncoderParams params;
|
||||
|
||||
MemoryManager memory_manager_;
|
||||
|
||||
HasherHandle hasher_;
|
||||
uint64_t input_pos_;
|
||||
RingBuffer ringbuffer_;
|
||||
size_t cmd_alloc_size_;
|
||||
|
@ -73,10 +80,17 @@ typedef struct BrotliEncoderStateStruct {
|
|||
int saved_dist_cache_[4];
|
||||
uint16_t last_bytes_;
|
||||
uint8_t last_bytes_bits_;
|
||||
/* "Flint" is a tiny uncompressed block emitted before the continuation
|
||||
block to unwire literal context from previous data. Despite being int8_t,
|
||||
field is actually BrotliEncoderFlintState enum. */
|
||||
int8_t flint_;
|
||||
uint8_t prev_byte_;
|
||||
uint8_t prev_byte2_;
|
||||
size_t storage_size_;
|
||||
uint8_t* storage_;
|
||||
|
||||
Hasher hasher_;
|
||||
|
||||
/* Hash table for FAST_ONE_PASS_COMPRESSION_QUALITY mode. */
|
||||
int small_table_[1 << 10]; /* 4KiB */
|
||||
int* large_table_; /* Allocated only when needed */
|
||||
|
@ -114,8 +128,6 @@ typedef struct BrotliEncoderStateStruct {
|
|||
BROTLI_BOOL is_initialized_;
|
||||
} BrotliEncoderStateStruct;
|
||||
|
||||
static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s);
|
||||
|
||||
static size_t InputBlockSize(BrotliEncoderState* s) {
|
||||
return (size_t)1 << s->params.lgblock;
|
||||
}
|
||||
|
@ -174,6 +186,11 @@ BROTLI_BOOL BrotliEncoderSetParameter(
|
|||
state->params.dist.num_direct_distance_codes = value;
|
||||
return BROTLI_TRUE;
|
||||
|
||||
case BROTLI_PARAM_STREAM_OFFSET:
|
||||
if (value > (1u << 30)) return BROTLI_FALSE;
|
||||
state->params.stream_offset = value;
|
||||
return BROTLI_TRUE;
|
||||
|
||||
default: return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +212,7 @@ static uint8_t* GetBrotliStorage(BrotliEncoderState* s, size_t size) {
|
|||
if (s->storage_size_ < size) {
|
||||
BROTLI_FREE(m, s->storage_);
|
||||
s->storage_ = BROTLI_ALLOC(m, uint8_t, size);
|
||||
if (BROTLI_IS_OOM(m)) return NULL;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->storage_)) return NULL;
|
||||
s->storage_size_ = size;
|
||||
}
|
||||
return s->storage_;
|
||||
|
@ -234,7 +251,7 @@ static int* GetHashTable(BrotliEncoderState* s, int quality,
|
|||
s->large_table_size_ = htsize;
|
||||
BROTLI_FREE(m, s->large_table_);
|
||||
s->large_table_ = BROTLI_ALLOC(m, int, htsize);
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->large_table_)) return 0;
|
||||
}
|
||||
table = s->large_table_;
|
||||
}
|
||||
|
@ -499,7 +516,7 @@ static BROTLI_BOOL ShouldCompress(
|
|||
/* TODO: find more precise minimal block overhead. */
|
||||
if (bytes <= 2) return BROTLI_FALSE;
|
||||
if (num_commands < (bytes >> 8) + 2) {
|
||||
if (num_literals > 0.99 * (double)bytes) {
|
||||
if ((double)num_literals > 0.99 * (double)bytes) {
|
||||
uint32_t literal_histo[256] = { 0 };
|
||||
static const uint32_t kSampleRate = 13;
|
||||
static const double kMinEntropy = 7.92;
|
||||
|
@ -617,11 +634,7 @@ static void WriteMetaBlockInternal(MemoryManager* m,
|
|||
/* The number of distance symbols effectively used for distance
|
||||
histograms. It might be less than distance alphabet size
|
||||
for "Large Window Brotli" (32-bit). */
|
||||
uint32_t num_effective_dist_codes = block_params.dist.alphabet_size;
|
||||
if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
|
||||
num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
|
||||
}
|
||||
BrotliOptimizeHistograms(num_effective_dist_codes, &mb);
|
||||
BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
|
||||
}
|
||||
BrotliStoreMetaBlock(m, data, wrapped_last_flush_pos, bytes, mask,
|
||||
prev_byte, prev_byte2,
|
||||
|
@ -678,12 +691,23 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
|
|||
|
||||
s->last_bytes_bits_ = 0;
|
||||
s->last_bytes_ = 0;
|
||||
s->flint_ = BROTLI_FLINT_DONE;
|
||||
s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
|
||||
|
||||
SanitizeParams(&s->params);
|
||||
s->params.lgblock = ComputeLgBlock(&s->params);
|
||||
ChooseDistanceParams(&s->params);
|
||||
|
||||
if (s->params.stream_offset != 0) {
|
||||
s->flint_ = BROTLI_FLINT_NEEDS_2_BYTES;
|
||||
/* Poison the distance cache. -16 +- 3 is still less than zero (invalid). */
|
||||
s->dist_cache_[0] = -16;
|
||||
s->dist_cache_[1] = -16;
|
||||
s->dist_cache_[2] = -16;
|
||||
s->dist_cache_[3] = -16;
|
||||
memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
|
||||
}
|
||||
|
||||
RingBufferSetup(&s->params, &s->ringbuffer_);
|
||||
|
||||
/* Initialize last byte with stream header. */
|
||||
|
@ -693,8 +717,14 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
|
|||
s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
|
||||
lgwin = BROTLI_MAX(int, lgwin, 18);
|
||||
}
|
||||
EncodeWindowBits(lgwin, s->params.large_window,
|
||||
&s->last_bytes_, &s->last_bytes_bits_);
|
||||
if (s->params.stream_offset == 0) {
|
||||
EncodeWindowBits(lgwin, s->params.large_window,
|
||||
&s->last_bytes_, &s->last_bytes_bits_);
|
||||
} else {
|
||||
/* Bigger values have the same effect, but could cause overflows. */
|
||||
s->params.stream_offset = BROTLI_MIN(size_t,
|
||||
s->params.stream_offset, BROTLI_MAX_BACKWARD_LIMIT(lgwin));
|
||||
}
|
||||
}
|
||||
|
||||
if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
|
||||
|
@ -712,13 +742,15 @@ static void BrotliEncoderInitParams(BrotliEncoderParams* params) {
|
|||
params->quality = BROTLI_DEFAULT_QUALITY;
|
||||
params->lgwin = BROTLI_DEFAULT_WINDOW;
|
||||
params->lgblock = 0;
|
||||
params->stream_offset = 0;
|
||||
params->size_hint = 0;
|
||||
params->disable_literal_context_modeling = BROTLI_FALSE;
|
||||
BrotliInitEncoderDictionary(¶ms->dictionary);
|
||||
params->dist.distance_postfix_bits = 0;
|
||||
params->dist.num_direct_distance_codes = 0;
|
||||
params->dist.alphabet_size =
|
||||
params->dist.alphabet_size_max =
|
||||
BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_MAX_DISTANCE_BITS);
|
||||
params->dist.alphabet_size_limit = params->dist.alphabet_size_max;
|
||||
params->dist.max_distance = BROTLI_MAX_DISTANCE;
|
||||
}
|
||||
|
||||
|
@ -734,7 +766,7 @@ static void BrotliEncoderInitState(BrotliEncoderState* s) {
|
|||
s->prev_byte2_ = 0;
|
||||
s->storage_size_ = 0;
|
||||
s->storage_ = 0;
|
||||
s->hasher_ = NULL;
|
||||
HasherInit(&s->hasher_);
|
||||
s->large_table_ = NULL;
|
||||
s->large_table_size_ = 0;
|
||||
s->cmd_code_numbits_ = 0;
|
||||
|
@ -902,6 +934,7 @@ static void ExtendLastCommand(BrotliEncoderState* s, uint32_t* bytes,
|
|||
(*bytes)--;
|
||||
(*wrapped_last_processed_pos)++;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
/* The copy length is at most the metablock size, and thus expressible. */
|
||||
GetLengthCode(last_command->insert_len_,
|
||||
|
@ -934,6 +967,7 @@ static BROTLI_BOOL EncodeData(
|
|||
uint32_t mask;
|
||||
MemoryManager* m = &s->memory_manager_;
|
||||
ContextType literal_context_mode;
|
||||
ContextLut literal_context_lut;
|
||||
|
||||
data = s->ringbuffer_.buffer_;
|
||||
mask = s->ringbuffer_.mask_;
|
||||
|
@ -951,7 +985,10 @@ static BROTLI_BOOL EncodeData(
|
|||
BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
|
||||
s->literal_buf_ =
|
||||
BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
|
||||
BROTLI_IS_NULL(s->literal_buf_)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
|
||||
|
@ -1009,7 +1046,7 @@ static BROTLI_BOOL EncodeData(
|
|||
newsize += (bytes / 4) + 16;
|
||||
s->cmd_alloc_size_ = newsize;
|
||||
new_commands = BROTLI_ALLOC(m, Command, newsize);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) return BROTLI_FALSE;
|
||||
if (s->commands_) {
|
||||
memcpy(new_commands, s->commands_, sizeof(Command) * s->num_commands_);
|
||||
BROTLI_FREE(m, s->commands_);
|
||||
|
@ -1024,6 +1061,7 @@ static BROTLI_BOOL EncodeData(
|
|||
literal_context_mode = ChooseContextMode(
|
||||
&s->params, data, WrapPosition(s->last_flush_pos_),
|
||||
mask, (size_t)(s->input_pos_ - s->last_flush_pos_));
|
||||
literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
|
||||
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
|
||||
|
@ -1034,20 +1072,23 @@ static BROTLI_BOOL EncodeData(
|
|||
if (s->params.quality == ZOPFLIFICATION_QUALITY) {
|
||||
BROTLI_DCHECK(s->params.hasher.type == 10);
|
||||
BrotliCreateZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
|
||||
data, mask, &s->params, s->hasher_, s->dist_cache_,
|
||||
data, mask, literal_context_lut, &s->params,
|
||||
&s->hasher_, s->dist_cache_,
|
||||
&s->last_insert_len_, &s->commands_[s->num_commands_],
|
||||
&s->num_commands_, &s->num_literals_);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
} else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) {
|
||||
BROTLI_DCHECK(s->params.hasher.type == 10);
|
||||
BrotliCreateHqZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
|
||||
data, mask, &s->params, s->hasher_, s->dist_cache_,
|
||||
data, mask, literal_context_lut, &s->params,
|
||||
&s->hasher_, s->dist_cache_,
|
||||
&s->last_insert_len_, &s->commands_[s->num_commands_],
|
||||
&s->num_commands_, &s->num_literals_);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
} else {
|
||||
BrotliCreateBackwardReferences(bytes, wrapped_last_processed_pos,
|
||||
data, mask, &s->params, s->hasher_, s->dist_cache_,
|
||||
data, mask, literal_context_lut, &s->params,
|
||||
&s->hasher_, s->dist_cache_,
|
||||
&s->last_insert_len_, &s->commands_[s->num_commands_],
|
||||
&s->num_commands_, &s->num_literals_);
|
||||
}
|
||||
|
@ -1072,7 +1113,7 @@ static BROTLI_BOOL EncodeData(
|
|||
s->num_commands_ < max_commands) {
|
||||
/* Merge with next input block. Everything will happen later. */
|
||||
if (UpdateLastProcessedPos(s)) {
|
||||
HasherReset(s->hasher_);
|
||||
HasherReset(&s->hasher_);
|
||||
}
|
||||
*out_size = 0;
|
||||
return BROTLI_TRUE;
|
||||
|
@ -1113,7 +1154,7 @@ static BROTLI_BOOL EncodeData(
|
|||
s->last_bytes_bits_ = storage_ix & 7u;
|
||||
s->last_flush_pos_ = s->input_pos_;
|
||||
if (UpdateLastProcessedPos(s)) {
|
||||
HasherReset(s->hasher_);
|
||||
HasherReset(&s->hasher_);
|
||||
}
|
||||
if (s->last_flush_pos_ > 0) {
|
||||
s->prev_byte_ = data[((uint32_t)s->last_flush_pos_ - 1) & mask];
|
||||
|
@ -1174,7 +1215,6 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|||
size_t total_out_size = 0;
|
||||
uint16_t last_bytes;
|
||||
uint8_t last_bytes_bits;
|
||||
HasherHandle hasher = NULL;
|
||||
|
||||
const size_t hasher_eff_size = BROTLI_MIN(size_t,
|
||||
input_size, BROTLI_MAX_BACKWARD_LIMIT(lgwin) + BROTLI_WINDOW_GAP);
|
||||
|
@ -1190,6 +1230,9 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|||
uint8_t prev_byte = 0;
|
||||
uint8_t prev_byte2 = 0;
|
||||
|
||||
Hasher hasher;
|
||||
HasherInit(&hasher);
|
||||
|
||||
BrotliEncoderInitParams(¶ms);
|
||||
params.quality = 10;
|
||||
params.lgwin = lgwin;
|
||||
|
@ -1226,6 +1269,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|||
|
||||
ContextType literal_context_mode = ChooseContextMode(¶ms,
|
||||
input_buffer, metablock_start, mask, metablock_end - metablock_start);
|
||||
ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
|
||||
|
||||
size_t block_start;
|
||||
for (block_start = metablock_start; block_start < metablock_end; ) {
|
||||
|
@ -1234,12 +1278,12 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|||
ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, block_size + 1);
|
||||
size_t path_size;
|
||||
size_t new_cmd_alloc_size;
|
||||
if (BROTLI_IS_OOM(m)) goto oom;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) goto oom;
|
||||
BrotliInitZopfliNodes(nodes, block_size + 1);
|
||||
StitchToPreviousBlockH10(hasher, block_size, block_start,
|
||||
StitchToPreviousBlockH10(&hasher.privat._H10, block_size, block_start,
|
||||
input_buffer, mask);
|
||||
path_size = BrotliZopfliComputeShortestPath(m, block_size, block_start,
|
||||
input_buffer, mask, ¶ms, dist_cache, hasher,
|
||||
input_buffer, mask, literal_context_lut, ¶ms, dist_cache, &hasher,
|
||||
nodes);
|
||||
if (BROTLI_IS_OOM(m)) goto oom;
|
||||
/* We allocate a command buffer in the first iteration of this loop that
|
||||
|
@ -1254,7 +1298,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|||
num_commands + path_size + 1);
|
||||
if (cmd_alloc_size != new_cmd_alloc_size) {
|
||||
Command* new_commands = BROTLI_ALLOC(m, Command, new_cmd_alloc_size);
|
||||
if (BROTLI_IS_OOM(m)) goto oom;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) goto oom;
|
||||
cmd_alloc_size = new_cmd_alloc_size;
|
||||
if (commands) {
|
||||
memcpy(new_commands, commands, sizeof(Command) * num_commands);
|
||||
|
@ -1286,7 +1330,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|||
if (metablock_size == 0) {
|
||||
/* Write the ISLAST and ISEMPTY bits. */
|
||||
storage = BROTLI_ALLOC(m, uint8_t, 16);
|
||||
if (BROTLI_IS_OOM(m)) goto oom;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
|
||||
storage[0] = (uint8_t)last_bytes;
|
||||
storage[1] = (uint8_t)(last_bytes >> 8);
|
||||
BrotliWriteBits(2, 3, &storage_ix, storage);
|
||||
|
@ -1297,7 +1341,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|||
CreateBackwardReferences is now unused. */
|
||||
memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
|
||||
storage = BROTLI_ALLOC(m, uint8_t, metablock_size + 16);
|
||||
if (BROTLI_IS_OOM(m)) goto oom;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
|
||||
storage[0] = (uint8_t)last_bytes;
|
||||
storage[1] = (uint8_t)(last_bytes >> 8);
|
||||
BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
|
||||
|
@ -1318,14 +1362,10 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|||
/* The number of distance symbols effectively used for distance
|
||||
histograms. It might be less than distance alphabet size
|
||||
for "Large Window Brotli" (32-bit). */
|
||||
uint32_t num_effective_dist_codes = block_params.dist.alphabet_size;
|
||||
if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
|
||||
num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
|
||||
}
|
||||
BrotliOptimizeHistograms(num_effective_dist_codes, &mb);
|
||||
BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
|
||||
}
|
||||
storage = BROTLI_ALLOC(m, uint8_t, 2 * metablock_size + 503);
|
||||
if (BROTLI_IS_OOM(m)) goto oom;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
|
||||
storage[0] = (uint8_t)last_bytes;
|
||||
storage[1] = (uint8_t)(last_bytes >> 8);
|
||||
BrotliStoreMetaBlock(m, input_buffer, metablock_start, metablock_size,
|
||||
|
@ -1576,7 +1616,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
|
|||
BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
|
||||
s->literal_buf_ =
|
||||
BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
|
||||
BROTLI_IS_NULL(s->literal_buf_)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
if (s->command_buf_) {
|
||||
command_buf = s->command_buf_;
|
||||
|
@ -1584,7 +1627,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
|
|||
} else {
|
||||
tmp_command_buf = BROTLI_ALLOC(m, uint32_t, buf_size);
|
||||
tmp_literal_buf = BROTLI_ALLOC(m, uint8_t, buf_size);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp_command_buf) ||
|
||||
BROTLI_IS_NULL(tmp_literal_buf)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
command_buf = tmp_command_buf;
|
||||
literal_buf = tmp_literal_buf;
|
||||
}
|
||||
|
@ -1640,8 +1686,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
|
|||
&storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
}
|
||||
*next_in += block_size;
|
||||
*available_in -= block_size;
|
||||
if (block_size != 0) {
|
||||
*next_in += block_size;
|
||||
*available_in -= block_size;
|
||||
}
|
||||
if (inplace) {
|
||||
size_t out_bytes = storage_ix >> 3;
|
||||
BROTLI_DCHECK(out_bytes <= *available_out);
|
||||
|
@ -1786,6 +1834,10 @@ BROTLI_BOOL BrotliEncoderCompressStream(
|
|||
}
|
||||
while (BROTLI_TRUE) {
|
||||
size_t remaining_block_size = RemainingInputBlockSize(s);
|
||||
/* Shorten input to flint size. */
|
||||
if (s->flint_ >= 0 && remaining_block_size > (size_t)s->flint_) {
|
||||
remaining_block_size = (size_t)s->flint_;
|
||||
}
|
||||
|
||||
if (remaining_block_size != 0 && *available_in != 0) {
|
||||
size_t copy_input_size =
|
||||
|
@ -1793,10 +1845,18 @@ BROTLI_BOOL BrotliEncoderCompressStream(
|
|||
CopyInputToRingBuffer(s, copy_input_size, *next_in);
|
||||
*next_in += copy_input_size;
|
||||
*available_in -= copy_input_size;
|
||||
if (s->flint_ > 0) s->flint_ = (int8_t)(s->flint_ - (int)copy_input_size);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) {
|
||||
/* Exit the "emit flint" workflow. */
|
||||
if (s->flint_ == BROTLI_FLINT_WAITING_FOR_FLUSHING) {
|
||||
CheckFlushComplete(s);
|
||||
if (s->stream_state_ == BROTLI_STREAM_PROCESSING) {
|
||||
s->flint_ = BROTLI_FLINT_DONE;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1810,6 +1870,11 @@ BROTLI_BOOL BrotliEncoderCompressStream(
|
|||
BROTLI_BOOL force_flush = TO_BROTLI_BOOL(
|
||||
(*available_in == 0) && op == BROTLI_OPERATION_FLUSH);
|
||||
BROTLI_BOOL result;
|
||||
/* Force emitting (uncompressed) piece containing flint. */
|
||||
if (!is_last && s->flint_ == 0) {
|
||||
s->flint_ = BROTLI_FLINT_WAITING_FOR_FLUSHING;
|
||||
force_flush = BROTLI_TRUE;
|
||||
}
|
||||
UpdateSizeHint(s, *available_in);
|
||||
result = EncodeData(s, is_last, force_flush,
|
||||
&s->available_out_, &s->next_out_);
|
||||
|
|
|
@ -17,14 +17,15 @@ extern "C" {
|
|||
|
||||
void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict) {
|
||||
dict->words = BrotliGetDictionary();
|
||||
dict->num_transforms = (uint32_t)BrotliGetTransforms()->num_transforms;
|
||||
|
||||
dict->hash_table = kStaticDictionaryHash;
|
||||
dict->hash_table_words = kStaticDictionaryHashWords;
|
||||
dict->hash_table_lengths = kStaticDictionaryHashLengths;
|
||||
dict->buckets = kStaticDictionaryBuckets;
|
||||
dict->dict_words = kStaticDictionaryWords;
|
||||
|
||||
dict->cutoffTransformsCount = kCutoffTransformsCount;
|
||||
dict->cutoffTransforms = kCutoffTransforms;
|
||||
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
|
|
@ -19,13 +19,15 @@ extern "C" {
|
|||
/* Dictionary data (words and transforms) for 1 possible context */
|
||||
typedef struct BrotliEncoderDictionary {
|
||||
const BrotliDictionary* words;
|
||||
uint32_t num_transforms;
|
||||
|
||||
/* cut off for fast encoder */
|
||||
uint32_t cutoffTransformsCount;
|
||||
uint64_t cutoffTransforms;
|
||||
|
||||
/* from dictionary_hash.h, for fast encoder */
|
||||
const uint16_t* hash_table;
|
||||
const uint16_t* hash_table_words;
|
||||
const uint8_t* hash_table_lengths;
|
||||
|
||||
/* from static_dict_lut.h, for slow encoder */
|
||||
const uint16_t* buckets;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
const size_t kBrotliShellGaps[] = {132, 57, 23, 10, 4, 1};
|
||||
|
||||
BROTLI_BOOL BrotliSetDepth(
|
||||
int p0, HuffmanTree* pool, uint8_t* depth, int max_depth) {
|
||||
int stack[16];
|
||||
|
|
|
@ -76,12 +76,12 @@ BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
|
|||
size_t len,
|
||||
uint16_t* bits);
|
||||
|
||||
BROTLI_INTERNAL extern const size_t kBrotliShellGaps[6];
|
||||
/* Input size optimized Shell sort. */
|
||||
typedef BROTLI_BOOL (*HuffmanTreeComparator)(
|
||||
const HuffmanTree*, const HuffmanTree*);
|
||||
static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
|
||||
const size_t n, HuffmanTreeComparator comparator) {
|
||||
static const size_t gaps[] = {132, 57, 23, 10, 4, 1};
|
||||
if (n < 13) {
|
||||
/* Insertion sort. */
|
||||
size_t i;
|
||||
|
@ -101,7 +101,7 @@ static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
|
|||
/* Shell sort. */
|
||||
int g = n < 57 ? 2 : 0;
|
||||
for (; g < 6; ++g) {
|
||||
size_t gap = gaps[g];
|
||||
size_t gap = kBrotliShellGaps[g];
|
||||
size_t i;
|
||||
for (i = gap; i < n; ++i) {
|
||||
size_t j = i;
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./fast_log.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
|
||||
const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE] = {
|
||||
0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
|
||||
1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
|
||||
2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
|
||||
3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f,
|
||||
3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f,
|
||||
3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f,
|
||||
4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f,
|
||||
4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f,
|
||||
4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f,
|
||||
4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f,
|
||||
4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f,
|
||||
5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f,
|
||||
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
|
||||
};
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
|
@ -19,10 +19,8 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
|
||||
/* TODO: generalize and move to platform.h */
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
return 31u ^ (uint32_t)__builtin_clz((uint32_t)n);
|
||||
#if defined(BROTLI_BSR32)
|
||||
return BROTLI_BSR32((uint32_t)n);
|
||||
#else
|
||||
uint32_t result = 0;
|
||||
while (n >>= 1) result++;
|
||||
|
@ -30,110 +28,31 @@ static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/* A lookup table for small values of log2(int) to be used in entropy
|
||||
computation.
|
||||
#define BROTLI_LOG2_TABLE_SIZE 256
|
||||
|
||||
", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
|
||||
static const float kLog2Table[] = {
|
||||
0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
|
||||
1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
|
||||
2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
|
||||
3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f,
|
||||
3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f,
|
||||
3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f,
|
||||
4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f,
|
||||
4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f,
|
||||
4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f,
|
||||
4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f,
|
||||
4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f,
|
||||
5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f,
|
||||
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
|
||||
};
|
||||
/* A lookup table for small values of log2(int) to be used in entropy
|
||||
computation. */
|
||||
BROTLI_INTERNAL extern const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE];
|
||||
|
||||
/* Visual Studio 2012 and Android API levels < 18 do not have the log2()
|
||||
* function defined, so we use log() and a multiplication instead. */
|
||||
#if !defined(BROTLI_HAVE_LOG2)
|
||||
#if ((defined(_MSC_VER) && _MSC_VER <= 1700) || \
|
||||
(defined(__ANDROID_API__) && __ANDROID_API__ < 18))
|
||||
#define BROTLI_HAVE_LOG2 0
|
||||
#else
|
||||
#define BROTLI_HAVE_LOG2 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LOG_2_INV 1.4426950408889634
|
||||
|
||||
/* Faster logarithm for small integers, with the property of log2(0) == 0. */
|
||||
static BROTLI_INLINE double FastLog2(size_t v) {
|
||||
if (v < sizeof(kLog2Table) / sizeof(kLog2Table[0])) {
|
||||
return kLog2Table[v];
|
||||
if (v < BROTLI_LOG2_TABLE_SIZE) {
|
||||
return kBrotliLog2Table[v];
|
||||
}
|
||||
#if (defined(_MSC_VER) && _MSC_VER <= 1700) || \
|
||||
(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. */
|
||||
#if !(BROTLI_HAVE_LOG2)
|
||||
return log((double)v) * LOG_2_INV;
|
||||
#else
|
||||
return log2((double)v);
|
||||
|
|
|
@ -17,8 +17,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/* 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,
|
||||
const uint8_t* s2,
|
||||
size_t limit) {
|
||||
|
@ -32,7 +31,7 @@ static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
|
|||
} else {
|
||||
uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
|
||||
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;
|
||||
return matched;
|
||||
}
|
||||
|
|
|
@ -27,34 +27,19 @@
|
|||
extern "C" {
|
||||
#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
|
||||
*
|
||||
* Using "define" instead of "typedef", because on MSVC __restrict does not work
|
||||
* on typedef pointer types. */
|
||||
#define HasherHandle uint8_t*
|
||||
|
||||
typedef struct {
|
||||
/* Dynamically allocated area; first member for quickest access. */
|
||||
void* extra;
|
||||
|
||||
size_t dict_num_lookups;
|
||||
size_t dict_num_matches;
|
||||
|
||||
BrotliHasherParams params;
|
||||
|
||||
/* False if hasher needs to be "prepared" before use. */
|
||||
BROTLI_BOOL is_prepared_;
|
||||
|
||||
size_t dict_num_lookups;
|
||||
size_t dict_num_matches;
|
||||
} HasherCommon;
|
||||
|
||||
static BROTLI_INLINE HasherCommon* GetHasherCommon(HasherHandle handle) {
|
||||
return (HasherCommon*)handle;
|
||||
}
|
||||
|
||||
#define score_t size_t
|
||||
|
||||
static const uint32_t kCutoffTransformsCount = 10;
|
||||
|
@ -149,17 +134,13 @@ static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(
|
|||
}
|
||||
|
||||
static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
|
||||
const BrotliEncoderDictionary* dictionary, size_t item,
|
||||
const BrotliEncoderDictionary* dictionary, size_t len, size_t word_idx,
|
||||
const uint8_t* data, size_t max_length, size_t max_backward,
|
||||
size_t max_distance, HasherSearchResult* out) {
|
||||
size_t len;
|
||||
size_t word_idx;
|
||||
size_t offset;
|
||||
size_t matchlen;
|
||||
size_t backward;
|
||||
score_t score;
|
||||
len = item & 0x1F;
|
||||
word_idx = item >> 5;
|
||||
offset = dictionary->words->offsets_by_length[len] + len * word_idx;
|
||||
if (len > max_length) {
|
||||
return BROTLI_FALSE;
|
||||
|
@ -193,25 +174,24 @@ static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
|
|||
|
||||
static BROTLI_INLINE void SearchInStaticDictionary(
|
||||
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, size_t max_distance,
|
||||
HasherSearchResult* out, BROTLI_BOOL shallow) {
|
||||
size_t key;
|
||||
size_t i;
|
||||
HasherCommon* self = GetHasherCommon(handle);
|
||||
if (self->dict_num_matches < (self->dict_num_lookups >> 7)) {
|
||||
if (common->dict_num_matches < (common->dict_num_lookups >> 7)) {
|
||||
return;
|
||||
}
|
||||
key = Hash14(data) << 1;
|
||||
for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) {
|
||||
size_t item = dictionary->hash_table[key];
|
||||
self->dict_num_lookups++;
|
||||
if (item != 0) {
|
||||
common->dict_num_lookups++;
|
||||
if (dictionary->hash_table_lengths[key] != 0) {
|
||||
BROTLI_BOOL item_matches = TestStaticDictionaryItem(
|
||||
dictionary, item, data,
|
||||
dictionary, dictionary->hash_table_lengths[key],
|
||||
dictionary->hash_table_words[key], data,
|
||||
max_length, max_backward, max_distance, out);
|
||||
if (item_matches) {
|
||||
self->dict_num_matches++;
|
||||
common->dict_num_matches++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -260,37 +240,37 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
|||
/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
|
||||
#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
|
||||
and HTML inputs. */
|
||||
|
||||
#define HASHER() H2
|
||||
#define BUCKET_BITS 16
|
||||
#define BUCKET_SWEEP 1
|
||||
#define BUCKET_SWEEP_BITS 0
|
||||
#define HASH_LEN 5
|
||||
#define USE_DICTIONARY 1
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef BUCKET_SWEEP
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
#undef USE_DICTIONARY
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H3
|
||||
#define BUCKET_SWEEP 2
|
||||
#define BUCKET_SWEEP_BITS 1
|
||||
#define USE_DICTIONARY 0
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef USE_DICTIONARY
|
||||
#undef BUCKET_SWEEP
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
#undef BUCKET_BITS
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H4
|
||||
#define BUCKET_BITS 17
|
||||
#define BUCKET_SWEEP 4
|
||||
#define BUCKET_SWEEP_BITS 2
|
||||
#define USE_DICTIONARY 1
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef USE_DICTIONARY
|
||||
#undef HASH_LEN
|
||||
#undef BUCKET_SWEEP
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
#undef BUCKET_BITS
|
||||
#undef HASHER
|
||||
|
||||
|
@ -334,13 +314,13 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
|||
|
||||
#define HASHER() H54
|
||||
#define BUCKET_BITS 20
|
||||
#define BUCKET_SWEEP 4
|
||||
#define BUCKET_SWEEP_BITS 2
|
||||
#define HASH_LEN 7
|
||||
#define USE_DICTIONARY 0
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef USE_DICTIONARY
|
||||
#undef HASH_LEN
|
||||
#undef BUCKET_SWEEP
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
#undef BUCKET_BITS
|
||||
#undef HASHER
|
||||
|
||||
|
@ -393,97 +373,107 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
|||
#undef 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)\
|
||||
H(35) H(55) H(65)
|
||||
#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)
|
||||
|
||||
static BROTLI_INLINE void DestroyHasher(
|
||||
MemoryManager* m, HasherHandle* handle) {
|
||||
if (*handle == NULL) return;
|
||||
BROTLI_FREE(m, *handle);
|
||||
typedef struct {
|
||||
HasherCommon common;
|
||||
|
||||
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) {
|
||||
if (handle == NULL) return;
|
||||
GetHasherCommon(handle)->is_prepared_ = BROTLI_FALSE;
|
||||
static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) {
|
||||
if (hasher->common.extra == NULL) return;
|
||||
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,
|
||||
BROTLI_BOOL one_shot, const size_t input_size) {
|
||||
size_t result = sizeof(HasherCommon);
|
||||
switch (params->hasher.type) {
|
||||
#define SIZE_(N) \
|
||||
case N: \
|
||||
result += HashMemAllocInBytesH ## N(params, one_shot, input_size); \
|
||||
break;
|
||||
#define SIZE_(N) \
|
||||
case N: \
|
||||
return HashMemAllocInBytesH ## N(params, one_shot, input_size);
|
||||
FOR_ALL_HASHERS(SIZE_)
|
||||
#undef SIZE_
|
||||
default:
|
||||
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,
|
||||
size_t input_size, BROTLI_BOOL is_last) {
|
||||
HasherHandle self = NULL;
|
||||
HasherCommon* common = NULL;
|
||||
BROTLI_BOOL one_shot = (position == 0 && is_last);
|
||||
if (*handle == NULL) {
|
||||
if (hasher->common.extra == NULL) {
|
||||
size_t alloc_size;
|
||||
ChooseHasher(params, ¶ms->hasher);
|
||||
alloc_size = HasherSize(params, one_shot, input_size);
|
||||
self = BROTLI_ALLOC(m, uint8_t, alloc_size);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
*handle = self;
|
||||
common = GetHasherCommon(self);
|
||||
common->params = params->hasher;
|
||||
switch (common->params.type) {
|
||||
#define INITIALIZE_(N) \
|
||||
case N: \
|
||||
InitializeH ## N(*handle, params); \
|
||||
hasher->common.extra = BROTLI_ALLOC(m, uint8_t, alloc_size);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra)) return;
|
||||
hasher->common.params = params->hasher;
|
||||
switch (hasher->common.params.type) {
|
||||
#define INITIALIZE_(N) \
|
||||
case N: \
|
||||
InitializeH ## N(&hasher->common, \
|
||||
&hasher->privat._H ## N, params); \
|
||||
break;
|
||||
FOR_ALL_HASHERS(INITIALIZE_);
|
||||
#undef INITIALIZE_
|
||||
default:
|
||||
break;
|
||||
}
|
||||
HasherReset(*handle);
|
||||
HasherReset(hasher);
|
||||
}
|
||||
|
||||
self = *handle;
|
||||
common = GetHasherCommon(self);
|
||||
if (!common->is_prepared_) {
|
||||
switch (common->params.type) {
|
||||
#define PREPARE_(N) \
|
||||
case N: \
|
||||
PrepareH ## N(self, one_shot, input_size, data); \
|
||||
if (!hasher->common.is_prepared_) {
|
||||
switch (hasher->common.params.type) {
|
||||
#define PREPARE_(N) \
|
||||
case N: \
|
||||
PrepareH ## N( \
|
||||
&hasher->privat._H ## N, \
|
||||
one_shot, input_size, data); \
|
||||
break;
|
||||
FOR_ALL_HASHERS(PREPARE_)
|
||||
#undef PREPARE_
|
||||
default: break;
|
||||
}
|
||||
if (position == 0) {
|
||||
common->dict_num_lookups = 0;
|
||||
common->dict_num_matches = 0;
|
||||
hasher->common.dict_num_lookups = 0;
|
||||
hasher->common.dict_num_matches = 0;
|
||||
}
|
||||
common->is_prepared_ = BROTLI_TRUE;
|
||||
hasher->common.is_prepared_ = BROTLI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
BROTLI_BOOL is_last) {
|
||||
HasherHandle self;
|
||||
HasherSetup(m, handle, params, data, position, input_size, is_last);
|
||||
HasherSetup(m, hasher, params, data, position, input_size, is_last);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
self = *handle;
|
||||
switch (GetHasherCommon(self)->params.type) {
|
||||
#define INIT_(N) \
|
||||
case N: \
|
||||
StitchToPreviousBlockH ## N(self, input_size, position, data, mask); \
|
||||
switch (hasher->common.params.type) {
|
||||
#define INIT_(N) \
|
||||
case N: \
|
||||
StitchToPreviousBlockH ## N( \
|
||||
&hasher->privat._H ## N, \
|
||||
input_size, position, data, mask); \
|
||||
break;
|
||||
FOR_ALL_HASHERS(INIT_)
|
||||
#undef INIT_
|
||||
|
|
|
@ -28,20 +28,25 @@ static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
|
|||
}
|
||||
|
||||
typedef struct HashComposite {
|
||||
HasherHandle ha;
|
||||
HasherHandle hb;
|
||||
HASHER_A ha;
|
||||
HASHER_B hb;
|
||||
HasherCommon hb_common;
|
||||
|
||||
/* Shortcuts. */
|
||||
void* extra;
|
||||
HasherCommon* common;
|
||||
|
||||
BROTLI_BOOL fresh;
|
||||
const BrotliEncoderParams* params;
|
||||
} HashComposite;
|
||||
|
||||
static BROTLI_INLINE HashComposite* FN(Self)(HasherHandle handle) {
|
||||
return (HashComposite*)&(GetHasherCommon(handle)[1]);
|
||||
}
|
||||
static void FN(Initialize)(HasherCommon* common,
|
||||
HashComposite* BROTLI_RESTRICT self, const BrotliEncoderParams* params) {
|
||||
self->common = common;
|
||||
self->extra = common->extra;
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
self->ha = 0;
|
||||
self->hb = 0;
|
||||
self->hb_common = *self->common;
|
||||
self->fresh = BROTLI_TRUE;
|
||||
self->params = params;
|
||||
/* TODO: Initialize of the hashers is defered to Prepare (and params
|
||||
remembered here) because we don't get the one_shot and input_size params
|
||||
|
@ -49,87 +54,71 @@ static void FN(Initialize)(
|
|||
those params to all hashers FN(Initialize) */
|
||||
}
|
||||
|
||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
if (!self->ha) {
|
||||
HasherCommon* common_a;
|
||||
HasherCommon* common_b;
|
||||
static void FN(Prepare)(
|
||||
HashComposite* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
if (self->fresh) {
|
||||
self->fresh = BROTLI_FALSE;
|
||||
self->hb_common.extra = (uint8_t*)self->extra +
|
||||
FN_A(HashMemAllocInBytes)(self->params, one_shot, input_size);
|
||||
|
||||
self->ha = handle + sizeof(HasherCommon) + sizeof(HashComposite);
|
||||
common_a = (HasherCommon*)self->ha;
|
||||
common_a->params = self->params->hasher;
|
||||
common_a->is_prepared_ = BROTLI_FALSE;
|
||||
common_a->dict_num_lookups = 0;
|
||||
common_a->dict_num_matches = 0;
|
||||
FN_A(Initialize)(self->ha, self->params);
|
||||
|
||||
self->hb = self->ha + sizeof(HasherCommon) + FN_A(HashMemAllocInBytes)(
|
||||
self->params, one_shot, input_size);
|
||||
common_b = (HasherCommon*)self->hb;
|
||||
common_b->params = self->params->hasher;
|
||||
common_b->is_prepared_ = BROTLI_FALSE;
|
||||
common_b->dict_num_lookups = 0;
|
||||
common_b->dict_num_matches = 0;
|
||||
FN_B(Initialize)(self->hb, self->params);
|
||||
FN_A(Initialize)(self->common, &self->ha, self->params);
|
||||
FN_B(Initialize)(&self->hb_common, &self->hb, self->params);
|
||||
}
|
||||
FN_A(Prepare)(self->ha, one_shot, input_size, data);
|
||||
FN_B(Prepare)(self->hb, one_shot, input_size, data);
|
||||
FN_A(Prepare)(&self->ha, one_shot, input_size, data);
|
||||
FN_B(Prepare)(&self->hb, one_shot, input_size, data);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
return sizeof(HashComposite) + 2 * sizeof(HasherCommon) +
|
||||
FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
|
||||
return FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
|
||||
FN_B(HashMemAllocInBytes)(params, one_shot, input_size);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
|
||||
static BROTLI_INLINE void FN(Store)(HashComposite* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
FN_A(Store)(self->ha, data, mask, ix);
|
||||
FN_B(Store)(self->hb, data, mask, ix);
|
||||
FN_A(Store)(&self->ha, data, mask, ix);
|
||||
FN_B(Store)(&self->hb, data, mask, ix);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
static BROTLI_INLINE void FN(StoreRange)(
|
||||
HashComposite* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
FN_A(StoreRange)(self->ha, data, mask, ix_start, ix_end);
|
||||
FN_B(StoreRange)(self->hb, data, mask, ix_start, ix_end);
|
||||
FN_A(StoreRange)(&self->ha, data, mask, ix_start, ix_end);
|
||||
FN_B(StoreRange)(&self->hb, data, mask, ix_start, ix_end);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashComposite* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ring_buffer_mask) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
FN_A(StitchToPreviousBlock)(self->ha, num_bytes, position, ringbuffer,
|
||||
ring_buffer_mask);
|
||||
FN_B(StitchToPreviousBlock)(self->hb, num_bytes, position, ringbuffer,
|
||||
ring_buffer_mask);
|
||||
FN_A(StitchToPreviousBlock)(&self->ha, num_bytes, position,
|
||||
ringbuffer, ring_buffer_mask);
|
||||
FN_B(StitchToPreviousBlock)(&self->hb, num_bytes, position,
|
||||
ringbuffer, ring_buffer_mask);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
FN_A(PrepareDistanceCache)(self->ha, distance_cache);
|
||||
FN_B(PrepareDistanceCache)(self->hb, distance_cache);
|
||||
HashComposite* BROTLI_RESTRICT self, int* BROTLI_RESTRICT distance_cache) {
|
||||
FN_A(PrepareDistanceCache)(&self->ha, distance_cache);
|
||||
FN_B(PrepareDistanceCache)(&self->hb, distance_cache);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashComposite* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, 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 gap, const size_t max_distance,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HashComposite* self = FN(Self)(handle);
|
||||
FN_A(FindLongestMatch)(self->ha, dictionary, data, ring_buffer_mask,
|
||||
distance_cache, cur_ix, max_length, max_backward, gap,
|
||||
FN_A(FindLongestMatch)(&self->ha, dictionary, data, ring_buffer_mask,
|
||||
distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
|
||||
max_distance, out);
|
||||
FN_B(FindLongestMatch)(self->hb, dictionary, data, ring_buffer_mask,
|
||||
distance_cache, cur_ix, max_length, max_backward, gap,
|
||||
FN_B(FindLongestMatch)(&self->hb, dictionary, data, ring_buffer_mask,
|
||||
distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
|
||||
max_distance, out);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(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.*/
|
||||
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_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
|
@ -45,28 +45,56 @@ typedef struct FN(Bank) {
|
|||
} FN(Bank);
|
||||
|
||||
typedef struct HashForgetfulChain {
|
||||
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];
|
||||
uint16_t free_slot_idx[NUM_BANKS];
|
||||
uint16_t free_slot_idx[NUM_BANKS]; /* Up to 1KiB. Move to dynamic? */
|
||||
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;
|
||||
|
||||
static BROTLI_INLINE HashForgetfulChain* FN(Self)(HasherHandle handle) {
|
||||
return (HashForgetfulChain*)&(GetHasherCommon(handle)[1]);
|
||||
static uint32_t* FN(Addr)(void* extra) {
|
||||
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)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
FN(Self)(handle)->max_hops =
|
||||
(params->quality > 6 ? 7u : 8u) << (params->quality - 4);
|
||||
HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
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,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashForgetfulChain* self = FN(Self)(handle);
|
||||
static void FN(Prepare)(
|
||||
HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
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). */
|
||||
size_t partial_prepare_threshold = BUCKET_SIZE >> 6;
|
||||
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) {
|
||||
size_t bucket = FN(HashBytes)(&data[i]);
|
||||
/* See InitEmpty comment. */
|
||||
self->addr[bucket] = 0xCCCCCCCC;
|
||||
self->head[bucket] = 0xCCCC;
|
||||
addr[bucket] = 0xCCCCCCCC;
|
||||
head[bucket] = 0xCCCC;
|
||||
}
|
||||
} else {
|
||||
/* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
|
||||
processed by hasher never reaches 3GB + 64M; this makes all new chains
|
||||
to be terminated after the first node. */
|
||||
memset(self->addr, 0xCC, sizeof(self->addr));
|
||||
memset(self->head, 0, sizeof(self->head));
|
||||
memset(addr, 0xCC, sizeof(uint32_t) * BUCKET_SIZE);
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -94,51 +122,58 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
|||
BROTLI_UNUSED(params);
|
||||
BROTLI_UNUSED(one_shot);
|
||||
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
|
||||
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) {
|
||||
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 bank = key & (NUM_BANKS - 1);
|
||||
const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1);
|
||||
size_t delta = ix - self->addr[key];
|
||||
self->tiny_hash[(uint16_t)ix] = (uint8_t)key;
|
||||
size_t delta = ix - addr[key];
|
||||
tiny_hash[(uint16_t)ix] = (uint8_t)key;
|
||||
if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF;
|
||||
self->banks[bank].slots[idx].delta = (uint16_t)delta;
|
||||
self->banks[bank].slots[idx].next = self->head[key];
|
||||
self->addr[key] = (uint32_t)ix;
|
||||
self->head[key] = (uint16_t)idx;
|
||||
banks[bank].slots[idx].delta = (uint16_t)delta;
|
||||
banks[bank].slots[idx].next = head[key];
|
||||
addr[key] = (uint32_t)ix;
|
||||
head[key] = (uint16_t)idx;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
static BROTLI_INLINE void FN(StoreRange)(
|
||||
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t 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 ring_buffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 3);
|
||||
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 2);
|
||||
FN(Store)(handle, ringbuffer, ring_buffer_mask, position - 1);
|
||||
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(handle);
|
||||
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(self);
|
||||
PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK);
|
||||
}
|
||||
|
||||
|
@ -153,14 +188,18 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
|||
Does not look for matches further away than max_backward.
|
||||
Writes the best match into |out|.
|
||||
|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)(
|
||||
HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, 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 gap, const size_t max_distance,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
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_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;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
|
@ -176,7 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|||
const size_t backward = (size_t)distance_cache[i];
|
||||
size_t prev_ix = (cur_ix - backward);
|
||||
/* 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) {
|
||||
continue;
|
||||
}
|
||||
|
@ -204,16 +243,16 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|||
const size_t bank = key & (NUM_BANKS - 1);
|
||||
size_t backward = 0;
|
||||
size_t hops = self->max_hops;
|
||||
size_t delta = cur_ix - self->addr[key];
|
||||
size_t slot = self->head[key];
|
||||
size_t delta = cur_ix - addr[key];
|
||||
size_t slot = head[key];
|
||||
while (hops--) {
|
||||
size_t prev_ix;
|
||||
size_t last = slot;
|
||||
backward += delta;
|
||||
if (backward > max_backward || (CAPPED_CHAINS && !delta)) break;
|
||||
prev_ix = (cur_ix - backward) & ring_buffer_mask;
|
||||
slot = self->banks[bank].slots[last].next;
|
||||
delta = self->banks[bank].slots[last].delta;
|
||||
slot = banks[bank].slots[last].next;
|
||||
delta = banks[bank].slots[last].delta;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
|
@ -238,11 +277,11 @@ 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) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
handle, &data[cur_ix_masked], max_length, max_backward + gap,
|
||||
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
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; }
|
||||
|
||||
/* 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 int shift) {
|
||||
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). */
|
||||
uint32_t block_mask_;
|
||||
|
||||
int block_bits_;
|
||||
int num_last_distances_to_check_;
|
||||
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common_;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
/* 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. */
|
||||
/* uint32_t* buckets[bucket_size * block_size]; */
|
||||
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||
} 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)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
HasherCommon* common = GetHasherCommon(handle);
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common_ = common;
|
||||
|
||||
BROTLI_UNUSED(params);
|
||||
self->hash_shift_ = 64 - common->params.bucket_bits;
|
||||
self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
|
||||
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_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,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
static void FN(Prepare)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
||||
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;
|
||||
BROTLI_UNUSED(one_shot);
|
||||
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].
|
||||
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) {
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
|
||||
self->hash_shift_);
|
||||
const size_t minor_ix = num[key] & self->block_mask_;
|
||||
const size_t offset =
|
||||
minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
|
||||
FN(Buckets)(self)[offset] = (uint32_t)ix;
|
||||
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||
++num[key];
|
||||
buckets[offset] = (uint32_t)ix;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t 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 ringbuffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache,
|
||||
GetHasherCommon(handle)->params.num_last_distances_to_check);
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
||||
}
|
||||
|
||||
/* Find a longest backward match of &data[cur_ix] up to the length of
|
||||
|
@ -157,17 +159,16 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
|||
Does not look for matches further away than max_backward.
|
||||
Writes the best match into |out|.
|
||||
|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)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, 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 gap, const size_t max_distance,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HasherCommon* common = GetHasherCommon(handle);
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
uint32_t* buckets = FN(Buckets)(self);
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
|
@ -177,7 +178,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
/* 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];
|
||||
size_t prev_ix = (size_t)(cur_ix - backward);
|
||||
if (prev_ix >= cur_ix) {
|
||||
|
@ -218,8 +219,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|||
{
|
||||
const uint32_t key = FN(HashBytes)(
|
||||
&data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
|
||||
uint32_t* BROTLI_RESTRICT bucket =
|
||||
&buckets[key << common->params.block_bits];
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
const size_t down =
|
||||
(num[key] > self->block_size_) ?
|
||||
(num[key] - self->block_size_) : 0u;
|
||||
|
@ -259,7 +259,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|||
}
|
||||
if (min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
handle, &data[cur_ix_masked], max_length, max_backward + gap,
|
||||
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(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. */
|
||||
static uint32_t FN(HashBytes)(const uint8_t* data, const int shift) {
|
||||
static uint32_t FN(HashBytes)(
|
||||
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,
|
||||
so we take our results from there. */
|
||||
|
@ -38,42 +39,46 @@ typedef struct HashLongestMatch {
|
|||
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
||||
uint32_t block_mask_;
|
||||
|
||||
int block_bits_;
|
||||
int num_last_distances_to_check_;
|
||||
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common_;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
/* 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. */
|
||||
/* uint32_t* buckets[bucket_size * block_size]; */
|
||||
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||
} 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 BROTLI_INLINE uint16_t* FN(Num)(void* extra) {
|
||||
return (uint16_t*)extra;
|
||||
}
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
HasherCommon* common = GetHasherCommon(handle);
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common_ = common;
|
||||
|
||||
BROTLI_UNUSED(params);
|
||||
self->hash_shift_ = 32 - 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_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,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
static void FN(Prepare)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
||||
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;
|
||||
BROTLI_UNUSED(one_shot);
|
||||
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].
|
||||
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) {
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
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 offset =
|
||||
minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
|
||||
FN(Buckets)(self)[offset] = (uint32_t)ix;
|
||||
++num[key];
|
||||
const size_t minor_ix = self->num_[key] & self->block_mask_;
|
||||
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||
self->buckets_[offset] = (uint32_t)ix;
|
||||
++self->num_[key];
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t 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 ringbuffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache,
|
||||
GetHasherCommon(handle)->params.num_last_distances_to_check);
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
||||
}
|
||||
|
||||
/* Find a longest backward match of &data[cur_ix] up to the length of
|
||||
|
@ -150,17 +155,16 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
|||
Does not look for matches further away than max_backward.
|
||||
Writes the best match into |out|.
|
||||
|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)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, 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 gap, const size_t max_distance,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HasherCommon* common = GetHasherCommon(handle);
|
||||
HashLongestMatch* self = FN(Self)(handle);
|
||||
uint16_t* num = FN(Num)(self);
|
||||
uint32_t* buckets = FN(Buckets)(self);
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
|
@ -170,7 +174,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
/* 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];
|
||||
size_t prev_ix = (size_t)(cur_ix - backward);
|
||||
if (prev_ix >= cur_ix) {
|
||||
|
@ -211,8 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|||
{
|
||||
const uint32_t key =
|
||||
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
||||
uint32_t* BROTLI_RESTRICT bucket =
|
||||
&buckets[key << common->params.block_bits];
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
const size_t down =
|
||||
(num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
|
||||
for (i = num[key]; i > down;) {
|
||||
|
@ -251,7 +254,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|||
}
|
||||
if (min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
handle, &data[cur_ix_masked], max_length, max_backward + gap,
|
||||
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,15 +5,16 @@
|
|||
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
|
||||
*/
|
||||
|
||||
#define HashLongestMatchQuickly HASHER()
|
||||
|
||||
#define BUCKET_SIZE (1 << BUCKET_BITS)
|
||||
|
||||
#define HASH_MAP_SIZE (4 << BUCKET_BITS)
|
||||
#define BUCKET_MASK (BUCKET_SIZE - 1)
|
||||
#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(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
|
||||
help create backward references to previous data.
|
||||
|
||||
This is a hash map of fixed size (BUCKET_SIZE). Starting from the
|
||||
given index, BUCKET_SWEEP buckets are used to store values of a key. */
|
||||
This is a hash map of fixed size (BUCKET_SIZE). */
|
||||
typedef struct HashLongestMatchQuickly {
|
||||
uint32_t buckets_[BUCKET_SIZE + BUCKET_SWEEP];
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
|
||||
} HashLongestMatchQuickly;
|
||||
|
||||
static BROTLI_INLINE HashLongestMatchQuickly* FN(Self)(HasherHandle handle) {
|
||||
return (HashLongestMatchQuickly*)&(GetHasherCommon(handle)[1]);
|
||||
}
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
BROTLI_UNUSED(handle);
|
||||
HasherCommon* common, HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common = common;
|
||||
|
||||
BROTLI_UNUSED(params);
|
||||
self->buckets_ = (uint32_t*)common->extra;
|
||||
}
|
||||
|
||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashLongestMatchQuickly* self = FN(Self)(handle);
|
||||
static void FN(Prepare)(
|
||||
HashLongestMatchQuickly* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
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). */
|
||||
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) {
|
||||
size_t i;
|
||||
for (i = 0; i < input_size; ++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 {
|
||||
/* It is not strictly necessary to fill this buffer here, but
|
||||
not filling will make the results of the compression stochastic
|
||||
(but correct). This is because random data would cause the
|
||||
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(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
return sizeof(HashLongestMatchQuickly);
|
||||
return sizeof(uint32_t) * BUCKET_SIZE;
|
||||
}
|
||||
|
||||
/* Look at 5 bytes at &data[ix & mask].
|
||||
Compute a hash from these, and store the value somewhere within
|
||||
[ix .. ix+3]. */
|
||||
static BROTLI_INLINE void FN(Store)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix) {
|
||||
static BROTLI_INLINE void FN(Store)(
|
||||
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]);
|
||||
/* Wiggle the value with the bucket sweep range. */
|
||||
const uint32_t off = (ix >> 3) % BUCKET_SWEEP;
|
||||
FN(Self)(handle)->buckets_[key + off] = (uint32_t)ix;
|
||||
if (BUCKET_SWEEP == 1) {
|
||||
self->buckets_[key] = (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,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
static BROTLI_INLINE void FN(StoreRange)(
|
||||
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t 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, 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) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(handle, ringbuffer, ringbuffer_mask, position - 1);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(handle);
|
||||
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(self);
|
||||
BROTLI_UNUSED(distance_cache);
|
||||
}
|
||||
|
||||
|
@ -125,17 +145,19 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
|||
Writes the best match into |out|.
|
||||
|out|->score is updated only if a better match is found. */
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HasherHandle handle, const BrotliEncoderDictionary* dictionary,
|
||||
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data,
|
||||
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 gap, const size_t max_distance,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HashLongestMatchQuickly* self = FN(Self)(handle);
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t best_len_in = out->len;
|
||||
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];
|
||||
size_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
||||
size_t key_out;
|
||||
score_t min_score = out->score;
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = best_len_in;
|
||||
|
@ -145,21 +167,21 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
|||
if (prev_ix < cur_ix) {
|
||||
prev_ix &= (uint32_t)ring_buffer_mask;
|
||||
if (compare_char == data[prev_ix + best_len]) {
|
||||
size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
||||
&data[cur_ix_masked],
|
||||
max_length);
|
||||
const size_t len = FindMatchLengthWithLimit(
|
||||
&data[prev_ix], &data[cur_ix_masked], max_length);
|
||||
if (len >= 4) {
|
||||
const score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = len;
|
||||
out->distance = cached_backward;
|
||||
out->score = best_score;
|
||||
compare_char = data[cur_ix_masked + best_len];
|
||||
out->score = score;
|
||||
if (BUCKET_SWEEP == 1) {
|
||||
self->buckets_[key] = (uint32_t)cur_ix;
|
||||
buckets[key] = (uint32_t)cur_ix;
|
||||
return;
|
||||
} else {
|
||||
best_len = len;
|
||||
best_score = score;
|
||||
compare_char = data[cur_ix_masked + len];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,8 +191,8 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
|||
size_t backward;
|
||||
size_t len;
|
||||
/* Only one to look for, don't bother to prepare for a loop. */
|
||||
prev_ix = self->buckets_[key];
|
||||
self->buckets_[key] = (uint32_t)cur_ix;
|
||||
prev_ix = buckets[key];
|
||||
buckets[key] = (uint32_t)cur_ix;
|
||||
backward = cur_ix - prev_ix;
|
||||
prev_ix &= (uint32_t)ring_buffer_mask;
|
||||
if (compare_char != data[prev_ix + best_len_in]) {
|
||||
|
@ -192,12 +214,17 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t* bucket = self->buckets_ + key;
|
||||
int i;
|
||||
prev_ix = *bucket++;
|
||||
for (i = 0; i < BUCKET_SWEEP; ++i, prev_ix = *bucket++) {
|
||||
const size_t backward = cur_ix - prev_ix;
|
||||
size_t keys[BUCKET_SWEEP];
|
||||
size_t i;
|
||||
for (i = 0; i < BUCKET_SWEEP; ++i) {
|
||||
keys[i] = (key + (i << 3)) & BUCKET_MASK;
|
||||
}
|
||||
key_out = keys[(cur_ix & BUCKET_SWEEP_MASK) >> 3];
|
||||
for (i = 0; i < BUCKET_SWEEP; ++i) {
|
||||
size_t len;
|
||||
size_t backward;
|
||||
prev_ix = buckets[keys[i]];
|
||||
backward = cur_ix - prev_ix;
|
||||
prev_ix &= (uint32_t)ring_buffer_mask;
|
||||
if (compare_char != data[prev_ix + best_len]) {
|
||||
continue;
|
||||
|
@ -211,25 +238,29 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
|||
if (len >= 4) {
|
||||
const score_t score = BackwardReferenceScore(len, backward);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->len = len;
|
||||
compare_char = data[cur_ix_masked + len];
|
||||
best_score = score;
|
||||
out->score = score;
|
||||
compare_char = data[cur_ix_masked + best_len];
|
||||
out->distance = backward;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (USE_DICTIONARY && min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
handle, &data[cur_ix_masked], max_length, max_backward + gap,
|
||||
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_TRUE);
|
||||
}
|
||||
self->buckets_[key + ((cur_ix >> 3) % BUCKET_SWEEP)] = (uint32_t)cur_ix;
|
||||
if (BUCKET_SWEEP != 1) {
|
||||
buckets[key_out] = (uint32_t)cur_ix;
|
||||
}
|
||||
}
|
||||
|
||||
#undef HASH_MAP_SIZE
|
||||
#undef BUCKET_SWEEP_MASK
|
||||
#undef BUCKET_SWEEP
|
||||
#undef BUCKET_MASK
|
||||
#undef BUCKET_SIZE
|
||||
|
||||
#undef HashLongestMatchQuickly
|
||||
|
|
|
@ -51,13 +51,9 @@ typedef struct HashRolling {
|
|||
uint32_t factor_remove;
|
||||
} HashRolling;
|
||||
|
||||
static BROTLI_INLINE HashRolling* FN(Self)(HasherHandle handle) {
|
||||
return (HashRolling*)&(GetHasherCommon(handle)[1]);
|
||||
}
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
HashRolling* self = FN(Self)(handle);
|
||||
HasherCommon* common, HashRolling* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
size_t i;
|
||||
self->state = 0;
|
||||
self->next_ix = 0;
|
||||
|
@ -71,7 +67,7 @@ static void FN(Initialize)(
|
|||
self->factor_remove *= self->factor;
|
||||
}
|
||||
|
||||
self->table = (uint32_t*)((HasherHandle)self + sizeof(HashRolling));
|
||||
self->table = (uint32_t*)common->extra;
|
||||
for (i = 0; i < NUMBUCKETS; i++) {
|
||||
self->table[i] = FN(kInvalidPos);
|
||||
}
|
||||
|
@ -79,9 +75,8 @@ static void FN(Initialize)(
|
|||
BROTLI_UNUSED(params);
|
||||
}
|
||||
|
||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashRolling* self = FN(Self)(handle);
|
||||
static void FN(Prepare)(HashRolling* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
size_t i;
|
||||
/* Too small size, cannot use this hasher. */
|
||||
if (input_size < CHUNKLEN) return;
|
||||
|
@ -96,36 +91,36 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
|||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
return sizeof(HashRolling) + NUMBUCKETS * sizeof(uint32_t);
|
||||
return NUMBUCKETS * sizeof(uint32_t);
|
||||
BROTLI_UNUSED(params);
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
|
||||
static BROTLI_INLINE void FN(Store)(HashRolling* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
||||
BROTLI_UNUSED(handle);
|
||||
BROTLI_UNUSED(self);
|
||||
BROTLI_UNUSED(data);
|
||||
BROTLI_UNUSED(mask);
|
||||
BROTLI_UNUSED(ix);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
BROTLI_UNUSED(handle);
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashRolling* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
BROTLI_UNUSED(self);
|
||||
BROTLI_UNUSED(data);
|
||||
BROTLI_UNUSED(mask);
|
||||
BROTLI_UNUSED(ix_start);
|
||||
BROTLI_UNUSED(ix_end);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashRolling* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ring_buffer_mask) {
|
||||
/* In this case we must re-initialize the hasher from scratch from the
|
||||
current position. */
|
||||
HashRolling* self = FN(Self)(handle);
|
||||
size_t position_masked;
|
||||
size_t available = num_bytes;
|
||||
if ((position & (JUMP - 1)) != 0) {
|
||||
|
@ -139,28 +134,29 @@ static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
|||
available = ring_buffer_mask - position_masked;
|
||||
}
|
||||
|
||||
FN(Prepare)(handle, BROTLI_FALSE, available,
|
||||
FN(Prepare)(self, BROTLI_FALSE, available,
|
||||
ringbuffer + (position & ring_buffer_mask));
|
||||
self->next_ix = position;
|
||||
BROTLI_UNUSED(num_bytes);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(handle);
|
||||
HashRolling* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
BROTLI_UNUSED(self);
|
||||
BROTLI_UNUSED(distance_cache);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashRolling* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, 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 gap, const size_t max_distance,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
HashRolling* self = FN(Self)(handle);
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
size_t pos = self->next_ix;
|
||||
size_t pos;
|
||||
|
||||
if ((cur_ix & (JUMP - 1)) != 0) return;
|
||||
|
||||
|
@ -209,7 +205,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|||
backup-hasher, the main hasher already searches in it. */
|
||||
BROTLI_UNUSED(dictionary);
|
||||
BROTLI_UNUSED(distance_cache);
|
||||
BROTLI_UNUSED(gap);
|
||||
BROTLI_UNUSED(dictionary_distance);
|
||||
BROTLI_UNUSED(max_distance);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
|
|||
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_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
|
@ -38,7 +38,7 @@ typedef struct HashToBinaryTree {
|
|||
/* 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
|
||||
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
|
||||
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
|
||||
the left and right children of a sequence starting at pos are
|
||||
forest_[2 * pos] and forest_[2 * pos + 1]. */
|
||||
/* uint32_t forest[2 * num_nodes] */
|
||||
uint32_t* forest_; /* uint32_t[2 * num_nodes] */
|
||||
} 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)(
|
||||
HasherHandle handle, const BrotliEncoderParams* params) {
|
||||
HashToBinaryTree* self = FN(Self)(handle);
|
||||
HasherCommon* common, HashToBinaryTree* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->buckets_ = (uint32_t*)common->extra;
|
||||
self->forest_ = &self->buckets_[BUCKET_SIZE];
|
||||
|
||||
self->window_mask_ = (1u << params->lgwin) - 1u;
|
||||
self->invalid_pos_ = (uint32_t)(0 - self->window_mask_);
|
||||
}
|
||||
|
||||
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* data) {
|
||||
HashToBinaryTree* self = FN(Self)(handle);
|
||||
static void FN(Prepare)
|
||||
(HashToBinaryTree* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint32_t invalid_pos = self->invalid_pos_;
|
||||
uint32_t i;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
BROTLI_UNUSED(data);
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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. */
|
||||
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 max_backward, size_t* const BROTLI_RESTRICT best_len,
|
||||
BackwardMatch* BROTLI_RESTRICT matches) {
|
||||
|
@ -123,8 +121,9 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
|
|||
const BROTLI_BOOL should_reroot_tree =
|
||||
TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH);
|
||||
const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
||||
uint32_t* forest = FN(Forest)(self);
|
||||
size_t prev_ix = self->buckets_[key];
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
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
|
||||
root, updated as we traverse and re-root the tree of the hash bucket. */
|
||||
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 depth_remaining;
|
||||
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) {
|
||||
const size_t backward = cur_ix - prev_ix;
|
||||
|
@ -199,11 +198,13 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
|
|||
matches in matches[0] to matches[*num_matches - 1]. The matches will be
|
||||
sorted by strictly increasing length and (non-strictly) increasing
|
||||
distance. */
|
||||
static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
|
||||
const BrotliEncoderDictionary* dictionary, const uint8_t* data,
|
||||
static BROTLI_INLINE size_t FN(FindAllMatches)(
|
||||
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 max_length, const size_t max_backward,
|
||||
const size_t gap, const BrotliEncoderParams* params,
|
||||
const size_t dictionary_distance, const BrotliEncoderParams* params,
|
||||
BackwardMatch* matches) {
|
||||
BackwardMatch* const orig_matches = matches;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
|
@ -236,7 +237,7 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
|
|||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) {
|
||||
|
@ -252,7 +253,7 @@ static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
|
|||
for (l = minlen; l <= maxlen; ++l) {
|
||||
uint32_t dict_id = dict_matches[l];
|
||||
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 <= params->dist.max_distance) {
|
||||
InitDictionaryBackwardMatch(matches++, distance, l, dict_id & 31);
|
||||
}
|
||||
|
@ -266,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
|
||||
current sequence, without returning any matches.
|
||||
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) {
|
||||
HashToBinaryTree* self = FN(Self)(handle);
|
||||
/* 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;
|
||||
FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH,
|
||||
max_backward, NULL, NULL);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
||||
const uint8_t* data, const size_t mask, const size_t ix_start,
|
||||
const size_t ix_end) {
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashToBinaryTree* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t i = ix_start;
|
||||
size_t j = ix_start;
|
||||
if (ix_start + 63 <= ix_end) {
|
||||
|
@ -285,18 +286,18 @@ static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
|||
}
|
||||
if (ix_start + 512 <= i) {
|
||||
for (; j < i; j += 8) {
|
||||
FN(Store)(handle, data, mask, j);
|
||||
FN(Store)(self, data, mask, j);
|
||||
}
|
||||
}
|
||||
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 ringbuffer_mask) {
|
||||
HashToBinaryTree* self = FN(Self)(handle);
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 &&
|
||||
position >= MAX_TREE_COMP_LENGTH) {
|
||||
/* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.
|
||||
|
|
|
@ -56,6 +56,18 @@ BROTLI_INTERNAL void BrotliFree(MemoryManager* m, void* p);
|
|||
#define BROTLI_IS_OOM(M) (!!(M)->is_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);
|
||||
|
||||
/*
|
||||
|
@ -66,18 +78,18 @@ 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) && C != 0) \
|
||||
memcpy(new_array, A, C * sizeof(T)); \
|
||||
BROTLI_FREE((M), A); \
|
||||
A = new_array; \
|
||||
C = _new_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; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -28,34 +28,30 @@ extern "C" {
|
|||
void BrotliInitDistanceParams(BrotliEncoderParams* params,
|
||||
uint32_t npostfix, uint32_t ndirect) {
|
||||
BrotliDistanceParams* dist_params = ¶ms->dist;
|
||||
uint32_t alphabet_size, max_distance;
|
||||
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 = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||
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) {
|
||||
static const uint32_t bound[BROTLI_MAX_NPOSTFIX + 1] = {0, 4, 12, 28};
|
||||
uint32_t postfix = 1U << npostfix;
|
||||
alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||
BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
|
||||
BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
|
||||
alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||
npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
|
||||
/* The maximum distance is set so that no distance symbol used can encode
|
||||
a distance larger than BROTLI_MAX_ALLOWED_DISTANCE with all
|
||||
its extra bits set. */
|
||||
if (ndirect < bound[npostfix]) {
|
||||
max_distance = BROTLI_MAX_ALLOWED_DISTANCE - (bound[npostfix] - ndirect);
|
||||
} else if (ndirect >= bound[npostfix] + postfix) {
|
||||
max_distance = (3U << 29) - 4 + (ndirect - bound[npostfix]);
|
||||
} else {
|
||||
max_distance = BROTLI_MAX_ALLOWED_DISTANCE;
|
||||
}
|
||||
alphabet_size_limit = limit.max_alphabet_size;
|
||||
max_distance = limit.max_distance;
|
||||
}
|
||||
|
||||
dist_params->alphabet_size = alphabet_size;
|
||||
dist_params->alphabet_size_max = alphabet_size_max;
|
||||
dist_params->alphabet_size_limit = alphabet_size_limit;
|
||||
dist_params->max_distance = max_distance;
|
||||
}
|
||||
|
||||
|
@ -200,7 +196,7 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
|||
literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
|
||||
literal_context_modes =
|
||||
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) {
|
||||
literal_context_modes[i] = literal_context_mode;
|
||||
}
|
||||
|
@ -210,21 +206,21 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
|||
mb->literal_split.num_types * literal_context_multiplier;
|
||||
literal_histograms =
|
||||
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);
|
||||
|
||||
distance_histograms_size =
|
||||
mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
|
||||
distance_histograms =
|
||||
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);
|
||||
|
||||
BROTLI_DCHECK(mb->command_histograms == 0);
|
||||
mb->command_histograms_size = mb->command_split.num_types;
|
||||
mb->command_histograms =
|
||||
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);
|
||||
|
||||
BrotliBuildHistogramsWithContext(cmds, num_commands,
|
||||
|
@ -238,13 +234,13 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
|||
mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
|
||||
mb->literal_context_map =
|
||||
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;
|
||||
|
||||
BROTLI_DCHECK(mb->literal_histograms == 0);
|
||||
mb->literal_histograms_size = mb->literal_context_map_size;
|
||||
mb->literal_histograms =
|
||||
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,
|
||||
kMaxNumberOfHistograms, mb->literal_histograms,
|
||||
|
@ -269,13 +265,13 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
|||
mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
|
||||
mb->distance_context_map =
|
||||
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;
|
||||
|
||||
BROTLI_DCHECK(mb->distance_histograms == 0);
|
||||
mb->distance_histograms_size = mb->distance_context_map_size;
|
||||
mb->distance_histograms =
|
||||
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,
|
||||
mb->distance_context_map_size,
|
||||
|
@ -373,7 +369,7 @@ static void InitContextBlockSplitter(
|
|||
*histograms_size = max_num_types * num_contexts;
|
||||
*histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
|
||||
self->histograms_ = *histograms;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
|
||||
/* Clear only current histogram. */
|
||||
ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
|
||||
self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
|
||||
|
@ -423,7 +419,7 @@ static void ContextBlockSplitterFinishBlock(
|
|||
double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
|
||||
double diff[2] = { 0.0 };
|
||||
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) {
|
||||
size_t curr_histo_ix = self->curr_histogram_ix_ + i;
|
||||
size_t j;
|
||||
|
@ -527,7 +523,7 @@ static void MapStaticContexts(MemoryManager* m,
|
|||
mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
|
||||
mb->literal_context_map =
|
||||
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) {
|
||||
uint32_t offset = (uint32_t)(i * num_contexts);
|
||||
|
|
|
@ -71,7 +71,7 @@ static void FN(InitBlockSplitter)(
|
|||
*histograms_size = max_num_types;
|
||||
*histograms = BROTLI_ALLOC(m, HistogramType, *histograms_size);
|
||||
self->histograms_ = *histograms;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
|
||||
/* Clear only current histogram. */
|
||||
FN(HistogramClear)(&self->histograms_[0]);
|
||||
self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
|
||||
|
|
|
@ -23,7 +23,8 @@ typedef struct BrotliHasherParams {
|
|||
typedef struct BrotliDistanceParams {
|
||||
uint32_t distance_postfix_bits;
|
||||
uint32_t num_direct_distance_codes;
|
||||
uint32_t alphabet_size;
|
||||
uint32_t alphabet_size_max;
|
||||
uint32_t alphabet_size_limit;
|
||||
size_t max_distance;
|
||||
} BrotliDistanceParams;
|
||||
|
||||
|
@ -33,6 +34,7 @@ typedef struct BrotliEncoderParams {
|
|||
int quality;
|
||||
int lgwin;
|
||||
int lgblock;
|
||||
size_t stream_offset;
|
||||
size_t size_hint;
|
||||
BROTLI_BOOL disable_literal_context_modeling;
|
||||
BROTLI_BOOL large_window;
|
||||
|
|
|
@ -75,7 +75,7 @@ static BROTLI_INLINE void RingBufferInitBuffer(
|
|||
uint8_t* new_data = BROTLI_ALLOC(
|
||||
m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere);
|
||||
size_t i;
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_data)) return;
|
||||
if (rb->data_) {
|
||||
memcpy(new_data, rb->data_,
|
||||
2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere);
|
||||
|
@ -125,6 +125,9 @@ static BROTLI_INLINE void RingBufferWrite(
|
|||
later when we copy the last two bytes to the first two positions. */
|
||||
rb->buffer_[rb->size_ - 2] = 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_;
|
||||
|
|
|
@ -77,7 +77,7 @@ BROTLI_BOOL BrotliIsMostlyUTF8(
|
|||
i += 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)
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*#define BIT_WRITER_DEBUG */
|
||||
|
||||
/* This function writes bits into bytes in increasing addresses, and within
|
||||
a byte least-significant-bit first.
|
||||
|
||||
|
@ -28,7 +26,7 @@ extern "C" {
|
|||
|
||||
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.
|
||||
|
||||
For n bits, we take the last 5 bits, OR that with high bits in BYTE-0,
|
||||
|
@ -37,37 +35,41 @@ static BROTLI_INLINE void BrotliWriteBits(size_t n_bits,
|
|||
uint64_t bits,
|
||||
size_t* BROTLI_RESTRICT pos,
|
||||
uint8_t* BROTLI_RESTRICT array) {
|
||||
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,
|
||||
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
|
||||
bits are in *p and we write 57 bits, then the next write will
|
||||
access a byte that was never initialized). */
|
||||
uint8_t* p = &array[*pos >> 3];
|
||||
uint64_t v = (uint64_t)(*p); /* Zero-extend 8 to 64 bits. */
|
||||
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);
|
||||
v |= bits << (*pos & 7);
|
||||
BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */
|
||||
*pos += n_bits;
|
||||
{
|
||||
uint8_t* p = &array[*pos >> 3];
|
||||
uint64_t v = (uint64_t)(*p); /* Zero-extend 8 to 64 bits. */
|
||||
v |= bits << (*pos & 7);
|
||||
BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */
|
||||
*pos += n_bits;
|
||||
}
|
||||
#else
|
||||
/* implicit & 0xFF is assumed for uint8_t arithmetics */
|
||||
uint8_t* array_pos = &array[*pos >> 3];
|
||||
const size_t bits_reserved_in_first_byte = (*pos & 7);
|
||||
size_t bits_left_to_write;
|
||||
bits <<= bits_reserved_in_first_byte;
|
||||
*array_pos++ |= (uint8_t)bits;
|
||||
for (bits_left_to_write = n_bits + bits_reserved_in_first_byte;
|
||||
bits_left_to_write >= 9;
|
||||
bits_left_to_write -= 8) {
|
||||
bits >>= 8;
|
||||
*array_pos++ = (uint8_t)bits;
|
||||
{
|
||||
uint8_t* array_pos = &array[*pos >> 3];
|
||||
const size_t bits_reserved_in_first_byte = (*pos & 7);
|
||||
size_t bits_left_to_write;
|
||||
bits <<= bits_reserved_in_first_byte;
|
||||
*array_pos++ |= (uint8_t)bits;
|
||||
for (bits_left_to_write = n_bits + bits_reserved_in_first_byte;
|
||||
bits_left_to_write >= 9;
|
||||
bits_left_to_write -= 8) {
|
||||
bits >>= 8;
|
||||
*array_pos++ = (uint8_t)bits;
|
||||
}
|
||||
*array_pos = 0;
|
||||
*pos += n_bits;
|
||||
}
|
||||
*array_pos = 0;
|
||||
*pos += n_bits;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -201,7 +201,23 @@ typedef enum BrotliEncoderParameter {
|
|||
*
|
||||
* Range is from 0 to (15 << NPOSTFIX) in steps of (1 << NPOSTFIX).
|
||||
*/
|
||||
BROTLI_PARAM_NDIRECT = 8
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -274,6 +290,11 @@ BROTLI_ENC_API size_t BrotliEncoderMaxCompressedSize(size_t input_size);
|
|||
* @note If ::BrotliEncoderMaxCompressedSize(@p input_size) returns non-zero
|
||||
* 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 lgwin lgwin parameter value, e.g. ::BROTLI_DEFAULT_WINDOW
|
||||
* @param mode mode parameter value, e.g. ::BROTLI_DEFAULT_MODE
|
||||
|
|
|
@ -218,6 +218,20 @@
|
|||
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
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define BROTLI_PUBLIC
|
||||
#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \
|
||||
|
|
|
@ -14,7 +14,10 @@ EXPORTS.brotli += [
|
|||
]
|
||||
|
||||
SOURCES += [
|
||||
'common/constants.c',
|
||||
'common/context.c',
|
||||
'common/dictionary.c',
|
||||
'common/platform.c',
|
||||
'common/transform.c',
|
||||
'dec/bit_reader.c',
|
||||
'dec/decode.c',
|
||||
|
@ -44,12 +47,14 @@ HOST_SOURCES += [
|
|||
'enc/block_splitter.c',
|
||||
'enc/brotli_bit_stream.c',
|
||||
'enc/cluster.c',
|
||||
'enc/command.c',
|
||||
'enc/compress_fragment.c',
|
||||
'enc/compress_fragment_two_pass.c',
|
||||
'enc/dictionary_hash.c',
|
||||
'enc/encode.c',
|
||||
'enc/encoder_dict.c',
|
||||
'enc/entropy_encode.c',
|
||||
'enc/fast_log.c',
|
||||
'enc/histogram.c',
|
||||
'enc/literal_cost.c',
|
||||
'enc/memory.c',
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
|
||||
/* 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 <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
@ -86,10 +91,10 @@ typedef struct {
|
|||
/* Parameters */
|
||||
int quality;
|
||||
int lgwin;
|
||||
int verbosity;
|
||||
BROTLI_BOOL force_overwrite;
|
||||
BROTLI_BOOL junk_source;
|
||||
BROTLI_BOOL copy_stat;
|
||||
BROTLI_BOOL verbose;
|
||||
BROTLI_BOOL write_to_stdout;
|
||||
BROTLI_BOOL test_integrity;
|
||||
BROTLI_BOOL decompress;
|
||||
|
@ -121,6 +126,12 @@ typedef struct {
|
|||
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;
|
||||
|
||||
/* Parse up to 5 decimal digits. */
|
||||
|
@ -257,7 +268,7 @@ static Command ParseParams(Context* params) {
|
|||
return COMMAND_HELP;
|
||||
} else if (c == 'j' || c == 'k') {
|
||||
if (keep_set) {
|
||||
fprintf(stderr, "argument --rm / -j or --keep / -n already set\n");
|
||||
fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
|
||||
return COMMAND_INVALID;
|
||||
}
|
||||
keep_set = BROTLI_TRUE;
|
||||
|
@ -279,11 +290,11 @@ static Command ParseParams(Context* params) {
|
|||
command = COMMAND_TEST_INTEGRITY;
|
||||
continue;
|
||||
} else if (c == 'v') {
|
||||
if (params->verbose) {
|
||||
if (params->verbosity > 0) {
|
||||
fprintf(stderr, "argument --verbose / -v already set\n");
|
||||
return COMMAND_INVALID;
|
||||
}
|
||||
params->verbose = BROTLI_TRUE;
|
||||
params->verbosity = 1;
|
||||
continue;
|
||||
} else if (c == 'V') {
|
||||
/* Don't parse further. */
|
||||
|
@ -382,7 +393,7 @@ static Command ParseParams(Context* params) {
|
|||
return COMMAND_HELP;
|
||||
} else if (strcmp("keep", arg) == 0) {
|
||||
if (keep_set) {
|
||||
fprintf(stderr, "argument --rm / -j or --keep / -n already set\n");
|
||||
fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
|
||||
return COMMAND_INVALID;
|
||||
}
|
||||
keep_set = BROTLI_TRUE;
|
||||
|
@ -395,7 +406,7 @@ static Command ParseParams(Context* params) {
|
|||
params->copy_stat = BROTLI_FALSE;
|
||||
} else if (strcmp("rm", arg) == 0) {
|
||||
if (keep_set) {
|
||||
fprintf(stderr, "argument --rm / -j or --keep / -n already set\n");
|
||||
fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
|
||||
return COMMAND_INVALID;
|
||||
}
|
||||
keep_set = BROTLI_TRUE;
|
||||
|
@ -415,11 +426,11 @@ static Command ParseParams(Context* params) {
|
|||
command_set = BROTLI_TRUE;
|
||||
command = COMMAND_TEST_INTEGRITY;
|
||||
} else if (strcmp("verbose", arg) == 0) {
|
||||
if (params->verbose) {
|
||||
if (params->verbosity > 0) {
|
||||
fprintf(stderr, "argument --verbose / -v already set\n");
|
||||
return COMMAND_INVALID;
|
||||
}
|
||||
params->verbose = BROTLI_TRUE;
|
||||
params->verbosity = 1;
|
||||
} else if (strcmp("version", arg) == 0) {
|
||||
/* Don't parse further. */
|
||||
return COMMAND_VERSION;
|
||||
|
@ -550,11 +561,17 @@ static void PrintHelp(const char* name, BROTLI_BOOL error) {
|
|||
" -t, --test test compressed file integrity\n"
|
||||
" -v, --verbose verbose mode\n");
|
||||
fprintf(media,
|
||||
" -w NUM, --lgwin=NUM set LZ77 window size (0, %d-%d)\n",
|
||||
" -w NUM, --lgwin=NUM set LZ77 window size (0, %d-%d)\n"
|
||||
" window size = 2**NUM - 16\n"
|
||||
" 0 lets compressor choose the optimal value\n",
|
||||
BROTLI_MIN_WINDOW_BITS, BROTLI_MAX_WINDOW_BITS);
|
||||
fprintf(media,
|
||||
" window size = 2**NUM - 16\n"
|
||||
" 0 lets compressor choose the optimal value\n");
|
||||
" --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",
|
||||
DEFAULT_SUFFIX);
|
||||
|
@ -787,8 +804,12 @@ static void InitializeBuffers(Context* context) {
|
|||
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;
|
||||
}
|
||||
|
@ -796,6 +817,7 @@ static BROTLI_BOOL HasMoreInput(Context* context) {
|
|||
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",
|
||||
|
@ -808,6 +830,7 @@ static BROTLI_BOOL ProvideInput(Context* context) {
|
|||
/* 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;
|
||||
|
||||
|
@ -833,6 +856,25 @@ static BROTLI_BOOL FlushOutput(Context* context) {
|
|||
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) {
|
||||
BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
|
||||
InitializeBuffers(context);
|
||||
|
@ -848,11 +890,18 @@ static BROTLI_BOOL DecompressFile(Context* context, BrotliDecoderState* s) {
|
|||
if (!ProvideOutput(context)) return BROTLI_FALSE;
|
||||
} else if (result == BROTLI_DECODER_RESULT_SUCCESS) {
|
||||
if (!FlushOutput(context)) return BROTLI_FALSE;
|
||||
if (context->available_in != 0 || HasMoreInput(context)) {
|
||||
int has_more_input =
|
||||
(context->available_in != 0) || (fgetc(context->fin) != EOF);
|
||||
if (has_more_input) {
|
||||
fprintf(stderr, "corrupt input [%s]\n",
|
||||
PrintablePath(context->current_input_path));
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (context->verbosity > 0) {
|
||||
fprintf(stderr, "Decompressed ");
|
||||
PrintFileProcessingProgress(context);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
return BROTLI_TRUE;
|
||||
} else {
|
||||
fprintf(stderr, "corrupt input [%s]\n",
|
||||
|
@ -915,7 +964,13 @@ static BROTLI_BOOL CompressFile(Context* context, BrotliEncoderState* s) {
|
|||
}
|
||||
|
||||
if (BrotliEncoderIsFinished(s)) {
|
||||
return FlushOutput(context);
|
||||
if (!FlushOutput(context)) return BROTLI_FALSE;
|
||||
if (context->verbosity > 0) {
|
||||
fprintf(stderr, "Compressed ");
|
||||
PrintFileProcessingProgress(context);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -979,11 +1034,11 @@ int main(int argc, char** argv) {
|
|||
|
||||
context.quality = 11;
|
||||
context.lgwin = -1;
|
||||
context.verbosity = 0;
|
||||
context.force_overwrite = BROTLI_FALSE;
|
||||
context.junk_source = BROTLI_FALSE;
|
||||
context.copy_stat = BROTLI_TRUE;
|
||||
context.test_integrity = BROTLI_FALSE;
|
||||
context.verbose = BROTLI_FALSE;
|
||||
context.write_to_stdout = BROTLI_FALSE;
|
||||
context.decompress = BROTLI_FALSE;
|
||||
context.large_window = BROTLI_FALSE;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
MY_TEMP_DIR=`mktemp -d -t brotli_update.XXXXXX` || exit 1
|
||||
|
||||
git clone https://github.com/google/brotli ${MY_TEMP_DIR}/brotli
|
||||
git -C ${MY_TEMP_DIR}/brotli checkout v1.0.7
|
||||
git -C ${MY_TEMP_DIR}/brotli checkout v1.0.9
|
||||
|
||||
COMMIT=$(git -C ${MY_TEMP_DIR}/brotli rev-parse HEAD)
|
||||
perl -p -i -e "s/\[commit [0-9a-f]{40}\]/[commit ${COMMIT}]/" README.mozilla;
|
||||
|
|
Loading…
Reference in New Issue