brotli 0.2.3 → 0.4.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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +34 -0
  3. data/.github/workflows/publish.yml +34 -0
  4. data/Gemfile +6 -3
  5. data/Rakefile +16 -9
  6. data/brotli.gemspec +7 -13
  7. data/ext/brotli/brotli.c +209 -31
  8. data/ext/brotli/buffer.c +1 -7
  9. data/ext/brotli/buffer.h +1 -1
  10. data/ext/brotli/extconf.rb +20 -18
  11. data/lib/brotli/version.rb +1 -1
  12. data/test/brotli_test.rb +104 -0
  13. data/test/brotli_writer_test.rb +36 -0
  14. data/test/test_helper.rb +8 -0
  15. data/vendor/brotli/c/common/constants.c +15 -0
  16. data/vendor/brotli/c/common/constants.h +136 -0
  17. data/vendor/brotli/c/common/context.c +156 -0
  18. data/vendor/brotli/c/common/context.h +4 -152
  19. data/vendor/brotli/c/common/dictionary.bin.br +0 -0
  20. data/vendor/brotli/c/common/dictionary.c +10 -1
  21. data/vendor/brotli/c/common/platform.c +22 -0
  22. data/vendor/brotli/c/common/platform.h +43 -17
  23. data/vendor/brotli/c/common/transform.c +59 -3
  24. data/vendor/brotli/c/common/transform.h +5 -0
  25. data/vendor/brotli/c/common/version.h +2 -2
  26. data/vendor/brotli/c/dec/bit_reader.c +28 -0
  27. data/vendor/brotli/c/dec/bit_reader.h +58 -16
  28. data/vendor/brotli/c/dec/decode.c +353 -251
  29. data/vendor/brotli/c/dec/huffman.h +6 -12
  30. data/vendor/brotli/c/dec/prefix.h +0 -18
  31. data/vendor/brotli/c/dec/state.c +9 -14
  32. data/vendor/brotli/c/dec/state.h +144 -37
  33. data/vendor/brotli/c/enc/backward_references.c +8 -7
  34. data/vendor/brotli/c/enc/backward_references.h +5 -4
  35. data/vendor/brotli/c/enc/backward_references_hq.c +51 -33
  36. data/vendor/brotli/c/enc/backward_references_hq.h +11 -8
  37. data/vendor/brotli/c/enc/backward_references_inc.h +24 -14
  38. data/vendor/brotli/c/enc/block_splitter.c +3 -3
  39. data/vendor/brotli/c/enc/block_splitter_inc.h +15 -6
  40. data/vendor/brotli/c/enc/brotli_bit_stream.c +13 -30
  41. data/vendor/brotli/c/enc/cluster_inc.h +6 -3
  42. data/vendor/brotli/c/enc/command.c +28 -0
  43. data/vendor/brotli/c/enc/command.h +12 -12
  44. data/vendor/brotli/c/enc/compress_fragment_two_pass.c +1 -1
  45. data/vendor/brotli/c/enc/dictionary_hash.c +1826 -1100
  46. data/vendor/brotli/c/enc/dictionary_hash.h +2 -1
  47. data/vendor/brotli/c/enc/encode.c +104 -39
  48. data/vendor/brotli/c/enc/encoder_dict.c +3 -2
  49. data/vendor/brotli/c/enc/encoder_dict.h +3 -1
  50. data/vendor/brotli/c/enc/entropy_encode.c +2 -0
  51. data/vendor/brotli/c/enc/entropy_encode.h +2 -2
  52. data/vendor/brotli/c/enc/fast_log.c +105 -0
  53. data/vendor/brotli/c/enc/fast_log.h +19 -100
  54. data/vendor/brotli/c/enc/find_match_length.h +2 -3
  55. data/vendor/brotli/c/enc/hash.h +80 -90
  56. data/vendor/brotli/c/enc/hash_composite_inc.h +52 -63
  57. data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +88 -49
  58. data/vendor/brotli/c/enc/hash_longest_match64_inc.h +50 -50
  59. data/vendor/brotli/c/enc/hash_longest_match_inc.h +53 -50
  60. data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +91 -60
  61. data/vendor/brotli/c/enc/hash_rolling_inc.h +23 -27
  62. data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +39 -38
  63. data/vendor/brotli/c/enc/memory.h +24 -12
  64. data/vendor/brotli/c/enc/metablock.c +23 -27
  65. data/vendor/brotli/c/enc/metablock_inc.h +1 -1
  66. data/vendor/brotli/c/enc/params.h +3 -1
  67. data/vendor/brotli/c/enc/ringbuffer.h +4 -1
  68. data/vendor/brotli/c/enc/utf8_util.c +1 -1
  69. data/vendor/brotli/c/enc/write_bits.h +27 -25
  70. data/vendor/brotli/c/include/brotli/encode.h +22 -1
  71. data/vendor/brotli/c/include/brotli/port.h +14 -0
  72. metadata +17 -97
  73. data/.travis.yml +0 -31
  74. data/docs/Brotli.html +0 -485
  75. data/docs/Brotli/Error.html +0 -124
  76. data/docs/_index.html +0 -122
  77. data/docs/class_list.html +0 -51
  78. data/docs/css/common.css +0 -1
  79. data/docs/css/full_list.css +0 -58
  80. data/docs/css/style.css +0 -496
  81. data/docs/file.README.html +0 -127
  82. data/docs/file_list.html +0 -56
  83. data/docs/frames.html +0 -17
  84. data/docs/index.html +0 -127
  85. data/docs/js/app.js +0 -292
  86. data/docs/js/full_list.js +0 -216
  87. data/docs/js/jquery.js +0 -4
  88. data/docs/method_list.html +0 -67
  89. data/docs/top-level-namespace.html +0 -110
  90. data/spec/brotli_spec.rb +0 -88
  91. data/spec/inflate_spec.rb +0 -75
  92. data/spec/spec_helper.rb +0 -4
