/*
 * Copyright 2026 CodingMarkus
 *
 * SPDX-License-Identifier: AGPL-3.0-or-later OR Apache-2.0
 */

#pragma once

#include <stddef.h>
#include <stdint.h>

#ifndef SQUINCH_RESULT_DEFINED
#define SQUINCH_RESULT_DEFINED

/**
	Reports the result of a compression or decompression operation.
*/
enum SquinchResult {
	/** Operation completed successfully. */
	Success_SquinchResult,

	/** The input buffer was NULL with a nonzero input size. */
	InputBufferIsNULL_SquinchResult,

	/** The output buffer was NULL with a nonzero output size. */
	OutputBufferIsNULL_SquinchResult,

	/** The out-bytes-written pointer was NULL. */
	OutBytesWrittenIsNULL_SquinchResult,

	/** The input bytes consumed pointer was NULL. */
	InputBytesConsumedIsNULL_SquinchResult,

	/** The out output bytes written pointer was NULL. */
	OutputBytesWrittenIsNULL_SquinchResult,

	/** A header-value output pointer was NULL. */
	OutHeaderValueIsNULL_SquinchResult,

	/** The window size was outside its accepted range. */
	WindowSizeOutOfRange_SquinchResult,

	/** The match limit was outside its accepted range. */
	MatchLimitOutOfRange_SquinchResult,

	/** The compressor pointer was NULL. */
	CompressorIsNULL_SquinchResult,

	/** The decompressor pointer was NULL. */
	DecompressorIsNULL_SquinchResult,

	/** The maximum window size was outside its accepted range. */
	MaximumWindowSizeOutOfRange_SquinchResult,

	/** The compressed input was malformed. */
	InvalidInput_SquinchResult,

	/** Memory allocation failed or a size was not representable. */
	OutOfMemory_SquinchResult,

	/** The stream requires more history than the decoder reserved. */
	WindowTooSmall_SquinchResult,

	/** Input was supplied after the end of data. */
	InputAfterEndOfData_SquinchResult,

	/** Output was requested after the end of data was fully drained. */
	NoMoreOutputAvailable_SquinchResult,

	/** The complete stream header has not been parsed yet. */
	HeaderNotFullyParsed_SquinchResult,

	/** The look-ahead size was zero. */
	LookAheadSizeOutOfRange_SquinchResult,
};

#endif


struct SquinchDecompressor;


/**
	Decompresses one complete input buffer into an output buffer.

	The stream header supplies the history window size, which must be in the
	range 16 through 65536 bytes.

	@param[in] input The complete compressed stream. This may be NULL only
		when inputSize is zero. The input and output buffers must not overlap.
	@param[in] inputSize The number of input bytes in the range 0 through
		SIZE_MAX. A valid stream contains at least 16 bytes.
	@param[out] output The destination buffer. This may be NULL only when
		outputSize is zero.
	@param[in] outputSize The destination capacity in bytes in the range 0
		through SIZE_MAX.
	@param[out] outBytesWritten Receives the number of bytes written, including
		when the output buffer is full or malformed input is found. This
		pointer must not be NULL.

	@returns
		- Success_SquinchResult: On success.
		- A parameter-specific invalid-argument result.
		- InvalidInput_SquinchResult: For a malformed stream.
		- OutOfMemory_SquinchResult: When allocation fails.
*/
enum SquinchResult SquinchDecompress(
	const void * input,
	size_t inputSize,
	void * output,
	size_t outputSize,
	size_t * outBytesWritten
);


/**
	Creates a streaming decompressor with an optional maximum window size.

	A nonzero maxWindowSize allocates the history buffer during this call.
	Decoding then performs no allocations. If the stream header declares a
	larger window, input returns WindowTooSmall_SquinchResult.

	A zero maxWindowSize defers the storage allocation until input has parsed
	the complete stream header. It then allocates one block containing the
	declared window size.

	@param[out] outDecompressor Receives the new decompressor on success. This
		pointer must not be NULL and is not modified on failure.
	@param[in] maxWindowSize The maximum accepted stream window in bytes.
		Zero defers allocation. A nonzero value must be in the range 16 through
		65536.

	@returns
		- Success_SquinchResult: On success.
		- A parameter-specific invalid-argument result.
		- OutOfMemory_SquinchResult: When setup allocation fails.
*/
enum SquinchResult SquinchDecompressorCreate(
	struct SquinchDecompressor ** outDecompressor,
	size_t maxWindowSize
);


/**
	Consumes input and writes decompressed output in one call.

	The function may consume no input while producing output from a pending
	copy or RLE operation. It retains up to five bytes for an incomplete
	instruction when the input ends. A zero inputSize finishes and validates the
	stream. After finishing, call this function with zero input until it writes
	no more output. No input may be supplied after the stream has been finished.

	@param[in,out] decompressor The decompressor to update. It must not be
		NULL, finished, or in a failed state.
	@param[in] input The compressed bytes to consume. This may be NULL only
		when inputSize is zero.
	@param[in] inputSize The number of input bytes in the range 0 through
		SIZE_MAX. Zero finishes the stream.
	@param[out] output The destination buffer. This may be NULL only when
		outputSize is zero.
	@param[in] outputSize The destination capacity in bytes.
	@param[out] outInputBytesConsumed Receives the number of input bytes
		consumed in the range 0 through inputSize.
	@param[out] outOutputBytesWritten Receives the number of output bytes
		written in the range 0 through outputSize.

	@returns
		- Success_SquinchResult: When all supplied input was consumed. Output
		  may remain pending and is returned by later calls.
		- InvalidInput_SquinchResult: For a malformed or incomplete stream.
		- WindowTooSmall_SquinchResult: When the stream window exceeds a
			nonzero setup maximum.
		- OutOfMemory_SquinchResult: When deferred allocation fails.
		- A parameter-specific invalid-argument result.
		- InputAfterEndOfData_SquinchResult: For input after end of data.
		- NoMoreOutputAvailable_SquinchResult: For output after it was drained.
*/
enum SquinchResult SquinchDecompressorStep(
	struct SquinchDecompressor * decompressor,
	const void * input,
	size_t inputSize,
	void * output,
	size_t outputSize,
	size_t * outInputBytesConsumed,
	size_t * outOutputBytesWritten
);


/**
	Returns the total uncompressed size from the complete stream header.

	@param[in] decompressor The decompressor to inspect. It must not be NULL.
	@param[out] outUncompressedSize Receives the header value. This pointer must
		not be NULL. Zero means that the size is unknown.

	@returns
		- Success_SquinchResult: On success.
		- HeaderNotFullyParsed_SquinchResult: Before the full header is parsed.
*/
enum SquinchResult SquinchDecompressorGetUncompressedSize(
	const struct SquinchDecompressor * decompressor,
	uint_least64_t * outUncompressedSize
);


/**
	Returns the window size from the complete stream header.
*/
enum SquinchResult SquinchDecompressorGetWindowSize(
	const struct SquinchDecompressor * decompressor,
	size_t * outWindowSize
);


/**
	Returns the format version from the complete stream header.
*/
enum SquinchResult SquinchDecompressorGetVersion(
	const struct SquinchDecompressor * decompressor,
	unsigned char * outVersion
);


/**
	Destroys a streaming decompressor and releases its memory.

	@param decompressor The decompressor to destroy, or NULL. A non-NULL
		pointer is invalid after this call.
*/
void SquinchDecompressorDestroy( struct SquinchDecompressor * decompressor );
