File: | Deflate.c |
Warning: | line 636, column 17 The right operand of '+' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | #include "Deflate.h" | |||
2 | #include "String.h" | |||
3 | #include "Logger.h" | |||
4 | #include "Funcs.h" | |||
5 | #include "Platform.h" | |||
6 | #include "Stream.h" | |||
7 | #include "Errors.h" | |||
8 | #include "Utils.h" | |||
9 | ||||
10 | #define Header_ReadU8(value)if ((res = s->ReadU8(s, &value))) return res; if ((res = s->ReadU8(s, &value))) return res; | |||
11 | /*########################################################################################################################* | |||
12 | *-------------------------------------------------------GZip header-------------------------------------------------------* | |||
13 | *#########################################################################################################################*/ | |||
14 | enum GzipState { | |||
15 | GZIP_STATE_HEADER1, GZIP_STATE_HEADER2, GZIP_STATE_COMPRESSIONMETHOD, GZIP_STATE_FLAGS, | |||
16 | GZIP_STATE_LASTMODIFIED, GZIP_STATE_COMPRESSIONFLAGS, GZIP_STATE_OPERATINGSYSTEM, | |||
17 | GZIP_STATE_HEADERCHECKSUM, GZIP_STATE_FILENAME, GZIP_STATE_COMMENT, GZIP_STATE_DONE | |||
18 | }; | |||
19 | ||||
20 | void GZipHeader_Init(struct GZipHeader* header) { | |||
21 | header->state = GZIP_STATE_HEADER1; | |||
22 | header->done = false0; | |||
23 | header->flags = 0; | |||
24 | header->partsRead = 0; | |||
25 | } | |||
26 | ||||
27 | cc_result GZipHeader_Read(struct Stream* s, struct GZipHeader* header) { | |||
28 | cc_uint8 tmp; | |||
29 | cc_result res; | |||
30 | switch (header->state) { | |||
31 | ||||
32 | case GZIP_STATE_HEADER1: | |||
33 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
34 | if (tmp != 0x1F) return GZIP_ERR_HEADER1; | |||
35 | header->state++; | |||
36 | ||||
37 | case GZIP_STATE_HEADER2: | |||
38 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
39 | if (tmp != 0x8B) return GZIP_ERR_HEADER2; | |||
40 | header->state++; | |||
41 | ||||
42 | case GZIP_STATE_COMPRESSIONMETHOD: | |||
43 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
44 | if (tmp != 0x08) return GZIP_ERR_METHOD; | |||
45 | header->state++; | |||
46 | ||||
47 | case GZIP_STATE_FLAGS: | |||
48 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
49 | header->flags = tmp; | |||
50 | if (header->flags & 0x04) return GZIP_ERR_FLAGS; | |||
51 | header->state++; | |||
52 | ||||
53 | case GZIP_STATE_LASTMODIFIED: | |||
54 | for (; header->partsRead < 4; header->partsRead++) { | |||
55 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
56 | } | |||
57 | header->state++; | |||
58 | header->partsRead = 0; | |||
59 | ||||
60 | case GZIP_STATE_COMPRESSIONFLAGS: | |||
61 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
62 | header->state++; | |||
63 | ||||
64 | case GZIP_STATE_OPERATINGSYSTEM: | |||
65 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
66 | header->state++; | |||
67 | ||||
68 | case GZIP_STATE_FILENAME: | |||
69 | if (header->flags & 0x08) { | |||
70 | for (; ;) { | |||
71 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
72 | if (tmp == '\0') break; | |||
73 | } | |||
74 | } | |||
75 | header->state++; | |||
76 | ||||
77 | case GZIP_STATE_COMMENT: | |||
78 | if (header->flags & 0x10) { | |||
79 | for (; ;) { | |||
80 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
81 | if (tmp == '\0') break; | |||
82 | } | |||
83 | } | |||
84 | header->state++; | |||
85 | ||||
86 | case GZIP_STATE_HEADERCHECKSUM: | |||
87 | if (header->flags & 0x02) { | |||
88 | for (; header->partsRead < 2; header->partsRead++) { | |||
89 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
90 | } | |||
91 | } | |||
92 | header->state++; | |||
93 | header->partsRead = 0; | |||
94 | header->done = true1; | |||
95 | } | |||
96 | return 0; | |||
97 | } | |||
98 | ||||
99 | ||||
100 | /*########################################################################################################################* | |||
101 | *-------------------------------------------------------ZLib header-------------------------------------------------------* | |||
102 | *#########################################################################################################################*/ | |||
103 | enum ZlibState { ZLIB_STATE_COMPRESSIONMETHOD, ZLIB_STATE_FLAGS, ZLIB_STATE_DONE }; | |||
104 | ||||
105 | void ZLibHeader_Init(struct ZLibHeader* header) { | |||
106 | header->state = ZLIB_STATE_COMPRESSIONMETHOD; | |||
107 | header->done = false0; | |||
108 | } | |||
109 | ||||
110 | cc_result ZLibHeader_Read(struct Stream* s, struct ZLibHeader* header) { | |||
111 | cc_uint8 tmp; | |||
112 | cc_result res; | |||
113 | switch (header->state) { | |||
114 | ||||
115 | case ZLIB_STATE_COMPRESSIONMETHOD: | |||
116 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
117 | if ((tmp & 0x0F) != 0x08) return ZLIB_ERR_METHOD; | |||
118 | /* Upper 4 bits are window size (ignored) */ | |||
119 | header->state++; | |||
120 | ||||
121 | case ZLIB_STATE_FLAGS: | |||
122 | Header_ReadU8(tmp)if ((res = s->ReadU8(s, &tmp))) return res;; | |||
123 | if (tmp & 0x20) return ZLIB_ERR_FLAGS; | |||
124 | header->state++; | |||
125 | header->done = true1; | |||
126 | } | |||
127 | return 0; | |||
128 | } | |||
129 | ||||
130 | ||||
131 | /*########################################################################################################################* | |||
132 | *--------------------------------------------------Inflate (decompress)---------------------------------------------------* | |||
133 | *#########################################################################################################################*/ | |||
134 | enum INFLATE_STATE_ { | |||
135 | INFLATE_STATE_HEADER, INFLATE_STATE_UNCOMPRESSED_HEADER, | |||
136 | INFLATE_STATE_UNCOMPRESSED_DATA, INFLATE_STATE_DYNAMIC_HEADER, | |||
137 | INFLATE_STATE_DYNAMIC_CODELENS, INFLATE_STATE_DYNAMIC_LITSDISTS, | |||
138 | INFLATE_STATE_DYNAMIC_LITSDISTSREPEAT, INFLATE_STATE_COMPRESSED_LIT, | |||
139 | INFLATE_STATE_COMPRESSED_LITEXTRA, INFLATE_STATE_COMPRESSED_DIST, | |||
140 | INFLATE_STATE_COMPRESSED_DISTEXTRA, INFLATE_STATE_COMPRESSED_DATA, | |||
141 | INFLATE_STATE_FASTCOMPRESSED, INFLATE_STATE_DONE | |||
142 | }; | |||
143 | ||||
144 | /* Insert next byte into the bit buffer */ | |||
145 | #define Inflate_GetByte(state)state->AvailIn--; state->Bits |= (cc_uint32)(*state-> NextIn++) << state->NumBits; state->NumBits += 8; state->AvailIn--; state->Bits |= (cc_uint32)(*state->NextIn++) << state->NumBits; state->NumBits += 8; | |||
146 | /* Retrieves bits from the bit buffer */ | |||
147 | #define Inflate_PeekBits(state, bits)(state->Bits & ((1UL << (bits)) - 1UL)) (state->Bits & ((1UL << (bits)) - 1UL)) | |||
148 | /* Consumes/eats up bits from the bit buffer */ | |||
149 | #define Inflate_ConsumeBits(state, bits)state->Bits >>= (bits); state->NumBits -= (bits); state->Bits >>= (bits); state->NumBits -= (bits); | |||
150 | /* Aligns bit buffer to be on a byte boundary */ | |||
151 | #define Inflate_AlignBits(state)cc_uint32 alignSkip = state->NumBits & 7; state->Bits >>= (alignSkip); state->NumBits -= (alignSkip);; cc_uint32 alignSkip = state->NumBits & 7; Inflate_ConsumeBits(state, alignSkip)state->Bits >>= (alignSkip); state->NumBits -= (alignSkip );; | |||
152 | /* Ensures there are 'bitsCount' bits, or returns if not */ | |||
153 | #define Inflate_EnsureBits(state, bitsCount)while (state->NumBits < bitsCount) { if (!state->AvailIn ) return; state->AvailIn--; state->Bits |= (cc_uint32)( *state->NextIn++) << state->NumBits; state->NumBits += 8;; } while (state->NumBits < bitsCount) { if (!state->AvailIn) return; Inflate_GetByte(state)state->AvailIn--; state->Bits |= (cc_uint32)(*state-> NextIn++) << state->NumBits; state->NumBits += 8;; } | |||
154 | /* Ensures there are 'bitsCount' bits */ | |||
155 | #define Inflate_UNSAFE_EnsureBits(state, bitsCount)while (state->NumBits < bitsCount) { state->AvailIn-- ; state->Bits |= (cc_uint32)(*state->NextIn++) << state->NumBits; state->NumBits += 8;; } while (state->NumBits < bitsCount) { Inflate_GetByte(state)state->AvailIn--; state->Bits |= (cc_uint32)(*state-> NextIn++) << state->NumBits; state->NumBits += 8;; } | |||
156 | /* Peeks then consumes given bits */ | |||
157 | #define Inflate_ReadBits(state, bitsCount)(state->Bits & ((1UL << (bitsCount)) - 1UL)); state ->Bits >>= (bitsCount); state->NumBits -= (bitsCount );; Inflate_PeekBits(state, bitsCount)(state->Bits & ((1UL << (bitsCount)) - 1UL)); Inflate_ConsumeBits(state, bitsCount)state->Bits >>= (bitsCount); state->NumBits -= (bitsCount );; | |||
158 | /* Sets to given result and sets state to DONE */ | |||
159 | #define Inflate_Fail(state, res)state->result = res; state->State = INFLATE_STATE_DONE; state->result = res; state->State = INFLATE_STATE_DONE; | |||
160 | ||||
161 | /* Goes to the next state, after having read data of a block */ | |||
162 | #define Inflate_NextBlockState(state)(state->LastBlock ? INFLATE_STATE_DONE : INFLATE_STATE_HEADER ) (state->LastBlock ? INFLATE_STATE_DONE : INFLATE_STATE_HEADER) | |||
163 | /* Goes to the next state, after having finished reading a compressed entry */ | |||
164 | #define Inflate_NextCompressState(state)((state->AvailIn >= 10 && state->AvailOut >= 258) ? INFLATE_STATE_FASTCOMPRESSED : INFLATE_STATE_COMPRESSED_LIT ) ((state->AvailIn >= INFLATE_FASTINF_IN10 && state->AvailOut >= INFLATE_FASTINF_OUT258) ? INFLATE_STATE_FASTCOMPRESSED : INFLATE_STATE_COMPRESSED_LIT) | |||
165 | /* The maximum amount of bytes that can be output is 258 */ | |||
166 | #define INFLATE_FASTINF_OUT258 258 | |||
167 | /* The most input bytes required for huffman codes and extra data is 16 + 5 + 16 + 13 bits. Add 3 extra bytes to account for putting data into the bit buffer. */ | |||
168 | #define INFLATE_FASTINF_IN10 10 | |||
169 | ||||
170 | static cc_uint32 Huffman_ReverseBits(cc_uint32 n, cc_uint8 bits) { | |||
171 | n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); | |||
172 | n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); | |||
173 | n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); | |||
174 | n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); | |||
175 | return n >> (16 - bits); | |||
176 | } | |||
177 | ||||
178 | /* Builds a huffman tree, based on input lengths of each codeword */ | |||
179 | static cc_result Huffman_Build(struct HuffmanTable* table, const cc_uint8* bitLens, int count) { | |||
180 | int bl_count[INFLATE_MAX_BITS16], bl_offsets[INFLATE_MAX_BITS16]; | |||
181 | int code, offset, value; | |||
182 | int i, j; | |||
183 | ||||
184 | /* Initialise 'zero bit length' codewords */ | |||
185 | table->FirstCodewords[0] = 0; | |||
186 | table->FirstOffsets[0] = 0; | |||
187 | table->EndCodewords[0] = 0; | |||
188 | ||||
189 | /* Count number of codewords assigned to each bit length */ | |||
190 | for (i = 0; i < INFLATE_MAX_BITS16; i++) bl_count[i] = 0; | |||
191 | for (i = 0; i < count; i++) { | |||
192 | bl_count[bitLens[i]]++; | |||
193 | } | |||
194 | ||||
195 | /* Ensure huffman tree actually makes sense */ | |||
196 | bl_count[0] = 0; | |||
197 | for (i = 1; i < INFLATE_MAX_BITS16; i++) { | |||
198 | /* Check if too many huffman codes for bit length */ | |||
199 | if (bl_count[i] > (1 << i)) return INF_ERR_NUM_CODES; | |||
200 | } | |||
201 | ||||
202 | /* Compute the codewords for the huffman tree. | |||
203 | * Codewords are ordered, so consider this example tree: | |||
204 | * 2 of length 2, 3 of length 3, 1 of length 4 | |||
205 | * Codewords produced would be: 00,01 100,101,110, 1110 | |||
206 | */ | |||
207 | code = 0; offset = 0; | |||
208 | for (i = 1; i < INFLATE_MAX_BITS16; i++) { | |||
209 | code = (code + bl_count[i - 1]) << 1; | |||
210 | bl_offsets[i] = offset; | |||
211 | ||||
212 | table->FirstCodewords[i] = code; | |||
213 | table->FirstOffsets[i] = offset; | |||
214 | offset += bl_count[i]; | |||
215 | ||||
216 | /* Last codeword is actually: code + (bl_count[i] - 1) | |||
217 | * However, when decoding we peform < against this value though, so need to add 1 here. | |||
218 | * This way, don't need to special case bit lengths with 0 codewords when decoding. | |||
219 | */ | |||
220 | if (bl_count[i]) { | |||
221 | table->EndCodewords[i] = code + bl_count[i]; | |||
222 | } else { | |||
223 | table->EndCodewords[i] = 0; | |||
224 | } | |||
225 | } | |||
226 | ||||
227 | /* Assigns values to each codeword. | |||
228 | * Note that although codewords are ordered, values may not be. | |||
229 | * Some values may also not be assigned to any codeword. | |||
230 | */ | |||
231 | value = 0; | |||
232 | Mem_Set(table->Fast, UInt8_MaxValue((cc_uint8)255), sizeof(table->Fast)); | |||
233 | for (i = 0; i < count; i++, value++) { | |||
234 | int len = bitLens[i]; | |||
235 | if (!len) continue; | |||
236 | table->Values[bl_offsets[len]] = value; | |||
237 | ||||
238 | /* Compute the accelerated lookup table values for this codeword. | |||
239 | * For example, assume len = 4 and codeword = 0100 | |||
240 | * - Shift it left to be 0100_00000 | |||
241 | * - Then, for all the indices from 0100_00000 to 0100_11111, | |||
242 | * - bit reverse index, as huffman codes are read backwards | |||
243 | * - set fast value to specify a 'value' value, and to skip 'len' bits | |||
244 | */ | |||
245 | if (len <= INFLATE_FAST_BITS9) { | |||
246 | cc_int16 packed = (cc_int16)((len << INFLATE_FAST_BITS9) | value); | |||
247 | int codeword = table->FirstCodewords[len] + (bl_offsets[len] - table->FirstOffsets[len]); | |||
248 | codeword <<= (INFLATE_FAST_BITS9 - len); | |||
249 | ||||
250 | for (j = 0; j < 1 << (INFLATE_FAST_BITS9 - len); j++, codeword++) { | |||
251 | int index = Huffman_ReverseBits(codeword, INFLATE_FAST_BITS9); | |||
252 | table->Fast[index] = packed; | |||
253 | } | |||
254 | } | |||
255 | bl_offsets[len]++; | |||
256 | } | |||
257 | return 0; | |||
258 | } | |||
259 | ||||
260 | /* Attempts to read the next huffman encoded value from the bitstream, using given table */ | |||
261 | /* Returns -1 if there are insufficient bits to read the value */ | |||
262 | static int Huffman_Decode(struct InflateState* state, struct HuffmanTable* table) { | |||
263 | cc_uint32 i, j, codeword; | |||
264 | int packed, bits, offset; | |||
265 | ||||
266 | /* Buffer as many bits as possible */ | |||
267 | while (state->NumBits <= INFLATE_MAX_BITS16) { | |||
268 | if (!state->AvailIn) break; | |||
269 | Inflate_GetByte(state)state->AvailIn--; state->Bits |= (cc_uint32)(*state-> NextIn++) << state->NumBits; state->NumBits += 8;; | |||
270 | } | |||
271 | ||||
272 | /* Try fast accelerated table lookup */ | |||
273 | if (state->NumBits >= INFLATE_FAST_BITS9) { | |||
274 | packed = table->Fast[Inflate_PeekBits(state, INFLATE_FAST_BITS)(state->Bits & ((1UL << (9)) - 1UL))]; | |||
275 | if (packed >= 0) { | |||
276 | bits = packed >> INFLATE_FAST_BITS9; | |||
277 | Inflate_ConsumeBits(state, bits)state->Bits >>= (bits); state->NumBits -= (bits);; | |||
278 | return packed & 0x1FF; | |||
279 | } | |||
280 | } | |||
281 | ||||
282 | /* Slow, bit by bit lookup */ | |||
283 | codeword = 0; | |||
284 | for (i = 1, j = 0; i < INFLATE_MAX_BITS16; i++, j++) { | |||
285 | if (state->NumBits < i) return -1; | |||
286 | codeword = (codeword << 1) | ((state->Bits >> j) & 1); | |||
287 | ||||
288 | if (codeword < table->EndCodewords[i]) { | |||
289 | offset = table->FirstOffsets[i] + (codeword - table->FirstCodewords[i]); | |||
290 | Inflate_ConsumeBits(state, i)state->Bits >>= (i); state->NumBits -= (i);; | |||
291 | return table->Values[offset]; | |||
292 | } | |||
293 | } | |||
294 | ||||
295 | Inflate_Fail(state, INF_ERR_INVALID_CODE)state->result = INF_ERR_INVALID_CODE; state->State = INFLATE_STATE_DONE ;; | |||
296 | return -1; | |||
297 | } | |||
298 | ||||
299 | /* Inline the common <= 9 bits case */ | |||
300 | #define Huffman_UNSAFE_Decode(state, table, result){ while (state->NumBits < 16) { state->AvailIn--; state ->Bits |= (cc_uint32)(*state->NextIn++) << state-> NumBits; state->NumBits += 8;; }; packed = table.Fast[(state ->Bits & ((1UL << (9)) - 1UL))]; if (packed >= 0) { consumedBits = packed >> 9; state->Bits >>= (consumedBits); state->NumBits -= (consumedBits);; result = packed & 0x1FF; } else { result = Huffman_UNSAFE_Decode_Slow (state, &table); }} \ | |||
301 | {\ | |||
302 | Inflate_UNSAFE_EnsureBits(state, INFLATE_MAX_BITS)while (state->NumBits < 16) { state->AvailIn--; state ->Bits |= (cc_uint32)(*state->NextIn++) << state-> NumBits; state->NumBits += 8;; };\ | |||
303 | packed = table.Fast[Inflate_PeekBits(state, INFLATE_FAST_BITS)(state->Bits & ((1UL << (9)) - 1UL))];\ | |||
304 | if (packed >= 0) {\ | |||
305 | consumedBits = packed >> INFLATE_FAST_BITS9;\ | |||
306 | Inflate_ConsumeBits(state, consumedBits)state->Bits >>= (consumedBits); state->NumBits -= (consumedBits);;\ | |||
307 | result = packed & 0x1FF;\ | |||
308 | } else {\ | |||
309 | result = Huffman_UNSAFE_Decode_Slow(state, &table);\ | |||
310 | }\ | |||
311 | } | |||
312 | ||||
313 | static int Huffman_UNSAFE_Decode_Slow(struct InflateState* state, struct HuffmanTable* table) { | |||
314 | cc_uint32 i, j, codeword; | |||
315 | int offset; | |||
316 | ||||
317 | /* Slow, bit by bit lookup. Need to reverse order for huffman. */ | |||
318 | codeword = Inflate_PeekBits(state, INFLATE_FAST_BITS)(state->Bits & ((1UL << (9)) - 1UL)); | |||
319 | codeword = Huffman_ReverseBits(codeword, INFLATE_FAST_BITS9); | |||
320 | ||||
321 | for (i = INFLATE_FAST_BITS9 + 1, j = INFLATE_FAST_BITS9; i < INFLATE_MAX_BITS16; i++, j++) { | |||
322 | codeword = (codeword << 1) | ((state->Bits >> j) & 1); | |||
323 | ||||
324 | if (codeword < table->EndCodewords[i]) { | |||
325 | offset = table->FirstOffsets[i] + (codeword - table->FirstCodewords[i]); | |||
326 | Inflate_ConsumeBits(state, i)state->Bits >>= (i); state->NumBits -= (i);; | |||
327 | return table->Values[offset]; | |||
328 | } | |||
329 | } | |||
330 | ||||
331 | Inflate_Fail(state, INF_ERR_INVALID_CODE)state->result = INF_ERR_INVALID_CODE; state->State = INFLATE_STATE_DONE ;; | |||
332 | /* Need to exit the fast decode loop */ | |||
333 | /* TODO: This means a few garbage bytes can get written */ | |||
334 | /* to the output, but it probably doesn't matter */ | |||
335 | state->AvailIn = 0; | |||
336 | return 0; | |||
337 | } | |||
338 | ||||
339 | void Inflate_Init2(struct InflateState* state, struct Stream* source) { | |||
340 | state->State = INFLATE_STATE_HEADER; | |||
341 | state->LastBlock = false0; | |||
342 | state->Bits = 0; | |||
343 | state->NumBits = 0; | |||
344 | state->NextIn = state->Input; | |||
345 | state->AvailIn = 0; | |||
346 | state->Output = NULL((void*)0); | |||
347 | state->AvailOut = 0; | |||
348 | state->Source = source; | |||
349 | state->WindowIndex = 0; | |||
350 | state->result = 0; | |||
351 | } | |||
352 | ||||
353 | static const cc_uint8 fixed_lits[INFLATE_MAX_LITS288] = { | |||
354 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | |||
355 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | |||
356 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | |||
357 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, | |||
358 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, | |||
359 | 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, | |||
360 | 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, | |||
361 | 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, | |||
362 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 | |||
363 | }; | |||
364 | static const cc_uint8 fixed_dists[INFLATE_MAX_DISTS32] = { | |||
365 | 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 | |||
366 | }; | |||
367 | ||||
368 | static const cc_uint16 len_base[31] = { | |||
369 | 3,4,5,6,7,8,9,10,11,13, | |||
370 | 15,17,19,23,27,31,35,43,51,59, | |||
371 | 67,83,99,115,131,163,195,227,258,0,0 | |||
372 | }; | |||
373 | static const cc_uint8 len_bits[31] = { | |||
374 | 0,0,0,0,0,0,0,0,1,1, | |||
375 | 1,1,2,2,2,2,3,3,3,3, | |||
376 | 4,4,4,4,5,5,5,5,0,0,0 | |||
377 | }; | |||
378 | static const cc_uint16 dist_base[32] = { | |||
379 | 1,2,3,4,5,7,9,13,17,25, | |||
380 | 33,49,65,97,129,193,257,385,513,769, | |||
381 | 1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0 | |||
382 | }; | |||
383 | static const cc_uint8 dist_bits[32] = { | |||
384 | 0,0,0,0,1,1,2,2,3,3, | |||
385 | 4,4,5,5,6,6,7,7,8,8, | |||
386 | 9,9,10,10,11,11,12,12,13,13,0,0 | |||
387 | }; | |||
388 | static const cc_uint8 codelens_order[INFLATE_MAX_CODELENS19] = { | |||
389 | 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 | |||
390 | }; | |||
391 | ||||
392 | static void Inflate_InflateFast(struct InflateState* s) { | |||
393 | /* huffman variables */ | |||
394 | cc_uint32 lit, len, dist; | |||
395 | cc_uint32 bits, lenIdx, distIdx; | |||
396 | int packed, consumedBits; | |||
397 | ||||
398 | /* window variables */ | |||
399 | cc_uint8* window; | |||
400 | cc_uint32 i, curIdx, startIdx; | |||
401 | cc_uint32 copyStart, copyLen, partLen; | |||
402 | ||||
403 | window = s->Window; | |||
404 | curIdx = s->WindowIndex; | |||
405 | copyStart = s->WindowIndex; | |||
406 | copyLen = 0; | |||
407 | ||||
408 | #define INFLATE_FAST_COPY_MAX(0x8000UL - 258) (INFLATE_WINDOW_SIZE0x8000UL - INFLATE_FASTINF_OUT258) | |||
409 | while (s->AvailOut >= INFLATE_FASTINF_OUT258 && s->AvailIn >= INFLATE_FASTINF_IN10 && copyLen < INFLATE_FAST_COPY_MAX(0x8000UL - 258)) { | |||
410 | Huffman_UNSAFE_Decode(s, s->Table.Lits, lit){ while (s->NumBits < 16) { s->AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s-> NumBits += 8;; }; packed = s->Table.Lits.Fast[(s->Bits & ((1UL << (9)) - 1UL))]; if (packed >= 0) { consumedBits = packed >> 9; s->Bits >>= (consumedBits); s-> NumBits -= (consumedBits);; lit = packed & 0x1FF; } else { lit = Huffman_UNSAFE_Decode_Slow(s, &s->Table.Lits); } }; | |||
411 | ||||
412 | if (lit <= 256) { | |||
413 | if (lit < 256) { | |||
414 | window[curIdx] = (cc_uint8)lit; | |||
415 | s->AvailOut--; copyLen++; | |||
416 | curIdx = (curIdx + 1) & INFLATE_WINDOW_MASK0x7FFFUL; | |||
417 | } else { | |||
418 | s->State = Inflate_NextBlockState(s)(s->LastBlock ? INFLATE_STATE_DONE : INFLATE_STATE_HEADER); | |||
419 | break; | |||
420 | } | |||
421 | } else { | |||
422 | lenIdx = lit - 257; | |||
423 | bits = len_bits[lenIdx]; | |||
424 | Inflate_UNSAFE_EnsureBits(s, bits)while (s->NumBits < bits) { s->AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s-> NumBits += 8;; }; | |||
425 | len = len_base[lenIdx] + Inflate_ReadBits(s, bits)(s->Bits & ((1UL << (bits)) - 1UL)); s->Bits >>= (bits); s->NumBits -= (bits);;; | |||
426 | ||||
427 | Huffman_UNSAFE_Decode(s, s->TableDists, distIdx){ while (s->NumBits < 16) { s->AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s-> NumBits += 8;; }; packed = s->TableDists.Fast[(s->Bits & ((1UL << (9)) - 1UL))]; if (packed >= 0) { consumedBits = packed >> 9; s->Bits >>= (consumedBits); s-> NumBits -= (consumedBits);; distIdx = packed & 0x1FF; } else { distIdx = Huffman_UNSAFE_Decode_Slow(s, &s->TableDists ); }}; | |||
428 | bits = dist_bits[distIdx]; | |||
429 | Inflate_UNSAFE_EnsureBits(s, bits)while (s->NumBits < bits) { s->AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s-> NumBits += 8;; }; | |||
430 | dist = dist_base[distIdx] + Inflate_ReadBits(s, bits)(s->Bits & ((1UL << (bits)) - 1UL)); s->Bits >>= (bits); s->NumBits -= (bits);;; | |||
431 | ||||
432 | /* Window infinitely repeats like ...xyz|uvwxyz|uvwxyz|uvw... */ | |||
433 | /* If start and end don't cross a boundary, can avoid masking index */ | |||
434 | startIdx = (curIdx - dist) & INFLATE_WINDOW_MASK0x7FFFUL; | |||
435 | if (curIdx >= startIdx && (curIdx + len) < INFLATE_WINDOW_SIZE0x8000UL) { | |||
436 | cc_uint8* src = &window[startIdx]; | |||
437 | cc_uint8* dst = &window[curIdx]; | |||
438 | ||||
439 | for (i = 0; i < (len & ~0x3); i += 4) { | |||
440 | *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; | |||
441 | } | |||
442 | for (; i < len; i++) { *dst++ = *src++; } | |||
443 | } else { | |||
444 | for (i = 0; i < len; i++) { | |||
445 | window[(curIdx + i) & INFLATE_WINDOW_MASK0x7FFFUL] = window[(startIdx + i) & INFLATE_WINDOW_MASK0x7FFFUL]; | |||
446 | } | |||
447 | } | |||
448 | curIdx = (curIdx + len) & INFLATE_WINDOW_MASK0x7FFFUL; | |||
449 | s->AvailOut -= len; copyLen += len; | |||
450 | } | |||
451 | } | |||
452 | ||||
453 | s->WindowIndex = curIdx; | |||
454 | if (!copyLen) return; | |||
455 | ||||
456 | if (copyStart + copyLen < INFLATE_WINDOW_SIZE0x8000UL) { | |||
457 | Mem_Copy(s->Output, &s->Window[copyStart], copyLen); | |||
458 | s->Output += copyLen; | |||
459 | } else { | |||
460 | partLen = INFLATE_WINDOW_SIZE0x8000UL - copyStart; | |||
461 | Mem_Copy(s->Output, &s->Window[copyStart], partLen); | |||
462 | s->Output += partLen; | |||
463 | Mem_Copy(s->Output, s->Window, copyLen - partLen); | |||
464 | s->Output += (copyLen - partLen); | |||
465 | } | |||
466 | } | |||
467 | ||||
468 | void Inflate_Process(struct InflateState* s) { | |||
469 | cc_uint32 len, dist, nlen; | |||
470 | cc_uint32 i, bits; | |||
471 | cc_uint32 blockHeader; | |||
472 | cc_result res; | |||
473 | ||||
474 | /* len/dist table variables */ | |||
475 | cc_uint32 distIdx, lenIdx; | |||
476 | int lit; | |||
477 | /* code lens table variables */ | |||
478 | cc_uint32 count, repeatCount; | |||
| ||||
479 | cc_uint8 repeatValue; | |||
480 | /* window variables */ | |||
481 | cc_uint32 startIdx, curIdx; | |||
482 | cc_uint32 copyLen, windowCopyLen; | |||
483 | ||||
484 | for (;;) { | |||
485 | switch (s->State) { | |||
486 | case INFLATE_STATE_HEADER: { | |||
487 | Inflate_EnsureBits(s, 3)while (s->NumBits < 3) { if (!s->AvailIn) return; s-> AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s->NumBits += 8;; }; | |||
488 | blockHeader = Inflate_ReadBits(s, 3)(s->Bits & ((1UL << (3)) - 1UL)); s->Bits >>= (3); s->NumBits -= (3);;; | |||
489 | s->LastBlock = blockHeader & 1; | |||
490 | ||||
491 | switch (blockHeader >> 1) { | |||
492 | case 0: { /* Uncompressed block */ | |||
493 | Inflate_AlignBits(s)cc_uint32 alignSkip = s->NumBits & 7; s->Bits >>= (alignSkip); s->NumBits -= (alignSkip);;; | |||
494 | s->State = INFLATE_STATE_UNCOMPRESSED_HEADER; | |||
495 | } break; | |||
496 | ||||
497 | case 1: { /* Fixed/static huffman compressed */ | |||
498 | (void)Huffman_Build(&s->Table.Lits, fixed_lits, INFLATE_MAX_LITS288); | |||
499 | (void)Huffman_Build(&s->TableDists, fixed_dists, INFLATE_MAX_DISTS32); | |||
500 | s->State = Inflate_NextCompressState(s)((s->AvailIn >= 10 && s->AvailOut >= 258) ? INFLATE_STATE_FASTCOMPRESSED : INFLATE_STATE_COMPRESSED_LIT ); | |||
501 | } break; | |||
502 | ||||
503 | case 2: { /* Dynamic huffman compressed */ | |||
504 | s->State = INFLATE_STATE_DYNAMIC_HEADER; | |||
505 | } break; | |||
506 | ||||
507 | case 3: { | |||
508 | Inflate_Fail(s, INF_ERR_BLOCKTYPE)s->result = INF_ERR_BLOCKTYPE; s->State = INFLATE_STATE_DONE ;; | |||
509 | } break; | |||
510 | ||||
511 | } | |||
512 | break; | |||
513 | } | |||
514 | ||||
515 | case INFLATE_STATE_UNCOMPRESSED_HEADER: { | |||
516 | Inflate_EnsureBits(s, 32)while (s->NumBits < 32) { if (!s->AvailIn) return; s ->AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s->NumBits += 8;; }; | |||
517 | len = Inflate_ReadBits(s, 16)(s->Bits & ((1UL << (16)) - 1UL)); s->Bits >>= (16); s->NumBits -= (16);;; | |||
518 | nlen = Inflate_ReadBits(s, 16)(s->Bits & ((1UL << (16)) - 1UL)); s->Bits >>= (16); s->NumBits -= (16);;; | |||
519 | ||||
520 | if (len != (nlen ^ 0xFFFFUL)) { | |||
521 | Inflate_Fail(s, INF_ERR_BLOCKTYPE)s->result = INF_ERR_BLOCKTYPE; s->State = INFLATE_STATE_DONE ;; return; | |||
522 | } | |||
523 | s->Index = len; /* Reuse for 'uncompressed length' */ | |||
524 | s->State = INFLATE_STATE_UNCOMPRESSED_DATA; | |||
525 | } | |||
526 | ||||
527 | case INFLATE_STATE_UNCOMPRESSED_DATA: { | |||
528 | /* read bits left in bit buffer (slow way) */ | |||
529 | while (s->NumBits && s->AvailOut && s->Index) { | |||
530 | *s->Output = Inflate_ReadBits(s, 8)(s->Bits & ((1UL << (8)) - 1UL)); s->Bits >>= (8); s->NumBits -= (8);;; | |||
531 | s->Window[s->WindowIndex] = *s->Output; | |||
532 | ||||
533 | s->WindowIndex = (s->WindowIndex + 1) & INFLATE_WINDOW_MASK0x7FFFUL; | |||
534 | s->Output++; s->AvailOut--; s->Index--; | |||
535 | } | |||
536 | if (!s->AvailIn || !s->AvailOut) return; | |||
537 | ||||
538 | copyLen = min(s->AvailIn, s->AvailOut)((s->AvailIn) < (s->AvailOut) ? (s->AvailIn) : (s ->AvailOut)); | |||
539 | copyLen = min(copyLen, s->Index)((copyLen) < (s->Index) ? (copyLen) : (s->Index)); | |||
540 | if (copyLen > 0) { | |||
541 | Mem_Copy(s->Output, s->NextIn, copyLen); | |||
542 | windowCopyLen = INFLATE_WINDOW_SIZE0x8000UL - s->WindowIndex; | |||
543 | windowCopyLen = min(windowCopyLen, copyLen)((windowCopyLen) < (copyLen) ? (windowCopyLen) : (copyLen) ); | |||
544 | ||||
545 | Mem_Copy(&s->Window[s->WindowIndex], s->Output, windowCopyLen); | |||
546 | /* Wrap around remainder of copy to start from beginning of window */ | |||
547 | if (windowCopyLen < copyLen) { | |||
548 | Mem_Copy(s->Window, &s->Output[windowCopyLen], copyLen - windowCopyLen); | |||
549 | } | |||
550 | ||||
551 | s->WindowIndex = (s->WindowIndex + copyLen) & INFLATE_WINDOW_MASK0x7FFFUL; | |||
552 | s->Output += copyLen; s->AvailOut -= copyLen; s->Index -= copyLen; | |||
553 | s->NextIn += copyLen; s->AvailIn -= copyLen; | |||
554 | } | |||
555 | ||||
556 | if (!s->Index) { s->State = Inflate_NextBlockState(s)(s->LastBlock ? INFLATE_STATE_DONE : INFLATE_STATE_HEADER); } | |||
557 | break; | |||
558 | } | |||
559 | ||||
560 | case INFLATE_STATE_DYNAMIC_HEADER: { | |||
561 | Inflate_EnsureBits(s, 14)while (s->NumBits < 14) { if (!s->AvailIn) return; s ->AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s->NumBits += 8;; }; | |||
562 | s->NumLits = 257 + Inflate_ReadBits(s, 5)(s->Bits & ((1UL << (5)) - 1UL)); s->Bits >>= (5); s->NumBits -= (5);;; | |||
563 | s->NumDists = 1 + Inflate_ReadBits(s, 5)(s->Bits & ((1UL << (5)) - 1UL)); s->Bits >>= (5); s->NumBits -= (5);;; | |||
564 | s->NumCodeLens = 4 + Inflate_ReadBits(s, 4)(s->Bits & ((1UL << (4)) - 1UL)); s->Bits >>= (4); s->NumBits -= (4);;; | |||
565 | s->Index = 0; | |||
566 | s->State = INFLATE_STATE_DYNAMIC_CODELENS; | |||
567 | } | |||
568 | ||||
569 | case INFLATE_STATE_DYNAMIC_CODELENS: { | |||
570 | while (s->Index < s->NumCodeLens) { | |||
571 | Inflate_EnsureBits(s, 3)while (s->NumBits < 3) { if (!s->AvailIn) return; s-> AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s->NumBits += 8;; }; | |||
572 | i = codelens_order[s->Index]; | |||
573 | s->Buffer[i] = Inflate_ReadBits(s, 3)(s->Bits & ((1UL << (3)) - 1UL)); s->Bits >>= (3); s->NumBits -= (3);;; | |||
574 | s->Index++; | |||
575 | } | |||
576 | for (i = s->NumCodeLens; i < INFLATE_MAX_CODELENS19; i++) { | |||
577 | s->Buffer[codelens_order[i]] = 0; | |||
578 | } | |||
579 | ||||
580 | s->Index = 0; | |||
581 | s->State = INFLATE_STATE_DYNAMIC_LITSDISTS; | |||
582 | res = Huffman_Build(&s->Table.CodeLens, s->Buffer, INFLATE_MAX_CODELENS19); | |||
583 | if (res) { Inflate_Fail(s, res)s->result = res; s->State = INFLATE_STATE_DONE;; return; } | |||
584 | } | |||
585 | ||||
586 | case INFLATE_STATE_DYNAMIC_LITSDISTS: { | |||
587 | count = s->NumLits + s->NumDists; | |||
588 | while (s->Index < count) { | |||
589 | int bits = Huffman_Decode(s, &s->Table.CodeLens); | |||
590 | if (bits < 16) { | |||
591 | if (bits == -1) return; | |||
592 | s->Buffer[s->Index] = (cc_uint8)bits; | |||
593 | s->Index++; | |||
594 | } else { | |||
595 | s->TmpCodeLens = bits; | |||
596 | s->State = INFLATE_STATE_DYNAMIC_LITSDISTSREPEAT; | |||
597 | break; | |||
598 | } | |||
599 | } | |||
600 | ||||
601 | if (s->Index == count) { | |||
602 | s->Index = 0; | |||
603 | s->State = Inflate_NextCompressState(s)((s->AvailIn >= 10 && s->AvailOut >= 258) ? INFLATE_STATE_FASTCOMPRESSED : INFLATE_STATE_COMPRESSED_LIT ); | |||
604 | ||||
605 | res = Huffman_Build(&s->Table.Lits, s->Buffer, s->NumLits); | |||
606 | if (res) { Inflate_Fail(s, res)s->result = res; s->State = INFLATE_STATE_DONE;; return; } | |||
607 | res = Huffman_Build(&s->TableDists, s->Buffer + s->NumLits, s->NumDists); | |||
608 | if (res) { Inflate_Fail(s, res)s->result = res; s->State = INFLATE_STATE_DONE;; return; } | |||
609 | } | |||
610 | break; | |||
611 | } | |||
612 | ||||
613 | case INFLATE_STATE_DYNAMIC_LITSDISTSREPEAT: { | |||
614 | switch (s->TmpCodeLens) { | |||
615 | case 16: | |||
616 | Inflate_EnsureBits(s, 2)while (s->NumBits < 2) { if (!s->AvailIn) return; s-> AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s->NumBits += 8;; }; | |||
617 | repeatCount = Inflate_ReadBits(s, 2)(s->Bits & ((1UL << (2)) - 1UL)); s->Bits >>= (2); s->NumBits -= (2);;; | |||
618 | if (!s->Index) { Inflate_Fail(s, INF_ERR_REPEAT_BEG)s->result = INF_ERR_REPEAT_BEG; s->State = INFLATE_STATE_DONE ;; return; } | |||
619 | repeatCount += 3; repeatValue = s->Buffer[s->Index - 1]; | |||
620 | break; | |||
621 | ||||
622 | case 17: | |||
623 | Inflate_EnsureBits(s, 3)while (s->NumBits < 3) { if (!s->AvailIn) return; s-> AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s->NumBits += 8;; }; | |||
624 | repeatCount = Inflate_ReadBits(s, 3)(s->Bits & ((1UL << (3)) - 1UL)); s->Bits >>= (3); s->NumBits -= (3);;; | |||
625 | repeatCount += 3; repeatValue = 0; | |||
626 | break; | |||
627 | ||||
628 | case 18: | |||
629 | Inflate_EnsureBits(s, 7)while (s->NumBits < 7) { if (!s->AvailIn) return; s-> AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s->NumBits += 8;; }; | |||
630 | repeatCount = Inflate_ReadBits(s, 7)(s->Bits & ((1UL << (7)) - 1UL)); s->Bits >>= (7); s->NumBits -= (7);;; | |||
631 | repeatCount += 11; repeatValue = 0; | |||
632 | break; | |||
633 | } | |||
634 | ||||
635 | count = s->NumLits + s->NumDists; | |||
636 | if (s->Index + repeatCount > count) { | |||
| ||||
637 | Inflate_Fail(s, INF_ERR_REPEAT_END)s->result = INF_ERR_REPEAT_END; s->State = INFLATE_STATE_DONE ;; return; | |||
638 | } | |||
639 | ||||
640 | Mem_Set(&s->Buffer[s->Index], repeatValue, repeatCount); | |||
641 | s->Index += repeatCount; | |||
642 | s->State = INFLATE_STATE_DYNAMIC_LITSDISTS; | |||
643 | break; | |||
644 | } | |||
645 | ||||
646 | case INFLATE_STATE_COMPRESSED_LIT: { | |||
647 | if (!s->AvailOut) return; | |||
648 | lit = Huffman_Decode(s, &s->Table.Lits); | |||
649 | ||||
650 | if (lit < 256) { | |||
651 | if (lit == -1) return; | |||
652 | *s->Output = (cc_uint8)lit; | |||
653 | s->Window[s->WindowIndex] = (cc_uint8)lit; | |||
654 | s->Output++; s->AvailOut--; | |||
655 | s->WindowIndex = (s->WindowIndex + 1) & INFLATE_WINDOW_MASK0x7FFFUL; | |||
656 | break; | |||
657 | } else if (lit == 256) { | |||
658 | s->State = Inflate_NextBlockState(s)(s->LastBlock ? INFLATE_STATE_DONE : INFLATE_STATE_HEADER); | |||
659 | break; | |||
660 | } else { | |||
661 | s->TmpLit = lit - 257; | |||
662 | s->State = INFLATE_STATE_COMPRESSED_LITEXTRA; | |||
663 | } | |||
664 | } | |||
665 | ||||
666 | case INFLATE_STATE_COMPRESSED_LITEXTRA: { | |||
667 | lenIdx = s->TmpLit; | |||
668 | bits = len_bits[lenIdx]; | |||
669 | Inflate_EnsureBits(s, bits)while (s->NumBits < bits) { if (!s->AvailIn) return; s->AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s->NumBits += 8;; }; | |||
670 | s->TmpLit = len_base[lenIdx] + Inflate_ReadBits(s, bits)(s->Bits & ((1UL << (bits)) - 1UL)); s->Bits >>= (bits); s->NumBits -= (bits);;; | |||
671 | s->State = INFLATE_STATE_COMPRESSED_DIST; | |||
672 | } | |||
673 | ||||
674 | case INFLATE_STATE_COMPRESSED_DIST: { | |||
675 | s->TmpDist = Huffman_Decode(s, &s->TableDists); | |||
676 | if (s->TmpDist == -1) return; | |||
677 | s->State = INFLATE_STATE_COMPRESSED_DISTEXTRA; | |||
678 | } | |||
679 | ||||
680 | case INFLATE_STATE_COMPRESSED_DISTEXTRA: { | |||
681 | distIdx = s->TmpDist; | |||
682 | bits = dist_bits[distIdx]; | |||
683 | Inflate_EnsureBits(s, bits)while (s->NumBits < bits) { if (!s->AvailIn) return; s->AvailIn--; s->Bits |= (cc_uint32)(*s->NextIn++) << s->NumBits; s->NumBits += 8;; }; | |||
684 | s->TmpDist = dist_base[distIdx] + Inflate_ReadBits(s, bits)(s->Bits & ((1UL << (bits)) - 1UL)); s->Bits >>= (bits); s->NumBits -= (bits);;; | |||
685 | s->State = INFLATE_STATE_COMPRESSED_DATA; | |||
686 | } | |||
687 | ||||
688 | case INFLATE_STATE_COMPRESSED_DATA: { | |||
689 | if (!s->AvailOut) return; | |||
690 | len = s->TmpLit; dist = s->TmpDist; | |||
691 | len = min(len, s->AvailOut)((len) < (s->AvailOut) ? (len) : (s->AvailOut)); | |||
692 | ||||
693 | /* TODO: Should we test outside of the loop, whether a masking will be required or not? */ | |||
694 | startIdx = (s->WindowIndex - dist) & INFLATE_WINDOW_MASK0x7FFFUL; | |||
695 | curIdx = s->WindowIndex; | |||
696 | for (i = 0; i < len; i++) { | |||
697 | cc_uint8 value = s->Window[(startIdx + i) & INFLATE_WINDOW_MASK0x7FFFUL]; | |||
698 | *s->Output = value; | |||
699 | s->Window[(curIdx + i) & INFLATE_WINDOW_MASK0x7FFFUL] = value; | |||
700 | s->Output++; | |||
701 | } | |||
702 | ||||
703 | s->WindowIndex = (curIdx + len) & INFLATE_WINDOW_MASK0x7FFFUL; | |||
704 | s->TmpLit -= len; | |||
705 | s->AvailOut -= len; | |||
706 | if (!s->TmpLit) { s->State = Inflate_NextCompressState(s)((s->AvailIn >= 10 && s->AvailOut >= 258) ? INFLATE_STATE_FASTCOMPRESSED : INFLATE_STATE_COMPRESSED_LIT ); } | |||
707 | break; | |||
708 | } | |||
709 | ||||
710 | case INFLATE_STATE_FASTCOMPRESSED: { | |||
711 | Inflate_InflateFast(s); | |||
712 | if (s->State == INFLATE_STATE_FASTCOMPRESSED) { | |||
713 | s->State = Inflate_NextCompressState(s)((s->AvailIn >= 10 && s->AvailOut >= 258) ? INFLATE_STATE_FASTCOMPRESSED : INFLATE_STATE_COMPRESSED_LIT ); | |||
714 | } | |||
715 | break; | |||
716 | } | |||
717 | ||||
718 | case INFLATE_STATE_DONE: | |||
719 | return; | |||
720 | } | |||
721 | } | |||
722 | } | |||
723 | ||||
724 | static cc_result Inflate_StreamRead(struct Stream* stream, cc_uint8* data, cc_uint32 count, cc_uint32* modified) { | |||
725 | struct InflateState* state; | |||
726 | cc_uint8* inputEnd; | |||
727 | cc_uint32 read, left; | |||
728 | cc_uint32 startAvailOut; | |||
729 | cc_bool hasInput; | |||
730 | cc_result res; | |||
731 | ||||
732 | *modified = 0; | |||
733 | state = (struct InflateState*)stream->Meta.Inflate; | |||
734 | state->Output = data; | |||
735 | state->AvailOut = count; | |||
736 | ||||
737 | hasInput = true1; | |||
738 | while (state->AvailOut > 0 && hasInput) { | |||
739 | if (state->State == INFLATE_STATE_DONE) return state->result; | |||
740 | ||||
741 | if (!state->AvailIn) { | |||
742 | /* Fully used up input buffer. Cycle back to start. */ | |||
743 | inputEnd = state->Input + INFLATE_MAX_INPUT8192; | |||
744 | if (state->NextIn == inputEnd) state->NextIn = state->Input; | |||
745 | ||||
746 | left = (cc_uint32)(inputEnd - state->NextIn); | |||
747 | res = state->Source->Read(state->Source, state->NextIn, left, &read); | |||
748 | if (res) return res; | |||
749 | ||||
750 | /* Did we fail to read in more input data? Can't immediately return here, */ | |||
751 | /* because there might be a few bits of data left in the bit buffer */ | |||
752 | hasInput = read > 0; | |||
753 | state->AvailIn += read; | |||
754 | } | |||
755 | ||||
756 | /* Reading data reduces available out */ | |||
757 | startAvailOut = state->AvailOut; | |||
758 | Inflate_Process(state); | |||
759 | *modified += (startAvailOut - state->AvailOut); | |||
760 | } | |||
761 | return 0; | |||
762 | } | |||
763 | ||||
764 | void Inflate_MakeStream2(struct Stream* stream, struct InflateState* state, struct Stream* underlying) { | |||
765 | Stream_Init(stream); | |||
766 | Inflate_Init2(state, underlying); | |||
767 | stream->Meta.Inflate = state; | |||
768 | stream->Read = Inflate_StreamRead; | |||
769 | } | |||
770 | ||||
771 | ||||
772 | /*########################################################################################################################* | |||
773 | *---------------------------------------------------Deflate (compress)----------------------------------------------------* | |||
774 | *#########################################################################################################################*/ | |||
775 | /* these are copies of len_base and dist_base, with UINT16_MAX instead of 0 for sentinel cutoff */ | |||
776 | static const cc_uint16 deflate_len[30] = { | |||
777 | 3,4,5,6,7,8,9,10,11,13, | |||
778 | 15,17,19,23,27,31,35,43,51,59, | |||
779 | 67,83,99,115,131,163,195,227,258,UInt16_MaxValue((cc_uint16)65535) | |||
780 | }; | |||
781 | static const cc_uint16 deflate_dist[31] = { | |||
782 | 1,2,3,4,5,7,9,13,17,25, | |||
783 | 33,49,65,97,129,193,257,385,513,769, | |||
784 | 1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,UInt16_MaxValue((cc_uint16)65535) | |||
785 | }; | |||
786 | ||||
787 | /* Pushes given bits, but does not write them */ | |||
788 | #define Deflate_PushBits(state, value, bits)state->Bits |= (value) << state->NumBits; state-> NumBits += (bits); state->Bits |= (value) << state->NumBits; state->NumBits += (bits); | |||
789 | /* Pushes bits of the huffman codeword bits for the given literal, but does not write them */ | |||
790 | #define Deflate_PushLit(state, value)state->Bits |= (state->LitsCodewords[value]) << state ->NumBits; state->NumBits += (state->LitsLens[value] ); Deflate_PushBits(state, state->LitsCodewords[value], state->LitsLens[value])state->Bits |= (state->LitsCodewords[value]) << state ->NumBits; state->NumBits += (state->LitsLens[value] ); | |||
791 | /* Pushes given bits (reversing for huffman code), but does not write them */ | |||
792 | #define Deflate_PushHuff(state, value, bits)state->Bits |= (Huffman_ReverseBits(value, bits)) << state->NumBits; state->NumBits += (bits); Deflate_PushBits(state, Huffman_ReverseBits(value, bits), bits)state->Bits |= (Huffman_ReverseBits(value, bits)) << state->NumBits; state->NumBits += (bits); | |||
793 | /* Writes given byte to output */ | |||
794 | #define Deflate_WriteByte(state)*state->NextOut++ = state->Bits; state->AvailOut--; state ->Bits >>= 8; state->NumBits -= 8; *state->NextOut++ = state->Bits; state->AvailOut--; state->Bits >>= 8; state->NumBits -= 8; | |||
795 | /* Flushes bits in buffer to output buffer */ | |||
796 | #define Deflate_FlushBits(state)while (state->NumBits >= 8) { *state->NextOut++ = state ->Bits; state->AvailOut--; state->Bits >>= 8; state ->NumBits -= 8;; } while (state->NumBits >= 8) { Deflate_WriteByte(state)*state->NextOut++ = state->Bits; state->AvailOut--; state ->Bits >>= 8; state->NumBits -= 8;; } | |||
797 | ||||
798 | #define MIN_MATCH_LEN3 3 | |||
799 | #define MAX_MATCH_LEN258 258 | |||
800 | ||||
801 | /* Number of bytes that match (are the same) from a and b */ | |||
802 | static int Deflate_MatchLen(cc_uint8* a, cc_uint8* b, int maxLen) { | |||
803 | int i = 0; | |||
804 | while (i < maxLen && *a == *b) { i++; a++; b++; } | |||
805 | return i; | |||
806 | } | |||
807 | ||||
808 | /* Hashes 3 bytes of data */ | |||
809 | static cc_uint32 Deflate_Hash(cc_uint8* src) { | |||
810 | return (cc_uint32)((src[0] << 8) ^ (src[1] << 4) ^ (src[2])) & DEFLATE_HASH_MASK0x0FFFUL; | |||
811 | } | |||
812 | ||||
813 | /* Writes a literal to state->Output */ | |||
814 | static void Deflate_Lit(struct DeflateState* state, int lit) { | |||
815 | Deflate_PushLit(state, lit)state->Bits |= (state->LitsCodewords[lit]) << state ->NumBits; state->NumBits += (state->LitsLens[lit]);; | |||
816 | Deflate_FlushBits(state)while (state->NumBits >= 8) { *state->NextOut++ = state ->Bits; state->AvailOut--; state->Bits >>= 8; state ->NumBits -= 8;; }; | |||
817 | } | |||
818 | ||||
819 | /* Writes a length-distance pair to state->Output */ | |||
820 | static void Deflate_LenDist(struct DeflateState* state, int len, int dist) { | |||
821 | int j; | |||
822 | /* TODO: Do we actually need the if (len_bits[j]) ????????? does writing 0 bits matter??? */ | |||
823 | ||||
824 | for (j = 0; len >= deflate_len[j + 1]; j++); | |||
825 | Deflate_PushLit(state, j + 257)state->Bits |= (state->LitsCodewords[j + 257]) << state->NumBits; state->NumBits += (state->LitsLens[ j + 257]);; | |||
826 | if (len_bits[j]) { Deflate_PushBits(state, len - deflate_len[j], len_bits[j])state->Bits |= (len - deflate_len[j]) << state->NumBits ; state->NumBits += (len_bits[j]);; } | |||
827 | Deflate_FlushBits(state)while (state->NumBits >= 8) { *state->NextOut++ = state ->Bits; state->AvailOut--; state->Bits >>= 8; state ->NumBits -= 8;; }; | |||
828 | ||||
829 | for (j = 0; dist >= deflate_dist[j + 1]; j++); | |||
830 | Deflate_PushHuff(state, j, 5)state->Bits |= (Huffman_ReverseBits(j, 5)) << state-> NumBits; state->NumBits += (5);; | |||
831 | if (dist_bits[j]) { Deflate_PushBits(state, dist - deflate_dist[j], dist_bits[j])state->Bits |= (dist - deflate_dist[j]) << state-> NumBits; state->NumBits += (dist_bits[j]);; } | |||
832 | Deflate_FlushBits(state)while (state->NumBits >= 8) { *state->NextOut++ = state ->Bits; state->AvailOut--; state->Bits >>= 8; state ->NumBits -= 8;; }; | |||
833 | } | |||
834 | ||||
835 | /* Moves "current block" to "previous block", adjusting state if needed. */ | |||
836 | static void Deflate_MoveBlock(struct DeflateState* state) { | |||
837 | int i; | |||
838 | Mem_Copy(state->Input, state->Input + DEFLATE_BLOCK_SIZE16384, DEFLATE_BLOCK_SIZE16384); | |||
839 | state->InputPosition = DEFLATE_BLOCK_SIZE16384; | |||
840 | ||||
841 | /* adjust hash table offsets, removing offsets that are no longer in data at all */ | |||
842 | for (i = 0; i < Array_Elems(state->Head)(sizeof(state->Head) / sizeof(state->Head[0])); i++) { | |||
843 | state->Head[i] = state->Head[i] < DEFLATE_BLOCK_SIZE16384 ? 0 : (state->Head[i] - DEFLATE_BLOCK_SIZE16384); | |||
844 | } | |||
845 | for (i = 0; i < Array_Elems(state->Prev)(sizeof(state->Prev) / sizeof(state->Prev[0])); i++) { | |||
846 | state->Prev[i] = state->Prev[i] < DEFLATE_BLOCK_SIZE16384 ? 0 : (state->Prev[i] - DEFLATE_BLOCK_SIZE16384); | |||
847 | } | |||
848 | } | |||
849 | ||||
850 | /* Compresses current block of data */ | |||
851 | static cc_result Deflate_FlushBlock(struct DeflateState* state, int len) { | |||
852 | cc_uint32 hash, nextHash; | |||
853 | int bestLen, maxLen, matchLen, depth; | |||
854 | int bestPos, pos, nextPos; | |||
855 | cc_uint16 oldHead; | |||
856 | cc_uint8* input; | |||
857 | cc_uint8* cur; | |||
858 | cc_result res; | |||
859 | ||||
860 | if (!state->WroteHeader) { | |||
861 | state->WroteHeader = true1; | |||
862 | Deflate_PushBits(state, 3, 3)state->Bits |= (3) << state->NumBits; state->NumBits += (3);; /* final block TRUE, block type FIXED */ | |||
863 | } | |||
864 | ||||
865 | /* Based off descriptions from http://www.gzip.org/algorithm.txt and | |||
866 | https://github.com/nothings/stb/blob/master/stb_image_write.h */ | |||
867 | input = state->Input; | |||
868 | cur = input + DEFLATE_BLOCK_SIZE16384; | |||
869 | ||||
870 | /* Compress current block of data */ | |||
871 | /* Use > instead of >=, because also try match at one byte after current */ | |||
872 | while (len > MIN_MATCH_LEN3) { | |||
873 | hash = Deflate_Hash(cur); | |||
874 | maxLen = min(len, MAX_MATCH_LEN)((len) < (258) ? (len) : (258)); | |||
875 | ||||
876 | bestLen = MIN_MATCH_LEN3 - 1; /* Match must be at least 3 bytes */ | |||
877 | bestPos = 0; | |||
878 | ||||
879 | /* Find longest match starting at this byte */ | |||
880 | /* Only explore up to 5 previous matches, to avoid slow performance */ | |||
881 | /* (i.e prefer quickly saving maps/screenshots to completely optimal filesize) */ | |||
882 | pos = state->Head[hash]; | |||
883 | for (depth = 0; pos != 0 && depth < 5; depth++) { | |||
884 | matchLen = Deflate_MatchLen(&input[pos], cur, maxLen); | |||
885 | if (matchLen > bestLen) { bestLen = matchLen; bestPos = pos; } | |||
886 | pos = state->Prev[pos]; | |||
887 | } | |||
888 | ||||
889 | /* Insert this entry into the hash chain */ | |||
890 | pos = (int)(cur - input); | |||
891 | oldHead = state->Head[hash]; | |||
892 | state->Head[hash] = pos; | |||
893 | state->Prev[pos] = oldHead; | |||
894 | ||||
895 | /* Lazy evaluation: Find longest match starting at next byte */ | |||
896 | /* If that's longer than the longest match at current byte, throwaway this match */ | |||
897 | if (bestPos) { | |||
898 | nextHash = Deflate_Hash(cur + 1); | |||
899 | nextPos = state->Head[nextHash]; | |||
900 | maxLen = min(len - 1, MAX_MATCH_LEN)((len - 1) < (258) ? (len - 1) : (258)); | |||
901 | ||||
902 | for (depth = 0; nextPos != 0 && depth < 5; depth++) { | |||
903 | matchLen = Deflate_MatchLen(&input[nextPos], cur + 1, maxLen); | |||
904 | if (matchLen > bestLen) { bestPos = 0; break; } | |||
905 | nextPos = state->Prev[nextPos]; | |||
906 | } | |||
907 | } | |||
908 | ||||
909 | if (bestPos) { | |||
910 | Deflate_LenDist(state, bestLen, pos - bestPos); | |||
911 | len -= bestLen; cur += bestLen; | |||
912 | } else { | |||
913 | Deflate_Lit(state, *cur); | |||
914 | len--; cur++; | |||
915 | } | |||
916 | ||||
917 | /* leave room for a few bytes and literals at end */ | |||
918 | if (state->AvailOut >= 20) continue; | |||
919 | res = Stream_Write(state->Dest, state->Output, DEFLATE_OUT_SIZE8192 - state->AvailOut); | |||
920 | state->NextOut = state->Output; | |||
921 | state->AvailOut = DEFLATE_OUT_SIZE8192; | |||
922 | if (res) return res; | |||
923 | } | |||
924 | ||||
925 | /* literals for last few bytes */ | |||
926 | while (len > 0) { | |||
927 | Deflate_Lit(state, *cur); | |||
928 | len--; cur++; | |||
929 | } | |||
930 | ||||
931 | res = Stream_Write(state->Dest, state->Output, DEFLATE_OUT_SIZE8192 - state->AvailOut); | |||
932 | state->NextOut = state->Output; | |||
933 | state->AvailOut = DEFLATE_OUT_SIZE8192; | |||
934 | ||||
935 | Deflate_MoveBlock(state); | |||
936 | return res; | |||
937 | } | |||
938 | ||||
939 | /* Adds data to buffered output data, flushing if needed */ | |||
940 | static cc_result Deflate_StreamWrite(struct Stream* stream, const cc_uint8* data, cc_uint32 total, cc_uint32* modified) { | |||
941 | struct DeflateState* state; | |||
942 | cc_result res; | |||
943 | ||||
944 | state = (struct DeflateState*)stream->Meta.Inflate; | |||
945 | *modified = 0; | |||
946 | ||||
947 | while (total > 0) { | |||
948 | cc_uint8* dst = &state->Input[state->InputPosition]; | |||
949 | cc_uint32 len = total; | |||
950 | if (state->InputPosition + len >= DEFLATE_BUFFER_SIZE32768) { | |||
951 | len = DEFLATE_BUFFER_SIZE32768 - state->InputPosition; | |||
952 | } | |||
953 | ||||
954 | Mem_Copy(dst, data, len); | |||
955 | total -= len; | |||
956 | state->InputPosition += len; | |||
957 | *modified += len; | |||
958 | data += len; | |||
959 | ||||
960 | if (state->InputPosition == DEFLATE_BUFFER_SIZE32768) { | |||
961 | res = Deflate_FlushBlock(state, DEFLATE_BLOCK_SIZE16384); | |||
962 | if (res) return res; | |||
963 | } | |||
964 | } | |||
965 | return 0; | |||
966 | } | |||
967 | ||||
968 | /* Flushes any buffered data, then writes terminating symbol */ | |||
969 | static cc_result Deflate_StreamClose(struct Stream* stream) { | |||
970 | struct DeflateState* state; | |||
971 | cc_result res; | |||
972 | ||||
973 | state = (struct DeflateState*)stream->Meta.Inflate; | |||
974 | res = Deflate_FlushBlock(state, state->InputPosition - DEFLATE_BLOCK_SIZE16384); | |||
975 | if (res) return res; | |||
976 | ||||
977 | /* Write huffman encoded "literal 256" to terminate symbols */ | |||
978 | Deflate_PushLit(state, 256)state->Bits |= (state->LitsCodewords[256]) << state ->NumBits; state->NumBits += (state->LitsLens[256]);; | |||
979 | Deflate_FlushBits(state)while (state->NumBits >= 8) { *state->NextOut++ = state ->Bits; state->AvailOut--; state->Bits >>= 8; state ->NumBits -= 8;; }; | |||
980 | ||||
981 | /* In case last byte still has a few extra bits */ | |||
982 | if (state->NumBits) { | |||
983 | while (state->NumBits < 8) { Deflate_PushBits(state, 0, 1)state->Bits |= (0) << state->NumBits; state->NumBits += (1);; } | |||
984 | Deflate_FlushBits(state)while (state->NumBits >= 8) { *state->NextOut++ = state ->Bits; state->AvailOut--; state->Bits >>= 8; state ->NumBits -= 8;; }; | |||
985 | } | |||
986 | ||||
987 | return Stream_Write(state->Dest, state->Output, DEFLATE_OUT_SIZE8192 - state->AvailOut); | |||
988 | } | |||
989 | ||||
990 | /* Constructs a huffman encoding table (for values to codewords) */ | |||
991 | static void Deflate_BuildTable(const cc_uint8* lens, int count, cc_uint16* codewords, cc_uint8* bitlens) { | |||
992 | int i, j, offset, codeword; | |||
993 | struct HuffmanTable table; | |||
994 | ||||
995 | /* NOTE: Can ignore since lens table is not user controlled */ | |||
996 | (void)Huffman_Build(&table, lens, count); | |||
997 | for (i = 0; i < INFLATE_MAX_BITS16; i++) { | |||
998 | if (!table.EndCodewords[i]) continue; | |||
999 | count = table.EndCodewords[i] - table.FirstCodewords[i]; | |||
1000 | ||||
1001 | for (j = 0; j < count; j++) { | |||
1002 | offset = table.Values[table.FirstOffsets[i] + j]; | |||
1003 | codeword = table.FirstCodewords[i] + j; | |||
1004 | bitlens[offset] = i; | |||
1005 | codewords[offset] = Huffman_ReverseBits(codeword, i); | |||
1006 | } | |||
1007 | } | |||
1008 | } | |||
1009 | ||||
1010 | void Deflate_MakeStream(struct Stream* stream, struct DeflateState* state, struct Stream* underlying) { | |||
1011 | Stream_Init(stream); | |||
1012 | stream->Meta.Inflate = state; | |||
1013 | stream->Write = Deflate_StreamWrite; | |||
1014 | stream->Close = Deflate_StreamClose; | |||
1015 | ||||
1016 | /* First half of buffer is "previous block" */ | |||
1017 | state->InputPosition = DEFLATE_BLOCK_SIZE16384; | |||
1018 | state->Bits = 0; | |||
1019 | state->NumBits = 0; | |||
1020 | ||||
1021 | state->NextOut = state->Output; | |||
1022 | state->AvailOut = DEFLATE_OUT_SIZE8192; | |||
1023 | state->Dest = underlying; | |||
1024 | state->WroteHeader = false0; | |||
1025 | ||||
1026 | Mem_Set(state->Head, 0, sizeof(state->Head)); | |||
1027 | Mem_Set(state->Prev, 0, sizeof(state->Prev)); | |||
1028 | Deflate_BuildTable(fixed_lits, INFLATE_MAX_LITS288, state->LitsCodewords, state->LitsLens); | |||
1029 | } | |||
1030 | ||||
1031 | ||||
1032 | /*########################################################################################################################* | |||
1033 | *-----------------------------------------------------GZip (compress)-----------------------------------------------------* | |||
1034 | *#########################################################################################################################*/ | |||
1035 | static cc_result GZip_StreamClose(struct Stream* stream) { | |||
1036 | struct GZipState* state = (struct GZipState*)stream->Meta.Inflate; | |||
1037 | cc_uint8 data[8]; | |||
1038 | cc_result res; | |||
1039 | ||||
1040 | if ((res = Deflate_StreamClose(stream))) return res; | |||
1041 | Stream_SetU32_LE(&data[0], state->Crc32 ^ 0xFFFFFFFFUL); | |||
1042 | Stream_SetU32_LE(&data[4], state->Size); | |||
1043 | return Stream_Write(state->Base.Dest, data, sizeof(data)); | |||
1044 | } | |||
1045 | ||||
1046 | static cc_result GZip_StreamWrite(struct Stream* stream, const cc_uint8* data, cc_uint32 count, cc_uint32* modified) { | |||
1047 | struct GZipState* state = (struct GZipState*)stream->Meta.Inflate; | |||
1048 | cc_uint32 i, crc32 = state->Crc32; | |||
1049 | state->Size += count; | |||
1050 | ||||
1051 | /* TODO: Optimise this calculation */ | |||
1052 | for (i = 0; i < count; i++) { | |||
1053 | crc32 = Utils_Crc32Table[(crc32 ^ data[i]) & 0xFF] ^ (crc32 >> 8); | |||
1054 | } | |||
1055 | ||||
1056 | state->Crc32 = crc32; | |||
1057 | return Deflate_StreamWrite(stream, data, count, modified); | |||
1058 | } | |||
1059 | ||||
1060 | static cc_result GZip_StreamWriteFirst(struct Stream* stream, const cc_uint8* data, cc_uint32 count, cc_uint32* modified) { | |||
1061 | static cc_uint8 header[10] = { 0x1F, 0x8B, 0x08 }; /* GZip header */ | |||
1062 | struct GZipState* state = (struct GZipState*)stream->Meta.Inflate; | |||
1063 | cc_result res; | |||
1064 | ||||
1065 | if ((res = Stream_Write(state->Base.Dest, header, sizeof(header)))) return res; | |||
1066 | stream->Write = GZip_StreamWrite; | |||
1067 | return GZip_StreamWrite(stream, data, count, modified); | |||
1068 | } | |||
1069 | ||||
1070 | void GZip_MakeStream(struct Stream* stream, struct GZipState* state, struct Stream* underlying) { | |||
1071 | Deflate_MakeStream(stream, &state->Base, underlying); | |||
1072 | state->Crc32 = 0xFFFFFFFFUL; | |||
1073 | state->Size = 0; | |||
1074 | stream->Write = GZip_StreamWriteFirst; | |||
1075 | stream->Close = GZip_StreamClose; | |||
1076 | } | |||
1077 | ||||
1078 | ||||
1079 | /*########################################################################################################################* | |||
1080 | *-----------------------------------------------------ZLib (compress)-----------------------------------------------------* | |||
1081 | *#########################################################################################################################*/ | |||
1082 | static cc_result ZLib_StreamClose(struct Stream* stream) { | |||
1083 | struct ZLibState* state = (struct ZLibState*)stream->Meta.Inflate; | |||
1084 | cc_uint8 data[4]; | |||
1085 | cc_result res; | |||
1086 | ||||
1087 | if ((res = Deflate_StreamClose(stream))) return res; | |||
1088 | Stream_SetU32_BE(&data[0], state->Adler32); | |||
1089 | return Stream_Write(state->Base.Dest, data, sizeof(data)); | |||
1090 | } | |||
1091 | ||||
1092 | static cc_result ZLib_StreamWrite(struct Stream* stream, const cc_uint8* data, cc_uint32 count, cc_uint32* modified) { | |||
1093 | struct ZLibState* state = (struct ZLibState*)stream->Meta.Inflate; | |||
1094 | cc_uint32 i, adler32 = state->Adler32; | |||
1095 | cc_uint32 s1 = adler32 & 0xFFFF, s2 = (adler32 >> 16) & 0xFFFF; | |||
1096 | ||||
1097 | /* TODO: Optimise this calculation */ | |||
1098 | for (i = 0; i < count; i++) { | |||
1099 | #define ADLER32_BASE65521 65521 | |||
1100 | s1 = (s1 + data[i]) % ADLER32_BASE65521; | |||
1101 | s2 = (s2 + s1) % ADLER32_BASE65521; | |||
1102 | } | |||
1103 | ||||
1104 | state->Adler32 = (s2 << 16) | s1; | |||
1105 | return Deflate_StreamWrite(stream, data, count, modified); | |||
1106 | } | |||
1107 | ||||
1108 | static cc_result ZLib_StreamWriteFirst(struct Stream* stream, const cc_uint8* data, cc_uint32 count, cc_uint32* modified) { | |||
1109 | static cc_uint8 header[2] = { 0x78, 0x9C }; /* ZLib header */ | |||
1110 | struct ZLibState* state = (struct ZLibState*)stream->Meta.Inflate; | |||
1111 | cc_result res; | |||
1112 | ||||
1113 | if ((res = Stream_Write(state->Base.Dest, header, sizeof(header)))) return res; | |||
1114 | stream->Write = ZLib_StreamWrite; | |||
1115 | return ZLib_StreamWrite(stream, data, count, modified); | |||
1116 | } | |||
1117 | ||||
1118 | void ZLib_MakeStream(struct Stream* stream, struct ZLibState* state, struct Stream* underlying) { | |||
1119 | Deflate_MakeStream(stream, &state->Base, underlying); | |||
1120 | state->Adler32 = 1; | |||
1121 | stream->Write = ZLib_StreamWriteFirst; | |||
1122 | stream->Close = ZLib_StreamClose; | |||
1123 | } | |||
1124 | ||||
1125 | ||||
1126 | /*########################################################################################################################* | |||
1127 | *--------------------------------------------------------ZipEntry---------------------------------------------------------* | |||
1128 | *#########################################################################################################################*/ | |||
1129 | #define ZIP_MAXNAMELEN512 512 | |||
1130 | static cc_result Zip_ReadLocalFileHeader(struct ZipState* state, struct ZipEntry* entry) { | |||
1131 | struct Stream* stream = state->input; | |||
1132 | cc_uint8 header[26]; | |||
1133 | cc_uint32 compressedSize, uncompressedSize; | |||
1134 | int method, pathLen, extraLen; | |||
1135 | ||||
1136 | cc_string path; char pathBuffer[ZIP_MAXNAMELEN512]; | |||
1137 | struct Stream portion, compStream; | |||
1138 | struct InflateState inflate; | |||
1139 | cc_result res; | |||
1140 | if ((res = Stream_Read(stream, header, sizeof(header)))) return res; | |||
1141 | ||||
1142 | method = Stream_GetU16_LE(&header[4]); | |||
1143 | compressedSize = Stream_GetU32_LE(&header[14]); | |||
1144 | uncompressedSize = Stream_GetU32_LE(&header[18]); | |||
1145 | ||||
1146 | /* Some .zip files don't set these in local file header */ | |||
1147 | if (!compressedSize) compressedSize = entry->CompressedSize; | |||
1148 | if (!uncompressedSize) uncompressedSize = entry->UncompressedSize; | |||
1149 | ||||
1150 | pathLen = Stream_GetU16_LE(&header[22]); | |||
1151 | extraLen = Stream_GetU16_LE(&header[24]); | |||
1152 | if (pathLen > ZIP_MAXNAMELEN512) return ZIP_ERR_FILENAME_LEN; | |||
1153 | ||||
1154 | /* NOTE: ZIP spec says path uses code page 437 for encoding */ | |||
1155 | path = String_Init(pathBuffer, pathLen, pathLen); | |||
1156 | if ((res = Stream_Read(stream, (cc_uint8*)pathBuffer, pathLen))) return res; | |||
1157 | state->_curEntry = entry; | |||
1158 | ||||
1159 | if (!state->SelectEntry(&path)) return 0; | |||
1160 | /* local file may have extra data before actual data (e.g. ZIP64) */ | |||
1161 | if ((res = stream->Skip(stream, extraLen))) return res; | |||
1162 | ||||
1163 | if (method == 0) { | |||
1164 | Stream_ReadonlyPortion(&portion, stream, uncompressedSize); | |||
1165 | return state->ProcessEntry(&path, &portion, state); | |||
1166 | } else if (method == 8) { | |||
1167 | Stream_ReadonlyPortion(&portion, stream, compressedSize); | |||
1168 | Inflate_MakeStream2(&compStream, &inflate, &portion); | |||
1169 | return state->ProcessEntry(&path, &compStream, state); | |||
1170 | } else { | |||
1171 | Platform_Log1("Unsupported.zip entry compression method: %i", &method); | |||
1172 | /* TODO: Should this be an error */ | |||
1173 | } | |||
1174 | return 0; | |||
1175 | } | |||
1176 | ||||
1177 | static cc_result Zip_ReadCentralDirectory(struct ZipState* state) { | |||
1178 | struct Stream* stream = state->input; | |||
1179 | struct ZipEntry* entry; | |||
1180 | cc_uint8 header[42]; | |||
1181 | ||||
1182 | cc_string path; char pathBuffer[ZIP_MAXNAMELEN512]; | |||
1183 | int pathLen, extraLen, commentLen; | |||
1184 | cc_result res; | |||
1185 | if ((res = Stream_Read(stream, header, sizeof(header)))) return res; | |||
1186 | ||||
1187 | pathLen = Stream_GetU16_LE(&header[24]); | |||
1188 | if (pathLen > ZIP_MAXNAMELEN512) return ZIP_ERR_FILENAME_LEN; | |||
1189 | ||||
1190 | /* NOTE: ZIP spec says path uses code page 437 for encoding */ | |||
1191 | path = String_Init(pathBuffer, pathLen, pathLen); | |||
1192 | if ((res = Stream_Read(stream, (cc_uint8*)pathBuffer, pathLen))) return res; | |||
1193 | ||||
1194 | /* skip data following central directory entry header */ | |||
1195 | extraLen = Stream_GetU16_LE(&header[26]); | |||
1196 | commentLen = Stream_GetU16_LE(&header[28]); | |||
1197 | if ((res = stream->Skip(stream, extraLen + commentLen))) return res; | |||
1198 | ||||
1199 | if (!state->SelectEntry(&path)) return 0; | |||
1200 | if (state->_usedEntries >= ZIP_MAX_ENTRIES1024) return ZIP_ERR_TOO_MANY_ENTRIES; | |||
1201 | entry = &state->entries[state->_usedEntries++]; | |||
1202 | ||||
1203 | entry->CRC32 = Stream_GetU32_LE(&header[12]); | |||
1204 | entry->CompressedSize = Stream_GetU32_LE(&header[16]); | |||
1205 | entry->UncompressedSize = Stream_GetU32_LE(&header[20]); | |||
1206 | entry->LocalHeaderOffset = Stream_GetU32_LE(&header[38]); | |||
1207 | return 0; | |||
1208 | } | |||
1209 | ||||
1210 | static cc_result Zip_ReadEndOfCentralDirectory(struct ZipState* state) { | |||
1211 | struct Stream* stream = state->input; | |||
1212 | cc_uint8 header[18]; | |||
1213 | ||||
1214 | cc_result res; | |||
1215 | if ((res = Stream_Read(stream, header, sizeof(header)))) return res; | |||
1216 | ||||
1217 | state->_totalEntries = Stream_GetU16_LE(&header[6]); | |||
1218 | state->_centralDirBeg = Stream_GetU32_LE(&header[12]); | |||
1219 | return 0; | |||
1220 | } | |||
1221 | ||||
1222 | enum ZipSig { | |||
1223 | ZIP_SIG_ENDOFCENTRALDIR = 0x06054b50, | |||
1224 | ZIP_SIG_CENTRALDIR = 0x02014b50, | |||
1225 | ZIP_SIG_LOCALFILEHEADER = 0x04034b50 | |||
1226 | }; | |||
1227 | ||||
1228 | static cc_result Zip_DefaultProcessor(const cc_string* path, struct Stream* data, struct ZipState* s) { return 0; } | |||
1229 | static cc_bool Zip_DefaultSelector(const cc_string* path) { return true1; } | |||
1230 | void Zip_Init(struct ZipState* state, struct Stream* input) { | |||
1231 | state->input = input; | |||
1232 | state->obj = NULL((void*)0); | |||
1233 | state->ProcessEntry = Zip_DefaultProcessor; | |||
1234 | state->SelectEntry = Zip_DefaultSelector; | |||
1235 | } | |||
1236 | ||||
1237 | cc_result Zip_Extract(struct ZipState* state) { | |||
1238 | struct Stream* stream = state->input; | |||
1239 | cc_uint32 stream_len; | |||
1240 | cc_uint32 sig = 0; | |||
1241 | int i, count; | |||
1242 | ||||
1243 | cc_result res; | |||
1244 | if ((res = stream->Length(stream, &stream_len))) return res; | |||
1245 | ||||
1246 | /* At -22 for nearly all zips, but try a bit further back in case of comment */ | |||
1247 | count = min(257, stream_len)((257) < (stream_len) ? (257) : (stream_len)); | |||
1248 | for (i = 22; i < count; i++) { | |||
1249 | res = stream->Seek(stream, stream_len - i); | |||
1250 | if (res) return ZIP_ERR_SEEK_END_OF_CENTRAL_DIR; | |||
1251 | ||||
1252 | if ((res = Stream_ReadU32_LE(stream, &sig))) return res; | |||
1253 | if (sig == ZIP_SIG_ENDOFCENTRALDIR) break; | |||
1254 | } | |||
1255 | ||||
1256 | if (sig != ZIP_SIG_ENDOFCENTRALDIR) return ZIP_ERR_NO_END_OF_CENTRAL_DIR; | |||
1257 | res = Zip_ReadEndOfCentralDirectory(state); | |||
1258 | if (res) return res; | |||
1259 | ||||
1260 | res = stream->Seek(stream, state->_centralDirBeg); | |||
1261 | if (res) return ZIP_ERR_SEEK_CENTRAL_DIR; | |||
1262 | state->_usedEntries = 0; | |||
1263 | ||||
1264 | /* Read all the central directory entries */ | |||
1265 | for (i = 0; i < state->_totalEntries; i++) { | |||
1266 | if ((res = Stream_ReadU32_LE(stream, &sig))) return res; | |||
1267 | ||||
1268 | if (sig == ZIP_SIG_CENTRALDIR) { | |||
1269 | res = Zip_ReadCentralDirectory(state); | |||
1270 | if (res) return res; | |||
1271 | } else if (sig == ZIP_SIG_ENDOFCENTRALDIR) { | |||
1272 | break; | |||
1273 | } else { | |||
1274 | return ZIP_ERR_INVALID_CENTRAL_DIR; | |||
1275 | } | |||
1276 | } | |||
1277 | ||||
1278 | /* Now read the local file header entries */ | |||
1279 | for (i = 0; i < state->_usedEntries; i++) { | |||
1280 | struct ZipEntry* entry = &state->entries[i]; | |||
1281 | res = stream->Seek(stream, entry->LocalHeaderOffset); | |||
1282 | if (res) return ZIP_ERR_SEEK_LOCAL_DIR; | |||
1283 | ||||
1284 | if ((res = Stream_ReadU32_LE(stream, &sig))) return res; | |||
1285 | if (sig != ZIP_SIG_LOCALFILEHEADER) return ZIP_ERR_INVALID_LOCAL_DIR; | |||
1286 | ||||
1287 | res = Zip_ReadLocalFileHeader(state, entry); | |||
1288 | if (res) return res; | |||
1289 | } | |||
1290 | return 0; | |||
1291 | } |