]> pd.if.org Git - zpackage/blobdiff - lzma/common/vli_decoder.c
integrate lzma
[zpackage] / lzma / common / vli_decoder.c
diff --git a/lzma/common/vli_decoder.c b/lzma/common/vli_decoder.c
new file mode 100644 (file)
index 0000000..c181828
--- /dev/null
@@ -0,0 +1,86 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file       vli_decoder.c
+/// \brief      Decodes variable-length integers
+//
+//  Author:     Lasse Collin
+//
+//  This file has been put into the public domain.
+//  You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_vli_decode(lzma_vli *restrict vli, size_t *vli_pos,
+               const uint8_t *restrict in, size_t *restrict in_pos,
+               size_t in_size)
+{
+       // If we haven't been given vli_pos, work in single-call mode.
+       size_t vli_pos_internal = 0;
+       if (vli_pos == NULL) {
+               vli_pos = &vli_pos_internal;
+               *vli = 0;
+
+               // If there's no input, use LZMA_DATA_ERROR. This way it is
+               // easy to decode VLIs from buffers that have known size,
+               // and get the correct error code in case the buffer is
+               // too short.
+               if (*in_pos >= in_size)
+                       return LZMA_DATA_ERROR;
+
+       } else {
+               // Initialize *vli when starting to decode a new integer.
+               if (*vli_pos == 0)
+                       *vli = 0;
+
+               // Validate the arguments.
+               if (*vli_pos >= LZMA_VLI_BYTES_MAX
+                               || (*vli >> (*vli_pos * 7)) != 0)
+                       return LZMA_PROG_ERROR;;
+
+               if (*in_pos >= in_size)
+                       return LZMA_BUF_ERROR;
+       }
+
+       do {
+               // Read the next byte. Use a temporary variable so that we
+               // can update *in_pos immediately.
+               const uint8_t byte = in[*in_pos];
+               ++*in_pos;
+
+               // Add the newly read byte to *vli.
+               *vli += (lzma_vli)(byte & 0x7F) << (*vli_pos * 7);
+               ++*vli_pos;
+
+               // Check if this is the last byte of a multibyte integer.
+               if ((byte & 0x80) == 0) {
+                       // We don't allow using variable-length integers as
+                       // padding i.e. the encoding must use the most the
+                       // compact form.
+                       if (byte == 0x00 && *vli_pos > 1)
+                               return LZMA_DATA_ERROR;
+
+                       return vli_pos == &vli_pos_internal
+                                       ? LZMA_OK : LZMA_STREAM_END;
+               }
+
+               // There is at least one more byte coming. If we have already
+               // read maximum number of bytes, the integer is considered
+               // corrupt.
+               //
+               // If we need bigger integers in future, old versions liblzma
+               // will confusingly indicate the file being corrupt istead of
+               // unsupported. I suppose it's still better this way, because
+               // in the foreseeable future (writing this in 2008) the only
+               // reason why files would appear having over 63-bit integers
+               // is that the files are simply corrupt.
+               if (*vli_pos == LZMA_VLI_BYTES_MAX)
+                       return LZMA_DATA_ERROR;
+
+       } while (*in_pos < in_size);
+
+       return vli_pos == &vli_pos_internal ? LZMA_DATA_ERROR : LZMA_OK;
+}