blob: 28b40153cc2c9734e73b2f86d1109e488af4c067 [file] [log] [blame]
khenaidoo7d3c5582021-08-11 18:09:44 -04001// 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 "github.com/klauspost/compress/huff0"
9)
10
11// history contains the information transferred between blocks.
12type history struct {
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053013 // Literal decompression
14 huffTree *huff0.Scratch
15
16 // Sequence decompression
khenaidoo7d3c5582021-08-11 18:09:44 -040017 decoders sequenceDecs
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053018 recentOffsets [3]int
19
20 // History buffer...
21 b []byte
22
23 // ignoreBuffer is meant to ignore a number of bytes
24 // when checking for matches in history
25 ignoreBuffer int
26
27 windowSize int
28 allocFrameBuffer int // needed?
29 error bool
30 dict *dict
khenaidoo7d3c5582021-08-11 18:09:44 -040031}
32
33// reset will reset the history to initial state of a frame.
34// The history must already have been initialized to the desired size.
35func (h *history) reset() {
36 h.b = h.b[:0]
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053037 h.ignoreBuffer = 0
khenaidoo7d3c5582021-08-11 18:09:44 -040038 h.error = false
39 h.recentOffsets = [3]int{1, 4, 8}
40 if f := h.decoders.litLengths.fse; f != nil && !f.preDefined {
41 fseDecoderPool.Put(f)
42 }
43 if f := h.decoders.offsets.fse; f != nil && !f.preDefined {
44 fseDecoderPool.Put(f)
45 }
46 if f := h.decoders.matchLengths.fse; f != nil && !f.preDefined {
47 fseDecoderPool.Put(f)
48 }
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053049 h.decoders = sequenceDecs{br: h.decoders.br}
khenaidoo7d3c5582021-08-11 18:09:44 -040050 if h.huffTree != nil {
51 if h.dict == nil || h.dict.litEnc != h.huffTree {
52 huffDecoderPool.Put(h.huffTree)
53 }
54 }
55 h.huffTree = nil
56 h.dict = nil
57 //printf("history created: %+v (l: %d, c: %d)", *h, len(h.b), cap(h.b))
58}
59
60func (h *history) setDict(dict *dict) {
61 if dict == nil {
62 return
63 }
64 h.dict = dict
65 h.decoders.litLengths = dict.llDec
66 h.decoders.offsets = dict.ofDec
67 h.decoders.matchLengths = dict.mlDec
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053068 h.decoders.dict = dict.content
khenaidoo7d3c5582021-08-11 18:09:44 -040069 h.recentOffsets = dict.offsets
70 h.huffTree = dict.litEnc
71}
72
73// append bytes to history.
74// This function will make sure there is space for it,
75// if the buffer has been allocated with enough extra space.
76func (h *history) append(b []byte) {
77 if len(b) >= h.windowSize {
78 // Discard all history by simply overwriting
79 h.b = h.b[:h.windowSize]
80 copy(h.b, b[len(b)-h.windowSize:])
81 return
82 }
83
84 // If there is space, append it.
85 if len(b) < cap(h.b)-len(h.b) {
86 h.b = append(h.b, b...)
87 return
88 }
89
90 // Move data down so we only have window size left.
91 // We know we have less than window size in b at this point.
92 discard := len(b) + len(h.b) - h.windowSize
93 copy(h.b, h.b[discard:])
94 h.b = h.b[:h.windowSize]
95 copy(h.b[h.windowSize-len(b):], b)
96}
97
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053098// ensureBlock will ensure there is space for at least one block...
99func (h *history) ensureBlock() {
100 if cap(h.b) < h.allocFrameBuffer {
101 h.b = make([]byte, 0, h.allocFrameBuffer)
102 return
103 }
104
105 avail := cap(h.b) - len(h.b)
106 if avail >= h.windowSize || avail > maxCompressedBlockSize {
107 return
108 }
109 // Move data down so we only have window size left.
110 // We know we have less than window size in b at this point.
111 discard := len(h.b) - h.windowSize
112 copy(h.b, h.b[discard:])
113 h.b = h.b[:h.windowSize]
114}
115
khenaidoo7d3c5582021-08-11 18:09:44 -0400116// append bytes to history without ever discarding anything.
117func (h *history) appendKeep(b []byte) {
118 h.b = append(h.b, b...)
119}