// Copyright 2019+ Klaus Post. All rights reserved.
// License information can be found in the LICENSE file.
// Based on work by Yann Collet, released under BSD License.

package zstd

import (
	
	
	
	

	
)

// Decoder provides decoding of zstandard streams.
// The decoder has been designed to operate without allocations after a warmup.
// This means that you should store the decoder for best performance.
// To re-use a stream decoder, use the Reset(r io.Reader) error to switch to another stream.
// A decoder can safely be re-used even if the previous stream failed.
// To release the resources, you must call the Close() function on a decoder.
type Decoder struct {
	o decoderOptions

	// Unreferenced decoders, ready for use.
	decoders chan *blockDec

	// Current read position used for Reader functionality.
	current decoderState

	// sync stream decoding
	syncStream struct {
		decodedFrame uint64
		br           readerWrapper
		enabled      bool
		inFrame      bool
		dstBuf       []byte
	}

	frame *frameDec

	// Custom dictionaries.
	dicts map[uint32]*dict

	// streamWg is the waitgroup for all streams
	streamWg sync.WaitGroup
}

// decoderState is used for maintaining state when the decoder
// is used for streaming.
type decoderState struct {
	// current block being written to stream.
	decodeOutput

	// output in order to be written to stream.
	output chan decodeOutput

	// cancel remaining output.
	cancel context.CancelFunc

	// crc of current frame
	crc *xxhash.Digest

	flushed bool
}

var (
	// Check the interfaces we want to support.
	_ = io.WriterTo(&Decoder{})
	_ = io.Reader(&Decoder{})
)

// NewReader creates a new decoder.
// A nil Reader can be provided in which case Reset can be used to start a decode.
//
// A Decoder can be used in two modes:
//
// 1) As a stream, or
// 2) For stateless decoding using DecodeAll.
//
// Only a single stream can be decoded concurrently, but the same decoder
// can run multiple concurrent stateless decodes. It is even possible to
// use stateless decodes while a stream is being decoded.
//
// The Reset function can be used to initiate a new stream, which will considerably
// reduce the allocations normally caused by NewReader.
func ( io.Reader,  ...DOption) (*Decoder, error) {
	initPredefined()
	var  Decoder
	.o.setDefault()
	for ,  := range  {
		 := (&.o)
		if  != nil {
			return nil, 
		}
	}
	.current.crc = xxhash.New()
	.current.flushed = true

	if  == nil {
		.current.err = ErrDecoderNilInput
	}

	// Transfer option dicts.
	.dicts = make(map[uint32]*dict, len(.o.dicts))
	for ,  := range .o.dicts {
		.dicts[.id] = 
	}
	.o.dicts = nil

	// Create decoders
	.decoders = make(chan *blockDec, .o.concurrent)
	for  := 0;  < .o.concurrent; ++ {
		 := newBlockDec(.o.lowMem)
		.localFrame = newFrameDec(.o)
		.decoders <- 
	}

	if  == nil {
		return &, nil
	}
	return &, .Reset()
}

// Read bytes from the decompressed stream into p.
// Returns the number of bytes read and any error that occurred.
// When the stream is done, io.EOF will be returned.
func ( *Decoder) ( []byte) (int, error) {
	var  int
	for {
		if len(.current.b) > 0 {
			 := copy(, .current.b)
			 = [:]
			.current.b = .current.b[:]
			 += 
		}
		if len() == 0 {
			break
		}
		if len(.current.b) == 0 {
			// We have an error and no more data
			if .current.err != nil {
				break
			}
			if !.nextBlock( == 0) {
				return , .current.err
			}
		}
	}
	if len(.current.b) > 0 {
		if debugDecoder {
			println("returning", , "still bytes left:", len(.current.b))
		}
		// Only return error at end of block
		return , nil
	}
	if .current.err != nil {
		.drainOutput()
	}
	if debugDecoder {
		println("returning", , .current.err, len(.decoders))
	}
	return , .current.err
}