@@ -15,7 +15,8 @@
15
15
  extern "C" {
16
16
  #endif
17
17
 
18
- extern const uint16_t kStaticDictionaryHash[32768];
18
+ extern const uint16_t kStaticDictionaryHashWords[32768];
19
+ extern const uint8_t kStaticDictionaryHashLengths[32768];
19
20
 
20
21
  #if defined(__cplusplus) || defined(c_plusplus)
21
22
  } /* extern "C" */
@@ -54,12 +54,19 @@ typedef enum BrotliEncoderStreamState {
54
54
  BROTLI_STREAM_METADATA_BODY = 4
55
55
  } BrotliEncoderStreamState;
56
56
 
57
+ typedef enum BrotliEncoderFlintState {
58
+ BROTLI_FLINT_NEEDS_2_BYTES = 2,
59
+ BROTLI_FLINT_NEEDS_1_BYTE = 1,
60
+ BROTLI_FLINT_WAITING_FOR_PROCESSING = 0,
61
+ BROTLI_FLINT_WAITING_FOR_FLUSHING = -1,
62
+ BROTLI_FLINT_DONE = -2
63
+ } BrotliEncoderFlintState;
64
+
57
65
  typedef struct BrotliEncoderStateStruct {
58
66
  BrotliEncoderParams params;
59
67
 
60
68
  MemoryManager memory_manager_;
61
69
 
62
- HasherHandle hasher_;
63
70
  uint64_t input_pos_;
64
71
  RingBuffer ringbuffer_;
65
72
  size_t cmd_alloc_size_;
@@ -73,10 +80,17 @@ typedef struct BrotliEncoderStateStruct {
73
80
  int saved_dist_cache_[4];
74
81
  uint16_t last_bytes_;
75
82
  uint8_t last_bytes_bits_;
83
+ /* "Flint" is a tiny uncompressed block emitted before the continuation
84
+ block to unwire literal context from previous data. Despite being int8_t,
85
+ field is actually BrotliEncoderFlintState enum. */
86
+ int8_t flint_;
76
87
  uint8_t prev_byte_;
77
88
  uint8_t prev_byte2_;
78
89
  size_t storage_size_;
79
90
  uint8_t* storage_;
91
+
92
+ Hasher hasher_;
93
+
80
94
  /* Hash table for FAST_ONE_PASS_COMPRESSION_QUALITY mode. */
81
95
  int small_table_[1 << 10]; /* 4KiB */
82
96
  int* large_table_; /* Allocated only when needed */
@@ -114,8 +128,6 @@ typedef struct BrotliEncoderStateStruct {
114
128
  BROTLI_BOOL is_initialized_;
115
129
  } BrotliEncoderStateStruct;
116
130
 
117
- static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s);
118
-
119
131
  static size_t InputBlockSize(BrotliEncoderState* s) {
120
132
  return (size_t)1 << s->params.lgblock;
121
133
  }
@@ -174,6 +186,11 @@ BROTLI_BOOL BrotliEncoderSetParameter(
174
186
  state->params.dist.num_direct_distance_codes = value;
175
187
  return BROTLI_TRUE;
176
188
 
189
+ case BROTLI_PARAM_STREAM_OFFSET:
190
+ if (value > (1u << 30)) return BROTLI_FALSE;
191
+ state->params.stream_offset = value;
192
+ return BROTLI_TRUE;
193
+
177
194
  default: return BROTLI_FALSE;
178
195
  }
179
196
  }
