// Copyright 2011 The Snappy-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package snappy

import (
	
	
	
)

var (
	// ErrCorrupt reports that the input is invalid.
	ErrCorrupt = errors.New("snappy: corrupt input")
	// ErrTooLarge reports that the uncompressed length is too large.
	ErrTooLarge = errors.New("snappy: decoded block is too large")
	// ErrUnsupported reports that the input isn't supported.
	ErrUnsupported = errors.New("snappy: unsupported input")

	errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
)

// DecodedLen returns the length of the decoded block.
func ( []byte) (int, error) {
	, ,  := decodedLen()
	return , 
}

// decodedLen returns the length of the decoded block and the number of bytes
// that the length header occupied.
func decodedLen( []byte) (,  int,  error) {
	,  := binary.Uvarint()
	if  <= 0 ||  > 0xffffffff {
		return 0, 0, ErrCorrupt
	}

	const  = 32 << (^uint(0) >> 32 & 1)
	if  == 32 &&  > 0x7fffffff {
		return 0, 0, ErrTooLarge
	}
	return int(), , nil
}

const (
	decodeErrCodeCorrupt                  = 1
	decodeErrCodeUnsupportedLiteralLength = 2
)

// Decode returns the decoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire decoded block.
// Otherwise, a newly allocated slice will be returned.
//
// The dst and src must not overlap. It is valid to pass a nil dst.
//
// Decode handles the Snappy block format, not the Snappy stream format.
func (,  []byte) ([]byte, error) {
	, ,  := decodedLen()
	if  != nil {
		return nil, 
	}
	if  <= len() {
		 = [:]
	} else {
		 = make([]byte, )
	}
	switch decode(, [:]) {
	case 0:
		return , nil
	case decodeErrCodeUnsupportedLiteralLength:
		return nil, errUnsupportedLiteralLength
	}
	return nil, ErrCorrupt
}

// NewReader returns a new Reader that decompresses from r, using the framing
// format described at
// https://github.com/google/snappy/blob/master/framing_format.txt
func ( io.Reader) *Reader {
	return &Reader{
		r:       ,
		decoded: make([]byte, maxBlockSize),
		buf:     make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize),
	}
}

// Reader is an io.Reader that can read Snappy-compressed bytes.
//
// Reader handles the Snappy stream format, not the Snappy block format.
type Reader struct {
	r       io.Reader
	err     error
	decoded []byte
	buf     []byte
	// decoded[i:j] contains decoded bytes that have not yet been passed on.
	i, j       int
	readHeader bool
}

// Reset discards any buffered data, resets all state, and switches the Snappy
// reader to read from r. This permits reusing a Reader rather than allocating
// a new one.
func ( *Reader) ( io.Reader) {
	.r = 
	.err = nil
	.i = 0
	.j = 0
	.readHeader = false
}

func ( *Reader) ( []byte,  bool) ( bool) {
	if _, .err = io.ReadFull(.r, ); .err != nil {
		if .err == io.ErrUnexpectedEOF || (.err == io.EOF && !) {
			.err = ErrCorrupt
		}
		return false
	}
	return true
}

func ( *Reader) () error {
	for .i >= .j {
		if !.readFull(.buf[:4], true) {
			return .err
		}
		 := .buf[0]
		if !.readHeader {
			if  != chunkTypeStreamIdentifier {
				.err = ErrCorrupt
				return .err
			}
			.readHeader = true
		}
		 := int(.buf[1]) | int(.buf[2])<<8 | int(.buf[3])<<16
		if  > len(.buf) {
			.err = ErrUnsupported
			return .err
		}

		// The chunk types are specified at
		// https://github.com/google/snappy/blob/master/framing_format.txt
		switch  {
		case chunkTypeCompressedData:
			// Section 4.2. Compressed data (chunk type 0x00).
			if  < checksumSize {
				.err = ErrCorrupt
				return .err
			}
			 := .buf[:]
			if !.readFull(, false) {
				return .err
			}
			 := uint32([0]) | uint32([1])<<8 | uint32([2])<<16 | uint32([3])<<24
			 = [checksumSize:]

			,  := DecodedLen()
			if  != nil {
				.err = 
				return .err
			}
			if  > len(.decoded) {
				.err = ErrCorrupt
				return .err
			}
			if ,  := Decode(.decoded, );  != nil {
				.err = 
				return .err
			}
			if crc(.decoded[:]) !=  {
				.err = ErrCorrupt
				return .err
			}
			.i, .j = 0, 
			continue

		case chunkTypeUncompressedData:
			// Section 4.3. Uncompressed data (chunk type 0x01).
			if  < checksumSize {
				.err = ErrCorrupt
				return .err
			}
			 := .buf[:checksumSize]
			if !.readFull(, false) {
				return .err
			}
			 := uint32([0]) | uint32([1])<<8 | uint32([2])<<16 | uint32([3])<<24
			// Read directly into r.decoded instead of via r.buf.
			 :=  - checksumSize
			if  > len(.decoded) {
				.err = ErrCorrupt
				return .err
			}
			if !.readFull(.decoded[:], false) {
				return .err
			}
			if crc(.decoded[:]) !=  {
				.err = ErrCorrupt
				return .err
			}
			.i, .j = 0, 
			continue

		case chunkTypeStreamIdentifier:
			// Section 4.1. Stream identifier (chunk type 0xff).
			if  != len(magicBody) {
				.err = ErrCorrupt
				return .err
			}
			if !.readFull(.buf[:len(magicBody)], false) {
				return .err
			}
			for  := 0;  < len(magicBody); ++ {
				if .buf[] != magicBody[] {
					.err = ErrCorrupt
					return .err
				}
			}
			continue
		}

		if  <= 0x7f {
			// Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
			.err = ErrUnsupported
			return .err
		}
		// Section 4.4 Padding (chunk type 0xfe).
		// Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
		if !.readFull(.buf[:], false) {
			return .err
		}
	}

	return nil
}

// Read satisfies the io.Reader interface.
func ( *Reader) ( []byte) (int, error) {
	if .err != nil {
		return 0, .err
	}

	if  := .fill();  != nil {
		return 0, 
	}

	 := copy(, .decoded[.i:.j])
	.i += 
	return , nil
}

// ReadByte satisfies the io.ByteReader interface.
func ( *Reader) () (byte, error) {
	if .err != nil {
		return 0, .err
	}

	if  := .fill();  != nil {
		return 0, 
	}

	 := .decoded[.i]
	.i++
	return , nil
}