// Reset will reset the decoder the supplied stream after the current has finished processing.
// Note that this functionality cannot be used after Close has been called.
// Reset can be called with a nil reader to release references to the previous reader.
// After being called with a nil reader, no other operations than Reset or DecodeAll or Close
// should be used.
func ( *Decoder) ( io.Reader) error {
	if .current.err == ErrDecoderClosed {
		return .current.err
	}

	.drainOutput()

	.syncStream.br.r = nil
	if  == nil {
		.current.err = ErrDecoderNilInput
		if len(.current.b) > 0 {
			.current.b = .current.b[:0]
		}
		.current.flushed = true
		return nil
	}

	// If bytes buffer and < 5MB, do sync decoding anyway.
	if ,  := .(byter);  && .Len() < .o.decodeBufsBelow && !.o.limitToCap {
		 := 
		if debugDecoder {
			println("*bytes.Buffer detected, doing sync decode, len:", .Len())
		}
		 := .Bytes()
		var  []byte
		if cap(.syncStream.dstBuf) > 0 {
			 = .syncStream.dstBuf[:0]
		}

		,  := .DecodeAll(, )
		if  == nil {
			 = io.EOF
		}
		// Save output buffer
		.syncStream.dstBuf = 
		.current.b = 
		.current.err = 
		.current.flushed = true
		if debugDecoder {
			println("sync decode to", len(), "bytes, err:", )
		}
		return nil
	}
	// Remove current block.
	.stashDecoder()
	.current.decodeOutput = decodeOutput{}
	.current.err = nil
	.current.flushed = false
	.current.d = nil
	.syncStream.dstBuf = nil

	// Ensure no-one else is still running...
	.streamWg.Wait()
	if .frame == nil {
		.frame = newFrameDec(.o)
	}

	if .o.concurrent == 1 {
		return .startSyncDecoder()
	}

	.current.output = make(chan decodeOutput, .o.concurrent)
	,  := context.WithCancel(context.Background())
	.current.cancel = 
	.streamWg.Add(1)
	go .startStreamDecoder(, , .current.output)

	return nil
}

// drainOutput will drain the output until errEndOfStream is sent.
func ( *Decoder) () {
	if .current.cancel != nil {
		if debugDecoder {
			println("cancelling current")
		}
		.current.cancel()
		.current.cancel = nil
	}
	if .current.d != nil {
		if debugDecoder {
			printf("re-adding current decoder %p, decoders: %d", .current.d, len(.decoders))
		}
		.decoders <- .current.d
		.current.d = nil
		.current.b = nil
	}
	if .current.output == nil || .current.flushed {
		println("current already flushed")
		return
	}
	for  := range .current.output {
		if .d != nil {
			if debugDecoder {
				printf("re-adding decoder %p", .d)
			}
			.decoders <- .d
		}
	}
	.current.output = nil
	.current.flushed = true
}

// WriteTo writes data to w until there's no more data to write or when an error occurs.
// The return value n is the number of bytes written.
// Any error encountered during the write is also returned.
func ( *Decoder) ( io.Writer) (int64, error) {
	var  int64
	for {
		if len(.current.b) > 0 {
			,  := .Write(.current.b)
			 += int64()
			if  != nil && (.current.err == nil || .current.err == io.EOF) {
				.current.err = 
			} else if  != len(.current.b) {
				.current.err = io.ErrShortWrite
			}
		}
		if .current.err != nil {
			break
		}
		.nextBlock(true)
	}
	 := .current.err
	if  != nil {
		.drainOutput()
	}
	if  == io.EOF {
		 = nil
	}
	return , 
}

