brotli 0.2.0 → 0.2.1

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 (106) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +1 -0
  3. data/Rakefile +6 -1
  4. data/brotli.gemspec +1 -1
  5. data/docs/Brotli.html +485 -0
  6. data/docs/Brotli/Error.html +124 -0
  7. data/docs/_index.html +122 -0
  8. data/docs/class_list.html +51 -0
  9. data/docs/css/common.css +1 -0
  10. data/docs/css/full_list.css +58 -0
  11. data/docs/css/style.css +496 -0
  12. data/docs/file.README.html +127 -0
  13. data/docs/file_list.html +56 -0
  14. data/docs/frames.html +17 -0
  15. data/docs/index.html +127 -0
  16. data/docs/js/app.js +292 -0
  17. data/docs/js/full_list.js +216 -0
  18. data/docs/js/jquery.js +4 -0
  19. data/docs/method_list.html +67 -0
  20. data/docs/top-level-namespace.html +110 -0
  21. data/ext/brotli/brotli.c +20 -0
  22. data/lib/brotli/version.rb +1 -1
  23. data/vendor/brotli/c/common/constants.h +13 -6
  24. data/vendor/brotli/c/{dec → common}/context.h +182 -172
  25. data/vendor/brotli/c/common/dictionary.bin +0 -0
  26. data/vendor/brotli/c/common/dictionary.bin.br +0 -0
  27. data/vendor/brotli/c/common/dictionary.c +1 -1
  28. data/vendor/brotli/c/common/dictionary.h +4 -4
  29. data/vendor/brotli/c/common/platform.h +509 -0
  30. data/vendor/brotli/c/common/transform.c +235 -0
  31. data/vendor/brotli/c/common/transform.h +80 -0
  32. data/vendor/brotli/c/common/version.h +8 -1
  33. data/vendor/brotli/c/dec/bit_reader.c +1 -1
  34. data/vendor/brotli/c/dec/bit_reader.h +35 -86
  35. data/vendor/brotli/c/dec/decode.c +322 -205
  36. data/vendor/brotli/c/dec/huffman.c +35 -37
  37. data/vendor/brotli/c/dec/huffman.h +13 -9
  38. data/vendor/brotli/c/dec/prefix.h +3 -4
  39. data/vendor/brotli/c/dec/state.c +26 -34
  40. data/vendor/brotli/c/dec/state.h +34 -23
  41. data/vendor/brotli/c/enc/backward_references.c +25 -15
  42. data/vendor/brotli/c/enc/backward_references.h +5 -6
  43. data/vendor/brotli/c/enc/backward_references_hq.c +94 -68
  44. data/vendor/brotli/c/enc/backward_references_hq.h +22 -25
  45. data/vendor/brotli/c/enc/backward_references_inc.h +10 -10
  46. data/vendor/brotli/c/enc/bit_cost.c +1 -1
  47. data/vendor/brotli/c/enc/bit_cost.h +5 -5
  48. data/vendor/brotli/c/enc/block_encoder_inc.h +7 -6
  49. data/vendor/brotli/c/enc/block_splitter.c +2 -3
  50. data/vendor/brotli/c/enc/block_splitter.h +1 -1
  51. data/vendor/brotli/c/enc/block_splitter_inc.h +11 -11
  52. data/vendor/brotli/c/enc/brotli_bit_stream.c +102 -101
  53. data/vendor/brotli/c/enc/brotli_bit_stream.h +19 -38
  54. data/vendor/brotli/c/enc/cluster.c +1 -1
  55. data/vendor/brotli/c/enc/cluster.h +1 -1
  56. data/vendor/brotli/c/enc/command.h +40 -30
  57. data/vendor/brotli/c/enc/compress_fragment.c +21 -22
  58. data/vendor/brotli/c/enc/compress_fragment.h +1 -1
  59. data/vendor/brotli/c/enc/compress_fragment_two_pass.c +101 -68
  60. data/vendor/brotli/c/enc/compress_fragment_two_pass.h +1 -1
  61. data/vendor/brotli/c/enc/dictionary_hash.c +1 -1
  62. data/vendor/brotli/c/enc/encode.c +262 -162
  63. data/vendor/brotli/c/enc/encoder_dict.c +32 -0
  64. data/vendor/brotli/c/enc/encoder_dict.h +41 -0
  65. data/vendor/brotli/c/enc/entropy_encode.c +14 -14
  66. data/vendor/brotli/c/enc/entropy_encode.h +5 -5
  67. data/vendor/brotli/c/enc/entropy_encode_static.h +3 -3
  68. data/vendor/brotli/c/enc/fast_log.h +4 -2
  69. data/vendor/brotli/c/enc/find_match_length.h +3 -3
  70. data/vendor/brotli/c/enc/hash.h +75 -24
  71. data/vendor/brotli/c/enc/hash_composite_inc.h +133 -0
  72. data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +9 -8
  73. data/vendor/brotli/c/enc/hash_longest_match64_inc.h +8 -8
  74. data/vendor/brotli/c/enc/hash_longest_match_inc.h +8 -8
  75. data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +10 -9
  76. data/vendor/brotli/c/enc/hash_rolling_inc.h +215 -0
  77. data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +9 -8
  78. data/vendor/brotli/c/enc/histogram.c +9 -6
  79. data/vendor/brotli/c/enc/histogram.h +6 -3
  80. data/vendor/brotli/c/enc/histogram_inc.h +1 -1
  81. data/vendor/brotli/c/enc/literal_cost.c +5 -5
  82. data/vendor/brotli/c/enc/literal_cost.h +2 -2
  83. data/vendor/brotli/c/enc/memory.c +5 -16
  84. data/vendor/brotli/c/enc/memory.h +40 -1
  85. data/vendor/brotli/c/enc/metablock.c +163 -25
  86. data/vendor/brotli/c/enc/metablock.h +13 -8
  87. data/vendor/brotli/c/enc/metablock_inc.h +1 -1
  88. data/vendor/brotli/c/enc/params.h +44 -0
  89. data/vendor/brotli/c/enc/prefix.h +3 -4
  90. data/vendor/brotli/c/enc/quality.h +29 -24
  91. data/vendor/brotli/c/enc/ringbuffer.h +15 -11
  92. data/vendor/brotli/c/enc/static_dict.c +49 -45
  93. data/vendor/brotli/c/enc/static_dict.h +4 -3
  94. data/vendor/brotli/c/enc/static_dict_lut.h +1 -1
  95. data/vendor/brotli/c/enc/utf8_util.c +20 -20
  96. data/vendor/brotli/c/enc/utf8_util.h +1 -1
  97. data/vendor/brotli/c/enc/write_bits.h +16 -21
  98. data/vendor/brotli/c/include/brotli/decode.h +13 -8
  99. data/vendor/brotli/c/include/brotli/encode.h +33 -8
  100. data/vendor/brotli/c/include/brotli/port.h +211 -83
  101. data/vendor/brotli/c/include/brotli/types.h +0 -7
  102. metadata +33 -12
  103. data/vendor/brotli/c/dec/port.h +0 -168
  104. data/vendor/brotli/c/dec/transform.h +0 -300
  105. data/vendor/brotli/c/enc/context.h +0 -184
  106. data/vendor/brotli/c/enc/port.h +0 -184
