13
"github.com/klauspost/compress/huff0"
14
snappy "github.com/klauspost/compress/internal/snapref"
18
snappyTagLiteral = 0x00
25
snappyChecksumSize = 4
26
snappyMagicBody = "sNaPpY"
36
snappyMaxBlockSize = 65536
42
snappyMaxEncodedLenOfMaxBlockSize = 76490
46
chunkTypeCompressedData = 0x00
47
chunkTypeUncompressedData = 0x01
48
chunkTypePadding = 0xfe
49
chunkTypeStreamIdentifier = 0xff
54
ErrSnappyCorrupt = errors.New("snappy: corrupt input")
56
ErrSnappyTooLarge = errors.New("snappy: decoded block is too large")
58
ErrSnappyUnsupported = errors.New("snappy: unsupported input")
60
errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
72
type SnappyConverter struct {
82
func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
90
r.block.initNewEncode()
91
if len(r.buf) != snappyMaxEncodedLenOfMaxBlockSize+snappyChecksumSize {
92
r.buf = make([]byte, snappyMaxEncodedLenOfMaxBlockSize+snappyChecksumSize)
94
r.block.litEnc.Reuse = huff0.ReusePolicyNone
100
header, r.err = frameHeader{WindowSize: snappyMaxBlockSize}.appendTo(r.buf[:0])
102
n, r.err = w.Write(header)
104
return written, r.err
110
if !r.readFull(r.buf[:4], true) {
114
err := r.block.encodeLits(r.block.literals, false)
118
n, err := w.Write(r.block.output)
124
return written, r.err
126
chunkType := r.buf[0]
128
if chunkType != chunkTypeStreamIdentifier {
129
println("chunkType != chunkTypeStreamIdentifier", chunkType)
130
r.err = ErrSnappyCorrupt
131
return written, r.err
135
chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
136
if chunkLen > len(r.buf) {
137
println("chunkLen > len(r.buf)", chunkType)
138
r.err = ErrSnappyUnsupported
139
return written, r.err
145
case chunkTypeCompressedData:
147
if chunkLen < snappyChecksumSize {
148
println("chunkLen < snappyChecksumSize", chunkLen, snappyChecksumSize)
149
r.err = ErrSnappyCorrupt
150
return written, r.err
152
buf := r.buf[:chunkLen]
153
if !r.readFull(buf, false) {
154
return written, r.err
157
buf = buf[snappyChecksumSize:]
159
n, hdr, err := snappyDecodedLen(buf)
162
return written, r.err
165
if n > snappyMaxBlockSize {
166
println("n > snappyMaxBlockSize", n, snappyMaxBlockSize)
167
r.err = ErrSnappyCorrupt
168
return written, r.err
171
r.block.pushOffsets()
172
if err := decodeSnappy(r.block, buf); err != nil {
174
return written, r.err
176
if r.block.size+r.block.extraLits != n {
177
printf("invalid size, want %d, got %d\n", n, r.block.size+r.block.extraLits)
178
r.err = ErrSnappyCorrupt
179
return written, r.err
181
err = r.block.encode(nil, false, false)
183
case errIncompressible:
186
r.block.literals, err = snappy.Decode(r.block.literals[:n], r.buf[snappyChecksumSize:chunkLen])
190
err = r.block.encodeLits(r.block.literals, false)
199
n, r.err = w.Write(r.block.output)
205
case chunkTypeUncompressedData:
207
println("Uncompressed, chunklen", chunkLen)
210
if chunkLen < snappyChecksumSize {
211
println("chunkLen < snappyChecksumSize", chunkLen, snappyChecksumSize)
212
r.err = ErrSnappyCorrupt
213
return written, r.err
216
buf := r.buf[:snappyChecksumSize]
217
if !r.readFull(buf, false) {
218
return written, r.err
220
checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
222
n := chunkLen - snappyChecksumSize
223
if n > snappyMaxBlockSize {
224
println("n > snappyMaxBlockSize", n, snappyMaxBlockSize)
225
r.err = ErrSnappyCorrupt
226
return written, r.err
228
r.block.literals = r.block.literals[:n]
229
if !r.readFull(r.block.literals, false) {
230
return written, r.err
232
if snappyCRC(r.block.literals) != checksum {
233
println("literals crc mismatch")
234
r.err = ErrSnappyCorrupt
235
return written, r.err
237
err := r.block.encodeLits(r.block.literals, false)
241
n, r.err = w.Write(r.block.output)
248
case chunkTypeStreamIdentifier:
250
println("stream id", chunkLen, len(snappyMagicBody))
253
if chunkLen != len(snappyMagicBody) {
254
println("chunkLen != len(snappyMagicBody)", chunkLen, len(snappyMagicBody))
255
r.err = ErrSnappyCorrupt
256
return written, r.err
258
if !r.readFull(r.buf[:len(snappyMagicBody)], false) {
259
return written, r.err
261
for i := 0; i < len(snappyMagicBody); i++ {
262
if r.buf[i] != snappyMagicBody[i] {
263
println("r.buf[i] != snappyMagicBody[i]", r.buf[i], snappyMagicBody[i], i)
264
r.err = ErrSnappyCorrupt
265
return written, r.err
271
if chunkType <= 0x7f {
273
println("chunkType <= 0x7f")
274
r.err = ErrSnappyUnsupported
275
return written, r.err
279
if !r.readFull(r.buf[:chunkLen], false) {
280
return written, r.err
287
func decodeSnappy(blk *blockEnc, src []byte) error {
290
lits := blk.extraLits
293
switch src[s] & 0x03 {
294
case snappyTagLiteral:
295
x := uint32(src[s] >> 2)
301
if uint(s) > uint(len(src)) {
302
println("uint(s) > uint(len(src)", s, src)
303
return ErrSnappyCorrupt
308
if uint(s) > uint(len(src)) {
309
println("uint(s) > uint(len(src)", s, src)
310
return ErrSnappyCorrupt
312
x = uint32(src[s-2]) | uint32(src[s-1])<<8
315
if uint(s) > uint(len(src)) {
316
println("uint(s) > uint(len(src)", s, src)
317
return ErrSnappyCorrupt
319
x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
322
if uint(s) > uint(len(src)) {
323
println("uint(s) > uint(len(src)", s, src)
324
return ErrSnappyCorrupt
326
x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
328
if x > snappyMaxBlockSize {
329
println("x > snappyMaxBlockSize", x, snappyMaxBlockSize)
330
return ErrSnappyCorrupt
334
println("length <= 0 ", length)
336
return errUnsupportedLiteralLength
342
blk.literals = append(blk.literals, src[s:s+length]...)
350
if uint(s) > uint(len(src)) {
351
println("uint(s) > uint(len(src)", s, len(src))
352
return ErrSnappyCorrupt
354
length = 4 + int(src[s-2])>>2&0x7
355
offset = uint32(src[s-2])&0xe0<<3 | uint32(src[s-1])
359
if uint(s) > uint(len(src)) {
360
println("uint(s) > uint(len(src)", s, len(src))
361
return ErrSnappyCorrupt
363
length = 1 + int(src[s-3])>>2
364
offset = uint32(src[s-2]) | uint32(src[s-1])<<8
368
if uint(s) > uint(len(src)) {
369
println("uint(s) > uint(len(src)", s, len(src))
370
return ErrSnappyCorrupt
372
length = 1 + int(src[s-5])>>2
373
offset = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
376
if offset <= 0 || blk.size+lits < int(offset) {
377
println("offset <= 0 || blk.size+lits < int(offset)", offset, blk.size+lits, int(offset), blk.size, lits)
379
return ErrSnappyCorrupt
386
offset = blk.matchOffset(offset, uint32(lits))
391
blk.sequences = append(blk.sequences, seq{
392
litLen: uint32(lits),
394
matchLen: uint32(length) - zstdMinMatch,
396
blk.size += length + lits
403
func (r *SnappyConverter) readFull(p []byte, allowEOF bool) (ok bool) {
404
if _, r.err = io.ReadFull(r.r, p); r.err != nil {
405
if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
406
r.err = ErrSnappyCorrupt
413
var crcTable = crc32.MakeTable(crc32.Castagnoli)
417
func snappyCRC(b []byte) uint32 {
418
c := crc32.Update(0, crcTable, b)
419
return c>>15 | c<<17 + 0xa282ead8
424
func snappyDecodedLen(src []byte) (blockLen, headerLen int, err error) {
425
v, n := binary.Uvarint(src)
426
if n <= 0 || v > 0xffffffff {
427
return 0, 0, ErrSnappyCorrupt
430
const wordSize = 32 << (^uint(0) >> 32 & 1)
431
if wordSize == 32 && v > 0x7fffffff {
432
return 0, 0, ErrSnappyTooLarge
434
return int(v), n, nil