You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
3.0 KiB
119 lines
3.0 KiB
// Copyright 2019+ Klaus Post. All rights reserved. |
|
// License information can be found in the LICENSE file. |
|
// Based on work by Yann Collet, released under BSD License. |
|
|
|
package zstd |
|
|
|
import ( |
|
"github.com/klauspost/compress/huff0" |
|
) |
|
|
|
// history contains the information transferred between blocks. |
|
type history struct { |
|
// Literal decompression |
|
huffTree *huff0.Scratch |
|
|
|
// Sequence decompression |
|
decoders sequenceDecs |
|
recentOffsets [3]int |
|
|
|
// History buffer... |
|
b []byte |
|
|
|
// ignoreBuffer is meant to ignore a number of bytes |
|
// when checking for matches in history |
|
ignoreBuffer int |
|
|
|
windowSize int |
|
allocFrameBuffer int // needed? |
|
error bool |
|
dict *dict |
|
} |
|
|
|
// reset will reset the history to initial state of a frame. |
|
// The history must already have been initialized to the desired size. |
|
func (h *history) reset() { |
|
h.b = h.b[:0] |
|
h.ignoreBuffer = 0 |
|
h.error = false |
|
h.recentOffsets = [3]int{1, 4, 8} |
|
if f := h.decoders.litLengths.fse; f != nil && !f.preDefined { |
|
fseDecoderPool.Put(f) |
|
} |
|
if f := h.decoders.offsets.fse; f != nil && !f.preDefined { |
|
fseDecoderPool.Put(f) |
|
} |
|
if f := h.decoders.matchLengths.fse; f != nil && !f.preDefined { |
|
fseDecoderPool.Put(f) |
|
} |
|
h.decoders = sequenceDecs{br: h.decoders.br} |
|
if h.huffTree != nil { |
|
if h.dict == nil || h.dict.litEnc != h.huffTree { |
|
huffDecoderPool.Put(h.huffTree) |
|
} |
|
} |
|
h.huffTree = nil |
|
h.dict = nil |
|
//printf("history created: %+v (l: %d, c: %d)", *h, len(h.b), cap(h.b)) |
|
} |
|
|
|
func (h *history) setDict(dict *dict) { |
|
if dict == nil { |
|
return |
|
} |
|
h.dict = dict |
|
h.decoders.litLengths = dict.llDec |
|
h.decoders.offsets = dict.ofDec |
|
h.decoders.matchLengths = dict.mlDec |
|
h.decoders.dict = dict.content |
|
h.recentOffsets = dict.offsets |
|
h.huffTree = dict.litEnc |
|
} |
|
|
|
// append bytes to history. |
|
// This function will make sure there is space for it, |
|
// if the buffer has been allocated with enough extra space. |
|
func (h *history) append(b []byte) { |
|
if len(b) >= h.windowSize { |
|
// Discard all history by simply overwriting |
|
h.b = h.b[:h.windowSize] |
|
copy(h.b, b[len(b)-h.windowSize:]) |
|
return |
|
} |
|
|
|
// If there is space, append it. |
|
if len(b) < cap(h.b)-len(h.b) { |
|
h.b = append(h.b, b...) |
|
return |
|
} |
|
|
|
// Move data down so we only have window size left. |
|
// We know we have less than window size in b at this point. |
|
discard := len(b) + len(h.b) - h.windowSize |
|
copy(h.b, h.b[discard:]) |
|
h.b = h.b[:h.windowSize] |
|
copy(h.b[h.windowSize-len(b):], b) |
|
} |
|
|
|
// ensureBlock will ensure there is space for at least one block... |
|
func (h *history) ensureBlock() { |
|
if cap(h.b) < h.allocFrameBuffer { |
|
h.b = make([]byte, 0, h.allocFrameBuffer) |
|
return |
|
} |
|
|
|
avail := cap(h.b) - len(h.b) |
|
if avail >= h.windowSize || avail > maxCompressedBlockSize { |
|
return |
|
} |
|
// Move data down so we only have window size left. |
|
// We know we have less than window size in b at this point. |
|
discard := len(h.b) - h.windowSize |
|
copy(h.b, h.b[discard:]) |
|
h.b = h.b[:h.windowSize] |
|
} |
|
|
|
// append bytes to history without ever discarding anything. |
|
func (h *history) appendKeep(b []byte) { |
|
h.b = append(h.b, b...) |
|
}
|
|
|