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.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +37 -0
  3. data/.github/workflows/publish.yml +24 -0
  4. data/.gitmodules +1 -1
  5. data/Gemfile +6 -3
  6. data/README.md +2 -2
  7. data/Rakefile +16 -9
  8. data/brotli.gemspec +7 -13
  9. data/ext/brotli/brotli.c +210 -31
  10. data/ext/brotli/buffer.c +1 -7
  11. data/ext/brotli/buffer.h +1 -1
  12. data/ext/brotli/extconf.rb +25 -17
  13. data/lib/brotli/version.rb +1 -1
  14. data/test/brotli_test.rb +107 -0
  15. data/test/brotli_writer_test.rb +36 -0
  16. data/test/test_helper.rb +8 -0
  17. data/vendor/brotli/c/common/constants.c +15 -0
  18. data/vendor/brotli/c/common/constants.h +137 -0
  19. data/vendor/brotli/c/common/context.c +156 -0
  20. data/vendor/brotli/c/common/context.h +4 -152
  21. data/vendor/brotli/c/common/dictionary.bin.br +0 -0
  22. data/vendor/brotli/c/common/dictionary.c +14 -3
  23. data/vendor/brotli/c/common/platform.c +23 -0
  24. data/vendor/brotli/c/common/platform.h +95 -122
  25. data/vendor/brotli/c/common/shared_dictionary.c +521 -0
  26. data/vendor/brotli/c/common/shared_dictionary_internal.h +75 -0
  27. data/vendor/brotli/c/common/transform.c +60 -4
  28. data/vendor/brotli/c/common/transform.h +5 -0
  29. data/vendor/brotli/c/common/version.h +31 -6
  30. data/vendor/brotli/c/dec/bit_reader.c +34 -4
  31. data/vendor/brotli/c/dec/bit_reader.h +221 -107
  32. data/vendor/brotli/c/dec/decode.c +772 -403
  33. data/vendor/brotli/c/dec/huffman.c +7 -4
  34. data/vendor/brotli/c/dec/huffman.h +8 -13
  35. data/vendor/brotli/c/dec/prefix.h +1 -18
  36. data/vendor/brotli/c/dec/state.c +40 -21
  37. data/vendor/brotli/c/dec/state.h +201 -59
  38. data/vendor/brotli/c/enc/backward_references.c +88 -25
  39. data/vendor/brotli/c/enc/backward_references.h +10 -8
  40. data/vendor/brotli/c/enc/backward_references_hq.c +194 -80
  41. data/vendor/brotli/c/enc/backward_references_hq.h +17 -13
  42. data/vendor/brotli/c/enc/backward_references_inc.h +52 -16
  43. data/vendor/brotli/c/enc/bit_cost.c +8 -7
  44. data/vendor/brotli/c/enc/bit_cost.h +5 -4
  45. data/vendor/brotli/c/enc/block_splitter.c +40 -17
  46. data/vendor/brotli/c/enc/block_splitter.h +5 -4
  47. data/vendor/brotli/c/enc/block_splitter_inc.h +99 -49
  48. data/vendor/brotli/c/enc/brotli_bit_stream.c +142 -137
  49. data/vendor/brotli/c/enc/brotli_bit_stream.h +11 -6
  50. data/vendor/brotli/c/enc/cluster.c +10 -9
  51. data/vendor/brotli/c/enc/cluster.h +7 -6
  52. data/vendor/brotli/c/enc/cluster_inc.h +30 -22
  53. data/vendor/brotli/c/enc/command.c +28 -0
  54. data/vendor/brotli/c/enc/command.h +17 -16
  55. data/vendor/brotli/c/enc/compound_dictionary.c +207 -0
  56. data/vendor/brotli/c/enc/compound_dictionary.h +74 -0
  57. data/vendor/brotli/c/enc/compress_fragment.c +93 -83
  58. data/vendor/brotli/c/enc/compress_fragment.h +32 -7
  59. data/vendor/brotli/c/enc/compress_fragment_two_pass.c +100 -88
  60. data/vendor/brotli/c/enc/compress_fragment_two_pass.h +21 -3
  61. data/vendor/brotli/c/enc/dictionary_hash.c +1829 -1101
  62. data/vendor/brotli/c/enc/dictionary_hash.h +2 -1
  63. data/vendor/brotli/c/enc/encode.c +550 -416
  64. data/vendor/brotli/c/enc/encoder_dict.c +613 -5
  65. data/vendor/brotli/c/enc/encoder_dict.h +120 -4
  66. data/vendor/brotli/c/enc/entropy_encode.c +5 -2
  67. data/vendor/brotli/c/enc/entropy_encode.h +4 -3
  68. data/vendor/brotli/c/enc/entropy_encode_static.h +5 -2
  69. data/vendor/brotli/c/enc/fast_log.c +105 -0
  70. data/vendor/brotli/c/enc/fast_log.h +21 -101
  71. data/vendor/brotli/c/enc/find_match_length.h +17 -25
  72. data/vendor/brotli/c/enc/hash.h +350 -120
  73. data/vendor/brotli/c/enc/hash_composite_inc.h +71 -67
  74. data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +92 -51
  75. data/vendor/brotli/c/enc/hash_longest_match64_inc.h +79 -84
  76. data/vendor/brotli/c/enc/hash_longest_match_inc.h +53 -54
  77. data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +93 -62
  78. data/vendor/brotli/c/enc/hash_rolling_inc.h +25 -29
  79. data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +42 -40
  80. data/vendor/brotli/c/enc/histogram.c +4 -4
  81. data/vendor/brotli/c/enc/histogram.h +7 -6
  82. data/vendor/brotli/c/enc/literal_cost.c +20 -15
  83. data/vendor/brotli/c/enc/literal_cost.h +4 -2
  84. data/vendor/brotli/c/enc/memory.c +29 -5
  85. data/vendor/brotli/c/enc/memory.h +43 -14
  86. data/vendor/brotli/c/enc/metablock.c +95 -85
  87. data/vendor/brotli/c/enc/metablock.h +9 -8
  88. data/vendor/brotli/c/enc/metablock_inc.h +9 -7
  89. data/vendor/brotli/c/enc/params.h +7 -4
  90. data/vendor/brotli/c/enc/prefix.h +3 -2
  91. data/vendor/brotli/c/enc/quality.h +40 -3
  92. data/vendor/brotli/c/enc/ringbuffer.h +8 -4
  93. data/vendor/brotli/c/enc/state.h +104 -0
  94. data/vendor/brotli/c/enc/static_dict.c +60 -4
  95. data/vendor/brotli/c/enc/static_dict.h +3 -2
  96. data/vendor/brotli/c/enc/static_dict_lut.h +2 -0
  97. data/vendor/brotli/c/enc/utf8_util.c +2 -2
  98. data/vendor/brotli/c/enc/utf8_util.h +2 -1
  99. data/vendor/brotli/c/enc/write_bits.h +29 -26
  100. data/vendor/brotli/c/include/brotli/decode.h +67 -2
  101. data/vendor/brotli/c/include/brotli/encode.h +77 -3
  102. data/vendor/brotli/c/include/brotli/port.h +34 -3
  103. data/vendor/brotli/c/include/brotli/shared_dictionary.h +100 -0
  104. metadata +23 -97
  105. data/.travis.yml +0 -31
  106. data/docs/Brotli/Error.html +0 -124
  107. data/docs/Brotli.html +0 -485
  108. data/docs/_index.html +0 -122
  109. data/docs/class_list.html +0 -51
  110. data/docs/css/common.css +0 -1
  111. data/docs/css/full_list.css +0 -58
  112. data/docs/css/style.css +0 -496
  113. data/docs/file.README.html +0 -127
  114. data/docs/file_list.html +0 -56
  115. data/docs/frames.html +0 -17
  116. data/docs/index.html +0 -127
  117. data/docs/js/app.js +0 -292
  118. data/docs/js/full_list.js +0 -216
  119. data/docs/js/jquery.js +0 -4
  120. data/docs/method_list.html +0 -67
  121. data/docs/top-level-namespace.html +0 -110
  122. data/spec/brotli_spec.rb +0 -88
  123. data/spec/inflate_spec.rb +0 -75
  124. 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 "./backward_references_hq.h"
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 <brotli/types.h>
16
- #include "./command.h"
17
- #include "./fast_log.h"
18
- #include "./find_match_length.h"
19
- #include "./literal_cost.h"
20
- #include "./memory.h"
21
- #include "./params.h"
22
- #include "./prefix.h"
23
- #include "./quality.h"
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->alphabet_size);
96
- self->distance_histogram_size = 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
- uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
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, &literal_costs[1]);
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
- size_t gap = 0;
435
+ const CompoundDictionary* addon = &params->dictionary.compound;
436
+ size_t gap = addon->total_size;
421
437
 
