// Copyright 2023 The 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 zstd

import (
	
)

// debug can be set in the source to print debug info using println.
const debug = false

// compressedBlock decompresses a compressed block, storing the decompressed
// data in r.buffer. The blockSize argument is the compressed size.
// RFC 3.1.1.3.
func ( *Reader) ( int) error {
	if len(.compressedBuf) >=  {
		.compressedBuf = .compressedBuf[:]
	} else {
		// We know that blockSize <= 128K,
		// so this won't allocate an enormous amount.
		 :=  - len(.compressedBuf)
		.compressedBuf = append(.compressedBuf, make([]byte, )...)
	}

	if ,  := io.ReadFull(.r, .compressedBuf);  != nil {
		return .wrapNonEOFError(0, )
	}

	 := block(.compressedBuf)
	 := 0
	.buffer = .buffer[:0]

	, ,  := .readLiterals(, , .literals[:0])
	if  != nil {
		return 
	}
	.literals = 

	 = 

	, ,  := .initSeqs(, )
	if  != nil {
		return 
	}

	if  == 0 {
		// No sequences, just literals.
		if  < len() {
			return .makeError(, "extraneous data after no sequences")
		}

		.buffer = append(.buffer, ...)

		return nil
	}

	return .execSeqs(, , , )
}

// seqCode is the kind of sequence codes we have to handle.
type seqCode int

const (
	seqLiteral seqCode = iota
	seqOffset
	seqMatch
)

// seqCodeInfoData is the information needed to set up seqTables and
// seqTableBits for a particular kind of sequence code.
type seqCodeInfoData struct {
	predefTable     []fseBaselineEntry // predefined FSE
	predefTableBits int                // number of bits in predefTable
	maxSym          int                // max symbol value in FSE
	maxBits         int                // max bits for FSE

	// toBaseline converts from an FSE table to an FSE baseline table.
	toBaseline func(*Reader, int, []fseEntry, []fseBaselineEntry) error
}

// seqCodeInfo is the seqCodeInfoData for each kind of sequence code.
var seqCodeInfo = [3]seqCodeInfoData{
	seqLiteral: {
		predefTable:     predefinedLiteralTable[:],
		predefTableBits: 6,
		maxSym:          35,
		maxBits:         9,
		toBaseline:      (*Reader).makeLiteralBaselineFSE,
	},
	seqOffset: {
		predefTable:     predefinedOffsetTable[:],
		predefTableBits: 5,
		maxSym:          31,
		maxBits:         8,
		toBaseline:      (*Reader).makeOffsetBaselineFSE,
	},
	seqMatch: {
		predefTable:     predefinedMatchTable[:],
		predefTableBits: 6,
		maxSym:          52,
		maxBits:         9,
		toBaseline:      (*Reader).makeMatchBaselineFSE,
	},
}

// initSeqs reads the Sequences_Section_Header and sets up the FSE
// tables used to read the sequence codes. It returns the number of
// sequences and the new offset. RFC 3.1.1.3.2.1.
func ( *Reader) ( block,  int) (int, int, error) {
	if  >= len() {
		return 0, 0, .makeEOFError()
	}

	 := []
	++
	if  == 0 {
		return 0, , nil
	}

	var  int
	if  < 128 {
		 = int()
	} else if  < 255 {
		if  >= len() {
			return 0, 0, .makeEOFError()
		}
		 = ((int() - 128) << 8) + int([])
		++
	} else {
		if +1 >= len() {
			return 0, 0, .makeEOFError()
		}
		 = int([]) + (int([+1]) << 8) + 0x7f00
		 += 2
	}

	// Read the Symbol_Compression_Modes byte.

	if  >= len() {
		return 0, 0, .makeEOFError()
	}
	 := []
	if &3 != 0 {
		return 0, 0, .makeError(, "invalid symbol compression mode")
	}
	++

	// Set up the FSE tables used to decode the sequence codes.

	var  error
	,  = .setSeqTable(, , seqLiteral, (>>6)&3)
	if  != nil {
		return 0, 0, 
	}

	,  = .setSeqTable(, , seqOffset, (>>4)&3)
	if  != nil {
		return 0, 0, 
	}

	,  = .setSeqTable(, , seqMatch, (>>2)&3)
	if  != nil {
		return 0, 0, 
	}

	return , , nil
}

