Update dependencies and replace uuid library (#100)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/huff0-fuzz.zip
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
// Copyright 2018 Klaus Post. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
|
||||
|
||||
package huff0
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// bitReader reads a bitstream in reverse.
|
||||
// The last set bit indicates the start of the stream and is used
|
||||
// for aligning the input.
|
||||
type bitReader struct {
|
||||
in []byte
|
||||
off uint // next byte to read is at in[off - 1]
|
||||
value uint64
|
||||
bitsRead uint8
|
||||
}
|
||||
|
||||
// init initializes and resets the bit reader.
|
||||
func (b *bitReader) init(in []byte) error {
|
||||
if len(in) < 1 {
|
||||
return errors.New("corrupt stream: too short")
|
||||
}
|
||||
b.in = in
|
||||
b.off = uint(len(in))
|
||||
// The highest bit of the last byte indicates where to start
|
||||
v := in[len(in)-1]
|
||||
if v == 0 {
|
||||
return errors.New("corrupt stream, did not find end of stream")
|
||||
}
|
||||
b.bitsRead = 64
|
||||
b.value = 0
|
||||
b.fill()
|
||||
b.fill()
|
||||
b.bitsRead += 8 - uint8(highBit32(uint32(v)))
|
||||
return nil
|
||||
}
|
||||
|
||||
// getBits will return n bits. n can be 0.
|
||||
func (b *bitReader) getBits(n uint8) uint16 {
|
||||
if n == 0 || b.bitsRead >= 64 {
|
||||
return 0
|
||||
}
|
||||
return b.getBitsFast(n)
|
||||
}
|
||||
|
||||
// getBitsFast requires that at least one bit is requested every time.
|
||||
// There are no checks if the buffer is filled.
|
||||
func (b *bitReader) getBitsFast(n uint8) uint16 {
|
||||
const regMask = 64 - 1
|
||||
v := uint16((b.value << (b.bitsRead & regMask)) >> ((regMask + 1 - n) & regMask))
|
||||
b.bitsRead += n
|
||||
return v
|
||||
}
|
||||
|
||||
// peekBitsFast requires that at least one bit is requested every time.
|
||||
// There are no checks if the buffer is filled.
|
||||
func (b *bitReader) peekBitsFast(n uint8) uint16 {
|
||||
const regMask = 64 - 1
|
||||
v := uint16((b.value << (b.bitsRead & regMask)) >> ((regMask + 1 - n) & regMask))
|
||||
return v
|
||||
}
|
||||
|
||||
// fillFast() will make sure at least 32 bits are available.
|
||||
// There must be at least 4 bytes available.
|
||||
func (b *bitReader) fillFast() {
|
||||
if b.bitsRead < 32 {
|
||||
return
|
||||
}
|
||||
// Do single re-slice to avoid bounds checks.
|
||||
v := b.in[b.off-4 : b.off]
|
||||
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
|
||||
b.value = (b.value << 32) | uint64(low)
|
||||
b.bitsRead -= 32
|
||||
b.off -= 4
|
||||
}
|
||||
|
||||
// fill() will make sure at least 32 bits are available.
|
||||
func (b *bitReader) fill() {
|
||||
if b.bitsRead < 32 {
|
||||
return
|
||||
}
|
||||
if b.off > 4 {
|
||||
v := b.in[b.off-4 : b.off]
|
||||
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
|
||||
b.value = (b.value << 32) | uint64(low)
|
||||
b.bitsRead -= 32
|
||||
b.off -= 4
|
||||
return
|
||||
}
|
||||
for b.off > 0 {
|
||||
b.value = (b.value << 8) | uint64(b.in[b.off-1])
|
||||
b.bitsRead -= 8
|
||||
b.off--
|
||||
}
|
||||
}
|
||||
|
||||
// finished returns true if all bits have been read from the bit stream.
|
||||
func (b *bitReader) finished() bool {
|
||||
return b.off == 0 && b.bitsRead >= 64
|
||||
}
|
||||
|
||||
// close the bitstream and returns an error if out-of-buffer reads occurred.
|
||||
func (b *bitReader) close() error {
|
||||
// Release reference.
|
||||
b.in = nil
|
||||
if b.bitsRead > 64 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
// Copyright 2018 Klaus Post. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
|
||||
|
||||
package huff0
|
||||
|
||||
import "fmt"
|
||||
|
||||
// bitWriter will write bits.
|
||||
// First bit will be LSB of the first byte of output.
|
||||
type bitWriter struct {
|
||||
bitContainer uint64
|
||||
nBits uint8
|
||||
out []byte
|
||||
}
|
||||
|
||||
// bitMask16 is bitmasks. Has extra to avoid bounds check.
|
||||
var bitMask16 = [32]uint16{
|
||||
0, 1, 3, 7, 0xF, 0x1F,
|
||||
0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
|
||||
0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF} /* up to 16 bits */
|
||||
|
||||
// addBits16NC will add up to 16 bits.
|
||||
// It will not check if there is space for them,
|
||||
// so the caller must ensure that it has flushed recently.
|
||||
func (b *bitWriter) addBits16NC(value uint16, bits uint8) {
|
||||
b.bitContainer |= uint64(value&bitMask16[bits&31]) << (b.nBits & 63)
|
||||
b.nBits += bits
|
||||
}
|
||||
|
||||
// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
|
||||
// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
|
||||
func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
|
||||
b.bitContainer |= uint64(value) << (b.nBits & 63)
|
||||
b.nBits += bits
|
||||
}
|
||||
|
||||
// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
|
||||
// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
|
||||
func (b *bitWriter) encSymbol(ct cTable, symbol byte) {
|
||||
enc := ct[symbol]
|
||||
b.bitContainer |= uint64(enc.val) << (b.nBits & 63)
|
||||
b.nBits += enc.nBits
|
||||
}
|
||||
|
||||
// addBits16ZeroNC will add up to 16 bits.
|
||||
// It will not check if there is space for them,
|
||||
// so the caller must ensure that it has flushed recently.
|
||||
// This is fastest if bits can be zero.
|
||||
func (b *bitWriter) addBits16ZeroNC(value uint16, bits uint8) {
|
||||
if bits == 0 {
|
||||
return
|
||||
}
|
||||
value <<= (16 - bits) & 15
|
||||
value >>= (16 - bits) & 15
|
||||
b.bitContainer |= uint64(value) << (b.nBits & 63)
|
||||
b.nBits += bits
|
||||
}
|
||||
|
||||
// flush will flush all pending full bytes.
|
||||
// There will be at least 56 bits available for writing when this has been called.
|
||||
// Using flush32 is faster, but leaves less space for writing.
|
||||
func (b *bitWriter) flush() {
|
||||
v := b.nBits >> 3
|
||||
switch v {
|
||||
case 0:
|
||||
case 1:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
)
|
||||
case 2:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
)
|
||||
case 3:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
)
|
||||
case 4:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
)
|
||||
case 5:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
)
|
||||
case 6:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
byte(b.bitContainer>>40),
|
||||
)
|
||||
case 7:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
byte(b.bitContainer>>40),
|
||||
byte(b.bitContainer>>48),
|
||||
)
|
||||
case 8:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
byte(b.bitContainer>>40),
|
||||
byte(b.bitContainer>>48),
|
||||
byte(b.bitContainer>>56),
|
||||
)
|
||||
default:
|
||||
panic(fmt.Errorf("bits (%d) > 64", b.nBits))
|
||||
}
|
||||
b.bitContainer >>= v << 3
|
||||
b.nBits &= 7
|
||||
}
|
||||
|
||||
// flush32 will flush out, so there are at least 32 bits available for writing.
|
||||
func (b *bitWriter) flush32() {
|
||||
if b.nBits < 32 {
|
||||
return
|
||||
}
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24))
|
||||
b.nBits -= 32
|
||||
b.bitContainer >>= 32
|
||||
}
|
||||
|
||||
// flushAlign will flush remaining full bytes and align to next byte boundary.
|
||||
func (b *bitWriter) flushAlign() {
|
||||
nbBytes := (b.nBits + 7) >> 3
|
||||
for i := uint8(0); i < nbBytes; i++ {
|
||||
b.out = append(b.out, byte(b.bitContainer>>(i*8)))
|
||||
}
|
||||
b.nBits = 0
|
||||
b.bitContainer = 0
|
||||
}
|
||||
|
||||
// close will write the alignment bit and write the final byte(s)
|
||||
// to the output.
|
||||
func (b *bitWriter) close() error {
|
||||
// End mark
|
||||
b.addBits16Clean(1, 1)
|
||||
// flush until next byte.
|
||||
b.flushAlign()
|
||||
return nil
|
||||
}
|
||||
|
||||
// reset and continue writing by appending to out.
|
||||
func (b *bitWriter) reset(out []byte) {
|
||||
b.bitContainer = 0
|
||||
b.nBits = 0
|
||||
b.out = out
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
// Copyright 2018 Klaus Post. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
|
||||
|
||||
package huff0
|
||||
|
||||
// byteReader provides a byte reader that reads
|
||||
// little endian values from a byte stream.
|
||||
// The input stream is manually advanced.
|
||||
// The reader performs no bounds checks.
|
||||
type byteReader struct {
|
||||
b []byte
|
||||
off int
|
||||
}
|
||||
|
||||
// init will initialize the reader and set the input.
|
||||
func (b *byteReader) init(in []byte) {
|
||||
b.b = in
|
||||
b.off = 0
|
||||
}
|
||||
|
||||
// advance the stream b n bytes.
|
||||
func (b *byteReader) advance(n uint) {
|
||||
b.off += int(n)
|
||||
}
|
||||
|
||||
// Int32 returns a little endian int32 starting at current offset.
|
||||
func (b byteReader) Int32() int32 {
|
||||
v3 := int32(b.b[b.off+3])
|
||||
v2 := int32(b.b[b.off+2])
|
||||
v1 := int32(b.b[b.off+1])
|
||||
v0 := int32(b.b[b.off])
|
||||
return (v3 << 24) | (v2 << 16) | (v1 << 8) | v0
|
||||
}
|
||||
|
||||
// Uint32 returns a little endian uint32 starting at current offset.
|
||||
func (b byteReader) Uint32() uint32 {
|
||||
v3 := uint32(b.b[b.off+3])
|
||||
v2 := uint32(b.b[b.off+2])
|
||||
v1 := uint32(b.b[b.off+1])
|
||||
v0 := uint32(b.b[b.off])
|
||||
return (v3 << 24) | (v2 << 16) | (v1 << 8) | v0
|
||||
}
|
||||
|
||||
// unread returns the unread portion of the input.
|
||||
func (b byteReader) unread() []byte {
|
||||
return b.b[b.off:]
|
||||
}
|
||||
|
||||
// remain will return the number of bytes remaining.
|
||||
func (b byteReader) remain() int {
|
||||
return len(b.b) - b.off
|
||||
}
|
||||
+600
@@ -0,0 +1,600 @@
|
||||
package huff0
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func Compress1X(in []byte, s *Scratch) (out []byte, reUsed bool, err error) {
|
||||
s, err = s.prepare(in)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return compress(in, s, s.compress1X)
|
||||
}
|
||||
|
||||
func Compress4X(in []byte, s *Scratch) (out []byte, reUsed bool, err error) {
|
||||
s, err = s.prepare(in)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if false {
|
||||
// TODO: compress4Xp only slightly faster.
|
||||
const parallelThreshold = 8 << 10
|
||||
if len(in) < parallelThreshold || runtime.GOMAXPROCS(0) == 1 {
|
||||
return compress(in, s, s.compress4X)
|
||||
}
|
||||
return compress(in, s, s.compress4Xp)
|
||||
}
|
||||
return compress(in, s, s.compress4X)
|
||||
}
|
||||
|
||||
func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)) (out []byte, reUsed bool, err error) {
|
||||
// Nuke previous table if we cannot reuse anyway.
|
||||
if s.Reuse == ReusePolicyNone {
|
||||
s.prevTable = s.prevTable[:0]
|
||||
}
|
||||
|
||||
// Create histogram, if none was provided.
|
||||
maxCount := s.maxCount
|
||||
var canReuse = false
|
||||
if maxCount == 0 {
|
||||
maxCount, canReuse = s.countSimple(in)
|
||||
} else {
|
||||
canReuse = s.canUseTable(s.prevTable)
|
||||
}
|
||||
|
||||
// Reset for next run.
|
||||
s.clearCount = true
|
||||
s.maxCount = 0
|
||||
if maxCount >= len(in) {
|
||||
if maxCount > len(in) {
|
||||
return nil, false, fmt.Errorf("maxCount (%d) > length (%d)", maxCount, len(in))
|
||||
}
|
||||
// One symbol, use RLE
|
||||
return nil, false, ErrUseRLE
|
||||
}
|
||||
if maxCount == 1 || maxCount < (len(in)>>7) {
|
||||
// Each symbol present maximum once or too well distributed.
|
||||
return nil, false, ErrIncompressible
|
||||
}
|
||||
|
||||
if s.Reuse == ReusePolicyPrefer && canReuse {
|
||||
keepTable := s.cTable
|
||||
s.cTable = s.prevTable
|
||||
s.Out, err = compressor(in)
|
||||
s.cTable = keepTable
|
||||
if err == nil && len(s.Out) < len(in) {
|
||||
s.OutData = s.Out
|
||||
return s.Out, true, nil
|
||||
}
|
||||
// Do not attempt to re-use later.
|
||||
s.prevTable = s.prevTable[:0]
|
||||
}
|
||||
|
||||
// Calculate new table.
|
||||
s.optimalTableLog()
|
||||
err = s.buildCTable()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
if !s.canUseTable(s.cTable) {
|
||||
// TODO: Not needed.
|
||||
panic("invalid table generated")
|
||||
}
|
||||
|
||||
if s.Reuse == ReusePolicyAllow && canReuse {
|
||||
hSize := len(s.Out)
|
||||
oldSize := s.prevTable.estimateSize(s.count[:s.symbolLen])
|
||||
newSize := s.cTable.estimateSize(s.count[:s.symbolLen])
|
||||
if oldSize <= hSize+newSize || hSize+12 >= len(in) {
|
||||
// Retain cTable even if we re-use.
|
||||
keepTable := s.cTable
|
||||
s.cTable = s.prevTable
|
||||
s.Out, err = compressor(in)
|
||||
s.cTable = keepTable
|
||||
if len(s.Out) >= len(in) {
|
||||
return nil, false, ErrIncompressible
|
||||
}
|
||||
s.OutData = s.Out
|
||||
return s.Out, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Use new table
|
||||
s.cTable.write(s)
|
||||
s.OutTable = s.Out
|
||||
|
||||
// Compress using new table
|
||||
s.Out, err = compressor(in)
|
||||
if err != nil {
|
||||
s.OutTable = nil
|
||||
return nil, false, err
|
||||
}
|
||||
if len(s.Out) >= len(in) {
|
||||
s.OutTable = nil
|
||||
return nil, false, ErrIncompressible
|
||||
}
|
||||
// Move current table into previous.
|
||||
s.prevTable, s.cTable = s.cTable, s.prevTable[:0]
|
||||
s.OutData = s.Out[len(s.OutTable):]
|
||||
return s.Out, false, nil
|
||||
}
|
||||
|
||||
func (s *Scratch) compress1X(src []byte) ([]byte, error) {
|
||||
return s.compress1xDo(s.Out, src)
|
||||
}
|
||||
|
||||
func (s *Scratch) compress1xDo(dst, src []byte) ([]byte, error) {
|
||||
var bw = bitWriter{out: dst}
|
||||
|
||||
// N is length divisible by 4.
|
||||
n := len(src)
|
||||
n -= n & 3
|
||||
cTable := s.cTable[:256]
|
||||
|
||||
// Encode last bytes.
|
||||
for i := len(src) & 3; i > 0; i-- {
|
||||
bw.encSymbol(cTable, src[n+i-1])
|
||||
}
|
||||
if s.actualTableLog <= 8 {
|
||||
n -= 4
|
||||
for ; n >= 0; n -= 4 {
|
||||
tmp := src[n : n+4]
|
||||
// tmp should be len 4
|
||||
bw.flush32()
|
||||
bw.encSymbol(cTable, tmp[3])
|
||||
bw.encSymbol(cTable, tmp[2])
|
||||
bw.encSymbol(cTable, tmp[1])
|
||||
bw.encSymbol(cTable, tmp[0])
|
||||
}
|
||||
} else {
|
||||
n -= 4
|
||||
for ; n >= 0; n -= 4 {
|
||||
tmp := src[n : n+4]
|
||||
// tmp should be len 4
|
||||
bw.flush32()
|
||||
bw.encSymbol(cTable, tmp[3])
|
||||
bw.encSymbol(cTable, tmp[2])
|
||||
bw.flush32()
|
||||
bw.encSymbol(cTable, tmp[1])
|
||||
bw.encSymbol(cTable, tmp[0])
|
||||
}
|
||||
}
|
||||
err := bw.close()
|
||||
return bw.out, err
|
||||
}
|
||||
|
||||
var sixZeros [6]byte
|
||||
|
||||
func (s *Scratch) compress4X(src []byte) ([]byte, error) {
|
||||
if len(src) < 12 {
|
||||
return nil, ErrIncompressible
|
||||
}
|
||||
segmentSize := (len(src) + 3) / 4
|
||||
|
||||
// Add placeholder for output length
|
||||
offsetIdx := len(s.Out)
|
||||
s.Out = append(s.Out, sixZeros[:]...)
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
toDo := src
|
||||
if len(toDo) > segmentSize {
|
||||
toDo = toDo[:segmentSize]
|
||||
}
|
||||
src = src[len(toDo):]
|
||||
|
||||
var err error
|
||||
idx := len(s.Out)
|
||||
s.Out, err = s.compress1xDo(s.Out, toDo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Write compressed length as little endian before block.
|
||||
if i < 3 {
|
||||
// Last length is not written.
|
||||
length := len(s.Out) - idx
|
||||
s.Out[i*2+offsetIdx] = byte(length)
|
||||
s.Out[i*2+offsetIdx+1] = byte(length >> 8)
|
||||
}
|
||||
}
|
||||
|
||||
return s.Out, nil
|
||||
}
|
||||
|
||||
// compress4Xp will compress 4 streams using separate goroutines.
|
||||
func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
|
||||
if len(src) < 12 {
|
||||
return nil, ErrIncompressible
|
||||
}
|
||||
// Add placeholder for output length
|
||||
s.Out = s.Out[:6]
|
||||
|
||||
segmentSize := (len(src) + 3) / 4
|
||||
var wg sync.WaitGroup
|
||||
var errs [4]error
|
||||
wg.Add(4)
|
||||
for i := 0; i < 4; i++ {
|
||||
toDo := src
|
||||
if len(toDo) > segmentSize {
|
||||
toDo = toDo[:segmentSize]
|
||||
}
|
||||
src = src[len(toDo):]
|
||||
|
||||
// Separate goroutine for each block.
|
||||
go func(i int) {
|
||||
s.tmpOut[i], errs[i] = s.compress1xDo(s.tmpOut[i][:0], toDo)
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
for i := 0; i < 4; i++ {
|
||||
if errs[i] != nil {
|
||||
return nil, errs[i]
|
||||
}
|
||||
o := s.tmpOut[i]
|
||||
// Write compressed length as little endian before block.
|
||||
if i < 3 {
|
||||
// Last length is not written.
|
||||
s.Out[i*2] = byte(len(o))
|
||||
s.Out[i*2+1] = byte(len(o) >> 8)
|
||||
}
|
||||
|
||||
// Write output.
|
||||
s.Out = append(s.Out, o...)
|
||||
}
|
||||
return s.Out, nil
|
||||
}
|
||||
|
||||
// countSimple will create a simple histogram in s.count.
|
||||
// Returns the biggest count.
|
||||
// Does not update s.clearCount.
|
||||
func (s *Scratch) countSimple(in []byte) (max int, reuse bool) {
|
||||
reuse = true
|
||||
for _, v := range in {
|
||||
s.count[v]++
|
||||
}
|
||||
m := uint32(0)
|
||||
if len(s.prevTable) > 0 {
|
||||
for i, v := range s.count[:] {
|
||||
if v > m {
|
||||
m = v
|
||||
}
|
||||
if v > 0 {
|
||||
s.symbolLen = uint16(i) + 1
|
||||
if i >= len(s.prevTable) {
|
||||
reuse = false
|
||||
} else {
|
||||
if s.prevTable[i].nBits == 0 {
|
||||
reuse = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return int(m), reuse
|
||||
}
|
||||
for i, v := range s.count[:] {
|
||||
if v > m {
|
||||
m = v
|
||||
}
|
||||
if v > 0 {
|
||||
s.symbolLen = uint16(i) + 1
|
||||
}
|
||||
}
|
||||
return int(m), false
|
||||
}
|
||||
|
||||
func (s *Scratch) canUseTable(c cTable) bool {
|
||||
if len(c) < int(s.symbolLen) {
|
||||
return false
|
||||
}
|
||||
for i, v := range s.count[:s.symbolLen] {
|
||||
if v != 0 && c[i].nBits == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// minTableLog provides the minimum logSize to safely represent a distribution.
|
||||
func (s *Scratch) minTableLog() uint8 {
|
||||
minBitsSrc := highBit32(uint32(s.br.remain()-1)) + 1
|
||||
minBitsSymbols := highBit32(uint32(s.symbolLen-1)) + 2
|
||||
if minBitsSrc < minBitsSymbols {
|
||||
return uint8(minBitsSrc)
|
||||
}
|
||||
return uint8(minBitsSymbols)
|
||||
}
|
||||
|
||||
// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog
|
||||
func (s *Scratch) optimalTableLog() {
|
||||
tableLog := s.TableLog
|
||||
minBits := s.minTableLog()
|
||||
maxBitsSrc := uint8(highBit32(uint32(s.br.remain()-1))) - 2
|
||||
if maxBitsSrc < tableLog {
|
||||
// Accuracy can be reduced
|
||||
tableLog = maxBitsSrc
|
||||
}
|
||||
if minBits > tableLog {
|
||||
tableLog = minBits
|
||||
}
|
||||
// Need a minimum to safely represent all symbol values
|
||||
if tableLog < minTablelog {
|
||||
tableLog = minTablelog
|
||||
}
|
||||
if tableLog > tableLogMax {
|
||||
tableLog = tableLogMax
|
||||
}
|
||||
s.actualTableLog = tableLog
|
||||
}
|
||||
|
||||
type cTableEntry struct {
|
||||
val uint16
|
||||
nBits uint8
|
||||
// We have 8 bits extra
|
||||
}
|
||||
|
||||
const huffNodesMask = huffNodesLen - 1
|
||||
|
||||
func (s *Scratch) buildCTable() error {
|
||||
if cap(s.cTable) < maxSymbolValue+1 {
|
||||
s.cTable = make([]cTableEntry, 0, maxSymbolValue+1)
|
||||
}
|
||||
|
||||
s.huffSort()
|
||||
s.cTable = s.cTable[:s.symbolLen]
|
||||
|
||||
var startNode = int16(s.symbolLen)
|
||||
nonNullRank := s.symbolLen - 1
|
||||
|
||||
nodeNb := int16(startNode)
|
||||
huffNode := s.nodes[1 : huffNodesLen+1]
|
||||
|
||||
// This overlays the slice above, but allows "-1" index lookups.
|
||||
// Different from reference implementation.
|
||||
huffNode0 := s.nodes[0 : huffNodesLen+1]
|
||||
|
||||
for huffNode[nonNullRank].count == 0 {
|
||||
nonNullRank--
|
||||
}
|
||||
|
||||
lowS := int16(nonNullRank)
|
||||
nodeRoot := nodeNb + lowS - 1
|
||||
lowN := nodeNb
|
||||
huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count
|
||||
huffNode[lowS].parent, huffNode[lowS-1].parent = uint16(nodeNb), uint16(nodeNb)
|
||||
nodeNb++
|
||||
lowS -= 2
|
||||
for n := nodeNb; n <= nodeRoot; n++ {
|
||||
huffNode[n].count = 1 << 30
|
||||
}
|
||||
// fake entry, strong barrier
|
||||
huffNode0[0].count = 1 << 31
|
||||
|
||||
// create parents
|
||||
for nodeNb <= nodeRoot {
|
||||
var n1, n2 int16
|
||||
if huffNode0[lowS+1].count < huffNode0[lowN+1].count {
|
||||
n1 = lowS
|
||||
lowS--
|
||||
} else {
|
||||
n1 = lowN
|
||||
lowN++
|
||||
}
|
||||
if huffNode0[lowS+1].count < huffNode0[lowN+1].count {
|
||||
n2 = lowS
|
||||
lowS--
|
||||
} else {
|
||||
n2 = lowN
|
||||
lowN++
|
||||
}
|
||||
|
||||
huffNode[nodeNb].count = huffNode0[n1+1].count + huffNode0[n2+1].count
|
||||
huffNode0[n1+1].parent, huffNode0[n2+1].parent = uint16(nodeNb), uint16(nodeNb)
|
||||
nodeNb++
|
||||
}
|
||||
|
||||
// distribute weights (unlimited tree height)
|
||||
huffNode[nodeRoot].nbBits = 0
|
||||
for n := nodeRoot - 1; n >= startNode; n-- {
|
||||
huffNode[n].nbBits = huffNode[huffNode[n].parent].nbBits + 1
|
||||
}
|
||||
for n := uint16(0); n <= nonNullRank; n++ {
|
||||
huffNode[n].nbBits = huffNode[huffNode[n].parent].nbBits + 1
|
||||
}
|
||||
s.actualTableLog = s.setMaxHeight(int(nonNullRank))
|
||||
maxNbBits := s.actualTableLog
|
||||
|
||||
// fill result into tree (val, nbBits)
|
||||
if maxNbBits > tableLogMax {
|
||||
return fmt.Errorf("internal error: maxNbBits (%d) > tableLogMax (%d)", maxNbBits, tableLogMax)
|
||||
}
|
||||
var nbPerRank [tableLogMax + 1]uint16
|
||||
var valPerRank [tableLogMax + 1]uint16
|
||||
for _, v := range huffNode[:nonNullRank+1] {
|
||||
nbPerRank[v.nbBits]++
|
||||
}
|
||||
// determine stating value per rank
|
||||
{
|
||||
min := uint16(0)
|
||||
for n := maxNbBits; n > 0; n-- {
|
||||
// get starting value within each rank
|
||||
valPerRank[n] = min
|
||||
min += nbPerRank[n]
|
||||
min >>= 1
|
||||
}
|
||||
}
|
||||
|
||||
// push nbBits per symbol, symbol order
|
||||
// TODO: changed `s.symbolLen` -> `nonNullRank+1` (micro-opt)
|
||||
for _, v := range huffNode[:nonNullRank+1] {
|
||||
s.cTable[v.symbol].nBits = v.nbBits
|
||||
}
|
||||
|
||||
// assign value within rank, symbol order
|
||||
for n, val := range s.cTable[:s.symbolLen] {
|
||||
v := valPerRank[val.nBits]
|
||||
s.cTable[n].val = v
|
||||
valPerRank[val.nBits] = v + 1
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// huffSort will sort symbols, decreasing order.
|
||||
func (s *Scratch) huffSort() {
|
||||
type rankPos struct {
|
||||
base uint32
|
||||
current uint32
|
||||
}
|
||||
|
||||
// Clear nodes
|
||||
nodes := s.nodes[:huffNodesLen+1]
|
||||
s.nodes = nodes
|
||||
nodes = nodes[1 : huffNodesLen+1]
|
||||
|
||||
// Sort into buckets based on length of symbol count.
|
||||
var rank [32]rankPos
|
||||
for _, v := range s.count[:s.symbolLen] {
|
||||
r := highBit32(v+1) & 31
|
||||
rank[r].base++
|
||||
}
|
||||
for n := 30; n > 0; n-- {
|
||||
rank[n-1].base += rank[n].base
|
||||
}
|
||||
for n := range rank[:] {
|
||||
rank[n].current = rank[n].base
|
||||
}
|
||||
for n, c := range s.count[:s.symbolLen] {
|
||||
r := (highBit32(c+1) + 1) & 31
|
||||
pos := rank[r].current
|
||||
rank[r].current++
|
||||
prev := nodes[(pos-1)&huffNodesMask]
|
||||
for pos > rank[r].base && c > prev.count {
|
||||
nodes[pos&huffNodesMask] = prev
|
||||
pos--
|
||||
prev = nodes[(pos-1)&huffNodesMask]
|
||||
}
|
||||
nodes[pos&huffNodesMask] = nodeElt{count: c, symbol: byte(n)}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
|
||||
maxNbBits := s.TableLog
|
||||
huffNode := s.nodes[1 : huffNodesLen+1]
|
||||
//huffNode = huffNode[: huffNodesLen]
|
||||
|
||||
largestBits := huffNode[lastNonNull].nbBits
|
||||
|
||||
// early exit : no elt > maxNbBits
|
||||
if largestBits <= maxNbBits {
|
||||
return largestBits
|
||||
}
|
||||
totalCost := int(0)
|
||||
baseCost := int(1) << (largestBits - maxNbBits)
|
||||
n := uint32(lastNonNull)
|
||||
|
||||
for huffNode[n].nbBits > maxNbBits {
|
||||
totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits))
|
||||
huffNode[n].nbBits = maxNbBits
|
||||
n--
|
||||
}
|
||||
// n stops at huffNode[n].nbBits <= maxNbBits
|
||||
|
||||
for huffNode[n].nbBits == maxNbBits {
|
||||
n--
|
||||
}
|
||||
// n end at index of smallest symbol using < maxNbBits
|
||||
|
||||
// renorm totalCost
|
||||
totalCost >>= largestBits - maxNbBits /* note : totalCost is necessarily a multiple of baseCost */
|
||||
|
||||
/* repay normalized cost */
|
||||
{
|
||||
const noSymbol = 0xF0F0F0F0
|
||||
var rankLast [tableLogMax + 2]uint32
|
||||
|
||||
for i := range rankLast[:] {
|
||||
rankLast[i] = noSymbol
|
||||
}
|
||||
|
||||
// Get pos of last (smallest) symbol per rank
|
||||
{
|
||||
currentNbBits := uint8(maxNbBits)
|
||||
for pos := int(n); pos >= 0; pos-- {
|
||||
if huffNode[pos].nbBits >= currentNbBits {
|
||||
continue
|
||||
}
|
||||
currentNbBits = huffNode[pos].nbBits /* < maxNbBits */
|
||||
rankLast[maxNbBits-currentNbBits] = uint32(pos)
|
||||
}
|
||||
}
|
||||
|
||||
for totalCost > 0 {
|
||||
nBitsToDecrease := uint8(highBit32(uint32(totalCost))) + 1
|
||||
|
||||
for ; nBitsToDecrease > 1; nBitsToDecrease-- {
|
||||
highPos := rankLast[nBitsToDecrease]
|
||||
lowPos := rankLast[nBitsToDecrease-1]
|
||||
if highPos == noSymbol {
|
||||
continue
|
||||
}
|
||||
if lowPos == noSymbol {
|
||||
break
|
||||
}
|
||||
highTotal := huffNode[highPos].count
|
||||
lowTotal := 2 * huffNode[lowPos].count
|
||||
if highTotal <= lowTotal {
|
||||
break
|
||||
}
|
||||
}
|
||||
// only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !)
|
||||
// HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary
|
||||
// FIXME: try to remove
|
||||
for (nBitsToDecrease <= tableLogMax) && (rankLast[nBitsToDecrease] == noSymbol) {
|
||||
nBitsToDecrease++
|
||||
}
|
||||
totalCost -= 1 << (nBitsToDecrease - 1)
|
||||
if rankLast[nBitsToDecrease-1] == noSymbol {
|
||||
// this rank is no longer empty
|
||||
rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]
|
||||
}
|
||||
huffNode[rankLast[nBitsToDecrease]].nbBits++
|
||||
if rankLast[nBitsToDecrease] == 0 {
|
||||
/* special case, reached largest symbol */
|
||||
rankLast[nBitsToDecrease] = noSymbol
|
||||
} else {
|
||||
rankLast[nBitsToDecrease]--
|
||||
if huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease {
|
||||
rankLast[nBitsToDecrease] = noSymbol /* this rank is now empty */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for totalCost < 0 { /* Sometimes, cost correction overshoot */
|
||||
if rankLast[1] == noSymbol { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
|
||||
for huffNode[n].nbBits == maxNbBits {
|
||||
n--
|
||||
}
|
||||
huffNode[n+1].nbBits--
|
||||
rankLast[1] = n + 1
|
||||
totalCost++
|
||||
continue
|
||||
}
|
||||
huffNode[rankLast[1]+1].nbBits--
|
||||
rankLast[1]++
|
||||
totalCost++
|
||||
}
|
||||
}
|
||||
return maxNbBits
|
||||
}
|
||||
|
||||
type nodeElt struct {
|
||||
count uint32
|
||||
parent uint16
|
||||
symbol byte
|
||||
nbBits uint8
|
||||
}
|
||||
+437
@@ -0,0 +1,437 @@
|
||||
package huff0
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/klauspost/compress/flate"
|
||||
)
|
||||
|
||||
type inputFn func() ([]byte, error)
|
||||
|
||||
var testfiles = []struct {
|
||||
name string
|
||||
fn inputFn
|
||||
err1X error
|
||||
err4X error
|
||||
}{
|
||||
// Digits is the digits of the irrational number e. Its decimal representation
|
||||
// does not repeat, but there are only 10 possible digits, so it should be
|
||||
// reasonably compressible.
|
||||
{name: "digits", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/e.txt") }},
|
||||
// gettysburg.txt is a small plain text.
|
||||
{name: "gettysburg", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/gettysburg.txt") }},
|
||||
// Twain is Project Gutenberg's edition of Mark Twain's classic English novel.
|
||||
{name: "twain", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/Mark.Twain-Tom.Sawyer.txt") }},
|
||||
// Random bytes
|
||||
{name: "random", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/sharnd.out") }, err1X: ErrIncompressible, err4X: ErrIncompressible},
|
||||
// Low entropy
|
||||
{name: "low-ent.10k", fn: func() ([]byte, error) { return []byte(strings.Repeat("1221", 10000)), nil }},
|
||||
// Super Low entropy
|
||||
{name: "superlow-ent-10k", fn: func() ([]byte, error) { return []byte(strings.Repeat("1", 10000) + strings.Repeat("2", 500)), nil }},
|
||||
// Zero bytes
|
||||
{name: "zeroes", fn: func() ([]byte, error) { return make([]byte, 10000), nil }, err1X: ErrUseRLE, err4X: ErrUseRLE},
|
||||
{name: "crash1", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/crash1.bin") }, err1X: ErrIncompressible, err4X: ErrIncompressible},
|
||||
{name: "crash2", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/crash2.bin") }, err4X: ErrIncompressible},
|
||||
{name: "crash3", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/crash3.bin") }, err1X: ErrIncompressible, err4X: ErrIncompressible},
|
||||
{name: "endzerobits", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/endzerobits.bin") }, err1X: nil, err4X: ErrIncompressible},
|
||||
{name: "endnonzero", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/endnonzero.bin") }, err4X: ErrIncompressible},
|
||||
{name: "case1", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/case1.bin") }, err1X: nil},
|
||||
{name: "case2", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/case2.bin") }, err1X: nil},
|
||||
{name: "case3", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/case3.bin") }, err1X: nil},
|
||||
{name: "pngdata.001", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/pngdata.bin") }, err1X: nil},
|
||||
{name: "normcount2", fn: func() ([]byte, error) { return ioutil.ReadFile("../testdata/normcount2.bin") }, err1X: nil},
|
||||
}
|
||||
|
||||
type fuzzInput struct {
|
||||
name string
|
||||
fn inputFn
|
||||
}
|
||||
|
||||
var testfilesExtended []fuzzInput
|
||||
|
||||
func init() {
|
||||
filepath.Walk("./fuzz/compress/corpus", func(path string, info os.FileInfo, err error) error {
|
||||
if info.Size() == 0 || info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
testfilesExtended = append(testfilesExtended, fuzzInput{
|
||||
name: filepath.Base(path),
|
||||
fn: func() ([]byte, error) {
|
||||
return ioutil.ReadFile(path)
|
||||
},
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestCompress1X(t *testing.T) {
|
||||
for _, test := range testfiles {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var s Scratch
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
b, re, err := Compress1X(buf0, &s)
|
||||
if err != test.err1X {
|
||||
t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err1X, err, err)
|
||||
}
|
||||
if err != nil {
|
||||
t.Log(test.name, err.Error())
|
||||
return
|
||||
}
|
||||
if b == nil {
|
||||
t.Error("got no output")
|
||||
return
|
||||
}
|
||||
min := s.minSize(len(buf0))
|
||||
if len(s.OutData) < min {
|
||||
t.Errorf("output data length (%d) below shannon limit (%d)", len(s.OutData), min)
|
||||
}
|
||||
if len(s.OutTable) == 0 {
|
||||
t.Error("got no table definition")
|
||||
}
|
||||
if re {
|
||||
t.Error("claimed to have re-used.")
|
||||
}
|
||||
if len(s.OutData) == 0 {
|
||||
t.Error("got no data output")
|
||||
}
|
||||
t.Logf("%s: %d -> %d bytes (%.2f:1) re:%t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
|
||||
s.Out = nil
|
||||
bRe, _, err := Compress1X(b, &s)
|
||||
if err == nil {
|
||||
t.Log("Could re-compress to", len(bRe))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompress4X(t *testing.T) {
|
||||
for _, test := range testfiles {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var s Scratch
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
b, re, err := Compress4X(buf0, &s)
|
||||
if err != test.err4X {
|
||||
t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err4X, err, err)
|
||||
}
|
||||
if err != nil {
|
||||
t.Log(test.name, err.Error())
|
||||
return
|
||||
}
|
||||
if b == nil {
|
||||
t.Error("got no output")
|
||||
return
|
||||
}
|
||||
if len(s.OutTable) == 0 {
|
||||
t.Error("got no table definition")
|
||||
}
|
||||
if re {
|
||||
t.Error("claimed to have re-used.")
|
||||
}
|
||||
if len(s.OutData) == 0 {
|
||||
t.Error("got no data output")
|
||||
}
|
||||
|
||||
t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompress1XReuse(t *testing.T) {
|
||||
for _, test := range testfiles {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var s Scratch
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
b, re, err := Compress1X(buf0, &s)
|
||||
if err != test.err1X {
|
||||
t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err1X, err, err)
|
||||
}
|
||||
if err != nil {
|
||||
t.Log(test.name, err.Error())
|
||||
return
|
||||
}
|
||||
if b == nil {
|
||||
t.Error("got no output")
|
||||
return
|
||||
}
|
||||
firstData := len(s.OutData)
|
||||
s.Reuse = ReusePolicyAllow
|
||||
b, re, err = Compress1X(buf0, &s)
|
||||
if err != nil {
|
||||
t.Errorf("got secondary error %v (%T)", err, err)
|
||||
return
|
||||
}
|
||||
if !re {
|
||||
t.Error("Didn't re-use even if data was the same")
|
||||
}
|
||||
if len(s.OutTable) != 0 {
|
||||
t.Error("got table definition, don't want any")
|
||||
}
|
||||
if len(s.OutData) == 0 {
|
||||
t.Error("got no data output")
|
||||
}
|
||||
if len(b) != firstData {
|
||||
t.Errorf("data length did not match first: %d, second:%d", firstData, len(b))
|
||||
}
|
||||
t.Logf("%s: %d -> %d bytes (%.2f:1) %t", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDeflate(b *testing.B) {
|
||||
for _, tt := range testfiles {
|
||||
test := tt
|
||||
if test.err1X != nil {
|
||||
continue
|
||||
}
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
dec, err := flate.NewWriter(ioutil.Discard, flate.HuffmanOnly)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if test.err1X != nil {
|
||||
b.Skip("skipping")
|
||||
}
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf0)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
dec.Reset(ioutil.Discard)
|
||||
n, err := dec.Write(buf0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if n != len(buf0) {
|
||||
b.Fatal("mismatch", n, len(buf0))
|
||||
}
|
||||
dec.Close()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompress1XReuseNone(b *testing.B) {
|
||||
for _, tt := range testfiles {
|
||||
test := tt
|
||||
if test.err1X != nil {
|
||||
continue
|
||||
}
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
var s Scratch
|
||||
s.Reuse = ReusePolicyNone
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
_, re, err := Compress1X(buf0, &s)
|
||||
if err != test.err1X {
|
||||
b.Fatal("unexpected error:", err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf0)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, re, _ = Compress1X(buf0, &s)
|
||||
if re {
|
||||
b.Fatal("reused")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompress1XReuseAllow(b *testing.B) {
|
||||
for _, tt := range testfiles {
|
||||
test := tt
|
||||
if test.err1X != nil {
|
||||
continue
|
||||
}
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
var s Scratch
|
||||
s.Reuse = ReusePolicyAllow
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
_, re, err := Compress1X(buf0, &s)
|
||||
if err != test.err1X {
|
||||
b.Fatal("unexpected error:", err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf0)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, re, _ = Compress1X(buf0, &s)
|
||||
if !re {
|
||||
b.Fatal("not reused")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompress1XReusePrefer(b *testing.B) {
|
||||
for _, tt := range testfiles {
|
||||
test := tt
|
||||
if test.err1X != nil {
|
||||
continue
|
||||
}
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
var s Scratch
|
||||
s.Reuse = ReusePolicyPrefer
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
_, re, err := Compress1X(buf0, &s)
|
||||
if err != test.err1X {
|
||||
b.Fatal("unexpected error:", err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf0)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, re, _ = Compress1X(buf0, &s)
|
||||
if !re {
|
||||
b.Fatal("not reused")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompress4XReuseNone(b *testing.B) {
|
||||
for _, tt := range testfiles {
|
||||
test := tt
|
||||
if test.err4X != nil {
|
||||
continue
|
||||
}
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
var s Scratch
|
||||
s.Reuse = ReusePolicyNone
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
_, re, err := Compress4X(buf0, &s)
|
||||
if err != test.err1X {
|
||||
b.Fatal("unexpected error:", err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf0)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, re, _ = Compress4X(buf0, &s)
|
||||
if re {
|
||||
b.Fatal("reused")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompress4XReuseAllow(b *testing.B) {
|
||||
for _, tt := range testfiles {
|
||||
test := tt
|
||||
if test.err4X != nil {
|
||||
continue
|
||||
}
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
var s Scratch
|
||||
s.Reuse = ReusePolicyAllow
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
_, re, err := Compress4X(buf0, &s)
|
||||
if err != test.err1X {
|
||||
b.Fatal("unexpected error:", err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf0)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, re, _ = Compress4X(buf0, &s)
|
||||
if !re {
|
||||
b.Fatal("not reused")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompress4XReusePrefer(b *testing.B) {
|
||||
for _, tt := range testfiles {
|
||||
test := tt
|
||||
if test.err4X != nil {
|
||||
continue
|
||||
}
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
var s Scratch
|
||||
s.Reuse = ReusePolicyPrefer
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
_, re, err := Compress4X(buf0, &s)
|
||||
if err != test.err4X {
|
||||
b.Fatal("unexpected error:", err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf0)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, re, _ = Compress4X(buf0, &s)
|
||||
if !re {
|
||||
b.Fatal("not reused")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+392
@@ -0,0 +1,392 @@
|
||||
package huff0
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/klauspost/compress/fse"
|
||||
)
|
||||
|
||||
type dTable struct {
|
||||
single []dEntrySingle
|
||||
double []dEntryDouble
|
||||
}
|
||||
|
||||
// single-symbols decoding
|
||||
type dEntrySingle struct {
|
||||
byte uint8
|
||||
nBits uint8
|
||||
}
|
||||
|
||||
// double-symbols decoding
|
||||
type dEntryDouble struct {
|
||||
seq uint16
|
||||
nBits uint8
|
||||
len uint8
|
||||
}
|
||||
|
||||
// ReadTable will read a table from the input.
|
||||
// The size of the input may be larger than the table definition.
|
||||
// Any content remaining after the table definition will be returned.
|
||||
// if no Scratch is provided a new one is allocated.
|
||||
// The returned Scratch can be used for decoding input using this table.
|
||||
func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
|
||||
s, err = s.prepare(in)
|
||||
if err != nil {
|
||||
return s, nil, err
|
||||
}
|
||||
if len(in) <= 1 {
|
||||
return s, nil, errors.New("input too small for table")
|
||||
}
|
||||
iSize := in[0]
|
||||
in = in[1:]
|
||||
if iSize >= 128 {
|
||||
// Uncompressed
|
||||
oSize := iSize - 127
|
||||
iSize = (oSize + 1) / 2
|
||||
if int(iSize) > len(in) {
|
||||
return s, nil, errors.New("input too small for table")
|
||||
}
|
||||
for n := uint8(0); n < oSize; n += 2 {
|
||||
v := in[n/2]
|
||||
s.huffWeight[n] = v >> 4
|
||||
s.huffWeight[n+1] = v & 15
|
||||
}
|
||||
s.symbolLen = uint16(oSize)
|
||||
in = in[iSize:]
|
||||
} else {
|
||||
if len(in) <= int(iSize) {
|
||||
return s, nil, errors.New("input too small for table")
|
||||
}
|
||||
// FSE compressed weights
|
||||
s.fse.DecompressLimit = 255
|
||||
hw := s.huffWeight[:]
|
||||
s.fse.Out = hw
|
||||
b, err := fse.Decompress(in[:iSize], s.fse)
|
||||
s.fse.Out = nil
|
||||
if err != nil {
|
||||
return s, nil, err
|
||||
}
|
||||
if len(b) > 255 {
|
||||
return s, nil, errors.New("corrupt input: output table too large")
|
||||
}
|
||||
s.symbolLen = uint16(len(b))
|
||||
in = in[iSize:]
|
||||
}
|
||||
|
||||
// collect weight stats
|
||||
var rankStats [tableLogMax + 1]uint32
|
||||
weightTotal := uint32(0)
|
||||
for _, v := range s.huffWeight[:s.symbolLen] {
|
||||
if v > tableLogMax {
|
||||
return s, nil, errors.New("corrupt input: weight too large")
|
||||
}
|
||||
rankStats[v]++
|
||||
weightTotal += (1 << (v & 15)) >> 1
|
||||
}
|
||||
if weightTotal == 0 {
|
||||
return s, nil, errors.New("corrupt input: weights zero")
|
||||
}
|
||||
|
||||
// get last non-null symbol weight (implied, total must be 2^n)
|
||||
{
|
||||
tableLog := highBit32(weightTotal) + 1
|
||||
if tableLog > tableLogMax {
|
||||
return s, nil, errors.New("corrupt input: tableLog too big")
|
||||
}
|
||||
s.actualTableLog = uint8(tableLog)
|
||||
// determine last weight
|
||||
{
|
||||
total := uint32(1) << tableLog
|
||||
rest := total - weightTotal
|
||||
verif := uint32(1) << highBit32(rest)
|
||||
lastWeight := highBit32(rest) + 1
|
||||
if verif != rest {
|
||||
// last value must be a clean power of 2
|
||||
return s, nil, errors.New("corrupt input: last value not power of two")
|
||||
}
|
||||
s.huffWeight[s.symbolLen] = uint8(lastWeight)
|
||||
s.symbolLen++
|
||||
rankStats[lastWeight]++
|
||||
}
|
||||
}
|
||||
|
||||
if (rankStats[1] < 2) || (rankStats[1]&1 != 0) {
|
||||
// by construction : at least 2 elts of rank 1, must be even
|
||||
return s, nil, errors.New("corrupt input: min elt size, even check failed ")
|
||||
}
|
||||
|
||||
// TODO: Choose between single/double symbol decoding
|
||||
|
||||
// Calculate starting value for each rank
|
||||
{
|
||||
var nextRankStart uint32
|
||||
for n := uint8(1); n < s.actualTableLog+1; n++ {
|
||||
current := nextRankStart
|
||||
nextRankStart += rankStats[n] << (n - 1)
|
||||
rankStats[n] = current
|
||||
}
|
||||
}
|
||||
|
||||
// fill DTable (always full size)
|
||||
tSize := 1 << tableLogMax
|
||||
if len(s.dt.single) != tSize {
|
||||
s.dt.single = make([]dEntrySingle, tSize)
|
||||
}
|
||||
|
||||
for n, w := range s.huffWeight[:s.symbolLen] {
|
||||
length := (uint32(1) << w) >> 1
|
||||
d := dEntrySingle{
|
||||
byte: uint8(n),
|
||||
nBits: s.actualTableLog + 1 - w,
|
||||
}
|
||||
for u := rankStats[w]; u < rankStats[w]+length; u++ {
|
||||
s.dt.single[u] = d
|
||||
}
|
||||
rankStats[w] += length
|
||||
}
|
||||
return s, in, nil
|
||||
}
|
||||
|
||||
// Decompress1X will decompress a 1X encoded stream.
|
||||
// The supplied input must match the end of a block exactly.
|
||||
// Before this is called, the table must be initialized with ReadTable.
|
||||
func (s *Scratch) Decompress1X(in []byte) (out []byte, err error) {
|
||||
if len(s.dt.single) == 0 {
|
||||
return nil, errors.New("no table loaded")
|
||||
}
|
||||
var br bitReader
|
||||
err = br.init(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Out = s.Out[:0]
|
||||
|
||||
decode := func() byte {
|
||||
val := br.peekBitsFast(s.actualTableLog) /* note : actualTableLog >= 1 */
|
||||
v := s.dt.single[val]
|
||||
br.bitsRead += v.nBits
|
||||
return v.byte
|
||||
}
|
||||
hasDec := func(v dEntrySingle) byte {
|
||||
br.bitsRead += v.nBits
|
||||
return v.byte
|
||||
}
|
||||
|
||||
// Avoid bounds check by always having full sized table.
|
||||
const tlSize = 1 << tableLogMax
|
||||
const tlMask = tlSize - 1
|
||||
dt := s.dt.single[:tlSize]
|
||||
|
||||
// Use temp table to avoid bound checks/append penalty.
|
||||
var tmp = s.huffWeight[:256]
|
||||
var off uint8
|
||||
|
||||
for br.off >= 8 {
|
||||
br.fillFast()
|
||||
tmp[off+0] = hasDec(dt[br.peekBitsFast(s.actualTableLog)&tlMask])
|
||||
tmp[off+1] = hasDec(dt[br.peekBitsFast(s.actualTableLog)&tlMask])
|
||||
br.fillFast()
|
||||
tmp[off+2] = hasDec(dt[br.peekBitsFast(s.actualTableLog)&tlMask])
|
||||
tmp[off+3] = hasDec(dt[br.peekBitsFast(s.actualTableLog)&tlMask])
|
||||
off += 4
|
||||
if off == 0 {
|
||||
s.Out = append(s.Out, tmp...)
|
||||
}
|
||||
}
|
||||
|
||||
s.Out = append(s.Out, tmp[:off]...)
|
||||
|
||||
for !br.finished() {
|
||||
br.fill()
|
||||
s.Out = append(s.Out, decode())
|
||||
}
|
||||
return s.Out, br.close()
|
||||
}
|
||||
|
||||
// Decompress4X will decompress a 4X encoded stream.
|
||||
// Before this is called, the table must be initialized with ReadTable.
|
||||
// The supplied input must match the end of a block exactly.
|
||||
// The destination size of the uncompressed data must be known and provided.
|
||||
func (s *Scratch) Decompress4X(in []byte, dstSize int) (out []byte, err error) {
|
||||
if len(s.dt.single) == 0 {
|
||||
return nil, errors.New("no table loaded")
|
||||
}
|
||||
if len(in) < 6+(4*1) {
|
||||
return nil, errors.New("input too small")
|
||||
}
|
||||
// TODO: We do not detect when we overrun a buffer, except if the last one does.
|
||||
|
||||
var br [4]bitReader
|
||||
start := 6
|
||||
for i := 0; i < 3; i++ {
|
||||
length := int(in[i*2]) | (int(in[i*2+1]) << 8)
|
||||
if start+length >= len(in) {
|
||||
return nil, errors.New("truncated input (or invalid offset)")
|
||||
}
|
||||
err = br[i].init(in[start : start+length])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
start += length
|
||||
}
|
||||
err = br[3].init(in[start:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prepare output
|
||||
if cap(s.Out) < dstSize {
|
||||
s.Out = make([]byte, 0, dstSize)
|
||||
}
|
||||
s.Out = s.Out[:dstSize]
|
||||
// destination, offset to match first output
|
||||
dstOut := s.Out
|
||||
dstEvery := (dstSize + 3) / 4
|
||||
|
||||
decode := func(br *bitReader) byte {
|
||||
val := br.peekBitsFast(s.actualTableLog) /* note : actualTableLog >= 1 */
|
||||
v := s.dt.single[val]
|
||||
br.bitsRead += v.nBits
|
||||
return v.byte
|
||||
}
|
||||
|
||||
// Use temp table to avoid bound checks/append penalty.
|
||||
var tmp = s.huffWeight[:256]
|
||||
var off uint8
|
||||
|
||||
// Decode 2 values from each decoder/loop.
|
||||
const bufoff = 256 / 4
|
||||
bigloop:
|
||||
for {
|
||||
for i := range br {
|
||||
if br[i].off < 4 {
|
||||
break bigloop
|
||||
}
|
||||
br[i].fillFast()
|
||||
}
|
||||
tmp[off] = decode(&br[0])
|
||||
tmp[off+bufoff] = decode(&br[1])
|
||||
tmp[off+bufoff*2] = decode(&br[2])
|
||||
tmp[off+bufoff*3] = decode(&br[3])
|
||||
tmp[off+1] = decode(&br[0])
|
||||
tmp[off+1+bufoff] = decode(&br[1])
|
||||
tmp[off+1+bufoff*2] = decode(&br[2])
|
||||
tmp[off+1+bufoff*3] = decode(&br[3])
|
||||
off += 2
|
||||
if off == bufoff {
|
||||
copy(dstOut, tmp[:bufoff])
|
||||
copy(dstOut[dstEvery:], tmp[bufoff:bufoff*2])
|
||||
copy(dstOut[dstEvery*2:], tmp[bufoff*2:bufoff*3])
|
||||
copy(dstOut[dstEvery*3:], tmp[bufoff*3:bufoff*4])
|
||||
off = 0
|
||||
dstOut = dstOut[bufoff:]
|
||||
// There must at least be 3 buffers left.
|
||||
if len(dstOut) < dstEvery*3+3 {
|
||||
return nil, errors.New("corruption detected: stream overrun")
|
||||
}
|
||||
}
|
||||
}
|
||||
if off > 0 {
|
||||
ioff := int(off)
|
||||
if len(dstOut) < dstEvery*3-ioff {
|
||||
return nil, errors.New("corruption detected: stream overrun")
|
||||
}
|
||||
copy(dstOut, tmp[:off])
|
||||
copy(dstOut[dstEvery:dstEvery+ioff], tmp[bufoff:bufoff*2])
|
||||
copy(dstOut[dstEvery*2:dstEvery*2+ioff], tmp[bufoff*2:bufoff*3])
|
||||
copy(dstOut[dstEvery*3:dstEvery*3+ioff], tmp[bufoff*3:bufoff*4])
|
||||
dstOut = dstOut[off:]
|
||||
}
|
||||
|
||||
for i := range br {
|
||||
offset := dstEvery * i
|
||||
br := &br[i]
|
||||
for !br.finished() {
|
||||
br.fill()
|
||||
if offset >= len(dstOut) {
|
||||
return nil, errors.New("corruption detected: stream overrun")
|
||||
}
|
||||
dstOut[offset] = decode(br)
|
||||
offset++
|
||||
}
|
||||
err = br.close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return s.Out, nil
|
||||
}
|
||||
|
||||
// matches will compare a decoding table to a coding table.
|
||||
// Errors are written to the writer.
|
||||
// Nothing will be written if table is ok.
|
||||
func (s *Scratch) matches(ct cTable, w io.Writer) {
|
||||
if s == nil || len(s.dt.single) == 0 {
|
||||
return
|
||||
}
|
||||
dt := s.dt.single[:1<<s.actualTableLog]
|
||||
tablelog := s.actualTableLog
|
||||
ok := 0
|
||||
broken := 0
|
||||
for sym, enc := range ct {
|
||||
errs := 0
|
||||
broken++
|
||||
if enc.nBits == 0 {
|
||||
for _, dec := range dt {
|
||||
if dec.byte == byte(sym) {
|
||||
fmt.Fprintf(w, "symbol %x has decoder, but no encoder\n", sym)
|
||||
errs++
|
||||
break
|
||||
}
|
||||
}
|
||||
if errs == 0 {
|
||||
broken--
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Unused bits in input
|
||||
ub := tablelog - enc.nBits
|
||||
top := enc.val << ub
|
||||
// decoder looks at top bits.
|
||||
dec := dt[top]
|
||||
if dec.nBits != enc.nBits {
|
||||
fmt.Fprintf(w, "symbol 0x%x bit size mismatch (enc: %d, dec:%d).\n", sym, enc.nBits, dec.nBits)
|
||||
errs++
|
||||
}
|
||||
if dec.byte != uint8(sym) {
|
||||
fmt.Fprintf(w, "symbol 0x%x decoder output mismatch (enc: %d, dec:%d).\n", sym, sym, dec.byte)
|
||||
errs++
|
||||
}
|
||||
if errs > 0 {
|
||||
fmt.Fprintf(w, "%d errros in base, stopping\n", errs)
|
||||
continue
|
||||
}
|
||||
// Ensure that all combinations are covered.
|
||||
for i := uint16(0); i < (1 << ub); i++ {
|
||||
vval := top | i
|
||||
dec := dt[vval]
|
||||
if dec.nBits != enc.nBits {
|
||||
fmt.Fprintf(w, "symbol 0x%x bit size mismatch (enc: %d, dec:%d).\n", vval, enc.nBits, dec.nBits)
|
||||
errs++
|
||||
}
|
||||
if dec.byte != uint8(sym) {
|
||||
fmt.Fprintf(w, "symbol 0x%x decoder output mismatch (enc: %d, dec:%d).\n", vval, sym, dec.byte)
|
||||
errs++
|
||||
}
|
||||
if errs > 20 {
|
||||
fmt.Fprintf(w, "%d errros, stopping\n", errs)
|
||||
break
|
||||
}
|
||||
}
|
||||
if errs == 0 {
|
||||
ok++
|
||||
broken--
|
||||
}
|
||||
}
|
||||
if broken > 0 {
|
||||
fmt.Fprintf(w, "%d broken, %d ok\n", broken, ok)
|
||||
}
|
||||
}
|
||||
+482
@@ -0,0 +1,482 @@
|
||||
package huff0
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestDecompress1X(t *testing.T) {
|
||||
for _, test := range testfiles {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var s = &Scratch{}
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
b, re, err := Compress1X(buf0, s)
|
||||
if err != test.err1X {
|
||||
t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err1X, err, err)
|
||||
}
|
||||
if err != nil {
|
||||
t.Log(test.name, err.Error())
|
||||
return
|
||||
}
|
||||
if b == nil {
|
||||
t.Error("got no output")
|
||||
return
|
||||
}
|
||||
if len(s.OutTable) == 0 {
|
||||
t.Error("got no table definition")
|
||||
}
|
||||
if re {
|
||||
t.Error("claimed to have re-used.")
|
||||
}
|
||||
if len(s.OutData) == 0 {
|
||||
t.Error("got no data output")
|
||||
}
|
||||
|
||||
wantRemain := len(s.OutData)
|
||||
t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
|
||||
|
||||
s.Out = nil
|
||||
var remain []byte
|
||||
s, remain, err = ReadTable(b, s)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if s.matches(s.prevTable, &buf); buf.Len() > 0 {
|
||||
t.Error(buf.String())
|
||||
}
|
||||
if len(remain) != wantRemain {
|
||||
t.Fatalf("remain mismatch, want %d, got %d bytes", wantRemain, len(remain))
|
||||
}
|
||||
t.Logf("remain: %d bytes, ok", len(remain))
|
||||
dc, err := s.Decompress1X(remain)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if len(buf0) != len(dc) {
|
||||
t.Errorf(test.name+"decompressed, want size: %d, got %d", len(buf0), len(dc))
|
||||
if len(buf0) > len(dc) {
|
||||
buf0 = buf0[:len(dc)]
|
||||
} else {
|
||||
dc = dc[:len(buf0)]
|
||||
}
|
||||
if !cmp.Equal(buf0, dc) {
|
||||
if len(dc) > 1024 {
|
||||
t.Log(string(dc[:1024]))
|
||||
t.Errorf(test.name+"decompressed, got delta: \n(in)\t%02x !=\n(out)\t%02x\n", buf0[:1024], dc[:1024])
|
||||
} else {
|
||||
t.Log(string(dc))
|
||||
t.Errorf(test.name+"decompressed, got delta: (in) %v != (out) %v\n", buf0, dc)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if !cmp.Equal(buf0, dc) {
|
||||
if len(buf0) > 1024 {
|
||||
t.Log(string(dc[:1024]))
|
||||
} else {
|
||||
t.Log(string(dc))
|
||||
}
|
||||
//t.Errorf(test.name+": decompressed, got delta: \n%s")
|
||||
t.Errorf(test.name + ": decompressed, got delta")
|
||||
}
|
||||
if !t.Failed() {
|
||||
t.Log("... roundtrip ok!")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecompress4X(t *testing.T) {
|
||||
for _, test := range testfiles {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var s = &Scratch{}
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
b, re, err := Compress4X(buf0, s)
|
||||
if err != test.err4X {
|
||||
t.Errorf("want error %v (%T), got %v (%T)", test.err1X, test.err1X, err, err)
|
||||
}
|
||||
if err != nil {
|
||||
t.Log(test.name, err.Error())
|
||||
return
|
||||
}
|
||||
if b == nil {
|
||||
t.Error("got no output")
|
||||
return
|
||||
}
|
||||
if len(s.OutTable) == 0 {
|
||||
t.Error("got no table definition")
|
||||
}
|
||||
if re {
|
||||
t.Error("claimed to have re-used.")
|
||||
}
|
||||
if len(s.OutData) == 0 {
|
||||
t.Error("got no data output")
|
||||
}
|
||||
|
||||
wantRemain := len(s.OutData)
|
||||
t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
|
||||
|
||||
s.Out = nil
|
||||
var remain []byte
|
||||
s, remain, err = ReadTable(b, s)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if s.matches(s.prevTable, &buf); buf.Len() > 0 {
|
||||
t.Error(buf.String())
|
||||
}
|
||||
if len(remain) != wantRemain {
|
||||
t.Fatalf("remain mismatch, want %d, got %d bytes", wantRemain, len(remain))
|
||||
}
|
||||
t.Logf("remain: %d bytes, ok", len(remain))
|
||||
dc, err := s.Decompress4X(remain, len(buf0))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if len(buf0) != len(dc) {
|
||||
t.Errorf(test.name+"decompressed, want size: %d, got %d", len(buf0), len(dc))
|
||||
if len(buf0) > len(dc) {
|
||||
buf0 = buf0[:len(dc)]
|
||||
} else {
|
||||
dc = dc[:len(buf0)]
|
||||
}
|
||||
if !cmp.Equal(buf0, dc) {
|
||||
if len(dc) > 1024 {
|
||||
t.Log(string(dc[:1024]))
|
||||
t.Errorf(test.name+"decompressed, got delta: \n(in)\t%02x !=\n(out)\t%02x\n", buf0[:1024], dc[:1024])
|
||||
} else {
|
||||
t.Log(string(dc))
|
||||
t.Errorf(test.name+"decompressed, got delta: (in) %v != (out) %v\n", buf0, dc)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if !cmp.Equal(buf0, dc) {
|
||||
if len(buf0) > 1024 {
|
||||
t.Log(string(dc[:1024]))
|
||||
} else {
|
||||
t.Log(string(dc))
|
||||
}
|
||||
//t.Errorf(test.name+": decompressed, got delta: \n%s")
|
||||
t.Errorf(test.name + ": decompressed, got delta")
|
||||
}
|
||||
if !t.Failed() {
|
||||
t.Log("... roundtrip ok!")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecompress1XFuzz(t *testing.T) {
|
||||
for _, test := range testfilesExtended {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var s = &Scratch{}
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
b, re, err := Compress1X(buf0, s)
|
||||
if err != nil {
|
||||
if err == ErrIncompressible || err == ErrUseRLE || err == ErrTooBig {
|
||||
t.Log(test.name, err.Error())
|
||||
return
|
||||
}
|
||||
t.Error(test.name, err.Error())
|
||||
return
|
||||
}
|
||||
if b == nil {
|
||||
t.Error("got no output")
|
||||
return
|
||||
}
|
||||
if len(s.OutTable) == 0 {
|
||||
t.Error("got no table definition")
|
||||
}
|
||||
if re {
|
||||
t.Error("claimed to have re-used.")
|
||||
}
|
||||
if len(s.OutData) == 0 {
|
||||
t.Error("got no data output")
|
||||
}
|
||||
|
||||
wantRemain := len(s.OutData)
|
||||
t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
|
||||
|
||||
s.Out = nil
|
||||
var remain []byte
|
||||
s, remain, err = ReadTable(b, s)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if s.matches(s.prevTable, &buf); buf.Len() > 0 {
|
||||
t.Error(buf.String())
|
||||
}
|
||||
if len(remain) != wantRemain {
|
||||
t.Fatalf("remain mismatch, want %d, got %d bytes", wantRemain, len(remain))
|
||||
}
|
||||
t.Logf("remain: %d bytes, ok", len(remain))
|
||||
dc, err := s.Decompress1X(remain)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if len(buf0) != len(dc) {
|
||||
t.Errorf(test.name+"decompressed, want size: %d, got %d", len(buf0), len(dc))
|
||||
if len(buf0) > len(dc) {
|
||||
buf0 = buf0[:len(dc)]
|
||||
} else {
|
||||
dc = dc[:len(buf0)]
|
||||
}
|
||||
if !cmp.Equal(buf0, dc) {
|
||||
if len(dc) > 1024 {
|
||||
t.Log(string(dc[:1024]))
|
||||
t.Errorf(test.name+"decompressed, got delta: \n(in)\t%02x !=\n(out)\t%02x\n", buf0[:1024], dc[:1024])
|
||||
} else {
|
||||
t.Log(string(dc))
|
||||
t.Errorf(test.name+"decompressed, got delta: (in) %v != (out) %v\n", buf0, dc)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if !cmp.Equal(buf0, dc) {
|
||||
if len(buf0) > 1024 {
|
||||
t.Log(string(dc[:1024]))
|
||||
} else {
|
||||
t.Log(string(dc))
|
||||
}
|
||||
//t.Errorf(test.name+": decompressed, got delta: \n%s")
|
||||
t.Errorf(test.name + ": decompressed, got delta")
|
||||
}
|
||||
if !t.Failed() {
|
||||
t.Log("... roundtrip ok!")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecompress4XFuzz(t *testing.T) {
|
||||
for _, test := range testfilesExtended {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var s = &Scratch{}
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
b, re, err := Compress4X(buf0, s)
|
||||
if err != nil {
|
||||
if err == ErrIncompressible || err == ErrUseRLE || err == ErrTooBig {
|
||||
t.Log(test.name, err.Error())
|
||||
return
|
||||
}
|
||||
t.Error(test.name, err.Error())
|
||||
return
|
||||
}
|
||||
if b == nil {
|
||||
t.Error("got no output")
|
||||
return
|
||||
}
|
||||
if len(s.OutTable) == 0 {
|
||||
t.Error("got no table definition")
|
||||
}
|
||||
if re {
|
||||
t.Error("claimed to have re-used.")
|
||||
}
|
||||
if len(s.OutData) == 0 {
|
||||
t.Error("got no data output")
|
||||
}
|
||||
|
||||
wantRemain := len(s.OutData)
|
||||
t.Logf("%s: %d -> %d bytes (%.2f:1) %t (table: %d bytes)", test.name, len(buf0), len(b), float64(len(buf0))/float64(len(b)), re, len(s.OutTable))
|
||||
|
||||
s.Out = nil
|
||||
var remain []byte
|
||||
s, remain, err = ReadTable(b, s)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if s.matches(s.prevTable, &buf); buf.Len() > 0 {
|
||||
t.Error(buf.String())
|
||||
}
|
||||
if len(remain) != wantRemain {
|
||||
t.Fatalf("remain mismatch, want %d, got %d bytes", wantRemain, len(remain))
|
||||
}
|
||||
t.Logf("remain: %d bytes, ok", len(remain))
|
||||
dc, err := s.Decompress4X(remain, len(buf0))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if len(buf0) != len(dc) {
|
||||
t.Errorf(test.name+"decompressed, want size: %d, got %d", len(buf0), len(dc))
|
||||
if len(buf0) > len(dc) {
|
||||
buf0 = buf0[:len(dc)]
|
||||
} else {
|
||||
dc = dc[:len(buf0)]
|
||||
}
|
||||
if !cmp.Equal(buf0, dc) {
|
||||
if len(dc) > 1024 {
|
||||
t.Log(string(dc[:1024]))
|
||||
t.Errorf(test.name+"decompressed, got delta: \n(in)\t%02x !=\n(out)\t%02x\n", buf0[:1024], dc[:1024])
|
||||
} else {
|
||||
t.Log(string(dc))
|
||||
t.Errorf(test.name+"decompressed, got delta: (in) %v != (out) %v\n", buf0, dc)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if !cmp.Equal(buf0, dc) {
|
||||
if len(buf0) > 1024 {
|
||||
t.Log(string(dc[:1024]))
|
||||
} else {
|
||||
t.Log(string(dc))
|
||||
}
|
||||
//t.Errorf(test.name+": decompressed, got delta: \n%s")
|
||||
t.Errorf(test.name + ": decompressed, got delta")
|
||||
}
|
||||
if !t.Failed() {
|
||||
t.Log("... roundtrip ok!")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecompress1XTable(b *testing.B) {
|
||||
for _, tt := range testfiles {
|
||||
test := tt
|
||||
if test.err1X != nil {
|
||||
continue
|
||||
}
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
var s = &Scratch{}
|
||||
s.Reuse = ReusePolicyNone
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
compressed, _, err := Compress1X(buf0, s)
|
||||
if err != test.err1X {
|
||||
b.Fatal("unexpected error:", err)
|
||||
}
|
||||
s.Out = nil
|
||||
s, remain, _ := ReadTable(compressed, s)
|
||||
s.Decompress1X(remain)
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf0)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
s, remain, err := ReadTable(compressed, s)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_, err = s.Decompress1X(remain)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecompress1XNoTable(b *testing.B) {
|
||||
for _, tt := range testfiles {
|
||||
test := tt
|
||||
if test.err1X != nil {
|
||||
continue
|
||||
}
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
var s = &Scratch{}
|
||||
s.Reuse = ReusePolicyNone
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
compressed, _, err := Compress1X(buf0, s)
|
||||
if err != test.err1X {
|
||||
b.Fatal("unexpected error:", err)
|
||||
}
|
||||
s.Out = nil
|
||||
s, remain, _ := ReadTable(compressed, s)
|
||||
s.Decompress1X(remain)
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf0)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = s.Decompress1X(remain)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecompress4XNoTable(b *testing.B) {
|
||||
for _, tt := range testfiles {
|
||||
test := tt
|
||||
if test.err4X != nil {
|
||||
continue
|
||||
}
|
||||
b.Run(test.name, func(b *testing.B) {
|
||||
var s = &Scratch{}
|
||||
s.Reuse = ReusePolicyNone
|
||||
buf0, err := test.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if len(buf0) > BlockSizeMax {
|
||||
buf0 = buf0[:BlockSizeMax]
|
||||
}
|
||||
compressed, _, err := Compress4X(buf0, s)
|
||||
if err != test.err1X {
|
||||
b.Fatal("unexpected error:", err)
|
||||
}
|
||||
s.Out = nil
|
||||
s, remain, _ := ReadTable(compressed, s)
|
||||
s.Decompress4X(remain, len(buf0))
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf0)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = s.Decompress4X(remain, len(buf0))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
012939495969798997C2
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
CaDCaDcAecDc7De7777-accD77DeDEEAf_ZohDnpPnXJKmFtxmGZFOVgbxbCaAEEAAfecbD4dc44.x.xAfF-45405050xdbCaDAEEd0EcdDA7AfecbD4dc454057025Vz-04454224054e-0276666767011776664.efZohQpggnpGPTrniXRqJlKmFtmGZFOgVMgwxAAfeB643xbBCaBABE3BEcd3AAfecbD64Bdc664423703235e-07503-0xB66C9fad.-75946554523692857652911-i1V___hoNaqWTStRM9101862645149230957031250xdbBC2aBDABEEd73801BEcdD3A7AfecbD864Bdc1862645149230957031259101862645149230957031250xdbBC2aBDABEEd73801BEcdD3A7AfecbD864Bdc186264514923095703125\B___L7D3PS0hd1_Gxkg_Eg2P_Uo_3yd3gU_a_2__Ct28_l1w16r4_p_Q898Fv_22_6_28282357FECfCFCdBEEaE47fb5Bcý{ý1.0xd-0534420.-8911368683772161602973534420.-89113686<-7301351713.7376291319585350ýý[
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
-08338832110233882812
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
8869fecbD864Bdc186264514923095703125-70989128513186264514923095703125
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
xhy_1P_X_Bers6vz3zZ_95_J_DSW6IkV4_woYf___aC7_p1_1gED_4_Q_28_T73eUL053440.-136868-
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
012756789aefxbcdefx
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
8869-0x0e.-9101862645149230957031250xdbBC2aBDABEEd73801BEcdD3A7AfecbD864Bdc186264514923095703125-70989128513186264514923095703125
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
0345678defghijklmnopqrstuvwxyz18872161F029739CFeBEbaE7fb-05340.-13686
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
"�4656612873077392578125
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
186264514923095703125
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
0aaef11119910xC8fFCFCEEaEfb.144-0440.-89116868771616097937988815-9101862645149230957031250xbCaBEBEDAfebDBdc32-xcA3.7475562603-0x0e0862645149230957031250xdbBC2aBDABEEd73801BEcdD3A7AfecbD864Bdc186264514923095703125|7318e000175420
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
*?| "
|
||||
%`Rw_Y} [QQ.=Rtw
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
1136868377216160798828125
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
GPTrniXRqJlK_mFt____AmGZ__BF_Og__VM_gw.4995325xC2aBABd731BEd3A7Aecb8dc866414295731253.0xDe9D94B9EEaf48EDccB4b5Da0-0x0e-9101862645149230957031250xdbBC2aBDABEEd73801BEcdD3A7AfecbD864Bdc186264514923095703125
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
4995325233449559994-09-519341245142309503125
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
92309570312
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
"�465663981283077397778125
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
012@456789@4567x
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
0003<Nv=TiKOMgwDDDyvS<kZQKHwIUmUjWymgXsPoltRZ-ZoISLwOSNjYuumzYRjJv\Vze*.eVzTyLniwrmMYzsIs\.eED(---.--[1111aEEDAfeDd-qdAEl.VZohQpFpGPtgnpGPTrniXRqJlKFtmGZFOgVMgw3Afb35353;af4ba-x___Tr44niX_Rq_JlK_mF__t___4A57_EAxmGZ__BF_Og__VM8gw418451435731250xbBaBEBEd3A7AfbD8Bd18241423095703125!91018245149230957031250xdbB2aBDABEEd73801BEcdD3A7AfecbD84Bdc1862645149230957031253.0742642597915814946756428320630820e-0xf34qj-910162645149230957031250xdbBC2aBDABEEd73801BEcdD3A7AfecbD864Bdc1862645149230957031253Vz-808534522276595512169.4hyPXrsvzzZJSWIkVwoY_aC_pCaEfDc644xfC2.050xDdFae0xAf05AdEF4e2C09e5da6445xC2E3EdD3AcbDc8664118626451492095031250xdbBC2aBDABEd73801BEcdD3A7Afecb7332
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
054175252231364715157010273365424.-0xaC4bc3bBFEE733c17Cb23c7B4E9
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
e11188721616029739CFeBEEbaE7fb-053440.-136868
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
"69128307397778125
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
bDabBef136316160973937988281250xCc8Ed-0534420.-89113686837721616
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
11686837721616029739
|
||||
Generated
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
)+~\ <?;ECPFPIE)::
|
||||
~?
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
-083・883022338828
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
1814923095703125
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
0123456789abcdefx
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
1136868377216160297393798828125
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
exF.-30030xCaEEDA7AfecbDc474499570350xdbCaDABEEd730BEcdD3A7AfecbD84Bdc864549309570325-03753662640774330616234263332315.-09918907192036521631809-0x0eÿ-9101862645149230957031250xdbBC2aBDABEEd73801BEcdD3A7AfecbD864Bdc186264514923095703125
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
)~\ <_______?;bE1bEC_AcyvP__FPI1bE1d_)+u::]~?
|
||||
__j_5bu__yU__Dv19WNu_13g_Y1_RYWQvX______1z_L_G_k1Mm[_&_6d48_7V9_hSINhG8r__yj1_8_SWh_pGx_Nk_S1__u08_iZVaayDaTxoo%ujDcH11Q._'riRZU/h_UO__63v2_G052"B_w34C_K1K.-Afc64ZmsVOt-'tqnf0x8f4E.-07__g.-03255663.-6&OyGOaL_h_Tt2Y1k717n1_7o6vN_KQ6MFXEO_2ANI4__z_l_a_PLn5Hm61_birB_/
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
-0xbafD8aae3Df5b9Bef111368683772161602973937988281250xCc3EBf357FEdaCfCF4CdeBEEbaE47fb5Bc691.-0xd-0Df5b9Bef1113686837721616029739379�Ń7288281250xCc3EBf357FEdaCfCF4CdeBEEbaE47fb5Bc˛ČÁŮ»ľ691.-0xd-0534420.-8911368683772161602973534420.-89113686<37721ľŕÁ[¨616029739379882812
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
-0757e0664060273074361272e0x2cF8a8E.-9101862645149230957031250xdbBC2aBDABEEd73801BEcdD3A7AfecbD864Bdc186264514923095703125-0xcA3.07047556026031-0x0e-9101862645149230957031250xdbBC2aBDABEEd73801BEcdD3A7AfecbD864Bdc1862645149230957031257318e00017542035
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
18695703125
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
3095703125
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
412221647115710273365424.-0xaC4BFE3cCb3c7BE9
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
111%613475767778796029739CFeBEEbaE7fb-053440.-
|
||||
Generated
Vendored
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user