1*6777b538SAndroid Build Coastguard Worker /* Copyright 2013 Google Inc. All Rights Reserved.
2*6777b538SAndroid Build Coastguard Worker
3*6777b538SAndroid Build Coastguard Worker Distributed under MIT license.
4*6777b538SAndroid Build Coastguard Worker See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5*6777b538SAndroid Build Coastguard Worker */
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker /* Implementation of Brotli compressor. */
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include <brotli/encode.h>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker #include <stdlib.h> /* free, malloc */
12*6777b538SAndroid Build Coastguard Worker #include <string.h> /* memcpy, memset */
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker #include "../common/constants.h"
15*6777b538SAndroid Build Coastguard Worker #include "../common/context.h"
16*6777b538SAndroid Build Coastguard Worker #include "../common/platform.h"
17*6777b538SAndroid Build Coastguard Worker #include "../common/version.h"
18*6777b538SAndroid Build Coastguard Worker #include "backward_references.h"
19*6777b538SAndroid Build Coastguard Worker #include "backward_references_hq.h"
20*6777b538SAndroid Build Coastguard Worker #include "bit_cost.h"
21*6777b538SAndroid Build Coastguard Worker #include "brotli_bit_stream.h"
22*6777b538SAndroid Build Coastguard Worker #include "compress_fragment.h"
23*6777b538SAndroid Build Coastguard Worker #include "compress_fragment_two_pass.h"
24*6777b538SAndroid Build Coastguard Worker #include "dictionary_hash.h"
25*6777b538SAndroid Build Coastguard Worker #include "encoder_dict.h"
26*6777b538SAndroid Build Coastguard Worker #include "entropy_encode.h"
27*6777b538SAndroid Build Coastguard Worker #include "fast_log.h"
28*6777b538SAndroid Build Coastguard Worker #include "hash.h"
29*6777b538SAndroid Build Coastguard Worker #include "histogram.h"
30*6777b538SAndroid Build Coastguard Worker #include "memory.h"
31*6777b538SAndroid Build Coastguard Worker #include "metablock.h"
32*6777b538SAndroid Build Coastguard Worker #include "prefix.h"
33*6777b538SAndroid Build Coastguard Worker #include "quality.h"
34*6777b538SAndroid Build Coastguard Worker #include "ringbuffer.h"
35*6777b538SAndroid Build Coastguard Worker #include "utf8_util.h"
36*6777b538SAndroid Build Coastguard Worker #include "write_bits.h"
37*6777b538SAndroid Build Coastguard Worker
38*6777b538SAndroid Build Coastguard Worker #if defined(__cplusplus) || defined(c_plusplus)
39*6777b538SAndroid Build Coastguard Worker extern "C" {
40*6777b538SAndroid Build Coastguard Worker #endif
41*6777b538SAndroid Build Coastguard Worker
42*6777b538SAndroid Build Coastguard Worker #define COPY_ARRAY(dst, src) memcpy(dst, src, sizeof(src));
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Worker typedef enum BrotliEncoderStreamState {
45*6777b538SAndroid Build Coastguard Worker /* Default state. */
46*6777b538SAndroid Build Coastguard Worker BROTLI_STREAM_PROCESSING = 0,
47*6777b538SAndroid Build Coastguard Worker /* Intermediate state; after next block is emitted, byte-padding should be
48*6777b538SAndroid Build Coastguard Worker performed before getting back to default state. */
49*6777b538SAndroid Build Coastguard Worker BROTLI_STREAM_FLUSH_REQUESTED = 1,
50*6777b538SAndroid Build Coastguard Worker /* Last metablock was produced; no more input is acceptable. */
51*6777b538SAndroid Build Coastguard Worker BROTLI_STREAM_FINISHED = 2,
52*6777b538SAndroid Build Coastguard Worker /* Flushing compressed block and writing meta-data block header. */
53*6777b538SAndroid Build Coastguard Worker BROTLI_STREAM_METADATA_HEAD = 3,
54*6777b538SAndroid Build Coastguard Worker /* Writing metadata block body. */
55*6777b538SAndroid Build Coastguard Worker BROTLI_STREAM_METADATA_BODY = 4
56*6777b538SAndroid Build Coastguard Worker } BrotliEncoderStreamState;
57*6777b538SAndroid Build Coastguard Worker
58*6777b538SAndroid Build Coastguard Worker typedef enum BrotliEncoderFlintState {
59*6777b538SAndroid Build Coastguard Worker BROTLI_FLINT_NEEDS_2_BYTES = 2,
60*6777b538SAndroid Build Coastguard Worker BROTLI_FLINT_NEEDS_1_BYTE = 1,
61*6777b538SAndroid Build Coastguard Worker BROTLI_FLINT_WAITING_FOR_PROCESSING = 0,
62*6777b538SAndroid Build Coastguard Worker BROTLI_FLINT_WAITING_FOR_FLUSHING = -1,
63*6777b538SAndroid Build Coastguard Worker BROTLI_FLINT_DONE = -2
64*6777b538SAndroid Build Coastguard Worker } BrotliEncoderFlintState;
65*6777b538SAndroid Build Coastguard Worker
66*6777b538SAndroid Build Coastguard Worker typedef struct BrotliEncoderStateStruct {
67*6777b538SAndroid Build Coastguard Worker BrotliEncoderParams params;
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker MemoryManager memory_manager_;
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Worker uint64_t input_pos_;
72*6777b538SAndroid Build Coastguard Worker RingBuffer ringbuffer_;
73*6777b538SAndroid Build Coastguard Worker size_t cmd_alloc_size_;
74*6777b538SAndroid Build Coastguard Worker Command* commands_;
75*6777b538SAndroid Build Coastguard Worker size_t num_commands_;
76*6777b538SAndroid Build Coastguard Worker size_t num_literals_;
77*6777b538SAndroid Build Coastguard Worker size_t last_insert_len_;
78*6777b538SAndroid Build Coastguard Worker uint64_t last_flush_pos_;
79*6777b538SAndroid Build Coastguard Worker uint64_t last_processed_pos_;
80*6777b538SAndroid Build Coastguard Worker int dist_cache_[BROTLI_NUM_DISTANCE_SHORT_CODES];
81*6777b538SAndroid Build Coastguard Worker int saved_dist_cache_[4];
82*6777b538SAndroid Build Coastguard Worker uint16_t last_bytes_;
83*6777b538SAndroid Build Coastguard Worker uint8_t last_bytes_bits_;
84*6777b538SAndroid Build Coastguard Worker /* "Flint" is a tiny uncompressed block emitted before the continuation
85*6777b538SAndroid Build Coastguard Worker block to unwire literal context from previous data. Despite being int8_t,
86*6777b538SAndroid Build Coastguard Worker field is actually BrotliEncoderFlintState enum. */
87*6777b538SAndroid Build Coastguard Worker int8_t flint_;
88*6777b538SAndroid Build Coastguard Worker uint8_t prev_byte_;
89*6777b538SAndroid Build Coastguard Worker uint8_t prev_byte2_;
90*6777b538SAndroid Build Coastguard Worker size_t storage_size_;
91*6777b538SAndroid Build Coastguard Worker uint8_t* storage_;
92*6777b538SAndroid Build Coastguard Worker
93*6777b538SAndroid Build Coastguard Worker Hasher hasher_;
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard Worker /* Hash table for FAST_ONE_PASS_COMPRESSION_QUALITY mode. */
96*6777b538SAndroid Build Coastguard Worker int small_table_[1 << 10]; /* 4KiB */
97*6777b538SAndroid Build Coastguard Worker int* large_table_; /* Allocated only when needed */
98*6777b538SAndroid Build Coastguard Worker size_t large_table_size_;
99*6777b538SAndroid Build Coastguard Worker
100*6777b538SAndroid Build Coastguard Worker BrotliOnePassArena* one_pass_arena_;
101*6777b538SAndroid Build Coastguard Worker BrotliTwoPassArena* two_pass_arena_;
102*6777b538SAndroid Build Coastguard Worker
103*6777b538SAndroid Build Coastguard Worker /* Command and literal buffers for FAST_TWO_PASS_COMPRESSION_QUALITY. */
104*6777b538SAndroid Build Coastguard Worker uint32_t* command_buf_;
105*6777b538SAndroid Build Coastguard Worker uint8_t* literal_buf_;
106*6777b538SAndroid Build Coastguard Worker
107*6777b538SAndroid Build Coastguard Worker uint8_t* next_out_;
108*6777b538SAndroid Build Coastguard Worker size_t available_out_;
109*6777b538SAndroid Build Coastguard Worker size_t total_out_;
110*6777b538SAndroid Build Coastguard Worker /* Temporary buffer for padding flush bits or metadata block header / body. */
111*6777b538SAndroid Build Coastguard Worker union {
112*6777b538SAndroid Build Coastguard Worker uint64_t u64[2];
113*6777b538SAndroid Build Coastguard Worker uint8_t u8[16];
114*6777b538SAndroid Build Coastguard Worker } tiny_buf_;
115*6777b538SAndroid Build Coastguard Worker uint32_t remaining_metadata_bytes_;
116*6777b538SAndroid Build Coastguard Worker BrotliEncoderStreamState stream_state_;
117*6777b538SAndroid Build Coastguard Worker
118*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL is_last_block_emitted_;
119*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL is_initialized_;
120*6777b538SAndroid Build Coastguard Worker } BrotliEncoderStateStruct;
121*6777b538SAndroid Build Coastguard Worker
InputBlockSize(BrotliEncoderState * s)122*6777b538SAndroid Build Coastguard Worker static size_t InputBlockSize(BrotliEncoderState* s) {
123*6777b538SAndroid Build Coastguard Worker return (size_t)1 << s->params.lgblock;
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker
UnprocessedInputSize(BrotliEncoderState * s)126*6777b538SAndroid Build Coastguard Worker static uint64_t UnprocessedInputSize(BrotliEncoderState* s) {
127*6777b538SAndroid Build Coastguard Worker return s->input_pos_ - s->last_processed_pos_;
128*6777b538SAndroid Build Coastguard Worker }
129*6777b538SAndroid Build Coastguard Worker
RemainingInputBlockSize(BrotliEncoderState * s)130*6777b538SAndroid Build Coastguard Worker static size_t RemainingInputBlockSize(BrotliEncoderState* s) {
131*6777b538SAndroid Build Coastguard Worker const uint64_t delta = UnprocessedInputSize(s);
132*6777b538SAndroid Build Coastguard Worker size_t block_size = InputBlockSize(s);
133*6777b538SAndroid Build Coastguard Worker if (delta >= block_size) return 0;
134*6777b538SAndroid Build Coastguard Worker return block_size - (size_t)delta;
135*6777b538SAndroid Build Coastguard Worker }
136*6777b538SAndroid Build Coastguard Worker
BrotliEncoderSetParameter(BrotliEncoderState * state,BrotliEncoderParameter p,uint32_t value)137*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL BrotliEncoderSetParameter(
138*6777b538SAndroid Build Coastguard Worker BrotliEncoderState* state, BrotliEncoderParameter p, uint32_t value) {
139*6777b538SAndroid Build Coastguard Worker /* Changing parameters on the fly is not implemented yet. */
140*6777b538SAndroid Build Coastguard Worker if (state->is_initialized_) return BROTLI_FALSE;
141*6777b538SAndroid Build Coastguard Worker /* TODO(eustas): Validate/clamp parameters here. */
142*6777b538SAndroid Build Coastguard Worker switch (p) {
143*6777b538SAndroid Build Coastguard Worker case BROTLI_PARAM_MODE:
144*6777b538SAndroid Build Coastguard Worker state->params.mode = (BrotliEncoderMode)value;
145*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
146*6777b538SAndroid Build Coastguard Worker
147*6777b538SAndroid Build Coastguard Worker case BROTLI_PARAM_QUALITY:
148*6777b538SAndroid Build Coastguard Worker state->params.quality = (int)value;
149*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
150*6777b538SAndroid Build Coastguard Worker
151*6777b538SAndroid Build Coastguard Worker case BROTLI_PARAM_LGWIN:
152*6777b538SAndroid Build Coastguard Worker state->params.lgwin = (int)value;
153*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Worker case BROTLI_PARAM_LGBLOCK:
156*6777b538SAndroid Build Coastguard Worker state->params.lgblock = (int)value;
157*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker case BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING:
160*6777b538SAndroid Build Coastguard Worker if ((value != 0) && (value != 1)) return BROTLI_FALSE;
161*6777b538SAndroid Build Coastguard Worker state->params.disable_literal_context_modeling = TO_BROTLI_BOOL(!!value);
162*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
163*6777b538SAndroid Build Coastguard Worker
164*6777b538SAndroid Build Coastguard Worker case BROTLI_PARAM_SIZE_HINT:
165*6777b538SAndroid Build Coastguard Worker state->params.size_hint = value;
166*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
167*6777b538SAndroid Build Coastguard Worker
168*6777b538SAndroid Build Coastguard Worker case BROTLI_PARAM_LARGE_WINDOW:
169*6777b538SAndroid Build Coastguard Worker state->params.large_window = TO_BROTLI_BOOL(!!value);
170*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
171*6777b538SAndroid Build Coastguard Worker
172*6777b538SAndroid Build Coastguard Worker case BROTLI_PARAM_NPOSTFIX:
173*6777b538SAndroid Build Coastguard Worker state->params.dist.distance_postfix_bits = value;
174*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
175*6777b538SAndroid Build Coastguard Worker
176*6777b538SAndroid Build Coastguard Worker case BROTLI_PARAM_NDIRECT:
177*6777b538SAndroid Build Coastguard Worker state->params.dist.num_direct_distance_codes = value;
178*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
179*6777b538SAndroid Build Coastguard Worker
180*6777b538SAndroid Build Coastguard Worker case BROTLI_PARAM_STREAM_OFFSET:
181*6777b538SAndroid Build Coastguard Worker if (value > (1u << 30)) return BROTLI_FALSE;
182*6777b538SAndroid Build Coastguard Worker state->params.stream_offset = value;
183*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
184*6777b538SAndroid Build Coastguard Worker
185*6777b538SAndroid Build Coastguard Worker default: return BROTLI_FALSE;
186*6777b538SAndroid Build Coastguard Worker }
187*6777b538SAndroid Build Coastguard Worker }
188*6777b538SAndroid Build Coastguard Worker
189*6777b538SAndroid Build Coastguard Worker /* Wraps 64-bit input position to 32-bit ring-buffer position preserving
190*6777b538SAndroid Build Coastguard Worker "not-a-first-lap" feature. */
WrapPosition(uint64_t position)191*6777b538SAndroid Build Coastguard Worker static uint32_t WrapPosition(uint64_t position) {
192*6777b538SAndroid Build Coastguard Worker uint32_t result = (uint32_t)position;
193*6777b538SAndroid Build Coastguard Worker uint64_t gb = position >> 30;
194*6777b538SAndroid Build Coastguard Worker if (gb > 2) {
195*6777b538SAndroid Build Coastguard Worker /* Wrap every 2GiB; The first 3GB are continuous. */
196*6777b538SAndroid Build Coastguard Worker result = (result & ((1u << 30) - 1)) | ((uint32_t)((gb - 1) & 1) + 1) << 30;
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker return result;
199*6777b538SAndroid Build Coastguard Worker }
200*6777b538SAndroid Build Coastguard Worker
GetBrotliStorage(BrotliEncoderState * s,size_t size)201*6777b538SAndroid Build Coastguard Worker static uint8_t* GetBrotliStorage(BrotliEncoderState* s, size_t size) {
202*6777b538SAndroid Build Coastguard Worker MemoryManager* m = &s->memory_manager_;
203*6777b538SAndroid Build Coastguard Worker if (s->storage_size_ < size) {
204*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, s->storage_);
205*6777b538SAndroid Build Coastguard Worker s->storage_ = BROTLI_ALLOC(m, uint8_t, size);
206*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->storage_)) return NULL;
207*6777b538SAndroid Build Coastguard Worker s->storage_size_ = size;
208*6777b538SAndroid Build Coastguard Worker }
209*6777b538SAndroid Build Coastguard Worker return s->storage_;
210*6777b538SAndroid Build Coastguard Worker }
211*6777b538SAndroid Build Coastguard Worker
HashTableSize(size_t max_table_size,size_t input_size)212*6777b538SAndroid Build Coastguard Worker static size_t HashTableSize(size_t max_table_size, size_t input_size) {
213*6777b538SAndroid Build Coastguard Worker size_t htsize = 256;
214*6777b538SAndroid Build Coastguard Worker while (htsize < max_table_size && htsize < input_size) {
215*6777b538SAndroid Build Coastguard Worker htsize <<= 1;
216*6777b538SAndroid Build Coastguard Worker }
217*6777b538SAndroid Build Coastguard Worker return htsize;
218*6777b538SAndroid Build Coastguard Worker }
219*6777b538SAndroid Build Coastguard Worker
GetHashTable(BrotliEncoderState * s,int quality,size_t input_size,size_t * table_size)220*6777b538SAndroid Build Coastguard Worker static int* GetHashTable(BrotliEncoderState* s, int quality,
221*6777b538SAndroid Build Coastguard Worker size_t input_size, size_t* table_size) {
222*6777b538SAndroid Build Coastguard Worker /* Use smaller hash table when input.size() is smaller, since we
223*6777b538SAndroid Build Coastguard Worker fill the table, incurring O(hash table size) overhead for
224*6777b538SAndroid Build Coastguard Worker compression, and if the input is short, we won't need that
225*6777b538SAndroid Build Coastguard Worker many hash table entries anyway. */
226*6777b538SAndroid Build Coastguard Worker MemoryManager* m = &s->memory_manager_;
227*6777b538SAndroid Build Coastguard Worker const size_t max_table_size = MaxHashTableSize(quality);
228*6777b538SAndroid Build Coastguard Worker size_t htsize = HashTableSize(max_table_size, input_size);
229*6777b538SAndroid Build Coastguard Worker int* table;
230*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(max_table_size >= 256);
231*6777b538SAndroid Build Coastguard Worker if (quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
232*6777b538SAndroid Build Coastguard Worker /* Only odd shifts are supported by fast-one-pass. */
233*6777b538SAndroid Build Coastguard Worker if ((htsize & 0xAAAAA) == 0) {
234*6777b538SAndroid Build Coastguard Worker htsize <<= 1;
235*6777b538SAndroid Build Coastguard Worker }
236*6777b538SAndroid Build Coastguard Worker }
237*6777b538SAndroid Build Coastguard Worker
238*6777b538SAndroid Build Coastguard Worker if (htsize <= sizeof(s->small_table_) / sizeof(s->small_table_[0])) {
239*6777b538SAndroid Build Coastguard Worker table = s->small_table_;
240*6777b538SAndroid Build Coastguard Worker } else {
241*6777b538SAndroid Build Coastguard Worker if (htsize > s->large_table_size_) {
242*6777b538SAndroid Build Coastguard Worker s->large_table_size_ = htsize;
243*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, s->large_table_);
244*6777b538SAndroid Build Coastguard Worker s->large_table_ = BROTLI_ALLOC(m, int, htsize);
245*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->large_table_)) return 0;
246*6777b538SAndroid Build Coastguard Worker }
247*6777b538SAndroid Build Coastguard Worker table = s->large_table_;
248*6777b538SAndroid Build Coastguard Worker }
249*6777b538SAndroid Build Coastguard Worker
250*6777b538SAndroid Build Coastguard Worker *table_size = htsize;
251*6777b538SAndroid Build Coastguard Worker memset(table, 0, htsize * sizeof(*table));
252*6777b538SAndroid Build Coastguard Worker return table;
253*6777b538SAndroid Build Coastguard Worker }
254*6777b538SAndroid Build Coastguard Worker
EncodeWindowBits(int lgwin,BROTLI_BOOL large_window,uint16_t * last_bytes,uint8_t * last_bytes_bits)255*6777b538SAndroid Build Coastguard Worker static void EncodeWindowBits(int lgwin, BROTLI_BOOL large_window,
256*6777b538SAndroid Build Coastguard Worker uint16_t* last_bytes, uint8_t* last_bytes_bits) {
257*6777b538SAndroid Build Coastguard Worker if (large_window) {
258*6777b538SAndroid Build Coastguard Worker *last_bytes = (uint16_t)(((lgwin & 0x3F) << 8) | 0x11);
259*6777b538SAndroid Build Coastguard Worker *last_bytes_bits = 14;
260*6777b538SAndroid Build Coastguard Worker } else {
261*6777b538SAndroid Build Coastguard Worker if (lgwin == 16) {
262*6777b538SAndroid Build Coastguard Worker *last_bytes = 0;
263*6777b538SAndroid Build Coastguard Worker *last_bytes_bits = 1;
264*6777b538SAndroid Build Coastguard Worker } else if (lgwin == 17) {
265*6777b538SAndroid Build Coastguard Worker *last_bytes = 1;
266*6777b538SAndroid Build Coastguard Worker *last_bytes_bits = 7;
267*6777b538SAndroid Build Coastguard Worker } else if (lgwin > 17) {
268*6777b538SAndroid Build Coastguard Worker *last_bytes = (uint16_t)(((lgwin - 17) << 1) | 0x01);
269*6777b538SAndroid Build Coastguard Worker *last_bytes_bits = 4;
270*6777b538SAndroid Build Coastguard Worker } else {
271*6777b538SAndroid Build Coastguard Worker *last_bytes = (uint16_t)(((lgwin - 8) << 4) | 0x01);
272*6777b538SAndroid Build Coastguard Worker *last_bytes_bits = 7;
273*6777b538SAndroid Build Coastguard Worker }
274*6777b538SAndroid Build Coastguard Worker }
275*6777b538SAndroid Build Coastguard Worker }
276*6777b538SAndroid Build Coastguard Worker
277*6777b538SAndroid Build Coastguard Worker /* TODO(eustas): move to compress_fragment.c? */
278*6777b538SAndroid Build Coastguard Worker /* Initializes the command and distance prefix codes for the first block. */
InitCommandPrefixCodes(BrotliOnePassArena * s)279*6777b538SAndroid Build Coastguard Worker static void InitCommandPrefixCodes(BrotliOnePassArena* s) {
280*6777b538SAndroid Build Coastguard Worker static const uint8_t kDefaultCommandDepths[128] = {
281*6777b538SAndroid Build Coastguard Worker 0, 4, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8,
282*6777b538SAndroid Build Coastguard Worker 0, 0, 0, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7,
283*6777b538SAndroid Build Coastguard Worker 7, 7, 10, 10, 10, 10, 10, 10, 0, 4, 4, 5, 5, 5, 6, 6,
284*6777b538SAndroid Build Coastguard Worker 7, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
285*6777b538SAndroid Build Coastguard Worker 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
286*6777b538SAndroid Build Coastguard Worker 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,
287*6777b538SAndroid Build Coastguard Worker 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 10,
288*6777b538SAndroid Build Coastguard Worker 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
289*6777b538SAndroid Build Coastguard Worker };
290*6777b538SAndroid Build Coastguard Worker static const uint16_t kDefaultCommandBits[128] = {
291*6777b538SAndroid Build Coastguard Worker 0, 0, 8, 9, 3, 35, 7, 71,
292*6777b538SAndroid Build Coastguard Worker 39, 103, 23, 47, 175, 111, 239, 31,
293*6777b538SAndroid Build Coastguard Worker 0, 0, 0, 4, 12, 2, 10, 6,
294*6777b538SAndroid Build Coastguard Worker 13, 29, 11, 43, 27, 59, 87, 55,
295*6777b538SAndroid Build Coastguard Worker 15, 79, 319, 831, 191, 703, 447, 959,
296*6777b538SAndroid Build Coastguard Worker 0, 14, 1, 25, 5, 21, 19, 51,
297*6777b538SAndroid Build Coastguard Worker 119, 159, 95, 223, 479, 991, 63, 575,
298*6777b538SAndroid Build Coastguard Worker 127, 639, 383, 895, 255, 767, 511, 1023,
299*6777b538SAndroid Build Coastguard Worker 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
300*6777b538SAndroid Build Coastguard Worker 27, 59, 7, 39, 23, 55, 30, 1, 17, 9, 25, 5, 0, 8, 4, 12,
301*6777b538SAndroid Build Coastguard Worker 2, 10, 6, 21, 13, 29, 3, 19, 11, 15, 47, 31, 95, 63, 127, 255,
302*6777b538SAndroid Build Coastguard Worker 767, 2815, 1791, 3839, 511, 2559, 1535, 3583, 1023, 3071, 2047, 4095,
303*6777b538SAndroid Build Coastguard Worker };
304*6777b538SAndroid Build Coastguard Worker static const uint8_t kDefaultCommandCode[] = {
305*6777b538SAndroid Build Coastguard Worker 0xff, 0x77, 0xd5, 0xbf, 0xe7, 0xde, 0xea, 0x9e, 0x51, 0x5d, 0xde, 0xc6,
306*6777b538SAndroid Build Coastguard Worker 0x70, 0x57, 0xbc, 0x58, 0x58, 0x58, 0xd8, 0xd8, 0x58, 0xd5, 0xcb, 0x8c,
307*6777b538SAndroid Build Coastguard Worker 0xea, 0xe0, 0xc3, 0x87, 0x1f, 0x83, 0xc1, 0x60, 0x1c, 0x67, 0xb2, 0xaa,
308*6777b538SAndroid Build Coastguard Worker 0x06, 0x83, 0xc1, 0x60, 0x30, 0x18, 0xcc, 0xa1, 0xce, 0x88, 0x54, 0x94,
309*6777b538SAndroid Build Coastguard Worker 0x46, 0xe1, 0xb0, 0xd0, 0x4e, 0xb2, 0xf7, 0x04, 0x00,
310*6777b538SAndroid Build Coastguard Worker };
311*6777b538SAndroid Build Coastguard Worker static const size_t kDefaultCommandCodeNumBits = 448;
312*6777b538SAndroid Build Coastguard Worker COPY_ARRAY(s->cmd_depth, kDefaultCommandDepths);
313*6777b538SAndroid Build Coastguard Worker COPY_ARRAY(s->cmd_bits, kDefaultCommandBits);
314*6777b538SAndroid Build Coastguard Worker
315*6777b538SAndroid Build Coastguard Worker /* Initialize the pre-compressed form of the command and distance prefix
316*6777b538SAndroid Build Coastguard Worker codes. */
317*6777b538SAndroid Build Coastguard Worker COPY_ARRAY(s->cmd_code, kDefaultCommandCode);
318*6777b538SAndroid Build Coastguard Worker s->cmd_code_numbits = kDefaultCommandCodeNumBits;
319*6777b538SAndroid Build Coastguard Worker }
320*6777b538SAndroid Build Coastguard Worker
321*6777b538SAndroid Build Coastguard Worker /* Decide about the context map based on the ability of the prediction
322*6777b538SAndroid Build Coastguard Worker ability of the previous byte UTF8-prefix on the next byte. The
323*6777b538SAndroid Build Coastguard Worker prediction ability is calculated as Shannon entropy. Here we need
324*6777b538SAndroid Build Coastguard Worker Shannon entropy instead of 'BitsEntropy' since the prefix will be
325*6777b538SAndroid Build Coastguard Worker encoded with the remaining 6 bits of the following byte, and
326*6777b538SAndroid Build Coastguard Worker BitsEntropy will assume that symbol to be stored alone using Huffman
327*6777b538SAndroid Build Coastguard Worker coding. */
ChooseContextMap(int quality,uint32_t * bigram_histo,size_t * num_literal_contexts,const uint32_t ** literal_context_map)328*6777b538SAndroid Build Coastguard Worker static void ChooseContextMap(int quality,
329*6777b538SAndroid Build Coastguard Worker uint32_t* bigram_histo,
330*6777b538SAndroid Build Coastguard Worker size_t* num_literal_contexts,
331*6777b538SAndroid Build Coastguard Worker const uint32_t** literal_context_map) {
332*6777b538SAndroid Build Coastguard Worker static const uint32_t kStaticContextMapContinuation[64] = {
333*6777b538SAndroid Build Coastguard Worker 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
334*6777b538SAndroid Build Coastguard Worker 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
335*6777b538SAndroid Build Coastguard Worker 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
336*6777b538SAndroid Build Coastguard Worker 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
337*6777b538SAndroid Build Coastguard Worker };
338*6777b538SAndroid Build Coastguard Worker static const uint32_t kStaticContextMapSimpleUTF8[64] = {
339*6777b538SAndroid Build Coastguard Worker 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
340*6777b538SAndroid Build Coastguard Worker 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
341*6777b538SAndroid Build Coastguard Worker 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
342*6777b538SAndroid Build Coastguard Worker 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
343*6777b538SAndroid Build Coastguard Worker };
344*6777b538SAndroid Build Coastguard Worker
345*6777b538SAndroid Build Coastguard Worker uint32_t monogram_histo[3] = { 0 };
346*6777b538SAndroid Build Coastguard Worker uint32_t two_prefix_histo[6] = { 0 };
347*6777b538SAndroid Build Coastguard Worker size_t total;
348*6777b538SAndroid Build Coastguard Worker size_t i;
349*6777b538SAndroid Build Coastguard Worker size_t dummy;
350*6777b538SAndroid Build Coastguard Worker double entropy[4];
351*6777b538SAndroid Build Coastguard Worker for (i = 0; i < 9; ++i) {
352*6777b538SAndroid Build Coastguard Worker monogram_histo[i % 3] += bigram_histo[i];
353*6777b538SAndroid Build Coastguard Worker two_prefix_histo[i % 6] += bigram_histo[i];
354*6777b538SAndroid Build Coastguard Worker }
355*6777b538SAndroid Build Coastguard Worker entropy[1] = ShannonEntropy(monogram_histo, 3, &dummy);
356*6777b538SAndroid Build Coastguard Worker entropy[2] = (ShannonEntropy(two_prefix_histo, 3, &dummy) +
357*6777b538SAndroid Build Coastguard Worker ShannonEntropy(two_prefix_histo + 3, 3, &dummy));
358*6777b538SAndroid Build Coastguard Worker entropy[3] = 0;
359*6777b538SAndroid Build Coastguard Worker for (i = 0; i < 3; ++i) {
360*6777b538SAndroid Build Coastguard Worker entropy[3] += ShannonEntropy(bigram_histo + 3 * i, 3, &dummy);
361*6777b538SAndroid Build Coastguard Worker }
362*6777b538SAndroid Build Coastguard Worker
363*6777b538SAndroid Build Coastguard Worker total = monogram_histo[0] + monogram_histo[1] + monogram_histo[2];
364*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(total != 0);
365*6777b538SAndroid Build Coastguard Worker entropy[0] = 1.0 / (double)total;
366*6777b538SAndroid Build Coastguard Worker entropy[1] *= entropy[0];
367*6777b538SAndroid Build Coastguard Worker entropy[2] *= entropy[0];
368*6777b538SAndroid Build Coastguard Worker entropy[3] *= entropy[0];
369*6777b538SAndroid Build Coastguard Worker
370*6777b538SAndroid Build Coastguard Worker if (quality < MIN_QUALITY_FOR_HQ_CONTEXT_MODELING) {
371*6777b538SAndroid Build Coastguard Worker /* 3 context models is a bit slower, don't use it at lower qualities. */
372*6777b538SAndroid Build Coastguard Worker entropy[3] = entropy[1] * 10;
373*6777b538SAndroid Build Coastguard Worker }
374*6777b538SAndroid Build Coastguard Worker /* If expected savings by symbol are less than 0.2 bits, skip the
375*6777b538SAndroid Build Coastguard Worker context modeling -- in exchange for faster decoding speed. */
376*6777b538SAndroid Build Coastguard Worker if (entropy[1] - entropy[2] < 0.2 &&
377*6777b538SAndroid Build Coastguard Worker entropy[1] - entropy[3] < 0.2) {
378*6777b538SAndroid Build Coastguard Worker *num_literal_contexts = 1;
379*6777b538SAndroid Build Coastguard Worker } else if (entropy[2] - entropy[3] < 0.02) {
380*6777b538SAndroid Build Coastguard Worker *num_literal_contexts = 2;
381*6777b538SAndroid Build Coastguard Worker *literal_context_map = kStaticContextMapSimpleUTF8;
382*6777b538SAndroid Build Coastguard Worker } else {
383*6777b538SAndroid Build Coastguard Worker *num_literal_contexts = 3;
384*6777b538SAndroid Build Coastguard Worker *literal_context_map = kStaticContextMapContinuation;
385*6777b538SAndroid Build Coastguard Worker }
386*6777b538SAndroid Build Coastguard Worker }
387*6777b538SAndroid Build Coastguard Worker
388*6777b538SAndroid Build Coastguard Worker /* Decide if we want to use a more complex static context map containing 13
389*6777b538SAndroid Build Coastguard Worker context values, based on the entropy reduction of histograms over the
390*6777b538SAndroid Build Coastguard Worker first 5 bits of literals. */
ShouldUseComplexStaticContextMap(const uint8_t * input,size_t start_pos,size_t length,size_t mask,int quality,size_t size_hint,size_t * num_literal_contexts,const uint32_t ** literal_context_map,uint32_t * arena)391*6777b538SAndroid Build Coastguard Worker static BROTLI_BOOL ShouldUseComplexStaticContextMap(const uint8_t* input,
392*6777b538SAndroid Build Coastguard Worker size_t start_pos, size_t length, size_t mask, int quality, size_t size_hint,
393*6777b538SAndroid Build Coastguard Worker size_t* num_literal_contexts, const uint32_t** literal_context_map,
394*6777b538SAndroid Build Coastguard Worker uint32_t* arena) {
395*6777b538SAndroid Build Coastguard Worker static const uint32_t kStaticContextMapComplexUTF8[64] = {
396*6777b538SAndroid Build Coastguard Worker 11, 11, 12, 12, /* 0 special */
397*6777b538SAndroid Build Coastguard Worker 0, 0, 0, 0, /* 4 lf */
398*6777b538SAndroid Build Coastguard Worker 1, 1, 9, 9, /* 8 space */
399*6777b538SAndroid Build Coastguard Worker 2, 2, 2, 2, /* !, first after space/lf and after something else. */
400*6777b538SAndroid Build Coastguard Worker 1, 1, 1, 1, /* " */
401*6777b538SAndroid Build Coastguard Worker 8, 3, 3, 3, /* % */
402*6777b538SAndroid Build Coastguard Worker 1, 1, 1, 1, /* ({[ */
403*6777b538SAndroid Build Coastguard Worker 2, 2, 2, 2, /* }]) */
404*6777b538SAndroid Build Coastguard Worker 8, 4, 4, 4, /* :; */
405*6777b538SAndroid Build Coastguard Worker 8, 7, 4, 4, /* . */
406*6777b538SAndroid Build Coastguard Worker 8, 0, 0, 0, /* > */
407*6777b538SAndroid Build Coastguard Worker 3, 3, 3, 3, /* [0..9] */
408*6777b538SAndroid Build Coastguard Worker 5, 5, 10, 5, /* [A-Z] */
409*6777b538SAndroid Build Coastguard Worker 5, 5, 10, 5,
410*6777b538SAndroid Build Coastguard Worker 6, 6, 6, 6, /* [a-z] */
411*6777b538SAndroid Build Coastguard Worker 6, 6, 6, 6,
412*6777b538SAndroid Build Coastguard Worker };
413*6777b538SAndroid Build Coastguard Worker BROTLI_UNUSED(quality);
414*6777b538SAndroid Build Coastguard Worker /* Try the more complex static context map only for long data. */
415*6777b538SAndroid Build Coastguard Worker if (size_hint < (1 << 20)) {
416*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
417*6777b538SAndroid Build Coastguard Worker } else {
418*6777b538SAndroid Build Coastguard Worker const size_t end_pos = start_pos + length;
419*6777b538SAndroid Build Coastguard Worker /* To make entropy calculations faster, we collect histograms
420*6777b538SAndroid Build Coastguard Worker over the 5 most significant bits of literals. One histogram
421*6777b538SAndroid Build Coastguard Worker without context and 13 additional histograms for each context value. */
422*6777b538SAndroid Build Coastguard Worker uint32_t* BROTLI_RESTRICT const combined_histo = arena;
423*6777b538SAndroid Build Coastguard Worker uint32_t* BROTLI_RESTRICT const context_histo = arena + 32;
424*6777b538SAndroid Build Coastguard Worker uint32_t total = 0;
425*6777b538SAndroid Build Coastguard Worker double entropy[3];
426*6777b538SAndroid Build Coastguard Worker size_t dummy;
427*6777b538SAndroid Build Coastguard Worker size_t i;
428*6777b538SAndroid Build Coastguard Worker ContextLut utf8_lut = BROTLI_CONTEXT_LUT(CONTEXT_UTF8);
429*6777b538SAndroid Build Coastguard Worker memset(arena, 0, sizeof(arena[0]) * 32 * 14);
430*6777b538SAndroid Build Coastguard Worker for (; start_pos + 64 <= end_pos; start_pos += 4096) {
431*6777b538SAndroid Build Coastguard Worker const size_t stride_end_pos = start_pos + 64;
432*6777b538SAndroid Build Coastguard Worker uint8_t prev2 = input[start_pos & mask];
433*6777b538SAndroid Build Coastguard Worker uint8_t prev1 = input[(start_pos + 1) & mask];
434*6777b538SAndroid Build Coastguard Worker size_t pos;
435*6777b538SAndroid Build Coastguard Worker /* To make the analysis of the data faster we only examine 64 byte long
436*6777b538SAndroid Build Coastguard Worker strides at every 4kB intervals. */
437*6777b538SAndroid Build Coastguard Worker for (pos = start_pos + 2; pos < stride_end_pos; ++pos) {
438*6777b538SAndroid Build Coastguard Worker const uint8_t literal = input[pos & mask];
439*6777b538SAndroid Build Coastguard Worker const uint8_t context = (uint8_t)kStaticContextMapComplexUTF8[
440*6777b538SAndroid Build Coastguard Worker BROTLI_CONTEXT(prev1, prev2, utf8_lut)];
441*6777b538SAndroid Build Coastguard Worker ++total;
442*6777b538SAndroid Build Coastguard Worker ++combined_histo[literal >> 3];
443*6777b538SAndroid Build Coastguard Worker ++context_histo[(context << 5) + (literal >> 3)];
444*6777b538SAndroid Build Coastguard Worker prev2 = prev1;
445*6777b538SAndroid Build Coastguard Worker prev1 = literal;
446*6777b538SAndroid Build Coastguard Worker }
447*6777b538SAndroid Build Coastguard Worker }
448*6777b538SAndroid Build Coastguard Worker entropy[1] = ShannonEntropy(combined_histo, 32, &dummy);
449*6777b538SAndroid Build Coastguard Worker entropy[2] = 0;
450*6777b538SAndroid Build Coastguard Worker for (i = 0; i < 13; ++i) {
451*6777b538SAndroid Build Coastguard Worker entropy[2] += ShannonEntropy(context_histo + (i << 5), 32, &dummy);
452*6777b538SAndroid Build Coastguard Worker }
453*6777b538SAndroid Build Coastguard Worker entropy[0] = 1.0 / (double)total;
454*6777b538SAndroid Build Coastguard Worker entropy[1] *= entropy[0];
455*6777b538SAndroid Build Coastguard Worker entropy[2] *= entropy[0];
456*6777b538SAndroid Build Coastguard Worker /* The triggering heuristics below were tuned by compressing the individual
457*6777b538SAndroid Build Coastguard Worker files of the silesia corpus. If we skip this kind of context modeling
458*6777b538SAndroid Build Coastguard Worker for not very well compressible input (i.e. entropy using context modeling
459*6777b538SAndroid Build Coastguard Worker is 60% of maximal entropy) or if expected savings by symbol are less
460*6777b538SAndroid Build Coastguard Worker than 0.2 bits, then in every case when it triggers, the final compression
461*6777b538SAndroid Build Coastguard Worker ratio is improved. Note however that this heuristics might be too strict
462*6777b538SAndroid Build Coastguard Worker for some cases and could be tuned further. */
463*6777b538SAndroid Build Coastguard Worker if (entropy[2] > 3.0 || entropy[1] - entropy[2] < 0.2) {
464*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
465*6777b538SAndroid Build Coastguard Worker } else {
466*6777b538SAndroid Build Coastguard Worker *num_literal_contexts = 13;
467*6777b538SAndroid Build Coastguard Worker *literal_context_map = kStaticContextMapComplexUTF8;
468*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
469*6777b538SAndroid Build Coastguard Worker }
470*6777b538SAndroid Build Coastguard Worker }
471*6777b538SAndroid Build Coastguard Worker }
472*6777b538SAndroid Build Coastguard Worker
DecideOverLiteralContextModeling(const uint8_t * input,size_t start_pos,size_t length,size_t mask,int quality,size_t size_hint,size_t * num_literal_contexts,const uint32_t ** literal_context_map,uint32_t * arena)473*6777b538SAndroid Build Coastguard Worker static void DecideOverLiteralContextModeling(const uint8_t* input,
474*6777b538SAndroid Build Coastguard Worker size_t start_pos, size_t length, size_t mask, int quality, size_t size_hint,
475*6777b538SAndroid Build Coastguard Worker size_t* num_literal_contexts, const uint32_t** literal_context_map,
476*6777b538SAndroid Build Coastguard Worker uint32_t* arena) {
477*6777b538SAndroid Build Coastguard Worker if (quality < MIN_QUALITY_FOR_CONTEXT_MODELING || length < 64) {
478*6777b538SAndroid Build Coastguard Worker return;
479*6777b538SAndroid Build Coastguard Worker } else if (ShouldUseComplexStaticContextMap(
480*6777b538SAndroid Build Coastguard Worker input, start_pos, length, mask, quality, size_hint,
481*6777b538SAndroid Build Coastguard Worker num_literal_contexts, literal_context_map, arena)) {
482*6777b538SAndroid Build Coastguard Worker /* Context map was already set, nothing else to do. */
483*6777b538SAndroid Build Coastguard Worker } else {
484*6777b538SAndroid Build Coastguard Worker /* Gather bi-gram data of the UTF8 byte prefixes. To make the analysis of
485*6777b538SAndroid Build Coastguard Worker UTF8 data faster we only examine 64 byte long strides at every 4kB
486*6777b538SAndroid Build Coastguard Worker intervals. */
487*6777b538SAndroid Build Coastguard Worker const size_t end_pos = start_pos + length;
488*6777b538SAndroid Build Coastguard Worker uint32_t* BROTLI_RESTRICT const bigram_prefix_histo = arena;
489*6777b538SAndroid Build Coastguard Worker memset(bigram_prefix_histo, 0, sizeof(arena[0]) * 9);
490*6777b538SAndroid Build Coastguard Worker for (; start_pos + 64 <= end_pos; start_pos += 4096) {
491*6777b538SAndroid Build Coastguard Worker static const int lut[4] = { 0, 0, 1, 2 };
492*6777b538SAndroid Build Coastguard Worker const size_t stride_end_pos = start_pos + 64;
493*6777b538SAndroid Build Coastguard Worker int prev = lut[input[start_pos & mask] >> 6] * 3;
494*6777b538SAndroid Build Coastguard Worker size_t pos;
495*6777b538SAndroid Build Coastguard Worker for (pos = start_pos + 1; pos < stride_end_pos; ++pos) {
496*6777b538SAndroid Build Coastguard Worker const uint8_t literal = input[pos & mask];
497*6777b538SAndroid Build Coastguard Worker ++bigram_prefix_histo[prev + lut[literal >> 6]];
498*6777b538SAndroid Build Coastguard Worker prev = lut[literal >> 6] * 3;
499*6777b538SAndroid Build Coastguard Worker }
500*6777b538SAndroid Build Coastguard Worker }
501*6777b538SAndroid Build Coastguard Worker ChooseContextMap(quality, &bigram_prefix_histo[0], num_literal_contexts,
502*6777b538SAndroid Build Coastguard Worker literal_context_map);
503*6777b538SAndroid Build Coastguard Worker }
504*6777b538SAndroid Build Coastguard Worker }
505*6777b538SAndroid Build Coastguard Worker
ShouldCompress(const uint8_t * data,const size_t mask,const uint64_t last_flush_pos,const size_t bytes,const size_t num_literals,const size_t num_commands)506*6777b538SAndroid Build Coastguard Worker static BROTLI_BOOL ShouldCompress(
507*6777b538SAndroid Build Coastguard Worker const uint8_t* data, const size_t mask, const uint64_t last_flush_pos,
508*6777b538SAndroid Build Coastguard Worker const size_t bytes, const size_t num_literals, const size_t num_commands) {
509*6777b538SAndroid Build Coastguard Worker /* TODO(eustas): find more precise minimal block overhead. */
510*6777b538SAndroid Build Coastguard Worker if (bytes <= 2) return BROTLI_FALSE;
511*6777b538SAndroid Build Coastguard Worker if (num_commands < (bytes >> 8) + 2) {
512*6777b538SAndroid Build Coastguard Worker if ((double)num_literals > 0.99 * (double)bytes) {
513*6777b538SAndroid Build Coastguard Worker uint32_t literal_histo[256] = { 0 };
514*6777b538SAndroid Build Coastguard Worker static const uint32_t kSampleRate = 13;
515*6777b538SAndroid Build Coastguard Worker static const double kMinEntropy = 7.92;
516*6777b538SAndroid Build Coastguard Worker const double bit_cost_threshold =
517*6777b538SAndroid Build Coastguard Worker (double)bytes * kMinEntropy / kSampleRate;
518*6777b538SAndroid Build Coastguard Worker size_t t = (bytes + kSampleRate - 1) / kSampleRate;
519*6777b538SAndroid Build Coastguard Worker uint32_t pos = (uint32_t)last_flush_pos;
520*6777b538SAndroid Build Coastguard Worker size_t i;
521*6777b538SAndroid Build Coastguard Worker for (i = 0; i < t; i++) {
522*6777b538SAndroid Build Coastguard Worker ++literal_histo[data[pos & mask]];
523*6777b538SAndroid Build Coastguard Worker pos += kSampleRate;
524*6777b538SAndroid Build Coastguard Worker }
525*6777b538SAndroid Build Coastguard Worker if (BitsEntropy(literal_histo, 256) > bit_cost_threshold) {
526*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
527*6777b538SAndroid Build Coastguard Worker }
528*6777b538SAndroid Build Coastguard Worker }
529*6777b538SAndroid Build Coastguard Worker }
530*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
531*6777b538SAndroid Build Coastguard Worker }
532*6777b538SAndroid Build Coastguard Worker
533*6777b538SAndroid Build Coastguard Worker /* Chooses the literal context mode for a metablock */
ChooseContextMode(const BrotliEncoderParams * params,const uint8_t * data,const size_t pos,const size_t mask,const size_t length)534*6777b538SAndroid Build Coastguard Worker static ContextType ChooseContextMode(const BrotliEncoderParams* params,
535*6777b538SAndroid Build Coastguard Worker const uint8_t* data, const size_t pos, const size_t mask,
536*6777b538SAndroid Build Coastguard Worker const size_t length) {
537*6777b538SAndroid Build Coastguard Worker /* We only do the computation for the option of something else than
538*6777b538SAndroid Build Coastguard Worker CONTEXT_UTF8 for the highest qualities */
539*6777b538SAndroid Build Coastguard Worker if (params->quality >= MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING &&
540*6777b538SAndroid Build Coastguard Worker !BrotliIsMostlyUTF8(data, pos, mask, length, kMinUTF8Ratio)) {
541*6777b538SAndroid Build Coastguard Worker return CONTEXT_SIGNED;
542*6777b538SAndroid Build Coastguard Worker }
543*6777b538SAndroid Build Coastguard Worker return CONTEXT_UTF8;
544*6777b538SAndroid Build Coastguard Worker }
545*6777b538SAndroid Build Coastguard Worker
WriteMetaBlockInternal(MemoryManager * m,const uint8_t * data,const size_t mask,const uint64_t last_flush_pos,const size_t bytes,const BROTLI_BOOL is_last,ContextType literal_context_mode,const BrotliEncoderParams * params,const uint8_t prev_byte,const uint8_t prev_byte2,const size_t num_literals,const size_t num_commands,Command * commands,const int * saved_dist_cache,int * dist_cache,size_t * storage_ix,uint8_t * storage)546*6777b538SAndroid Build Coastguard Worker static void WriteMetaBlockInternal(MemoryManager* m,
547*6777b538SAndroid Build Coastguard Worker const uint8_t* data,
548*6777b538SAndroid Build Coastguard Worker const size_t mask,
549*6777b538SAndroid Build Coastguard Worker const uint64_t last_flush_pos,
550*6777b538SAndroid Build Coastguard Worker const size_t bytes,
551*6777b538SAndroid Build Coastguard Worker const BROTLI_BOOL is_last,
552*6777b538SAndroid Build Coastguard Worker ContextType literal_context_mode,
553*6777b538SAndroid Build Coastguard Worker const BrotliEncoderParams* params,
554*6777b538SAndroid Build Coastguard Worker const uint8_t prev_byte,
555*6777b538SAndroid Build Coastguard Worker const uint8_t prev_byte2,
556*6777b538SAndroid Build Coastguard Worker const size_t num_literals,
557*6777b538SAndroid Build Coastguard Worker const size_t num_commands,
558*6777b538SAndroid Build Coastguard Worker Command* commands,
559*6777b538SAndroid Build Coastguard Worker const int* saved_dist_cache,
560*6777b538SAndroid Build Coastguard Worker int* dist_cache,
561*6777b538SAndroid Build Coastguard Worker size_t* storage_ix,
562*6777b538SAndroid Build Coastguard Worker uint8_t* storage) {
563*6777b538SAndroid Build Coastguard Worker const uint32_t wrapped_last_flush_pos = WrapPosition(last_flush_pos);
564*6777b538SAndroid Build Coastguard Worker uint16_t last_bytes;
565*6777b538SAndroid Build Coastguard Worker uint8_t last_bytes_bits;
566*6777b538SAndroid Build Coastguard Worker ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
567*6777b538SAndroid Build Coastguard Worker BrotliEncoderParams block_params = *params;
568*6777b538SAndroid Build Coastguard Worker
569*6777b538SAndroid Build Coastguard Worker if (bytes == 0) {
570*6777b538SAndroid Build Coastguard Worker /* Write the ISLAST and ISEMPTY bits. */
571*6777b538SAndroid Build Coastguard Worker BrotliWriteBits(2, 3, storage_ix, storage);
572*6777b538SAndroid Build Coastguard Worker *storage_ix = (*storage_ix + 7u) & ~7u;
573*6777b538SAndroid Build Coastguard Worker return;
574*6777b538SAndroid Build Coastguard Worker }
575*6777b538SAndroid Build Coastguard Worker
576*6777b538SAndroid Build Coastguard Worker if (!ShouldCompress(data, mask, last_flush_pos, bytes,
577*6777b538SAndroid Build Coastguard Worker num_literals, num_commands)) {
578*6777b538SAndroid Build Coastguard Worker /* Restore the distance cache, as its last update by
579*6777b538SAndroid Build Coastguard Worker CreateBackwardReferences is now unused. */
580*6777b538SAndroid Build Coastguard Worker memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
581*6777b538SAndroid Build Coastguard Worker BrotliStoreUncompressedMetaBlock(is_last, data,
582*6777b538SAndroid Build Coastguard Worker wrapped_last_flush_pos, mask, bytes,
583*6777b538SAndroid Build Coastguard Worker storage_ix, storage);
584*6777b538SAndroid Build Coastguard Worker return;
585*6777b538SAndroid Build Coastguard Worker }
586*6777b538SAndroid Build Coastguard Worker
587*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(*storage_ix <= 14);
588*6777b538SAndroid Build Coastguard Worker last_bytes = (uint16_t)((storage[1] << 8) | storage[0]);
589*6777b538SAndroid Build Coastguard Worker last_bytes_bits = (uint8_t)(*storage_ix);
590*6777b538SAndroid Build Coastguard Worker if (params->quality <= MAX_QUALITY_FOR_STATIC_ENTROPY_CODES) {
591*6777b538SAndroid Build Coastguard Worker BrotliStoreMetaBlockFast(m, data, wrapped_last_flush_pos,
592*6777b538SAndroid Build Coastguard Worker bytes, mask, is_last, params,
593*6777b538SAndroid Build Coastguard Worker commands, num_commands,
594*6777b538SAndroid Build Coastguard Worker storage_ix, storage);
595*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
596*6777b538SAndroid Build Coastguard Worker } else if (params->quality < MIN_QUALITY_FOR_BLOCK_SPLIT) {
597*6777b538SAndroid Build Coastguard Worker BrotliStoreMetaBlockTrivial(m, data, wrapped_last_flush_pos,
598*6777b538SAndroid Build Coastguard Worker bytes, mask, is_last, params,
599*6777b538SAndroid Build Coastguard Worker commands, num_commands,
600*6777b538SAndroid Build Coastguard Worker storage_ix, storage);
601*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
602*6777b538SAndroid Build Coastguard Worker } else {
603*6777b538SAndroid Build Coastguard Worker MetaBlockSplit mb;
604*6777b538SAndroid Build Coastguard Worker InitMetaBlockSplit(&mb);
605*6777b538SAndroid Build Coastguard Worker if (params->quality < MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING) {
606*6777b538SAndroid Build Coastguard Worker size_t num_literal_contexts = 1;
607*6777b538SAndroid Build Coastguard Worker const uint32_t* literal_context_map = NULL;
608*6777b538SAndroid Build Coastguard Worker if (!params->disable_literal_context_modeling) {
609*6777b538SAndroid Build Coastguard Worker /* TODO(eustas): pull to higher level and reuse. */
610*6777b538SAndroid Build Coastguard Worker uint32_t* arena = BROTLI_ALLOC(m, uint32_t, 14 * 32);
611*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return;
612*6777b538SAndroid Build Coastguard Worker DecideOverLiteralContextModeling(
613*6777b538SAndroid Build Coastguard Worker data, wrapped_last_flush_pos, bytes, mask, params->quality,
614*6777b538SAndroid Build Coastguard Worker params->size_hint, &num_literal_contexts,
615*6777b538SAndroid Build Coastguard Worker &literal_context_map, arena);
616*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, arena);
617*6777b538SAndroid Build Coastguard Worker }
618*6777b538SAndroid Build Coastguard Worker BrotliBuildMetaBlockGreedy(m, data, wrapped_last_flush_pos, mask,
619*6777b538SAndroid Build Coastguard Worker prev_byte, prev_byte2, literal_context_lut, num_literal_contexts,
620*6777b538SAndroid Build Coastguard Worker literal_context_map, commands, num_commands, &mb);
621*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
622*6777b538SAndroid Build Coastguard Worker } else {
623*6777b538SAndroid Build Coastguard Worker BrotliBuildMetaBlock(m, data, wrapped_last_flush_pos, mask, &block_params,
624*6777b538SAndroid Build Coastguard Worker prev_byte, prev_byte2,
625*6777b538SAndroid Build Coastguard Worker commands, num_commands,
626*6777b538SAndroid Build Coastguard Worker literal_context_mode,
627*6777b538SAndroid Build Coastguard Worker &mb);
628*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
629*6777b538SAndroid Build Coastguard Worker }
630*6777b538SAndroid Build Coastguard Worker if (params->quality >= MIN_QUALITY_FOR_OPTIMIZE_HISTOGRAMS) {
631*6777b538SAndroid Build Coastguard Worker /* The number of distance symbols effectively used for distance
632*6777b538SAndroid Build Coastguard Worker histograms. It might be less than distance alphabet size
633*6777b538SAndroid Build Coastguard Worker for "Large Window Brotli" (32-bit). */
634*6777b538SAndroid Build Coastguard Worker BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
635*6777b538SAndroid Build Coastguard Worker }
636*6777b538SAndroid Build Coastguard Worker BrotliStoreMetaBlock(m, data, wrapped_last_flush_pos, bytes, mask,
637*6777b538SAndroid Build Coastguard Worker prev_byte, prev_byte2,
638*6777b538SAndroid Build Coastguard Worker is_last,
639*6777b538SAndroid Build Coastguard Worker &block_params,
640*6777b538SAndroid Build Coastguard Worker literal_context_mode,
641*6777b538SAndroid Build Coastguard Worker commands, num_commands,
642*6777b538SAndroid Build Coastguard Worker &mb,
643*6777b538SAndroid Build Coastguard Worker storage_ix, storage);
644*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
645*6777b538SAndroid Build Coastguard Worker DestroyMetaBlockSplit(m, &mb);
646*6777b538SAndroid Build Coastguard Worker }
647*6777b538SAndroid Build Coastguard Worker if (bytes + 4 < (*storage_ix >> 3)) {
648*6777b538SAndroid Build Coastguard Worker /* Restore the distance cache and last byte. */
649*6777b538SAndroid Build Coastguard Worker memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
650*6777b538SAndroid Build Coastguard Worker storage[0] = (uint8_t)last_bytes;
651*6777b538SAndroid Build Coastguard Worker storage[1] = (uint8_t)(last_bytes >> 8);
652*6777b538SAndroid Build Coastguard Worker *storage_ix = last_bytes_bits;
653*6777b538SAndroid Build Coastguard Worker BrotliStoreUncompressedMetaBlock(is_last, data,
654*6777b538SAndroid Build Coastguard Worker wrapped_last_flush_pos, mask,
655*6777b538SAndroid Build Coastguard Worker bytes, storage_ix, storage);
656*6777b538SAndroid Build Coastguard Worker }
657*6777b538SAndroid Build Coastguard Worker }
658*6777b538SAndroid Build Coastguard Worker
ChooseDistanceParams(BrotliEncoderParams * params)659*6777b538SAndroid Build Coastguard Worker static void ChooseDistanceParams(BrotliEncoderParams* params) {
660*6777b538SAndroid Build Coastguard Worker uint32_t distance_postfix_bits = 0;
661*6777b538SAndroid Build Coastguard Worker uint32_t num_direct_distance_codes = 0;
662*6777b538SAndroid Build Coastguard Worker
663*6777b538SAndroid Build Coastguard Worker if (params->quality >= MIN_QUALITY_FOR_NONZERO_DISTANCE_PARAMS) {
664*6777b538SAndroid Build Coastguard Worker uint32_t ndirect_msb;
665*6777b538SAndroid Build Coastguard Worker if (params->mode == BROTLI_MODE_FONT) {
666*6777b538SAndroid Build Coastguard Worker distance_postfix_bits = 1;
667*6777b538SAndroid Build Coastguard Worker num_direct_distance_codes = 12;
668*6777b538SAndroid Build Coastguard Worker } else {
669*6777b538SAndroid Build Coastguard Worker distance_postfix_bits = params->dist.distance_postfix_bits;
670*6777b538SAndroid Build Coastguard Worker num_direct_distance_codes = params->dist.num_direct_distance_codes;
671*6777b538SAndroid Build Coastguard Worker }
672*6777b538SAndroid Build Coastguard Worker ndirect_msb = (num_direct_distance_codes >> distance_postfix_bits) & 0x0F;
673*6777b538SAndroid Build Coastguard Worker if (distance_postfix_bits > BROTLI_MAX_NPOSTFIX ||
674*6777b538SAndroid Build Coastguard Worker num_direct_distance_codes > BROTLI_MAX_NDIRECT ||
675*6777b538SAndroid Build Coastguard Worker (ndirect_msb << distance_postfix_bits) != num_direct_distance_codes) {
676*6777b538SAndroid Build Coastguard Worker distance_postfix_bits = 0;
677*6777b538SAndroid Build Coastguard Worker num_direct_distance_codes = 0;
678*6777b538SAndroid Build Coastguard Worker }
679*6777b538SAndroid Build Coastguard Worker }
680*6777b538SAndroid Build Coastguard Worker
681*6777b538SAndroid Build Coastguard Worker BrotliInitDistanceParams(¶ms->dist, distance_postfix_bits,
682*6777b538SAndroid Build Coastguard Worker num_direct_distance_codes, params->large_window);
683*6777b538SAndroid Build Coastguard Worker }
684*6777b538SAndroid Build Coastguard Worker
EnsureInitialized(BrotliEncoderState * s)685*6777b538SAndroid Build Coastguard Worker static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
686*6777b538SAndroid Build Coastguard Worker MemoryManager* m = &s->memory_manager_;
687*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
688*6777b538SAndroid Build Coastguard Worker if (s->is_initialized_) return BROTLI_TRUE;
689*6777b538SAndroid Build Coastguard Worker
690*6777b538SAndroid Build Coastguard Worker s->last_bytes_bits_ = 0;
691*6777b538SAndroid Build Coastguard Worker s->last_bytes_ = 0;
692*6777b538SAndroid Build Coastguard Worker s->flint_ = BROTLI_FLINT_DONE;
693*6777b538SAndroid Build Coastguard Worker s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
694*6777b538SAndroid Build Coastguard Worker
695*6777b538SAndroid Build Coastguard Worker SanitizeParams(&s->params);
696*6777b538SAndroid Build Coastguard Worker s->params.lgblock = ComputeLgBlock(&s->params);
697*6777b538SAndroid Build Coastguard Worker ChooseDistanceParams(&s->params);
698*6777b538SAndroid Build Coastguard Worker
699*6777b538SAndroid Build Coastguard Worker if (s->params.stream_offset != 0) {
700*6777b538SAndroid Build Coastguard Worker s->flint_ = BROTLI_FLINT_NEEDS_2_BYTES;
701*6777b538SAndroid Build Coastguard Worker /* Poison the distance cache. -16 +- 3 is still less than zero (invalid). */
702*6777b538SAndroid Build Coastguard Worker s->dist_cache_[0] = -16;
703*6777b538SAndroid Build Coastguard Worker s->dist_cache_[1] = -16;
704*6777b538SAndroid Build Coastguard Worker s->dist_cache_[2] = -16;
705*6777b538SAndroid Build Coastguard Worker s->dist_cache_[3] = -16;
706*6777b538SAndroid Build Coastguard Worker memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
707*6777b538SAndroid Build Coastguard Worker }
708*6777b538SAndroid Build Coastguard Worker
709*6777b538SAndroid Build Coastguard Worker RingBufferSetup(&s->params, &s->ringbuffer_);
710*6777b538SAndroid Build Coastguard Worker
711*6777b538SAndroid Build Coastguard Worker /* Initialize last byte with stream header. */
712*6777b538SAndroid Build Coastguard Worker {
713*6777b538SAndroid Build Coastguard Worker int lgwin = s->params.lgwin;
714*6777b538SAndroid Build Coastguard Worker if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
715*6777b538SAndroid Build Coastguard Worker s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
716*6777b538SAndroid Build Coastguard Worker lgwin = BROTLI_MAX(int, lgwin, 18);
717*6777b538SAndroid Build Coastguard Worker }
718*6777b538SAndroid Build Coastguard Worker if (s->params.stream_offset == 0) {
719*6777b538SAndroid Build Coastguard Worker EncodeWindowBits(lgwin, s->params.large_window,
720*6777b538SAndroid Build Coastguard Worker &s->last_bytes_, &s->last_bytes_bits_);
721*6777b538SAndroid Build Coastguard Worker } else {
722*6777b538SAndroid Build Coastguard Worker /* Bigger values have the same effect, but could cause overflows. */
723*6777b538SAndroid Build Coastguard Worker s->params.stream_offset = BROTLI_MIN(size_t,
724*6777b538SAndroid Build Coastguard Worker s->params.stream_offset, BROTLI_MAX_BACKWARD_LIMIT(lgwin));
725*6777b538SAndroid Build Coastguard Worker }
726*6777b538SAndroid Build Coastguard Worker }
727*6777b538SAndroid Build Coastguard Worker
728*6777b538SAndroid Build Coastguard Worker if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
729*6777b538SAndroid Build Coastguard Worker s->one_pass_arena_ = BROTLI_ALLOC(m, BrotliOnePassArena, 1);
730*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
731*6777b538SAndroid Build Coastguard Worker InitCommandPrefixCodes(s->one_pass_arena_);
732*6777b538SAndroid Build Coastguard Worker } else if (s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
733*6777b538SAndroid Build Coastguard Worker s->two_pass_arena_ = BROTLI_ALLOC(m, BrotliTwoPassArena, 1);
734*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
735*6777b538SAndroid Build Coastguard Worker }
736*6777b538SAndroid Build Coastguard Worker
737*6777b538SAndroid Build Coastguard Worker s->is_initialized_ = BROTLI_TRUE;
738*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
739*6777b538SAndroid Build Coastguard Worker }
740*6777b538SAndroid Build Coastguard Worker
BrotliEncoderInitParams(BrotliEncoderParams * params)741*6777b538SAndroid Build Coastguard Worker static void BrotliEncoderInitParams(BrotliEncoderParams* params) {
742*6777b538SAndroid Build Coastguard Worker params->mode = BROTLI_DEFAULT_MODE;
743*6777b538SAndroid Build Coastguard Worker params->large_window = BROTLI_FALSE;
744*6777b538SAndroid Build Coastguard Worker params->quality = BROTLI_DEFAULT_QUALITY;
745*6777b538SAndroid Build Coastguard Worker params->lgwin = BROTLI_DEFAULT_WINDOW;
746*6777b538SAndroid Build Coastguard Worker params->lgblock = 0;
747*6777b538SAndroid Build Coastguard Worker params->stream_offset = 0;
748*6777b538SAndroid Build Coastguard Worker params->size_hint = 0;
749*6777b538SAndroid Build Coastguard Worker params->disable_literal_context_modeling = BROTLI_FALSE;
750*6777b538SAndroid Build Coastguard Worker BrotliInitSharedEncoderDictionary(¶ms->dictionary);
751*6777b538SAndroid Build Coastguard Worker params->dist.distance_postfix_bits = 0;
752*6777b538SAndroid Build Coastguard Worker params->dist.num_direct_distance_codes = 0;
753*6777b538SAndroid Build Coastguard Worker params->dist.alphabet_size_max =
754*6777b538SAndroid Build Coastguard Worker BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_MAX_DISTANCE_BITS);
755*6777b538SAndroid Build Coastguard Worker params->dist.alphabet_size_limit = params->dist.alphabet_size_max;
756*6777b538SAndroid Build Coastguard Worker params->dist.max_distance = BROTLI_MAX_DISTANCE;
757*6777b538SAndroid Build Coastguard Worker }
758*6777b538SAndroid Build Coastguard Worker
BrotliEncoderCleanupParams(MemoryManager * m,BrotliEncoderParams * params)759*6777b538SAndroid Build Coastguard Worker static void BrotliEncoderCleanupParams(MemoryManager* m,
760*6777b538SAndroid Build Coastguard Worker BrotliEncoderParams* params) {
761*6777b538SAndroid Build Coastguard Worker BrotliCleanupSharedEncoderDictionary(m, ¶ms->dictionary);
762*6777b538SAndroid Build Coastguard Worker }
763*6777b538SAndroid Build Coastguard Worker
BrotliEncoderInitState(BrotliEncoderState * s)764*6777b538SAndroid Build Coastguard Worker static void BrotliEncoderInitState(BrotliEncoderState* s) {
765*6777b538SAndroid Build Coastguard Worker BrotliEncoderInitParams(&s->params);
766*6777b538SAndroid Build Coastguard Worker s->input_pos_ = 0;
767*6777b538SAndroid Build Coastguard Worker s->num_commands_ = 0;
768*6777b538SAndroid Build Coastguard Worker s->num_literals_ = 0;
769*6777b538SAndroid Build Coastguard Worker s->last_insert_len_ = 0;
770*6777b538SAndroid Build Coastguard Worker s->last_flush_pos_ = 0;
771*6777b538SAndroid Build Coastguard Worker s->last_processed_pos_ = 0;
772*6777b538SAndroid Build Coastguard Worker s->prev_byte_ = 0;
773*6777b538SAndroid Build Coastguard Worker s->prev_byte2_ = 0;
774*6777b538SAndroid Build Coastguard Worker s->storage_size_ = 0;
775*6777b538SAndroid Build Coastguard Worker s->storage_ = 0;
776*6777b538SAndroid Build Coastguard Worker HasherInit(&s->hasher_);
777*6777b538SAndroid Build Coastguard Worker s->large_table_ = NULL;
778*6777b538SAndroid Build Coastguard Worker s->large_table_size_ = 0;
779*6777b538SAndroid Build Coastguard Worker s->one_pass_arena_ = NULL;
780*6777b538SAndroid Build Coastguard Worker s->two_pass_arena_ = NULL;
781*6777b538SAndroid Build Coastguard Worker s->command_buf_ = NULL;
782*6777b538SAndroid Build Coastguard Worker s->literal_buf_ = NULL;
783*6777b538SAndroid Build Coastguard Worker s->next_out_ = NULL;
784*6777b538SAndroid Build Coastguard Worker s->available_out_ = 0;
785*6777b538SAndroid Build Coastguard Worker s->total_out_ = 0;
786*6777b538SAndroid Build Coastguard Worker s->stream_state_ = BROTLI_STREAM_PROCESSING;
787*6777b538SAndroid Build Coastguard Worker s->is_last_block_emitted_ = BROTLI_FALSE;
788*6777b538SAndroid Build Coastguard Worker s->is_initialized_ = BROTLI_FALSE;
789*6777b538SAndroid Build Coastguard Worker
790*6777b538SAndroid Build Coastguard Worker RingBufferInit(&s->ringbuffer_);
791*6777b538SAndroid Build Coastguard Worker
792*6777b538SAndroid Build Coastguard Worker s->commands_ = 0;
793*6777b538SAndroid Build Coastguard Worker s->cmd_alloc_size_ = 0;
794*6777b538SAndroid Build Coastguard Worker
795*6777b538SAndroid Build Coastguard Worker /* Initialize distance cache. */
796*6777b538SAndroid Build Coastguard Worker s->dist_cache_[0] = 4;
797*6777b538SAndroid Build Coastguard Worker s->dist_cache_[1] = 11;
798*6777b538SAndroid Build Coastguard Worker s->dist_cache_[2] = 15;
799*6777b538SAndroid Build Coastguard Worker s->dist_cache_[3] = 16;
800*6777b538SAndroid Build Coastguard Worker /* Save the state of the distance cache in case we need to restore it for
801*6777b538SAndroid Build Coastguard Worker emitting an uncompressed block. */
802*6777b538SAndroid Build Coastguard Worker memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
803*6777b538SAndroid Build Coastguard Worker }
804*6777b538SAndroid Build Coastguard Worker
BrotliEncoderCreateInstance(brotli_alloc_func alloc_func,brotli_free_func free_func,void * opaque)805*6777b538SAndroid Build Coastguard Worker BrotliEncoderState* BrotliEncoderCreateInstance(
806*6777b538SAndroid Build Coastguard Worker brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
807*6777b538SAndroid Build Coastguard Worker BrotliEncoderState* state = (BrotliEncoderState*)BrotliBootstrapAlloc(
808*6777b538SAndroid Build Coastguard Worker sizeof(BrotliEncoderState), alloc_func, free_func, opaque);
809*6777b538SAndroid Build Coastguard Worker if (state == NULL) {
810*6777b538SAndroid Build Coastguard Worker /* BROTLI_DUMP(); */
811*6777b538SAndroid Build Coastguard Worker return 0;
812*6777b538SAndroid Build Coastguard Worker }
813*6777b538SAndroid Build Coastguard Worker BrotliInitMemoryManager(
814*6777b538SAndroid Build Coastguard Worker &state->memory_manager_, alloc_func, free_func, opaque);
815*6777b538SAndroid Build Coastguard Worker BrotliEncoderInitState(state);
816*6777b538SAndroid Build Coastguard Worker return state;
817*6777b538SAndroid Build Coastguard Worker }
818*6777b538SAndroid Build Coastguard Worker
BrotliEncoderCleanupState(BrotliEncoderState * s)819*6777b538SAndroid Build Coastguard Worker static void BrotliEncoderCleanupState(BrotliEncoderState* s) {
820*6777b538SAndroid Build Coastguard Worker MemoryManager* m = &s->memory_manager_;
821*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) {
822*6777b538SAndroid Build Coastguard Worker BrotliWipeOutMemoryManager(m);
823*6777b538SAndroid Build Coastguard Worker return;
824*6777b538SAndroid Build Coastguard Worker }
825*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, s->storage_);
826*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, s->commands_);
827*6777b538SAndroid Build Coastguard Worker RingBufferFree(m, &s->ringbuffer_);
828*6777b538SAndroid Build Coastguard Worker DestroyHasher(m, &s->hasher_);
829*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, s->large_table_);
830*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, s->one_pass_arena_);
831*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, s->two_pass_arena_);
832*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, s->command_buf_);
833*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, s->literal_buf_);
834*6777b538SAndroid Build Coastguard Worker BrotliEncoderCleanupParams(m, &s->params);
835*6777b538SAndroid Build Coastguard Worker }
836*6777b538SAndroid Build Coastguard Worker
837*6777b538SAndroid Build Coastguard Worker /* Deinitializes and frees BrotliEncoderState instance. */
BrotliEncoderDestroyInstance(BrotliEncoderState * state)838*6777b538SAndroid Build Coastguard Worker void BrotliEncoderDestroyInstance(BrotliEncoderState* state) {
839*6777b538SAndroid Build Coastguard Worker if (!state) {
840*6777b538SAndroid Build Coastguard Worker return;
841*6777b538SAndroid Build Coastguard Worker } else {
842*6777b538SAndroid Build Coastguard Worker BrotliEncoderCleanupState(state);
843*6777b538SAndroid Build Coastguard Worker BrotliBootstrapFree(state, &state->memory_manager_);
844*6777b538SAndroid Build Coastguard Worker }
845*6777b538SAndroid Build Coastguard Worker }
846*6777b538SAndroid Build Coastguard Worker
847*6777b538SAndroid Build Coastguard Worker /*
848*6777b538SAndroid Build Coastguard Worker Copies the given input data to the internal ring buffer of the compressor.
849*6777b538SAndroid Build Coastguard Worker No processing of the data occurs at this time and this function can be
850*6777b538SAndroid Build Coastguard Worker called multiple times before calling WriteBrotliData() to process the
851*6777b538SAndroid Build Coastguard Worker accumulated input. At most input_block_size() bytes of input data can be
852*6777b538SAndroid Build Coastguard Worker copied to the ring buffer, otherwise the next WriteBrotliData() will fail.
853*6777b538SAndroid Build Coastguard Worker */
CopyInputToRingBuffer(BrotliEncoderState * s,const size_t input_size,const uint8_t * input_buffer)854*6777b538SAndroid Build Coastguard Worker static void CopyInputToRingBuffer(BrotliEncoderState* s,
855*6777b538SAndroid Build Coastguard Worker const size_t input_size,
856*6777b538SAndroid Build Coastguard Worker const uint8_t* input_buffer) {
857*6777b538SAndroid Build Coastguard Worker RingBuffer* ringbuffer_ = &s->ringbuffer_;
858*6777b538SAndroid Build Coastguard Worker MemoryManager* m = &s->memory_manager_;
859*6777b538SAndroid Build Coastguard Worker RingBufferWrite(m, input_buffer, input_size, ringbuffer_);
860*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return;
861*6777b538SAndroid Build Coastguard Worker s->input_pos_ += input_size;
862*6777b538SAndroid Build Coastguard Worker
863*6777b538SAndroid Build Coastguard Worker /* TL;DR: If needed, initialize 7 more bytes in the ring buffer to make the
864*6777b538SAndroid Build Coastguard Worker hashing not depend on uninitialized data. This makes compression
865*6777b538SAndroid Build Coastguard Worker deterministic and it prevents uninitialized memory warnings in Valgrind.
866*6777b538SAndroid Build Coastguard Worker Even without erasing, the output would be valid (but nondeterministic).
867*6777b538SAndroid Build Coastguard Worker
868*6777b538SAndroid Build Coastguard Worker Background information: The compressor stores short (at most 8 bytes)
869*6777b538SAndroid Build Coastguard Worker substrings of the input already read in a hash table, and detects
870*6777b538SAndroid Build Coastguard Worker repetitions by looking up such substrings in the hash table. If it
871*6777b538SAndroid Build Coastguard Worker can find a substring, it checks whether the substring is really there
872*6777b538SAndroid Build Coastguard Worker in the ring buffer (or it's just a hash collision). Should the hash
873*6777b538SAndroid Build Coastguard Worker table become corrupt, this check makes sure that the output is
874*6777b538SAndroid Build Coastguard Worker still valid, albeit the compression ratio would be bad.
875*6777b538SAndroid Build Coastguard Worker
876*6777b538SAndroid Build Coastguard Worker The compressor populates the hash table from the ring buffer as it's
877*6777b538SAndroid Build Coastguard Worker reading new bytes from the input. However, at the last few indexes of
878*6777b538SAndroid Build Coastguard Worker the ring buffer, there are not enough bytes to build full-length
879*6777b538SAndroid Build Coastguard Worker substrings from. Since the hash table always contains full-length
880*6777b538SAndroid Build Coastguard Worker substrings, we erase with dummy zeros here to make sure that those
881*6777b538SAndroid Build Coastguard Worker substrings will contain zeros at the end instead of uninitialized
882*6777b538SAndroid Build Coastguard Worker data.
883*6777b538SAndroid Build Coastguard Worker
884*6777b538SAndroid Build Coastguard Worker Please note that erasing is not necessary (because the
885*6777b538SAndroid Build Coastguard Worker memory region is already initialized since he ring buffer
886*6777b538SAndroid Build Coastguard Worker has a `tail' that holds a copy of the beginning,) so we
887*6777b538SAndroid Build Coastguard Worker skip erasing if we have already gone around at least once in
888*6777b538SAndroid Build Coastguard Worker the ring buffer.
889*6777b538SAndroid Build Coastguard Worker
890*6777b538SAndroid Build Coastguard Worker Only clear during the first round of ring-buffer writes. On
891*6777b538SAndroid Build Coastguard Worker subsequent rounds data in the ring-buffer would be affected. */
892*6777b538SAndroid Build Coastguard Worker if (ringbuffer_->pos_ <= ringbuffer_->mask_) {
893*6777b538SAndroid Build Coastguard Worker /* This is the first time when the ring buffer is being written.
894*6777b538SAndroid Build Coastguard Worker We clear 7 bytes just after the bytes that have been copied from
895*6777b538SAndroid Build Coastguard Worker the input buffer.
896*6777b538SAndroid Build Coastguard Worker
897*6777b538SAndroid Build Coastguard Worker The ring-buffer has a "tail" that holds a copy of the beginning,
898*6777b538SAndroid Build Coastguard Worker but only once the ring buffer has been fully written once, i.e.,
899*6777b538SAndroid Build Coastguard Worker pos <= mask. For the first time, we need to write values
900*6777b538SAndroid Build Coastguard Worker in this tail (where index may be larger than mask), so that
901*6777b538SAndroid Build Coastguard Worker we have exactly defined behavior and don't read uninitialized
902*6777b538SAndroid Build Coastguard Worker memory. Due to performance reasons, hashing reads data using a
903*6777b538SAndroid Build Coastguard Worker LOAD64, which can go 7 bytes beyond the bytes written in the
904*6777b538SAndroid Build Coastguard Worker ring-buffer. */
905*6777b538SAndroid Build Coastguard Worker memset(ringbuffer_->buffer_ + ringbuffer_->pos_, 0, 7);
906*6777b538SAndroid Build Coastguard Worker }
907*6777b538SAndroid Build Coastguard Worker }
908*6777b538SAndroid Build Coastguard Worker
909*6777b538SAndroid Build Coastguard Worker /* Marks all input as processed.
910*6777b538SAndroid Build Coastguard Worker Returns true if position wrapping occurs. */
UpdateLastProcessedPos(BrotliEncoderState * s)911*6777b538SAndroid Build Coastguard Worker static BROTLI_BOOL UpdateLastProcessedPos(BrotliEncoderState* s) {
912*6777b538SAndroid Build Coastguard Worker uint32_t wrapped_last_processed_pos = WrapPosition(s->last_processed_pos_);
913*6777b538SAndroid Build Coastguard Worker uint32_t wrapped_input_pos = WrapPosition(s->input_pos_);
914*6777b538SAndroid Build Coastguard Worker s->last_processed_pos_ = s->input_pos_;
915*6777b538SAndroid Build Coastguard Worker return TO_BROTLI_BOOL(wrapped_input_pos < wrapped_last_processed_pos);
916*6777b538SAndroid Build Coastguard Worker }
917*6777b538SAndroid Build Coastguard Worker
ExtendLastCommand(BrotliEncoderState * s,uint32_t * bytes,uint32_t * wrapped_last_processed_pos)918*6777b538SAndroid Build Coastguard Worker static void ExtendLastCommand(BrotliEncoderState* s, uint32_t* bytes,
919*6777b538SAndroid Build Coastguard Worker uint32_t* wrapped_last_processed_pos) {
920*6777b538SAndroid Build Coastguard Worker Command* last_command = &s->commands_[s->num_commands_ - 1];
921*6777b538SAndroid Build Coastguard Worker const uint8_t* data = s->ringbuffer_.buffer_;
922*6777b538SAndroid Build Coastguard Worker const uint32_t mask = s->ringbuffer_.mask_;
923*6777b538SAndroid Build Coastguard Worker uint64_t max_backward_distance =
924*6777b538SAndroid Build Coastguard Worker (((uint64_t)1) << s->params.lgwin) - BROTLI_WINDOW_GAP;
925*6777b538SAndroid Build Coastguard Worker uint64_t last_copy_len = last_command->copy_len_ & 0x1FFFFFF;
926*6777b538SAndroid Build Coastguard Worker uint64_t last_processed_pos = s->last_processed_pos_ - last_copy_len;
927*6777b538SAndroid Build Coastguard Worker uint64_t max_distance = last_processed_pos < max_backward_distance ?
928*6777b538SAndroid Build Coastguard Worker last_processed_pos : max_backward_distance;
929*6777b538SAndroid Build Coastguard Worker uint64_t cmd_dist = (uint64_t)s->dist_cache_[0];
930*6777b538SAndroid Build Coastguard Worker uint32_t distance_code = CommandRestoreDistanceCode(last_command,
931*6777b538SAndroid Build Coastguard Worker &s->params.dist);
932*6777b538SAndroid Build Coastguard Worker const CompoundDictionary* dict = &s->params.dictionary.compound;
933*6777b538SAndroid Build Coastguard Worker size_t compound_dictionary_size = dict->total_size;
934*6777b538SAndroid Build Coastguard Worker if (distance_code < BROTLI_NUM_DISTANCE_SHORT_CODES ||
935*6777b538SAndroid Build Coastguard Worker distance_code - (BROTLI_NUM_DISTANCE_SHORT_CODES - 1) == cmd_dist) {
936*6777b538SAndroid Build Coastguard Worker if (cmd_dist <= max_distance) {
937*6777b538SAndroid Build Coastguard Worker while (*bytes != 0 && data[*wrapped_last_processed_pos & mask] ==
938*6777b538SAndroid Build Coastguard Worker data[(*wrapped_last_processed_pos - cmd_dist) & mask]) {
939*6777b538SAndroid Build Coastguard Worker last_command->copy_len_++;
940*6777b538SAndroid Build Coastguard Worker (*bytes)--;
941*6777b538SAndroid Build Coastguard Worker (*wrapped_last_processed_pos)++;
942*6777b538SAndroid Build Coastguard Worker }
943*6777b538SAndroid Build Coastguard Worker } else {
944*6777b538SAndroid Build Coastguard Worker if ((cmd_dist - max_distance - 1) < compound_dictionary_size &&
945*6777b538SAndroid Build Coastguard Worker last_copy_len < cmd_dist - max_distance) {
946*6777b538SAndroid Build Coastguard Worker size_t address =
947*6777b538SAndroid Build Coastguard Worker compound_dictionary_size - (size_t)(cmd_dist - max_distance) +
948*6777b538SAndroid Build Coastguard Worker (size_t)last_copy_len;
949*6777b538SAndroid Build Coastguard Worker size_t br_index = 0;
950*6777b538SAndroid Build Coastguard Worker size_t br_offset;
951*6777b538SAndroid Build Coastguard Worker const uint8_t* chunk;
952*6777b538SAndroid Build Coastguard Worker size_t chunk_length;
953*6777b538SAndroid Build Coastguard Worker while (address >= dict->chunk_offsets[br_index + 1]) br_index++;
954*6777b538SAndroid Build Coastguard Worker br_offset = address - dict->chunk_offsets[br_index];
955*6777b538SAndroid Build Coastguard Worker chunk = dict->chunk_source[br_index];
956*6777b538SAndroid Build Coastguard Worker chunk_length =
957*6777b538SAndroid Build Coastguard Worker dict->chunk_offsets[br_index + 1] - dict->chunk_offsets[br_index];
958*6777b538SAndroid Build Coastguard Worker while (*bytes != 0 && data[*wrapped_last_processed_pos & mask] ==
959*6777b538SAndroid Build Coastguard Worker chunk[br_offset]) {
960*6777b538SAndroid Build Coastguard Worker last_command->copy_len_++;
961*6777b538SAndroid Build Coastguard Worker (*bytes)--;
962*6777b538SAndroid Build Coastguard Worker (*wrapped_last_processed_pos)++;
963*6777b538SAndroid Build Coastguard Worker if (++br_offset == chunk_length) {
964*6777b538SAndroid Build Coastguard Worker br_index++;
965*6777b538SAndroid Build Coastguard Worker br_offset = 0;
966*6777b538SAndroid Build Coastguard Worker if (br_index != dict->num_chunks) {
967*6777b538SAndroid Build Coastguard Worker chunk = dict->chunk_source[br_index];
968*6777b538SAndroid Build Coastguard Worker chunk_length = dict->chunk_offsets[br_index + 1] -
969*6777b538SAndroid Build Coastguard Worker dict->chunk_offsets[br_index];
970*6777b538SAndroid Build Coastguard Worker } else {
971*6777b538SAndroid Build Coastguard Worker break;
972*6777b538SAndroid Build Coastguard Worker }
973*6777b538SAndroid Build Coastguard Worker }
974*6777b538SAndroid Build Coastguard Worker }
975*6777b538SAndroid Build Coastguard Worker }
976*6777b538SAndroid Build Coastguard Worker }
977*6777b538SAndroid Build Coastguard Worker /* The copy length is at most the metablock size, and thus expressible. */
978*6777b538SAndroid Build Coastguard Worker GetLengthCode(last_command->insert_len_,
979*6777b538SAndroid Build Coastguard Worker (size_t)((int)(last_command->copy_len_ & 0x1FFFFFF) +
980*6777b538SAndroid Build Coastguard Worker (int)(last_command->copy_len_ >> 25)),
981*6777b538SAndroid Build Coastguard Worker TO_BROTLI_BOOL((last_command->dist_prefix_ & 0x3FF) == 0),
982*6777b538SAndroid Build Coastguard Worker &last_command->cmd_prefix_);
983*6777b538SAndroid Build Coastguard Worker }
984*6777b538SAndroid Build Coastguard Worker }
985*6777b538SAndroid Build Coastguard Worker
986*6777b538SAndroid Build Coastguard Worker /*
987*6777b538SAndroid Build Coastguard Worker Processes the accumulated input data and sets |*out_size| to the length of
988*6777b538SAndroid Build Coastguard Worker the new output meta-block, or to zero if no new output meta-block has been
989*6777b538SAndroid Build Coastguard Worker created (in this case the processed input data is buffered internally).
990*6777b538SAndroid Build Coastguard Worker If |*out_size| is positive, |*output| points to the start of the output
991*6777b538SAndroid Build Coastguard Worker data. If |is_last| or |force_flush| is BROTLI_TRUE, an output meta-block is
992*6777b538SAndroid Build Coastguard Worker always created. However, until |is_last| is BROTLI_TRUE encoder may retain up
993*6777b538SAndroid Build Coastguard Worker to 7 bits of the last byte of output. To force encoder to dump the remaining
994*6777b538SAndroid Build Coastguard Worker bits use WriteMetadata() to append an empty meta-data block.
995*6777b538SAndroid Build Coastguard Worker Returns BROTLI_FALSE if the size of the input data is larger than
996*6777b538SAndroid Build Coastguard Worker input_block_size().
997*6777b538SAndroid Build Coastguard Worker */
EncodeData(BrotliEncoderState * s,const BROTLI_BOOL is_last,const BROTLI_BOOL force_flush,size_t * out_size,uint8_t ** output)998*6777b538SAndroid Build Coastguard Worker static BROTLI_BOOL EncodeData(
999*6777b538SAndroid Build Coastguard Worker BrotliEncoderState* s, const BROTLI_BOOL is_last,
1000*6777b538SAndroid Build Coastguard Worker const BROTLI_BOOL force_flush, size_t* out_size, uint8_t** output) {
1001*6777b538SAndroid Build Coastguard Worker const uint64_t delta = UnprocessedInputSize(s);
1002*6777b538SAndroid Build Coastguard Worker uint32_t bytes = (uint32_t)delta;
1003*6777b538SAndroid Build Coastguard Worker uint32_t wrapped_last_processed_pos = WrapPosition(s->last_processed_pos_);
1004*6777b538SAndroid Build Coastguard Worker uint8_t* data;
1005*6777b538SAndroid Build Coastguard Worker uint32_t mask;
1006*6777b538SAndroid Build Coastguard Worker MemoryManager* m = &s->memory_manager_;
1007*6777b538SAndroid Build Coastguard Worker ContextType literal_context_mode;
1008*6777b538SAndroid Build Coastguard Worker ContextLut literal_context_lut;
1009*6777b538SAndroid Build Coastguard Worker
1010*6777b538SAndroid Build Coastguard Worker data = s->ringbuffer_.buffer_;
1011*6777b538SAndroid Build Coastguard Worker mask = s->ringbuffer_.mask_;
1012*6777b538SAndroid Build Coastguard Worker
1013*6777b538SAndroid Build Coastguard Worker if (s->params.quality > s->params.dictionary.max_quality) return BROTLI_FALSE;
1014*6777b538SAndroid Build Coastguard Worker /* Adding more blocks after "last" block is forbidden. */
1015*6777b538SAndroid Build Coastguard Worker if (s->is_last_block_emitted_) return BROTLI_FALSE;
1016*6777b538SAndroid Build Coastguard Worker if (is_last) s->is_last_block_emitted_ = BROTLI_TRUE;
1017*6777b538SAndroid Build Coastguard Worker
1018*6777b538SAndroid Build Coastguard Worker if (delta > InputBlockSize(s)) {
1019*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1020*6777b538SAndroid Build Coastguard Worker }
1021*6777b538SAndroid Build Coastguard Worker if (s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY &&
1022*6777b538SAndroid Build Coastguard Worker !s->command_buf_) {
1023*6777b538SAndroid Build Coastguard Worker s->command_buf_ =
1024*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
1025*6777b538SAndroid Build Coastguard Worker s->literal_buf_ =
1026*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
1027*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
1028*6777b538SAndroid Build Coastguard Worker BROTLI_IS_NULL(s->literal_buf_)) {
1029*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1030*6777b538SAndroid Build Coastguard Worker }
1031*6777b538SAndroid Build Coastguard Worker }
1032*6777b538SAndroid Build Coastguard Worker
1033*6777b538SAndroid Build Coastguard Worker if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
1034*6777b538SAndroid Build Coastguard Worker s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
1035*6777b538SAndroid Build Coastguard Worker uint8_t* storage;
1036*6777b538SAndroid Build Coastguard Worker size_t storage_ix = s->last_bytes_bits_;
1037*6777b538SAndroid Build Coastguard Worker size_t table_size;
1038*6777b538SAndroid Build Coastguard Worker int* table;
1039*6777b538SAndroid Build Coastguard Worker
1040*6777b538SAndroid Build Coastguard Worker if (delta == 0 && !is_last) {
1041*6777b538SAndroid Build Coastguard Worker /* We have no new input data and we don't have to finish the stream, so
1042*6777b538SAndroid Build Coastguard Worker nothing to do. */
1043*6777b538SAndroid Build Coastguard Worker *out_size = 0;
1044*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1045*6777b538SAndroid Build Coastguard Worker }
1046*6777b538SAndroid Build Coastguard Worker storage = GetBrotliStorage(s, 2 * bytes + 503);
1047*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1048*6777b538SAndroid Build Coastguard Worker storage[0] = (uint8_t)s->last_bytes_;
1049*6777b538SAndroid Build Coastguard Worker storage[1] = (uint8_t)(s->last_bytes_ >> 8);
1050*6777b538SAndroid Build Coastguard Worker table = GetHashTable(s, s->params.quality, bytes, &table_size);
1051*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1052*6777b538SAndroid Build Coastguard Worker if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
1053*6777b538SAndroid Build Coastguard Worker BrotliCompressFragmentFast(
1054*6777b538SAndroid Build Coastguard Worker s->one_pass_arena_, &data[wrapped_last_processed_pos & mask],
1055*6777b538SAndroid Build Coastguard Worker bytes, is_last,
1056*6777b538SAndroid Build Coastguard Worker table, table_size,
1057*6777b538SAndroid Build Coastguard Worker &storage_ix, storage);
1058*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1059*6777b538SAndroid Build Coastguard Worker } else {
1060*6777b538SAndroid Build Coastguard Worker BrotliCompressFragmentTwoPass(
1061*6777b538SAndroid Build Coastguard Worker s->two_pass_arena_, &data[wrapped_last_processed_pos & mask],
1062*6777b538SAndroid Build Coastguard Worker bytes, is_last,
1063*6777b538SAndroid Build Coastguard Worker s->command_buf_, s->literal_buf_,
1064*6777b538SAndroid Build Coastguard Worker table, table_size,
1065*6777b538SAndroid Build Coastguard Worker &storage_ix, storage);
1066*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1067*6777b538SAndroid Build Coastguard Worker }
1068*6777b538SAndroid Build Coastguard Worker s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]);
1069*6777b538SAndroid Build Coastguard Worker s->last_bytes_bits_ = storage_ix & 7u;
1070*6777b538SAndroid Build Coastguard Worker UpdateLastProcessedPos(s);
1071*6777b538SAndroid Build Coastguard Worker *output = &storage[0];
1072*6777b538SAndroid Build Coastguard Worker *out_size = storage_ix >> 3;
1073*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1074*6777b538SAndroid Build Coastguard Worker }
1075*6777b538SAndroid Build Coastguard Worker
1076*6777b538SAndroid Build Coastguard Worker {
1077*6777b538SAndroid Build Coastguard Worker /* Theoretical max number of commands is 1 per 2 bytes. */
1078*6777b538SAndroid Build Coastguard Worker size_t newsize = s->num_commands_ + bytes / 2 + 1;
1079*6777b538SAndroid Build Coastguard Worker if (newsize > s->cmd_alloc_size_) {
1080*6777b538SAndroid Build Coastguard Worker Command* new_commands;
1081*6777b538SAndroid Build Coastguard Worker /* Reserve a bit more memory to allow merging with a next block
1082*6777b538SAndroid Build Coastguard Worker without reallocation: that would impact speed. */
1083*6777b538SAndroid Build Coastguard Worker newsize += (bytes / 4) + 16;
1084*6777b538SAndroid Build Coastguard Worker s->cmd_alloc_size_ = newsize;
1085*6777b538SAndroid Build Coastguard Worker new_commands = BROTLI_ALLOC(m, Command, newsize);
1086*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) return BROTLI_FALSE;
1087*6777b538SAndroid Build Coastguard Worker if (s->commands_) {
1088*6777b538SAndroid Build Coastguard Worker memcpy(new_commands, s->commands_, sizeof(Command) * s->num_commands_);
1089*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, s->commands_);
1090*6777b538SAndroid Build Coastguard Worker }
1091*6777b538SAndroid Build Coastguard Worker s->commands_ = new_commands;
1092*6777b538SAndroid Build Coastguard Worker }
1093*6777b538SAndroid Build Coastguard Worker }
1094*6777b538SAndroid Build Coastguard Worker
1095*6777b538SAndroid Build Coastguard Worker InitOrStitchToPreviousBlock(m, &s->hasher_, data, mask, &s->params,
1096*6777b538SAndroid Build Coastguard Worker wrapped_last_processed_pos, bytes, is_last);
1097*6777b538SAndroid Build Coastguard Worker
1098*6777b538SAndroid Build Coastguard Worker literal_context_mode = ChooseContextMode(
1099*6777b538SAndroid Build Coastguard Worker &s->params, data, WrapPosition(s->last_flush_pos_),
1100*6777b538SAndroid Build Coastguard Worker mask, (size_t)(s->input_pos_ - s->last_flush_pos_));
1101*6777b538SAndroid Build Coastguard Worker literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
1102*6777b538SAndroid Build Coastguard Worker
1103*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1104*6777b538SAndroid Build Coastguard Worker
1105*6777b538SAndroid Build Coastguard Worker if (s->num_commands_ && s->last_insert_len_ == 0) {
1106*6777b538SAndroid Build Coastguard Worker ExtendLastCommand(s, &bytes, &wrapped_last_processed_pos);
1107*6777b538SAndroid Build Coastguard Worker }
1108*6777b538SAndroid Build Coastguard Worker
1109*6777b538SAndroid Build Coastguard Worker if (s->params.quality == ZOPFLIFICATION_QUALITY) {
1110*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(s->params.hasher.type == 10);
1111*6777b538SAndroid Build Coastguard Worker BrotliCreateZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
1112*6777b538SAndroid Build Coastguard Worker data, mask, literal_context_lut, &s->params,
1113*6777b538SAndroid Build Coastguard Worker &s->hasher_, s->dist_cache_,
1114*6777b538SAndroid Build Coastguard Worker &s->last_insert_len_, &s->commands_[s->num_commands_],
1115*6777b538SAndroid Build Coastguard Worker &s->num_commands_, &s->num_literals_);
1116*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1117*6777b538SAndroid Build Coastguard Worker } else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) {
1118*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(s->params.hasher.type == 10);
1119*6777b538SAndroid Build Coastguard Worker BrotliCreateHqZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
1120*6777b538SAndroid Build Coastguard Worker data, mask, literal_context_lut, &s->params,
1121*6777b538SAndroid Build Coastguard Worker &s->hasher_, s->dist_cache_,
1122*6777b538SAndroid Build Coastguard Worker &s->last_insert_len_, &s->commands_[s->num_commands_],
1123*6777b538SAndroid Build Coastguard Worker &s->num_commands_, &s->num_literals_);
1124*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1125*6777b538SAndroid Build Coastguard Worker } else {
1126*6777b538SAndroid Build Coastguard Worker BrotliCreateBackwardReferences(bytes, wrapped_last_processed_pos,
1127*6777b538SAndroid Build Coastguard Worker data, mask, literal_context_lut, &s->params,
1128*6777b538SAndroid Build Coastguard Worker &s->hasher_, s->dist_cache_,
1129*6777b538SAndroid Build Coastguard Worker &s->last_insert_len_, &s->commands_[s->num_commands_],
1130*6777b538SAndroid Build Coastguard Worker &s->num_commands_, &s->num_literals_);
1131*6777b538SAndroid Build Coastguard Worker }
1132*6777b538SAndroid Build Coastguard Worker
1133*6777b538SAndroid Build Coastguard Worker {
1134*6777b538SAndroid Build Coastguard Worker const size_t max_length = MaxMetablockSize(&s->params);
1135*6777b538SAndroid Build Coastguard Worker const size_t max_literals = max_length / 8;
1136*6777b538SAndroid Build Coastguard Worker const size_t max_commands = max_length / 8;
1137*6777b538SAndroid Build Coastguard Worker const size_t processed_bytes = (size_t)(s->input_pos_ - s->last_flush_pos_);
1138*6777b538SAndroid Build Coastguard Worker /* If maximal possible additional block doesn't fit metablock, flush now. */
1139*6777b538SAndroid Build Coastguard Worker /* TODO(eustas): Postpone decision until next block arrives? */
1140*6777b538SAndroid Build Coastguard Worker const BROTLI_BOOL next_input_fits_metablock = TO_BROTLI_BOOL(
1141*6777b538SAndroid Build Coastguard Worker processed_bytes + InputBlockSize(s) <= max_length);
1142*6777b538SAndroid Build Coastguard Worker /* If block splitting is not used, then flush as soon as there is some
1143*6777b538SAndroid Build Coastguard Worker amount of commands / literals produced. */
1144*6777b538SAndroid Build Coastguard Worker const BROTLI_BOOL should_flush = TO_BROTLI_BOOL(
1145*6777b538SAndroid Build Coastguard Worker s->params.quality < MIN_QUALITY_FOR_BLOCK_SPLIT &&
1146*6777b538SAndroid Build Coastguard Worker s->num_literals_ + s->num_commands_ >= MAX_NUM_DELAYED_SYMBOLS);
1147*6777b538SAndroid Build Coastguard Worker if (!is_last && !force_flush && !should_flush &&
1148*6777b538SAndroid Build Coastguard Worker next_input_fits_metablock &&
1149*6777b538SAndroid Build Coastguard Worker s->num_literals_ < max_literals &&
1150*6777b538SAndroid Build Coastguard Worker s->num_commands_ < max_commands) {
1151*6777b538SAndroid Build Coastguard Worker /* Merge with next input block. Everything will happen later. */
1152*6777b538SAndroid Build Coastguard Worker if (UpdateLastProcessedPos(s)) {
1153*6777b538SAndroid Build Coastguard Worker HasherReset(&s->hasher_);
1154*6777b538SAndroid Build Coastguard Worker }
1155*6777b538SAndroid Build Coastguard Worker *out_size = 0;
1156*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1157*6777b538SAndroid Build Coastguard Worker }
1158*6777b538SAndroid Build Coastguard Worker }
1159*6777b538SAndroid Build Coastguard Worker
1160*6777b538SAndroid Build Coastguard Worker /* Create the last insert-only command. */
1161*6777b538SAndroid Build Coastguard Worker if (s->last_insert_len_ > 0) {
1162*6777b538SAndroid Build Coastguard Worker InitInsertCommand(&s->commands_[s->num_commands_++], s->last_insert_len_);
1163*6777b538SAndroid Build Coastguard Worker s->num_literals_ += s->last_insert_len_;
1164*6777b538SAndroid Build Coastguard Worker s->last_insert_len_ = 0;
1165*6777b538SAndroid Build Coastguard Worker }
1166*6777b538SAndroid Build Coastguard Worker
1167*6777b538SAndroid Build Coastguard Worker if (!is_last && s->input_pos_ == s->last_flush_pos_) {
1168*6777b538SAndroid Build Coastguard Worker /* We have no new input data and we don't have to finish the stream, so
1169*6777b538SAndroid Build Coastguard Worker nothing to do. */
1170*6777b538SAndroid Build Coastguard Worker *out_size = 0;
1171*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1172*6777b538SAndroid Build Coastguard Worker }
1173*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(s->input_pos_ >= s->last_flush_pos_);
1174*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(s->input_pos_ > s->last_flush_pos_ || is_last);
1175*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(s->input_pos_ - s->last_flush_pos_ <= 1u << 24);
1176*6777b538SAndroid Build Coastguard Worker {
1177*6777b538SAndroid Build Coastguard Worker const uint32_t metablock_size =
1178*6777b538SAndroid Build Coastguard Worker (uint32_t)(s->input_pos_ - s->last_flush_pos_);
1179*6777b538SAndroid Build Coastguard Worker uint8_t* storage = GetBrotliStorage(s, 2 * metablock_size + 503);
1180*6777b538SAndroid Build Coastguard Worker size_t storage_ix = s->last_bytes_bits_;
1181*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1182*6777b538SAndroid Build Coastguard Worker storage[0] = (uint8_t)s->last_bytes_;
1183*6777b538SAndroid Build Coastguard Worker storage[1] = (uint8_t)(s->last_bytes_ >> 8);
1184*6777b538SAndroid Build Coastguard Worker WriteMetaBlockInternal(
1185*6777b538SAndroid Build Coastguard Worker m, data, mask, s->last_flush_pos_, metablock_size, is_last,
1186*6777b538SAndroid Build Coastguard Worker literal_context_mode, &s->params, s->prev_byte_, s->prev_byte2_,
1187*6777b538SAndroid Build Coastguard Worker s->num_literals_, s->num_commands_, s->commands_, s->saved_dist_cache_,
1188*6777b538SAndroid Build Coastguard Worker s->dist_cache_, &storage_ix, storage);
1189*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1190*6777b538SAndroid Build Coastguard Worker s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]);
1191*6777b538SAndroid Build Coastguard Worker s->last_bytes_bits_ = storage_ix & 7u;
1192*6777b538SAndroid Build Coastguard Worker s->last_flush_pos_ = s->input_pos_;
1193*6777b538SAndroid Build Coastguard Worker if (UpdateLastProcessedPos(s)) {
1194*6777b538SAndroid Build Coastguard Worker HasherReset(&s->hasher_);
1195*6777b538SAndroid Build Coastguard Worker }
1196*6777b538SAndroid Build Coastguard Worker if (s->last_flush_pos_ > 0) {
1197*6777b538SAndroid Build Coastguard Worker s->prev_byte_ = data[((uint32_t)s->last_flush_pos_ - 1) & mask];
1198*6777b538SAndroid Build Coastguard Worker }
1199*6777b538SAndroid Build Coastguard Worker if (s->last_flush_pos_ > 1) {
1200*6777b538SAndroid Build Coastguard Worker s->prev_byte2_ = data[(uint32_t)(s->last_flush_pos_ - 2) & mask];
1201*6777b538SAndroid Build Coastguard Worker }
1202*6777b538SAndroid Build Coastguard Worker s->num_commands_ = 0;
1203*6777b538SAndroid Build Coastguard Worker s->num_literals_ = 0;
1204*6777b538SAndroid Build Coastguard Worker /* Save the state of the distance cache in case we need to restore it for
1205*6777b538SAndroid Build Coastguard Worker emitting an uncompressed block. */
1206*6777b538SAndroid Build Coastguard Worker memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
1207*6777b538SAndroid Build Coastguard Worker *output = &storage[0];
1208*6777b538SAndroid Build Coastguard Worker *out_size = storage_ix >> 3;
1209*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1210*6777b538SAndroid Build Coastguard Worker }
1211*6777b538SAndroid Build Coastguard Worker }
1212*6777b538SAndroid Build Coastguard Worker
1213*6777b538SAndroid Build Coastguard Worker /* Dumps remaining output bits and metadata header to |header|.
1214*6777b538SAndroid Build Coastguard Worker Returns number of produced bytes.
1215*6777b538SAndroid Build Coastguard Worker REQUIRED: |header| should be 8-byte aligned and at least 16 bytes long.
1216*6777b538SAndroid Build Coastguard Worker REQUIRED: |block_size| <= (1 << 24). */
WriteMetadataHeader(BrotliEncoderState * s,const size_t block_size,uint8_t * header)1217*6777b538SAndroid Build Coastguard Worker static size_t WriteMetadataHeader(
1218*6777b538SAndroid Build Coastguard Worker BrotliEncoderState* s, const size_t block_size, uint8_t* header) {
1219*6777b538SAndroid Build Coastguard Worker size_t storage_ix;
1220*6777b538SAndroid Build Coastguard Worker storage_ix = s->last_bytes_bits_;
1221*6777b538SAndroid Build Coastguard Worker header[0] = (uint8_t)s->last_bytes_;
1222*6777b538SAndroid Build Coastguard Worker header[1] = (uint8_t)(s->last_bytes_ >> 8);
1223*6777b538SAndroid Build Coastguard Worker s->last_bytes_ = 0;
1224*6777b538SAndroid Build Coastguard Worker s->last_bytes_bits_ = 0;
1225*6777b538SAndroid Build Coastguard Worker
1226*6777b538SAndroid Build Coastguard Worker BrotliWriteBits(1, 0, &storage_ix, header);
1227*6777b538SAndroid Build Coastguard Worker BrotliWriteBits(2, 3, &storage_ix, header);
1228*6777b538SAndroid Build Coastguard Worker BrotliWriteBits(1, 0, &storage_ix, header);
1229*6777b538SAndroid Build Coastguard Worker if (block_size == 0) {
1230*6777b538SAndroid Build Coastguard Worker BrotliWriteBits(2, 0, &storage_ix, header);
1231*6777b538SAndroid Build Coastguard Worker } else {
1232*6777b538SAndroid Build Coastguard Worker uint32_t nbits = (block_size == 1) ? 0 :
1233*6777b538SAndroid Build Coastguard Worker (Log2FloorNonZero((uint32_t)block_size - 1) + 1);
1234*6777b538SAndroid Build Coastguard Worker uint32_t nbytes = (nbits + 7) / 8;
1235*6777b538SAndroid Build Coastguard Worker BrotliWriteBits(2, nbytes, &storage_ix, header);
1236*6777b538SAndroid Build Coastguard Worker BrotliWriteBits(8 * nbytes, block_size - 1, &storage_ix, header);
1237*6777b538SAndroid Build Coastguard Worker }
1238*6777b538SAndroid Build Coastguard Worker return (storage_ix + 7u) >> 3;
1239*6777b538SAndroid Build Coastguard Worker }
1240*6777b538SAndroid Build Coastguard Worker
BrotliCompressBufferQuality10(int lgwin,size_t input_size,const uint8_t * input_buffer,size_t * encoded_size,uint8_t * encoded_buffer)1241*6777b538SAndroid Build Coastguard Worker static BROTLI_NOINLINE BROTLI_BOOL BrotliCompressBufferQuality10(
1242*6777b538SAndroid Build Coastguard Worker int lgwin, size_t input_size, const uint8_t* input_buffer,
1243*6777b538SAndroid Build Coastguard Worker size_t* encoded_size, uint8_t* encoded_buffer) {
1244*6777b538SAndroid Build Coastguard Worker MemoryManager* m =
1245*6777b538SAndroid Build Coastguard Worker (MemoryManager*)BrotliBootstrapAlloc(sizeof(MemoryManager), 0, 0, 0);
1246*6777b538SAndroid Build Coastguard Worker
1247*6777b538SAndroid Build Coastguard Worker const size_t mask = BROTLI_SIZE_MAX >> 1;
1248*6777b538SAndroid Build Coastguard Worker int dist_cache[4] = { 4, 11, 15, 16 };
1249*6777b538SAndroid Build Coastguard Worker int saved_dist_cache[4] = { 4, 11, 15, 16 };
1250*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL ok = BROTLI_TRUE;
1251*6777b538SAndroid Build Coastguard Worker const size_t max_out_size = *encoded_size;
1252*6777b538SAndroid Build Coastguard Worker size_t total_out_size = 0;
1253*6777b538SAndroid Build Coastguard Worker uint16_t last_bytes;
1254*6777b538SAndroid Build Coastguard Worker uint8_t last_bytes_bits;
1255*6777b538SAndroid Build Coastguard Worker
1256*6777b538SAndroid Build Coastguard Worker const size_t hasher_eff_size = BROTLI_MIN(size_t,
1257*6777b538SAndroid Build Coastguard Worker input_size, BROTLI_MAX_BACKWARD_LIMIT(lgwin) + BROTLI_WINDOW_GAP);
1258*6777b538SAndroid Build Coastguard Worker
1259*6777b538SAndroid Build Coastguard Worker const int lgmetablock = BROTLI_MIN(int, 24, lgwin + 1);
1260*6777b538SAndroid Build Coastguard Worker size_t max_block_size;
1261*6777b538SAndroid Build Coastguard Worker const size_t max_metablock_size = (size_t)1 << lgmetablock;
1262*6777b538SAndroid Build Coastguard Worker const size_t max_literals_per_metablock = max_metablock_size / 8;
1263*6777b538SAndroid Build Coastguard Worker const size_t max_commands_per_metablock = max_metablock_size / 8;
1264*6777b538SAndroid Build Coastguard Worker size_t metablock_start = 0;
1265*6777b538SAndroid Build Coastguard Worker uint8_t prev_byte = 0;
1266*6777b538SAndroid Build Coastguard Worker uint8_t prev_byte2 = 0;
1267*6777b538SAndroid Build Coastguard Worker
1268*6777b538SAndroid Build Coastguard Worker BrotliEncoderParams* params = NULL;
1269*6777b538SAndroid Build Coastguard Worker Hasher* hasher = NULL;
1270*6777b538SAndroid Build Coastguard Worker
1271*6777b538SAndroid Build Coastguard Worker if (m == NULL) return BROTLI_FALSE;
1272*6777b538SAndroid Build Coastguard Worker BrotliInitMemoryManager(m, 0, 0, 0);
1273*6777b538SAndroid Build Coastguard Worker params = BROTLI_ALLOC(m, BrotliEncoderParams, 2);
1274*6777b538SAndroid Build Coastguard Worker hasher = BROTLI_ALLOC(m, Hasher, 1);
1275*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(params) || BROTLI_IS_NULL(hasher)) {
1276*6777b538SAndroid Build Coastguard Worker goto oom;
1277*6777b538SAndroid Build Coastguard Worker }
1278*6777b538SAndroid Build Coastguard Worker BrotliEncoderInitParams(params);
1279*6777b538SAndroid Build Coastguard Worker HasherInit(hasher);
1280*6777b538SAndroid Build Coastguard Worker
1281*6777b538SAndroid Build Coastguard Worker params->quality = 10;
1282*6777b538SAndroid Build Coastguard Worker params->lgwin = lgwin;
1283*6777b538SAndroid Build Coastguard Worker if (lgwin > BROTLI_MAX_WINDOW_BITS) {
1284*6777b538SAndroid Build Coastguard Worker params->large_window = BROTLI_TRUE;
1285*6777b538SAndroid Build Coastguard Worker }
1286*6777b538SAndroid Build Coastguard Worker SanitizeParams(params);
1287*6777b538SAndroid Build Coastguard Worker params->lgblock = ComputeLgBlock(params);
1288*6777b538SAndroid Build Coastguard Worker ChooseDistanceParams(params);
1289*6777b538SAndroid Build Coastguard Worker max_block_size = (size_t)1 << params->lgblock;
1290*6777b538SAndroid Build Coastguard Worker
1291*6777b538SAndroid Build Coastguard Worker /* Since default static dictionary is used we assume that
1292*6777b538SAndroid Build Coastguard Worker * params->quality < params->dictionary.max_quality. */
1293*6777b538SAndroid Build Coastguard Worker
1294*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(input_size <= mask + 1);
1295*6777b538SAndroid Build Coastguard Worker EncodeWindowBits(lgwin, params->large_window, &last_bytes, &last_bytes_bits);
1296*6777b538SAndroid Build Coastguard Worker InitOrStitchToPreviousBlock(m, hasher, input_buffer, mask, params,
1297*6777b538SAndroid Build Coastguard Worker 0, hasher_eff_size, BROTLI_TRUE);
1298*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) goto oom;
1299*6777b538SAndroid Build Coastguard Worker
1300*6777b538SAndroid Build Coastguard Worker while (ok && metablock_start < input_size) {
1301*6777b538SAndroid Build Coastguard Worker const size_t metablock_end =
1302*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, input_size, metablock_start + max_metablock_size);
1303*6777b538SAndroid Build Coastguard Worker const size_t expected_num_commands =
1304*6777b538SAndroid Build Coastguard Worker (metablock_end - metablock_start) / 12 + 16;
1305*6777b538SAndroid Build Coastguard Worker Command* commands = 0;
1306*6777b538SAndroid Build Coastguard Worker size_t num_commands = 0;
1307*6777b538SAndroid Build Coastguard Worker size_t last_insert_len = 0;
1308*6777b538SAndroid Build Coastguard Worker size_t num_literals = 0;
1309*6777b538SAndroid Build Coastguard Worker size_t metablock_size = 0;
1310*6777b538SAndroid Build Coastguard Worker size_t cmd_alloc_size = 0;
1311*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL is_last;
1312*6777b538SAndroid Build Coastguard Worker uint8_t* storage;
1313*6777b538SAndroid Build Coastguard Worker size_t storage_ix;
1314*6777b538SAndroid Build Coastguard Worker
1315*6777b538SAndroid Build Coastguard Worker ContextType literal_context_mode = ChooseContextMode(params,
1316*6777b538SAndroid Build Coastguard Worker input_buffer, metablock_start, mask, metablock_end - metablock_start);
1317*6777b538SAndroid Build Coastguard Worker ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
1318*6777b538SAndroid Build Coastguard Worker
1319*6777b538SAndroid Build Coastguard Worker size_t block_start;
1320*6777b538SAndroid Build Coastguard Worker for (block_start = metablock_start; block_start < metablock_end; ) {
1321*6777b538SAndroid Build Coastguard Worker size_t block_size =
1322*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, metablock_end - block_start, max_block_size);
1323*6777b538SAndroid Build Coastguard Worker ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, block_size + 1);
1324*6777b538SAndroid Build Coastguard Worker size_t path_size;
1325*6777b538SAndroid Build Coastguard Worker size_t new_cmd_alloc_size;
1326*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) goto oom;
1327*6777b538SAndroid Build Coastguard Worker BrotliInitZopfliNodes(nodes, block_size + 1);
1328*6777b538SAndroid Build Coastguard Worker StitchToPreviousBlockH10(&hasher->privat._H10, block_size, block_start,
1329*6777b538SAndroid Build Coastguard Worker input_buffer, mask);
1330*6777b538SAndroid Build Coastguard Worker path_size = BrotliZopfliComputeShortestPath(m, block_size, block_start,
1331*6777b538SAndroid Build Coastguard Worker input_buffer, mask, literal_context_lut, params, dist_cache, hasher,
1332*6777b538SAndroid Build Coastguard Worker nodes);
1333*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) goto oom;
1334*6777b538SAndroid Build Coastguard Worker /* We allocate a command buffer in the first iteration of this loop that
1335*6777b538SAndroid Build Coastguard Worker will be likely big enough for the whole metablock, so that for most
1336*6777b538SAndroid Build Coastguard Worker inputs we will not have to reallocate in later iterations. We do the
1337*6777b538SAndroid Build Coastguard Worker allocation here and not before the loop, because if the input is small,
1338*6777b538SAndroid Build Coastguard Worker this will be allocated after the Zopfli cost model is freed, so this
1339*6777b538SAndroid Build Coastguard Worker will not increase peak memory usage.
1340*6777b538SAndroid Build Coastguard Worker TODO(eustas): If the first allocation is too small, increase command
1341*6777b538SAndroid Build Coastguard Worker buffer size exponentially. */
1342*6777b538SAndroid Build Coastguard Worker new_cmd_alloc_size = BROTLI_MAX(size_t, expected_num_commands,
1343*6777b538SAndroid Build Coastguard Worker num_commands + path_size + 1);
1344*6777b538SAndroid Build Coastguard Worker if (cmd_alloc_size != new_cmd_alloc_size) {
1345*6777b538SAndroid Build Coastguard Worker Command* new_commands = BROTLI_ALLOC(m, Command, new_cmd_alloc_size);
1346*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) goto oom;
1347*6777b538SAndroid Build Coastguard Worker cmd_alloc_size = new_cmd_alloc_size;
1348*6777b538SAndroid Build Coastguard Worker if (commands) {
1349*6777b538SAndroid Build Coastguard Worker memcpy(new_commands, commands, sizeof(Command) * num_commands);
1350*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, commands);
1351*6777b538SAndroid Build Coastguard Worker }
1352*6777b538SAndroid Build Coastguard Worker commands = new_commands;
1353*6777b538SAndroid Build Coastguard Worker }
1354*6777b538SAndroid Build Coastguard Worker BrotliZopfliCreateCommands(block_size, block_start, &nodes[0], dist_cache,
1355*6777b538SAndroid Build Coastguard Worker &last_insert_len, params, &commands[num_commands], &num_literals);
1356*6777b538SAndroid Build Coastguard Worker num_commands += path_size;
1357*6777b538SAndroid Build Coastguard Worker block_start += block_size;
1358*6777b538SAndroid Build Coastguard Worker metablock_size += block_size;
1359*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, nodes);
1360*6777b538SAndroid Build Coastguard Worker if (num_literals > max_literals_per_metablock ||
1361*6777b538SAndroid Build Coastguard Worker num_commands > max_commands_per_metablock) {
1362*6777b538SAndroid Build Coastguard Worker break;
1363*6777b538SAndroid Build Coastguard Worker }
1364*6777b538SAndroid Build Coastguard Worker }
1365*6777b538SAndroid Build Coastguard Worker
1366*6777b538SAndroid Build Coastguard Worker if (last_insert_len > 0) {
1367*6777b538SAndroid Build Coastguard Worker InitInsertCommand(&commands[num_commands++], last_insert_len);
1368*6777b538SAndroid Build Coastguard Worker num_literals += last_insert_len;
1369*6777b538SAndroid Build Coastguard Worker }
1370*6777b538SAndroid Build Coastguard Worker
1371*6777b538SAndroid Build Coastguard Worker is_last = TO_BROTLI_BOOL(metablock_start + metablock_size == input_size);
1372*6777b538SAndroid Build Coastguard Worker storage = NULL;
1373*6777b538SAndroid Build Coastguard Worker storage_ix = last_bytes_bits;
1374*6777b538SAndroid Build Coastguard Worker
1375*6777b538SAndroid Build Coastguard Worker if (metablock_size == 0) {
1376*6777b538SAndroid Build Coastguard Worker /* Write the ISLAST and ISEMPTY bits. */
1377*6777b538SAndroid Build Coastguard Worker storage = BROTLI_ALLOC(m, uint8_t, 16);
1378*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
1379*6777b538SAndroid Build Coastguard Worker storage[0] = (uint8_t)last_bytes;
1380*6777b538SAndroid Build Coastguard Worker storage[1] = (uint8_t)(last_bytes >> 8);
1381*6777b538SAndroid Build Coastguard Worker BrotliWriteBits(2, 3, &storage_ix, storage);
1382*6777b538SAndroid Build Coastguard Worker storage_ix = (storage_ix + 7u) & ~7u;
1383*6777b538SAndroid Build Coastguard Worker } else if (!ShouldCompress(input_buffer, mask, metablock_start,
1384*6777b538SAndroid Build Coastguard Worker metablock_size, num_literals, num_commands)) {
1385*6777b538SAndroid Build Coastguard Worker /* Restore the distance cache, as its last update by
1386*6777b538SAndroid Build Coastguard Worker CreateBackwardReferences is now unused. */
1387*6777b538SAndroid Build Coastguard Worker memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
1388*6777b538SAndroid Build Coastguard Worker storage = BROTLI_ALLOC(m, uint8_t, metablock_size + 16);
1389*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
1390*6777b538SAndroid Build Coastguard Worker storage[0] = (uint8_t)last_bytes;
1391*6777b538SAndroid Build Coastguard Worker storage[1] = (uint8_t)(last_bytes >> 8);
1392*6777b538SAndroid Build Coastguard Worker BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
1393*6777b538SAndroid Build Coastguard Worker metablock_start, mask, metablock_size,
1394*6777b538SAndroid Build Coastguard Worker &storage_ix, storage);
1395*6777b538SAndroid Build Coastguard Worker } else {
1396*6777b538SAndroid Build Coastguard Worker MetaBlockSplit mb;
1397*6777b538SAndroid Build Coastguard Worker BrotliEncoderParams* block_params = params + 1;
1398*6777b538SAndroid Build Coastguard Worker *block_params = *params; /* shallow copy */
1399*6777b538SAndroid Build Coastguard Worker InitMetaBlockSplit(&mb);
1400*6777b538SAndroid Build Coastguard Worker BrotliBuildMetaBlock(m, input_buffer, metablock_start, mask,
1401*6777b538SAndroid Build Coastguard Worker block_params,
1402*6777b538SAndroid Build Coastguard Worker prev_byte, prev_byte2,
1403*6777b538SAndroid Build Coastguard Worker commands, num_commands,
1404*6777b538SAndroid Build Coastguard Worker literal_context_mode,
1405*6777b538SAndroid Build Coastguard Worker &mb);
1406*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) goto oom;
1407*6777b538SAndroid Build Coastguard Worker {
1408*6777b538SAndroid Build Coastguard Worker /* The number of distance symbols effectively used for distance
1409*6777b538SAndroid Build Coastguard Worker histograms. It might be less than distance alphabet size
1410*6777b538SAndroid Build Coastguard Worker for "Large Window Brotli" (32-bit). */
1411*6777b538SAndroid Build Coastguard Worker BrotliOptimizeHistograms(block_params->dist.alphabet_size_limit, &mb);
1412*6777b538SAndroid Build Coastguard Worker }
1413*6777b538SAndroid Build Coastguard Worker storage = BROTLI_ALLOC(m, uint8_t, 2 * metablock_size + 503);
1414*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
1415*6777b538SAndroid Build Coastguard Worker storage[0] = (uint8_t)last_bytes;
1416*6777b538SAndroid Build Coastguard Worker storage[1] = (uint8_t)(last_bytes >> 8);
1417*6777b538SAndroid Build Coastguard Worker BrotliStoreMetaBlock(m, input_buffer, metablock_start, metablock_size,
1418*6777b538SAndroid Build Coastguard Worker mask, prev_byte, prev_byte2,
1419*6777b538SAndroid Build Coastguard Worker is_last,
1420*6777b538SAndroid Build Coastguard Worker block_params,
1421*6777b538SAndroid Build Coastguard Worker literal_context_mode,
1422*6777b538SAndroid Build Coastguard Worker commands, num_commands,
1423*6777b538SAndroid Build Coastguard Worker &mb,
1424*6777b538SAndroid Build Coastguard Worker &storage_ix, storage);
1425*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) goto oom;
1426*6777b538SAndroid Build Coastguard Worker if (metablock_size + 4 < (storage_ix >> 3)) {
1427*6777b538SAndroid Build Coastguard Worker /* Restore the distance cache and last byte. */
1428*6777b538SAndroid Build Coastguard Worker memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
1429*6777b538SAndroid Build Coastguard Worker storage[0] = (uint8_t)last_bytes;
1430*6777b538SAndroid Build Coastguard Worker storage[1] = (uint8_t)(last_bytes >> 8);
1431*6777b538SAndroid Build Coastguard Worker storage_ix = last_bytes_bits;
1432*6777b538SAndroid Build Coastguard Worker BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
1433*6777b538SAndroid Build Coastguard Worker metablock_start, mask,
1434*6777b538SAndroid Build Coastguard Worker metablock_size, &storage_ix, storage);
1435*6777b538SAndroid Build Coastguard Worker }
1436*6777b538SAndroid Build Coastguard Worker DestroyMetaBlockSplit(m, &mb);
1437*6777b538SAndroid Build Coastguard Worker }
1438*6777b538SAndroid Build Coastguard Worker last_bytes = (uint16_t)(storage[storage_ix >> 3]);
1439*6777b538SAndroid Build Coastguard Worker last_bytes_bits = storage_ix & 7u;
1440*6777b538SAndroid Build Coastguard Worker metablock_start += metablock_size;
1441*6777b538SAndroid Build Coastguard Worker if (metablock_start < input_size) {
1442*6777b538SAndroid Build Coastguard Worker prev_byte = input_buffer[metablock_start - 1];
1443*6777b538SAndroid Build Coastguard Worker prev_byte2 = input_buffer[metablock_start - 2];
1444*6777b538SAndroid Build Coastguard Worker }
1445*6777b538SAndroid Build Coastguard Worker /* Save the state of the distance cache in case we need to restore it for
1446*6777b538SAndroid Build Coastguard Worker emitting an uncompressed block. */
1447*6777b538SAndroid Build Coastguard Worker memcpy(saved_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
1448*6777b538SAndroid Build Coastguard Worker
1449*6777b538SAndroid Build Coastguard Worker {
1450*6777b538SAndroid Build Coastguard Worker const size_t out_size = storage_ix >> 3;
1451*6777b538SAndroid Build Coastguard Worker total_out_size += out_size;
1452*6777b538SAndroid Build Coastguard Worker if (total_out_size <= max_out_size) {
1453*6777b538SAndroid Build Coastguard Worker memcpy(encoded_buffer, storage, out_size);
1454*6777b538SAndroid Build Coastguard Worker encoded_buffer += out_size;
1455*6777b538SAndroid Build Coastguard Worker } else {
1456*6777b538SAndroid Build Coastguard Worker ok = BROTLI_FALSE;
1457*6777b538SAndroid Build Coastguard Worker }
1458*6777b538SAndroid Build Coastguard Worker }
1459*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, storage);
1460*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, commands);
1461*6777b538SAndroid Build Coastguard Worker }
1462*6777b538SAndroid Build Coastguard Worker
1463*6777b538SAndroid Build Coastguard Worker *encoded_size = total_out_size;
1464*6777b538SAndroid Build Coastguard Worker DestroyHasher(m, hasher);
1465*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, hasher);
1466*6777b538SAndroid Build Coastguard Worker BrotliEncoderCleanupParams(m, params);
1467*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, params);
1468*6777b538SAndroid Build Coastguard Worker BrotliBootstrapFree(m, m);
1469*6777b538SAndroid Build Coastguard Worker return ok;
1470*6777b538SAndroid Build Coastguard Worker
1471*6777b538SAndroid Build Coastguard Worker oom:
1472*6777b538SAndroid Build Coastguard Worker BrotliWipeOutMemoryManager(m);
1473*6777b538SAndroid Build Coastguard Worker BrotliBootstrapFree(m, m);
1474*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1475*6777b538SAndroid Build Coastguard Worker }
1476*6777b538SAndroid Build Coastguard Worker
BrotliEncoderMaxCompressedSize(size_t input_size)1477*6777b538SAndroid Build Coastguard Worker size_t BrotliEncoderMaxCompressedSize(size_t input_size) {
1478*6777b538SAndroid Build Coastguard Worker /* [window bits / empty metadata] + N * [uncompressed] + [last empty] */
1479*6777b538SAndroid Build Coastguard Worker size_t num_large_blocks = input_size >> 14;
1480*6777b538SAndroid Build Coastguard Worker size_t overhead = 2 + (4 * num_large_blocks) + 3 + 1;
1481*6777b538SAndroid Build Coastguard Worker size_t result = input_size + overhead;
1482*6777b538SAndroid Build Coastguard Worker if (input_size == 0) return 2;
1483*6777b538SAndroid Build Coastguard Worker return (result < input_size) ? 0 : result;
1484*6777b538SAndroid Build Coastguard Worker }
1485*6777b538SAndroid Build Coastguard Worker
1486*6777b538SAndroid Build Coastguard Worker /* Wraps data to uncompressed brotli stream with minimal window size.
1487*6777b538SAndroid Build Coastguard Worker |output| should point at region with at least BrotliEncoderMaxCompressedSize
1488*6777b538SAndroid Build Coastguard Worker addressable bytes.
1489*6777b538SAndroid Build Coastguard Worker Returns the length of stream. */
MakeUncompressedStream(const uint8_t * input,size_t input_size,uint8_t * output)1490*6777b538SAndroid Build Coastguard Worker static size_t MakeUncompressedStream(
1491*6777b538SAndroid Build Coastguard Worker const uint8_t* input, size_t input_size, uint8_t* output) {
1492*6777b538SAndroid Build Coastguard Worker size_t size = input_size;
1493*6777b538SAndroid Build Coastguard Worker size_t result = 0;
1494*6777b538SAndroid Build Coastguard Worker size_t offset = 0;
1495*6777b538SAndroid Build Coastguard Worker if (input_size == 0) {
1496*6777b538SAndroid Build Coastguard Worker output[0] = 6;
1497*6777b538SAndroid Build Coastguard Worker return 1;
1498*6777b538SAndroid Build Coastguard Worker }
1499*6777b538SAndroid Build Coastguard Worker output[result++] = 0x21; /* window bits = 10, is_last = false */
1500*6777b538SAndroid Build Coastguard Worker output[result++] = 0x03; /* empty metadata, padding */
1501*6777b538SAndroid Build Coastguard Worker while (size > 0) {
1502*6777b538SAndroid Build Coastguard Worker uint32_t nibbles = 0;
1503*6777b538SAndroid Build Coastguard Worker uint32_t chunk_size;
1504*6777b538SAndroid Build Coastguard Worker uint32_t bits;
1505*6777b538SAndroid Build Coastguard Worker chunk_size = (size > (1u << 24)) ? (1u << 24) : (uint32_t)size;
1506*6777b538SAndroid Build Coastguard Worker if (chunk_size > (1u << 16)) nibbles = (chunk_size > (1u << 20)) ? 2 : 1;
1507*6777b538SAndroid Build Coastguard Worker bits =
1508*6777b538SAndroid Build Coastguard Worker (nibbles << 1) | ((chunk_size - 1) << 3) | (1u << (19 + 4 * nibbles));
1509*6777b538SAndroid Build Coastguard Worker output[result++] = (uint8_t)bits;
1510*6777b538SAndroid Build Coastguard Worker output[result++] = (uint8_t)(bits >> 8);
1511*6777b538SAndroid Build Coastguard Worker output[result++] = (uint8_t)(bits >> 16);
1512*6777b538SAndroid Build Coastguard Worker if (nibbles == 2) output[result++] = (uint8_t)(bits >> 24);
1513*6777b538SAndroid Build Coastguard Worker memcpy(&output[result], &input[offset], chunk_size);
1514*6777b538SAndroid Build Coastguard Worker result += chunk_size;
1515*6777b538SAndroid Build Coastguard Worker offset += chunk_size;
1516*6777b538SAndroid Build Coastguard Worker size -= chunk_size;
1517*6777b538SAndroid Build Coastguard Worker }
1518*6777b538SAndroid Build Coastguard Worker output[result++] = 3;
1519*6777b538SAndroid Build Coastguard Worker return result;
1520*6777b538SAndroid Build Coastguard Worker }
1521*6777b538SAndroid Build Coastguard Worker
BrotliEncoderCompress(int quality,int lgwin,BrotliEncoderMode mode,size_t input_size,const uint8_t input_buffer[BROTLI_ARRAY_PARAM (input_size)],size_t * encoded_size,uint8_t encoded_buffer[BROTLI_ARRAY_PARAM (* encoded_size)])1522*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL BrotliEncoderCompress(
1523*6777b538SAndroid Build Coastguard Worker int quality, int lgwin, BrotliEncoderMode mode, size_t input_size,
1524*6777b538SAndroid Build Coastguard Worker const uint8_t input_buffer[BROTLI_ARRAY_PARAM(input_size)],
1525*6777b538SAndroid Build Coastguard Worker size_t* encoded_size,
1526*6777b538SAndroid Build Coastguard Worker uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(*encoded_size)]) {
1527*6777b538SAndroid Build Coastguard Worker BrotliEncoderState* s;
1528*6777b538SAndroid Build Coastguard Worker size_t out_size = *encoded_size;
1529*6777b538SAndroid Build Coastguard Worker const uint8_t* input_start = input_buffer;
1530*6777b538SAndroid Build Coastguard Worker uint8_t* output_start = encoded_buffer;
1531*6777b538SAndroid Build Coastguard Worker size_t max_out_size = BrotliEncoderMaxCompressedSize(input_size);
1532*6777b538SAndroid Build Coastguard Worker if (out_size == 0) {
1533*6777b538SAndroid Build Coastguard Worker /* Output buffer needs at least one byte. */
1534*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1535*6777b538SAndroid Build Coastguard Worker }
1536*6777b538SAndroid Build Coastguard Worker if (input_size == 0) {
1537*6777b538SAndroid Build Coastguard Worker /* Handle the special case of empty input. */
1538*6777b538SAndroid Build Coastguard Worker *encoded_size = 1;
1539*6777b538SAndroid Build Coastguard Worker *encoded_buffer = 6;
1540*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1541*6777b538SAndroid Build Coastguard Worker }
1542*6777b538SAndroid Build Coastguard Worker if (quality == 10) {
1543*6777b538SAndroid Build Coastguard Worker /* TODO(eustas): Implement this direct path for all quality levels. */
1544*6777b538SAndroid Build Coastguard Worker const int lg_win = BROTLI_MIN(int, BROTLI_LARGE_MAX_WINDOW_BITS,
1545*6777b538SAndroid Build Coastguard Worker BROTLI_MAX(int, 16, lgwin));
1546*6777b538SAndroid Build Coastguard Worker int ok = BrotliCompressBufferQuality10(lg_win, input_size, input_buffer,
1547*6777b538SAndroid Build Coastguard Worker encoded_size, encoded_buffer);
1548*6777b538SAndroid Build Coastguard Worker if (!ok || (max_out_size && *encoded_size > max_out_size)) {
1549*6777b538SAndroid Build Coastguard Worker goto fallback;
1550*6777b538SAndroid Build Coastguard Worker }
1551*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1552*6777b538SAndroid Build Coastguard Worker }
1553*6777b538SAndroid Build Coastguard Worker
1554*6777b538SAndroid Build Coastguard Worker s = BrotliEncoderCreateInstance(0, 0, 0);
1555*6777b538SAndroid Build Coastguard Worker if (!s) {
1556*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1557*6777b538SAndroid Build Coastguard Worker } else {
1558*6777b538SAndroid Build Coastguard Worker size_t available_in = input_size;
1559*6777b538SAndroid Build Coastguard Worker const uint8_t* next_in = input_buffer;
1560*6777b538SAndroid Build Coastguard Worker size_t available_out = *encoded_size;
1561*6777b538SAndroid Build Coastguard Worker uint8_t* next_out = encoded_buffer;
1562*6777b538SAndroid Build Coastguard Worker size_t total_out = 0;
1563*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL result = BROTLI_FALSE;
1564*6777b538SAndroid Build Coastguard Worker BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, (uint32_t)quality);
1565*6777b538SAndroid Build Coastguard Worker BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, (uint32_t)lgwin);
1566*6777b538SAndroid Build Coastguard Worker BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, (uint32_t)mode);
1567*6777b538SAndroid Build Coastguard Worker BrotliEncoderSetParameter(s, BROTLI_PARAM_SIZE_HINT, (uint32_t)input_size);
1568*6777b538SAndroid Build Coastguard Worker if (lgwin > BROTLI_MAX_WINDOW_BITS) {
1569*6777b538SAndroid Build Coastguard Worker BrotliEncoderSetParameter(s, BROTLI_PARAM_LARGE_WINDOW, BROTLI_TRUE);
1570*6777b538SAndroid Build Coastguard Worker }
1571*6777b538SAndroid Build Coastguard Worker result = BrotliEncoderCompressStream(s, BROTLI_OPERATION_FINISH,
1572*6777b538SAndroid Build Coastguard Worker &available_in, &next_in, &available_out, &next_out, &total_out);
1573*6777b538SAndroid Build Coastguard Worker if (!BrotliEncoderIsFinished(s)) result = 0;
1574*6777b538SAndroid Build Coastguard Worker *encoded_size = total_out;
1575*6777b538SAndroid Build Coastguard Worker BrotliEncoderDestroyInstance(s);
1576*6777b538SAndroid Build Coastguard Worker if (!result || (max_out_size && *encoded_size > max_out_size)) {
1577*6777b538SAndroid Build Coastguard Worker goto fallback;
1578*6777b538SAndroid Build Coastguard Worker }
1579*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1580*6777b538SAndroid Build Coastguard Worker }
1581*6777b538SAndroid Build Coastguard Worker fallback:
1582*6777b538SAndroid Build Coastguard Worker *encoded_size = 0;
1583*6777b538SAndroid Build Coastguard Worker if (!max_out_size) return BROTLI_FALSE;
1584*6777b538SAndroid Build Coastguard Worker if (out_size >= max_out_size) {
1585*6777b538SAndroid Build Coastguard Worker *encoded_size =
1586*6777b538SAndroid Build Coastguard Worker MakeUncompressedStream(input_start, input_size, output_start);
1587*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1588*6777b538SAndroid Build Coastguard Worker }
1589*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1590*6777b538SAndroid Build Coastguard Worker }
1591*6777b538SAndroid Build Coastguard Worker
InjectBytePaddingBlock(BrotliEncoderState * s)1592*6777b538SAndroid Build Coastguard Worker static void InjectBytePaddingBlock(BrotliEncoderState* s) {
1593*6777b538SAndroid Build Coastguard Worker uint32_t seal = s->last_bytes_;
1594*6777b538SAndroid Build Coastguard Worker size_t seal_bits = s->last_bytes_bits_;
1595*6777b538SAndroid Build Coastguard Worker uint8_t* destination;
1596*6777b538SAndroid Build Coastguard Worker s->last_bytes_ = 0;
1597*6777b538SAndroid Build Coastguard Worker s->last_bytes_bits_ = 0;
1598*6777b538SAndroid Build Coastguard Worker /* is_last = 0, data_nibbles = 11, reserved = 0, meta_nibbles = 00 */
1599*6777b538SAndroid Build Coastguard Worker seal |= 0x6u << seal_bits;
1600*6777b538SAndroid Build Coastguard Worker seal_bits += 6;
1601*6777b538SAndroid Build Coastguard Worker /* If we have already created storage, then append to it.
1602*6777b538SAndroid Build Coastguard Worker Storage is valid until next block is being compressed. */
1603*6777b538SAndroid Build Coastguard Worker if (s->next_out_) {
1604*6777b538SAndroid Build Coastguard Worker destination = s->next_out_ + s->available_out_;
1605*6777b538SAndroid Build Coastguard Worker } else {
1606*6777b538SAndroid Build Coastguard Worker destination = s->tiny_buf_.u8;
1607*6777b538SAndroid Build Coastguard Worker s->next_out_ = destination;
1608*6777b538SAndroid Build Coastguard Worker }
1609*6777b538SAndroid Build Coastguard Worker destination[0] = (uint8_t)seal;
1610*6777b538SAndroid Build Coastguard Worker if (seal_bits > 8) destination[1] = (uint8_t)(seal >> 8);
1611*6777b538SAndroid Build Coastguard Worker if (seal_bits > 16) destination[2] = (uint8_t)(seal >> 16);
1612*6777b538SAndroid Build Coastguard Worker s->available_out_ += (seal_bits + 7) >> 3;
1613*6777b538SAndroid Build Coastguard Worker }
1614*6777b538SAndroid Build Coastguard Worker
1615*6777b538SAndroid Build Coastguard Worker /* Injects padding bits or pushes compressed data to output.
1616*6777b538SAndroid Build Coastguard Worker Returns false if nothing is done. */
InjectFlushOrPushOutput(BrotliEncoderState * s,size_t * available_out,uint8_t ** next_out,size_t * total_out)1617*6777b538SAndroid Build Coastguard Worker static BROTLI_BOOL InjectFlushOrPushOutput(BrotliEncoderState* s,
1618*6777b538SAndroid Build Coastguard Worker size_t* available_out, uint8_t** next_out, size_t* total_out) {
1619*6777b538SAndroid Build Coastguard Worker if (s->stream_state_ == BROTLI_STREAM_FLUSH_REQUESTED &&
1620*6777b538SAndroid Build Coastguard Worker s->last_bytes_bits_ != 0) {
1621*6777b538SAndroid Build Coastguard Worker InjectBytePaddingBlock(s);
1622*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1623*6777b538SAndroid Build Coastguard Worker }
1624*6777b538SAndroid Build Coastguard Worker
1625*6777b538SAndroid Build Coastguard Worker if (s->available_out_ != 0 && *available_out != 0) {
1626*6777b538SAndroid Build Coastguard Worker size_t copy_output_size =
1627*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, s->available_out_, *available_out);
1628*6777b538SAndroid Build Coastguard Worker memcpy(*next_out, s->next_out_, copy_output_size);
1629*6777b538SAndroid Build Coastguard Worker *next_out += copy_output_size;
1630*6777b538SAndroid Build Coastguard Worker *available_out -= copy_output_size;
1631*6777b538SAndroid Build Coastguard Worker s->next_out_ += copy_output_size;
1632*6777b538SAndroid Build Coastguard Worker s->available_out_ -= copy_output_size;
1633*6777b538SAndroid Build Coastguard Worker s->total_out_ += copy_output_size;
1634*6777b538SAndroid Build Coastguard Worker if (total_out) *total_out = s->total_out_;
1635*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1636*6777b538SAndroid Build Coastguard Worker }
1637*6777b538SAndroid Build Coastguard Worker
1638*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1639*6777b538SAndroid Build Coastguard Worker }
1640*6777b538SAndroid Build Coastguard Worker
CheckFlushComplete(BrotliEncoderState * s)1641*6777b538SAndroid Build Coastguard Worker static void CheckFlushComplete(BrotliEncoderState* s) {
1642*6777b538SAndroid Build Coastguard Worker if (s->stream_state_ == BROTLI_STREAM_FLUSH_REQUESTED &&
1643*6777b538SAndroid Build Coastguard Worker s->available_out_ == 0) {
1644*6777b538SAndroid Build Coastguard Worker s->stream_state_ = BROTLI_STREAM_PROCESSING;
1645*6777b538SAndroid Build Coastguard Worker s->next_out_ = 0;
1646*6777b538SAndroid Build Coastguard Worker }
1647*6777b538SAndroid Build Coastguard Worker }
1648*6777b538SAndroid Build Coastguard Worker
BrotliEncoderCompressStreamFast(BrotliEncoderState * s,BrotliEncoderOperation op,size_t * available_in,const uint8_t ** next_in,size_t * available_out,uint8_t ** next_out,size_t * total_out)1649*6777b538SAndroid Build Coastguard Worker static BROTLI_BOOL BrotliEncoderCompressStreamFast(
1650*6777b538SAndroid Build Coastguard Worker BrotliEncoderState* s, BrotliEncoderOperation op, size_t* available_in,
1651*6777b538SAndroid Build Coastguard Worker const uint8_t** next_in, size_t* available_out, uint8_t** next_out,
1652*6777b538SAndroid Build Coastguard Worker size_t* total_out) {
1653*6777b538SAndroid Build Coastguard Worker const size_t block_size_limit = (size_t)1 << s->params.lgwin;
1654*6777b538SAndroid Build Coastguard Worker const size_t buf_size = BROTLI_MIN(size_t, kCompressFragmentTwoPassBlockSize,
1655*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, *available_in, block_size_limit));
1656*6777b538SAndroid Build Coastguard Worker uint32_t* tmp_command_buf = NULL;
1657*6777b538SAndroid Build Coastguard Worker uint32_t* command_buf = NULL;
1658*6777b538SAndroid Build Coastguard Worker uint8_t* tmp_literal_buf = NULL;
1659*6777b538SAndroid Build Coastguard Worker uint8_t* literal_buf = NULL;
1660*6777b538SAndroid Build Coastguard Worker MemoryManager* m = &s->memory_manager_;
1661*6777b538SAndroid Build Coastguard Worker if (s->params.quality != FAST_ONE_PASS_COMPRESSION_QUALITY &&
1662*6777b538SAndroid Build Coastguard Worker s->params.quality != FAST_TWO_PASS_COMPRESSION_QUALITY) {
1663*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1664*6777b538SAndroid Build Coastguard Worker }
1665*6777b538SAndroid Build Coastguard Worker if (s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
1666*6777b538SAndroid Build Coastguard Worker if (!s->command_buf_ && buf_size == kCompressFragmentTwoPassBlockSize) {
1667*6777b538SAndroid Build Coastguard Worker s->command_buf_ =
1668*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
1669*6777b538SAndroid Build Coastguard Worker s->literal_buf_ =
1670*6777b538SAndroid Build Coastguard Worker BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
1671*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
1672*6777b538SAndroid Build Coastguard Worker BROTLI_IS_NULL(s->literal_buf_)) {
1673*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1674*6777b538SAndroid Build Coastguard Worker }
1675*6777b538SAndroid Build Coastguard Worker }
1676*6777b538SAndroid Build Coastguard Worker if (s->command_buf_) {
1677*6777b538SAndroid Build Coastguard Worker command_buf = s->command_buf_;
1678*6777b538SAndroid Build Coastguard Worker literal_buf = s->literal_buf_;
1679*6777b538SAndroid Build Coastguard Worker } else {
1680*6777b538SAndroid Build Coastguard Worker tmp_command_buf = BROTLI_ALLOC(m, uint32_t, buf_size);
1681*6777b538SAndroid Build Coastguard Worker tmp_literal_buf = BROTLI_ALLOC(m, uint8_t, buf_size);
1682*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp_command_buf) ||
1683*6777b538SAndroid Build Coastguard Worker BROTLI_IS_NULL(tmp_literal_buf)) {
1684*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1685*6777b538SAndroid Build Coastguard Worker }
1686*6777b538SAndroid Build Coastguard Worker command_buf = tmp_command_buf;
1687*6777b538SAndroid Build Coastguard Worker literal_buf = tmp_literal_buf;
1688*6777b538SAndroid Build Coastguard Worker }
1689*6777b538SAndroid Build Coastguard Worker }
1690*6777b538SAndroid Build Coastguard Worker
1691*6777b538SAndroid Build Coastguard Worker while (BROTLI_TRUE) {
1692*6777b538SAndroid Build Coastguard Worker if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) {
1693*6777b538SAndroid Build Coastguard Worker continue;
1694*6777b538SAndroid Build Coastguard Worker }
1695*6777b538SAndroid Build Coastguard Worker
1696*6777b538SAndroid Build Coastguard Worker /* Compress block only when internal output buffer is empty, stream is not
1697*6777b538SAndroid Build Coastguard Worker finished, there is no pending flush request, and there is either
1698*6777b538SAndroid Build Coastguard Worker additional input or pending operation. */
1699*6777b538SAndroid Build Coastguard Worker if (s->available_out_ == 0 &&
1700*6777b538SAndroid Build Coastguard Worker s->stream_state_ == BROTLI_STREAM_PROCESSING &&
1701*6777b538SAndroid Build Coastguard Worker (*available_in != 0 || op != BROTLI_OPERATION_PROCESS)) {
1702*6777b538SAndroid Build Coastguard Worker size_t block_size = BROTLI_MIN(size_t, block_size_limit, *available_in);
1703*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL is_last =
1704*6777b538SAndroid Build Coastguard Worker (*available_in == block_size) && (op == BROTLI_OPERATION_FINISH);
1705*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL force_flush =
1706*6777b538SAndroid Build Coastguard Worker (*available_in == block_size) && (op == BROTLI_OPERATION_FLUSH);
1707*6777b538SAndroid Build Coastguard Worker size_t max_out_size = 2 * block_size + 503;
1708*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL inplace = BROTLI_TRUE;
1709*6777b538SAndroid Build Coastguard Worker uint8_t* storage = NULL;
1710*6777b538SAndroid Build Coastguard Worker size_t storage_ix = s->last_bytes_bits_;
1711*6777b538SAndroid Build Coastguard Worker size_t table_size;
1712*6777b538SAndroid Build Coastguard Worker int* table;
1713*6777b538SAndroid Build Coastguard Worker
1714*6777b538SAndroid Build Coastguard Worker if (force_flush && block_size == 0) {
1715*6777b538SAndroid Build Coastguard Worker s->stream_state_ = BROTLI_STREAM_FLUSH_REQUESTED;
1716*6777b538SAndroid Build Coastguard Worker continue;
1717*6777b538SAndroid Build Coastguard Worker }
1718*6777b538SAndroid Build Coastguard Worker if (max_out_size <= *available_out) {
1719*6777b538SAndroid Build Coastguard Worker storage = *next_out;
1720*6777b538SAndroid Build Coastguard Worker } else {
1721*6777b538SAndroid Build Coastguard Worker inplace = BROTLI_FALSE;
1722*6777b538SAndroid Build Coastguard Worker storage = GetBrotliStorage(s, max_out_size);
1723*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1724*6777b538SAndroid Build Coastguard Worker }
1725*6777b538SAndroid Build Coastguard Worker storage[0] = (uint8_t)s->last_bytes_;
1726*6777b538SAndroid Build Coastguard Worker storage[1] = (uint8_t)(s->last_bytes_ >> 8);
1727*6777b538SAndroid Build Coastguard Worker table = GetHashTable(s, s->params.quality, block_size, &table_size);
1728*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1729*6777b538SAndroid Build Coastguard Worker
1730*6777b538SAndroid Build Coastguard Worker if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
1731*6777b538SAndroid Build Coastguard Worker BrotliCompressFragmentFast(s->one_pass_arena_, *next_in, block_size,
1732*6777b538SAndroid Build Coastguard Worker is_last, table, table_size, &storage_ix, storage);
1733*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1734*6777b538SAndroid Build Coastguard Worker } else {
1735*6777b538SAndroid Build Coastguard Worker BrotliCompressFragmentTwoPass(s->two_pass_arena_, *next_in, block_size,
1736*6777b538SAndroid Build Coastguard Worker is_last, command_buf, literal_buf, table, table_size,
1737*6777b538SAndroid Build Coastguard Worker &storage_ix, storage);
1738*6777b538SAndroid Build Coastguard Worker if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1739*6777b538SAndroid Build Coastguard Worker }
1740*6777b538SAndroid Build Coastguard Worker if (block_size != 0) {
1741*6777b538SAndroid Build Coastguard Worker *next_in += block_size;
1742*6777b538SAndroid Build Coastguard Worker *available_in -= block_size;
1743*6777b538SAndroid Build Coastguard Worker }
1744*6777b538SAndroid Build Coastguard Worker if (inplace) {
1745*6777b538SAndroid Build Coastguard Worker size_t out_bytes = storage_ix >> 3;
1746*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK(out_bytes <= *available_out);
1747*6777b538SAndroid Build Coastguard Worker BROTLI_DCHECK((storage_ix & 7) == 0 || out_bytes < *available_out);
1748*6777b538SAndroid Build Coastguard Worker *next_out += out_bytes;
1749*6777b538SAndroid Build Coastguard Worker *available_out -= out_bytes;
1750*6777b538SAndroid Build Coastguard Worker s->total_out_ += out_bytes;
1751*6777b538SAndroid Build Coastguard Worker if (total_out) *total_out = s->total_out_;
1752*6777b538SAndroid Build Coastguard Worker } else {
1753*6777b538SAndroid Build Coastguard Worker size_t out_bytes = storage_ix >> 3;
1754*6777b538SAndroid Build Coastguard Worker s->next_out_ = storage;
1755*6777b538SAndroid Build Coastguard Worker s->available_out_ = out_bytes;
1756*6777b538SAndroid Build Coastguard Worker }
1757*6777b538SAndroid Build Coastguard Worker s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]);
1758*6777b538SAndroid Build Coastguard Worker s->last_bytes_bits_ = storage_ix & 7u;
1759*6777b538SAndroid Build Coastguard Worker
1760*6777b538SAndroid Build Coastguard Worker if (force_flush) s->stream_state_ = BROTLI_STREAM_FLUSH_REQUESTED;
1761*6777b538SAndroid Build Coastguard Worker if (is_last) s->stream_state_ = BROTLI_STREAM_FINISHED;
1762*6777b538SAndroid Build Coastguard Worker continue;
1763*6777b538SAndroid Build Coastguard Worker }
1764*6777b538SAndroid Build Coastguard Worker break;
1765*6777b538SAndroid Build Coastguard Worker }
1766*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, tmp_command_buf);
1767*6777b538SAndroid Build Coastguard Worker BROTLI_FREE(m, tmp_literal_buf);
1768*6777b538SAndroid Build Coastguard Worker CheckFlushComplete(s);
1769*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1770*6777b538SAndroid Build Coastguard Worker }
1771*6777b538SAndroid Build Coastguard Worker
ProcessMetadata(BrotliEncoderState * s,size_t * available_in,const uint8_t ** next_in,size_t * available_out,uint8_t ** next_out,size_t * total_out)1772*6777b538SAndroid Build Coastguard Worker static BROTLI_BOOL ProcessMetadata(
1773*6777b538SAndroid Build Coastguard Worker BrotliEncoderState* s, size_t* available_in, const uint8_t** next_in,
1774*6777b538SAndroid Build Coastguard Worker size_t* available_out, uint8_t** next_out, size_t* total_out) {
1775*6777b538SAndroid Build Coastguard Worker if (*available_in > (1u << 24)) return BROTLI_FALSE;
1776*6777b538SAndroid Build Coastguard Worker /* Switch to metadata block workflow, if required. */
1777*6777b538SAndroid Build Coastguard Worker if (s->stream_state_ == BROTLI_STREAM_PROCESSING) {
1778*6777b538SAndroid Build Coastguard Worker s->remaining_metadata_bytes_ = (uint32_t)*available_in;
1779*6777b538SAndroid Build Coastguard Worker s->stream_state_ = BROTLI_STREAM_METADATA_HEAD;
1780*6777b538SAndroid Build Coastguard Worker }
1781*6777b538SAndroid Build Coastguard Worker if (s->stream_state_ != BROTLI_STREAM_METADATA_HEAD &&
1782*6777b538SAndroid Build Coastguard Worker s->stream_state_ != BROTLI_STREAM_METADATA_BODY) {
1783*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1784*6777b538SAndroid Build Coastguard Worker }
1785*6777b538SAndroid Build Coastguard Worker
1786*6777b538SAndroid Build Coastguard Worker while (BROTLI_TRUE) {
1787*6777b538SAndroid Build Coastguard Worker if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) {
1788*6777b538SAndroid Build Coastguard Worker continue;
1789*6777b538SAndroid Build Coastguard Worker }
1790*6777b538SAndroid Build Coastguard Worker if (s->available_out_ != 0) break;
1791*6777b538SAndroid Build Coastguard Worker
1792*6777b538SAndroid Build Coastguard Worker if (s->input_pos_ != s->last_flush_pos_) {
1793*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL result = EncodeData(s, BROTLI_FALSE, BROTLI_TRUE,
1794*6777b538SAndroid Build Coastguard Worker &s->available_out_, &s->next_out_);
1795*6777b538SAndroid Build Coastguard Worker if (!result) return BROTLI_FALSE;
1796*6777b538SAndroid Build Coastguard Worker continue;
1797*6777b538SAndroid Build Coastguard Worker }
1798*6777b538SAndroid Build Coastguard Worker
1799*6777b538SAndroid Build Coastguard Worker if (s->stream_state_ == BROTLI_STREAM_METADATA_HEAD) {
1800*6777b538SAndroid Build Coastguard Worker s->next_out_ = s->tiny_buf_.u8;
1801*6777b538SAndroid Build Coastguard Worker s->available_out_ =
1802*6777b538SAndroid Build Coastguard Worker WriteMetadataHeader(s, s->remaining_metadata_bytes_, s->next_out_);
1803*6777b538SAndroid Build Coastguard Worker s->stream_state_ = BROTLI_STREAM_METADATA_BODY;
1804*6777b538SAndroid Build Coastguard Worker continue;
1805*6777b538SAndroid Build Coastguard Worker } else {
1806*6777b538SAndroid Build Coastguard Worker /* Exit workflow only when there is no more input and no more output.
1807*6777b538SAndroid Build Coastguard Worker Otherwise client may continue producing empty metadata blocks. */
1808*6777b538SAndroid Build Coastguard Worker if (s->remaining_metadata_bytes_ == 0) {
1809*6777b538SAndroid Build Coastguard Worker s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
1810*6777b538SAndroid Build Coastguard Worker s->stream_state_ = BROTLI_STREAM_PROCESSING;
1811*6777b538SAndroid Build Coastguard Worker break;
1812*6777b538SAndroid Build Coastguard Worker }
1813*6777b538SAndroid Build Coastguard Worker if (*available_out) {
1814*6777b538SAndroid Build Coastguard Worker /* Directly copy input to output. */
1815*6777b538SAndroid Build Coastguard Worker uint32_t copy = (uint32_t)BROTLI_MIN(
1816*6777b538SAndroid Build Coastguard Worker size_t, s->remaining_metadata_bytes_, *available_out);
1817*6777b538SAndroid Build Coastguard Worker memcpy(*next_out, *next_in, copy);
1818*6777b538SAndroid Build Coastguard Worker *next_in += copy;
1819*6777b538SAndroid Build Coastguard Worker *available_in -= copy;
1820*6777b538SAndroid Build Coastguard Worker s->remaining_metadata_bytes_ -= copy;
1821*6777b538SAndroid Build Coastguard Worker *next_out += copy;
1822*6777b538SAndroid Build Coastguard Worker *available_out -= copy;
1823*6777b538SAndroid Build Coastguard Worker } else {
1824*6777b538SAndroid Build Coastguard Worker /* This guarantees progress in "TakeOutput" workflow. */
1825*6777b538SAndroid Build Coastguard Worker uint32_t copy = BROTLI_MIN(uint32_t, s->remaining_metadata_bytes_, 16);
1826*6777b538SAndroid Build Coastguard Worker s->next_out_ = s->tiny_buf_.u8;
1827*6777b538SAndroid Build Coastguard Worker memcpy(s->next_out_, *next_in, copy);
1828*6777b538SAndroid Build Coastguard Worker *next_in += copy;
1829*6777b538SAndroid Build Coastguard Worker *available_in -= copy;
1830*6777b538SAndroid Build Coastguard Worker s->remaining_metadata_bytes_ -= copy;
1831*6777b538SAndroid Build Coastguard Worker s->available_out_ = copy;
1832*6777b538SAndroid Build Coastguard Worker }
1833*6777b538SAndroid Build Coastguard Worker continue;
1834*6777b538SAndroid Build Coastguard Worker }
1835*6777b538SAndroid Build Coastguard Worker }
1836*6777b538SAndroid Build Coastguard Worker
1837*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1838*6777b538SAndroid Build Coastguard Worker }
1839*6777b538SAndroid Build Coastguard Worker
UpdateSizeHint(BrotliEncoderState * s,size_t available_in)1840*6777b538SAndroid Build Coastguard Worker static void UpdateSizeHint(BrotliEncoderState* s, size_t available_in) {
1841*6777b538SAndroid Build Coastguard Worker if (s->params.size_hint == 0) {
1842*6777b538SAndroid Build Coastguard Worker uint64_t delta = UnprocessedInputSize(s);
1843*6777b538SAndroid Build Coastguard Worker uint64_t tail = available_in;
1844*6777b538SAndroid Build Coastguard Worker uint32_t limit = 1u << 30;
1845*6777b538SAndroid Build Coastguard Worker uint32_t total;
1846*6777b538SAndroid Build Coastguard Worker if ((delta >= limit) || (tail >= limit) || ((delta + tail) >= limit)) {
1847*6777b538SAndroid Build Coastguard Worker total = limit;
1848*6777b538SAndroid Build Coastguard Worker } else {
1849*6777b538SAndroid Build Coastguard Worker total = (uint32_t)(delta + tail);
1850*6777b538SAndroid Build Coastguard Worker }
1851*6777b538SAndroid Build Coastguard Worker s->params.size_hint = total;
1852*6777b538SAndroid Build Coastguard Worker }
1853*6777b538SAndroid Build Coastguard Worker }
1854*6777b538SAndroid Build Coastguard Worker
BrotliEncoderCompressStream(BrotliEncoderState * s,BrotliEncoderOperation op,size_t * available_in,const uint8_t ** next_in,size_t * available_out,uint8_t ** next_out,size_t * total_out)1855*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL BrotliEncoderCompressStream(
1856*6777b538SAndroid Build Coastguard Worker BrotliEncoderState* s, BrotliEncoderOperation op, size_t* available_in,
1857*6777b538SAndroid Build Coastguard Worker const uint8_t** next_in, size_t* available_out,uint8_t** next_out,
1858*6777b538SAndroid Build Coastguard Worker size_t* total_out) {
1859*6777b538SAndroid Build Coastguard Worker if (!EnsureInitialized(s)) return BROTLI_FALSE;
1860*6777b538SAndroid Build Coastguard Worker
1861*6777b538SAndroid Build Coastguard Worker /* Unfinished metadata block; check requirements. */
1862*6777b538SAndroid Build Coastguard Worker if (s->remaining_metadata_bytes_ != BROTLI_UINT32_MAX) {
1863*6777b538SAndroid Build Coastguard Worker if (*available_in != s->remaining_metadata_bytes_) return BROTLI_FALSE;
1864*6777b538SAndroid Build Coastguard Worker if (op != BROTLI_OPERATION_EMIT_METADATA) return BROTLI_FALSE;
1865*6777b538SAndroid Build Coastguard Worker }
1866*6777b538SAndroid Build Coastguard Worker
1867*6777b538SAndroid Build Coastguard Worker if (op == BROTLI_OPERATION_EMIT_METADATA) {
1868*6777b538SAndroid Build Coastguard Worker UpdateSizeHint(s, 0); /* First data metablock might be emitted here. */
1869*6777b538SAndroid Build Coastguard Worker return ProcessMetadata(
1870*6777b538SAndroid Build Coastguard Worker s, available_in, next_in, available_out, next_out, total_out);
1871*6777b538SAndroid Build Coastguard Worker }
1872*6777b538SAndroid Build Coastguard Worker
1873*6777b538SAndroid Build Coastguard Worker if (s->stream_state_ == BROTLI_STREAM_METADATA_HEAD ||
1874*6777b538SAndroid Build Coastguard Worker s->stream_state_ == BROTLI_STREAM_METADATA_BODY) {
1875*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1876*6777b538SAndroid Build Coastguard Worker }
1877*6777b538SAndroid Build Coastguard Worker
1878*6777b538SAndroid Build Coastguard Worker if (s->stream_state_ != BROTLI_STREAM_PROCESSING && *available_in != 0) {
1879*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
1880*6777b538SAndroid Build Coastguard Worker }
1881*6777b538SAndroid Build Coastguard Worker if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
1882*6777b538SAndroid Build Coastguard Worker s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
1883*6777b538SAndroid Build Coastguard Worker return BrotliEncoderCompressStreamFast(s, op, available_in, next_in,
1884*6777b538SAndroid Build Coastguard Worker available_out, next_out, total_out);
1885*6777b538SAndroid Build Coastguard Worker }
1886*6777b538SAndroid Build Coastguard Worker while (BROTLI_TRUE) {
1887*6777b538SAndroid Build Coastguard Worker size_t remaining_block_size = RemainingInputBlockSize(s);
1888*6777b538SAndroid Build Coastguard Worker /* Shorten input to flint size. */
1889*6777b538SAndroid Build Coastguard Worker if (s->flint_ >= 0 && remaining_block_size > (size_t)s->flint_) {
1890*6777b538SAndroid Build Coastguard Worker remaining_block_size = (size_t)s->flint_;
1891*6777b538SAndroid Build Coastguard Worker }
1892*6777b538SAndroid Build Coastguard Worker
1893*6777b538SAndroid Build Coastguard Worker if (remaining_block_size != 0 && *available_in != 0) {
1894*6777b538SAndroid Build Coastguard Worker size_t copy_input_size =
1895*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, remaining_block_size, *available_in);
1896*6777b538SAndroid Build Coastguard Worker CopyInputToRingBuffer(s, copy_input_size, *next_in);
1897*6777b538SAndroid Build Coastguard Worker *next_in += copy_input_size;
1898*6777b538SAndroid Build Coastguard Worker *available_in -= copy_input_size;
1899*6777b538SAndroid Build Coastguard Worker if (s->flint_ > 0) s->flint_ = (int8_t)(s->flint_ - (int)copy_input_size);
1900*6777b538SAndroid Build Coastguard Worker continue;
1901*6777b538SAndroid Build Coastguard Worker }
1902*6777b538SAndroid Build Coastguard Worker
1903*6777b538SAndroid Build Coastguard Worker if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) {
1904*6777b538SAndroid Build Coastguard Worker /* Exit the "emit flint" workflow. */
1905*6777b538SAndroid Build Coastguard Worker if (s->flint_ == BROTLI_FLINT_WAITING_FOR_FLUSHING) {
1906*6777b538SAndroid Build Coastguard Worker CheckFlushComplete(s);
1907*6777b538SAndroid Build Coastguard Worker if (s->stream_state_ == BROTLI_STREAM_PROCESSING) {
1908*6777b538SAndroid Build Coastguard Worker s->flint_ = BROTLI_FLINT_DONE;
1909*6777b538SAndroid Build Coastguard Worker }
1910*6777b538SAndroid Build Coastguard Worker }
1911*6777b538SAndroid Build Coastguard Worker continue;
1912*6777b538SAndroid Build Coastguard Worker }
1913*6777b538SAndroid Build Coastguard Worker
1914*6777b538SAndroid Build Coastguard Worker /* Compress data only when internal output buffer is empty, stream is not
1915*6777b538SAndroid Build Coastguard Worker finished and there is no pending flush request. */
1916*6777b538SAndroid Build Coastguard Worker if (s->available_out_ == 0 &&
1917*6777b538SAndroid Build Coastguard Worker s->stream_state_ == BROTLI_STREAM_PROCESSING) {
1918*6777b538SAndroid Build Coastguard Worker if (remaining_block_size == 0 || op != BROTLI_OPERATION_PROCESS) {
1919*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL is_last = TO_BROTLI_BOOL(
1920*6777b538SAndroid Build Coastguard Worker (*available_in == 0) && op == BROTLI_OPERATION_FINISH);
1921*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL force_flush = TO_BROTLI_BOOL(
1922*6777b538SAndroid Build Coastguard Worker (*available_in == 0) && op == BROTLI_OPERATION_FLUSH);
1923*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL result;
1924*6777b538SAndroid Build Coastguard Worker /* Force emitting (uncompressed) piece containing flint. */
1925*6777b538SAndroid Build Coastguard Worker if (!is_last && s->flint_ == 0) {
1926*6777b538SAndroid Build Coastguard Worker s->flint_ = BROTLI_FLINT_WAITING_FOR_FLUSHING;
1927*6777b538SAndroid Build Coastguard Worker force_flush = BROTLI_TRUE;
1928*6777b538SAndroid Build Coastguard Worker }
1929*6777b538SAndroid Build Coastguard Worker UpdateSizeHint(s, *available_in);
1930*6777b538SAndroid Build Coastguard Worker result = EncodeData(s, is_last, force_flush,
1931*6777b538SAndroid Build Coastguard Worker &s->available_out_, &s->next_out_);
1932*6777b538SAndroid Build Coastguard Worker if (!result) return BROTLI_FALSE;
1933*6777b538SAndroid Build Coastguard Worker if (force_flush) s->stream_state_ = BROTLI_STREAM_FLUSH_REQUESTED;
1934*6777b538SAndroid Build Coastguard Worker if (is_last) s->stream_state_ = BROTLI_STREAM_FINISHED;
1935*6777b538SAndroid Build Coastguard Worker continue;
1936*6777b538SAndroid Build Coastguard Worker }
1937*6777b538SAndroid Build Coastguard Worker }
1938*6777b538SAndroid Build Coastguard Worker break;
1939*6777b538SAndroid Build Coastguard Worker }
1940*6777b538SAndroid Build Coastguard Worker CheckFlushComplete(s);
1941*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
1942*6777b538SAndroid Build Coastguard Worker }
1943*6777b538SAndroid Build Coastguard Worker
BrotliEncoderIsFinished(BrotliEncoderState * s)1944*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL BrotliEncoderIsFinished(BrotliEncoderState* s) {
1945*6777b538SAndroid Build Coastguard Worker return TO_BROTLI_BOOL(s->stream_state_ == BROTLI_STREAM_FINISHED &&
1946*6777b538SAndroid Build Coastguard Worker !BrotliEncoderHasMoreOutput(s));
1947*6777b538SAndroid Build Coastguard Worker }
1948*6777b538SAndroid Build Coastguard Worker
BrotliEncoderHasMoreOutput(BrotliEncoderState * s)1949*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL BrotliEncoderHasMoreOutput(BrotliEncoderState* s) {
1950*6777b538SAndroid Build Coastguard Worker return TO_BROTLI_BOOL(s->available_out_ != 0);
1951*6777b538SAndroid Build Coastguard Worker }
1952*6777b538SAndroid Build Coastguard Worker
BrotliEncoderTakeOutput(BrotliEncoderState * s,size_t * size)1953*6777b538SAndroid Build Coastguard Worker const uint8_t* BrotliEncoderTakeOutput(BrotliEncoderState* s, size_t* size) {
1954*6777b538SAndroid Build Coastguard Worker size_t consumed_size = s->available_out_;
1955*6777b538SAndroid Build Coastguard Worker uint8_t* result = s->next_out_;
1956*6777b538SAndroid Build Coastguard Worker if (*size) {
1957*6777b538SAndroid Build Coastguard Worker consumed_size = BROTLI_MIN(size_t, *size, s->available_out_);
1958*6777b538SAndroid Build Coastguard Worker }
1959*6777b538SAndroid Build Coastguard Worker if (consumed_size) {
1960*6777b538SAndroid Build Coastguard Worker s->next_out_ += consumed_size;
1961*6777b538SAndroid Build Coastguard Worker s->available_out_ -= consumed_size;
1962*6777b538SAndroid Build Coastguard Worker s->total_out_ += consumed_size;
1963*6777b538SAndroid Build Coastguard Worker CheckFlushComplete(s);
1964*6777b538SAndroid Build Coastguard Worker *size = consumed_size;
1965*6777b538SAndroid Build Coastguard Worker } else {
1966*6777b538SAndroid Build Coastguard Worker *size = 0;
1967*6777b538SAndroid Build Coastguard Worker result = 0;
1968*6777b538SAndroid Build Coastguard Worker }
1969*6777b538SAndroid Build Coastguard Worker return result;
1970*6777b538SAndroid Build Coastguard Worker }
1971*6777b538SAndroid Build Coastguard Worker
BrotliEncoderVersion(void)1972*6777b538SAndroid Build Coastguard Worker uint32_t BrotliEncoderVersion(void) {
1973*6777b538SAndroid Build Coastguard Worker return BROTLI_VERSION;
1974*6777b538SAndroid Build Coastguard Worker }
1975*6777b538SAndroid Build Coastguard Worker
BrotliEncoderPrepareDictionary(BrotliSharedDictionaryType type,size_t size,const uint8_t data[BROTLI_ARRAY_PARAM (size)],int quality,brotli_alloc_func alloc_func,brotli_free_func free_func,void * opaque)1976*6777b538SAndroid Build Coastguard Worker BrotliEncoderPreparedDictionary* BrotliEncoderPrepareDictionary(
1977*6777b538SAndroid Build Coastguard Worker BrotliSharedDictionaryType type, size_t size,
1978*6777b538SAndroid Build Coastguard Worker const uint8_t data[BROTLI_ARRAY_PARAM(size)], int quality,
1979*6777b538SAndroid Build Coastguard Worker brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
1980*6777b538SAndroid Build Coastguard Worker ManagedDictionary* managed_dictionary = NULL;
1981*6777b538SAndroid Build Coastguard Worker if (type != BROTLI_SHARED_DICTIONARY_RAW &&
1982*6777b538SAndroid Build Coastguard Worker type != BROTLI_SHARED_DICTIONARY_SERIALIZED) {
1983*6777b538SAndroid Build Coastguard Worker return NULL;
1984*6777b538SAndroid Build Coastguard Worker }
1985*6777b538SAndroid Build Coastguard Worker managed_dictionary =
1986*6777b538SAndroid Build Coastguard Worker BrotliCreateManagedDictionary(alloc_func, free_func, opaque);
1987*6777b538SAndroid Build Coastguard Worker if (managed_dictionary == NULL) {
1988*6777b538SAndroid Build Coastguard Worker return NULL;
1989*6777b538SAndroid Build Coastguard Worker }
1990*6777b538SAndroid Build Coastguard Worker if (type == BROTLI_SHARED_DICTIONARY_RAW) {
1991*6777b538SAndroid Build Coastguard Worker managed_dictionary->dictionary = (uint32_t*)CreatePreparedDictionary(
1992*6777b538SAndroid Build Coastguard Worker &managed_dictionary->memory_manager_, data, size);
1993*6777b538SAndroid Build Coastguard Worker } else {
1994*6777b538SAndroid Build Coastguard Worker SharedEncoderDictionary* dict = (SharedEncoderDictionary*)BrotliAllocate(
1995*6777b538SAndroid Build Coastguard Worker &managed_dictionary->memory_manager_, sizeof(SharedEncoderDictionary));
1996*6777b538SAndroid Build Coastguard Worker managed_dictionary->dictionary = (uint32_t*)dict;
1997*6777b538SAndroid Build Coastguard Worker if (dict != NULL) {
1998*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL ok = BrotliInitCustomSharedEncoderDictionary(
1999*6777b538SAndroid Build Coastguard Worker &managed_dictionary->memory_manager_, data, size, quality, dict);
2000*6777b538SAndroid Build Coastguard Worker if (!ok) {
2001*6777b538SAndroid Build Coastguard Worker BrotliFree(&managed_dictionary->memory_manager_, dict);
2002*6777b538SAndroid Build Coastguard Worker managed_dictionary->dictionary = NULL;
2003*6777b538SAndroid Build Coastguard Worker }
2004*6777b538SAndroid Build Coastguard Worker }
2005*6777b538SAndroid Build Coastguard Worker }
2006*6777b538SAndroid Build Coastguard Worker if (managed_dictionary->dictionary == NULL) {
2007*6777b538SAndroid Build Coastguard Worker BrotliDestroyManagedDictionary(managed_dictionary);
2008*6777b538SAndroid Build Coastguard Worker return NULL;
2009*6777b538SAndroid Build Coastguard Worker }
2010*6777b538SAndroid Build Coastguard Worker return (BrotliEncoderPreparedDictionary*)managed_dictionary;
2011*6777b538SAndroid Build Coastguard Worker }
2012*6777b538SAndroid Build Coastguard Worker
BrotliEncoderDestroyPreparedDictionary(BrotliEncoderPreparedDictionary * dictionary)2013*6777b538SAndroid Build Coastguard Worker void BrotliEncoderDestroyPreparedDictionary(
2014*6777b538SAndroid Build Coastguard Worker BrotliEncoderPreparedDictionary* dictionary) {
2015*6777b538SAndroid Build Coastguard Worker ManagedDictionary* dict = (ManagedDictionary*)dictionary;
2016*6777b538SAndroid Build Coastguard Worker if (!dictionary) return;
2017*6777b538SAndroid Build Coastguard Worker /* First field of dictionary structs. */
2018*6777b538SAndroid Build Coastguard Worker /* Only managed dictionaries are eligible for destruction by this method. */
2019*6777b538SAndroid Build Coastguard Worker if (dict->magic != kManagedDictionaryMagic) {
2020*6777b538SAndroid Build Coastguard Worker return;
2021*6777b538SAndroid Build Coastguard Worker }
2022*6777b538SAndroid Build Coastguard Worker if (dict->dictionary == NULL) {
2023*6777b538SAndroid Build Coastguard Worker /* This should never ever happen. */
2024*6777b538SAndroid Build Coastguard Worker } else if (*dict->dictionary == kPreparedDictionaryMagic) {
2025*6777b538SAndroid Build Coastguard Worker DestroyPreparedDictionary(
2026*6777b538SAndroid Build Coastguard Worker &dict->memory_manager_, (PreparedDictionary*)dict->dictionary);
2027*6777b538SAndroid Build Coastguard Worker } else if (*dict->dictionary == kSharedDictionaryMagic) {
2028*6777b538SAndroid Build Coastguard Worker BrotliCleanupSharedEncoderDictionary(&dict->memory_manager_,
2029*6777b538SAndroid Build Coastguard Worker (SharedEncoderDictionary*)dict->dictionary);
2030*6777b538SAndroid Build Coastguard Worker BrotliFree(&dict->memory_manager_, dict->dictionary);
2031*6777b538SAndroid Build Coastguard Worker } else {
2032*6777b538SAndroid Build Coastguard Worker /* This should never ever happen. */
2033*6777b538SAndroid Build Coastguard Worker }
2034*6777b538SAndroid Build Coastguard Worker dict->dictionary = NULL;
2035*6777b538SAndroid Build Coastguard Worker BrotliDestroyManagedDictionary(dict);
2036*6777b538SAndroid Build Coastguard Worker }
2037*6777b538SAndroid Build Coastguard Worker
BrotliEncoderAttachPreparedDictionary(BrotliEncoderState * state,const BrotliEncoderPreparedDictionary * dictionary)2038*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL BrotliEncoderAttachPreparedDictionary(BrotliEncoderState* state,
2039*6777b538SAndroid Build Coastguard Worker const BrotliEncoderPreparedDictionary* dictionary) {
2040*6777b538SAndroid Build Coastguard Worker /* First field of dictionary structs */
2041*6777b538SAndroid Build Coastguard Worker const BrotliEncoderPreparedDictionary* dict = dictionary;
2042*6777b538SAndroid Build Coastguard Worker uint32_t magic = *((const uint32_t*)dict);
2043*6777b538SAndroid Build Coastguard Worker SharedEncoderDictionary* current = NULL;
2044*6777b538SAndroid Build Coastguard Worker if (magic == kManagedDictionaryMagic) {
2045*6777b538SAndroid Build Coastguard Worker /* Unwrap managed dictionary. */
2046*6777b538SAndroid Build Coastguard Worker ManagedDictionary* managed_dictionary = (ManagedDictionary*)dict;
2047*6777b538SAndroid Build Coastguard Worker magic = *managed_dictionary->dictionary;
2048*6777b538SAndroid Build Coastguard Worker dict = (BrotliEncoderPreparedDictionary*)managed_dictionary->dictionary;
2049*6777b538SAndroid Build Coastguard Worker }
2050*6777b538SAndroid Build Coastguard Worker current = &state->params.dictionary;
2051*6777b538SAndroid Build Coastguard Worker if (magic == kPreparedDictionaryMagic) {
2052*6777b538SAndroid Build Coastguard Worker const PreparedDictionary* prepared = (const PreparedDictionary*)dict;
2053*6777b538SAndroid Build Coastguard Worker if (!AttachPreparedDictionary(¤t->compound, prepared)) {
2054*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
2055*6777b538SAndroid Build Coastguard Worker }
2056*6777b538SAndroid Build Coastguard Worker } else if (magic == kSharedDictionaryMagic) {
2057*6777b538SAndroid Build Coastguard Worker const SharedEncoderDictionary* attached =
2058*6777b538SAndroid Build Coastguard Worker (const SharedEncoderDictionary*)dict;
2059*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL was_default = !current->contextual.context_based &&
2060*6777b538SAndroid Build Coastguard Worker current->contextual.num_dictionaries == 1 &&
2061*6777b538SAndroid Build Coastguard Worker current->contextual.dict[0]->hash_table_words ==
2062*6777b538SAndroid Build Coastguard Worker kStaticDictionaryHashWords &&
2063*6777b538SAndroid Build Coastguard Worker current->contextual.dict[0]->hash_table_lengths ==
2064*6777b538SAndroid Build Coastguard Worker kStaticDictionaryHashLengths;
2065*6777b538SAndroid Build Coastguard Worker BROTLI_BOOL new_default = !attached->contextual.context_based &&
2066*6777b538SAndroid Build Coastguard Worker attached->contextual.num_dictionaries == 1 &&
2067*6777b538SAndroid Build Coastguard Worker attached->contextual.dict[0]->hash_table_words ==
2068*6777b538SAndroid Build Coastguard Worker kStaticDictionaryHashWords &&
2069*6777b538SAndroid Build Coastguard Worker attached->contextual.dict[0]->hash_table_lengths ==
2070*6777b538SAndroid Build Coastguard Worker kStaticDictionaryHashLengths;
2071*6777b538SAndroid Build Coastguard Worker size_t i;
2072*6777b538SAndroid Build Coastguard Worker if (state->is_initialized_) return BROTLI_FALSE;
2073*6777b538SAndroid Build Coastguard Worker current->max_quality =
2074*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(int, current->max_quality, attached->max_quality);
2075*6777b538SAndroid Build Coastguard Worker for (i = 0; i < attached->compound.num_chunks; i++) {
2076*6777b538SAndroid Build Coastguard Worker if (!AttachPreparedDictionary(¤t->compound,
2077*6777b538SAndroid Build Coastguard Worker attached->compound.chunks[i])) {
2078*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
2079*6777b538SAndroid Build Coastguard Worker }
2080*6777b538SAndroid Build Coastguard Worker }
2081*6777b538SAndroid Build Coastguard Worker if (!new_default) {
2082*6777b538SAndroid Build Coastguard Worker if (!was_default) return BROTLI_FALSE;
2083*6777b538SAndroid Build Coastguard Worker /* Copy by value, but then set num_instances_ to 0 because their memory
2084*6777b538SAndroid Build Coastguard Worker is managed by attached, not by current */
2085*6777b538SAndroid Build Coastguard Worker current->contextual = attached->contextual;
2086*6777b538SAndroid Build Coastguard Worker current->contextual.num_instances_ = 0;
2087*6777b538SAndroid Build Coastguard Worker }
2088*6777b538SAndroid Build Coastguard Worker } else {
2089*6777b538SAndroid Build Coastguard Worker return BROTLI_FALSE;
2090*6777b538SAndroid Build Coastguard Worker }
2091*6777b538SAndroid Build Coastguard Worker return BROTLI_TRUE;
2092*6777b538SAndroid Build Coastguard Worker }
2093*6777b538SAndroid Build Coastguard Worker
BrotliEncoderEstimatePeakMemoryUsage(int quality,int lgwin,size_t input_size)2094*6777b538SAndroid Build Coastguard Worker size_t BrotliEncoderEstimatePeakMemoryUsage(int quality, int lgwin,
2095*6777b538SAndroid Build Coastguard Worker size_t input_size) {
2096*6777b538SAndroid Build Coastguard Worker BrotliEncoderParams params;
2097*6777b538SAndroid Build Coastguard Worker BrotliEncoderInitParams(¶ms);
2098*6777b538SAndroid Build Coastguard Worker params.quality = quality;
2099*6777b538SAndroid Build Coastguard Worker params.lgwin = lgwin;
2100*6777b538SAndroid Build Coastguard Worker params.size_hint = input_size;
2101*6777b538SAndroid Build Coastguard Worker SanitizeParams(¶ms);
2102*6777b538SAndroid Build Coastguard Worker params.lgblock = ComputeLgBlock(¶ms);
2103*6777b538SAndroid Build Coastguard Worker ChooseHasher(¶ms, ¶ms.hasher);
2104*6777b538SAndroid Build Coastguard Worker if (params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
2105*6777b538SAndroid Build Coastguard Worker params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
2106*6777b538SAndroid Build Coastguard Worker size_t state_size = sizeof(BrotliEncoderState);
2107*6777b538SAndroid Build Coastguard Worker size_t block_size = BROTLI_MIN(size_t, input_size, (1ul << params.lgwin));
2108*6777b538SAndroid Build Coastguard Worker size_t hash_table_size =
2109*6777b538SAndroid Build Coastguard Worker HashTableSize(MaxHashTableSize(params.quality), block_size);
2110*6777b538SAndroid Build Coastguard Worker size_t hash_size =
2111*6777b538SAndroid Build Coastguard Worker (hash_table_size < (1u << 10)) ? 0 : sizeof(int) * hash_table_size;
2112*6777b538SAndroid Build Coastguard Worker size_t cmdbuf_size = params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY ?
2113*6777b538SAndroid Build Coastguard Worker 5 * BROTLI_MIN(size_t, block_size, 1ul << 17) : 0;
2114*6777b538SAndroid Build Coastguard Worker if (params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
2115*6777b538SAndroid Build Coastguard Worker state_size += sizeof(BrotliOnePassArena);
2116*6777b538SAndroid Build Coastguard Worker } else {
2117*6777b538SAndroid Build Coastguard Worker state_size += sizeof(BrotliTwoPassArena);
2118*6777b538SAndroid Build Coastguard Worker }
2119*6777b538SAndroid Build Coastguard Worker return hash_size + cmdbuf_size + state_size;
2120*6777b538SAndroid Build Coastguard Worker } else {
2121*6777b538SAndroid Build Coastguard Worker size_t short_ringbuffer_size = (size_t)1 << params.lgblock;
2122*6777b538SAndroid Build Coastguard Worker int ringbuffer_bits = ComputeRbBits(¶ms);
2123*6777b538SAndroid Build Coastguard Worker size_t ringbuffer_size = input_size < short_ringbuffer_size ?
2124*6777b538SAndroid Build Coastguard Worker input_size : (1u << ringbuffer_bits) + short_ringbuffer_size;
2125*6777b538SAndroid Build Coastguard Worker size_t hash_size[4] = {0};
2126*6777b538SAndroid Build Coastguard Worker size_t metablock_size =
2127*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, input_size, MaxMetablockSize(¶ms));
2128*6777b538SAndroid Build Coastguard Worker size_t inputblock_size =
2129*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, input_size, (size_t)1 << params.lgblock);
2130*6777b538SAndroid Build Coastguard Worker size_t cmdbuf_size = metablock_size * 2 + inputblock_size * 6;
2131*6777b538SAndroid Build Coastguard Worker size_t outbuf_size = metablock_size * 2 + 503;
2132*6777b538SAndroid Build Coastguard Worker size_t histogram_size = 0;
2133*6777b538SAndroid Build Coastguard Worker HasherSize(¶ms, BROTLI_TRUE, input_size, hash_size);
2134*6777b538SAndroid Build Coastguard Worker if (params.quality < MIN_QUALITY_FOR_BLOCK_SPLIT) {
2135*6777b538SAndroid Build Coastguard Worker cmdbuf_size = BROTLI_MIN(size_t, cmdbuf_size,
2136*6777b538SAndroid Build Coastguard Worker MAX_NUM_DELAYED_SYMBOLS * sizeof(Command) + inputblock_size * 12);
2137*6777b538SAndroid Build Coastguard Worker }
2138*6777b538SAndroid Build Coastguard Worker if (params.quality >= MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING) {
2139*6777b538SAndroid Build Coastguard Worker /* Only a very rough estimation, based on enwik8. */
2140*6777b538SAndroid Build Coastguard Worker histogram_size = 200 << 20;
2141*6777b538SAndroid Build Coastguard Worker } else if (params.quality >= MIN_QUALITY_FOR_BLOCK_SPLIT) {
2142*6777b538SAndroid Build Coastguard Worker size_t literal_histograms =
2143*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, metablock_size / 6144, 256);
2144*6777b538SAndroid Build Coastguard Worker size_t command_histograms =
2145*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, metablock_size / 6144, 256);
2146*6777b538SAndroid Build Coastguard Worker size_t distance_histograms =
2147*6777b538SAndroid Build Coastguard Worker BROTLI_MIN(size_t, metablock_size / 6144, 256);
2148*6777b538SAndroid Build Coastguard Worker histogram_size = literal_histograms * sizeof(HistogramLiteral) +
2149*6777b538SAndroid Build Coastguard Worker command_histograms * sizeof(HistogramCommand) +
2150*6777b538SAndroid Build Coastguard Worker distance_histograms * sizeof(HistogramDistance);
2151*6777b538SAndroid Build Coastguard Worker }
2152*6777b538SAndroid Build Coastguard Worker return (ringbuffer_size +
2153*6777b538SAndroid Build Coastguard Worker hash_size[0] + hash_size[1] + hash_size[2] + hash_size[3] +
2154*6777b538SAndroid Build Coastguard Worker cmdbuf_size +
2155*6777b538SAndroid Build Coastguard Worker outbuf_size +
2156*6777b538SAndroid Build Coastguard Worker histogram_size);
2157*6777b538SAndroid Build Coastguard Worker }
2158*6777b538SAndroid Build Coastguard Worker }
BrotliEncoderGetPreparedDictionarySize(const BrotliEncoderPreparedDictionary * prepared_dictionary)2159*6777b538SAndroid Build Coastguard Worker size_t BrotliEncoderGetPreparedDictionarySize(
2160*6777b538SAndroid Build Coastguard Worker const BrotliEncoderPreparedDictionary* prepared_dictionary) {
2161*6777b538SAndroid Build Coastguard Worker /* First field of dictionary structs */
2162*6777b538SAndroid Build Coastguard Worker const BrotliEncoderPreparedDictionary* prepared = prepared_dictionary;
2163*6777b538SAndroid Build Coastguard Worker uint32_t magic = *((const uint32_t*)prepared);
2164*6777b538SAndroid Build Coastguard Worker size_t overhead = 0;
2165*6777b538SAndroid Build Coastguard Worker if (magic == kManagedDictionaryMagic) {
2166*6777b538SAndroid Build Coastguard Worker const ManagedDictionary* managed = (const ManagedDictionary*)prepared;
2167*6777b538SAndroid Build Coastguard Worker overhead = sizeof(ManagedDictionary);
2168*6777b538SAndroid Build Coastguard Worker magic = *managed->dictionary;
2169*6777b538SAndroid Build Coastguard Worker prepared = (const BrotliEncoderPreparedDictionary*)managed->dictionary;
2170*6777b538SAndroid Build Coastguard Worker }
2171*6777b538SAndroid Build Coastguard Worker
2172*6777b538SAndroid Build Coastguard Worker if (magic == kPreparedDictionaryMagic) {
2173*6777b538SAndroid Build Coastguard Worker const PreparedDictionary* dictionary =
2174*6777b538SAndroid Build Coastguard Worker (const PreparedDictionary*)prepared;
2175*6777b538SAndroid Build Coastguard Worker /* Keep in sync with step 3 of CreatePreparedDictionary */
2176*6777b538SAndroid Build Coastguard Worker return sizeof(PreparedDictionary) + dictionary->source_size +
2177*6777b538SAndroid Build Coastguard Worker (sizeof(uint32_t) << dictionary->slot_bits) +
2178*6777b538SAndroid Build Coastguard Worker (sizeof(uint16_t) << dictionary->bucket_bits) +
2179*6777b538SAndroid Build Coastguard Worker (sizeof(uint32_t) * dictionary->source_offset) + overhead;
2180*6777b538SAndroid Build Coastguard Worker } else if (magic == kSharedDictionaryMagic) {
2181*6777b538SAndroid Build Coastguard Worker const SharedEncoderDictionary* dictionary =
2182*6777b538SAndroid Build Coastguard Worker (const SharedEncoderDictionary*)prepared;
2183*6777b538SAndroid Build Coastguard Worker const CompoundDictionary* compound = &dictionary->compound;
2184*6777b538SAndroid Build Coastguard Worker const ContextualEncoderDictionary* contextual = &dictionary->contextual;
2185*6777b538SAndroid Build Coastguard Worker size_t result = sizeof(*dictionary);
2186*6777b538SAndroid Build Coastguard Worker size_t i;
2187*6777b538SAndroid Build Coastguard Worker size_t num_instances;
2188*6777b538SAndroid Build Coastguard Worker const BrotliEncoderDictionary* instances;
2189*6777b538SAndroid Build Coastguard Worker for (i = 0; i < compound->num_prepared_instances_; i++) {
2190*6777b538SAndroid Build Coastguard Worker size_t size = BrotliEncoderGetPreparedDictionarySize(
2191*6777b538SAndroid Build Coastguard Worker (const BrotliEncoderPreparedDictionary*)
2192*6777b538SAndroid Build Coastguard Worker compound->prepared_instances_[i]);
2193*6777b538SAndroid Build Coastguard Worker if (!size) return 0; /* error */
2194*6777b538SAndroid Build Coastguard Worker result += size;
2195*6777b538SAndroid Build Coastguard Worker }
2196*6777b538SAndroid Build Coastguard Worker if (contextual->context_based) {
2197*6777b538SAndroid Build Coastguard Worker num_instances = contextual->num_instances_;
2198*6777b538SAndroid Build Coastguard Worker instances = contextual->instances_;
2199*6777b538SAndroid Build Coastguard Worker result += sizeof(*instances) * num_instances;
2200*6777b538SAndroid Build Coastguard Worker } else {
2201*6777b538SAndroid Build Coastguard Worker num_instances = 1;
2202*6777b538SAndroid Build Coastguard Worker instances = &contextual->instance_;
2203*6777b538SAndroid Build Coastguard Worker }
2204*6777b538SAndroid Build Coastguard Worker for (i = 0; i < num_instances; i++) {
2205*6777b538SAndroid Build Coastguard Worker const BrotliEncoderDictionary* dict = &instances[i];
2206*6777b538SAndroid Build Coastguard Worker result += dict->trie.pool_capacity * sizeof(BrotliTrieNode);
2207*6777b538SAndroid Build Coastguard Worker if (dict->hash_table_data_words_) {
2208*6777b538SAndroid Build Coastguard Worker result += sizeof(kStaticDictionaryHashWords);
2209*6777b538SAndroid Build Coastguard Worker }
2210*6777b538SAndroid Build Coastguard Worker if (dict->hash_table_data_lengths_) {
2211*6777b538SAndroid Build Coastguard Worker result += sizeof(kStaticDictionaryHashLengths);
2212*6777b538SAndroid Build Coastguard Worker }
2213*6777b538SAndroid Build Coastguard Worker if (dict->buckets_data_) {
2214*6777b538SAndroid Build Coastguard Worker result += sizeof(*dict->buckets_data_) * dict->buckets_alloc_size_;
2215*6777b538SAndroid Build Coastguard Worker }
2216*6777b538SAndroid Build Coastguard Worker if (dict->dict_words_data_) {
2217*6777b538SAndroid Build Coastguard Worker result += sizeof(*dict->dict_words) * dict->dict_words_alloc_size_;
2218*6777b538SAndroid Build Coastguard Worker }
2219*6777b538SAndroid Build Coastguard Worker if (dict->words_instance_) {
2220*6777b538SAndroid Build Coastguard Worker result += sizeof(*dict->words_instance_);
2221*6777b538SAndroid Build Coastguard Worker /* data_size not added here: it is never allocated by the
2222*6777b538SAndroid Build Coastguard Worker SharedEncoderDictionary, instead it always points to the file
2223*6777b538SAndroid Build Coastguard Worker already loaded in memory. So if the caller wants to include
2224*6777b538SAndroid Build Coastguard Worker this memory as well, add the size of the loaded dictionary
2225*6777b538SAndroid Build Coastguard Worker file to this. */
2226*6777b538SAndroid Build Coastguard Worker }
2227*6777b538SAndroid Build Coastguard Worker }
2228*6777b538SAndroid Build Coastguard Worker return result + overhead;
2229*6777b538SAndroid Build Coastguard Worker }
2230*6777b538SAndroid Build Coastguard Worker return 0; /* error */
2231*6777b538SAndroid Build Coastguard Worker }
2232*6777b538SAndroid Build Coastguard Worker
2233*6777b538SAndroid Build Coastguard Worker #if defined(BROTLI_TEST)
2234*6777b538SAndroid Build Coastguard Worker size_t MakeUncompressedStreamForTest(const uint8_t*, size_t, uint8_t*);
MakeUncompressedStreamForTest(const uint8_t * input,size_t input_size,uint8_t * output)2235*6777b538SAndroid Build Coastguard Worker size_t MakeUncompressedStreamForTest(
2236*6777b538SAndroid Build Coastguard Worker const uint8_t* input, size_t input_size, uint8_t* output) {
2237*6777b538SAndroid Build Coastguard Worker return MakeUncompressedStream(input, input_size, output);
2238*6777b538SAndroid Build Coastguard Worker }
2239*6777b538SAndroid Build Coastguard Worker #endif
2240*6777b538SAndroid Build Coastguard Worker
2241*6777b538SAndroid Build Coastguard Worker #if defined(__cplusplus) || defined(c_plusplus)
2242*6777b538SAndroid Build Coastguard Worker } /* extern "C" */
2243*6777b538SAndroid Build Coastguard Worker #endif
2244