| 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 | } |