blob: c3452bc3a9e2028cc507fd8c12b525a134bf501b [file] [log] [blame]
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +05301//go:build !amd64 || appengine || !gc || noasm
2// +build !amd64 appengine !gc noasm
3
4package zstd
5
6import (
7 "fmt"
8 "io"
9)
10
11// decode sequences from the stream with the provided history but without dictionary.
12func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
13 return false, nil
14}
15
16// decode sequences from the stream without the provided history.
17func (s *sequenceDecs) decode(seqs []seqVals) error {
18 br := s.br
19
20 // Grab full sizes tables, to avoid bounds checks.
21 llTable, mlTable, ofTable := s.litLengths.fse.dt[:maxTablesize], s.matchLengths.fse.dt[:maxTablesize], s.offsets.fse.dt[:maxTablesize]
22 llState, mlState, ofState := s.litLengths.state.state, s.matchLengths.state.state, s.offsets.state.state
23 s.seqSize = 0
24 litRemain := len(s.literals)
25
26 maxBlockSize := maxCompressedBlockSize
27 if s.windowSize < maxBlockSize {
28 maxBlockSize = s.windowSize
29 }
30 for i := range seqs {
31 var ll, mo, ml int
32 if br.off > 4+((maxOffsetBits+16+16)>>3) {
33 // inlined function:
34 // ll, mo, ml = s.nextFast(br, llState, mlState, ofState)
35
36 // Final will not read from stream.
37 var llB, mlB, moB uint8
38 ll, llB = llState.final()
39 ml, mlB = mlState.final()
40 mo, moB = ofState.final()
41
42 // extra bits are stored in reverse order.
43 br.fillFast()
44 mo += br.getBits(moB)
45 if s.maxBits > 32 {
46 br.fillFast()
47 }
48 ml += br.getBits(mlB)
49 ll += br.getBits(llB)
50
51 if moB > 1 {
52 s.prevOffset[2] = s.prevOffset[1]
53 s.prevOffset[1] = s.prevOffset[0]
54 s.prevOffset[0] = mo
55 } else {
56 // mo = s.adjustOffset(mo, ll, moB)
57 // Inlined for rather big speedup
58 if ll == 0 {
59 // There is an exception though, when current sequence's literals_length = 0.
60 // In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2,
61 // an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte.
62 mo++
63 }
64
65 if mo == 0 {
66 mo = s.prevOffset[0]
67 } else {
68 var temp int
69 if mo == 3 {
70 temp = s.prevOffset[0] - 1
71 } else {
72 temp = s.prevOffset[mo]
73 }
74
75 if temp == 0 {
76 // 0 is not valid; input is corrupted; force offset to 1
77 println("WARNING: temp was 0")
78 temp = 1
79 }
80
81 if mo != 1 {
82 s.prevOffset[2] = s.prevOffset[1]
83 }
84 s.prevOffset[1] = s.prevOffset[0]
85 s.prevOffset[0] = temp
86 mo = temp
87 }
88 }
89 br.fillFast()
90 } else {
91 if br.overread() {
92 if debugDecoder {
93 printf("reading sequence %d, exceeded available data\n", i)
94 }
95 return io.ErrUnexpectedEOF
96 }
97 ll, mo, ml = s.next(br, llState, mlState, ofState)
98 br.fill()
99 }
100
101 if debugSequences {
102 println("Seq", i, "Litlen:", ll, "mo:", mo, "(abs) ml:", ml)
103 }
104 // Evaluate.
105 // We might be doing this async, so do it early.
106 if mo == 0 && ml > 0 {
107 return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml)
108 }
109 if ml > maxMatchLen {
110 return fmt.Errorf("match len (%d) bigger than max allowed length", ml)
111 }
112 s.seqSize += ll + ml
113 if s.seqSize > maxBlockSize {
114 return fmt.Errorf("output (%d) bigger than max block size (%d)", s.seqSize, maxBlockSize)
115 }
116 litRemain -= ll
117 if litRemain < 0 {
118 return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, litRemain+ll)
119 }
120 seqs[i] = seqVals{
121 ll: ll,
122 ml: ml,
123 mo: mo,
124 }
125 if i == len(seqs)-1 {
126 // This is the last sequence, so we shouldn't update state.
127 break
128 }
129
130 // Manually inlined, ~ 5-20% faster
131 // Update all 3 states at once. Approx 20% faster.
132 nBits := llState.nbBits() + mlState.nbBits() + ofState.nbBits()
133 if nBits == 0 {
134 llState = llTable[llState.newState()&maxTableMask]
135 mlState = mlTable[mlState.newState()&maxTableMask]
136 ofState = ofTable[ofState.newState()&maxTableMask]
137 } else {
138 bits := br.get32BitsFast(nBits)
139 lowBits := uint16(bits >> ((ofState.nbBits() + mlState.nbBits()) & 31))
140 llState = llTable[(llState.newState()+lowBits)&maxTableMask]
141
142 lowBits = uint16(bits >> (ofState.nbBits() & 31))
143 lowBits &= bitMask[mlState.nbBits()&15]
144 mlState = mlTable[(mlState.newState()+lowBits)&maxTableMask]
145
146 lowBits = uint16(bits) & bitMask[ofState.nbBits()&15]
147 ofState = ofTable[(ofState.newState()+lowBits)&maxTableMask]
148 }
149 }
150 s.seqSize += litRemain
151 if s.seqSize > maxBlockSize {
152 return fmt.Errorf("output (%d) bigger than max block size (%d)", s.seqSize, maxBlockSize)
153 }
154 err := br.close()
155 if err != nil {
156 printf("Closing sequences: %v, %+v\n", err, *br)
157 }
158 return err
159}
160
161// executeSimple handles cases when a dictionary is not used.
162func (s *sequenceDecs) executeSimple(seqs []seqVals, hist []byte) error {
163 // Ensure we have enough output size...
164 if len(s.out)+s.seqSize > cap(s.out) {
165 addBytes := s.seqSize + len(s.out)
166 s.out = append(s.out, make([]byte, addBytes)...)
167 s.out = s.out[:len(s.out)-addBytes]
168 }
169
170 if debugDecoder {
171 printf("Execute %d seqs with literals: %d into %d bytes\n", len(seqs), len(s.literals), s.seqSize)
172 }
173
174 var t = len(s.out)
175 out := s.out[:t+s.seqSize]
176
177 for _, seq := range seqs {
178 // Add literals
179 copy(out[t:], s.literals[:seq.ll])
180 t += seq.ll
181 s.literals = s.literals[seq.ll:]
182
183 // Malformed input
184 if seq.mo > t+len(hist) || seq.mo > s.windowSize {
185 return fmt.Errorf("match offset (%d) bigger than current history (%d)", seq.mo, t+len(hist))
186 }
187
188 // Copy from history.
189 if v := seq.mo - t; v > 0 {
190 // v is the start position in history from end.
191 start := len(hist) - v
192 if seq.ml > v {
193 // Some goes into the current block.
194 // Copy remainder of history
195 copy(out[t:], hist[start:])
196 t += v
197 seq.ml -= v
198 } else {
199 copy(out[t:], hist[start:start+seq.ml])
200 t += seq.ml
201 continue
202 }
203 }
204
205 // We must be in the current buffer now
206 if seq.ml > 0 {
207 start := t - seq.mo
208 if seq.ml <= t-start {
209 // No overlap
210 copy(out[t:], out[start:start+seq.ml])
211 t += seq.ml
212 } else {
213 // Overlapping copy
214 // Extend destination slice and copy one byte at the time.
215 src := out[start : start+seq.ml]
216 dst := out[t:]
217 dst = dst[:len(src)]
218 t += len(src)
219 // Destination is the space we just added.
220 for i := range src {
221 dst[i] = src[i]
222 }
223 }
224 }
225 }
226 // Add final literals
227 copy(out[t:], s.literals)
228 if debugDecoder {
229 t += len(s.literals)
230 if t != len(out) {
231 panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(out), t, s.seqSize))
232 }
233 }
234 s.out = out
235
236 return nil
237}