xref: /freebsd/contrib/xz/src/liblzma/common/auto_decoder.c (revision 73ed8e77a79398eb8e7b600a0b67f286e9e5cd53)
181ad8388SMartin Matuska ///////////////////////////////////////////////////////////////////////////////
281ad8388SMartin Matuska //
381ad8388SMartin Matuska /// \file       auto_decoder.c
4*73ed8e77SXin LI /// \brief      Autodetect between .xz, .lzma (LZMA_Alone), and .lz (lzip)
581ad8388SMartin Matuska //
681ad8388SMartin Matuska //  Author:     Lasse Collin
781ad8388SMartin Matuska //
881ad8388SMartin Matuska //  This file has been put into the public domain.
981ad8388SMartin Matuska //  You can do whatever you want with this file.
1081ad8388SMartin Matuska //
1181ad8388SMartin Matuska ///////////////////////////////////////////////////////////////////////////////
1281ad8388SMartin Matuska 
1381ad8388SMartin Matuska #include "stream_decoder.h"
1481ad8388SMartin Matuska #include "alone_decoder.h"
15*73ed8e77SXin LI #ifdef HAVE_LZIP_DECODER
16*73ed8e77SXin LI #	include "lzip_decoder.h"
17*73ed8e77SXin LI #endif
1881ad8388SMartin Matuska 
1981ad8388SMartin Matuska 
201456f0f9SXin LI typedef struct {
21*73ed8e77SXin LI 	/// .xz Stream decoder, LZMA_Alone decoder, or lzip decoder
2281ad8388SMartin Matuska 	lzma_next_coder next;
2381ad8388SMartin Matuska 
2481ad8388SMartin Matuska 	uint64_t memlimit;
2581ad8388SMartin Matuska 	uint32_t flags;
2681ad8388SMartin Matuska 
2781ad8388SMartin Matuska 	enum {
2881ad8388SMartin Matuska 		SEQ_INIT,
2981ad8388SMartin Matuska 		SEQ_CODE,
3081ad8388SMartin Matuska 		SEQ_FINISH,
3181ad8388SMartin Matuska 	} sequence;
321456f0f9SXin LI } lzma_auto_coder;
3381ad8388SMartin Matuska 
3481ad8388SMartin Matuska 
3581ad8388SMartin Matuska static lzma_ret
361456f0f9SXin LI auto_decode(void *coder_ptr, const lzma_allocator *allocator,
3781ad8388SMartin Matuska 		const uint8_t *restrict in, size_t *restrict in_pos,
3881ad8388SMartin Matuska 		size_t in_size, uint8_t *restrict out,
3981ad8388SMartin Matuska 		size_t *restrict out_pos, size_t out_size, lzma_action action)
4081ad8388SMartin Matuska {
411456f0f9SXin LI 	lzma_auto_coder *coder = coder_ptr;
421456f0f9SXin LI 
4381ad8388SMartin Matuska 	switch (coder->sequence) {
4481ad8388SMartin Matuska 	case SEQ_INIT:
4581ad8388SMartin Matuska 		if (*in_pos >= in_size)
4681ad8388SMartin Matuska 			return LZMA_OK;
4781ad8388SMartin Matuska 
4881ad8388SMartin Matuska 		// Update the sequence now, because we want to continue from
4981ad8388SMartin Matuska 		// SEQ_CODE even if we return some LZMA_*_CHECK.
5081ad8388SMartin Matuska 		coder->sequence = SEQ_CODE;
5181ad8388SMartin Matuska 
52*73ed8e77SXin LI 		// Detect the file format. .xz files start with 0xFD which
53*73ed8e77SXin LI 		// cannot be the first byte of .lzma (LZMA_Alone) format.
54*73ed8e77SXin LI 		// The .lz format starts with 0x4C which could be the
55*73ed8e77SXin LI 		// first byte of a .lzma file but luckily it would mean
56*73ed8e77SXin LI 		// lc/lp/pb being 4/3/1 which liblzma doesn't support because
57*73ed8e77SXin LI 		// lc + lp > 4. So using just 0x4C to detect .lz is OK here.
5881ad8388SMartin Matuska 		if (in[*in_pos] == 0xFD) {
5981ad8388SMartin Matuska 			return_if_error(lzma_stream_decoder_init(
6081ad8388SMartin Matuska 					&coder->next, allocator,
6181ad8388SMartin Matuska 					coder->memlimit, coder->flags));
62*73ed8e77SXin LI #ifdef HAVE_LZIP_DECODER
63*73ed8e77SXin LI 		} else if (in[*in_pos] == 0x4C) {
64*73ed8e77SXin LI 			return_if_error(lzma_lzip_decoder_init(
65*73ed8e77SXin LI 					&coder->next, allocator,
66*73ed8e77SXin LI 					coder->memlimit, coder->flags));
67*73ed8e77SXin LI #endif
6881ad8388SMartin Matuska 		} else {
6981ad8388SMartin Matuska 			return_if_error(lzma_alone_decoder_init(&coder->next,
7042b10a37SXin LI 					allocator, coder->memlimit, true));
7181ad8388SMartin Matuska 
7281ad8388SMartin Matuska 			// If the application wants to know about missing
7381ad8388SMartin Matuska 			// integrity check or about the check in general, we
7481ad8388SMartin Matuska 			// need to handle it here, because LZMA_Alone decoder
7581ad8388SMartin Matuska 			// doesn't accept any flags.
7681ad8388SMartin Matuska 			if (coder->flags & LZMA_TELL_NO_CHECK)
7781ad8388SMartin Matuska 				return LZMA_NO_CHECK;
7881ad8388SMartin Matuska 
7981ad8388SMartin Matuska 			if (coder->flags & LZMA_TELL_ANY_CHECK)
8081ad8388SMartin Matuska 				return LZMA_GET_CHECK;
8181ad8388SMartin Matuska 		}
8281ad8388SMartin Matuska 
8381ad8388SMartin Matuska 	// Fall through
8481ad8388SMartin Matuska 
8581ad8388SMartin Matuska 	case SEQ_CODE: {
8681ad8388SMartin Matuska 		const lzma_ret ret = coder->next.code(
8781ad8388SMartin Matuska 				coder->next.coder, allocator,
8881ad8388SMartin Matuska 				in, in_pos, in_size,
8981ad8388SMartin Matuska 				out, out_pos, out_size, action);
9081ad8388SMartin Matuska 		if (ret != LZMA_STREAM_END
9181ad8388SMartin Matuska 				|| (coder->flags & LZMA_CONCATENATED) == 0)
9281ad8388SMartin Matuska 			return ret;
9381ad8388SMartin Matuska 
9481ad8388SMartin Matuska 		coder->sequence = SEQ_FINISH;
9581ad8388SMartin Matuska 	}
9681ad8388SMartin Matuska 
9781ad8388SMartin Matuska 	// Fall through
9881ad8388SMartin Matuska 
9981ad8388SMartin Matuska 	case SEQ_FINISH:
1009e6bbe47SXin LI 		// When LZMA_CONCATENATED was used and we were decoding
1019e6bbe47SXin LI 		// a LZMA_Alone file, we need to check that there is no
10281ad8388SMartin Matuska 		// trailing garbage and wait for LZMA_FINISH.
10381ad8388SMartin Matuska 		if (*in_pos < in_size)
10481ad8388SMartin Matuska 			return LZMA_DATA_ERROR;
10581ad8388SMartin Matuska 
10681ad8388SMartin Matuska 		return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK;
10781ad8388SMartin Matuska 
10881ad8388SMartin Matuska 	default:
10981ad8388SMartin Matuska 		assert(0);
11081ad8388SMartin Matuska 		return LZMA_PROG_ERROR;
11181ad8388SMartin Matuska 	}
11281ad8388SMartin Matuska }
11381ad8388SMartin Matuska 
11481ad8388SMartin Matuska 
11581ad8388SMartin Matuska static void
1161456f0f9SXin LI auto_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
11781ad8388SMartin Matuska {
1181456f0f9SXin LI 	lzma_auto_coder *coder = coder_ptr;
11981ad8388SMartin Matuska 	lzma_next_end(&coder->next, allocator);
12081ad8388SMartin Matuska 	lzma_free(coder, allocator);
12181ad8388SMartin Matuska 	return;
12281ad8388SMartin Matuska }
12381ad8388SMartin Matuska 
12481ad8388SMartin Matuska 
12581ad8388SMartin Matuska static lzma_check
1261456f0f9SXin LI auto_decoder_get_check(const void *coder_ptr)
12781ad8388SMartin Matuska {
1281456f0f9SXin LI 	const lzma_auto_coder *coder = coder_ptr;
1291456f0f9SXin LI 
13081ad8388SMartin Matuska 	// It is LZMA_Alone if get_check is NULL.
13181ad8388SMartin Matuska 	return coder->next.get_check == NULL ? LZMA_CHECK_NONE
13281ad8388SMartin Matuska 			: coder->next.get_check(coder->next.coder);
13381ad8388SMartin Matuska }
13481ad8388SMartin Matuska 
13581ad8388SMartin Matuska 
13681ad8388SMartin Matuska static lzma_ret
1371456f0f9SXin LI auto_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
13881ad8388SMartin Matuska 		uint64_t *old_memlimit, uint64_t new_memlimit)
13981ad8388SMartin Matuska {
1401456f0f9SXin LI 	lzma_auto_coder *coder = coder_ptr;
1411456f0f9SXin LI 
14281ad8388SMartin Matuska 	lzma_ret ret;
14381ad8388SMartin Matuska 
14481ad8388SMartin Matuska 	if (coder->next.memconfig != NULL) {
14581ad8388SMartin Matuska 		ret = coder->next.memconfig(coder->next.coder,
14681ad8388SMartin Matuska 				memusage, old_memlimit, new_memlimit);
14781ad8388SMartin Matuska 		assert(*old_memlimit == coder->memlimit);
14881ad8388SMartin Matuska 	} else {
14981ad8388SMartin Matuska 		// No coder is configured yet. Use the base value as
15081ad8388SMartin Matuska 		// the current memory usage.
15181ad8388SMartin Matuska 		*memusage = LZMA_MEMUSAGE_BASE;
15281ad8388SMartin Matuska 		*old_memlimit = coder->memlimit;
153b71a5db3SXin LI 
15481ad8388SMartin Matuska 		ret = LZMA_OK;
155b71a5db3SXin LI 		if (new_memlimit != 0 && new_memlimit < *memusage)
156b71a5db3SXin LI 			ret = LZMA_MEMLIMIT_ERROR;
15781ad8388SMartin Matuska 	}
15881ad8388SMartin Matuska 
15981ad8388SMartin Matuska 	if (ret == LZMA_OK && new_memlimit != 0)
16081ad8388SMartin Matuska 		coder->memlimit = new_memlimit;
16181ad8388SMartin Matuska 
16281ad8388SMartin Matuska 	return ret;
16381ad8388SMartin Matuska }
16481ad8388SMartin Matuska 
16581ad8388SMartin Matuska 
16681ad8388SMartin Matuska static lzma_ret
16753200025SRui Paulo auto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
16881ad8388SMartin Matuska 		uint64_t memlimit, uint32_t flags)
16981ad8388SMartin Matuska {
17081ad8388SMartin Matuska 	lzma_next_coder_init(&auto_decoder_init, next, allocator);
17181ad8388SMartin Matuska 
17281ad8388SMartin Matuska 	if (flags & ~LZMA_SUPPORTED_FLAGS)
17381ad8388SMartin Matuska 		return LZMA_OPTIONS_ERROR;
17481ad8388SMartin Matuska 
1751456f0f9SXin LI 	lzma_auto_coder *coder = next->coder;
1761456f0f9SXin LI 	if (coder == NULL) {
1771456f0f9SXin LI 		coder = lzma_alloc(sizeof(lzma_auto_coder), allocator);
1781456f0f9SXin LI 		if (coder == NULL)
17981ad8388SMartin Matuska 			return LZMA_MEM_ERROR;
18081ad8388SMartin Matuska 
1811456f0f9SXin LI 		next->coder = coder;
18281ad8388SMartin Matuska 		next->code = &auto_decode;
18381ad8388SMartin Matuska 		next->end = &auto_decoder_end;
18481ad8388SMartin Matuska 		next->get_check = &auto_decoder_get_check;
18581ad8388SMartin Matuska 		next->memconfig = &auto_decoder_memconfig;
1861456f0f9SXin LI 		coder->next = LZMA_NEXT_CODER_INIT;
18781ad8388SMartin Matuska 	}
18881ad8388SMartin Matuska 
189b71a5db3SXin LI 	coder->memlimit = my_max(1, memlimit);
1901456f0f9SXin LI 	coder->flags = flags;
1911456f0f9SXin LI 	coder->sequence = SEQ_INIT;
19281ad8388SMartin Matuska 
19381ad8388SMartin Matuska 	return LZMA_OK;
19481ad8388SMartin Matuska }
19581ad8388SMartin Matuska 
19681ad8388SMartin Matuska 
19781ad8388SMartin Matuska extern LZMA_API(lzma_ret)
19881ad8388SMartin Matuska lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
19981ad8388SMartin Matuska {
20081ad8388SMartin Matuska 	lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags);
20181ad8388SMartin Matuska 
20281ad8388SMartin Matuska 	strm->internal->supported_actions[LZMA_RUN] = true;
20381ad8388SMartin Matuska 	strm->internal->supported_actions[LZMA_FINISH] = true;
20481ad8388SMartin Matuska 
20581ad8388SMartin Matuska 	return LZMA_OK;
20681ad8388SMartin Matuska }
207