@@ -195,7 +212,7 @@ static uint8_t* GetBrotliStorage(BrotliEncoderState* s, size_t size) {
195
212
  if (s->storage_size_ < size) {
196
213
  BROTLI_FREE(m, s->storage_);
197
214
  s->storage_ = BROTLI_ALLOC(m, uint8_t, size);
198
- if (BROTLI_IS_OOM(m)) return NULL;
215
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->storage_)) return NULL;
199
216
  s->storage_size_ = size;
200
217
  }
201
218
  return s->storage_;
@@ -234,7 +251,7 @@ static int* GetHashTable(BrotliEncoderState* s, int quality,
234
251
  s->large_table_size_ = htsize;
235
252
  BROTLI_FREE(m, s->large_table_);
236
253
  s->large_table_ = BROTLI_ALLOC(m, int, htsize);
237
- if (BROTLI_IS_OOM(m)) return 0;
254
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->large_table_)) return 0;
238
255
  }
239
256
  table = s->large_table_;
240
257
  }
@@ -499,7 +516,7 @@ static BROTLI_BOOL ShouldCompress(
499
516
  /* TODO: find more precise minimal block overhead. */
500
517
  if (bytes <= 2) return BROTLI_FALSE;
501
518
  if (num_commands < (bytes >> 8) + 2) {
502
- if (num_literals > 0.99 * (double)bytes) {
519
+ if ((double)num_literals > 0.99 * (double)bytes) {
503
520
  uint32_t literal_histo[256] = { 0 };
504
521
  static const uint32_t kSampleRate = 13;
505
522
  static const double kMinEntropy = 7.92;
@@ -617,11 +634,7 @@ static void WriteMetaBlockInternal(MemoryManager* m,
617
634
  /* The number of distance symbols effectively used for distance
618
635
  histograms. It might be less than distance alphabet size
619
636
  for "Large Window Brotli" (32-bit). */
620
- uint32_t num_effective_dist_codes = block_params.dist.alphabet_size;
621
- if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
622
- num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
623
- }
624
- BrotliOptimizeHistograms(num_effective_dist_codes, &mb);
637
+ BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
625
638
  }
626
639
  BrotliStoreMetaBlock(m, data, wrapped_last_flush_pos, bytes, mask,
627
640
  prev_byte, prev_byte2,
@@ -678,12 +691,23 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
678
691
 
679
692
  s->last_bytes_bits_ = 0;
680
693
  s->last_bytes_ = 0;
694
+ s->flint_ = BROTLI_FLINT_DONE;
681
695
  s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
682
696
 
683
697
  SanitizeParams(&s->params);
684
698
  s->params.lgblock = ComputeLgBlock(&s->params);
685
699
  ChooseDistanceParams(&s->params);
686
700
 
701
+ if (s->params.stream_offset != 0) {
702
+ s->flint_ = BROTLI_FLINT_NEEDS_2_BYTES;
703
+ /* Poison the distance cache. -16 +- 3 is still less than zero (invalid). */
704
+ s->dist_cache_[0] = -16;
705
+ s->dist_cache_[1] = -16;
706
+ s->dist_cache_[2] = -16;
707
+ s->dist_cache_[3] = -16;
708
+ memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_));
709
+ }
710
+
687
711
  RingBufferSetup(&s->params, &s->ringbuffer_);
688
712
 
689
713
  /* Initialize last byte with stream header. */
@@ -693,8 +717,14 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
693
717
  s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
694
718
  lgwin = BROTLI_MAX(int, lgwin, 18);
695
719
  }
696
- EncodeWindowBits(lgwin, s->params.large_window,
697
- &s->last_bytes_, &s->last_bytes_bits_);
720
+ if (s->params.stream_offset == 0) {
721
+ EncodeWindowBits(lgwin, s->params.large_window,
722
+ &s->last_bytes_, &s->last_bytes_bits_);
723
+ } else {
724
+ /* Bigger values have the same effect, but could cause overflows. */
725
+ s->params.stream_offset = BROTLI_MIN(size_t,
726
+ s->params.stream_offset, BROTLI_MAX_BACKWARD_LIMIT(lgwin));
727
+ }
698
728
  }