// setSeqTable uses the Compression_Mode in mode to set up r.seqTables and
// r.seqTableBits for kind. We store these in the Reader because one of
// the modes simply reuses the value from the last block in the frame.
func ( *Reader) ( block,  int,  seqCode,  byte) (int, error) {
	 := &seqCodeInfo[]
	switch  {
	case 0:
		// Predefined_Mode
		.seqTables[] = .predefTable
		.seqTableBits[] = uint8(.predefTableBits)
		return , nil

	case 1:
		// RLE_Mode
		if  >= len() {
			return 0, .makeEOFError()
		}
		 := []
		++

		// Build a simple baseline table that always returns rle.

		 := []fseEntry{
			{
				sym:  ,
				bits: 0,
				base: 0,
			},
		}
		if cap(.seqTableBuffers[]) == 0 {
			.seqTableBuffers[] = make([]fseBaselineEntry, 1<<.maxBits)
		}
		.seqTableBuffers[] = .seqTableBuffers[][:1]
		if  := .toBaseline(, , , .seqTableBuffers[]);  != nil {
			return 0, 
		}

		.seqTables[] = .seqTableBuffers[]
		.seqTableBits[] = 0
		return , nil

	case 2:
		// FSE_Compressed_Mode
		if cap(.fseScratch) < 1<<.maxBits {
			.fseScratch = make([]fseEntry, 1<<.maxBits)
		}
		.fseScratch = .fseScratch[:1<<.maxBits]

		, ,  := .readFSE(, , .maxSym, .maxBits, .fseScratch)
		if  != nil {
			return 0, 
		}
		.fseScratch = .fseScratch[:1<<]

		if cap(.seqTableBuffers[]) == 0 {
			.seqTableBuffers[] = make([]fseBaselineEntry, 1<<.maxBits)
		}
		.seqTableBuffers[] = .seqTableBuffers[][:1<<]

		if  := .toBaseline(, , .fseScratch, .seqTableBuffers[]);  != nil {
			return 0, 
		}

		.seqTables[] = .seqTableBuffers[]
		.seqTableBits[] = uint8()
		return , nil

	case 3:
		// Repeat_Mode
		if len(.seqTables[]) == 0 {
			return 0, .makeError(, "missing repeat sequence FSE table")
		}
		return , nil
	}
	panic("unreachable")
}

// execSeqs reads and executes the sequences. RFC 3.1.1.3.2.1.2.
func ( *Reader) ( block,  int,  []byte,  int) error {
	// Set up the initial states for the sequence code readers.

	,  := .makeReverseBitReader(, len()-1, )
	if  != nil {
		return 
	}

	,  := .val(.seqTableBits[seqLiteral])
	if  != nil {
		return 
	}

	,  := .val(.seqTableBits[seqOffset])
	if  != nil {
		return 
	}

	,  := .val(.seqTableBits[seqMatch])
	if  != nil {
		return 
	}

	// Read and perform all the sequences. RFC 3.1.1.4.

	 := 0
	for  <  {
		if len(.buffer)+len() > 128<<10 {
			return .makeError("uncompressed size too big")
		}

		 := &.seqTables[seqOffset][]
		 := &.seqTables[seqMatch][]
		 := &.seqTables[seqLiteral][]

		,  := .val(.basebits)
		if  != nil {
			return 
		}
		 := .baseline + 

		,  = .val(.basebits)
		if  != nil {
			return 
		}
		 := .baseline + 

		,  = .val(.basebits)
		if  != nil {
			return 
		}
		 := .baseline + 

		// Handle repeat offsets. RFC 3.1.1.5.
		// See the comment in makeOffsetBaselineFSE.
		if .basebits > 1 {
			.repeatedOffset3 = .repeatedOffset2
			.repeatedOffset2 = .repeatedOffset1
			.repeatedOffset1 = 
		} else {
			if  == 0 {
				++
			}
			switch  {
			case 1:
				 = .repeatedOffset1
			case 2:
				 = .repeatedOffset2
				.repeatedOffset2 = .repeatedOffset1
				.repeatedOffset1 = 
			case 3:
				 = .repeatedOffset3
				.repeatedOffset3 = .repeatedOffset2
				.repeatedOffset2 = .repeatedOffset1
				.repeatedOffset1 = 
			case 4:
				 = .repeatedOffset1 - 1
				.repeatedOffset3 = .repeatedOffset2
				.repeatedOffset2 = .repeatedOffset1
				.repeatedOffset1 = 
			}
		}

		++
		if  <  {
			// Update the states.
			,  = .val(.bits)
			if  != nil {
				return 
			}
			 = uint32(.base) + 

			,  = .val(.bits)
			if  != nil {
				return 
			}
			 = uint32(.base) + 

			,  = .val(.bits)
			if  != nil {
				return 
			}
			 = uint32(.base) + 
		}

		// The next sequence is now in literal, offset, match.

		if debug {
			println("literal", , "offset", , "match", )
		}

		// Copy literal bytes from litbuf.
		if  > uint32(len()) {
			return .makeError("literal byte overflow")
		}
		if  > 0 {
			.buffer = append(.buffer, [:]...)
			 = [:]
		}

		if  > 0 {
			if  := .copyFromWindow(&, , );  != nil {
				return 
			}
		}
	}

	.buffer = append(.buffer, ...)

	if .cnt != 0 {
		return .makeError(, "extraneous data after sequences")
	}

	return nil
}

// Copy match bytes from the decoded output, or the window, at offset.
func ( *Reader) ( *reverseBitReader, ,  uint32) error {
	if  == 0 {
		return .makeError("invalid zero offset")
	}

	// Offset may point into the buffer or the window and
	// match may extend past the end of the initial buffer.
	// |--r.window--|--r.buffer--|
	//        |<-----offset------|
	//        |------match----------->|
	 := uint32(0)
	 := uint32(len(.buffer))
	if  <  {
		 := .window.len()
		 :=  - 
		if  >  {
			return .makeError("offset past window")
		}
		 :=  - 
		if  >  {
			 = 
		}
		.buffer = .window.appendTo(.buffer, , +)
		 -= 
	} else {
		 =  - 
	}

	// We are being asked to copy data that we are adding to the
	// buffer in the same copy.
	for  > 0 {
		 := uint32(len(.buffer)) - 
		if  >  {
			 = 
		}
		.buffer = append(.buffer, .buffer[:+]...)
		 -= 
	}
	return nil
}