(root)/
xz-5.4.5/
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  }