699
729
 
700
730
  if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) {
@@ -712,13 +742,15 @@ static void BrotliEncoderInitParams(BrotliEncoderParams* params) {
712
742
  params->quality = BROTLI_DEFAULT_QUALITY;
713
743
  params->lgwin = BROTLI_DEFAULT_WINDOW;
714
744
  params->lgblock = 0;
745
+ params->stream_offset = 0;
715
746
  params->size_hint = 0;
716
747
  params->disable_literal_context_modeling = BROTLI_FALSE;
717
748
  BrotliInitEncoderDictionary(&params->dictionary);
718
749
  params->dist.distance_postfix_bits = 0;
719
750
  params->dist.num_direct_distance_codes = 0;
720
- params->dist.alphabet_size =
751
+ params->dist.alphabet_size_max =
721
752
  BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_MAX_DISTANCE_BITS);
753
+ params->dist.alphabet_size_limit = params->dist.alphabet_size_max;
722
754
  params->dist.max_distance = BROTLI_MAX_DISTANCE;
723
755
  }
724
756
 
@@ -734,7 +766,7 @@ static void BrotliEncoderInitState(BrotliEncoderState* s) {
734
766
  s->prev_byte2_ = 0;
735
767
  s->storage_size_ = 0;
736
768
  s->storage_ = 0;
737
- s->hasher_ = NULL;
769
+ HasherInit(&s->hasher_);
738
770
  s->large_table_ = NULL;
739
771
  s->large_table_size_ = 0;
740
772
  s->cmd_code_numbits_ = 0;
@@ -902,6 +934,7 @@ static void ExtendLastCommand(BrotliEncoderState* s, uint32_t* bytes,
902
934
  (*bytes)--;
903
935
  (*wrapped_last_processed_pos)++;
904
936
  }
937
+ } else {
905
938
  }
906
939
  /* The copy length is at most the metablock size, and thus expressible. */
