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