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 | }
|
---|