1207753Smm/////////////////////////////////////////////////////////////////////////////// 2207753Smm// 3207753Smm/// \file stream_buffer_decoder.c 4207753Smm/// \brief Single-call .xz Stream decoder 5207753Smm// 6207753Smm// Author: Lasse Collin 7207753Smm// 8207753Smm// This file has been put into the public domain. 9207753Smm// You can do whatever you want with this file. 10207753Smm// 11207753Smm/////////////////////////////////////////////////////////////////////////////// 12207753Smm 13207753Smm#include "stream_decoder.h" 14207753Smm 15207753Smm 16207753Smmextern LZMA_API(lzma_ret) 17207753Smmlzma_stream_buffer_decode(uint64_t *memlimit, uint32_t flags, 18292588Sdelphij const lzma_allocator *allocator, 19207753Smm const uint8_t *in, size_t *in_pos, size_t in_size, 20207753Smm uint8_t *out, size_t *out_pos, size_t out_size) 21207753Smm{ 22207753Smm // Sanity checks 23207753Smm if (in_pos == NULL || (in == NULL && *in_pos != in_size) 24207753Smm || *in_pos > in_size || out_pos == NULL 25207753Smm || (out == NULL && *out_pos != out_size) 26207753Smm || *out_pos > out_size) 27207753Smm return LZMA_PROG_ERROR; 28207753Smm 29207753Smm // Catch flags that are not allowed in buffer-to-buffer decoding. 30207753Smm if (flags & LZMA_TELL_ANY_CHECK) 31207753Smm return LZMA_PROG_ERROR; 32207753Smm 33207753Smm // Initialize the Stream decoder. 34207753Smm // TODO: We need something to tell the decoder that it can use the 35207753Smm // output buffer as workspace, and thus save significant amount of RAM. 36207753Smm lzma_next_coder stream_decoder = LZMA_NEXT_CODER_INIT; 37207753Smm lzma_ret ret = lzma_stream_decoder_init( 38207753Smm &stream_decoder, allocator, *memlimit, flags); 39207753Smm 40207753Smm if (ret == LZMA_OK) { 41207753Smm // Save the positions so that we can restore them in case 42207753Smm // an error occurs. 43207753Smm const size_t in_start = *in_pos; 44207753Smm const size_t out_start = *out_pos; 45207753Smm 46207753Smm // Do the actual decoding. 47207753Smm ret = stream_decoder.code(stream_decoder.coder, allocator, 48207753Smm in, in_pos, in_size, out, out_pos, out_size, 49207753Smm LZMA_FINISH); 50207753Smm 51207753Smm if (ret == LZMA_STREAM_END) { 52207753Smm ret = LZMA_OK; 53207753Smm } else { 54207753Smm // Something went wrong, restore the positions. 55207753Smm *in_pos = in_start; 56207753Smm *out_pos = out_start; 57207753Smm 58207753Smm if (ret == LZMA_OK) { 59207753Smm // Either the input was truncated or the 60207753Smm // output buffer was too small. 61207753Smm assert(*in_pos == in_size 62207753Smm || *out_pos == out_size); 63207753Smm 64207753Smm // If all the input was consumed, then the 65207753Smm // input is truncated, even if the output 66207753Smm // buffer is also full. This is because 67207753Smm // processing the last byte of the Stream 68207753Smm // never produces output. 69207753Smm if (*in_pos == in_size) 70207753Smm ret = LZMA_DATA_ERROR; 71207753Smm else 72207753Smm ret = LZMA_BUF_ERROR; 73207753Smm 74207753Smm } else if (ret == LZMA_MEMLIMIT_ERROR) { 75207753Smm // Let the caller know how much memory would 76207753Smm // have been needed. 77207753Smm uint64_t memusage; 78207753Smm (void)stream_decoder.memconfig( 79207753Smm stream_decoder.coder, 80207753Smm memlimit, &memusage, 0); 81207753Smm } 82207753Smm } 83207753Smm } 84207753Smm 85207753Smm // Free the decoder memory. This needs to be done even if 86207753Smm // initialization fails, because the internal API doesn't 87207753Smm // require the initialization function to free its memory on error. 88207753Smm lzma_next_end(&stream_decoder, allocator); 89207753Smm 90207753Smm return ret; 91207753Smm} 92