Line data Source code
1 : /* SPDX-License-Identifier: Zlib */
2 :
3 : /*
4 : * tinfgzip - tiny gzip decompressor
5 : *
6 : * Copyright (c) 2003-2019 Joergen Ibsen
7 : *
8 : * This software is provided 'as-is', without any express or implied
9 : * warranty. In no event will the authors be held liable for any damages
10 : * arising from the use of this software.
11 : *
12 : * Permission is granted to anyone to use this software for any purpose,
13 : * including commercial applications, and to alter it and redistribute it
14 : * freely, subject to the following restrictions:
15 : *
16 : * 1. The origin of this software must not be misrepresented; you must
17 : * not claim that you wrote the original software. If you use this
18 : * software in a product, an acknowledgment in the product
19 : * documentation would be appreciated but is not required.
20 : *
21 : * 2. Altered source versions must be plainly marked as such, and must
22 : * not be misrepresented as being the original software.
23 : *
24 : * 3. This notice may not be removed or altered from any source
25 : * distribution.
26 : */
27 :
28 : #include "tinf.h"
29 :
30 : typedef enum {
31 : FTEXT = 1,
32 : FHCRC = 2,
33 : FEXTRA = 4,
34 : FNAME = 8,
35 : FCOMMENT = 16
36 : } tinf_gzip_flag;
37 :
38 0 : static unsigned int read_le16(const unsigned char *p)
39 : {
40 0 : return ((unsigned int) p[0])
41 0 : | ((unsigned int) p[1] << 8);
42 : }
43 :
44 12 : static unsigned int read_le32(const unsigned char *p)
45 : {
46 12 : return ((unsigned int) p[0])
47 12 : | ((unsigned int) p[1] << 8)
48 12 : | ((unsigned int) p[2] << 16)
49 12 : | ((unsigned int) p[3] << 24);
50 : }
51 :
52 9 : int tinf_gzip_uncompress(void *dest, unsigned int *destLen,
53 : const void *source, unsigned int sourceLen)
54 : {
55 9 : const unsigned char *src = (const unsigned char *) source;
56 9 : unsigned char *dst = (unsigned char *) dest;
57 : const unsigned char *start;
58 : unsigned int dlen, crc32;
59 : int res;
60 : unsigned char flg;
61 :
62 : /* -- Check header -- */
63 :
64 : /* Check room for at least 10 byte header and 8 byte trailer */
65 9 : if (sourceLen < 18) {
66 1 : return TINF_DATA_ERROR;
67 : }
68 :
69 : /* Check id bytes */
70 8 : if (src[0] != 0x1F || src[1] != 0x8B) {
71 2 : return TINF_DATA_ERROR;
72 : }
73 :
74 : /* Check method is deflate */
75 6 : if (src[2] != 8) {
76 0 : return TINF_DATA_ERROR;
77 : }
78 :
79 : /* Get flag byte */
80 6 : flg = src[3];
81 :
82 : /* Check that reserved bits are zero */
83 6 : if (flg & 0xE0) {
84 0 : return TINF_DATA_ERROR;
85 : }
86 :
87 : /* -- Find start of compressed data -- */
88 :
89 : /* Skip base header of 10 bytes */
90 6 : start = src + 10;
91 :
92 : /* Skip extra data if present */
93 6 : if (flg & FEXTRA) {
94 0 : unsigned int xlen = read_le16(start);
95 :
96 0 : if (xlen > sourceLen - 12) {
97 0 : return TINF_DATA_ERROR;
98 : }
99 :
100 0 : start += xlen + 2;
101 : }
102 :
103 : /* Skip file name if present */
104 6 : if (flg & FNAME) {
105 : do {
106 0 : if (start - src >= sourceLen) {
107 0 : return TINF_DATA_ERROR;
108 : }
109 0 : } while (*start++);
110 : }
111 :
112 : /* Skip file comment if present */
113 6 : if (flg & FCOMMENT) {
114 : do {
115 0 : if (start - src >= sourceLen) {
116 0 : return TINF_DATA_ERROR;
117 : }
118 0 : } while (*start++);
119 : }
120 :
121 : /* Check header crc if present */
122 6 : if (flg & FHCRC) {
123 : unsigned int hcrc;
124 :
125 0 : if (start - src > sourceLen - 2) {
126 0 : return TINF_DATA_ERROR;
127 : }
128 :
129 0 : hcrc = read_le16(start);
130 :
131 0 : if (hcrc != (tinf_crc32(src, start - src) & 0x0000FFFF)) {
132 0 : return TINF_DATA_ERROR;
133 : }
134 :
135 0 : start += 2;
136 : }
137 :
138 : /* -- Get decompressed length -- */
139 :
140 6 : dlen = read_le32(&src[sourceLen - 4]);
141 :
142 6 : if (dlen > *destLen) {
143 0 : return TINF_BUF_ERROR;
144 : }
145 :
146 : /* -- Get CRC32 checksum of original data -- */
147 :
148 6 : crc32 = read_le32(&src[sourceLen - 8]);
149 :
150 : /* -- Decompress data -- */
151 :
152 6 : if ((src + sourceLen) - start < 8) {
153 0 : return TINF_DATA_ERROR;
154 : }
155 :
156 6 : res = tinf_uncompress(dst, destLen, start,
157 6 : (src + sourceLen) - start - 8);
158 :
159 6 : if (res != TINF_OK) {
160 0 : return TINF_DATA_ERROR;
161 : }
162 :
163 6 : if (*destLen != dlen) {
164 0 : return TINF_DATA_ERROR;
165 : }
166 :
167 : /* -- Check CRC32 checksum -- */
168 :
169 6 : if (crc32 != tinf_crc32(dst, dlen)) {
170 0 : return TINF_DATA_ERROR;
171 : }
172 :
173 6 : return TINF_OK;
174 : }
|