xref: /freebsd/contrib/xz/src/liblzma/common/vli_decoder.c (revision 3b35e7ee8de9b0260149a2b77e87a2b9c7a36244)
1 // SPDX-License-Identifier: 0BSD
2 
3 ///////////////////////////////////////////////////////////////////////////////
4 //
5 /// \file       vli_decoder.c
6 /// \brief      Decodes variable-length integers
7 //
8 //  Author:     Lasse Collin
9 //
10 ///////////////////////////////////////////////////////////////////////////////
11 
12 #include "common.h"
13 
14 
15 extern LZMA_API(lzma_ret)
16 lzma_vli_decode(lzma_vli *restrict vli, size_t *vli_pos,
17 		const uint8_t *restrict in, size_t *restrict in_pos,
18 		size_t in_size)
19 {
20 	// If we haven't been given vli_pos, work in single-call mode.
21 	size_t vli_pos_internal = 0;
22 	if (vli_pos == NULL) {
23 		vli_pos = &vli_pos_internal;
24 		*vli = 0;
25 
26 		// If there's no input, use LZMA_DATA_ERROR. This way it is
27 		// easy to decode VLIs from buffers that have known size,
28 		// and get the correct error code in case the buffer is
29 		// too short.
30 		if (*in_pos >= in_size)
31 			return LZMA_DATA_ERROR;
32 
33 	} else {
34 		// Initialize *vli when starting to decode a new integer.
35 		if (*vli_pos == 0)
36 			*vli = 0;
37 
38 		// Validate the arguments.
39 		if (*vli_pos >= LZMA_VLI_BYTES_MAX
40 				|| (*vli >> (*vli_pos * 7)) != 0)
41 			return LZMA_PROG_ERROR;;
42 
43 		if (*in_pos >= in_size)
44 			return LZMA_BUF_ERROR;
45 	}
46 
47 	do {
48 		// Read the next byte. Use a temporary variable so that we
49 		// can update *in_pos immediately.
50 		const uint8_t byte = in[*in_pos];
51 		++*in_pos;
52 
53 		// Add the newly read byte to *vli.
54 		*vli += (lzma_vli)(byte & 0x7F) << (*vli_pos * 7);
55 		++*vli_pos;
56 
57 		// Check if this is the last byte of a multibyte integer.
58 		if ((byte & 0x80) == 0) {
59 			// We don't allow using variable-length integers as
60 			// padding i.e. the encoding must use the most the
61 			// compact form.
62 			if (byte == 0x00 && *vli_pos > 1)
63 				return LZMA_DATA_ERROR;
64 
65 			return vli_pos == &vli_pos_internal
66 					? LZMA_OK : LZMA_STREAM_END;
67 		}
68 
69 		// There is at least one more byte coming. If we have already
70 		// read maximum number of bytes, the integer is considered
71 		// corrupt.
72 		//
73 		// If we need bigger integers in future, old versions liblzma
74 		// will confusingly indicate the file being corrupt instead of
75 		// unsupported. I suppose it's still better this way, because
76 		// in the foreseeable future (writing this in 2008) the only
77 		// reason why files would appear having over 63-bit integers
78 		// is that the files are simply corrupt.
79 		if (*vli_pos == LZMA_VLI_BYTES_MAX)
80 			return LZMA_DATA_ERROR;
81 
82 	} while (*in_pos < in_size);
83 
84 	return vli_pos == &vli_pos_internal ? LZMA_DATA_ERROR : LZMA_OK;
85 }
86