brotli 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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;