907
940
  GetLengthCode(last_command->insert_len_,
@@ -934,6 +967,7 @@ static BROTLI_BOOL EncodeData(
934
967
  uint32_t mask;
935
968
  MemoryManager* m = &s->memory_manager_;
936
969
  ContextType literal_context_mode;
970
+ ContextLut literal_context_lut;
937
971
 
938
972
  data = s->ringbuffer_.buffer_;
939
973
  mask = s->ringbuffer_.mask_;
@@ -951,7 +985,10 @@ static BROTLI_BOOL EncodeData(
951
985
  BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
952
986
  s->literal_buf_ =
953
987
  BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
954
- if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
988
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
989
+ BROTLI_IS_NULL(s->literal_buf_)) {
990
+ return BROTLI_FALSE;
991
+ }
955
992
  }
956
993
 
957
994
  if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
@@ -1009,7 +1046,7 @@ static BROTLI_BOOL EncodeData(
1009
1046
  newsize += (bytes / 4) + 16;
1010
1047
  s->cmd_alloc_size_ = newsize;
1011
1048
  new_commands = BROTLI_ALLOC(m, Command, newsize);
1012
- if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1049
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) return BROTLI_FALSE;
1013
1050
  if (s->commands_) {
1014
1051
  memcpy(new_commands, s->commands_, sizeof(Command) * s->num_commands_);
1015
1052
  BROTLI_FREE(m, s->commands_);
@@ -1024,6 +1061,7 @@ static BROTLI_BOOL EncodeData(
1024
1061
  literal_context_mode = ChooseContextMode(
1025
1062
  &s->params, data, WrapPosition(s->last_flush_pos_),
1026
1063
  mask, (size_t)(s->input_pos_ - s->last_flush_pos_));
1064
+ literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
1027
1065
 
1028
1066
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1029
1067
 
@@ -1034,20 +1072,23 @@ static BROTLI_BOOL EncodeData(
1034
1072
  if (s->params.quality == ZOPFLIFICATION_QUALITY) {
1035
1073
  BROTLI_DCHECK(s->params.hasher.type == 10);
1036
1074
  BrotliCreateZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
1037
- data, mask, &s->params, s->hasher_, s->dist_cache_,
1075
+ data, mask, literal_context_lut, &s->params,
1076
+ &s->hasher_, s->dist_cache_,
1038
1077
  &s->last_insert_len_, &s->commands_[s->num_commands_],
1039
1078
  &s->num_commands_, &s->num_literals_);
1040
1079
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1041
1080
  } else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) {
1042
1081
  BROTLI_DCHECK(s->params.hasher.type == 10);
1043
1082
  BrotliCreateHqZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
1044
- data, mask, &s->params, s->hasher_, s->dist_cache_,
1083
+ data, mask, literal_context_lut, &s->params,
1084
+ &s->hasher_, s->dist_cache_,
1045
1085
  &s->last_insert_len_, &s->commands_[s->num_commands_],
1046
1086
  &s->num_commands_, &s->num_literals_);
1047
1087
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1048
1088
  } else {
1049
1089
  BrotliCreateBackwardReferences(bytes, wrapped_last_processed_pos,
1050
- data, mask, &s->params, s->hasher_, s->dist_cache_,
1090
+ data, mask, literal_context_lut, &s->params,
1091
+ &s->hasher_, s->dist_cache_,
1051
1092
  &s->last_insert_len_, &s->commands_[s->num_commands_],
1052
1093
  &s->num_commands_, &s->num_literals_);
1053
1094
  }
@@ -1072,7 +1113,7 @@ static BROTLI_BOOL EncodeData(
1072
1113
  s->num_commands_ < max_commands) {
1073
1114
  /* Merge with next input block. Everything will happen later. */
1074
1115
  if (UpdateLastProcessedPos(s)) {
1075
- HasherReset(s->hasher_);
1116
+ HasherReset(&s->hasher_);
1076
1117
  }
1077
1118
  *out_size = 0;
1078
1119
  return BROTLI_TRUE;
@@ -1113,7 +1154,7 @@ static BROTLI_BOOL EncodeData(
1113
1154
  s->last_bytes_bits_ = storage_ix & 7u;
1114
1155
  s->last_flush_pos_ = s->input_pos_;
1115
1156
  if (UpdateLastProcessedPos(s)) {
1116
- HasherReset(s->hasher_);
1157
+ HasherReset(&s->hasher_);
1117
1158
  }
1118
1159
  if (s->last_flush_pos_ > 0) {
1119
1160
  s->prev_byte_ = data[((uint32_t)s->last_flush_pos_ - 1) & mask];
@@ -1174,7 +1215,6 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1174
1215
  size_t total_out_size = 0;
1175
1216
  uint16_t last_bytes;
1176
1217
  uint8_t last_bytes_bits;
1177
- HasherHandle hasher = NULL;
1178
1218
 
1179
1219
  const size_t hasher_eff_size = BROTLI_MIN(size_t,
1180
1220
  input_size, BROTLI_MAX_BACKWARD_LIMIT(lgwin) + BROTLI_WINDOW_GAP);
@@ -1190,6 +1230,9 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1190
1230
  uint8_t prev_byte = 0;
1191
1231
  uint8_t prev_byte2 = 0;
1192
1232
 
1233
+ Hasher hasher;
1234
+ HasherInit(&hasher);
1235
+
1193
1236
  BrotliEncoderInitParams(&params);
1194
1237
  params.quality = 10;
1195
1238
  params.lgwin = lgwin;
@@ -1226,6 +1269,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1226
1269
 
1227
1270
  ContextType literal_context_mode = ChooseContextMode(&params,
1228
1271
  input_buffer, metablock_start, mask, metablock_end - metablock_start);
1272
+ ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
1229
1273
 
1230
1274
  size_t block_start;
1231
1275
  for (block_start = metablock_start; block_start < metablock_end; ) {
@@ -1234,12 +1278,12 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1234
1278
  ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, block_size + 1);
1235
1279
  size_t path_size;
1236
1280
  size_t new_cmd_alloc_size;
1237
- if (BROTLI_IS_OOM(m)) goto oom;
1281
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) goto oom;
1238
1282
  BrotliInitZopfliNodes(nodes, block_size + 1);
1239
- StitchToPreviousBlockH10(hasher, block_size, block_start,
1283
+ StitchToPreviousBlockH10(&hasher.privat._H10, block_size, block_start,
1240
1284
  input_buffer, mask);
1241
1285
  path_size = BrotliZopfliComputeShortestPath(m, block_size, block_start,
1242
- input_buffer, mask, &params, dist_cache, hasher,
1286
+ input_buffer, mask, literal_context_lut, &params, dist_cache, &hasher,
1243
1287
  nodes);
1244
1288
  if (BROTLI_IS_OOM(m)) goto oom;
1245
1289
  /* We allocate a command buffer in the first iteration of this loop that
@@ -1254,7 +1298,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1254
1298
  num_commands + path_size + 1);
1255
1299
  if (cmd_alloc_size != new_cmd_alloc_size) {
1256
1300
  Command* new_commands = BROTLI_ALLOC(m, Command, new_cmd_alloc_size);
1257
- if (BROTLI_IS_OOM(m)) goto oom;
1301
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) goto oom;
1258
1302
  cmd_alloc_size = new_cmd_alloc_size;
1259
1303
  if (commands) {
1260
1304
  memcpy(new_commands, commands, sizeof(Command) * num_commands);
@@ -1286,7 +1330,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1286
1330
  if (metablock_size == 0) {
1287
1331
  /* Write the ISLAST and ISEMPTY bits. */
1288
1332
  storage = BROTLI_ALLOC(m, uint8_t, 16);
1289
- if (BROTLI_IS_OOM(m)) goto oom;
1333
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
1290
1334
  storage[0] = (uint8_t)last_bytes;
1291
1335
  storage[1] = (uint8_t)(last_bytes >> 8);
1292
1336
  BrotliWriteBits(2, 3, &storage_ix, storage);
@@ -1297,7 +1341,7 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1297
1341
  CreateBackwardReferences is now unused. */
1298
1342
  memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
1299
1343
  storage = BROTLI_ALLOC(m, uint8_t, metablock_size + 16);
1300
- if (BROTLI_IS_OOM(m)) goto oom;
1344
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
1301
1345
  storage[0] = (uint8_t)last_bytes;
1302
1346
  storage[1] = (uint8_t)(last_bytes >> 8);
1303
1347
  BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
@@ -1318,14 +1362,10 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
1318
1362
  /* The number of distance symbols effectively used for distance
1319
1363
  histograms. It might be less than distance alphabet size
1320
1364
  for "Large Window Brotli" (32-bit). */
1321
- uint32_t num_effective_dist_codes = block_params.dist.alphabet_size;
1322
- if (num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS) {
1323
- num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
1324
- }
1325
- BrotliOptimizeHistograms(num_effective_dist_codes, &mb);
1365
+ BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb);
1326
1366
  }
1327
1367
  storage = BROTLI_ALLOC(m, uint8_t, 2 * metablock_size + 503);
1328
- if (BROTLI_IS_OOM(m)) goto oom;
1368
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
1329
1369
  storage[0] = (uint8_t)last_bytes;
1330
1370
  storage[1] = (uint8_t)(last_bytes >> 8);
1331
1371
  BrotliStoreMetaBlock(m, input_buffer, metablock_start, metablock_size,
@@ -1576,7 +1616,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
1576
1616
  BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize);
1577
1617
  s->literal_buf_ =
1578
1618
  BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize);
1579
- if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1619
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) ||
1620
+ BROTLI_IS_NULL(s->literal_buf_)) {
1621
+ return BROTLI_FALSE;
1622
+ }
1580
1623
  }
