filter_buffer_decoder.c revision 207842
1///////////////////////////////////////////////////////////////////////////////
2//
3/// \file       filter_buffer_decoder.c
4/// \brief      Single-call raw decoding
5//
6//  Author:     Lasse Collin
7//
8//  This file has been put into the public domain.
9//  You can do whatever you want with this file.
10//
11///////////////////////////////////////////////////////////////////////////////
12
13#include "filter_decoder.h"
14
15
16extern LZMA_API(lzma_ret)
17lzma_raw_buffer_decode(const lzma_filter *filters, lzma_allocator *allocator,
18		const uint8_t *in, size_t *in_pos, size_t in_size,
19		uint8_t *out, size_t *out_pos, size_t out_size)
20{
21	// Validate what isn't validated later in filter_common.c.
22	if (in == NULL || in_pos == NULL || *in_pos > in_size || out == NULL
23			|| out_pos == NULL || *out_pos > out_size)
24		return LZMA_PROG_ERROR;
25
26	// Initialize the decoer.
27	lzma_next_coder next = LZMA_NEXT_CODER_INIT;
28	return_if_error(lzma_raw_decoder_init(&next, allocator, filters));
29
30	// Store the positions so that we can restore them if something
31	// goes wrong.
32	const size_t in_start = *in_pos;
33	const size_t out_start = *out_pos;
34
35	// Do the actual decoding and free decoder's memory.
36	lzma_ret ret = next.code(next.coder, allocator, in, in_pos, in_size,
37			out, out_pos, out_size, LZMA_FINISH);
38
39	if (ret == LZMA_STREAM_END) {
40		ret = LZMA_OK;
41	} else {
42		if (ret == LZMA_OK) {
43			// Either the input was truncated or the
44			// output buffer was too small.
45			assert(*in_pos == in_size || *out_pos == out_size);
46
47			if (*in_pos != in_size) {
48				// Since input wasn't consumed completely,
49				// the output buffer became full and is
50				// too small.
51				ret = LZMA_BUF_ERROR;
52
53			} else if (*out_pos != out_size) {
54				// Since output didn't became full, the input
55				// has to be truncated.
56				ret = LZMA_DATA_ERROR;
57
58			} else {
59				// All the input was consumed and output
60				// buffer is full. Now we don't immediately
61				// know the reason for the error. Try
62				// decoding one more byte. If it succeeds,
63				// then the output buffer was too small. If
64				// we cannot get a new output byte, the input
65				// is truncated.
66				uint8_t tmp[1];
67				size_t tmp_pos = 0;
68				(void)next.code(next.coder, allocator,
69						in, in_pos, in_size,
70						tmp, &tmp_pos, 1, LZMA_FINISH);
71
72				if (tmp_pos == 1)
73					ret = LZMA_BUF_ERROR;
74				else
75					ret = LZMA_DATA_ERROR;
76			}
77		}
78
79		// Restore the positions.
80		*in_pos = in_start;
81		*out_pos = out_start;
82	}
83
84	lzma_next_end(&next, allocator);
85
86	return ret;
87}
88