brotli 0.2.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +37 -0
- data/.github/workflows/publish.yml +24 -0
- data/.gitmodules +1 -1
- data/Gemfile +6 -3
- data/README.md +2 -2
- data/Rakefile +16 -9
- data/brotli.gemspec +7 -13
- data/ext/brotli/brotli.c +210 -31
- data/ext/brotli/buffer.c +1 -7
- data/ext/brotli/buffer.h +1 -1
- data/ext/brotli/extconf.rb +25 -17
- data/lib/brotli/version.rb +1 -1
- data/test/brotli_test.rb +107 -0
- data/test/brotli_writer_test.rb +36 -0
- data/test/test_helper.rb +8 -0
- data/vendor/brotli/c/common/constants.c +15 -0
- data/vendor/brotli/c/common/constants.h +137 -0
- data/vendor/brotli/c/common/context.c +156 -0
- data/vendor/brotli/c/common/context.h +4 -152
- data/vendor/brotli/c/common/dictionary.bin.br +0 -0
- data/vendor/brotli/c/common/dictionary.c +14 -3
- data/vendor/brotli/c/common/platform.c +23 -0
- data/vendor/brotli/c/common/platform.h +95 -122
- data/vendor/brotli/c/common/shared_dictionary.c +521 -0
- data/vendor/brotli/c/common/shared_dictionary_internal.h +75 -0
- data/vendor/brotli/c/common/transform.c +60 -4
- data/vendor/brotli/c/common/transform.h +5 -0
- data/vendor/brotli/c/common/version.h +31 -6
- data/vendor/brotli/c/dec/bit_reader.c +34 -4
- data/vendor/brotli/c/dec/bit_reader.h +221 -107
- data/vendor/brotli/c/dec/decode.c +772 -403
- data/vendor/brotli/c/dec/huffman.c +7 -4
- data/vendor/brotli/c/dec/huffman.h +8 -13
- data/vendor/brotli/c/dec/prefix.h +1 -18
- data/vendor/brotli/c/dec/state.c +40 -21
- data/vendor/brotli/c/dec/state.h +201 -59
- data/vendor/brotli/c/enc/backward_references.c +88 -25
- data/vendor/brotli/c/enc/backward_references.h +10 -8
- data/vendor/brotli/c/enc/backward_references_hq.c +194 -80
- data/vendor/brotli/c/enc/backward_references_hq.h +17 -13
- data/vendor/brotli/c/enc/backward_references_inc.h +52 -16
- data/vendor/brotli/c/enc/bit_cost.c +8 -7
- data/vendor/brotli/c/enc/bit_cost.h +5 -4
- data/vendor/brotli/c/enc/block_splitter.c +40 -17
- data/vendor/brotli/c/enc/block_splitter.h +5 -4
- data/vendor/brotli/c/enc/block_splitter_inc.h +99 -49
- data/vendor/brotli/c/enc/brotli_bit_stream.c +142 -137
- data/vendor/brotli/c/enc/brotli_bit_stream.h +11 -6
- data/vendor/brotli/c/enc/cluster.c +10 -9
- data/vendor/brotli/c/enc/cluster.h +7 -6
- data/vendor/brotli/c/enc/cluster_inc.h +30 -22
- data/vendor/brotli/c/enc/command.c +28 -0
- data/vendor/brotli/c/enc/command.h +17 -16
- data/vendor/brotli/c/enc/compound_dictionary.c +207 -0
- data/vendor/brotli/c/enc/compound_dictionary.h +74 -0
- data/vendor/brotli/c/enc/compress_fragment.c +93 -83
- data/vendor/brotli/c/enc/compress_fragment.h +32 -7
- data/vendor/brotli/c/enc/compress_fragment_two_pass.c +100 -88
- data/vendor/brotli/c/enc/compress_fragment_two_pass.h +21 -3
- data/vendor/brotli/c/enc/dictionary_hash.c +1829 -1101
- data/vendor/brotli/c/enc/dictionary_hash.h +2 -1
- data/vendor/brotli/c/enc/encode.c +550 -416
- data/vendor/brotli/c/enc/encoder_dict.c +613 -5
- data/vendor/brotli/c/enc/encoder_dict.h +120 -4
- data/vendor/brotli/c/enc/entropy_encode.c +5 -2
- data/vendor/brotli/c/enc/entropy_encode.h +4 -3
- data/vendor/brotli/c/enc/entropy_encode_static.h +5 -2
- data/vendor/brotli/c/enc/fast_log.c +105 -0
- data/vendor/brotli/c/enc/fast_log.h +21 -101
- data/vendor/brotli/c/enc/find_match_length.h +17 -25
- data/vendor/brotli/c/enc/hash.h +350 -120
- data/vendor/brotli/c/enc/hash_composite_inc.h +71 -67
- data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +92 -51
- data/vendor/brotli/c/enc/hash_longest_match64_inc.h +79 -84
- data/vendor/brotli/c/enc/hash_longest_match_inc.h +53 -54
- data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +93 -62
- data/vendor/brotli/c/enc/hash_rolling_inc.h +25 -29
- data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +42 -40
- data/vendor/brotli/c/enc/histogram.c +4 -4
- data/vendor/brotli/c/enc/histogram.h +7 -6
- data/vendor/brotli/c/enc/literal_cost.c +20 -15
- data/vendor/brotli/c/enc/literal_cost.h +4 -2
- data/vendor/brotli/c/enc/memory.c +29 -5
- data/vendor/brotli/c/enc/memory.h +43 -14
- data/vendor/brotli/c/enc/metablock.c +95 -85
- data/vendor/brotli/c/enc/metablock.h +9 -8
- data/vendor/brotli/c/enc/metablock_inc.h +9 -7
- data/vendor/brotli/c/enc/params.h +7 -4
- data/vendor/brotli/c/enc/prefix.h +3 -2
- data/vendor/brotli/c/enc/quality.h +40 -3
- data/vendor/brotli/c/enc/ringbuffer.h +8 -4
- data/vendor/brotli/c/enc/state.h +104 -0
- data/vendor/brotli/c/enc/static_dict.c +60 -4
- data/vendor/brotli/c/enc/static_dict.h +3 -2
- data/vendor/brotli/c/enc/static_dict_lut.h +2 -0
- data/vendor/brotli/c/enc/utf8_util.c +2 -2
- data/vendor/brotli/c/enc/utf8_util.h +2 -1
- data/vendor/brotli/c/enc/write_bits.h +29 -26
- data/vendor/brotli/c/include/brotli/decode.h +67 -2
- data/vendor/brotli/c/include/brotli/encode.h +77 -3
- data/vendor/brotli/c/include/brotli/port.h +34 -3
- data/vendor/brotli/c/include/brotli/shared_dictionary.h +100 -0
- metadata +23 -97
- data/.travis.yml +0 -31
- data/docs/Brotli/Error.html +0 -124
- data/docs/Brotli.html +0 -485
- data/docs/_index.html +0 -122
- data/docs/class_list.html +0 -51
- data/docs/css/common.css +0 -1
- data/docs/css/full_list.css +0 -58
- data/docs/css/style.css +0 -496
- data/docs/file.README.html +0 -127
- data/docs/file_list.html +0 -56
- data/docs/frames.html +0 -17
- data/docs/index.html +0 -127
- data/docs/js/app.js +0 -292
- data/docs/js/full_list.js +0 -216
- data/docs/js/jquery.js +0 -4
- data/docs/method_list.html +0 -67
- data/docs/top-level-namespace.html +0 -110
- data/spec/brotli_spec.rb +0 -88
- data/spec/inflate_spec.rb +0 -75
- data/spec/spec_helper.rb +0 -4
@@ -6,26 +6,30 @@
|
|
6
6
|
|
7
7
|
/* Function to find backward reference copies. */
|
8
8
|
|
9
|
-
#include "
|
9
|
+
#include "backward_references_hq.h"
|
10
10
|
|
11
11
|
#include <string.h> /* memcpy, memset */
|
12
12
|
|
13
|
+
#include <brotli/types.h>
|
14
|
+
|
13
15
|
#include "../common/constants.h"
|
14
16
|
#include "../common/platform.h"
|
15
|
-
#include
|
16
|
-
#include "
|
17
|
-
#include "
|
18
|
-
#include "
|
19
|
-
#include "
|
20
|
-
#include "
|
21
|
-
#include "
|
22
|
-
#include "
|
23
|
-
#include "
|
17
|
+
#include "command.h"
|
18
|
+
#include "compound_dictionary.h"
|
19
|
+
#include "encoder_dict.h"
|
20
|
+
#include "fast_log.h"
|
21
|
+
#include "find_match_length.h"
|
22
|
+
#include "literal_cost.h"
|
23
|
+
#include "memory.h"
|
24
|
+
#include "params.h"
|
25
|
+
#include "prefix.h"
|
26
|
+
#include "quality.h"
|
24
27
|
|
25
28
|
#if defined(__cplusplus) || defined(c_plusplus)
|
26
29
|
extern "C" {
|
27
30
|
#endif
|
28
31
|
|
32
|
+
/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */
|
29
33
|
#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544
|
30
34
|
|
31
35
|
static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */
|
@@ -71,6 +75,14 @@ static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
|
|
71
75
|
return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF);
|
72
76
|
}
|
73
77
|
|
78
|
+
/* Temporary data for ZopfliCostModelSetFromCommands. */
|
79
|
+
typedef struct ZopfliCostModelArena {
|
80
|
+
uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
81
|
+
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
|
82
|
+
uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
|
83
|
+
float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
84
|
+
} ZopfliCostModelArena;
|
85
|
+
|
74
86
|
/* Histogram based cost model for zopflification. */
|
75
87
|
typedef struct ZopfliCostModel {
|
76
88
|
/* The insert and copy length symbols. */
|
@@ -81,19 +93,21 @@ typedef struct ZopfliCostModel {
|
|
81
93
|
float* literal_costs_;
|
82
94
|
float min_cost_cmd_;
|
83
95
|
size_t num_bytes_;
|
96
|
+
|
97
|
+
/* Temporary data. */
|
98
|
+
union {
|
99
|
+
size_t literal_histograms[3 * 256];
|
100
|
+
ZopfliCostModelArena arena;
|
101
|
+
};
|
84
102
|
} ZopfliCostModel;
|
85
103
|
|
86
104
|
static void InitZopfliCostModel(
|
87
105
|
MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist,
|
88
106
|
size_t num_bytes) {
|
89
|
-
uint32_t distance_histogram_size = dist->alphabet_size;
|
90
|
-
if (distance_histogram_size > BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE) {
|
91
|
-
distance_histogram_size = BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE;
|
92
|
-
}
|
93
107
|
self->num_bytes_ = num_bytes;
|
94
108
|
self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2);
|
95
|
-
self->cost_dist_ = BROTLI_ALLOC(m, float, dist->
|
96
|
-
self->distance_histogram_size =
|
109
|
+
self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit);
|
110
|
+
self->distance_histogram_size = dist->alphabet_size_limit;
|
97
111
|
if (BROTLI_IS_OOM(m)) return;
|
98
112
|
}
|
99
113
|
|
@@ -141,18 +155,15 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
|
141
155
|
const Command* commands,
|
142
156
|
size_t num_commands,
|
143
157
|
size_t last_insert_len) {
|
144
|
-
|
145
|
-
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
|
146
|
-
uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
|
147
|
-
float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
158
|
+
ZopfliCostModelArena* arena = &self->arena;
|
148
159
|
size_t pos = position - last_insert_len;
|
149
160
|
float min_cost_cmd = kInfinity;
|
150
161
|
size_t i;
|
151
162
|
float* cost_cmd = self->cost_cmd_;
|
152
163
|
|
153
|
-
memset(histogram_literal, 0, sizeof(histogram_literal));
|
154
|
-
memset(histogram_cmd, 0, sizeof(histogram_cmd));
|
155
|
-
memset(histogram_dist, 0, sizeof(histogram_dist));
|
164
|
+
memset(arena->histogram_literal, 0, sizeof(arena->histogram_literal));
|
165
|
+
memset(arena->histogram_cmd, 0, sizeof(arena->histogram_cmd));
|
166
|
+
memset(arena->histogram_dist, 0, sizeof(arena->histogram_dist));
|
156
167
|
|
157
168
|
for (i = 0; i < num_commands; i++) {
|
158
169
|
size_t inslength = commands[i].insert_len_;
|
@@ -161,21 +172,21 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
|
161
172
|
size_t cmdcode = commands[i].cmd_prefix_;
|
162
173
|
size_t j;
|
163
174
|
|
164
|
-
histogram_cmd[cmdcode]++;
|
165
|
-
if (cmdcode >= 128) histogram_dist[distcode]++;
|
175
|
+
arena->histogram_cmd[cmdcode]++;
|
176
|
+
if (cmdcode >= 128) arena->histogram_dist[distcode]++;
|
166
177
|
|
167
178
|
for (j = 0; j < inslength; j++) {
|
168
|
-
histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
|
179
|
+
arena->histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
|
169
180
|
}
|
170
181
|
|
171
182
|
pos += inslength + copylength;
|
172
183
|
}
|
173
184
|
|
174
|
-
SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
|
175
|
-
cost_literal);
|
176
|
-
SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
|
185
|
+
SetCost(arena->histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
|
186
|
+
arena->cost_literal);
|
187
|
+
SetCost(arena->histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
|
177
188
|
cost_cmd);
|
178
|
-
SetCost(histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
|
189
|
+
SetCost(arena->histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
|
179
190
|
self->cost_dist_);
|
180
191
|
|
181
192
|
for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
|
@@ -190,7 +201,7 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
|
190
201
|
literal_costs[0] = 0.0;
|
191
202
|
for (i = 0; i < num_bytes; ++i) {
|
192
203
|
literal_carry +=
|
193
|
-
cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
204
|
+
arena->cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
194
205
|
literal_costs[i + 1] = literal_costs[i] + literal_carry;
|
195
206
|
literal_carry -= literal_costs[i + 1] - literal_costs[i];
|
196
207
|
}
|
@@ -208,7 +219,8 @@ static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
|
|
208
219
|
size_t num_bytes = self->num_bytes_;
|
209
220
|
size_t i;
|
210
221
|
BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask,
|
211
|
-
ringbuffer,
|
222
|
+
ringbuffer, self->literal_histograms,
|
223
|
+
&literal_costs[1]);
|
212
224
|
literal_costs[0] = 0.0;
|
213
225
|
for (i = 0; i < num_bytes; ++i) {
|
214
226
|
literal_carry += literal_costs[i + 1];
|
@@ -408,19 +420,23 @@ static size_t UpdateNodes(
|
|
408
420
|
const int* starting_dist_cache, const size_t num_matches,
|
409
421
|
const BackwardMatch* matches, const ZopfliCostModel* model,
|
410
422
|
StartPosQueue* queue, ZopfliNode* nodes) {
|
423
|
+
const size_t stream_offset = params->stream_offset;
|
411
424
|
const size_t cur_ix = block_start + pos;
|
412
425
|
const size_t cur_ix_masked = cur_ix & ringbuffer_mask;
|
413
426
|
const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit);
|
427
|
+
const size_t dictionary_start = BROTLI_MIN(size_t,
|
428
|
+
cur_ix + stream_offset, max_backward_limit);
|
414
429
|
const size_t max_len = num_bytes - pos;
|
415
430
|
const size_t max_zopfli_len = MaxZopfliLen(params);
|
416
431
|
const size_t max_iters = MaxZopfliCandidates(params);
|
417
432
|
size_t min_len;
|
418
433
|
size_t result = 0;
|
419
434
|
size_t k;
|
420
|
-
|
435
|
+
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
436
|
+
size_t gap = addon->total_size;
|
421
437
|
|
422
|
-
EvaluateNode(block_start, pos, max_backward_limit, gap,
|
423
|
-
model, queue, nodes);
|
438
|
+
EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
|
439
|
+
starting_dist_cache, model, queue, nodes);
|
424
440
|
|
425
441
|
{
|
426
442
|
const PosData* posdata = StartPosQueueAt(queue, 0);
|
@@ -453,7 +469,7 @@ static size_t UpdateNodes(
|
|
453
469
|
if (cur_ix_masked + best_len > ringbuffer_mask) {
|
454
470
|
break;
|
455
471
|
}
|
456
|
-
if (BROTLI_PREDICT_FALSE(backward >
|
472
|
+
if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) {
|
457
473
|
/* Word dictionary -> ignore. */
|
458
474
|
continue;
|
459
475
|
}
|
@@ -471,7 +487,27 @@ static size_t UpdateNodes(
|
|
471
487
|
len = FindMatchLengthWithLimit(&ringbuffer[prev_ix],
|
472
488
|
&ringbuffer[cur_ix_masked],
|
473
489
|
max_len);
|
490
|
+
} else if (backward > dictionary_start) {
|
491
|
+
size_t d = 0;
|
492
|
+
size_t offset;
|
493
|
+
size_t limit;
|
494
|
+
const uint8_t* source;
|
495
|
+
offset = dictionary_start + 1 + addon->total_size - 1;
|
496
|
+
while (offset >= backward + addon->chunk_offsets[d + 1]) d++;
|
497
|
+
source = addon->chunk_source[d];
|
498
|
+
offset = offset - addon->chunk_offsets[d] - backward;
|
499
|
+
limit = addon->chunk_offsets[d + 1] - addon->chunk_offsets[d] - offset;
|
500
|
+
limit = limit > max_len ? max_len : limit;
|
501
|
+
if (best_len >= limit ||
|
502
|
+
continuation != source[offset + best_len]) {
|
503
|
+
continue;
|
504
|
+
}
|
505
|
+
len = FindMatchLengthWithLimit(&source[offset],
|
506
|
+
&ringbuffer[cur_ix_masked],
|
507
|
+
limit);
|
474
508
|
} else {
|
509
|
+
/* "Gray" area. It is addressable by decoder, but this encoder
|
510
|
+
instance does not have that data -> should not touch it. */
|
475
511
|
continue;
|
476
512
|
}
|
477
513
|
{
|
@@ -506,7 +542,7 @@ static size_t UpdateNodes(
|
|
506
542
|
BackwardMatch match = matches[j];
|
507
543
|
size_t dist = match.distance;
|
508
544
|
BROTLI_BOOL is_dictionary_match =
|
509
|
-
TO_BROTLI_BOOL(dist >
|
545
|
+
TO_BROTLI_BOOL(dist > dictionary_start + gap);
|
510
546
|
/* We already tried all possible last distance matches, so we can use
|
511
547
|
normal distance code here. */
|
512
548
|
size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
|
@@ -569,11 +605,12 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
|
569
605
|
const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
|
570
606
|
size_t* last_insert_len, const BrotliEncoderParams* params,
|
571
607
|
Command* commands, size_t* num_literals) {
|
608
|
+
const size_t stream_offset = params->stream_offset;
|
572
609
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
573
610
|
size_t pos = 0;
|
574
611
|
uint32_t offset = nodes[0].u.next;
|
575
612
|
size_t i;
|
576
|
-
size_t gap =
|
613
|
+
size_t gap = params->dictionary.compound.total_size;
|
577
614
|
for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
|
578
615
|
const ZopfliNode* next = &nodes[pos + offset];
|
579
616
|
size_t copy_length = ZopfliNodeCopyLength(next);
|
@@ -587,9 +624,10 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
|
587
624
|
{
|
588
625
|
size_t distance = ZopfliNodeCopyDistance(next);
|
589
626
|
size_t len_code = ZopfliNodeLengthCode(next);
|
590
|
-
size_t
|
591
|
-
|
592
|
-
BROTLI_BOOL is_dictionary =
|
627
|
+
size_t dictionary_start = BROTLI_MIN(size_t,
|
628
|
+
block_start + pos + stream_offset, max_backward_limit);
|
629
|
+
BROTLI_BOOL is_dictionary =
|
630
|
+
TO_BROTLI_BOOL(distance > dictionary_start + gap);
|
593
631
|
size_t dist_code = ZopfliNodeDistanceCode(next);
|
594
632
|
InitCommand(&commands[i], ¶ms->dist, insert_length,
|
595
633
|
copy_length, (int)len_code - (int)copy_length, dist_code);
|
@@ -613,6 +651,7 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
|
613
651
|
const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
|
614
652
|
const ZopfliCostModel* model, const uint32_t* num_matches,
|
615
653
|
const BackwardMatch* matches, ZopfliNode* nodes) {
|
654
|
+
const size_t stream_offset = params->stream_offset;
|
616
655
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
617
656
|
const size_t max_zopfli_len = MaxZopfliLen(params);
|
618
657
|
StartPosQueue queue;
|
@@ -637,7 +676,7 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
|
637
676
|
while (skip) {
|
638
677
|
i++;
|
639
678
|
if (i + 3 >= num_bytes) break;
|
640
|
-
EvaluateNode(position, i, max_backward_limit, gap,
|
679
|
+
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
641
680
|
dist_cache, model, &queue, nodes);
|
642
681
|
cur_match_pos += num_matches[i];
|
643
682
|
skip--;
|
@@ -647,44 +686,88 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
|
647
686
|
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
648
687
|
}
|
649
688
|
|
689
|
+
static void MergeMatches(BackwardMatch* dst,
|
690
|
+
BackwardMatch* src1, size_t len1, BackwardMatch* src2, size_t len2) {
|
691
|
+
while (len1 > 0 && len2 > 0) {
|
692
|
+
size_t l1 = BackwardMatchLength(src1);
|
693
|
+
size_t l2 = BackwardMatchLength(src2);
|
694
|
+
if (l1 < l2 || ((l1 == l2) && (src1->distance < src2->distance))) {
|
695
|
+
*dst++ = *src1++;
|
696
|
+
len1--;
|
697
|
+
} else {
|
698
|
+
*dst++ = *src2++;
|
699
|
+
len2--;
|
700
|
+
}
|
701
|
+
}
|
702
|
+
while (len1-- > 0) *dst++ = *src1++;
|
703
|
+
while (len2-- > 0) *dst++ = *src2++;
|
704
|
+
}
|
705
|
+
|
650
706
|
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
651
707
|
size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
652
708
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
653
|
-
const BrotliEncoderParams* params,
|
654
|
-
const int* dist_cache,
|
709
|
+
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
710
|
+
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) {
|
711
|
+
const size_t stream_offset = params->stream_offset;
|
655
712
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
656
713
|
const size_t max_zopfli_len = MaxZopfliLen(params);
|
657
|
-
ZopfliCostModel model;
|
658
714
|
StartPosQueue queue;
|
659
|
-
BackwardMatch
|
715
|
+
BackwardMatch* BROTLI_RESTRICT matches =
|
716
|
+
BROTLI_ALLOC(m, BackwardMatch, 2 * (MAX_NUM_MATCHES_H10 + 64));
|
660
717
|
const size_t store_end = num_bytes >= StoreLookaheadH10() ?
|
661
718
|
position + num_bytes - StoreLookaheadH10() + 1 : position;
|
662
719
|
size_t i;
|
663
|
-
|
664
|
-
size_t
|
720
|
+
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
721
|
+
size_t gap = addon->total_size;
|
722
|
+
size_t lz_matches_offset =
|
723
|
+
(addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0;
|
724
|
+
ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1);
|
725
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) || BROTLI_IS_NULL(matches)) {
|
726
|
+
return 0;
|
727
|
+
}
|
665
728
|
nodes[0].length = 0;
|
666
729
|
nodes[0].u.cost = 0;
|
667
|
-
InitZopfliCostModel(m,
|
730
|
+
InitZopfliCostModel(m, model, ¶ms->dist, num_bytes);
|
668
731
|
if (BROTLI_IS_OOM(m)) return 0;
|
669
732
|
ZopfliCostModelSetFromLiteralCosts(
|
670
|
-
|
733
|
+
model, position, ringbuffer, ringbuffer_mask);
|
671
734
|
InitStartPosQueue(&queue);
|
672
735
|
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
|
673
736
|
const size_t pos = position + i;
|
674
737
|
const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
738
|
+
const size_t dictionary_start = BROTLI_MIN(size_t,
|
739
|
+
pos + stream_offset, max_backward_limit);
|
675
740
|
size_t skip;
|
676
741
|
size_t num_matches;
|
677
|
-
|
678
|
-
|
742
|
+
int dict_id = 0;
|
743
|
+
if (params->dictionary.contextual.context_based) {
|
744
|
+
uint8_t p1 = pos >= 1 ?
|
745
|
+
ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0;
|
746
|
+
uint8_t p2 = pos >= 2 ?
|
747
|
+
ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0;
|
748
|
+
dict_id = params->dictionary.contextual.context_map[
|
749
|
+
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
750
|
+
}
|
751
|
+
num_matches = FindAllMatchesH10(&hasher->privat._H10,
|
752
|
+
params->dictionary.contextual.dict[dict_id],
|
679
753
|
ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
|
680
|
-
gap, params, &matches[lz_matches_offset]);
|
754
|
+
dictionary_start + gap, params, &matches[lz_matches_offset]);
|
755
|
+
if (addon->num_chunks != 0) {
|
756
|
+
size_t cd_matches = LookupAllCompoundDictionaryMatches(addon,
|
757
|
+
ringbuffer, ringbuffer_mask, pos, 3, num_bytes - i,
|
758
|
+
dictionary_start, params->dist.max_distance,
|
759
|
+
&matches[lz_matches_offset - 64], 64);
|
760
|
+
MergeMatches(matches, &matches[lz_matches_offset - 64], cd_matches,
|
761
|
+
&matches[lz_matches_offset], num_matches);
|
762
|
+
num_matches += cd_matches;
|
763
|
+
}
|
681
764
|
if (num_matches > 0 &&
|
682
765
|
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
|
683
766
|
matches[0] = matches[num_matches - 1];
|
684
767
|
num_matches = 1;
|
685
768
|
}
|
686
769
|
skip = UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask,
|
687
|
-
params, max_backward_limit, dist_cache, num_matches, matches,
|
770
|
+
params, max_backward_limit, dist_cache, num_matches, matches, model,
|
688
771
|
&queue, nodes);
|
689
772
|
if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
|
690
773
|
if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) {
|
@@ -692,33 +775,35 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
|
692
775
|
}
|
693
776
|
if (skip > 1) {
|
694
777
|
/* Add the tail of the copy to the hasher. */
|
695
|
-
StoreRangeH10(hasher,
|
778
|
+
StoreRangeH10(&hasher->privat._H10,
|
779
|
+
ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
|
696
780
|
size_t, pos + skip, store_end));
|
697
781
|
skip--;
|
698
782
|
while (skip) {
|
699
783
|
i++;
|
700
784
|
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
|
701
|
-
EvaluateNode(position, i, max_backward_limit, gap,
|
702
|
-
dist_cache,
|
785
|
+
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
786
|
+
dist_cache, model, &queue, nodes);
|
703
787
|
skip--;
|
704
788
|
}
|
705
789
|
}
|
706
790
|
}
|
707
|
-
CleanupZopfliCostModel(m,
|
791
|
+
CleanupZopfliCostModel(m, model);
|
792
|
+
BROTLI_FREE(m, model);
|
793
|
+
BROTLI_FREE(m, matches);
|
708
794
|
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
709
795
|
}
|
710
796
|
|
711
797
|
void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
712
798
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
713
|
-
const BrotliEncoderParams* params,
|
714
|
-
|
799
|
+
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
800
|
+
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
715
801
|
Command* commands, size_t* num_commands, size_t* num_literals) {
|
716
|
-
ZopfliNode* nodes;
|
717
|
-
|
718
|
-
if (BROTLI_IS_OOM(m)) return;
|
802
|
+
ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
803
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
719
804
|
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
720
805
|
*num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
|
721
|
-
position, ringbuffer, ringbuffer_mask, params,
|
806
|
+
position, ringbuffer, ringbuffer_mask, literal_context_lut, params,
|
722
807
|
dist_cache, hasher, nodes);
|
723
808
|
if (BROTLI_IS_OOM(m)) return;
|
724
809
|
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
@@ -728,9 +813,10 @@ void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|
728
813
|
|
729
814
|
void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
730
815
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
731
|
-
const BrotliEncoderParams* params,
|
732
|
-
|
816
|
+
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
817
|
+
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
733
818
|
Command* commands, size_t* num_commands, size_t* num_literals) {
|
819
|
+
const size_t stream_offset = params->stream_offset;
|
734
820
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
735
821
|
uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes);
|
736
822
|
size_t matches_size = 4 * num_bytes;
|
@@ -742,28 +828,54 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|
742
828
|
size_t orig_last_insert_len;
|
743
829
|
int orig_dist_cache[4];
|
744
830
|
size_t orig_num_commands;
|
745
|
-
ZopfliCostModel model;
|
831
|
+
ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1);
|
746
832
|
ZopfliNode* nodes;
|
747
833
|
BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
|
748
|
-
|
749
|
-
size_t
|
750
|
-
|
834
|
+
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
835
|
+
size_t gap = addon->total_size;
|
836
|
+
size_t shadow_matches =
|
837
|
+
(addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0;
|
838
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) ||
|
839
|
+
BROTLI_IS_NULL(num_matches) || BROTLI_IS_NULL(matches)) {
|
840
|
+
return;
|
841
|
+
}
|
751
842
|
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
|
752
843
|
const size_t pos = position + i;
|
753
844
|
size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
845
|
+
size_t dictionary_start = BROTLI_MIN(size_t,
|
846
|
+
pos + stream_offset, max_backward_limit);
|
754
847
|
size_t max_length = num_bytes - i;
|
755
848
|
size_t num_found_matches;
|
756
849
|
size_t cur_match_end;
|
757
850
|
size_t j;
|
851
|
+
int dict_id = 0;
|
852
|
+
if (params->dictionary.contextual.context_based) {
|
853
|
+
uint8_t p1 = pos >= 1 ?
|
854
|
+
ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0;
|
855
|
+
uint8_t p2 = pos >= 2 ?
|
856
|
+
ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0;
|
857
|
+
dict_id = params->dictionary.contextual.context_map[
|
858
|
+
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
859
|
+
}
|
758
860
|
/* Ensure that we have enough free slots. */
|
759
861
|
BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
|
760
862
|
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
|
761
863
|
if (BROTLI_IS_OOM(m)) return;
|
762
|
-
num_found_matches = FindAllMatchesH10(hasher,
|
763
|
-
|
864
|
+
num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
|
865
|
+
params->dictionary.contextual.dict[dict_id],
|
764
866
|
ringbuffer, ringbuffer_mask, pos, max_length,
|
765
|
-
max_distance, gap, params,
|
867
|
+
max_distance, dictionary_start + gap, params,
|
766
868
|
&matches[cur_match_pos + shadow_matches]);
|
869
|
+
if (addon->num_chunks != 0) {
|
870
|
+
size_t cd_matches = LookupAllCompoundDictionaryMatches(addon,
|
871
|
+
ringbuffer, ringbuffer_mask, pos, 3, max_length,
|
872
|
+
dictionary_start, params->dist.max_distance,
|
873
|
+
&matches[cur_match_pos + shadow_matches - 64], 64);
|
874
|
+
MergeMatches(&matches[cur_match_pos],
|
875
|
+
&matches[cur_match_pos + shadow_matches - 64], cd_matches,
|
876
|
+
&matches[cur_match_pos + shadow_matches], num_found_matches);
|
877
|
+
num_found_matches += cd_matches;
|
878
|
+
}
|
767
879
|
cur_match_end = cur_match_pos + num_found_matches;
|
768
880
|
for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
|
769
881
|
BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
|
@@ -777,7 +889,8 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|
777
889
|
matches[cur_match_pos++] = matches[cur_match_end - 1];
|
778
890
|
num_matches[i] = 1;
|
779
891
|
/* Add the tail of the copy to the hasher. */
|
780
|
-
StoreRangeH10(hasher,
|
892
|
+
StoreRangeH10(&hasher->privat._H10,
|
893
|
+
ringbuffer, ringbuffer_mask, pos + 1,
|
781
894
|
BROTLI_MIN(size_t, pos + match_len, store_end));
|
782
895
|
memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0]));
|
783
896
|
i += skip;
|
@@ -791,16 +904,16 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|
791
904
|
memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
|
792
905
|
orig_num_commands = *num_commands;
|
793
906
|
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
794
|
-
if (BROTLI_IS_OOM(m)) return;
|
795
|
-
InitZopfliCostModel(m,
|
907
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
908
|
+
InitZopfliCostModel(m, model, ¶ms->dist, num_bytes);
|
796
909
|
if (BROTLI_IS_OOM(m)) return;
|
797
910
|
for (i = 0; i < 2; i++) {
|
798
911
|
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
799
912
|
if (i == 0) {
|
800
913
|
ZopfliCostModelSetFromLiteralCosts(
|
801
|
-
|
914
|
+
model, position, ringbuffer, ringbuffer_mask);
|
802
915
|
} else {
|
803
|
-
ZopfliCostModelSetFromCommands(
|
916
|
+
ZopfliCostModelSetFromCommands(model, position, ringbuffer,
|
804
917
|
ringbuffer_mask, commands, *num_commands - orig_num_commands,
|
805
918
|
orig_last_insert_len);
|
806
919
|
}
|
@@ -809,12 +922,13 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|
809
922
|
*last_insert_len = orig_last_insert_len;
|
810
923
|
memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
|
811
924
|
*num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
|
812
|
-
ringbuffer_mask, params, gap, dist_cache,
|
925
|
+
ringbuffer_mask, params, gap, dist_cache, model, num_matches, matches,
|
813
926
|
nodes);
|
814
927
|
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
815
928
|
last_insert_len, params, commands, num_literals);
|
816
929
|
}
|
817
|
-
CleanupZopfliCostModel(m,
|
930
|
+
CleanupZopfliCostModel(m, model);
|
931
|
+
BROTLI_FREE(m, model);
|
818
932
|
BROTLI_FREE(m, nodes);
|
819
933
|
BROTLI_FREE(m, matches);
|
820
934
|
BROTLI_FREE(m, num_matches);
|
@@ -9,29 +9,33 @@
|
|
9
9
|
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
10
10
|
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
11
11
|
|
12
|
+
#include <brotli/types.h>
|
13
|
+
|
12
14
|
#include "../common/constants.h"
|
15
|
+
#include "../common/context.h"
|
13
16
|
#include "../common/dictionary.h"
|
14
17
|
#include "../common/platform.h"
|
15
|
-
#include
|
16
|
-
#include "
|
17
|
-
#include "
|
18
|
-
#include "
|
19
|
-
#include "./quality.h"
|
18
|
+
#include "command.h"
|
19
|
+
#include "hash.h"
|
20
|
+
#include "memory.h"
|
21
|
+
#include "quality.h"
|
20
22
|
|
21
23
|
#if defined(__cplusplus) || defined(c_plusplus)
|
22
24
|
extern "C" {
|
23
25
|
#endif
|
24
26
|
|
25
27
|
BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
|
26
|
-
size_t num_bytes,
|
27
|
-
size_t
|
28
|
-
|
28
|
+
size_t num_bytes,
|
29
|
+
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
30
|
+
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
31
|
+
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
29
32
|
Command* commands, size_t* num_commands, size_t* num_literals);
|
30
33
|
|
31
34
|
BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
32
|
-
size_t num_bytes,
|
33
|
-
size_t
|
34
|
-
|
35
|
+
size_t num_bytes,
|
36
|
+
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
37
|
+
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
38
|
+
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
35
39
|
Command* commands, size_t* num_commands, size_t* num_literals);
|
36
40
|
|
37
41
|
typedef struct ZopfliNode {
|
@@ -77,8 +81,8 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
|
|
77
81
|
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
|
78
82
|
MemoryManager* m, size_t num_bytes,
|
79
83
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
80
|
-
const BrotliEncoderParams* params,
|
81
|
-
const int* dist_cache,
|
84
|
+
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
85
|
+
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes);
|
82
86
|
|
83
87
|
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
|
84
88
|
const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes,
|