422
- EvaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache,
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 > max_distance + gap)) {
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 > max_distance + gap);
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 = 0;
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 max_distance =
591
- BROTLI_MIN(size_t, block_start + pos, max_backward_limit);
592
- BROTLI_BOOL is_dictionary = TO_BROTLI_BOOL(distance > max_distance + gap);
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], &params->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, HasherHandle hasher, ZopfliNode* nodes) {
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 matches[2 * (MAX_NUM_MATCHES_H10 + 64)];
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
- size_t gap = 0;
664
- size_t lz_matches_offset = 0;
720
+ const CompoundDictionary* addon = &params->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, &model, &params->dist, num_bytes);
730
+ InitZopfliCostModel(m, model, &params->dist, num_bytes);
668
731
  if (BROTLI_IS_OOM(m)) return 0;
669
732
  ZopfliCostModelSetFromLiteralCosts(
670
- &model, position, ringbuffer, ringbuffer_mask);
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
- num_matches = FindAllMatchesH10(hasher,
678
- &params->dictionary,
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, &model,
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, ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN(
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, &model, &queue, nodes);
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, &model);
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
- HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
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
- nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
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
- HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
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
- size_t gap = 0;
749
- size_t shadow_matches = 0;
750
- if (BROTLI_IS_OOM(m)) return;
834
+ const CompoundDictionary* addon = &params->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
- &params->dictionary,
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, ringbuffer, ringbuffer_mask, pos + 1,
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, &model, &params->dist, num_bytes);
907
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
908
+ InitZopfliCostModel(m, model, &params->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
- &model, position, ringbuffer, ringbuffer_mask);
914
+ model, position, ringbuffer, ringbuffer_mask);
802
915
  } else {
803
- ZopfliCostModelSetFromCommands(&model, position, ringbuffer,
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, &model, num_matches, matches,
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, &model);
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 <brotli/types.h>
16
- #include "./command.h"
17
- #include "./hash.h"
18
- #include "./memory.h"
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, size_t position, const uint8_t* ringbuffer,
27
- size_t ringbuffer_mask, const BrotliEncoderParams* params,
28
- HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
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, size_t position, const uint8_t* ringbuffer,
33
- size_t ringbuffer_mask, const BrotliEncoderParams* params,
34
- HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
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, HasherHandle hasher, ZopfliNode* nodes);
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,