Upgrade xz from 5.0.7 to 5.2.2 on the vendor branch
[dragonfly.git] / contrib / xz / src / liblzma / common / stream_buffer_decoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       stream_buffer_decoder.c
4 /// \brief      Single-call .xz Stream decoder
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 "stream_decoder.h"
14
15
16 extern LZMA_API(lzma_ret)
17 lzma_stream_buffer_decode(uint64_t *memlimit, uint32_t flags,
18                 const lzma_allocator *allocator,
19                 const uint8_t *in, size_t *in_pos, size_t in_size,
20                 uint8_t *out, size_t *out_pos, size_t out_size)
21 {
22         // Sanity checks
23         if (in_pos == NULL || (in == NULL && *in_pos != in_size)
24                         || *in_pos > in_size || out_pos == NULL
25                         || (out == NULL && *out_pos != out_size)
26                         || *out_pos > out_size)
27                 return LZMA_PROG_ERROR;
28
29         // Catch flags that are not allowed in buffer-to-buffer decoding.
30         if (flags & LZMA_TELL_ANY_CHECK)
31                 return LZMA_PROG_ERROR;
32
33         // Initialize the Stream decoder.
34         // TODO: We need something to tell the decoder that it can use the
35         // output buffer as workspace, and thus save significant amount of RAM.
36         lzma_next_coder stream_decoder = LZMA_NEXT_CODER_INIT;
37         lzma_ret ret = lzma_stream_decoder_init(
38                         &stream_decoder, allocator, *memlimit, flags);
39
40         if (ret == LZMA_OK) {
41                 // Save the positions so that we can restore them in case
42                 // an error occurs.
43                 const size_t in_start = *in_pos;
44                 const size_t out_start = *out_pos;
45
46                 // Do the actual decoding.
47                 ret = stream_decoder.code(stream_decoder.coder, allocator,
48                                 in, in_pos, in_size, out, out_pos, out_size,
49                                 LZMA_FINISH);
50
51                 if (ret == LZMA_STREAM_END) {
52                         ret = LZMA_OK;
53                 } else {
54                         // Something went wrong, restore the positions.
55                         *in_pos = in_start;
56                         *out_pos = out_start;
57
58                         if (ret == LZMA_OK) {
59                                 // Either the input was truncated or the
60                                 // output buffer was too small.
61                                 assert(*in_pos == in_size
62                                                 || *out_pos == out_size);
63
64                                 // If all the input was consumed, then the
65                                 // input is truncated, even if the output
66                                 // buffer is also full. This is because
67                                 // processing the last byte of the Stream
68                                 // never produces output.
69                                 if (*in_pos == in_size)
70                                         ret = LZMA_DATA_ERROR;
71                                 else
72                                         ret = LZMA_BUF_ERROR;
73
74                         } else if (ret == LZMA_MEMLIMIT_ERROR) {
75                                 // Let the caller know how much memory would
76                                 // have been needed.
77                                 uint64_t memusage;
78                                 (void)stream_decoder.memconfig(
79                                                 stream_decoder.coder,
80                                                 memlimit, &memusage, 0);
81                         }
82                 }
83         }
84
85         // Free the decoder memory. This needs to be done even if
86         // initialization fails, because the internal API doesn't
87         // require the initialization function to free its memory on error.
88         lzma_next_end(&stream_decoder, allocator);
89
90         return ret;
91 }