// DecodeAll allows stateless decoding of a blob of bytes.
// Output will be appended to dst, so if the destination size is known
// you can pre-allocate the destination slice to avoid allocations.
// DecodeAll can be used concurrently.
// The Decoder concurrency limits will be respected.
func ( *Decoder) (,  []byte) ([]byte, error) {
	if .decoders == nil {
		return , ErrDecoderClosed
	}

	// Grab a block decoder and frame decoder.
	 := <-.decoders
	 := .localFrame
	 := len()
	defer func() {
		if debugDecoder {
			printf("re-adding decoder: %p", )
		}
		.rawInput = nil
		.bBuf = nil
		if .history.decoders.br != nil {
			.history.decoders.br.in = nil
			.history.decoders.br.cursor = 0
		}
		.decoders <- 
	}()
	.bBuf = 

	for {
		.history.reset()
		 := .reset(&.bBuf)
		if  != nil {
			if  == io.EOF {
				if debugDecoder {
					println("frame reset return EOF")
				}
				return , nil
			}
			return , 
		}
		if  = .setDict();  != nil {
			return nil, 
		}
		if .WindowSize > .o.maxWindowSize {
			if debugDecoder {
				println("window size exceeded:", .WindowSize, ">", .o.maxWindowSize)
			}
			return , ErrWindowSizeExceeded
		}
		if .FrameContentSize != fcsUnknown {
			if .FrameContentSize > .o.maxDecodedSize-uint64(len()-) {
				if debugDecoder {
					println("decoder size exceeded; fcs:", .FrameContentSize, "> mcs:", .o.maxDecodedSize-uint64(len()-), "len:", len())
				}
				return , ErrDecoderSizeExceeded
			}
			if .o.limitToCap && .FrameContentSize > uint64(cap()-len()) {
				if debugDecoder {
					println("decoder size exceeded; fcs:", .FrameContentSize, "> (cap-len)", cap()-len())
				}
				return , ErrDecoderSizeExceeded
			}
			if cap()-len() < int(.FrameContentSize) {
				 := make([]byte, len(), len()+int(.FrameContentSize)+compressedBlockOverAlloc)
				copy(, )
				 = 
			}
		}

		if cap() == 0 && !.o.limitToCap {
			// Allocate len(input) * 2 by default if nothing is provided
			// and we didn't get frame content size.
			 := len() * 2
			// Cap to 1 MB.
			if  > 1<<20 {
				 = 1 << 20
			}
			if uint64() > .o.maxDecodedSize {
				 = int(.o.maxDecodedSize)
			}
			 = make([]byte, 0, )
		}

		,  = .runDecoder(, )
		if  != nil {
			return , 
		}
		if uint64(len()-) > .o.maxDecodedSize {
			return , ErrDecoderSizeExceeded
		}
		if len(.bBuf) == 0 {
			if debugDecoder {
				println("frame dbuf empty")
			}
			break
		}
	}
	return , nil
}

// nextBlock returns the next block.
// If an error occurs d.err will be set.
// Optionally the function can block for new output.
// If non-blocking mode is used the returned boolean will be false
// if no data was available without blocking.
func ( *Decoder) ( bool) ( bool) {
	if .current.err != nil {
		// Keep error state.
		return false
	}
	.current.b = .current.b[:0]

	// SYNC:
	if .syncStream.enabled {
		if ! {
			return false
		}
		 = .nextBlockSync()
		if ! {
			.stashDecoder()
		}
		return 
	}

	//ASYNC:
	.stashDecoder()
	if  {
		.current.decodeOutput,  = <-.current.output
	} else {
		select {
		case .current.decodeOutput,  = <-.current.output:
		default:
			return false
		}
	}
	if ! {
		// This should not happen, so signal error state...
		.current.err = io.ErrUnexpectedEOF
		return false
	}
	 := .current.decodeOutput
	if .d != nil && .d.async.newHist != nil {
		.current.crc.Reset()
	}
	if debugDecoder {
		var  [4]byte
		binary.LittleEndian.PutUint32([:], uint32(xxhash.Sum64(.b)))
		println("got", len(.current.b), "bytes, error:", .current.err, "data crc:", )
	}

	if .o.ignoreChecksum {
		return true
	}

	if len(.b) > 0 {
		.current.crc.Write(.b)
	}
	if .err == nil && .d != nil && .d.hasCRC {
		 := uint32(.current.crc.Sum64())
		if  != .d.checkCRC {
			if debugDecoder {
				printf("CRC Check Failed: %08x (got) != %08x (on stream)\n", , .d.checkCRC)
			}
			.current.err = ErrCRCMismatch
		} else {
			if debugDecoder {
				printf("CRC ok %08x\n", )
			}
		}
	}

	return true
}