@@ -13,9 +13,9 @@
13
13
  #ifndef BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
14
14
  #define BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
15
15
 
16
+ #include "../common/platform.h"
16
17
  #include <brotli/types.h>
17
18
  #include "./memory.h"
18
- #include "./port.h"
19
19
 
20
20
  #if defined(__cplusplus) || defined(c_plusplus)
21
21
  extern "C" {
@@ -6,7 +6,7 @@
6
6
 
7
7
  /* Hash table on the 4-byte prefixes of static dictionary words. */
8
8
 
9
- #include <brotli/port.h>
9
+ #include "../common/platform.h"
10
10
  #include "./dictionary_hash.h"
11
11
 
12
12
  #if defined(__cplusplus) || defined(c_plusplus)
@@ -11,6 +11,9 @@
11
11
  #include <stdlib.h> /* free, malloc */
12
12
  #include <string.h> /* memcpy, memset */
13
13
 
14
+ #include "../common/constants.h"
15
+ #include "../common/context.h"
16
+ #include "../common/platform.h"
14
17
  #include "../common/version.h"
15
18
  #include "./backward_references.h"
16
19
  #include "./backward_references_hq.h"
@@ -18,14 +21,13 @@
18
21
  #include "./brotli_bit_stream.h"
19
22
  #include "./compress_fragment.h"
20
23
  #include "./compress_fragment_two_pass.h"
21
- #include "./context.h"
24
+ #include "./encoder_dict.h"
22
25
  #include "./entropy_encode.h"
23
26
  #include "./fast_log.h"
24
27
  #include "./hash.h"
25
28
  #include "./histogram.h"
26
29
  #include "./memory.h"
27
30
  #include "./metablock.h"
28
- #include "./port.h"
29
31
  #include "./prefix.h"
30
32
  #include "./quality.h"
31
33
  #include "./ringbuffer.h"
@@ -69,8 +71,8 @@ typedef struct BrotliEncoderStateStruct {
69
71
  uint64_t last_processed_pos_;
70
72
  int dist_cache_[BROTLI_NUM_DISTANCE_SHORT_CODES];
71
73
  int saved_dist_cache_[4];
72
- uint8_t last_byte_;
73
- uint8_t last_byte_bits_;
74
+ uint16_t last_bytes_;
75
+ uint8_t last_bytes_bits_;
74
76
  uint8_t prev_byte_;
75
77
  uint8_t prev_byte2_;
76
78
  size_t storage_size_;
@@ -115,7 +117,6 @@ typedef struct BrotliEncoderStateStruct {
115
117
  static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s);
116
118
 
117
119
  static size_t InputBlockSize(BrotliEncoderState* s) {
118
- if (!EnsureInitialized(s)) return 0;
119
120
  return (size_t)1 << s->params.lgblock;
120
121
  }
121
122
 
@@ -161,27 +162,19 @@ BROTLI_BOOL BrotliEncoderSetParameter(
161
162
  state->params.size_hint = value;
162
163
  return BROTLI_TRUE;
163
164
 
164
- default: return BROTLI_FALSE;
165
- }
166
- }
165
+ case BROTLI_PARAM_LARGE_WINDOW:
166
+ state->params.large_window = TO_BROTLI_BOOL(!!value);
167
+ return BROTLI_TRUE;
167
168
 
168
- static void RecomputeDistancePrefixes(Command* cmds,
169
- size_t num_commands,
170
- uint32_t num_direct_distance_codes,
171
- uint32_t distance_postfix_bits) {
172
- size_t i;
173
- if (num_direct_distance_codes == 0 && distance_postfix_bits == 0) {
174
- return;
175
- }
176
- for (i = 0; i < num_commands; ++i) {
177
- Command* cmd = &cmds[i];
178
- if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
179
- PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd),
180
- num_direct_distance_codes,
181
- distance_postfix_bits,
182
- &cmd->dist_prefix_,
183
- &cmd->dist_extra_);
184
- }
169
+ case BROTLI_PARAM_NPOSTFIX:
170
+ state->params.dist.distance_postfix_bits = value;
171
+ return BROTLI_TRUE;
172
+
173
+ case BROTLI_PARAM_NDIRECT:
174
+ state->params.dist.num_direct_distance_codes = value;
175
+ return BROTLI_TRUE;
176
+
177
+ default: return BROTLI_FALSE;
185
178
  }
186
179
  }
187
180
 
