]> pd.if.org Git - zpackage/blobdiff - lzma/common/filter_buffer_decoder.c
integrate lzma
[zpackage] / lzma / common / filter_buffer_decoder.c
diff --git a/lzma/common/filter_buffer_decoder.c b/lzma/common/filter_buffer_decoder.c
new file mode 100644 (file)
index 0000000..6620986
--- /dev/null
@@ -0,0 +1,88 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       filter_buffer_decoder.c
+/// \brief      Single-call raw decoding
+//
+//  Author:     Lasse Collin
+//
+//  This file has been put into the public domain.
+//  You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_decoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_raw_buffer_decode(
+               const lzma_filter *filters, const lzma_allocator *allocator,
+               const uint8_t *in, size_t *in_pos, size_t in_size,
+               uint8_t *out, size_t *out_pos, size_t out_size)
+{
+       // Validate what isn't validated later in filter_common.c.
+       if (in == NULL || in_pos == NULL || *in_pos > in_size || out == NULL
+                       || out_pos == NULL || *out_pos > out_size)
+               return LZMA_PROG_ERROR;
+
+       // Initialize the decoer.
+       lzma_next_coder next = LZMA_NEXT_CODER_INIT;
+       return_if_error(lzma_raw_decoder_init(&next, allocator, filters));
+
+       // Store the positions so that we can restore them if something
+       // goes wrong.
+       const size_t in_start = *in_pos;
+       const size_t out_start = *out_pos;
+
+       // Do the actual decoding and free decoder's memory.
+       lzma_ret ret = next.code(next.coder, allocator, in, in_pos, in_size,
+                       out, out_pos, out_size, LZMA_FINISH);
+
+       if (ret == LZMA_STREAM_END) {
+               ret = LZMA_OK;
+       } else {
+               if (ret == LZMA_OK) {
+                       // Either the input was truncated or the
+                       // output buffer was too small.
+                       assert(*in_pos == in_size || *out_pos == out_size);
+
+                       if (*in_pos != in_size) {
+                               // Since input wasn't consumed completely,
+                               // the output buffer became full and is
+                               // too small.
+                               ret = LZMA_BUF_ERROR;
+
+                       } else if (*out_pos != out_size) {
+                               // Since output didn't became full, the input
+                               // has to be truncated.
+                               ret = LZMA_DATA_ERROR;
+
+                       } else {
+                               // All the input was consumed and output
+                               // buffer is full. Now we don't immediately
+                               // know the reason for the error. Try
+                               // decoding one more byte. If it succeeds,
+                               // then the output buffer was too small. If
+                               // we cannot get a new output byte, the input
+                               // is truncated.
+                               uint8_t tmp[1];
+                               size_t tmp_pos = 0;
+                               (void)next.code(next.coder, allocator,
+                                               in, in_pos, in_size,
+                                               tmp, &tmp_pos, 1, LZMA_FINISH);
+
+                               if (tmp_pos == 1)
+                                       ret = LZMA_BUF_ERROR;
+                               else
+                                       ret = LZMA_DATA_ERROR;
+                       }
+               }
+
+               // Restore the positions.
+               *in_pos = in_start;
+               *out_pos = out_start;
+       }
+
+       lzma_next_end(&next, allocator);
+
+       return ret;
+}