github.com/andybalholm/brotli@v1.0.6/encode.go (about) 1 package brotli 2 3 import ( 4 "io" 5 "math" 6 ) 7 8 /* Copyright 2016 Google Inc. All Rights Reserved. 9 10 Distributed under MIT license. 11 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 12 */ 13 14 /** Minimal value for ::BROTLI_PARAM_LGWIN parameter. */ 15 const minWindowBits = 10 16 17 /** 18 * Maximal value for ::BROTLI_PARAM_LGWIN parameter. 19 * 20 * @note equal to @c BROTLI_MAX_DISTANCE_BITS constant. 21 */ 22 const maxWindowBits = 24 23 24 /** 25 * Maximal value for ::BROTLI_PARAM_LGWIN parameter 26 * in "Large Window Brotli" (32-bit). 27 */ 28 const largeMaxWindowBits = 30 29 30 /** Minimal value for ::BROTLI_PARAM_LGBLOCK parameter. */ 31 const minInputBlockBits = 16 32 33 /** Maximal value for ::BROTLI_PARAM_LGBLOCK parameter. */ 34 const maxInputBlockBits = 24 35 36 /** Minimal value for ::BROTLI_PARAM_QUALITY parameter. */ 37 const minQuality = 0 38 39 /** Maximal value for ::BROTLI_PARAM_QUALITY parameter. */ 40 const maxQuality = 11 41 42 /** Options for ::BROTLI_PARAM_MODE parameter. */ 43 const ( 44 modeGeneric = 0 45 modeText = 1 46 modeFont = 2 47 ) 48 49 /** Default value for ::BROTLI_PARAM_QUALITY parameter. */ 50 const defaultQuality = 11 51 52 /** Default value for ::BROTLI_PARAM_LGWIN parameter. */ 53 const defaultWindow = 22 54 55 /** Default value for ::BROTLI_PARAM_MODE parameter. */ 56 const defaultMode = modeGeneric 57 58 /** Operations that can be performed by streaming encoder. */ 59 const ( 60 operationProcess = 0 61 operationFlush = 1 62 operationFinish = 2 63 operationEmitMetadata = 3 64 ) 65 66 const ( 67 streamProcessing = 0 68 streamFlushRequested = 1 69 streamFinished = 2 70 streamMetadataHead = 3 71 streamMetadataBody = 4 72 ) 73 74 type Writer struct { 75 dst io.Writer 76 options WriterOptions 77 err error 78 79 params encoderParams 80 hasher_ hasherHandle 81 input_pos_ uint64 82 ringbuffer_ ringBuffer 83 commands []command 84 num_literals_ uint 85 last_insert_len_ uint 86 last_flush_pos_ uint64 87 last_processed_pos_ uint64 88 dist_cache_ [numDistanceShortCodes]int 89 saved_dist_cache_ [4]int 90 last_bytes_ uint16 91 last_bytes_bits_ byte 92 prev_byte_ byte 93 prev_byte2_ byte 94 storage []byte 95 small_table_ [1 << 10]int 96 large_table_ []int 97 large_table_size_ uint 98 cmd_depths_ [128]byte 99 cmd_bits_ [128]uint16 100 cmd_code_ [512]byte 101 cmd_code_numbits_ uint 102 command_buf_ []uint32 103 literal_buf_ []byte 104 tiny_buf_ struct { 105 u64 [2]uint64 106 u8 [16]byte 107 } 108 remaining_metadata_bytes_ uint32 109 stream_state_ int 110 is_last_block_emitted_ bool 111 is_initialized_ bool 112 } 113 114 func inputBlockSize(s *Writer) uint { 115 return uint(1) << uint(s.params.lgblock) 116 } 117 118 func unprocessedInputSize(s *Writer) uint64 { 119 return s.input_pos_ - s.last_processed_pos_ 120 } 121 122 func remainingInputBlockSize(s *Writer) uint { 123 var delta uint64 = unprocessedInputSize(s) 124 var block_size uint = inputBlockSize(s) 125 if delta >= uint64(block_size) { 126 return 0 127 } 128 return block_size - uint(delta) 129 } 130 131 /* Wraps 64-bit input position to 32-bit ring-buffer position preserving 132 "not-a-first-lap" feature. */ 133 func wrapPosition(position uint64) uint32 { 134 var result uint32 = uint32(position) 135 var gb uint64 = position >> 30 136 if gb > 2 { 137 /* Wrap every 2GiB; The first 3GB are continuous. */ 138 result = result&((1<<30)-1) | (uint32((gb-1)&1)+1)<<30 139 } 140 141 return result 142 } 143 144 func (s *Writer) getStorage(size int) []byte { 145 if len(s.storage) < size { 146 s.storage = make([]byte, size) 147 } 148 149 return s.storage 150 } 151 152 func hashTableSize(max_table_size uint, input_size uint) uint { 153 var htsize uint = 256 154 for htsize < max_table_size && htsize < input_size { 155 htsize <<= 1 156 } 157 158 return htsize 159 } 160 161 func getHashTable(s *Writer, quality int, input_size uint, table_size *uint) []int { 162 var max_table_size uint = maxHashTableSize(quality) 163 var htsize uint = hashTableSize(max_table_size, input_size) 164 /* Use smaller hash table when input.size() is smaller, since we 165 fill the table, incurring O(hash table size) overhead for 166 compression, and if the input is short, we won't need that 167 many hash table entries anyway. */ 168 169 var table []int 170 assert(max_table_size >= 256) 171 if quality == fastOnePassCompressionQuality { 172 /* Only odd shifts are supported by fast-one-pass. */ 173 if htsize&0xAAAAA == 0 { 174 htsize <<= 1 175 } 176 } 177 178 if htsize <= uint(len(s.small_table_)) { 179 table = s.small_table_[:] 180 } else { 181 if htsize > s.large_table_size_ { 182 s.large_table_size_ = htsize 183 s.large_table_ = nil 184 s.large_table_ = make([]int, htsize) 185 } 186 187 table = s.large_table_ 188 } 189 190 *table_size = htsize 191 for i := 0; i < int(htsize); i++ { 192 table[i] = 0 193 } 194 return table 195 } 196 197 func encodeWindowBits(lgwin int, large_window bool, last_bytes *uint16, last_bytes_bits *byte) { 198 if large_window { 199 *last_bytes = uint16((lgwin&0x3F)<<8 | 0x11) 200 *last_bytes_bits = 14 201 } else { 202 if lgwin == 16 { 203 *last_bytes = 0 204 *last_bytes_bits = 1 205 } else if lgwin == 17 { 206 *last_bytes = 1 207 *last_bytes_bits = 7 208 } else if lgwin > 17 { 209 *last_bytes = uint16((lgwin-17)<<1 | 0x01) 210 *last_bytes_bits = 4 211 } else { 212 *last_bytes = uint16((lgwin-8)<<4 | 0x01) 213 *last_bytes_bits = 7 214 } 215 } 216 } 217 218 /* Decide about the context map based on the ability of the prediction 219 ability of the previous byte UTF8-prefix on the next byte. The 220 prediction ability is calculated as Shannon entropy. Here we need 221 Shannon entropy instead of 'BitsEntropy' since the prefix will be 222 encoded with the remaining 6 bits of the following byte, and 223 BitsEntropy will assume that symbol to be stored alone using Huffman 224 coding. */ 225 226 var kStaticContextMapContinuation = [64]uint32{ 227 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 229 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231 } 232 var kStaticContextMapSimpleUTF8 = [64]uint32{ 233 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 235 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237 } 238 239 func chooseContextMap(quality int, bigram_histo []uint32, num_literal_contexts *uint, literal_context_map *[]uint32) { 240 var monogram_histo = [3]uint32{0} 241 var two_prefix_histo = [6]uint32{0} 242 var total uint 243 var i uint 244 var dummy uint 245 var entropy [4]float64 246 for i = 0; i < 9; i++ { 247 monogram_histo[i%3] += bigram_histo[i] 248 two_prefix_histo[i%6] += bigram_histo[i] 249 } 250 251 entropy[1] = shannonEntropy(monogram_histo[:], 3, &dummy) 252 entropy[2] = (shannonEntropy(two_prefix_histo[:], 3, &dummy) + shannonEntropy(two_prefix_histo[3:], 3, &dummy)) 253 entropy[3] = 0 254 for i = 0; i < 3; i++ { 255 entropy[3] += shannonEntropy(bigram_histo[3*i:], 3, &dummy) 256 } 257 258 total = uint(monogram_histo[0] + monogram_histo[1] + monogram_histo[2]) 259 assert(total != 0) 260 entropy[0] = 1.0 / float64(total) 261 entropy[1] *= entropy[0] 262 entropy[2] *= entropy[0] 263 entropy[3] *= entropy[0] 264 265 if quality < minQualityForHqContextModeling { 266 /* 3 context models is a bit slower, don't use it at lower qualities. */ 267 entropy[3] = entropy[1] * 10 268 } 269 270 /* If expected savings by symbol are less than 0.2 bits, skip the 271 context modeling -- in exchange for faster decoding speed. */ 272 if entropy[1]-entropy[2] < 0.2 && entropy[1]-entropy[3] < 0.2 { 273 *num_literal_contexts = 1 274 } else if entropy[2]-entropy[3] < 0.02 { 275 *num_literal_contexts = 2 276 *literal_context_map = kStaticContextMapSimpleUTF8[:] 277 } else { 278 *num_literal_contexts = 3 279 *literal_context_map = kStaticContextMapContinuation[:] 280 } 281 } 282 283 /* Decide if we want to use a more complex static context map containing 13 284 context values, based on the entropy reduction of histograms over the 285 first 5 bits of literals. */ 286 287 var kStaticContextMapComplexUTF8 = [64]uint32{ 288 11, 11, 12, 12, /* 0 special */ 289 0, 0, 0, 0, /* 4 lf */ 290 1, 1, 9, 9, /* 8 space */ 291 2, 2, 2, 2, /* !, first after space/lf and after something else. */ 292 1, 1, 1, 1, /* " */ 293 8, 3, 3, 3, /* % */ 294 1, 1, 1, 1, /* ({[ */ 295 2, 2, 2, 2, /* }]) */ 296 8, 4, 4, 4, /* :; */ 297 8, 7, 4, 4, /* . */ 298 8, 0, 0, 0, /* > */ 299 3, 3, 3, 3, /* [0..9] */ 300 5, 5, 10, 5, /* [A-Z] */ 301 5, 5, 10, 5, 302 6, 6, 6, 6, /* [a-z] */ 303 6, 6, 6, 6, 304 } 305 306 func shouldUseComplexStaticContextMap(input []byte, start_pos uint, length uint, mask uint, quality int, size_hint uint, num_literal_contexts *uint, literal_context_map *[]uint32) bool { 307 /* Try the more complex static context map only for long data. */ 308 if size_hint < 1<<20 { 309 return false 310 } else { 311 var end_pos uint = start_pos + length 312 var combined_histo = [32]uint32{0} 313 var context_histo = [13][32]uint32{[32]uint32{0}} 314 var total uint32 = 0 315 var entropy [3]float64 316 var dummy uint 317 var i uint 318 var utf8_lut contextLUT = getContextLUT(contextUTF8) 319 /* To make entropy calculations faster and to fit on the stack, we collect 320 histograms over the 5 most significant bits of literals. One histogram 321 without context and 13 additional histograms for each context value. */ 322 for ; start_pos+64 <= end_pos; start_pos += 4096 { 323 var stride_end_pos uint = start_pos + 64 324 var prev2 byte = input[start_pos&mask] 325 var prev1 byte = input[(start_pos+1)&mask] 326 var pos uint 327 328 /* To make the analysis of the data faster we only examine 64 byte long 329 strides at every 4kB intervals. */ 330 for pos = start_pos + 2; pos < stride_end_pos; pos++ { 331 var literal byte = input[pos&mask] 332 var context byte = byte(kStaticContextMapComplexUTF8[getContext(prev1, prev2, utf8_lut)]) 333 total++ 334 combined_histo[literal>>3]++ 335 context_histo[context][literal>>3]++ 336 prev2 = prev1 337 prev1 = literal 338 } 339 } 340 341 entropy[1] = shannonEntropy(combined_histo[:], 32, &dummy) 342 entropy[2] = 0 343 for i = 0; i < 13; i++ { 344 entropy[2] += shannonEntropy(context_histo[i][0:], 32, &dummy) 345 } 346 347 entropy[0] = 1.0 / float64(total) 348 entropy[1] *= entropy[0] 349 entropy[2] *= entropy[0] 350 351 /* The triggering heuristics below were tuned by compressing the individual 352 files of the silesia corpus. If we skip this kind of context modeling 353 for not very well compressible input (i.e. entropy using context modeling 354 is 60% of maximal entropy) or if expected savings by symbol are less 355 than 0.2 bits, then in every case when it triggers, the final compression 356 ratio is improved. Note however that this heuristics might be too strict 357 for some cases and could be tuned further. */ 358 if entropy[2] > 3.0 || entropy[1]-entropy[2] < 0.2 { 359 return false 360 } else { 361 *num_literal_contexts = 13 362 *literal_context_map = kStaticContextMapComplexUTF8[:] 363 return true 364 } 365 } 366 } 367 368 func decideOverLiteralContextModeling(input []byte, start_pos uint, length uint, mask uint, quality int, size_hint uint, num_literal_contexts *uint, literal_context_map *[]uint32) { 369 if quality < minQualityForContextModeling || length < 64 { 370 return 371 } else if shouldUseComplexStaticContextMap(input, start_pos, length, mask, quality, size_hint, num_literal_contexts, literal_context_map) { 372 } else /* Context map was already set, nothing else to do. */ 373 { 374 var end_pos uint = start_pos + length 375 /* Gather bi-gram data of the UTF8 byte prefixes. To make the analysis of 376 UTF8 data faster we only examine 64 byte long strides at every 4kB 377 intervals. */ 378 379 var bigram_prefix_histo = [9]uint32{0} 380 for ; start_pos+64 <= end_pos; start_pos += 4096 { 381 var lut = [4]int{0, 0, 1, 2} 382 var stride_end_pos uint = start_pos + 64 383 var prev int = lut[input[start_pos&mask]>>6] * 3 384 var pos uint 385 for pos = start_pos + 1; pos < stride_end_pos; pos++ { 386 var literal byte = input[pos&mask] 387 bigram_prefix_histo[prev+lut[literal>>6]]++ 388 prev = lut[literal>>6] * 3 389 } 390 } 391 392 chooseContextMap(quality, bigram_prefix_histo[0:], num_literal_contexts, literal_context_map) 393 } 394 } 395 396 func shouldCompress_encode(data []byte, mask uint, last_flush_pos uint64, bytes uint, num_literals uint, num_commands uint) bool { 397 /* TODO: find more precise minimal block overhead. */ 398 if bytes <= 2 { 399 return false 400 } 401 if num_commands < (bytes>>8)+2 { 402 if float64(num_literals) > 0.99*float64(bytes) { 403 var literal_histo = [256]uint32{0} 404 const kSampleRate uint32 = 13 405 const kMinEntropy float64 = 7.92 406 var bit_cost_threshold float64 = float64(bytes) * kMinEntropy / float64(kSampleRate) 407 var t uint = uint((uint32(bytes) + kSampleRate - 1) / kSampleRate) 408 var pos uint32 = uint32(last_flush_pos) 409 var i uint 410 for i = 0; i < t; i++ { 411 literal_histo[data[pos&uint32(mask)]]++ 412 pos += kSampleRate 413 } 414 415 if bitsEntropy(literal_histo[:], 256) > bit_cost_threshold { 416 return false 417 } 418 } 419 } 420 421 return true 422 } 423 424 /* Chooses the literal context mode for a metablock */ 425 func chooseContextMode(params *encoderParams, data []byte, pos uint, mask uint, length uint) int { 426 /* We only do the computation for the option of something else than 427 CONTEXT_UTF8 for the highest qualities */ 428 if params.quality >= minQualityForHqBlockSplitting && !isMostlyUTF8(data, pos, mask, length, kMinUTF8Ratio) { 429 return contextSigned 430 } 431 432 return contextUTF8 433 } 434 435 func writeMetaBlockInternal(data []byte, mask uint, last_flush_pos uint64, bytes uint, is_last bool, literal_context_mode int, params *encoderParams, prev_byte byte, prev_byte2 byte, num_literals uint, commands []command, saved_dist_cache []int, dist_cache []int, storage_ix *uint, storage []byte) { 436 var wrapped_last_flush_pos uint32 = wrapPosition(last_flush_pos) 437 var last_bytes uint16 438 var last_bytes_bits byte 439 var literal_context_lut contextLUT = getContextLUT(literal_context_mode) 440 var block_params encoderParams = *params 441 442 if bytes == 0 { 443 /* Write the ISLAST and ISEMPTY bits. */ 444 writeBits(2, 3, storage_ix, storage) 445 446 *storage_ix = (*storage_ix + 7) &^ 7 447 return 448 } 449 450 if !shouldCompress_encode(data, mask, last_flush_pos, bytes, num_literals, uint(len(commands))) { 451 /* Restore the distance cache, as its last update by 452 CreateBackwardReferences is now unused. */ 453 copy(dist_cache, saved_dist_cache[:4]) 454 455 storeUncompressedMetaBlock(is_last, data, uint(wrapped_last_flush_pos), mask, bytes, storage_ix, storage) 456 return 457 } 458 459 assert(*storage_ix <= 14) 460 last_bytes = uint16(storage[1])<<8 | uint16(storage[0]) 461 last_bytes_bits = byte(*storage_ix) 462 if params.quality <= maxQualityForStaticEntropyCodes { 463 storeMetaBlockFast(data, uint(wrapped_last_flush_pos), bytes, mask, is_last, params, commands, storage_ix, storage) 464 } else if params.quality < minQualityForBlockSplit { 465 storeMetaBlockTrivial(data, uint(wrapped_last_flush_pos), bytes, mask, is_last, params, commands, storage_ix, storage) 466 } else { 467 mb := getMetaBlockSplit() 468 if params.quality < minQualityForHqBlockSplitting { 469 var num_literal_contexts uint = 1 470 var literal_context_map []uint32 = nil 471 if !params.disable_literal_context_modeling { 472 decideOverLiteralContextModeling(data, uint(wrapped_last_flush_pos), bytes, mask, params.quality, params.size_hint, &num_literal_contexts, &literal_context_map) 473 } 474 475 buildMetaBlockGreedy(data, uint(wrapped_last_flush_pos), mask, prev_byte, prev_byte2, literal_context_lut, num_literal_contexts, literal_context_map, commands, mb) 476 } else { 477 buildMetaBlock(data, uint(wrapped_last_flush_pos), mask, &block_params, prev_byte, prev_byte2, commands, literal_context_mode, mb) 478 } 479 480 if params.quality >= minQualityForOptimizeHistograms { 481 /* The number of distance symbols effectively used for distance 482 histograms. It might be less than distance alphabet size 483 for "Large Window Brotli" (32-bit). */ 484 var num_effective_dist_codes uint32 = block_params.dist.alphabet_size 485 if num_effective_dist_codes > numHistogramDistanceSymbols { 486 num_effective_dist_codes = numHistogramDistanceSymbols 487 } 488 489 optimizeHistograms(num_effective_dist_codes, mb) 490 } 491 492 storeMetaBlock(data, uint(wrapped_last_flush_pos), bytes, mask, prev_byte, prev_byte2, is_last, &block_params, literal_context_mode, commands, mb, storage_ix, storage) 493 freeMetaBlockSplit(mb) 494 } 495 496 if bytes+4 < *storage_ix>>3 { 497 /* Restore the distance cache and last byte. */ 498 copy(dist_cache, saved_dist_cache[:4]) 499 500 storage[0] = byte(last_bytes) 501 storage[1] = byte(last_bytes >> 8) 502 *storage_ix = uint(last_bytes_bits) 503 storeUncompressedMetaBlock(is_last, data, uint(wrapped_last_flush_pos), mask, bytes, storage_ix, storage) 504 } 505 } 506 507 func chooseDistanceParams(params *encoderParams) { 508 var distance_postfix_bits uint32 = 0 509 var num_direct_distance_codes uint32 = 0 510 511 if params.quality >= minQualityForNonzeroDistanceParams { 512 var ndirect_msb uint32 513 if params.mode == modeFont { 514 distance_postfix_bits = 1 515 num_direct_distance_codes = 12 516 } else { 517 distance_postfix_bits = params.dist.distance_postfix_bits 518 num_direct_distance_codes = params.dist.num_direct_distance_codes 519 } 520 521 ndirect_msb = (num_direct_distance_codes >> distance_postfix_bits) & 0x0F 522 if distance_postfix_bits > maxNpostfix || num_direct_distance_codes > maxNdirect || ndirect_msb<<distance_postfix_bits != num_direct_distance_codes { 523 distance_postfix_bits = 0 524 num_direct_distance_codes = 0 525 } 526 } 527 528 initDistanceParams(params, distance_postfix_bits, num_direct_distance_codes) 529 } 530 531 func ensureInitialized(s *Writer) bool { 532 if s.is_initialized_ { 533 return true 534 } 535 536 s.last_bytes_bits_ = 0 537 s.last_bytes_ = 0 538 s.remaining_metadata_bytes_ = math.MaxUint32 539 540 sanitizeParams(&s.params) 541 s.params.lgblock = computeLgBlock(&s.params) 542 chooseDistanceParams(&s.params) 543 544 ringBufferSetup(&s.params, &s.ringbuffer_) 545 546 /* Initialize last byte with stream header. */ 547 { 548 var lgwin int = int(s.params.lgwin) 549 if s.params.quality == fastOnePassCompressionQuality || s.params.quality == fastTwoPassCompressionQuality { 550 lgwin = brotli_max_int(lgwin, 18) 551 } 552 553 encodeWindowBits(lgwin, s.params.large_window, &s.last_bytes_, &s.last_bytes_bits_) 554 } 555 556 if s.params.quality == fastOnePassCompressionQuality { 557 s.cmd_depths_ = [128]byte{ 558 0, 4, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 559 0, 0, 0, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 560 7, 7, 10, 10, 10, 10, 10, 10, 0, 4, 4, 5, 5, 5, 6, 6, 561 7, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 562 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 563 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 564 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 10, 565 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 566 } 567 s.cmd_bits_ = [128]uint16{ 568 0, 0, 8, 9, 3, 35, 7, 71, 569 39, 103, 23, 47, 175, 111, 239, 31, 570 0, 0, 0, 4, 12, 2, 10, 6, 571 13, 29, 11, 43, 27, 59, 87, 55, 572 15, 79, 319, 831, 191, 703, 447, 959, 573 0, 14, 1, 25, 5, 21, 19, 51, 574 119, 159, 95, 223, 479, 991, 63, 575, 575 127, 639, 383, 895, 255, 767, 511, 1023, 576 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 577 27, 59, 7, 39, 23, 55, 30, 1, 17, 9, 25, 5, 0, 8, 4, 12, 578 2, 10, 6, 21, 13, 29, 3, 19, 11, 15, 47, 31, 95, 63, 127, 255, 579 767, 2815, 1791, 3839, 511, 2559, 1535, 3583, 1023, 3071, 2047, 4095, 580 } 581 s.cmd_code_ = [512]byte{ 582 0xff, 0x77, 0xd5, 0xbf, 0xe7, 0xde, 0xea, 0x9e, 0x51, 0x5d, 0xde, 0xc6, 583 0x70, 0x57, 0xbc, 0x58, 0x58, 0x58, 0xd8, 0xd8, 0x58, 0xd5, 0xcb, 0x8c, 584 0xea, 0xe0, 0xc3, 0x87, 0x1f, 0x83, 0xc1, 0x60, 0x1c, 0x67, 0xb2, 0xaa, 585 0x06, 0x83, 0xc1, 0x60, 0x30, 0x18, 0xcc, 0xa1, 0xce, 0x88, 0x54, 0x94, 586 0x46, 0xe1, 0xb0, 0xd0, 0x4e, 0xb2, 0xf7, 0x04, 0x00, 587 } 588 s.cmd_code_numbits_ = 448 589 } 590 591 s.is_initialized_ = true 592 return true 593 } 594 595 func encoderInitParams(params *encoderParams) { 596 params.mode = defaultMode 597 params.large_window = false 598 params.quality = defaultQuality 599 params.lgwin = defaultWindow 600 params.lgblock = 0 601 params.size_hint = 0 602 params.disable_literal_context_modeling = false 603 initEncoderDictionary(¶ms.dictionary) 604 params.dist.distance_postfix_bits = 0 605 params.dist.num_direct_distance_codes = 0 606 params.dist.alphabet_size = uint32(distanceAlphabetSize(0, 0, maxDistanceBits)) 607 params.dist.max_distance = maxDistance 608 } 609 610 func encoderInitState(s *Writer) { 611 encoderInitParams(&s.params) 612 s.input_pos_ = 0 613 s.commands = s.commands[:0] 614 s.num_literals_ = 0 615 s.last_insert_len_ = 0 616 s.last_flush_pos_ = 0 617 s.last_processed_pos_ = 0 618 s.prev_byte_ = 0 619 s.prev_byte2_ = 0 620 if s.hasher_ != nil { 621 s.hasher_.Common().is_prepared_ = false 622 } 623 s.cmd_code_numbits_ = 0 624 s.stream_state_ = streamProcessing 625 s.is_last_block_emitted_ = false 626 s.is_initialized_ = false 627 628 ringBufferInit(&s.ringbuffer_) 629 630 /* Initialize distance cache. */ 631 s.dist_cache_[0] = 4 632 633 s.dist_cache_[1] = 11 634 s.dist_cache_[2] = 15 635 s.dist_cache_[3] = 16 636 637 /* Save the state of the distance cache in case we need to restore it for 638 emitting an uncompressed block. */ 639 copy(s.saved_dist_cache_[:], s.dist_cache_[:]) 640 } 641 642 /* 643 Copies the given input data to the internal ring buffer of the compressor. 644 No processing of the data occurs at this time and this function can be 645 called multiple times before calling WriteBrotliData() to process the 646 accumulated input. At most input_block_size() bytes of input data can be 647 copied to the ring buffer, otherwise the next WriteBrotliData() will fail. 648 */ 649 func copyInputToRingBuffer(s *Writer, input_size uint, input_buffer []byte) { 650 var ringbuffer_ *ringBuffer = &s.ringbuffer_ 651 ringBufferWrite(input_buffer, input_size, ringbuffer_) 652 s.input_pos_ += uint64(input_size) 653 654 /* TL;DR: If needed, initialize 7 more bytes in the ring buffer to make the 655 hashing not depend on uninitialized data. This makes compression 656 deterministic and it prevents uninitialized memory warnings in Valgrind. 657 Even without erasing, the output would be valid (but nondeterministic). 658 659 Background information: The compressor stores short (at most 8 bytes) 660 substrings of the input already read in a hash table, and detects 661 repetitions by looking up such substrings in the hash table. If it 662 can find a substring, it checks whether the substring is really there 663 in the ring buffer (or it's just a hash collision). Should the hash 664 table become corrupt, this check makes sure that the output is 665 still valid, albeit the compression ratio would be bad. 666 667 The compressor populates the hash table from the ring buffer as it's 668 reading new bytes from the input. However, at the last few indexes of 669 the ring buffer, there are not enough bytes to build full-length 670 substrings from. Since the hash table always contains full-length 671 substrings, we erase with dummy zeros here to make sure that those 672 substrings will contain zeros at the end instead of uninitialized 673 data. 674 675 Please note that erasing is not necessary (because the 676 memory region is already initialized since he ring buffer 677 has a `tail' that holds a copy of the beginning,) so we 678 skip erasing if we have already gone around at least once in 679 the ring buffer. 680 681 Only clear during the first round of ring-buffer writes. On 682 subsequent rounds data in the ring-buffer would be affected. */ 683 if ringbuffer_.pos_ <= ringbuffer_.mask_ { 684 /* This is the first time when the ring buffer is being written. 685 We clear 7 bytes just after the bytes that have been copied from 686 the input buffer. 687 688 The ring-buffer has a "tail" that holds a copy of the beginning, 689 but only once the ring buffer has been fully written once, i.e., 690 pos <= mask. For the first time, we need to write values 691 in this tail (where index may be larger than mask), so that 692 we have exactly defined behavior and don't read uninitialized 693 memory. Due to performance reasons, hashing reads data using a 694 LOAD64, which can go 7 bytes beyond the bytes written in the 695 ring-buffer. */ 696 for i := 0; i < int(7); i++ { 697 ringbuffer_.buffer_[ringbuffer_.pos_:][i] = 0 698 } 699 } 700 } 701 702 /* Marks all input as processed. 703 Returns true if position wrapping occurs. */ 704 func updateLastProcessedPos(s *Writer) bool { 705 var wrapped_last_processed_pos uint32 = wrapPosition(s.last_processed_pos_) 706 var wrapped_input_pos uint32 = wrapPosition(s.input_pos_) 707 s.last_processed_pos_ = s.input_pos_ 708 return wrapped_input_pos < wrapped_last_processed_pos 709 } 710 711 func extendLastCommand(s *Writer, bytes *uint32, wrapped_last_processed_pos *uint32) { 712 var last_command *command = &s.commands[len(s.commands)-1] 713 var data []byte = s.ringbuffer_.buffer_ 714 var mask uint32 = s.ringbuffer_.mask_ 715 var max_backward_distance uint64 = ((uint64(1)) << s.params.lgwin) - windowGap 716 var last_copy_len uint64 = uint64(last_command.copy_len_) & 0x1FFFFFF 717 var last_processed_pos uint64 = s.last_processed_pos_ - last_copy_len 718 var max_distance uint64 719 if last_processed_pos < max_backward_distance { 720 max_distance = last_processed_pos 721 } else { 722 max_distance = max_backward_distance 723 } 724 var cmd_dist uint64 = uint64(s.dist_cache_[0]) 725 var distance_code uint32 = commandRestoreDistanceCode(last_command, &s.params.dist) 726 if distance_code < numDistanceShortCodes || uint64(distance_code-(numDistanceShortCodes-1)) == cmd_dist { 727 if cmd_dist <= max_distance { 728 for *bytes != 0 && data[*wrapped_last_processed_pos&mask] == data[(uint64(*wrapped_last_processed_pos)-cmd_dist)&uint64(mask)] { 729 last_command.copy_len_++ 730 (*bytes)-- 731 (*wrapped_last_processed_pos)++ 732 } 733 } 734 735 /* The copy length is at most the metablock size, and thus expressible. */ 736 getLengthCode(uint(last_command.insert_len_), uint(int(last_command.copy_len_&0x1FFFFFF)+int(last_command.copy_len_>>25)), (last_command.dist_prefix_&0x3FF == 0), &last_command.cmd_prefix_) 737 } 738 } 739 740 /* 741 Processes the accumulated input data and writes 742 the new output meta-block to s.dest, if one has been 743 created (otherwise the processed input data is buffered internally). 744 If |is_last| or |force_flush| is true, an output meta-block is 745 always created. However, until |is_last| is true encoder may retain up 746 to 7 bits of the last byte of output. To force encoder to dump the remaining 747 bits use WriteMetadata() to append an empty meta-data block. 748 Returns false if the size of the input data is larger than 749 input_block_size(). 750 */ 751 func encodeData(s *Writer, is_last bool, force_flush bool) bool { 752 var delta uint64 = unprocessedInputSize(s) 753 var bytes uint32 = uint32(delta) 754 var wrapped_last_processed_pos uint32 = wrapPosition(s.last_processed_pos_) 755 var data []byte 756 var mask uint32 757 var literal_context_mode int 758 759 data = s.ringbuffer_.buffer_ 760 mask = s.ringbuffer_.mask_ 761 762 /* Adding more blocks after "last" block is forbidden. */ 763 if s.is_last_block_emitted_ { 764 return false 765 } 766 if is_last { 767 s.is_last_block_emitted_ = true 768 } 769 770 if delta > uint64(inputBlockSize(s)) { 771 return false 772 } 773 774 if s.params.quality == fastTwoPassCompressionQuality { 775 if s.command_buf_ == nil || cap(s.command_buf_) < int(kCompressFragmentTwoPassBlockSize) { 776 s.command_buf_ = make([]uint32, kCompressFragmentTwoPassBlockSize) 777 s.literal_buf_ = make([]byte, kCompressFragmentTwoPassBlockSize) 778 } else { 779 s.command_buf_ = s.command_buf_[:kCompressFragmentTwoPassBlockSize] 780 s.literal_buf_ = s.literal_buf_[:kCompressFragmentTwoPassBlockSize] 781 } 782 } 783 784 if s.params.quality == fastOnePassCompressionQuality || s.params.quality == fastTwoPassCompressionQuality { 785 var storage []byte 786 var storage_ix uint = uint(s.last_bytes_bits_) 787 var table_size uint 788 var table []int 789 790 if delta == 0 && !is_last { 791 /* We have no new input data and we don't have to finish the stream, so 792 nothing to do. */ 793 return true 794 } 795 796 storage = s.getStorage(int(2*bytes + 503)) 797 storage[0] = byte(s.last_bytes_) 798 storage[1] = byte(s.last_bytes_ >> 8) 799 table = getHashTable(s, s.params.quality, uint(bytes), &table_size) 800 if s.params.quality == fastOnePassCompressionQuality { 801 compressFragmentFast(data[wrapped_last_processed_pos&mask:], uint(bytes), is_last, table, table_size, s.cmd_depths_[:], s.cmd_bits_[:], &s.cmd_code_numbits_, s.cmd_code_[:], &storage_ix, storage) 802 } else { 803 compressFragmentTwoPass(data[wrapped_last_processed_pos&mask:], uint(bytes), is_last, s.command_buf_, s.literal_buf_, table, table_size, &storage_ix, storage) 804 } 805 806 s.last_bytes_ = uint16(storage[storage_ix>>3]) 807 s.last_bytes_bits_ = byte(storage_ix & 7) 808 updateLastProcessedPos(s) 809 s.writeOutput(storage[:storage_ix>>3]) 810 return true 811 } 812 { 813 /* Theoretical max number of commands is 1 per 2 bytes. */ 814 newsize := len(s.commands) + int(bytes)/2 + 1 815 if newsize > cap(s.commands) { 816 /* Reserve a bit more memory to allow merging with a next block 817 without reallocation: that would impact speed. */ 818 newsize += int(bytes/4) + 16 819 820 new_commands := make([]command, len(s.commands), newsize) 821 if s.commands != nil { 822 copy(new_commands, s.commands) 823 } 824 825 s.commands = new_commands 826 } 827 } 828 829 initOrStitchToPreviousBlock(&s.hasher_, data, uint(mask), &s.params, uint(wrapped_last_processed_pos), uint(bytes), is_last) 830 831 literal_context_mode = chooseContextMode(&s.params, data, uint(wrapPosition(s.last_flush_pos_)), uint(mask), uint(s.input_pos_-s.last_flush_pos_)) 832 833 if len(s.commands) != 0 && s.last_insert_len_ == 0 { 834 extendLastCommand(s, &bytes, &wrapped_last_processed_pos) 835 } 836 837 if s.params.quality == zopflificationQuality { 838 assert(s.params.hasher.type_ == 10) 839 createZopfliBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_.(*h10), s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_) 840 } else if s.params.quality == hqZopflificationQuality { 841 assert(s.params.hasher.type_ == 10) 842 createHqZopfliBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_, s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_) 843 } else { 844 createBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_, s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_) 845 } 846 { 847 var max_length uint = maxMetablockSize(&s.params) 848 var max_literals uint = max_length / 8 849 max_commands := int(max_length / 8) 850 var processed_bytes uint = uint(s.input_pos_ - s.last_flush_pos_) 851 var next_input_fits_metablock bool = (processed_bytes+inputBlockSize(s) <= max_length) 852 var should_flush bool = (s.params.quality < minQualityForBlockSplit && s.num_literals_+uint(len(s.commands)) >= maxNumDelayedSymbols) 853 /* If maximal possible additional block doesn't fit metablock, flush now. */ 854 /* TODO: Postpone decision until next block arrives? */ 855 856 /* If block splitting is not used, then flush as soon as there is some 857 amount of commands / literals produced. */ 858 if !is_last && !force_flush && !should_flush && next_input_fits_metablock && s.num_literals_ < max_literals && len(s.commands) < max_commands { 859 /* Merge with next input block. Everything will happen later. */ 860 if updateLastProcessedPos(s) { 861 hasherReset(s.hasher_) 862 } 863 864 return true 865 } 866 } 867 868 /* Create the last insert-only command. */ 869 if s.last_insert_len_ > 0 { 870 s.commands = append(s.commands, makeInsertCommand(s.last_insert_len_)) 871 s.num_literals_ += s.last_insert_len_ 872 s.last_insert_len_ = 0 873 } 874 875 if !is_last && s.input_pos_ == s.last_flush_pos_ { 876 /* We have no new input data and we don't have to finish the stream, so 877 nothing to do. */ 878 return true 879 } 880 881 assert(s.input_pos_ >= s.last_flush_pos_) 882 assert(s.input_pos_ > s.last_flush_pos_ || is_last) 883 assert(s.input_pos_-s.last_flush_pos_ <= 1<<24) 884 { 885 var metablock_size uint32 = uint32(s.input_pos_ - s.last_flush_pos_) 886 var storage []byte = s.getStorage(int(2*metablock_size + 503)) 887 var storage_ix uint = uint(s.last_bytes_bits_) 888 storage[0] = byte(s.last_bytes_) 889 storage[1] = byte(s.last_bytes_ >> 8) 890 writeMetaBlockInternal(data, uint(mask), s.last_flush_pos_, uint(metablock_size), is_last, literal_context_mode, &s.params, s.prev_byte_, s.prev_byte2_, s.num_literals_, s.commands, s.saved_dist_cache_[:], s.dist_cache_[:], &storage_ix, storage) 891 s.last_bytes_ = uint16(storage[storage_ix>>3]) 892 s.last_bytes_bits_ = byte(storage_ix & 7) 893 s.last_flush_pos_ = s.input_pos_ 894 if updateLastProcessedPos(s) { 895 hasherReset(s.hasher_) 896 } 897 898 if s.last_flush_pos_ > 0 { 899 s.prev_byte_ = data[(uint32(s.last_flush_pos_)-1)&mask] 900 } 901 902 if s.last_flush_pos_ > 1 { 903 s.prev_byte2_ = data[uint32(s.last_flush_pos_-2)&mask] 904 } 905 906 s.commands = s.commands[:0] 907 s.num_literals_ = 0 908 909 /* Save the state of the distance cache in case we need to restore it for 910 emitting an uncompressed block. */ 911 copy(s.saved_dist_cache_[:], s.dist_cache_[:]) 912 913 s.writeOutput(storage[:storage_ix>>3]) 914 return true 915 } 916 } 917 918 /* Dumps remaining output bits and metadata header to |header|. 919 Returns number of produced bytes. 920 REQUIRED: |header| should be 8-byte aligned and at least 16 bytes long. 921 REQUIRED: |block_size| <= (1 << 24). */ 922 func writeMetadataHeader(s *Writer, block_size uint, header []byte) uint { 923 storage_ix := uint(s.last_bytes_bits_) 924 header[0] = byte(s.last_bytes_) 925 header[1] = byte(s.last_bytes_ >> 8) 926 s.last_bytes_ = 0 927 s.last_bytes_bits_ = 0 928 929 writeBits(1, 0, &storage_ix, header) 930 writeBits(2, 3, &storage_ix, header) 931 writeBits(1, 0, &storage_ix, header) 932 if block_size == 0 { 933 writeBits(2, 0, &storage_ix, header) 934 } else { 935 var nbits uint32 936 if block_size == 1 { 937 nbits = 0 938 } else { 939 nbits = log2FloorNonZero(uint(uint32(block_size)-1)) + 1 940 } 941 var nbytes uint32 = (nbits + 7) / 8 942 writeBits(2, uint64(nbytes), &storage_ix, header) 943 writeBits(uint(8*nbytes), uint64(block_size)-1, &storage_ix, header) 944 } 945 946 return (storage_ix + 7) >> 3 947 } 948 949 func injectBytePaddingBlock(s *Writer) { 950 var seal uint32 = uint32(s.last_bytes_) 951 var seal_bits uint = uint(s.last_bytes_bits_) 952 s.last_bytes_ = 0 953 s.last_bytes_bits_ = 0 954 955 /* is_last = 0, data_nibbles = 11, reserved = 0, meta_nibbles = 00 */ 956 seal |= 0x6 << seal_bits 957 958 seal_bits += 6 959 960 destination := s.tiny_buf_.u8[:] 961 962 destination[0] = byte(seal) 963 if seal_bits > 8 { 964 destination[1] = byte(seal >> 8) 965 } 966 if seal_bits > 16 { 967 destination[2] = byte(seal >> 16) 968 } 969 s.writeOutput(destination[:(seal_bits+7)>>3]) 970 } 971 972 func checkFlushComplete(s *Writer) { 973 if s.stream_state_ == streamFlushRequested && s.err == nil { 974 s.stream_state_ = streamProcessing 975 } 976 } 977 978 func encoderCompressStreamFast(s *Writer, op int, available_in *uint, next_in *[]byte) bool { 979 var block_size_limit uint = uint(1) << s.params.lgwin 980 var buf_size uint = brotli_min_size_t(kCompressFragmentTwoPassBlockSize, brotli_min_size_t(*available_in, block_size_limit)) 981 var command_buf []uint32 = nil 982 var literal_buf []byte = nil 983 if s.params.quality != fastOnePassCompressionQuality && s.params.quality != fastTwoPassCompressionQuality { 984 return false 985 } 986 987 if s.params.quality == fastTwoPassCompressionQuality { 988 if s.command_buf_ == nil || cap(s.command_buf_) < int(buf_size) { 989 s.command_buf_ = make([]uint32, buf_size) 990 s.literal_buf_ = make([]byte, buf_size) 991 } else { 992 s.command_buf_ = s.command_buf_[:buf_size] 993 s.literal_buf_ = s.literal_buf_[:buf_size] 994 } 995 996 command_buf = s.command_buf_ 997 literal_buf = s.literal_buf_ 998 } 999 1000 for { 1001 if s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 { 1002 injectBytePaddingBlock(s) 1003 continue 1004 } 1005 1006 /* Compress block only when stream is not 1007 finished, there is no pending flush request, and there is either 1008 additional input or pending operation. */ 1009 if s.stream_state_ == streamProcessing && (*available_in != 0 || op != int(operationProcess)) { 1010 var block_size uint = brotli_min_size_t(block_size_limit, *available_in) 1011 var is_last bool = (*available_in == block_size) && (op == int(operationFinish)) 1012 var force_flush bool = (*available_in == block_size) && (op == int(operationFlush)) 1013 var max_out_size uint = 2*block_size + 503 1014 var storage []byte = nil 1015 var storage_ix uint = uint(s.last_bytes_bits_) 1016 var table_size uint 1017 var table []int 1018 1019 if force_flush && block_size == 0 { 1020 s.stream_state_ = streamFlushRequested 1021 continue 1022 } 1023 1024 storage = s.getStorage(int(max_out_size)) 1025 1026 storage[0] = byte(s.last_bytes_) 1027 storage[1] = byte(s.last_bytes_ >> 8) 1028 table = getHashTable(s, s.params.quality, block_size, &table_size) 1029 1030 if s.params.quality == fastOnePassCompressionQuality { 1031 compressFragmentFast(*next_in, block_size, is_last, table, table_size, s.cmd_depths_[:], s.cmd_bits_[:], &s.cmd_code_numbits_, s.cmd_code_[:], &storage_ix, storage) 1032 } else { 1033 compressFragmentTwoPass(*next_in, block_size, is_last, command_buf, literal_buf, table, table_size, &storage_ix, storage) 1034 } 1035 1036 *next_in = (*next_in)[block_size:] 1037 *available_in -= block_size 1038 var out_bytes uint = storage_ix >> 3 1039 s.writeOutput(storage[:out_bytes]) 1040 1041 s.last_bytes_ = uint16(storage[storage_ix>>3]) 1042 s.last_bytes_bits_ = byte(storage_ix & 7) 1043 1044 if force_flush { 1045 s.stream_state_ = streamFlushRequested 1046 } 1047 if is_last { 1048 s.stream_state_ = streamFinished 1049 } 1050 continue 1051 } 1052 1053 break 1054 } 1055 1056 checkFlushComplete(s) 1057 return true 1058 } 1059 1060 func processMetadata(s *Writer, available_in *uint, next_in *[]byte) bool { 1061 if *available_in > 1<<24 { 1062 return false 1063 } 1064 1065 /* Switch to metadata block workflow, if required. */ 1066 if s.stream_state_ == streamProcessing { 1067 s.remaining_metadata_bytes_ = uint32(*available_in) 1068 s.stream_state_ = streamMetadataHead 1069 } 1070 1071 if s.stream_state_ != streamMetadataHead && s.stream_state_ != streamMetadataBody { 1072 return false 1073 } 1074 1075 for { 1076 if s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 { 1077 injectBytePaddingBlock(s) 1078 continue 1079 } 1080 1081 if s.input_pos_ != s.last_flush_pos_ { 1082 var result bool = encodeData(s, false, true) 1083 if !result { 1084 return false 1085 } 1086 continue 1087 } 1088 1089 if s.stream_state_ == streamMetadataHead { 1090 n := writeMetadataHeader(s, uint(s.remaining_metadata_bytes_), s.tiny_buf_.u8[:]) 1091 s.writeOutput(s.tiny_buf_.u8[:n]) 1092 s.stream_state_ = streamMetadataBody 1093 continue 1094 } else { 1095 /* Exit workflow only when there is no more input and no more output. 1096 Otherwise client may continue producing empty metadata blocks. */ 1097 if s.remaining_metadata_bytes_ == 0 { 1098 s.remaining_metadata_bytes_ = math.MaxUint32 1099 s.stream_state_ = streamProcessing 1100 break 1101 } 1102 1103 /* This guarantees progress in "TakeOutput" workflow. */ 1104 var c uint32 = brotli_min_uint32_t(s.remaining_metadata_bytes_, 16) 1105 copy(s.tiny_buf_.u8[:], (*next_in)[:c]) 1106 *next_in = (*next_in)[c:] 1107 *available_in -= uint(c) 1108 s.remaining_metadata_bytes_ -= c 1109 s.writeOutput(s.tiny_buf_.u8[:c]) 1110 1111 continue 1112 } 1113 } 1114 1115 return true 1116 } 1117 1118 func updateSizeHint(s *Writer, available_in uint) { 1119 if s.params.size_hint == 0 { 1120 var delta uint64 = unprocessedInputSize(s) 1121 var tail uint64 = uint64(available_in) 1122 var limit uint32 = 1 << 30 1123 var total uint32 1124 if (delta >= uint64(limit)) || (tail >= uint64(limit)) || ((delta + tail) >= uint64(limit)) { 1125 total = limit 1126 } else { 1127 total = uint32(delta + tail) 1128 } 1129 1130 s.params.size_hint = uint(total) 1131 } 1132 } 1133 1134 func encoderCompressStream(s *Writer, op int, available_in *uint, next_in *[]byte) bool { 1135 if !ensureInitialized(s) { 1136 return false 1137 } 1138 1139 /* Unfinished metadata block; check requirements. */ 1140 if s.remaining_metadata_bytes_ != math.MaxUint32 { 1141 if uint32(*available_in) != s.remaining_metadata_bytes_ { 1142 return false 1143 } 1144 if op != int(operationEmitMetadata) { 1145 return false 1146 } 1147 } 1148 1149 if op == int(operationEmitMetadata) { 1150 updateSizeHint(s, 0) /* First data metablock might be emitted here. */ 1151 return processMetadata(s, available_in, next_in) 1152 } 1153 1154 if s.stream_state_ == streamMetadataHead || s.stream_state_ == streamMetadataBody { 1155 return false 1156 } 1157 1158 if s.stream_state_ != streamProcessing && *available_in != 0 { 1159 return false 1160 } 1161 1162 if s.params.quality == fastOnePassCompressionQuality || s.params.quality == fastTwoPassCompressionQuality { 1163 return encoderCompressStreamFast(s, op, available_in, next_in) 1164 } 1165 1166 for { 1167 var remaining_block_size uint = remainingInputBlockSize(s) 1168 1169 if remaining_block_size != 0 && *available_in != 0 { 1170 var copy_input_size uint = brotli_min_size_t(remaining_block_size, *available_in) 1171 copyInputToRingBuffer(s, copy_input_size, *next_in) 1172 *next_in = (*next_in)[copy_input_size:] 1173 *available_in -= copy_input_size 1174 continue 1175 } 1176 1177 if s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 { 1178 injectBytePaddingBlock(s) 1179 continue 1180 } 1181 1182 /* Compress data only when stream is not 1183 finished and there is no pending flush request. */ 1184 if s.stream_state_ == streamProcessing { 1185 if remaining_block_size == 0 || op != int(operationProcess) { 1186 var is_last bool = ((*available_in == 0) && op == int(operationFinish)) 1187 var force_flush bool = ((*available_in == 0) && op == int(operationFlush)) 1188 var result bool 1189 updateSizeHint(s, *available_in) 1190 result = encodeData(s, is_last, force_flush) 1191 if !result { 1192 return false 1193 } 1194 if force_flush { 1195 s.stream_state_ = streamFlushRequested 1196 } 1197 if is_last { 1198 s.stream_state_ = streamFinished 1199 } 1200 continue 1201 } 1202 } 1203 1204 break 1205 } 1206 1207 checkFlushComplete(s) 1208 return true 1209 } 1210 1211 func (w *Writer) writeOutput(data []byte) { 1212 if w.err != nil { 1213 return 1214 } 1215 1216 _, w.err = w.dst.Write(data) 1217 if w.err == nil { 1218 checkFlushComplete(w) 1219 } 1220 }