func ( *Decoder) () ( bool) {
	if .current.d == nil {
		.current.d = <-.decoders
	}
	for len(.current.b) == 0 {
		if !.syncStream.inFrame {
			.frame.history.reset()
			.current.err = .frame.reset(&.syncStream.br)
			if .current.err == nil {
				.current.err = .setDict(.frame)
			}
			if .current.err != nil {
				return false
			}
			if .frame.WindowSize > .o.maxDecodedSize || .frame.WindowSize > .o.maxWindowSize {
				.current.err = ErrDecoderSizeExceeded
				return false
			}

			.syncStream.decodedFrame = 0
			.syncStream.inFrame = true
		}
		.current.err = .frame.next(.current.d)
		if .current.err != nil {
			return false
		}
		.frame.history.ensureBlock()
		if debugDecoder {
			println("History trimmed:", len(.frame.history.b), "decoded already:", .syncStream.decodedFrame)
		}
		 := len(.frame.history.b)
		.current.err = .current.d.decodeBuf(&.frame.history)

		if .current.err != nil {
			println("error after:", .current.err)
			return false
		}
		.current.b = .frame.history.b[:]
		if debugDecoder {
			println("history after:", len(.frame.history.b))
		}

		// Check frame size (before CRC)
		.syncStream.decodedFrame += uint64(len(.current.b))
		if .syncStream.decodedFrame > .frame.FrameContentSize {
			if debugDecoder {
				printf("DecodedFrame (%d) > FrameContentSize (%d)\n", .syncStream.decodedFrame, .frame.FrameContentSize)
			}
			.current.err = ErrFrameSizeExceeded
			return false
		}

		// Check FCS
		if .current.d.Last && .frame.FrameContentSize != fcsUnknown && .syncStream.decodedFrame != .frame.FrameContentSize {
			if debugDecoder {
				printf("DecodedFrame (%d) != FrameContentSize (%d)\n", .syncStream.decodedFrame, .frame.FrameContentSize)
			}
			.current.err = ErrFrameSizeMismatch
			return false
		}

		// Update/Check CRC
		if .frame.HasCheckSum {
			if !.o.ignoreChecksum {
				.frame.crc.Write(.current.b)
			}
			if .current.d.Last {
				if !.o.ignoreChecksum {
					.current.err = .frame.checkCRC()
				} else {
					.current.err = .frame.consumeCRC()
				}
				if .current.err != nil {
					println("CRC error:", .current.err)
					return false
				}
			}
		}
		.syncStream.inFrame = !.current.d.Last
	}
	return true
}

func ( *Decoder) () {
	if .current.d != nil {
		if debugDecoder {
			printf("re-adding current decoder %p", .current.d)
		}
		.decoders <- .current.d
		.current.d = nil
	}
}

// Close will release all resources.
// It is NOT possible to reuse the decoder after this.
func ( *Decoder) () {
	if .current.err == ErrDecoderClosed {
		return
	}
	.drainOutput()
	if .current.cancel != nil {
		.current.cancel()
		.streamWg.Wait()
		.current.cancel = nil
	}
	if .decoders != nil {
		close(.decoders)
		for  := range .decoders {
			.Close()
		}
		.decoders = nil
	}
	if .current.d != nil {
		.current.d.Close()
		.current.d = nil
	}
	.current.err = ErrDecoderClosed
}

// IOReadCloser returns the decoder as an io.ReadCloser for convenience.
// Any changes to the decoder will be reflected, so the returned ReadCloser
// can be reused along with the decoder.
// io.WriterTo is also supported by the returned ReadCloser.
func ( *Decoder) () io.ReadCloser {
	return closeWrapper{d: }
}

// closeWrapper wraps a function call as a closer.
type closeWrapper struct {
	d *Decoder
}

