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.
13
"github.com/klauspost/compress/zstd/internal/xxhash"
22
// Frame history passed between blocks
27
// Byte buffer that can be reused for small input blocks.
30
FrameContentSize uint64
38
// MinWindowSize is the minimum Window Size, which is 1 KB.
39
MinWindowSize = 1 << 10
41
// MaxWindowSize is the maximum encoder window size
42
// and the default decoder maximum window size.
43
MaxWindowSize = 1 << 29
47
frameMagic = []byte{0x28, 0xb5, 0x2f, 0xfd}
48
skippableFrameMagic = []byte{0x2a, 0x4d, 0x18}
51
func newFrameDec(o decoderOptions) *frameDec {
52
if o.maxWindowSize > o.maxDecodedSize {
53
o.maxWindowSize = o.maxDecodedSize
61
// reset will read the frame header and prepare for block decoding.
62
// If nothing can be read from the input, io.EOF will be returned.
63
// Any other error indicated that the stream contained data, but
64
// there was a problem.
65
func (d *frameDec) reset(br byteBuffer) error {
71
// Check if we can read more...
72
b, err := br.readSmall(1)
74
case io.EOF, io.ErrUnexpectedEOF:
81
// Read the rest, don't allow io.ErrUnexpectedEOF
82
b, err = br.readSmall(3)
89
copy(signature[1:], b)
92
if !bytes.Equal(signature[1:4], skippableFrameMagic) || signature[0]&0xf0 != 0x50 {
94
println("Not skippable", hex.EncodeToString(signature[:]), hex.EncodeToString(skippableFrameMagic))
96
// Break if not skippable frame.
100
b, err = br.readSmall(4)
103
println("Reading Frame Size", err)
107
n := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
108
println("Skipping frame with", n, "bytes.")
109
err = br.skipN(int(n))
112
println("Reading discarded frame", err)
117
if !bytes.Equal(signature[:], frameMagic) {
119
println("Got magic numbers: ", signature, "want:", frameMagic)
121
return ErrMagicMismatch
124
// Read Frame_Header_Descriptor
125
fhd, err := br.readByte()
128
println("Reading Frame_Header_Descriptor", err)
132
d.SingleSegment = fhd&(1<<5) != 0
135
return errors.New("reserved bit set on frame header")
138
// Read Window_Descriptor
139
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor
141
if !d.SingleSegment {
142
wd, err := br.readByte()
145
println("Reading Window_Descriptor", err)
149
printf("raw: %x, mantissa: %d, exponent: %d\n", wd, wd&7, wd>>3)
150
windowLog := 10 + (wd >> 3)
151
windowBase := uint64(1) << windowLog
152
windowAdd := (windowBase / 8) * uint64(wd&0x7)
153
d.WindowSize = windowBase + windowAdd
156
// Read Dictionary_ID
157
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id
159
if size := fhd & 3; size != 0 {
164
b, err := br.readSmall(int(size))
166
println("Reading Dictionary_ID", err)
174
id = uint32(b[0]) | (uint32(b[1]) << 8)
176
id = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
179
println("Dict size", size, "ID:", id)
182
// ID 0 means "sorry, no dictionary anyway".
183
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
188
// Read Frame_Content_Size
189
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_content_size
200
d.FrameContentSize = 0
202
b, err := br.readSmall(fcsSize)
204
println("Reading Frame content", err)
209
d.FrameContentSize = uint64(b[0])
211
// When FCS_Field_Size is 2, the offset of 256 is added.
212
d.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) + 256
214
d.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) | (uint64(b[2]) << 16) | (uint64(b[3]) << 24)
216
d1 := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
217
d2 := uint32(b[4]) | (uint32(b[5]) << 8) | (uint32(b[6]) << 16) | (uint32(b[7]) << 24)
218
d.FrameContentSize = uint64(d1) | (uint64(d2) << 32)
221
println("Read FCS:", d.FrameContentSize)
225
// Move this to shared.
226
d.HasCheckSum = fhd&(1<<2) != 0
234
if d.WindowSize == 0 && d.SingleSegment {
235
// We may not need window in this case.
236
d.WindowSize = d.FrameContentSize
237
if d.WindowSize < MinWindowSize {
238
d.WindowSize = MinWindowSize
242
if d.WindowSize > uint64(d.o.maxWindowSize) {
244
printf("window size %d > max %d\n", d.WindowSize, d.o.maxWindowSize)
246
return ErrWindowSizeExceeded
248
// The minimum Window_Size is 1 KB.
249
if d.WindowSize < MinWindowSize {
251
println("got window size: ", d.WindowSize)
253
return ErrWindowSizeTooSmall
255
d.history.windowSize = int(d.WindowSize)
256
if d.o.lowMem && d.history.windowSize < maxBlockSize {
257
d.history.allocFrameBuffer = d.history.windowSize * 2
258
// TODO: Maybe use FrameContent size
260
d.history.allocFrameBuffer = d.history.windowSize + maxBlockSize
264
println("Frame: Dict:", d.DictionaryID, "FrameContentSize:", d.FrameContentSize, "singleseg:", d.SingleSegment, "window:", d.WindowSize, "crc:", d.HasCheckSum)
267
// history contains input - maybe we do something
272
// next will start decoding the next block from stream.
273
func (d *frameDec) next(block *blockDec) error {
275
println("decoding new block")
277
err := block.reset(d.rawInput, d.WindowSize)
279
println("block error:", err)
280
// Signal the frame decoder we have a problem.
287
// checkCRC will check the checksum if the frame has one.
288
// Will return ErrCRCMismatch if crc check failed, otherwise nil.
289
func (d *frameDec) checkCRC() error {
295
// Flip to match file order.
296
tmp[0] = byte(got >> 0)
297
tmp[1] = byte(got >> 8)
298
tmp[2] = byte(got >> 16)
299
tmp[3] = byte(got >> 24)
301
// We can overwrite upper tmp now
302
want, err := d.rawInput.readSmall(4)
304
println("CRC missing?", err)
308
if !bytes.Equal(tmp[:], want) && !ignoreCRC {
310
println("CRC Check Failed:", tmp[:], "!=", want)
312
return ErrCRCMismatch
315
println("CRC ok", tmp[:])
320
// runDecoder will create a sync decoder that will decode a block of data.
321
func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) {
324
// We use the history for output to avoid copying it.
326
d.history.ignoreBuffer = len(dst)
327
// Store input length, so we only check new data.
331
err = dec.reset(d.rawInput, d.WindowSize)
336
println("next block:", dec)
338
err = dec.decodeBuf(&d.history)
342
if uint64(len(d.history.b)) > d.o.maxDecodedSize {
343
err = ErrDecoderSizeExceeded
346
if d.SingleSegment && uint64(len(d.history.b)) > d.o.maxDecodedSize {
347
println("runDecoder: single segment and", uint64(len(d.history.b)), ">", d.o.maxDecodedSize)
348
err = ErrFrameSizeExceeded
351
if d.FrameContentSize > 0 && uint64(len(d.history.b)-crcStart) > d.FrameContentSize {
352
println("runDecoder: FrameContentSize exceeded", uint64(len(d.history.b)-crcStart), ">", d.FrameContentSize)
353
err = ErrFrameSizeExceeded
359
if debugDecoder && d.FrameContentSize > 0 {
360
println("runDecoder: FrameContentSize", uint64(len(d.history.b)-crcStart), "<=", d.FrameContentSize)
365
if d.FrameContentSize > 0 && uint64(len(d.history.b)-crcStart) != d.FrameContentSize {
366
err = ErrFrameSizeMismatch
367
} else if d.HasCheckSum {
369
n, err = d.crc.Write(dst[crcStart:])
371
if n != len(dst)-crcStart {
372
err = io.ErrShortWrite