1// Copyright 2019+ Klaus Post. All rights reserved. 2// License information can be found in the LICENSE file. 3// Based on work by Yann Collet, released under BSD License. 4 5package zstd 6 7import ( 8 "errors" 9 "fmt" 10 "math" 11 "math/bits" 12 13 "github.com/klauspost/compress/huff0" 14) 15 16type blockEnc struct { 17 size int 18 literals []byte 19 sequences []seq 20 coders seqCoders 21 litEnc *huff0.Scratch 22 dictLitEnc *huff0.Scratch 23 wr bitWriter 24 25 extraLits int 26 last bool 27 28 output []byte 29 recentOffsets [3]uint32 30 prevRecentOffsets [3]uint32 31} 32 33// init should be used once the block has been created. 34// If called more than once, the effect is the same as calling reset. 35func (b *blockEnc) init() { 36 if cap(b.literals) < maxCompressedLiteralSize { 37 b.literals = make([]byte, 0, maxCompressedLiteralSize) 38 } 39 const defSeqs = 200 40 b.literals = b.literals[:0] 41 if cap(b.sequences) < defSeqs { 42 b.sequences = make([]seq, 0, defSeqs) 43 } 44 if cap(b.output) < maxCompressedBlockSize { 45 b.output = make([]byte, 0, maxCompressedBlockSize) 46 } 47 if b.coders.mlEnc == nil { 48 b.coders.mlEnc = &fseEncoder{} 49 b.coders.mlPrev = &fseEncoder{} 50 b.coders.ofEnc = &fseEncoder{} 51 b.coders.ofPrev = &fseEncoder{} 52 b.coders.llEnc = &fseEncoder{} 53 b.coders.llPrev = &fseEncoder{} 54 } 55 b.litEnc = &huff0.Scratch{WantLogLess: 4} 56 b.reset(nil) 57} 58 59// initNewEncode can be used to reset offsets and encoders to the initial state. 60func (b *blockEnc) initNewEncode() { 61 b.recentOffsets = [3]uint32{1, 4, 8} 62 b.litEnc.Reuse = huff0.ReusePolicyNone 63 b.coders.setPrev(nil, nil, nil) 64} 65 66// reset will reset the block for a new encode, but in the same stream, 67// meaning that state will be carried over, but the block content is reset. 68// If a previous block is provided, the recent offsets are carried over. 69func (b *blockEnc) reset(prev *blockEnc) { 70 b.extraLits = 0 71 b.literals = b.literals[:0] 72 b.size = 0 73 b.sequences = b.sequences[:0] 74 b.output = b.output[:0] 75 b.last = false 76 if prev != nil { 77 b.recentOffsets = prev.prevRecentOffsets 78 } 79} 80 81// reset will reset the block for a new encode, but in the same stream, 82// meaning that state will be carried over, but the block content is reset. 83// If a previous block is provided, the recent offsets are carried over. 84func (b *blockEnc) swapEncoders(prev *blockEnc) { 85 b.coders.swap(&prev.coders) 86 b.litEnc, prev.litEnc = prev.litEnc, b.litEnc 87} 88 89// blockHeader contains the information for a block header. 90type blockHeader uint32 91 92// setLast sets the 'last' indicator on a block. 93func (h *blockHeader) setLast(b bool) { 94 if b { 95 *h = *h | 1 96 } else { 97 const mask = (1 << 24) - 2 98 *h = *h & mask 99 } 100} 101 102// setSize will store the compressed size of a block. 103func (h *blockHeader) setSize(v uint32) { 104 const mask = 7 105 *h = (*h)&mask | blockHeader(v<<3) 106} 107 108// setType sets the block type. 109func (h *blockHeader) setType(t blockType) { 110 const mask = 1 | (((1 << 24) - 1) ^ 7) 111 *h = (*h & mask) | blockHeader(t<<1) 112} 113 114// appendTo will append the block header to a slice. 115func (h blockHeader) appendTo(b []byte) []byte { 116 return append(b, uint8(h), uint8(h>>8), uint8(h>>16)) 117} 118 119// String returns a string representation of the block. 120func (h blockHeader) String() string { 121 return fmt.Sprintf("Type: %d, Size: %d, Last:%t", (h>>1)&3, h>>3, h&1 == 1) 122} 123 124// literalsHeader contains literals header information. 125type literalsHeader uint64 126 127// setType can be used to set the type of literal block. 128func (h *literalsHeader) setType(t literalsBlockType) { 129 const mask = math.MaxUint64 - 3 130 *h = (*h & mask) | literalsHeader(t) 131} 132 133// setSize can be used to set a single size, for uncompressed and RLE content. 134func (h *literalsHeader) setSize(regenLen int) { 135 inBits := bits.Len32(uint32(regenLen)) 136 // Only retain 2 bits 137 const mask = 3 138 lh := uint64(*h & mask) 139 switch { 140 case inBits < 5: 141 lh |= (uint64(regenLen) << 3) | (1 << 60) 142 if debug { 143 got := int(lh>>3) & 0xff 144 if got != regenLen { 145 panic(fmt.Sprint("litRegenSize = ", regenLen, "(want) != ", got, "(got)")) 146 } 147 } 148 case inBits < 12: 149 lh |= (1 << 2) | (uint64(regenLen) << 4) | (2 << 60) 150 case inBits < 20: 151 lh |= (3 << 2) | (uint64(regenLen) << 4) | (3 << 60) 152 default: 153 panic(fmt.Errorf("internal error: block too big (%d)", regenLen)) 154 } 155 *h = literalsHeader(lh) 156} 157 158// setSizes will set the size of a compressed literals section and the input length. 159func (h *literalsHeader) setSizes(compLen, inLen int, single bool) { 160 compBits, inBits := bits.Len32(uint32(compLen)), bits.Len32(uint32(inLen)) 161 // Only retain 2 bits 162 const mask = 3 163 lh := uint64(*h & mask) 164 switch { 165 case compBits <= 10 && inBits <= 10: 166 if !single { 167 lh |= 1 << 2 168 } 169 lh |= (uint64(inLen) << 4) | (uint64(compLen) << (10 + 4)) | (3 << 60) 170 if debug { 171 const mmask = (1 << 24) - 1 172 n := (lh >> 4) & mmask 173 if int(n&1023) != inLen { 174 panic(fmt.Sprint("regensize:", int(n&1023), "!=", inLen, inBits)) 175 } 176 if int(n>>10) != compLen { 177 panic(fmt.Sprint("compsize:", int(n>>10), "!=", compLen, compBits)) 178 } 179 } 180 case compBits <= 14 && inBits <= 14: 181 lh |= (2 << 2) | (uint64(inLen) << 4) | (uint64(compLen) << (14 + 4)) | (4 << 60) 182 if single { 183 panic("single stream used with more than 10 bits length.") 184 } 185 case compBits <= 18 && inBits <= 18: 186 lh |= (3 << 2) | (uint64(inLen) << 4) | (uint64(compLen) << (18 + 4)) | (5 << 60) 187 if single { 188 panic("single stream used with more than 10 bits length.") 189 } 190 default: 191 panic("internal error: block too big") 192 } 193 *h = literalsHeader(lh) 194} 195 196// appendTo will append the literals header to a byte slice. 197func (h literalsHeader) appendTo(b []byte) []byte { 198 size := uint8(h >> 60) 199 switch size { 200 case 1: 201 b = append(b, uint8(h)) 202 case 2: 203 b = append(b, uint8(h), uint8(h>>8)) 204 case 3: 205 b = append(b, uint8(h), uint8(h>>8), uint8(h>>16)) 206 case 4: 207 b = append(b, uint8(h), uint8(h>>8), uint8(h>>16), uint8(h>>24)) 208 case 5: 209 b = append(b, uint8(h), uint8(h>>8), uint8(h>>16), uint8(h>>24), uint8(h>>32)) 210 default: 211 panic(fmt.Errorf("internal error: literalsHeader has invalid size (%d)", size)) 212 } 213 return b 214} 215 216// size returns the output size with currently set values. 217func (h literalsHeader) size() int { 218 return int(h >> 60) 219} 220 221func (h literalsHeader) String() string { 222 return fmt.Sprintf("Type: %d, SizeFormat: %d, Size: 0x%d, Bytes:%d", literalsBlockType(h&3), (h>>2)&3, h&((1<<60)-1)>>4, h>>60) 223} 224 225// pushOffsets will push the recent offsets to the backup store. 226func (b *blockEnc) pushOffsets() { 227 b.prevRecentOffsets = b.recentOffsets 228} 229 230// pushOffsets will push the recent offsets to the backup store. 231func (b *blockEnc) popOffsets() { 232 b.recentOffsets = b.prevRecentOffsets 233} 234 235// matchOffset will adjust recent offsets and return the adjusted one, 236// if it matches a previous offset. 237func (b *blockEnc) matchOffset(offset, lits uint32) uint32 { 238 // Check if offset is one of the recent offsets. 239 // Adjusts the output offset accordingly. 240 // Gives a tiny bit of compression, typically around 1%. 241 if true { 242 if lits > 0 { 243 switch offset { 244 case b.recentOffsets[0]: 245 offset = 1 246 case b.recentOffsets[1]: 247 b.recentOffsets[1] = b.recentOffsets[0] 248 b.recentOffsets[0] = offset 249 offset = 2 250 case b.recentOffsets[2]: 251 b.recentOffsets[2] = b.recentOffsets[1] 252 b.recentOffsets[1] = b.recentOffsets[0] 253 b.recentOffsets[0] = offset 254 offset = 3 255 default: 256 b.recentOffsets[2] = b.recentOffsets[1] 257 b.recentOffsets[1] = b.recentOffsets[0] 258 b.recentOffsets[0] = offset 259 offset += 3 260 } 261 } else { 262 switch offset { 263 case b.recentOffsets[1]: 264 b.recentOffsets[1] = b.recentOffsets[0] 265 b.recentOffsets[0] = offset 266 offset = 1 267 case b.recentOffsets[2]: 268 b.recentOffsets[2] = b.recentOffsets[1] 269 b.recentOffsets[1] = b.recentOffsets[0] 270 b.recentOffsets[0] = offset 271 offset = 2 272 case b.recentOffsets[0] - 1: 273 b.recentOffsets[2] = b.recentOffsets[1] 274 b.recentOffsets[1] = b.recentOffsets[0] 275 b.recentOffsets[0] = offset 276 offset = 3 277 default: 278 b.recentOffsets[2] = b.recentOffsets[1] 279 b.recentOffsets[1] = b.recentOffsets[0] 280 b.recentOffsets[0] = offset 281 offset += 3 282 } 283 } 284 } else { 285 offset += 3 286 } 287 return offset 288} 289 290// encodeRaw can be used to set the output to a raw representation of supplied bytes. 291func (b *blockEnc) encodeRaw(a []byte) { 292 var bh blockHeader 293 bh.setLast(b.last) 294 bh.setSize(uint32(len(a))) 295 bh.setType(blockTypeRaw) 296 b.output = bh.appendTo(b.output[:0]) 297 b.output = append(b.output, a...) 298 if debug { 299 println("Adding RAW block, length", len(a), "last:", b.last) 300 } 301} 302 303// encodeRaw can be used to set the output to a raw representation of supplied bytes. 304func (b *blockEnc) encodeRawTo(dst, src []byte) []byte { 305 var bh blockHeader 306 bh.setLast(b.last) 307 bh.setSize(uint32(len(src))) 308 bh.setType(blockTypeRaw) 309 dst = bh.appendTo(dst) 310 dst = append(dst, src...) 311 if debug { 312 println("Adding RAW block, length", len(src), "last:", b.last) 313 } 314 return dst 315} 316 317// encodeLits can be used if the block is only litLen. 318func (b *blockEnc) encodeLits(lits []byte, raw bool) error { 319 var bh blockHeader 320 bh.setLast(b.last) 321 bh.setSize(uint32(len(lits))) 322 323 // Don't compress extremely small blocks 324 if len(lits) < 8 || (len(lits) < 32 && b.dictLitEnc == nil) || raw { 325 if debug { 326 println("Adding RAW block, length", len(lits), "last:", b.last) 327 } 328 bh.setType(blockTypeRaw) 329 b.output = bh.appendTo(b.output) 330 b.output = append(b.output, lits...) 331 return nil 332 } 333 334 var ( 335 out []byte 336 reUsed, single bool 337 err error 338 ) 339 if b.dictLitEnc != nil { 340 b.litEnc.TransferCTable(b.dictLitEnc) 341 b.litEnc.Reuse = huff0.ReusePolicyAllow 342 b.dictLitEnc = nil 343 } 344 if len(lits) >= 1024 { 345 // Use 4 Streams. 346 out, reUsed, err = huff0.Compress4X(lits, b.litEnc) 347 } else if len(lits) > 32 { 348 // Use 1 stream 349 single = true 350 out, reUsed, err = huff0.Compress1X(lits, b.litEnc) 351 } else { 352 err = huff0.ErrIncompressible 353 } 354 355 switch err { 356 case huff0.ErrIncompressible: 357 if debug { 358 println("Adding RAW block, length", len(lits), "last:", b.last) 359 } 360 bh.setType(blockTypeRaw) 361 b.output = bh.appendTo(b.output) 362 b.output = append(b.output, lits...) 363 return nil 364 case huff0.ErrUseRLE: 365 if debug { 366 println("Adding RLE block, length", len(lits)) 367 } 368 bh.setType(blockTypeRLE) 369 b.output = bh.appendTo(b.output) 370 b.output = append(b.output, lits[0]) 371 return nil 372 default: 373 return err 374 case nil: 375 } 376 // Compressed... 377 // Now, allow reuse 378 b.litEnc.Reuse = huff0.ReusePolicyAllow 379 bh.setType(blockTypeCompressed) 380 var lh literalsHeader 381 if reUsed { 382 if debug { 383 println("Reused tree, compressed to", len(out)) 384 } 385 lh.setType(literalsBlockTreeless) 386 } else { 387 if debug { 388 println("New tree, compressed to", len(out), "tree size:", len(b.litEnc.OutTable)) 389 } 390 lh.setType(literalsBlockCompressed) 391 } 392 // Set sizes 393 lh.setSizes(len(out), len(lits), single) 394 bh.setSize(uint32(len(out) + lh.size() + 1)) 395 396 // Write block headers. 397 b.output = bh.appendTo(b.output) 398 b.output = lh.appendTo(b.output) 399 // Add compressed data. 400 b.output = append(b.output, out...) 401 // No sequences. 402 b.output = append(b.output, 0) 403 return nil 404} 405 406// fuzzFseEncoder can be used to fuzz the FSE encoder. 407func fuzzFseEncoder(data []byte) int { 408 if len(data) > maxSequences || len(data) < 2 { 409 return 0 410 } 411 enc := fseEncoder{} 412 hist := enc.Histogram()[:256] 413 maxSym := uint8(0) 414 for i, v := range data { 415 v = v & 63 416 data[i] = v 417 hist[v]++ 418 if v > maxSym { 419 maxSym = v 420 } 421 } 422 if maxSym == 0 { 423 // All 0 424 return 0 425 } 426 maxCount := func(a []uint32) int { 427 var max uint32 428 for _, v := range a { 429 if v > max { 430 max = v 431 } 432 } 433 return int(max) 434 } 435 cnt := maxCount(hist[:maxSym]) 436 if cnt == len(data) { 437 // RLE 438 return 0 439 } 440 enc.HistogramFinished(maxSym, cnt) 441 err := enc.normalizeCount(len(data)) 442 if err != nil { 443 return 0 444 } 445 _, err = enc.writeCount(nil) 446 if err != nil { 447 panic(err) 448 } 449 return 1 450} 451 452// encode will encode the block and append the output in b.output. 453// Previous offset codes must be pushed if more blocks are expected. 454func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error { 455 if len(b.sequences) == 0 { 456 return b.encodeLits(b.literals, rawAllLits) 457 } 458 // We want some difference to at least account for the headers. 459 saved := b.size - len(b.literals) - (b.size >> 5) 460 if saved < 16 { 461 if org == nil { 462 return errIncompressible 463 } 464 b.popOffsets() 465 return b.encodeLits(org, rawAllLits) 466 } 467 468 var bh blockHeader 469 var lh literalsHeader 470 bh.setLast(b.last) 471 bh.setType(blockTypeCompressed) 472 // Store offset of the block header. Needed when we know the size. 473 bhOffset := len(b.output) 474 b.output = bh.appendTo(b.output) 475 476 var ( 477 out []byte 478 reUsed, single bool 479 err error 480 ) 481 if b.dictLitEnc != nil { 482 b.litEnc.TransferCTable(b.dictLitEnc) 483 b.litEnc.Reuse = huff0.ReusePolicyAllow 484 b.dictLitEnc = nil 485 } 486 if len(b.literals) >= 1024 && !raw { 487 // Use 4 Streams. 488 out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc) 489 } else if len(b.literals) > 32 && !raw { 490 // Use 1 stream 491 single = true 492 out, reUsed, err = huff0.Compress1X(b.literals, b.litEnc) 493 } else { 494 err = huff0.ErrIncompressible 495 } 496 497 switch err { 498 case huff0.ErrIncompressible: 499 lh.setType(literalsBlockRaw) 500 lh.setSize(len(b.literals)) 501 b.output = lh.appendTo(b.output) 502 b.output = append(b.output, b.literals...) 503 if debug { 504 println("Adding literals RAW, length", len(b.literals)) 505 } 506 case huff0.ErrUseRLE: 507 lh.setType(literalsBlockRLE) 508 lh.setSize(len(b.literals)) 509 b.output = lh.appendTo(b.output) 510 b.output = append(b.output, b.literals[0]) 511 if debug { 512 println("Adding literals RLE") 513 } 514 default: 515 if debug { 516 println("Adding literals ERROR:", err) 517 } 518 return err 519 case nil: 520 // Compressed litLen... 521 if reUsed { 522 if debug { 523 println("reused tree") 524 } 525 lh.setType(literalsBlockTreeless) 526 } else { 527 if debug { 528 println("new tree, size:", len(b.litEnc.OutTable)) 529 } 530 lh.setType(literalsBlockCompressed) 531 if debug { 532 _, _, err := huff0.ReadTable(out, nil) 533 if err != nil { 534 panic(err) 535 } 536 } 537 } 538 lh.setSizes(len(out), len(b.literals), single) 539 if debug { 540 printf("Compressed %d literals to %d bytes", len(b.literals), len(out)) 541 println("Adding literal header:", lh) 542 } 543 b.output = lh.appendTo(b.output) 544 b.output = append(b.output, out...) 545 b.litEnc.Reuse = huff0.ReusePolicyAllow 546 if debug { 547 println("Adding literals compressed") 548 } 549 } 550 // Sequence compression 551 552 // Write the number of sequences 553 switch { 554 case len(b.sequences) < 128: 555 b.output = append(b.output, uint8(len(b.sequences))) 556 case len(b.sequences) < 0x7f00: // TODO: this could be wrong 557 n := len(b.sequences) 558 b.output = append(b.output, 128+uint8(n>>8), uint8(n)) 559 default: 560 n := len(b.sequences) - 0x7f00 561 b.output = append(b.output, 255, uint8(n), uint8(n>>8)) 562 } 563 if debug { 564 println("Encoding", len(b.sequences), "sequences") 565 } 566 b.genCodes() 567 llEnc := b.coders.llEnc 568 ofEnc := b.coders.ofEnc 569 mlEnc := b.coders.mlEnc 570 err = llEnc.normalizeCount(len(b.sequences)) 571 if err != nil { 572 return err 573 } 574 err = ofEnc.normalizeCount(len(b.sequences)) 575 if err != nil { 576 return err 577 } 578 err = mlEnc.normalizeCount(len(b.sequences)) 579 if err != nil { 580 return err 581 } 582 583 // Choose the best compression mode for each type. 584 // Will evaluate the new vs predefined and previous. 585 chooseComp := func(cur, prev, preDef *fseEncoder) (*fseEncoder, seqCompMode) { 586 // See if predefined/previous is better 587 hist := cur.count[:cur.symbolLen] 588 nSize := cur.approxSize(hist) + cur.maxHeaderSize() 589 predefSize := preDef.approxSize(hist) 590 prevSize := prev.approxSize(hist) 591 592 // Add a small penalty for new encoders. 593 // Don't bother with extremely small (<2 byte gains). 594 nSize = nSize + (nSize+2*8*16)>>4 595 switch { 596 case predefSize <= prevSize && predefSize <= nSize || forcePreDef: 597 if debug { 598 println("Using predefined", predefSize>>3, "<=", nSize>>3) 599 } 600 return preDef, compModePredefined 601 case prevSize <= nSize: 602 if debug { 603 println("Using previous", prevSize>>3, "<=", nSize>>3) 604 } 605 return prev, compModeRepeat 606 default: 607 if debug { 608 println("Using new, predef", predefSize>>3, ". previous:", prevSize>>3, ">", nSize>>3, "header max:", cur.maxHeaderSize()>>3, "bytes") 609 println("tl:", cur.actualTableLog, "symbolLen:", cur.symbolLen, "norm:", cur.norm[:cur.symbolLen], "hist", cur.count[:cur.symbolLen]) 610 } 611 return cur, compModeFSE 612 } 613 } 614 615 // Write compression mode 616 var mode uint8 617 if llEnc.useRLE { 618 mode |= uint8(compModeRLE) << 6 619 llEnc.setRLE(b.sequences[0].llCode) 620 if debug { 621 println("llEnc.useRLE") 622 } 623 } else { 624 var m seqCompMode 625 llEnc, m = chooseComp(llEnc, b.coders.llPrev, &fsePredefEnc[tableLiteralLengths]) 626 mode |= uint8(m) << 6 627 } 628 if ofEnc.useRLE { 629 mode |= uint8(compModeRLE) << 4 630 ofEnc.setRLE(b.sequences[0].ofCode) 631 if debug { 632 println("ofEnc.useRLE") 633 } 634 } else { 635 var m seqCompMode 636 ofEnc, m = chooseComp(ofEnc, b.coders.ofPrev, &fsePredefEnc[tableOffsets]) 637 mode |= uint8(m) << 4 638 } 639 640 if mlEnc.useRLE { 641 mode |= uint8(compModeRLE) << 2 642 mlEnc.setRLE(b.sequences[0].mlCode) 643 if debug { 644 println("mlEnc.useRLE, code: ", b.sequences[0].mlCode, "value", b.sequences[0].matchLen) 645 } 646 } else { 647 var m seqCompMode 648 mlEnc, m = chooseComp(mlEnc, b.coders.mlPrev, &fsePredefEnc[tableMatchLengths]) 649 mode |= uint8(m) << 2 650 } 651 b.output = append(b.output, mode) 652 if debug { 653 printf("Compression modes: 0b%b", mode) 654 } 655 b.output, err = llEnc.writeCount(b.output) 656 if err != nil { 657 return err 658 } 659 start := len(b.output) 660 b.output, err = ofEnc.writeCount(b.output) 661 if err != nil { 662 return err 663 } 664 if false { 665 println("block:", b.output[start:], "tablelog", ofEnc.actualTableLog, "maxcount:", ofEnc.maxCount) 666 fmt.Printf("selected TableLog: %d, Symbol length: %d\n", ofEnc.actualTableLog, ofEnc.symbolLen) 667 for i, v := range ofEnc.norm[:ofEnc.symbolLen] { 668 fmt.Printf("%3d: %5d -> %4d \n", i, ofEnc.count[i], v) 669 } 670 } 671 b.output, err = mlEnc.writeCount(b.output) 672 if err != nil { 673 return err 674 } 675 676 // Maybe in block? 677 wr := &b.wr 678 wr.reset(b.output) 679 680 var ll, of, ml cState 681 682 // Current sequence 683 seq := len(b.sequences) - 1 684 s := b.sequences[seq] 685 llEnc.setBits(llBitsTable[:]) 686 mlEnc.setBits(mlBitsTable[:]) 687 ofEnc.setBits(nil) 688 689 llTT, ofTT, mlTT := llEnc.ct.symbolTT[:256], ofEnc.ct.symbolTT[:256], mlEnc.ct.symbolTT[:256] 690 691 // We have 3 bounds checks here (and in the loop). 692 // Since we are iterating backwards it is kinda hard to avoid. 693 llB, ofB, mlB := llTT[s.llCode], ofTT[s.ofCode], mlTT[s.mlCode] 694 ll.init(wr, &llEnc.ct, llB) 695 of.init(wr, &ofEnc.ct, ofB) 696 wr.flush32() 697 ml.init(wr, &mlEnc.ct, mlB) 698 699 // Each of these lookups also generates a bounds check. 700 wr.addBits32NC(s.litLen, llB.outBits) 701 wr.addBits32NC(s.matchLen, mlB.outBits) 702 wr.flush32() 703 wr.addBits32NC(s.offset, ofB.outBits) 704 if debugSequences { 705 println("Encoded seq", seq, s, "codes:", s.llCode, s.mlCode, s.ofCode, "states:", ll.state, ml.state, of.state, "bits:", llB, mlB, ofB) 706 } 707 seq-- 708 if llEnc.maxBits+mlEnc.maxBits+ofEnc.maxBits <= 32 { 709 // No need to flush (common) 710 for seq >= 0 { 711 s = b.sequences[seq] 712 wr.flush32() 713 llB, ofB, mlB := llTT[s.llCode], ofTT[s.ofCode], mlTT[s.mlCode] 714 // tabelog max is 8 for all. 715 of.encode(ofB) 716 ml.encode(mlB) 717 ll.encode(llB) 718 wr.flush32() 719 720 // We checked that all can stay within 32 bits 721 wr.addBits32NC(s.litLen, llB.outBits) 722 wr.addBits32NC(s.matchLen, mlB.outBits) 723 wr.addBits32NC(s.offset, ofB.outBits) 724 725 if debugSequences { 726 println("Encoded seq", seq, s) 727 } 728 729 seq-- 730 } 731 } else { 732 for seq >= 0 { 733 s = b.sequences[seq] 734 wr.flush32() 735 llB, ofB, mlB := llTT[s.llCode], ofTT[s.ofCode], mlTT[s.mlCode] 736 // tabelog max is below 8 for each. 737 of.encode(ofB) 738 ml.encode(mlB) 739 ll.encode(llB) 740 wr.flush32() 741 742 // ml+ll = max 32 bits total 743 wr.addBits32NC(s.litLen, llB.outBits) 744 wr.addBits32NC(s.matchLen, mlB.outBits) 745 wr.flush32() 746 wr.addBits32NC(s.offset, ofB.outBits) 747 748 if debugSequences { 749 println("Encoded seq", seq, s) 750 } 751 752 seq-- 753 } 754 } 755 ml.flush(mlEnc.actualTableLog) 756 of.flush(ofEnc.actualTableLog) 757 ll.flush(llEnc.actualTableLog) 758 err = wr.close() 759 if err != nil { 760 return err 761 } 762 b.output = wr.out 763 764 if len(b.output)-3-bhOffset >= b.size { 765 // Maybe even add a bigger margin. 766 b.litEnc.Reuse = huff0.ReusePolicyNone 767 return errIncompressible 768 } 769 770 // Size is output minus block header. 771 bh.setSize(uint32(len(b.output)-bhOffset) - 3) 772 if debug { 773 println("Rewriting block header", bh) 774 } 775 _ = bh.appendTo(b.output[bhOffset:bhOffset]) 776 b.coders.setPrev(llEnc, mlEnc, ofEnc) 777 return nil 778} 779 780var errIncompressible = errors.New("incompressible") 781 782func (b *blockEnc) genCodes() { 783 if len(b.sequences) == 0 { 784 // nothing to do 785 return 786 } 787 788 if len(b.sequences) > math.MaxUint16 { 789 panic("can only encode up to 64K sequences") 790 } 791 // No bounds checks after here: 792 llH := b.coders.llEnc.Histogram()[:256] 793 ofH := b.coders.ofEnc.Histogram()[:256] 794 mlH := b.coders.mlEnc.Histogram()[:256] 795 for i := range llH { 796 llH[i] = 0 797 } 798 for i := range ofH { 799 ofH[i] = 0 800 } 801 for i := range mlH { 802 mlH[i] = 0 803 } 804 805 var llMax, ofMax, mlMax uint8 806 for i, seq := range b.sequences { 807 v := llCode(seq.litLen) 808 seq.llCode = v 809 llH[v]++ 810 if v > llMax { 811 llMax = v 812 } 813 814 v = ofCode(seq.offset) 815 seq.ofCode = v 816 ofH[v]++ 817 if v > ofMax { 818 ofMax = v 819 } 820 821 v = mlCode(seq.matchLen) 822 seq.mlCode = v 823 mlH[v]++ 824 if v > mlMax { 825 mlMax = v 826 if debugAsserts && mlMax > maxMatchLengthSymbol { 827 panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d), matchlen: %d", mlMax, seq.matchLen)) 828 } 829 } 830 b.sequences[i] = seq 831 } 832 maxCount := func(a []uint32) int { 833 var max uint32 834 for _, v := range a { 835 if v > max { 836 max = v 837 } 838 } 839 return int(max) 840 } 841 if debugAsserts && mlMax > maxMatchLengthSymbol { 842 panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d)", mlMax)) 843 } 844 if debugAsserts && ofMax > maxOffsetBits { 845 panic(fmt.Errorf("ofMax > maxOffsetBits (%d)", ofMax)) 846 } 847 if debugAsserts && llMax > maxLiteralLengthSymbol { 848 panic(fmt.Errorf("llMax > maxLiteralLengthSymbol (%d)", llMax)) 849 } 850 851 b.coders.mlEnc.HistogramFinished(mlMax, maxCount(mlH[:mlMax+1])) 852 b.coders.ofEnc.HistogramFinished(ofMax, maxCount(ofH[:ofMax+1])) 853 b.coders.llEnc.HistogramFinished(llMax, maxCount(llH[:llMax+1])) 854} 855