// WriteTo forwards WriteTo calls to the decoder.
func ( closeWrapper) ( io.Writer) ( int64,  error) {
	return .d.WriteTo()
}

// Read forwards read calls to the decoder.
func ( closeWrapper) ( []byte) ( int,  error) {
	return .d.Read()
}

// Close closes the decoder.
func ( closeWrapper) () error {
	.d.Close()
	return nil
}

type decodeOutput struct {
	d   *blockDec
	b   []byte
	err error
}

func ( *Decoder) ( io.Reader) error {
	.frame.history.reset()
	.syncStream.br = readerWrapper{r: }
	.syncStream.inFrame = false
	.syncStream.enabled = true
	.syncStream.decodedFrame = 0
	return nil
}

// Create Decoder:
// ASYNC:
// Spawn 3 go routines.
// 0: Read frames and decode block literals.
// 1: Decode sequences.
// 2: Execute sequences, send to output.
func ( *Decoder) ( context.Context,  io.Reader,  chan decodeOutput) {
	defer .streamWg.Done()
	 := readerWrapper{r: }

	var  = make(chan *blockDec, .o.concurrent)
	var  = make(chan *blockDec, .o.concurrent)

	// Async 1: Decode sequences...
	go func() {
		var  history
		var  bool

		for  := range  {
			if  {
				if  != nil {
					 <- 
				}
				continue
			}
			if .async.newHist != nil {
				if debugDecoder {
					println("Async 1: new history, recent:", .async.newHist.recentOffsets)
				}
				.reset()
				.decoders = .async.newHist.decoders
				.recentOffsets = .async.newHist.recentOffsets
				.windowSize = .async.newHist.windowSize
				if .async.newHist.dict != nil {
					.setDict(.async.newHist.dict)
				}
			}
			if .err != nil || .Type != blockTypeCompressed {
				 = .err != nil
				 <- 
				continue
			}

			.decoders.literals = .async.literals
			.err = .prepareSequences(.async.seqData, &)
			if debugDecoder && .err != nil {
				println("prepareSequences returned:", .err)
			}
			 = .err != nil
			if .err == nil {
				.err = .decodeSequences(&)
				if debugDecoder && .err != nil {
					println("decodeSequences returned:", .err)
				}
				 = .err != nil
				//				block.async.sequence = hist.decoders.seq[:hist.decoders.nSeqs]
				.async.seqSize = .decoders.seqSize
			}
			 <- 
		}
		close()
		.reset()
	}()

	var  sync.WaitGroup
	.Add(1)

	// Async 3: Execute sequences...
	 := .frame.history.b
	go func() {
		var  history
		var  uint64
		var  uint64
		var  bool
		for  := range  {
			 := decodeOutput{err: .err, d: }
			if .err != nil ||  {
				 = true
				 <- 
				continue
			}
			if .async.newHist != nil {
				if debugDecoder {
					println("Async 2: new history")
				}
				.reset()
				.windowSize = .async.newHist.windowSize
				.allocFrameBuffer = .async.newHist.allocFrameBuffer
				if .async.newHist.dict != nil {
					.setDict(.async.newHist.dict)
				}

				if cap(.b) < .allocFrameBuffer {
					if cap() >= .allocFrameBuffer {
						.b = 
					} else {
						.b = make([]byte, 0, .allocFrameBuffer)
						println("Alloc history sized", .allocFrameBuffer)
					}
				}
				.b = .b[:0]
				 = .async.fcs
				 = 0
			}
			 := decodeOutput{err: .err, d: }
			switch .Type {
			case blockTypeRLE:
				if debugDecoder {
					println("add rle block length:", .RLESize)
				}

				if cap(.dst) < int(.RLESize) {
					if .lowMem {
						.dst = make([]byte, .RLESize)
					} else {
						.dst = make([]byte, maxCompressedBlockSize)
					}
				}
				.dst = .dst[:.RLESize]
				 := .data[0]
				for  := range .dst {
					.dst[] = 
				}
				.append(.dst)
				.b = .dst
			case blockTypeRaw:
				if debugDecoder {
					println("add raw block length:", len(.data))
				}
				.append(.data)
				.b = .data
			case blockTypeCompressed:
				if debugDecoder {
					println("execute with history length:", len(.b), "window:", .windowSize)
				}
				.decoders.seqSize = .async.seqSize
				.decoders.literals = .async.literals
				.err = .executeSequences(&)
				 = .err != nil
				if debugDecoder &&  {
					println("executeSequences returned:", .err)
				}
				.b = .dst
			}
			if ! {
				 += uint64(len(.b))
				if  >  {
					println("fcs exceeded", .Last, , )
					.err = ErrFrameSizeExceeded
					 = true
				} else if .Last &&  != fcsUnknown &&  !=  {
					.err = ErrFrameSizeMismatch
					 = true
				} else {
					if debugDecoder {
						println("fcs ok", .Last, , )
					}
				}
			}
			 <- 
		}
		close()
		 = .b
		.Done()
		if debugDecoder {
			println("decoder goroutines finished")
		}
		.reset()
	}()

	var  history
:
	for {
		var  bool
		.reset()
		 := func( *blockDec) {
			if  {
				if  != nil {
					 <- 
				}
				return
			}
			if .err != nil || .Type != blockTypeCompressed {
				 = .err != nil
				 <- 
				return
			}

			,  := .decodeLiterals(.data, &)
			.err = 
			 = .err != nil
			if  == nil {
				.async.literals = .decoders.literals
				.async.seqData = 
			} else if debugDecoder {
				println("decodeLiterals error:", )
			}
			 <- 
		}
		 := .frame
		if debugDecoder {
			println("New frame...")
		}
		var  bool
		.history.reset()
		 := .reset(&)
		if debugDecoder &&  != nil {
			println("Frame decoder returned", )
		}
		if  == nil {
			 = .setDict()
		}
		if  == nil && .frame.WindowSize > .o.maxWindowSize {
			if debugDecoder {
				println("decoder size exceeded, fws:", .frame.WindowSize, "> mws:", .o.maxWindowSize)
			}

			 = ErrDecoderSizeExceeded
		}
		if  != nil {
			select {
			case <-.Done():
			case  := <-.decoders:
				.sendErr()
				()
			}
			break 
		}

		// Go through all blocks of the frame.
		for {
			var  *blockDec
			select {
			case <-.Done():
				break 
			case  = <-.decoders:
				// Once we have a decoder, we MUST return it.
			}
			 := .next()
			if ! {
				 := .history
				if debugDecoder {
					println("Alloc History:", .allocFrameBuffer)
				}
				.reset()
				if .dict != nil {
					.setDict(.dict)
				}
				.async.newHist = &
				.async.fcs = .FrameContentSize
				 = true
			} else {
				.async.newHist = nil
			}
			if debugDecoder &&  != nil {
				println("next block returned error:", )
			}
			.err = 
			.hasCRC = false
			if .Last && .HasCheckSum &&  == nil {
				,  := .rawInput.readSmall(4)
				if len() < 4 {
					if  == nil {
						 = io.ErrUnexpectedEOF

					}
					println("CRC missing?", )
					.err = 
				} else {
					.checkCRC = binary.LittleEndian.Uint32()
					.hasCRC = true
					if debugDecoder {
						printf("found crc to check: %08x\n", .checkCRC)
					}
				}
			}
			 = .err
			 := .Last
			()
			if  != nil {
				break 
			}
			if  {
				break
			}
		}
	}
	close()
	.Wait()
	.reset()
	.frame.history.b = 
}

func ( *Decoder) ( *frameDec) ( error) {
	,  := .dicts[.DictionaryID]
	if  {
		if debugDecoder {
			println("setting dict", .DictionaryID)
		}
		.history.setDict()
	} else if .DictionaryID != 0 {
		// A zero or missing dictionary id is ambiguous:
		// either dictionary zero, or no dictionary. In particular,
		// zstd --patch-from uses this id for the source file,
		// so only return an error if the dictionary id is not zero.
		 = ErrUnknownDictionary
	}
	return 
}