xref: /minix3/external/public-domain/xz/dist/src/liblzma/common/stream_buffer_decoder.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
15a645f22SBen Gras ///////////////////////////////////////////////////////////////////////////////
25a645f22SBen Gras //
35a645f22SBen Gras /// \file       stream_buffer_decoder.c
45a645f22SBen Gras /// \brief      Single-call .xz Stream decoder
55a645f22SBen Gras //
65a645f22SBen Gras //  Author:     Lasse Collin
75a645f22SBen Gras //
85a645f22SBen Gras //  This file has been put into the public domain.
95a645f22SBen Gras //  You can do whatever you want with this file.
105a645f22SBen Gras //
115a645f22SBen Gras ///////////////////////////////////////////////////////////////////////////////
125a645f22SBen Gras 
135a645f22SBen Gras #include "stream_decoder.h"
145a645f22SBen Gras 
155a645f22SBen Gras 
165a645f22SBen Gras extern LZMA_API(lzma_ret)
lzma_stream_buffer_decode(uint64_t * memlimit,uint32_t flags,const lzma_allocator * allocator,const uint8_t * in,size_t * in_pos,size_t in_size,uint8_t * out,size_t * out_pos,size_t out_size)175a645f22SBen Gras lzma_stream_buffer_decode(uint64_t *memlimit, uint32_t flags,
18*0a6a1f1dSLionel Sambuc 		const lzma_allocator *allocator,
195a645f22SBen Gras 		const uint8_t *in, size_t *in_pos, size_t in_size,
205a645f22SBen Gras 		uint8_t *out, size_t *out_pos, size_t out_size)
215a645f22SBen Gras {
225a645f22SBen Gras 	// Sanity checks
235a645f22SBen Gras 	if (in_pos == NULL || (in == NULL && *in_pos != in_size)
245a645f22SBen Gras 			|| *in_pos > in_size || out_pos == NULL
255a645f22SBen Gras 			|| (out == NULL && *out_pos != out_size)
265a645f22SBen Gras 			|| *out_pos > out_size)
275a645f22SBen Gras 		return LZMA_PROG_ERROR;
285a645f22SBen Gras 
295a645f22SBen Gras 	// Catch flags that are not allowed in buffer-to-buffer decoding.
305a645f22SBen Gras 	if (flags & LZMA_TELL_ANY_CHECK)
315a645f22SBen Gras 		return LZMA_PROG_ERROR;
325a645f22SBen Gras 
335a645f22SBen Gras 	// Initialize the Stream decoder.
345a645f22SBen Gras 	// TODO: We need something to tell the decoder that it can use the
355a645f22SBen Gras 	// output buffer as workspace, and thus save significant amount of RAM.
365a645f22SBen Gras 	lzma_next_coder stream_decoder = LZMA_NEXT_CODER_INIT;
375a645f22SBen Gras 	lzma_ret ret = lzma_stream_decoder_init(
385a645f22SBen Gras 			&stream_decoder, allocator, *memlimit, flags);
395a645f22SBen Gras 
405a645f22SBen Gras 	if (ret == LZMA_OK) {
415a645f22SBen Gras 		// Save the positions so that we can restore them in case
425a645f22SBen Gras 		// an error occurs.
435a645f22SBen Gras 		const size_t in_start = *in_pos;
445a645f22SBen Gras 		const size_t out_start = *out_pos;
455a645f22SBen Gras 
465a645f22SBen Gras 		// Do the actual decoding.
475a645f22SBen Gras 		ret = stream_decoder.code(stream_decoder.coder, allocator,
485a645f22SBen Gras 				in, in_pos, in_size, out, out_pos, out_size,
495a645f22SBen Gras 				LZMA_FINISH);
505a645f22SBen Gras 
515a645f22SBen Gras 		if (ret == LZMA_STREAM_END) {
525a645f22SBen Gras 			ret = LZMA_OK;
535a645f22SBen Gras 		} else {
545a645f22SBen Gras 			// Something went wrong, restore the positions.
555a645f22SBen Gras 			*in_pos = in_start;
565a645f22SBen Gras 			*out_pos = out_start;
575a645f22SBen Gras 
585a645f22SBen Gras 			if (ret == LZMA_OK) {
595a645f22SBen Gras 				// Either the input was truncated or the
605a645f22SBen Gras 				// output buffer was too small.
615a645f22SBen Gras 				assert(*in_pos == in_size
625a645f22SBen Gras 						|| *out_pos == out_size);
635a645f22SBen Gras 
645a645f22SBen Gras 				// If all the input was consumed, then the
655a645f22SBen Gras 				// input is truncated, even if the output
665a645f22SBen Gras 				// buffer is also full. This is because
675a645f22SBen Gras 				// processing the last byte of the Stream
685a645f22SBen Gras 				// never produces output.
695a645f22SBen Gras 				if (*in_pos == in_size)
705a645f22SBen Gras 					ret = LZMA_DATA_ERROR;
715a645f22SBen Gras 				else
725a645f22SBen Gras 					ret = LZMA_BUF_ERROR;
735a645f22SBen Gras 
745a645f22SBen Gras 			} else if (ret == LZMA_MEMLIMIT_ERROR) {
755a645f22SBen Gras 				// Let the caller know how much memory would
765a645f22SBen Gras 				// have been needed.
775a645f22SBen Gras 				uint64_t memusage;
785a645f22SBen Gras 				(void)stream_decoder.memconfig(
795a645f22SBen Gras 						stream_decoder.coder,
805a645f22SBen Gras 						memlimit, &memusage, 0);
815a645f22SBen Gras 			}
825a645f22SBen Gras 		}
835a645f22SBen Gras 	}
845a645f22SBen Gras 
855a645f22SBen Gras 	// Free the decoder memory. This needs to be done even if
865a645f22SBen Gras 	// initialization fails, because the internal API doesn't
875a645f22SBen Gras 	// require the initialization function to free its memory on error.
885a645f22SBen Gras 	lzma_next_end(&stream_decoder, allocator);
895a645f22SBen Gras 
905a645f22SBen Gras 	return ret;
915a645f22SBen Gras }
92