1207753Smm///////////////////////////////////////////////////////////////////////////////
2207753Smm//
3207753Smm/// \file       auto_decoder.c
4207753Smm/// \brief      Autodetect between .xz Stream and .lzma (LZMA_Alone) formats
5207753Smm//
6207753Smm//  Author:     Lasse Collin
7207753Smm//
8207753Smm//  This file has been put into the public domain.
9207753Smm//  You can do whatever you want with this file.
10207753Smm//
11207753Smm///////////////////////////////////////////////////////////////////////////////
12207753Smm
13207753Smm#include "stream_decoder.h"
14207753Smm#include "alone_decoder.h"
15207753Smm
16207753Smm
17312517Sdelphijtypedef struct {
18207753Smm	/// Stream decoder or LZMA_Alone decoder
19207753Smm	lzma_next_coder next;
20207753Smm
21207753Smm	uint64_t memlimit;
22207753Smm	uint32_t flags;
23207753Smm
24207753Smm	enum {
25207753Smm		SEQ_INIT,
26207753Smm		SEQ_CODE,
27207753Smm		SEQ_FINISH,
28207753Smm	} sequence;
29312517Sdelphij} lzma_auto_coder;
30207753Smm
31207753Smm
32207753Smmstatic lzma_ret
33312517Sdelphijauto_decode(void *coder_ptr, const lzma_allocator *allocator,
34207753Smm		const uint8_t *restrict in, size_t *restrict in_pos,
35207753Smm		size_t in_size, uint8_t *restrict out,
36207753Smm		size_t *restrict out_pos, size_t out_size, lzma_action action)
37207753Smm{
38312517Sdelphij	lzma_auto_coder *coder = coder_ptr;
39312517Sdelphij
40207753Smm	switch (coder->sequence) {
41207753Smm	case SEQ_INIT:
42207753Smm		if (*in_pos >= in_size)
43207753Smm			return LZMA_OK;
44207753Smm
45207753Smm		// Update the sequence now, because we want to continue from
46207753Smm		// SEQ_CODE even if we return some LZMA_*_CHECK.
47207753Smm		coder->sequence = SEQ_CODE;
48207753Smm
49207753Smm		// Detect the file format. For now this is simple, since if
50207753Smm		// it doesn't start with 0xFD (the first magic byte of the
51207753Smm		// new format), it has to be LZMA_Alone, or something that
52207753Smm		// we don't support at all.
53207753Smm		if (in[*in_pos] == 0xFD) {
54207753Smm			return_if_error(lzma_stream_decoder_init(
55207753Smm					&coder->next, allocator,
56207753Smm					coder->memlimit, coder->flags));
57207753Smm		} else {
58207753Smm			return_if_error(lzma_alone_decoder_init(&coder->next,
59262754Sdelphij					allocator, coder->memlimit, true));
60207753Smm
61207753Smm			// If the application wants to know about missing
62207753Smm			// integrity check or about the check in general, we
63207753Smm			// need to handle it here, because LZMA_Alone decoder
64207753Smm			// doesn't accept any flags.
65207753Smm			if (coder->flags & LZMA_TELL_NO_CHECK)
66207753Smm				return LZMA_NO_CHECK;
67207753Smm
68207753Smm			if (coder->flags & LZMA_TELL_ANY_CHECK)
69207753Smm				return LZMA_GET_CHECK;
70207753Smm		}
71207753Smm
72207753Smm	// Fall through
73207753Smm
74207753Smm	case SEQ_CODE: {
75207753Smm		const lzma_ret ret = coder->next.code(
76207753Smm				coder->next.coder, allocator,
77207753Smm				in, in_pos, in_size,
78207753Smm				out, out_pos, out_size, action);
79207753Smm		if (ret != LZMA_STREAM_END
80207753Smm				|| (coder->flags & LZMA_CONCATENATED) == 0)
81207753Smm			return ret;
82207753Smm
83207753Smm		coder->sequence = SEQ_FINISH;
84207753Smm	}
85207753Smm
86207753Smm	// Fall through
87207753Smm
88207753Smm	case SEQ_FINISH:
89207753Smm		// When LZMA_DECODE_CONCATENATED was used and we were decoding
90207753Smm		// LZMA_Alone file, we need to check check that there is no
91207753Smm		// trailing garbage and wait for LZMA_FINISH.
92207753Smm		if (*in_pos < in_size)
93207753Smm			return LZMA_DATA_ERROR;
94207753Smm
95207753Smm		return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK;
96207753Smm
97207753Smm	default:
98207753Smm		assert(0);
99207753Smm		return LZMA_PROG_ERROR;
100207753Smm	}
101207753Smm}
102207753Smm
103207753Smm
104207753Smmstatic void
105312517Sdelphijauto_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
106207753Smm{
107312517Sdelphij	lzma_auto_coder *coder = coder_ptr;
108207753Smm	lzma_next_end(&coder->next, allocator);
109207753Smm	lzma_free(coder, allocator);
110207753Smm	return;
111207753Smm}
112207753Smm
113207753Smm
114207753Smmstatic lzma_check
115312517Sdelphijauto_decoder_get_check(const void *coder_ptr)
116207753Smm{
117312517Sdelphij	const lzma_auto_coder *coder = coder_ptr;
118312517Sdelphij
119207753Smm	// It is LZMA_Alone if get_check is NULL.
120207753Smm	return coder->next.get_check == NULL ? LZMA_CHECK_NONE
121207753Smm			: coder->next.get_check(coder->next.coder);
122207753Smm}
123207753Smm
124207753Smm
125207753Smmstatic lzma_ret
126312517Sdelphijauto_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
127207753Smm		uint64_t *old_memlimit, uint64_t new_memlimit)
128207753Smm{
129312517Sdelphij	lzma_auto_coder *coder = coder_ptr;
130312517Sdelphij
131207753Smm	lzma_ret ret;
132207753Smm
133207753Smm	if (coder->next.memconfig != NULL) {
134207753Smm		ret = coder->next.memconfig(coder->next.coder,
135207753Smm				memusage, old_memlimit, new_memlimit);
136207753Smm		assert(*old_memlimit == coder->memlimit);
137207753Smm	} else {
138207753Smm		// No coder is configured yet. Use the base value as
139207753Smm		// the current memory usage.
140207753Smm		*memusage = LZMA_MEMUSAGE_BASE;
141207753Smm		*old_memlimit = coder->memlimit;
142334607Sdelphij
143207753Smm		ret = LZMA_OK;
144334607Sdelphij		if (new_memlimit != 0 && new_memlimit < *memusage)
145334607Sdelphij			ret = LZMA_MEMLIMIT_ERROR;
146207753Smm	}
147207753Smm
148207753Smm	if (ret == LZMA_OK && new_memlimit != 0)
149207753Smm		coder->memlimit = new_memlimit;
150207753Smm
151207753Smm	return ret;
152207753Smm}
153207753Smm
154207753Smm
155207753Smmstatic lzma_ret
156278433Srpauloauto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
157207753Smm		uint64_t memlimit, uint32_t flags)
158207753Smm{
159207753Smm	lzma_next_coder_init(&auto_decoder_init, next, allocator);
160207753Smm
161207753Smm	if (flags & ~LZMA_SUPPORTED_FLAGS)
162207753Smm		return LZMA_OPTIONS_ERROR;
163207753Smm
164312517Sdelphij	lzma_auto_coder *coder = next->coder;
165312517Sdelphij	if (coder == NULL) {
166312517Sdelphij		coder = lzma_alloc(sizeof(lzma_auto_coder), allocator);
167312517Sdelphij		if (coder == NULL)
168207753Smm			return LZMA_MEM_ERROR;
169207753Smm
170312517Sdelphij		next->coder = coder;
171207753Smm		next->code = &auto_decode;
172207753Smm		next->end = &auto_decoder_end;
173207753Smm		next->get_check = &auto_decoder_get_check;
174207753Smm		next->memconfig = &auto_decoder_memconfig;
175312517Sdelphij		coder->next = LZMA_NEXT_CODER_INIT;
176207753Smm	}
177207753Smm
178334607Sdelphij	coder->memlimit = my_max(1, memlimit);
179312517Sdelphij	coder->flags = flags;
180312517Sdelphij	coder->sequence = SEQ_INIT;
181207753Smm
182207753Smm	return LZMA_OK;
183207753Smm}
184207753Smm
185207753Smm
186207753Smmextern LZMA_API(lzma_ret)
187207753Smmlzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
188207753Smm{
189207753Smm	lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags);
190207753Smm
191207753Smm	strm->internal->supported_actions[LZMA_RUN] = true;
192207753Smm	strm->internal->supported_actions[LZMA_FINISH] = true;
193207753Smm
194207753Smm	return LZMA_OK;
195207753Smm}
196