1581
1624
  if (s->command_buf_) {
1582
1625
  command_buf = s->command_buf_;
@@ -1584,7 +1627,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
1584
1627
  } else {
1585
1628
  tmp_command_buf = BROTLI_ALLOC(m, uint32_t, buf_size);
1586
1629
  tmp_literal_buf = BROTLI_ALLOC(m, uint8_t, buf_size);
1587
- if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1630
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp_command_buf) ||
1631
+ BROTLI_IS_NULL(tmp_literal_buf)) {
1632
+ return BROTLI_FALSE;
1633
+ }
1588
1634
  command_buf = tmp_command_buf;
1589
1635
  literal_buf = tmp_literal_buf;
1590
1636
  }
@@ -1640,8 +1686,10 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
1640
1686
  &storage_ix, storage);
1641
1687
  if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
1642
1688
  }
1643
- *next_in += block_size;
1644
- *available_in -= block_size;
1689
+ if (block_size != 0) {
1690
+ *next_in += block_size;
1691
+ *available_in -= block_size;
1692
+ }
1645
1693
  if (inplace) {
1646
1694
  size_t out_bytes = storage_ix >> 3;
1647
1695
  BROTLI_DCHECK(out_bytes <= *available_out);
@@ -1786,6 +1834,10 @@ BROTLI_BOOL BrotliEncoderCompressStream(
1786
1834
  }
1787
1835
  while (BROTLI_TRUE) {
1788
1836
  size_t remaining_block_size = RemainingInputBlockSize(s);
1837
+ /* Shorten input to flint size. */
1838
+ if (s->flint_ >= 0 && remaining_block_size > (size_t)s->flint_) {
1839
+ remaining_block_size = (size_t)s->flint_;
1840
+ }
1789
1841
 
1790
1842
  if (remaining_block_size != 0 && *available_in != 0) {
1791
1843
  size_t copy_input_size =
@@ -1793,10 +1845,18 @@ BROTLI_BOOL BrotliEncoderCompressStream(
1793
1845
  CopyInputToRingBuffer(s, copy_input_size, *next_in);
1794
1846
  *next_in += copy_input_size;
1795
1847
  *available_in -= copy_input_size;
1848
+ if (s->flint_ > 0) s->flint_ = (int8_t)(s->flint_ - (int)copy_input_size);
1796
1849
  continue;
1797
1850
  }
1798
1851
 
1799
1852
  if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) {
1853
+ /* Exit the "emit flint" workflow. */
1854
+ if (s->flint_ == BROTLI_FLINT_WAITING_FOR_FLUSHING) {
1855
+ CheckFlushComplete(s);
1856
+ if (s->stream_state_ == BROTLI_STREAM_PROCESSING) {
1857
+ s->flint_ = BROTLI_FLINT_DONE;
1858
+ }
1859
+ }
1800
1860
  continue;
1801
1861
  }
1802
1862
 
@@ -1810,6 +1870,11 @@ BROTLI_BOOL BrotliEncoderCompressStream(
1810
1870
  BROTLI_BOOL force_flush = TO_BROTLI_BOOL(
1811
1871
  (*available_in == 0) && op == BROTLI_OPERATION_FLUSH);
1812
1872
  BROTLI_BOOL result;
1873
+ /* Force emitting (uncompressed) piece containing flint. */
1874
+ if (!is_last && s->flint_ == 0) {
1875
+ s->flint_ = BROTLI_FLINT_WAITING_FOR_FLUSHING;
1876
+ force_flush = BROTLI_TRUE;
1877
+ }
1813
1878
  UpdateSizeHint(s, *available_in);
1814
1879
  result = EncodeData(s, is_last, force_flush,
1815
1880
  &s->available_out_, &s->next_out_);
@@ -17,14 +17,15 @@ extern "C" {
17
17
 
18
18
  void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict) {
19
19
  dict->words = BrotliGetDictionary();
20
+ dict->num_transforms = (uint32_t)BrotliGetTransforms()->num_transforms;
20
21
 
21
- dict->hash_table = kStaticDictionaryHash;
22
+ dict->hash_table_words = kStaticDictionaryHashWords;
23
+ dict->hash_table_lengths = kStaticDictionaryHashLengths;
22
24
  dict->buckets = kStaticDictionaryBuckets;
23
25
  dict->dict_words = kStaticDictionaryWords;
24
26
 
25
27
  dict->cutoffTransformsCount = kCutoffTransformsCount;
26
28
  dict->cutoffTransforms = kCutoffTransforms;
27
-
28
29
  }
29
30
 
30
31
  #if defined(__cplusplus) || defined(c_plusplus)
@@ -19,13 +19,15 @@ extern "C" {
19
19
  /* Dictionary data (words and transforms) for 1 possible context */
20
20
  typedef struct BrotliEncoderDictionary {
21
21
  const BrotliDictionary* words;
22
+ uint32_t num_transforms;
22
23
 
23
24
  /* cut off for fast encoder */
24
25
  uint32_t cutoffTransformsCount;
25
26
  uint64_t cutoffTransforms;
26
27
 
27
28
  /* from dictionary_hash.h, for fast encoder */
28
- const uint16_t* hash_table;
29
+ const uint16_t* hash_table_words;
30
+ const uint8_t* hash_table_lengths;
29
31
 
30
32
  /* from static_dict_lut.h, for slow encoder */
31
33
  const uint16_t* buckets;