@@ -226,7 +219,7 @@ static int* GetHashTable(BrotliEncoderState* s, int quality,
226
219
  const size_t max_table_size = MaxHashTableSize(quality);
227
220
  size_t htsize = HashTableSize(max_table_size, input_size);
228
221
  int* table;
229
- assert(max_table_size >= 256);
222
+ BROTLI_DCHECK(max_table_size >= 256);
230
223
  if (quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
231
224
  /* Only odd shifts are supported by fast-one-pass. */
232
225
  if ((htsize & 0xAAAAA) == 0) {
@@ -251,20 +244,25 @@ static int* GetHashTable(BrotliEncoderState* s, int quality,
251
244
  return table;
252
245
  }
253
246
 
254
- static void EncodeWindowBits(int lgwin, uint8_t* last_byte,
255
- uint8_t* last_byte_bits) {
256
- if (lgwin == 16) {
257
- *last_byte = 0;
258
- *last_byte_bits = 1;
259
- } else if (lgwin == 17) {
260
- *last_byte = 1;
261
- *last_byte_bits = 7;
262
- } else if (lgwin > 17) {
263
- *last_byte = (uint8_t)(((lgwin - 17) << 1) | 1);
264
- *last_byte_bits = 4;
247
+ static void EncodeWindowBits(int lgwin, BROTLI_BOOL large_window,
248
+ uint16_t* last_bytes, uint8_t* last_bytes_bits) {
249
+ if (large_window) {
250
+ *last_bytes = (uint16_t)(((lgwin & 0x3F) << 8) | 0x11);
251
+ *last_bytes_bits = 14;
265
252
  } else {
266
- *last_byte = (uint8_t)(((lgwin - 8) << 4) | 1);
267
- *last_byte_bits = 7;
253
+ if (lgwin == 16) {
254
+ *last_bytes = 0;
255
+ *last_bytes_bits = 1;
256
+ } else if (lgwin == 17) {
257
+ *last_bytes = 1;
258
+ *last_bytes_bits = 7;
259
+ } else if (lgwin > 17) {
260
+ *last_bytes = (uint16_t)(((lgwin - 17) << 1) | 0x01);
261
+ *last_bytes_bits = 4;
262
+ } else {
263
+ *last_bytes = (uint16_t)(((lgwin - 8) << 4) | 0x01);
264
+ *last_bytes_bits = 7;
265
+ }
268
266
  }
269
267
  }
270
268
 
@@ -357,7 +355,7 @@ static void ChooseContextMap(int quality,
357
355
  }
358
356
 
359
357
  total = monogram_histo[0] + monogram_histo[1] + monogram_histo[2];
360
- assert(total != 0);
358
+ BROTLI_DCHECK(total != 0);
361
359
  entropy[0] = 1.0 / (double)total;
362
360
  entropy[1] *= entropy[0];
363
361
  entropy[2] *= entropy[0];
@@ -420,6 +418,7 @@ static BROTLI_BOOL ShouldUseComplexStaticContextMap(const uint8_t* input,
420
418
  double entropy[3];
421
419
  size_t dummy;
422
420
  size_t i;
421
+ ContextLut utf8_lut = BROTLI_CONTEXT_LUT(CONTEXT_UTF8);
423
422
  for (; start_pos + 64 <= end_pos; start_pos += 4096) {
424
423
  const size_t stride_end_pos = start_pos + 64;
425
424
  uint8_t prev2 = input[start_pos & mask];
@@ -430,7 +429,7 @@ static BROTLI_BOOL ShouldUseComplexStaticContextMap(const uint8_t* input,
430
429
  for (pos = start_pos + 2; pos < stride_end_pos; ++pos) {
431
430
  const uint8_t literal = input[pos & mask];
432
431
  const uint8_t context = (uint8_t)kStaticContextMapComplexUTF8[
433
- Context(prev1, prev2, CONTEXT_UTF8)];
432
+ BROTLI_CONTEXT(prev1, prev2, utf8_lut)];
434
433
  ++total;
435
434
  ++combined_histo[literal >> 3];
436
435
  ++context_histo[context][literal >> 3];
@@ -519,12 +518,26 @@ static BROTLI_BOOL ShouldCompress(
519
518
  return BROTLI_TRUE;
520
519
  }
521
520
 
521
+ /* Chooses the literal context mode for a metablock */
522
+ static ContextType ChooseContextMode(const BrotliEncoderParams* params,
523
+ const uint8_t* data, const size_t pos, const size_t mask,
524
+ const size_t length) {
525
+ /* We only do the computation for the option of something else than
526
+ CONTEXT_UTF8 for the highest qualities */
527
+ if (params->quality >= MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING &&
528
+ !BrotliIsMostlyUTF8(data, pos, mask, length, kMinUTF8Ratio)) {
529
+ return CONTEXT_SIGNED;
530
+ }
531
+ return CONTEXT_UTF8;
532
+ }
533
+
522
534
  static void WriteMetaBlockInternal(MemoryManager* m,
523
535
  const uint8_t* data,
524
536
  const size_t mask,
525
537
  const uint64_t last_flush_pos,
526
538
  const size_t bytes,
527
539
  const BROTLI_BOOL is_last,
540
+ ContextType literal_context_mode,
528
541
  const BrotliEncoderParams* params,
529
542
  const uint8_t prev_byte,
530
543
  const uint8_t prev_byte2,
@@ -536,10 +549,10 @@ static void WriteMetaBlockInternal(MemoryManager* m,
536
549
  size_t* storage_ix,
537
550
  uint8_t* storage) {
538
551
  const uint32_t wrapped_last_flush_pos = WrapPosition(last_flush_pos);
539
- uint8_t last_byte;
540
- uint8_t last_byte_bits;
541
- uint32_t num_direct_distance_codes = 0;
542
- uint32_t distance_postfix_bits = 0;
552
+ uint16_t last_bytes;
553
+ uint8_t last_bytes_bits;
554
+ ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
555
+ BrotliEncoderParams block_params = *params;
543
556
 
544
557
  if (bytes == 0) {
545
558
  /* Write the ISLAST and ISEMPTY bits. */
@@ -559,31 +572,22 @@ static void WriteMetaBlockInternal(MemoryManager* m,
559
572
  return;
560
573
  }
561
574
 
562
- last_byte = storage[0];
563
- last_byte_bits = (uint8_t)(*storage_ix & 0xff);
564
- if (params->quality >= MIN_QUALITY_FOR_RECOMPUTE_DISTANCE_PREFIXES &&
565
- params->mode == BROTLI_MODE_FONT) {
566
- num_direct_distance_codes = 12;
567
- distance_postfix_bits = 1;
568
- RecomputeDistancePrefixes(commands,
569
- num_commands,
570
- num_direct_distance_codes,
571
- distance_postfix_bits);
572
- }
575
+ BROTLI_DCHECK(*storage_ix <= 14);
576
+ last_bytes = (uint16_t)((storage[1] << 8) | storage[0]);
577
+ last_bytes_bits = (uint8_t)(*storage_ix);
573
578
  if (params->quality <= MAX_QUALITY_FOR_STATIC_ENTROPY_CODES) {
574
579
  BrotliStoreMetaBlockFast(m, data, wrapped_last_flush_pos,
575
- bytes, mask, is_last,
580
+ bytes, mask, is_last, params,
576
581
  commands, num_commands,
577
582
  storage_ix, storage);
578
583
  if (BROTLI_IS_OOM(m)) return;
579
584
  } else if (params->quality < MIN_QUALITY_FOR_BLOCK_SPLIT) {
580
585
  BrotliStoreMetaBlockTrivial(m, data, wrapped_last_flush_pos,
581
- bytes, mask, is_last,
586
+ bytes, mask, is_last, params,
582
587
  commands, num_commands,
583
588
  storage_ix, storage);
584
589
  if (BROTLI_IS_OOM(m)) return;
585
590
  } else {
586
- ContextType literal_context_mode = CONTEXT_UTF8;
587
591
  MetaBlockSplit mb;
588
592
  InitMetaBlockSplit(&mb);
589
593
  if (params->quality < MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING) {
@@ -596,15 +600,11 @@ static void WriteMetaBlockInternal(MemoryManager* m,
596
600
  &literal_context_map);
597
601
  }
598
602
  BrotliBuildMetaBlockGreedy(m, data, wrapped_last_flush_pos, mask,
599
- prev_byte, prev_byte2, literal_context_mode, num_literal_contexts,
603
+ prev_byte, prev_byte2, literal_context_lut, num_literal_contexts,
600
604
  literal_context_map, commands, num_commands, &mb);
601
605
  if (BROTLI_IS_OOM(m)) return;
602
606
  } else {
603
- if (!BrotliIsMostlyUTF8(data, wrapped_last_flush_pos, mask, bytes,
604
- kMinUTF8Ratio)) {
605
- literal_context_mode = CONTEXT_SIGNED;
606
- }
607
- BrotliBuildMetaBlock(m, data, wrapped_last_flush_pos, mask, params,
607
+ BrotliBuildMetaBlock(m, data, wrapped_last_flush_pos, mask, &block_params,
608
608
  prev_byte, prev_byte2,
609
609
  commands, num_commands,
610
610
  literal_context_mode,
@@ -612,15 +612,19 @@ static void WriteMetaBlockInternal(MemoryManager* m,
612
612
  if (BROTLI_IS_OOM(m)) return;
613
613
  }
614
614
  if (params->quality >= MIN_QUALITY_FOR_OPTIMIZE_HISTOGRAMS) {
615
- BrotliOptimizeHistograms(num_direct_distance_codes,
616
- distance_postfix_bits,
617
- &mb);
615
+ /* The number of distance symbols effectively used for distance
616
+ histograms. It might be less than distance alphabet size
617
+ for "Large Window Brotli" (32-bit). */
618
+ uint32_t num_effective_dist_codes = block_params.dist.alphabet_size;
619
+ if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
620
+ num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
621
+ }
622
+ BrotliOptimizeHistograms(num_effective_dist_codes, &mb);
618
623
  }
619
624
  BrotliStoreMetaBlock(m, data, wrapped_last_flush_pos, bytes, mask,
620
625
  prev_byte, prev_byte2,
621
626
  is_last,
622
- num_direct_distance_codes,
623
- distance_postfix_bits,
627
+ &block_params,
624
628
  literal_context_mode,
625
629
  commands, num_commands,
626
630
  &mb,
@@ -631,20 +635,48 @@ static void WriteMetaBlockInternal(MemoryManager* m,
631
635
  if (bytes + 4 < (*storage_ix >> 3)) {
632
636
  /* Restore the distance cache and last byte. */
633
637
  memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
634
- storage[0] = last_byte;
635
- *storage_ix = last_byte_bits;
638
+ storage[0] = (uint8_t)last_bytes;
639
+ storage[1] = (uint8_t)(last_bytes >> 8);
640
+ *storage_ix = last_bytes_bits;
636
641
  BrotliStoreUncompressedMetaBlock(is_last, data,
637
642
  wrapped_last_flush_pos, mask,
638
643
  bytes, storage_ix, storage);
639
644
  }
640
645
  }
641
646
 
647
+ static void ChooseDistanceParams(BrotliEncoderParams* params) {
648
+ uint32_t distance_postfix_bits = 0;
649
+ uint32_t num_direct_distance_codes = 0;
650
+
651
+ if (params->quality >= MIN_QUALITY_FOR_NONZERO_DISTANCE_PARAMS) {
652
+ uint32_t ndirect_msb;
653
+ if (params->mode == BROTLI_MODE_FONT) {
654
+ distance_postfix_bits = 1;
655
+ num_direct_distance_codes = 12;
656
+ } else {
657
+ distance_postfix_bits = params->dist.distance_postfix_bits;
658
+ num_direct_distance_codes = params->dist.num_direct_distance_codes;
659
+ }
660
+ ndirect_msb = (num_direct_distance_codes >> distance_postfix_bits) & 0x0F;
661
+ if (distance_postfix_bits > BROTLI_MAX_NPOSTFIX ||
662
+ num_direct_distance_codes > BROTLI_MAX_NDIRECT ||
663
+ (ndirect_msb << distance_postfix_bits) != num_direct_distance_codes) {
664
+ distance_postfix_bits = 0;
665
+ num_direct_distance_codes = 0;
666
+ }
667
+ }
668
+
669
+ BrotliInitDistanceParams(
670
+ params, distance_postfix_bits, num_direct_distance_codes);
671
+ }
672
+
642
673
  static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
643
674
  if (BROTLI_IS_OOM(&s->memory_manager_)) return BROTLI_FALSE;
644
675
  if (s->is_initialized_) return BROTLI_TRUE;
645
676
 
646
677
  SanitizeParams(&s->params);
647
678
  s->params.lgblock = ComputeLgBlock(&s->params);
679
+ ChooseDistanceParams(&s->params);
648
680
 
649
681
  s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
650
682
 
@@ -657,7 +689,8 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
657
689
  s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
658
690
  lgwin = BROTLI_MAX(int, lgwin, 18);
659
691
  }
660
- EncodeWindowBits(lgwin, &s->last_byte_, &s->last_byte_bits_);
692
+ EncodeWindowBits(lgwin, s->params.large_window,
693
+ &s->last_bytes_, &s->last_bytes_bits_);
661
694
  }
662
695
 
663
696
  if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
@@ -671,11 +704,18 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
671
704
 
672
705
  static void BrotliEncoderInitParams(BrotliEncoderParams* params) {
673
706
  params->mode = BROTLI_DEFAULT_MODE;
707
+ params->large_window = BROTLI_FALSE;
674
708
  params->quality = BROTLI_DEFAULT_QUALITY;
675
709
  params->lgwin = BROTLI_DEFAULT_WINDOW;
676
710
  params->lgblock = 0;
677
711
  params->size_hint = 0;
678
712
  params->disable_literal_context_modeling = BROTLI_FALSE;
713
+ BrotliInitEncoderDictionary(&params->dictionary);
714
+ params->dist.distance_postfix_bits = 0;
715
+ params->dist.num_direct_distance_codes = 0;
716
+ params->dist.alphabet_size =
717
+ BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_MAX_DISTANCE_BITS);
718
+ params->dist.max_distance = BROTLI_MAX_DISTANCE;
679
719
  }
680
720
 
681
721
  static void BrotliEncoderInitState(BrotliEncoderState* s) {
@@ -718,9 +758,8 @@ static void BrotliEncoderInitState(BrotliEncoderState* s) {
718
758
  memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
719
759
  }
720
760
 
721
- BrotliEncoderState* BrotliEncoderCreateInstance(brotli_alloc_func alloc_func,
722
- brotli_free_func free_func,
723
- void* opaque) {
761
+ BrotliEncoderState* BrotliEncoderCreateInstance(
762
+ brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
724
763
  BrotliEncoderState* state = 0;
725
764
  if (!alloc_func && !free_func) {
726
765
  state = (BrotliEncoderState*)malloc(sizeof(BrotliEncoderState));
@@ -777,7 +816,6 @@ static void CopyInputToRingBuffer(BrotliEncoderState* s,
777
816
  const uint8_t* input_buffer) {
778
817
  RingBuffer* ringbuffer_ = &s->ringbuffer_;
779
818
  MemoryManager* m = &s->memory_manager_;
780
- if (!EnsureInitialized(s)) return;
781
819
  RingBufferWrite(m, input_buffer, input_size, ringbuffer_);
782
820
  if (BROTLI_IS_OOM(m)) return;
783
821
  s->input_pos_ += input_size;
@@ -837,6 +875,39 @@ static BROTLI_BOOL UpdateLastProcessedPos(BrotliEncoderState* s) {
837
875
  return TO_BROTLI_BOOL(wrapped_input_pos < wrapped_last_processed_pos);
838
876
  }
839
877
 
878
+ static void ExtendLastCommand(BrotliEncoderState* s, uint32_t* bytes,
879
+ uint32_t* wrapped_last_processed_pos) {
880
+ Command* last_command = &s->commands_[s->num_commands_ - 1];
881
+ const uint8_t* data = s->ringbuffer_.buffer_;
882
+ const uint32_t mask = s->ringbuffer_.mask_;
883
+ uint64_t max_backward_distance =
884
+ (((uint64_t)1) << s->params.lgwin) - BROTLI_WINDOW_GAP;
885
+ uint64_t last_copy_len = last_command->copy_len_ & 0x1FFFFFF;
886
+ uint64_t last_processed_pos = s->last_processed_pos_ - last_copy_len;
887
+ uint64_t max_distance = last_processed_pos < max_backward_distance ?
888
+ last_processed_pos : max_backward_distance;
889
+ uint64_t cmd_dist = (uint64_t)s->dist_cache_[0];
890
+ uint32_t distance_code = CommandRestoreDistanceCode(last_command,
891
+ &s->params.dist);
892
+ if (distance_code < BROTLI_NUM_DISTANCE_SHORT_CODES ||
893
+ distance_code - (BROTLI_NUM_DISTANCE_SHORT_CODES - 1) == cmd_dist) {
894
+ if (cmd_dist <= max_distance) {
895
+ while (*bytes != 0 && data[*wrapped_last_processed_pos & mask] ==
896
+ data[(*wrapped_last_processed_pos - cmd_dist) & mask]) {
897
+ last_command->copy_len_++;
898
+ (*bytes)--;
899
+ (*wrapped_last_processed_pos)++;
900
+ }
901
+ }
902
+ /* The copy length is at most the metablock size, and thus expressible. */
903
+ GetLengthCode(last_command->insert_len_,
904
+ (size_t)((int)(last_command->copy_len_ & 0x1FFFFFF) +
905
+ (int)(last_command->copy_len_ >> 25)),
906
+ TO_BROTLI_BOOL((last_command->dist_prefix_ & 0x3FF) == 0),
907
+ &last_command->cmd_prefix_);
908
+ }
909
+ }
910
+
840
911
  /*
841
912
  Processes the accumulated input data and sets |*out_size| to the length of
842
913
  the new output meta-block, or to zero if no new output meta-block has been
@@ -853,15 +924,13 @@ static BROTLI_BOOL EncodeData(
853
924
  BrotliEncoderState* s, const BROTLI_BOOL is_last,
854
925
  const BROTLI_BOOL force_flush, size_t* out_size, uint8_t** output) {
855
926
  const uint64_t delta = UnprocessedInputSize(s);
856
- const uint32_t bytes = (uint32_t)delta;
857
- const uint32_t wrapped_last_processed_pos =
858
- WrapPosition(s->last_processed_pos_);
927
+ uint32_t bytes = (uint32_t)delta;
928
+ uint32_t wrapped_last_processed_pos = WrapPosition(s->last_processed_pos_);
859
929
  uint8_t* data;
860
930
  uint32_t mask;
861
931
  MemoryManager* m = &s->memory_manager_;
862
- const BrotliDictionary* dictionary = BrotliGetDictionary();
932
+ ContextType literal_context_mode;
863
933
 
864
- if (!EnsureInitialized(s)) return BROTLI_FALSE;
865
934
  data = s->ringbuffer_.buffer_;
866
935
  mask = s->ringbuffer_.mask_;
867
936
 
@@ -884,7 +953,7 @@ static BROTLI_BOOL EncodeData(
884
953
  if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
885
954
  s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
886
955
  uint8_t* storage;
887
- size_t storage_ix = s->last_byte_bits_;
956
+ size_t storage_ix = s->last_bytes_bits_;
888
957
  size_t table_size;
889
958
  int* table;
890
959
 
@@ -894,9 +963,10 @@ static BROTLI_BOOL EncodeData(
894
963
  *out_size = 0;
895
964
  return BROTLI_TRUE;
896
965
  }
897
- storage = GetBrotliStorage(s, 2 * bytes + 502);
966
+ storage = GetBrotliStorage(s, 2 * bytes + 503);
898
967
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
899
- storage[0] = s->last_byte_;
968
+ storage[0] = (uint8_t)s->last_bytes_;
969
+ storage[1] = (uint8_t)(s->last_bytes_ >> 8);
900
970
  table = GetHashTable(s, s->params.quality, bytes, &table_size);
901
971
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
902
972
  if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
@@ -917,8 +987,8 @@ static BROTLI_BOOL EncodeData(
917
987
  &storage_ix, storage);
918
988
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
919
989
  }
920
- s->last_byte_ = storage[storage_ix >> 3];
921
- s->last_byte_bits_ = storage_ix & 7u;
990
+ s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]);
991
+ s->last_bytes_bits_ = storage_ix & 7u;
922
992
  UpdateLastProcessedPos(s);
923
993
  *output = &storage[0];
924
994
  *out_size = storage_ix >> 3;
@@ -946,27 +1016,39 @@ static BROTLI_BOOL EncodeData(
946
1016
 
947
1017
  InitOrStitchToPreviousBlock(m, &s->hasher_, data, mask, &s->params,
948
1018
  wrapped_last_processed_pos, bytes, is_last);
1019
+
1020
+ literal_context_mode = ChooseContextMode(
1021
+ &s->params, data, WrapPosition(s->last_flush_pos_),
1022
+ mask, (size_t)(s->input_pos_ - s->last_flush_pos_));
1023
+
949
1024
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
950
1025
 
1026
+ if (s->num_commands_ && s->last_insert_len_ == 0) {
1027
+ ExtendLastCommand(s, &bytes, &wrapped_last_processed_pos);
1028
+ }
1029
+
951
1030
  if (s->params.quality == ZOPFLIFICATION_QUALITY) {
952
- assert(s->params.hasher.type == 10);
953
- BrotliCreateZopfliBackwardReferences(
954
- m, dictionary, bytes, wrapped_last_processed_pos, data, mask,
955
- &s->params, s->hasher_, s->dist_cache_, &s->last_insert_len_,
956
- &s->commands_[s->num_commands_], &s->num_commands_, &s->num_literals_);
1031
+ BROTLI_DCHECK(s->params.hasher.type == 10);
1032
+ BrotliCreateZopfliBackwardReferences(m,
1033
+ bytes, wrapped_last_processed_pos,
1034
+ data, mask, &s->params, s->hasher_, s->dist_cache_,
1035
+ &s->last_insert_len_, &s->commands_[s->num_commands_],
1036
+ &s->num_commands_, &s->num_literals_);
957
1037
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
958
1038
  } else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) {
959
- assert(s->params.hasher.type == 10);
960
- BrotliCreateHqZopfliBackwardReferences(
961
- m, dictionary, bytes, wrapped_last_processed_pos, data, mask,
962
- &s->params, s->hasher_, s->dist_cache_, &s->last_insert_len_,
963
- &s->commands_[s->num_commands_], &s->num_commands_, &s->num_literals_);
1039
+ BROTLI_DCHECK(s->params.hasher.type == 10);
1040
+ BrotliCreateHqZopfliBackwardReferences(m,
1041
+ bytes, wrapped_last_processed_pos,
1042
+ data, mask, &s->params, s->hasher_, s->dist_cache_,
1043
+ &s->last_insert_len_, &s->commands_[s->num_commands_],
1044
+ &s->num_commands_, &s->num_literals_);
964
1045
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
965
1046
  } else {
966
1047
  BrotliCreateBackwardReferences(
967
- dictionary, bytes, wrapped_last_processed_pos, data, mask,
968
- &s->params, s->hasher_, s->dist_cache_, &s->last_insert_len_,
969
- &s->commands_[s->num_commands_], &s->num_commands_, &s->num_literals_);
1048
+ bytes, wrapped_last_processed_pos,
1049
+ data, mask, &s->params, s->hasher_, s->dist_cache_,
1050
+ &s->last_insert_len_, &s->commands_[s->num_commands_],
1051
+ &s->num_commands_, &s->num_literals_);
970
1052
  }
971
1053
 
972
1054
  {
@@ -1009,24 +1091,25 @@ static BROTLI_BOOL EncodeData(
1009
1091
  *out_size = 0;
1010
1092
  return BROTLI_TRUE;
1011
1093
  }
1012
- assert(s->input_pos_ >= s->last_flush_pos_);
1013
- assert(s->input_pos_ > s->last_flush_pos_ || is_last);
1014
- assert(s->input_pos_ - s->last_flush_pos_ <= 1u << 24);
1094
+ BROTLI_DCHECK(s->input_pos_ >= s->last_flush_pos_);
1095
+ BROTLI_DCHECK(s->input_pos_ > s->last_flush_pos_ || is_last);
1096
+ BROTLI_DCHECK(s->input_pos_ - s->last_flush_pos_ <= 1u << 24);
1015
1097
  {
1016
1098
  const uint32_t metablock_size =
1017
1099
  (uint32_t)(s->input_pos_ - s->last_flush_pos_);
1018
- uint8_t* storage = GetBrotliStorage(s, 2 * metablock_size + 502);
1019
- size_t storage_ix = s->last_byte_bits_;
1100
+ uint8_t* storage = GetBrotliStorage(s, 2 * metablock_size + 503);
1101
+ size_t storage_ix = s->last_bytes_bits_;
1020
1102
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1021
- storage[0] = s->last_byte_;
1103
+ storage[0] = (uint8_t)s->last_bytes_;
1104
+ storage[1] = (uint8_t)(s->last_bytes_ >> 8);
1022
1105
  WriteMetaBlockInternal(
1023
1106
  m, data, mask, s->last_flush_pos_, metablock_size, is_last,
1024
- &s->params, s->prev_byte_, s->prev_byte2_,
1107
+ literal_context_mode, &s->params, s->prev_byte_, s->prev_byte2_,
1025
1108
  s->num_literals_, s->num_commands_, s->commands_, s->saved_dist_cache_,
1026
1109
  s->dist_cache_, &storage_ix, storage);
1027
1110
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1028
- s->last_byte_ = storage[storage_ix >> 3];
1029
- s->last_byte_bits_ = storage_ix & 7u;
1111
+ s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]);
1112
+ s->last_bytes_bits_ = storage_ix & 7u;
1030
1113
  s->last_flush_pos_ = s->input_pos_;
1031
1114
  if (UpdateLastProcessedPos(s)) {
1032
1115
  HasherReset(s->hasher_);
@@ -1055,10 +1138,11 @@ static BROTLI_BOOL EncodeData(
1055
1138
  static size_t WriteMetadataHeader(
1056
1139
  BrotliEncoderState* s, const size_t block_size, uint8_t* header) {
1057
1140
  size_t storage_ix;
1058
- storage_ix = s->last_byte_bits_;
1059
- header[0] = s->last_byte_;
1060
- s->last_byte_ = 0;
1061
- s->last_byte_bits_ = 0;
1141
+ storage_ix = s->last_bytes_bits_;
1142
+ header[0] = (uint8_t)s->last_bytes_;
1143
+ header[1] = (uint8_t)(s->last_bytes_ >> 8);
1144
+ s->last_bytes_ = 0;
1145
+ s->last_bytes_bits_ = 0;
1062
1146
 
1063
1147
  BrotliWriteBits(1, 0, &storage_ix, header);
1064
1148
  BrotliWriteBits(2, 3, &storage_ix, header);
@@ -1088,15 +1172,14 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1088
1172
  BROTLI_BOOL ok = BROTLI_TRUE;
1089
1173
  const size_t max_out_size = *encoded_size;
1090
1174
  size_t total_out_size = 0;
1091
- uint8_t last_byte;
1092
- uint8_t last_byte_bits;
1175
+ uint16_t last_bytes;
1176
+ uint8_t last_bytes_bits;
1093
1177
  HasherHandle hasher = NULL;
1094
1178
 
1095
1179
  const size_t hasher_eff_size =
1096
1180
  BROTLI_MIN(size_t, input_size, max_backward_limit + BROTLI_WINDOW_GAP);
1097
1181
 
1098
1182
  BrotliEncoderParams params;
1099
- const BrotliDictionary* dictionary = BrotliGetDictionary();
1100
1183
 
1101
1184
  const int lgmetablock = BROTLI_MIN(int, 24, lgwin + 1);
1102
1185
  size_t max_block_size;
@@ -1110,14 +1193,18 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1110
1193
  BrotliEncoderInitParams(&params);
1111
1194
  params.quality = 10;
1112
1195
  params.lgwin = lgwin;
1196
+ if (lgwin > BROTLI_MAX_WINDOW_BITS) {
1197
+ params.large_window = BROTLI_TRUE;
1198
+ }
1113
1199
  SanitizeParams(&params);
1114
1200
  params.lgblock = ComputeLgBlock(&params);
1201
+ ChooseDistanceParams(&params);
1115
1202
  max_block_size = (size_t)1 << params.lgblock;
1116
1203
 
1117
1204
  BrotliInitMemoryManager(m, 0, 0, 0);
1118
1205
 
1119
- assert(input_size <= mask + 1);
1120
- EncodeWindowBits(lgwin, &last_byte, &last_byte_bits);
1206
+ BROTLI_DCHECK(input_size <= mask + 1);
1207
+ EncodeWindowBits(lgwin, params.large_window, &last_bytes, &last_bytes_bits);
1121
1208
  InitOrStitchToPreviousBlock(m, &hasher, input_buffer, mask, &params,
1122
1209
  0, hasher_eff_size, BROTLI_TRUE);
1123
1210
  if (BROTLI_IS_OOM(m)) goto oom;
@@ -1137,6 +1224,9 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1137
1224
  uint8_t* storage;
1138
1225
  size_t storage_ix;
1139
1226
 
1227
+ ContextType literal_context_mode = ChooseContextMode(&params,
1228
+ input_buffer, metablock_start, mask, metablock_end - metablock_start);
1229
+
1140
1230
  size_t block_start;
1141
1231
  for (block_start = metablock_start; block_start < metablock_end; ) {
1142
1232
  size_t block_size =
@@ -1148,8 +1238,8 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1148
1238
  BrotliInitZopfliNodes(nodes, block_size + 1);
1149
1239
  StitchToPreviousBlockH10(hasher, block_size, block_start,
1150
1240
  input_buffer, mask);
1151
- path_size = BrotliZopfliComputeShortestPath(
1152
- m, dictionary, block_size, block_start, input_buffer, mask, &params,
1241
+ path_size = BrotliZopfliComputeShortestPath(m,
1242
+ block_size, block_start, input_buffer, mask, &params,
1153
1243
  max_backward_limit, dist_cache, hasher, nodes);
1154
1244
  if (BROTLI_IS_OOM(m)) goto oom;
1155
1245
  /* We allocate a command buffer in the first iteration of this loop that
@@ -1193,13 +1283,14 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1193
1283
 
1194
1284
  is_last = TO_BROTLI_BOOL(metablock_start + metablock_size == input_size);
1195
1285
  storage = NULL;
1196
- storage_ix = last_byte_bits;
1286
+ storage_ix = last_bytes_bits;
1197
1287
 
1198
1288
  if (metablock_size == 0) {
1199
1289
  /* Write the ISLAST and ISEMPTY bits. */
1200
1290
  storage = BROTLI_ALLOC(m, uint8_t, 16);
1201
1291
  if (BROTLI_IS_OOM(m)) goto oom;
1202
- storage[0] = last_byte;
1292
+ storage[0] = (uint8_t)last_bytes;
1293
+ storage[1] = (uint8_t)(last_bytes >> 8);
1203
1294
  BrotliWriteBits(2, 3, &storage_ix, storage);
1204
1295
  storage_ix = (storage_ix + 7u) & ~7u;
1205
1296
  } else if (!ShouldCompress(input_buffer, mask, metablock_start,
@@ -1209,37 +1300,40 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1209
1300
  memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
1210
1301
  storage = BROTLI_ALLOC(m, uint8_t, metablock_size + 16);
1211
1302
  if (BROTLI_IS_OOM(m)) goto oom;
1212
- storage[0] = last_byte;
1303
+ storage[0] = (uint8_t)last_bytes;
1304
+ storage[1] = (uint8_t)(last_bytes >> 8);
1213
1305
  BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
1214
1306
  metablock_start, mask, metablock_size,
1215
1307
  &storage_ix, storage);
1216
1308
  } else {
1217
- uint32_t num_direct_distance_codes = 0;
1218
- uint32_t distance_postfix_bits = 0;
1219
- ContextType literal_context_mode = CONTEXT_UTF8;
1220
1309
  MetaBlockSplit mb;
1310
+ BrotliEncoderParams block_params = params;
1221
1311
  InitMetaBlockSplit(&mb);
1222
- if (!BrotliIsMostlyUTF8(input_buffer, metablock_start, mask,
1223
- metablock_size, kMinUTF8Ratio)) {
1224
- literal_context_mode = CONTEXT_SIGNED;
1225
- }
1226
- BrotliBuildMetaBlock(m, input_buffer, metablock_start, mask, &params,
1312
+ BrotliBuildMetaBlock(m, input_buffer, metablock_start, mask,
1313
+ &block_params,
1227
1314
  prev_byte, prev_byte2,
1228
1315
  commands, num_commands,
1229
1316
  literal_context_mode,
1230
1317
  &mb);
1231
1318
  if (BROTLI_IS_OOM(m)) goto oom;
1232
- BrotliOptimizeHistograms(num_direct_distance_codes,
1233
- distance_postfix_bits,
1234
- &mb);
1235
- storage = BROTLI_ALLOC(m, uint8_t, 2 * metablock_size + 502);
1319
+ {
1320
+ /* The number of distance symbols effectively used for distance
1321
+ histograms. It might be less than distance alphabet size
1322
+ for "Large Window Brotli" (32-bit). */
1323
+ uint32_t num_effective_dist_codes = block_params.dist.alphabet_size;
1324
+ if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
1325
+ num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
1326
+ }
1327
+ BrotliOptimizeHistograms(num_effective_dist_codes, &mb);
1328
+ }
1329
+ storage = BROTLI_ALLOC(m, uint8_t, 2 * metablock_size + 503);
1236
1330
  if (BROTLI_IS_OOM(m)) goto oom;
1237
- storage[0] = last_byte;
1331
+ storage[0] = (uint8_t)last_bytes;
1332
+ storage[1] = (uint8_t)(last_bytes >> 8);
1238
1333
  BrotliStoreMetaBlock(m, input_buffer, metablock_start, metablock_size,
1239
1334
  mask, prev_byte, prev_byte2,
1240
1335
  is_last,
1241
- num_direct_distance_codes,
1242
- distance_postfix_bits,
1336
+ &block_params,
1243
1337
  literal_context_mode,
1244
1338
  commands, num_commands,
1245
1339
  &mb,
@@ -1248,19 +1342,22 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1248
1342
  if (metablock_size + 4 < (storage_ix >> 3)) {
1249
1343
  /* Restore the distance cache and last byte. */
1250
1344
  memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
1251
- storage[0] = last_byte;
1252
- storage_ix = last_byte_bits;
1345
+ storage[0] = (uint8_t)last_bytes;
1346
+ storage[1] = (uint8_t)(last_bytes >> 8);
1347
+ storage_ix = last_bytes_bits;
1253
1348
  BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
1254
1349
  metablock_start, mask,
1255
1350
  metablock_size, &storage_ix, storage);
1256
1351
  }
1257
1352
  DestroyMetaBlockSplit(m, &mb);
1258
1353
  }
1259
- last_byte = storage[storage_ix >> 3];
1260
- last_byte_bits = storage_ix & 7u;
1354
+ last_bytes = (uint16_t)(storage[storage_ix >> 3]);
1355
+ last_bytes_bits = storage_ix & 7u;
1261
1356
  metablock_start += metablock_size;
1262
- prev_byte = input_buffer[metablock_start - 1];
1263
- prev_byte2 = input_buffer[metablock_start - 2];
1357
+ if (metablock_start < input_size) {
1358
+ prev_byte = input_buffer[metablock_start - 1];
1359
+ prev_byte2 = input_buffer[metablock_start - 2];
1360
+ }
1264
1361
  /* Save the state of the distance cache in case we need to restore it for
1265
1362
  emitting an uncompressed block. */
1266
1363
  memcpy(saved_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
@@ -1290,12 +1387,10 @@ oom:
1290
1387
 
1291
1388
  size_t BrotliEncoderMaxCompressedSize(size_t input_size) {
1292
1389
  /* [window bits / empty metadata] + N * [uncompressed] + [last empty] */
1293
- size_t num_large_blocks = input_size >> 24;
1294
- size_t tail = input_size - (num_large_blocks << 24);
1295
- size_t tail_overhead = (tail > (1 << 20)) ? 4 : 3;
1296
- size_t overhead = 2 + (4 * num_large_blocks) + tail_overhead + 1;
1390
+ size_t num_large_blocks = input_size >> 14;
1391
+ size_t overhead = 2 + (4 * num_large_blocks) + 3 + 1;
1297
1392
  size_t result = input_size + overhead;
1298
- if (input_size == 0) return 1;
1393
+ if (input_size == 0) return 2;
1299
1394
  return (result < input_size) ? 0 : result;
1300
1395
  }
1301
1396
 
@@ -1356,7 +1451,7 @@ BROTLI_BOOL BrotliEncoderCompress(
1356
1451
  }
1357
1452
  if (quality == 10) {
1358
1453
  /* TODO: Implement this direct path for all quality levels. */
1359
- const int lg_win = BROTLI_MIN(int, BROTLI_MAX_WINDOW_BITS,
1454
+ const int lg_win = BROTLI_MIN(int, BROTLI_LARGE_MAX_WINDOW_BITS,
1360
1455
  BROTLI_MAX(int, 16, lgwin));
1361
1456
  int ok = BrotliCompressBufferQuality10(lg_win, input_size, input_buffer,
1362
1457
  encoded_size, encoded_buffer);
@@ -1380,6 +1475,9 @@ BROTLI_BOOL BrotliEncoderCompress(
1380
1475
  BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, (uint32_t)lgwin);
1381
1476
  BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, (uint32_t)mode);
1382
1477
  BrotliEncoderSetParameter(s, BROTLI_PARAM_SIZE_HINT, (uint32_t)input_size);
1478
+ if (lgwin > BROTLI_MAX_WINDOW_BITS) {
1479
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_LARGE_WINDOW, BROTLI_TRUE);
1480
+ }
1383
1481
  result = BrotliEncoderCompressStream(s, BROTLI_OPERATION_FINISH,
1384
1482
  &available_in, &next_in, &available_out, &next_out, &total_out);
1385
1483
  if (!BrotliEncoderIsFinished(s)) result = 0;
@@ -1402,11 +1500,11 @@ fallback:
1402
1500
  }
1403
1501
 
1404
1502
  static void InjectBytePaddingBlock(BrotliEncoderState* s) {
1405
- uint32_t seal = s->last_byte_;
1406
- size_t seal_bits = s->last_byte_bits_;
1503
+ uint32_t seal = s->last_bytes_;
1504
+ size_t seal_bits = s->last_bytes_bits_;
1407
1505
  uint8_t* destination;
1408
- s->last_byte_ = 0;
1409
- s->last_byte_bits_ = 0;
1506
+ s->last_bytes_ = 0;
1507
+ s->last_bytes_bits_ = 0;
1410
1508
  /* is_last = 0, data_nibbles = 11, reserved = 0, meta_nibbles = 00 */
1411
1509
  seal |= 0x6u << seal_bits;
1412
1510
  seal_bits += 6;
@@ -1420,6 +1518,7 @@ static void InjectBytePaddingBlock(BrotliEncoderState* s) {
1420
1518
  }
1421
1519
  destination[0] = (uint8_t)seal;
1422
1520
  if (seal_bits > 8) destination[1] = (uint8_t)(seal >> 8);
1521
+ if (seal_bits > 16) destination[2] = (uint8_t)(seal >> 16);
1423
1522
  s->available_out_ += (seal_bits + 7) >> 3;
1424
1523
  }
1425
1524
 
@@ -1428,7 +1527,7 @@ static void InjectBytePaddingBlock(BrotliEncoderState* s) {
1428
1527
  static BROTLI_BOOL InjectFlushOrPushOutput(BrotliEncoderState* s,
1429
1528
  size_t* available_out, uint8_t** next_out, size_t* total_out) {
1430
1529
  if (s->stream_state_ == BROTLI_STREAM_FLUSH_REQUESTED &&
1431
- s->last_byte_bits_ != 0) {
1530
+ s->last_bytes_bits_ != 0) {
1432
1531
  InjectBytePaddingBlock(s);
1433
1532
  return BROTLI_TRUE;
1434
1533
  }
@@ -1509,10 +1608,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
1509
1608
  (*available_in == block_size) && (op == BROTLI_OPERATION_FINISH);
1510
1609
  BROTLI_BOOL force_flush =
1511
1610
  (*available_in == block_size) && (op == BROTLI_OPERATION_FLUSH);
1512
- size_t max_out_size = 2 * block_size + 502;
1611
+ size_t max_out_size = 2 * block_size + 503;
1513
1612
  BROTLI_BOOL inplace = BROTLI_TRUE;
1514
1613
  uint8_t* storage = NULL;
1515
- size_t storage_ix = s->last_byte_bits_;
1614
+ size_t storage_ix = s->last_bytes_bits_;
1516
1615
  size_t table_size;
1517
1616
  int* table;
1518
1617
 
@@ -1527,7 +1626,8 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
1527
1626
  storage = GetBrotliStorage(s, max_out_size);
1528
1627
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1529
1628
  }
1530
- storage[0] = s->last_byte_;
1629
+ storage[0] = (uint8_t)s->last_bytes_;
1630
+ storage[1] = (uint8_t)(s->last_bytes_ >> 8);
1531
1631
  table = GetHashTable(s, s->params.quality, block_size, &table_size);
1532
1632
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1533
1633
 
@@ -1546,8 +1646,8 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
1546
1646
  *available_in -= block_size;
1547
1647
  if (inplace) {
1548
1648
  size_t out_bytes = storage_ix >> 3;
1549
- assert(out_bytes <= *available_out);
1550
- assert((storage_ix & 7) == 0 || out_bytes < *available_out);
1649
+ BROTLI_DCHECK(out_bytes <= *available_out);
1650
+ BROTLI_DCHECK((storage_ix & 7) == 0 || out_bytes < *available_out);
1551
1651
  *next_out += out_bytes;
1552
1652
  *available_out -= out_bytes;
1553
1653
  s->total_out_ += out_bytes;
@@ -1557,8 +1657,8 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
1557
1657
  s->next_out_ = storage;
1558
1658
  s->available_out_ = out_bytes;
1559
1659
  }
1560
- s->last_byte_ = storage[storage_ix >> 3];
1561
- s->last_byte_bits_ = storage_ix & 7u;
1660
+ s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]);
1661
+ s->last_bytes_bits_ = storage_ix & 7u;
1562
1662
 
1563
1663
  if (force_flush) s->stream_state_ = BROTLI_STREAM_FLUSH_REQUESTED;
1564
1664
  if (is_last) s->stream_state_ = BROTLI_STREAM_FINISHED;