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