]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/filter_buffer_decoder.c
Put the interesting parts of XZ Utils into the public domain.
[icculus/xz.git] / src / liblzma / common / filter_buffer_decoder.c
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
16 extern LZMA_API(lzma_ret)
17 lzma_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 immediatelly
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 }