xref: /dflybsd-src/contrib/xz/src/liblzma/common/auto_decoder.c (revision 46a2189dd86b644c3a76ac281d84b4182fd66b95)
12940b44dSPeter Avalos ///////////////////////////////////////////////////////////////////////////////
22940b44dSPeter Avalos //
32940b44dSPeter Avalos /// \file       auto_decoder.c
42940b44dSPeter Avalos /// \brief      Autodetect between .xz Stream and .lzma (LZMA_Alone) formats
52940b44dSPeter Avalos //
62940b44dSPeter Avalos //  Author:     Lasse Collin
72940b44dSPeter Avalos //
82940b44dSPeter Avalos //  This file has been put into the public domain.
92940b44dSPeter Avalos //  You can do whatever you want with this file.
102940b44dSPeter Avalos //
112940b44dSPeter Avalos ///////////////////////////////////////////////////////////////////////////////
122940b44dSPeter Avalos 
132940b44dSPeter Avalos #include "stream_decoder.h"
142940b44dSPeter Avalos #include "alone_decoder.h"
152940b44dSPeter Avalos 
162940b44dSPeter Avalos 
17*46a2189dSzrj typedef struct {
182940b44dSPeter Avalos 	/// Stream decoder or LZMA_Alone decoder
192940b44dSPeter Avalos 	lzma_next_coder next;
202940b44dSPeter Avalos 
212940b44dSPeter Avalos 	uint64_t memlimit;
222940b44dSPeter Avalos 	uint32_t flags;
232940b44dSPeter Avalos 
242940b44dSPeter Avalos 	enum {
252940b44dSPeter Avalos 		SEQ_INIT,
262940b44dSPeter Avalos 		SEQ_CODE,
272940b44dSPeter Avalos 		SEQ_FINISH,
282940b44dSPeter Avalos 	} sequence;
29*46a2189dSzrj } lzma_auto_coder;
302940b44dSPeter Avalos 
312940b44dSPeter Avalos 
322940b44dSPeter Avalos static lzma_ret
auto_decode(void * coder_ptr,const lzma_allocator * allocator,const uint8_t * restrict in,size_t * restrict in_pos,size_t in_size,uint8_t * restrict out,size_t * restrict out_pos,size_t out_size,lzma_action action)33*46a2189dSzrj auto_decode(void *coder_ptr, const lzma_allocator *allocator,
342940b44dSPeter Avalos 		const uint8_t *restrict in, size_t *restrict in_pos,
352940b44dSPeter Avalos 		size_t in_size, uint8_t *restrict out,
362940b44dSPeter Avalos 		size_t *restrict out_pos, size_t out_size, lzma_action action)
372940b44dSPeter Avalos {
38*46a2189dSzrj 	lzma_auto_coder *coder = coder_ptr;
39*46a2189dSzrj 
402940b44dSPeter Avalos 	switch (coder->sequence) {
412940b44dSPeter Avalos 	case SEQ_INIT:
422940b44dSPeter Avalos 		if (*in_pos >= in_size)
432940b44dSPeter Avalos 			return LZMA_OK;
442940b44dSPeter Avalos 
452940b44dSPeter Avalos 		// Update the sequence now, because we want to continue from
462940b44dSPeter Avalos 		// SEQ_CODE even if we return some LZMA_*_CHECK.
472940b44dSPeter Avalos 		coder->sequence = SEQ_CODE;
482940b44dSPeter Avalos 
492940b44dSPeter Avalos 		// Detect the file format. For now this is simple, since if
502940b44dSPeter Avalos 		// it doesn't start with 0xFD (the first magic byte of the
512940b44dSPeter Avalos 		// new format), it has to be LZMA_Alone, or something that
522940b44dSPeter Avalos 		// we don't support at all.
532940b44dSPeter Avalos 		if (in[*in_pos] == 0xFD) {
542940b44dSPeter Avalos 			return_if_error(lzma_stream_decoder_init(
552940b44dSPeter Avalos 					&coder->next, allocator,
562940b44dSPeter Avalos 					coder->memlimit, coder->flags));
572940b44dSPeter Avalos 		} else {
582940b44dSPeter Avalos 			return_if_error(lzma_alone_decoder_init(&coder->next,
59a530a267SJohn Marino 					allocator, coder->memlimit, true));
602940b44dSPeter Avalos 
612940b44dSPeter Avalos 			// If the application wants to know about missing
622940b44dSPeter Avalos 			// integrity check or about the check in general, we
632940b44dSPeter Avalos 			// need to handle it here, because LZMA_Alone decoder
642940b44dSPeter Avalos 			// doesn't accept any flags.
652940b44dSPeter Avalos 			if (coder->flags & LZMA_TELL_NO_CHECK)
662940b44dSPeter Avalos 				return LZMA_NO_CHECK;
672940b44dSPeter Avalos 
682940b44dSPeter Avalos 			if (coder->flags & LZMA_TELL_ANY_CHECK)
692940b44dSPeter Avalos 				return LZMA_GET_CHECK;
702940b44dSPeter Avalos 		}
712940b44dSPeter Avalos 
722940b44dSPeter Avalos 	// Fall through
732940b44dSPeter Avalos 
742940b44dSPeter Avalos 	case SEQ_CODE: {
752940b44dSPeter Avalos 		const lzma_ret ret = coder->next.code(
762940b44dSPeter Avalos 				coder->next.coder, allocator,
772940b44dSPeter Avalos 				in, in_pos, in_size,
782940b44dSPeter Avalos 				out, out_pos, out_size, action);
792940b44dSPeter Avalos 		if (ret != LZMA_STREAM_END
802940b44dSPeter Avalos 				|| (coder->flags & LZMA_CONCATENATED) == 0)
812940b44dSPeter Avalos 			return ret;
822940b44dSPeter Avalos 
832940b44dSPeter Avalos 		coder->sequence = SEQ_FINISH;
842940b44dSPeter Avalos 	}
852940b44dSPeter Avalos 
862940b44dSPeter Avalos 	// Fall through
872940b44dSPeter Avalos 
882940b44dSPeter Avalos 	case SEQ_FINISH:
892940b44dSPeter Avalos 		// When LZMA_DECODE_CONCATENATED was used and we were decoding
902940b44dSPeter Avalos 		// LZMA_Alone file, we need to check check that there is no
912940b44dSPeter Avalos 		// trailing garbage and wait for LZMA_FINISH.
922940b44dSPeter Avalos 		if (*in_pos < in_size)
932940b44dSPeter Avalos 			return LZMA_DATA_ERROR;
942940b44dSPeter Avalos 
952940b44dSPeter Avalos 		return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK;
962940b44dSPeter Avalos 
972940b44dSPeter Avalos 	default:
982940b44dSPeter Avalos 		assert(0);
992940b44dSPeter Avalos 		return LZMA_PROG_ERROR;
1002940b44dSPeter Avalos 	}
1012940b44dSPeter Avalos }
1022940b44dSPeter Avalos 
1032940b44dSPeter Avalos 
1042940b44dSPeter Avalos static void
auto_decoder_end(void * coder_ptr,const lzma_allocator * allocator)105*46a2189dSzrj auto_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
1062940b44dSPeter Avalos {
107*46a2189dSzrj 	lzma_auto_coder *coder = coder_ptr;
1082940b44dSPeter Avalos 	lzma_next_end(&coder->next, allocator);
1092940b44dSPeter Avalos 	lzma_free(coder, allocator);
1102940b44dSPeter Avalos 	return;
1112940b44dSPeter Avalos }
1122940b44dSPeter Avalos 
1132940b44dSPeter Avalos 
1142940b44dSPeter Avalos static lzma_check
auto_decoder_get_check(const void * coder_ptr)115*46a2189dSzrj auto_decoder_get_check(const void *coder_ptr)
1162940b44dSPeter Avalos {
117*46a2189dSzrj 	const lzma_auto_coder *coder = coder_ptr;
118*46a2189dSzrj 
1192940b44dSPeter Avalos 	// It is LZMA_Alone if get_check is NULL.
1202940b44dSPeter Avalos 	return coder->next.get_check == NULL ? LZMA_CHECK_NONE
1212940b44dSPeter Avalos 			: coder->next.get_check(coder->next.coder);
1222940b44dSPeter Avalos }
1232940b44dSPeter Avalos 
1242940b44dSPeter Avalos 
1252940b44dSPeter Avalos static lzma_ret
auto_decoder_memconfig(void * coder_ptr,uint64_t * memusage,uint64_t * old_memlimit,uint64_t new_memlimit)126*46a2189dSzrj auto_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
1272940b44dSPeter Avalos 		uint64_t *old_memlimit, uint64_t new_memlimit)
1282940b44dSPeter Avalos {
129*46a2189dSzrj 	lzma_auto_coder *coder = coder_ptr;
130*46a2189dSzrj 
1312940b44dSPeter Avalos 	lzma_ret ret;
1322940b44dSPeter Avalos 
1332940b44dSPeter Avalos 	if (coder->next.memconfig != NULL) {
1342940b44dSPeter Avalos 		ret = coder->next.memconfig(coder->next.coder,
1352940b44dSPeter Avalos 				memusage, old_memlimit, new_memlimit);
1362940b44dSPeter Avalos 		assert(*old_memlimit == coder->memlimit);
1372940b44dSPeter Avalos 	} else {
1382940b44dSPeter Avalos 		// No coder is configured yet. Use the base value as
1392940b44dSPeter Avalos 		// the current memory usage.
1402940b44dSPeter Avalos 		*memusage = LZMA_MEMUSAGE_BASE;
1412940b44dSPeter Avalos 		*old_memlimit = coder->memlimit;
142*46a2189dSzrj 
1432940b44dSPeter Avalos 		ret = LZMA_OK;
144*46a2189dSzrj 		if (new_memlimit != 0 && new_memlimit < *memusage)
145*46a2189dSzrj 			ret = LZMA_MEMLIMIT_ERROR;
1462940b44dSPeter Avalos 	}
1472940b44dSPeter Avalos 
1482940b44dSPeter Avalos 	if (ret == LZMA_OK && new_memlimit != 0)
1492940b44dSPeter Avalos 		coder->memlimit = new_memlimit;
1502940b44dSPeter Avalos 
1512940b44dSPeter Avalos 	return ret;
1522940b44dSPeter Avalos }
1532940b44dSPeter Avalos 
1542940b44dSPeter Avalos 
1552940b44dSPeter Avalos static lzma_ret
auto_decoder_init(lzma_next_coder * next,const lzma_allocator * allocator,uint64_t memlimit,uint32_t flags)15615ab8c86SJohn Marino auto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
1572940b44dSPeter Avalos 		uint64_t memlimit, uint32_t flags)
1582940b44dSPeter Avalos {
1592940b44dSPeter Avalos 	lzma_next_coder_init(&auto_decoder_init, next, allocator);
1602940b44dSPeter Avalos 
1612940b44dSPeter Avalos 	if (flags & ~LZMA_SUPPORTED_FLAGS)
1622940b44dSPeter Avalos 		return LZMA_OPTIONS_ERROR;
1632940b44dSPeter Avalos 
164*46a2189dSzrj 	lzma_auto_coder *coder = next->coder;
165*46a2189dSzrj 	if (coder == NULL) {
166*46a2189dSzrj 		coder = lzma_alloc(sizeof(lzma_auto_coder), allocator);
167*46a2189dSzrj 		if (coder == NULL)
1682940b44dSPeter Avalos 			return LZMA_MEM_ERROR;
1692940b44dSPeter Avalos 
170*46a2189dSzrj 		next->coder = coder;
1712940b44dSPeter Avalos 		next->code = &auto_decode;
1722940b44dSPeter Avalos 		next->end = &auto_decoder_end;
1732940b44dSPeter Avalos 		next->get_check = &auto_decoder_get_check;
1742940b44dSPeter Avalos 		next->memconfig = &auto_decoder_memconfig;
175*46a2189dSzrj 		coder->next = LZMA_NEXT_CODER_INIT;
1762940b44dSPeter Avalos 	}
1772940b44dSPeter Avalos 
178*46a2189dSzrj 	coder->memlimit = my_max(1, memlimit);
179*46a2189dSzrj 	coder->flags = flags;
180*46a2189dSzrj 	coder->sequence = SEQ_INIT;
1812940b44dSPeter Avalos 
1822940b44dSPeter Avalos 	return LZMA_OK;
1832940b44dSPeter Avalos }
1842940b44dSPeter Avalos 
1852940b44dSPeter Avalos 
1862940b44dSPeter Avalos extern LZMA_API(lzma_ret)
lzma_auto_decoder(lzma_stream * strm,uint64_t memlimit,uint32_t flags)1872940b44dSPeter Avalos lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
1882940b44dSPeter Avalos {
1892940b44dSPeter Avalos 	lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags);
1902940b44dSPeter Avalos 
1912940b44dSPeter Avalos 	strm->internal->supported_actions[LZMA_RUN] = true;
1922940b44dSPeter Avalos 	strm->internal->supported_actions[LZMA_FINISH] = true;
1932940b44dSPeter Avalos 
1942940b44dSPeter Avalos 	return LZMA_OK;
1952940b44dSPeter Avalos }
196