Mercurial > hg > dmlib
comparison src/dmzlib.c @ 960:1832ac20edb2
Clean up dmzlib and use it in stb_image.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 27 Feb 2015 04:46:13 +0200 |
parents | 985225a93aeb |
children | 76ac0d5c89b3 |
comparison
equal
deleted
inserted
replaced
959:36aec8ff670a | 960:1832ac20edb2 |
---|---|
10 #define DM_ZLIB_TMPBUF_SIZE (16 * 1024) | 10 #define DM_ZLIB_TMPBUF_SIZE (16 * 1024) |
11 #define DMSTBI_ASSERT(x) // dummy | 11 #define DMSTBI_ASSERT(x) // dummy |
12 | 12 |
13 | 13 |
14 // @TODO: should statically initialize these for optimal thread safety | 14 // @TODO: should statically initialize these for optimal thread safety |
15 static Uint8 stbi__zdefault_length[288], stbi__zdefault_distance[32]; | 15 static Uint8 dm_zdefault_length[288], dm_zdefault_distance[32]; |
16 | 16 |
17 | 17 |
18 void dmZLibInit() | 18 void dmZLibInit() |
19 { | 19 { |
20 int i; | 20 int i; |
21 | 21 |
22 // use <= to match clearly with spec | 22 // use <= to match clearly with spec |
23 for (i = 0; i <= 143; i++) | 23 for (i = 0; i <= 143; i++) |
24 stbi__zdefault_length[i] = 8; | 24 dm_zdefault_length[i] = 8; |
25 | 25 |
26 for (; i <= 255; i++) | 26 for (; i <= 255; i++) |
27 stbi__zdefault_length[i] = 9; | 27 dm_zdefault_length[i] = 9; |
28 | 28 |
29 for (; i <= 279; i++) | 29 for (; i <= 279; i++) |
30 stbi__zdefault_length[i] = 7; | 30 dm_zdefault_length[i] = 7; |
31 | 31 |
32 for (; i <= 287; i++) | 32 for (; i <= 287; i++) |
33 stbi__zdefault_length[i] = 8; | 33 dm_zdefault_length[i] = 8; |
34 | 34 |
35 for (i = 0; i <= 31; i++) | 35 for (i = 0; i <= 31; i++) |
36 stbi__zdefault_distance[i] = 5; | 36 dm_zdefault_distance[i] = 5; |
37 } | 37 } |
38 | 38 |
39 | 39 |
40 static inline int stbi__bit_reverse_16(int n) | 40 static inline int stbi__bit_reverse_16(int n) |
41 { | 41 { |
54 // e.g. 11 bits, bit reverse and shift away 5 | 54 // e.g. 11 bits, bit reverse and shift away 5 |
55 return stbi__bit_reverse_16(v) >> (16 - bits); | 55 return stbi__bit_reverse_16(v) >> (16 - bits); |
56 } | 56 } |
57 | 57 |
58 | 58 |
59 static int stbi__zbuild_huffman(DMZHuffmanContext * ctx, const Uint8 * sizelist, const int num) | 59 static int dmZLibBuildHuffmanTables(DMZHuffmanContext * ctx, const Uint8 * sizelist, const int num) |
60 { | 60 { |
61 int i, k = 0; | 61 int i, k = 0; |
62 int code, next_code[16], sizes[17]; | 62 int code, next_code[16], sizes[17]; |
63 | 63 |
64 // DEFLATE spec for generating codes | 64 // DEFLATE spec for generating codes |
121 } | 121 } |
122 return 1; | 122 return 1; |
123 } | 123 } |
124 | 124 |
125 | 125 |
126 static inline Uint8 stbi__zget8(DMZLibContext * ctx) | 126 static inline Uint8 dmZGet8(DMZLibContext * ctx) |
127 { | 127 { |
128 if (ctx->zbuffer >= ctx->zbufferEnd) | 128 if (ctx->zbuffer >= ctx->zbufferEnd) |
129 return 0; | 129 return 0; |
130 | 130 |
131 return *ctx->zbuffer++; | 131 return *ctx->zbuffer++; |
135 static void stbi__fill_bits(DMZLibContext * ctx) | 135 static void stbi__fill_bits(DMZLibContext * ctx) |
136 { | 136 { |
137 do | 137 do |
138 { | 138 { |
139 DMSTBI_ASSERT(ctx->codeBuffer < (1U << ctx->numBits)); | 139 DMSTBI_ASSERT(ctx->codeBuffer < (1U << ctx->numBits)); |
140 ctx->codeBuffer |= stbi__zget8(ctx) << ctx->numBits; | 140 ctx->codeBuffer |= dmZGet8(ctx) << ctx->numBits; |
141 ctx->numBits += 8; | 141 ctx->numBits += 8; |
142 } | 142 } |
143 while (ctx->numBits <= 24); | 143 while (ctx->numBits <= 24); |
144 } | 144 } |
145 | 145 |
146 | 146 |
147 static inline unsigned int stbi__zreceive(DMZLibContext * ctx, int n) | 147 static inline unsigned int dmZReceive(DMZLibContext * ctx, int n) |
148 { | 148 { |
149 unsigned int val; | 149 unsigned int val; |
150 | 150 |
151 if (ctx->numBits < n) | 151 if (ctx->numBits < n) |
152 stbi__fill_bits(ctx); | 152 stbi__fill_bits(ctx); |
160 | 160 |
161 | 161 |
162 static int stbi__zhuffman_decode_slowpath(DMZLibContext * ctx, DMZHuffmanContext * huff, int *val) | 162 static int stbi__zhuffman_decode_slowpath(DMZLibContext * ctx, DMZHuffmanContext * huff, int *val) |
163 { | 163 { |
164 int b, s, k; | 164 int b, s, k; |
165 *val = 0; | |
165 | 166 |
166 // not resolved by fast table, so compute it the slow way | 167 // not resolved by fast table, so compute it the slow way |
167 // use jpeg approach, which requires MSbits at top | 168 // use jpeg approach, which requires MSbits at top |
168 k = stbi__bit_reverse_16(ctx->codeBuffer); | 169 k = stbi__bit_reverse_16(ctx->codeBuffer); |
169 for (s = STBI__ZFAST_BITS + 1; ; s++) | 170 for (s = STBI__ZFAST_BITS + 1; ; s++) |
268 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, | 269 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, |
269 10, 11, 11, 12, 12, 13, 13 | 270 10, 11, 11, 12, 12, 13, 13 |
270 }; | 271 }; |
271 | 272 |
272 | 273 |
273 static int stbi__parse_huffman_block(DMZLibContext * a) | 274 static int dmZLibParseHuffmanBlock(DMZLibContext * a) |
274 { | 275 { |
275 Uint8 *zout = a->zout; | 276 Uint8 *zout = a->zout; |
276 for (;;) | 277 for (;;) |
277 { | 278 { |
278 int z, ret; | 279 int z, ret; |
301 } | 302 } |
302 z -= 257; | 303 z -= 257; |
303 | 304 |
304 len = stbi__zlength_base[z]; | 305 len = stbi__zlength_base[z]; |
305 if (stbi__zlength_extra[z]) | 306 if (stbi__zlength_extra[z]) |
306 len += stbi__zreceive(a, stbi__zlength_extra[z]); | 307 len += dmZReceive(a, stbi__zlength_extra[z]); |
307 | 308 |
308 if ((ret = stbi__zhuffman_decode(a, &a->zdistance, &z)) != DMERR_OK) | 309 if ((ret = stbi__zhuffman_decode(a, &a->zdistance, &z)) != DMERR_OK) |
309 return ret; | 310 return ret; |
310 | 311 |
311 dist = stbi__zdist_base[z]; | 312 dist = stbi__zdist_base[z]; |
312 if (stbi__zdist_extra[z]) | 313 if (stbi__zdist_extra[z]) |
313 dist += stbi__zreceive(a, stbi__zdist_extra[z]); | 314 dist += dmZReceive(a, stbi__zdist_extra[z]); |
314 | 315 |
315 if (zout - a->zoutStart < dist) | 316 if (zout - a->zoutStart < dist) |
316 { | 317 { |
317 return dmError(DMERR_DATA_ERROR, | 318 return dmError(DMERR_DATA_ERROR, |
318 "Bad Huffman block distance.\n"); | 319 "Bad Huffman block distance.\n"); |
345 6 , 10, 5 , 11, 4, 12, 3, | 346 6 , 10, 5 , 11, 4, 12, 3, |
346 13, 2 , 14, 1 , 15 | 347 13, 2 , 14, 1 , 15 |
347 }; | 348 }; |
348 | 349 |
349 | 350 |
350 static int stbi__compute_huffman_codes(DMZLibContext * a) | 351 static int dmZLibComputeHuffmanCodes(DMZLibContext * a) |
351 { | 352 { |
352 DMZHuffmanContext z_codelength; | 353 DMZHuffmanContext z_codelength; |
353 Uint8 lencodes[286 + 32 + 137]; //padding for maximum single op | 354 Uint8 codeLengths[286 + 32 + 137]; //padding for maximum single op |
354 Uint8 codelength_sizes[19]; | 355 Uint8 codeLengthSizes[19]; |
355 int i, n, ret; | 356 int i, n, ret; |
356 | 357 |
357 int hlit = stbi__zreceive(a, 5) + 257; | 358 int hlit = dmZReceive(a, 5) + 257; |
358 int hdist = stbi__zreceive(a, 5) + 1; | 359 int hdist = dmZReceive(a, 5) + 1; |
359 int hclen = stbi__zreceive(a, 4) + 4; | 360 int hclen = dmZReceive(a, 4) + 4; |
360 | 361 |
361 memset(codelength_sizes, 0, sizeof(codelength_sizes)); | 362 memset(codeLengthSizes, 0, sizeof(codeLengthSizes)); |
362 | 363 |
363 for (i = 0; i < hclen; i++) | 364 for (i = 0; i < hclen; i++) |
364 { | 365 { |
365 int s = stbi__zreceive(a, 3); | 366 int s = dmZReceive(a, 3); |
366 codelength_sizes[length_dezigzag[i]] = (Uint8) s; | 367 codeLengthSizes[length_dezigzag[i]] = (Uint8) s; |
367 } | 368 } |
368 | 369 |
369 if ((ret = stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) != DMERR_OK) | 370 if ((ret = dmZLibBuildHuffmanTables(&z_codelength, codeLengthSizes, 19)) != DMERR_OK) |
370 return ret; | 371 return ret; |
371 | 372 |
372 n = 0; | 373 n = 0; |
373 while (n < hlit + hdist) | 374 while (n < hlit + hdist) |
374 { | 375 { |
377 return ret; | 378 return ret; |
378 | 379 |
379 DMSTBI_ASSERT(c >= 0 && c < 19); | 380 DMSTBI_ASSERT(c >= 0 && c < 19); |
380 | 381 |
381 if (c < 16) | 382 if (c < 16) |
382 lencodes[n++] = (Uint8) c; | 383 codeLengths[n++] = (Uint8) c; |
383 else | 384 else |
384 if (c == 16) | 385 if (c == 16) |
385 { | 386 { |
386 c = stbi__zreceive(a, 2) + 3; | 387 c = dmZReceive(a, 2) + 3; |
387 memset(lencodes + n, lencodes[n - 1], c); | 388 memset(codeLengths + n, codeLengths[n - 1], c); |
388 n += c; | 389 n += c; |
389 } | 390 } |
390 else | 391 else |
391 if (c == 17) | 392 if (c == 17) |
392 { | 393 { |
393 c = stbi__zreceive(a, 3) + 3; | 394 c = dmZReceive(a, 3) + 3; |
394 memset(lencodes + n, 0, c); | 395 memset(codeLengths + n, 0, c); |
395 n += c; | 396 n += c; |
396 } | 397 } |
397 else | 398 else |
398 { | 399 { |
399 c = stbi__zreceive(a, 7) + 11; | 400 c = dmZReceive(a, 7) + 11; |
400 memset(lencodes + n, 0, c); | 401 memset(codeLengths + n, 0, c); |
401 n += c; | 402 n += c; |
402 } | 403 } |
403 } | 404 } |
404 | 405 |
405 if (n != hlit + hdist) | 406 if (n != hlit + hdist) |
406 { | 407 { |
407 return dmError(DMERR_DATA_ERROR, | 408 return dmError(DMERR_DATA_ERROR, |
408 "Bad huffman codelengths.\n"); | 409 "Bad huffman codelengths.\n"); |
409 } | 410 } |
410 | 411 |
411 if ((ret = stbi__zbuild_huffman(&a->zlength, lencodes, hlit)) != DMERR_OK) | 412 if ((ret = dmZLibBuildHuffmanTables(&a->zlength, codeLengths, hlit)) != DMERR_OK) |
412 return ret; | 413 return ret; |
413 | 414 |
414 if ((ret = stbi__zbuild_huffman(&a->zdistance, lencodes + hlit, hdist)) != DMERR_OK) | 415 if ((ret = dmZLibBuildHuffmanTables(&a->zdistance, codeLengths + hlit, hdist)) != DMERR_OK) |
415 return ret; | 416 return ret; |
416 | 417 |
417 return DMERR_OK; | 418 return DMERR_OK; |
418 } | 419 } |
419 | 420 |
420 | 421 |
421 static int stbi__parse_uncompressed_block(DMZLibContext * a) | 422 static int dmZLibParseUncompresedBlock(DMZLibContext * a) |
422 { | 423 { |
423 Uint8 header[4]; | 424 Uint8 header[4]; |
424 int len, nlen, k; | 425 int len, nlen, k; |
425 | 426 |
426 if (a->numBits & 7) | 427 if (a->numBits & 7) |
427 stbi__zreceive(a, a->numBits & 7); // discard | 428 dmZReceive(a, a->numBits & 7); // discard |
428 | 429 |
429 // drain the bit-packed data into header | 430 // drain the bit-packed data into header |
430 k = 0; | 431 k = 0; |
431 while (a->numBits > 0) | 432 while (a->numBits > 0) |
432 { | 433 { |
436 } | 437 } |
437 DMSTBI_ASSERT(a->numBits == 0); | 438 DMSTBI_ASSERT(a->numBits == 0); |
438 | 439 |
439 // now fill header the normal way | 440 // now fill header the normal way |
440 while (k < 4) | 441 while (k < 4) |
441 header[k++] = stbi__zget8(a); | 442 header[k++] = dmZGet8(a); |
442 | 443 |
443 len = (header[1] << 8) | header[0]; | 444 len = (header[1] << 8) | header[0]; |
444 nlen = (header[3] << 8) | header[2]; | 445 nlen = (header[3] << 8) | header[2]; |
445 | 446 |
446 if (nlen != (len ^ 0xffff)) | 447 if (nlen != (len ^ 0xffff)) |
469 } | 470 } |
470 | 471 |
471 | 472 |
472 int dmZLibParseHeader(DMZLibContext * ctx, BOOL checkPNG) | 473 int dmZLibParseHeader(DMZLibContext * ctx, BOOL checkPNG) |
473 { | 474 { |
474 int cmf = stbi__zget8(ctx); | 475 int cmf = dmZGet8(ctx); |
475 int flags = stbi__zget8(ctx); | 476 int flags = dmZGet8(ctx); |
476 int cm = cmf & 15; | 477 int cm = cmf & 15; |
477 // int cinfo = cmf >> 4; | 478 // int cinfo = cmf >> 4; |
478 | 479 |
479 if ((cmf * 256 + flags) % 31 != 0) | 480 if ((cmf * 256 + flags) % 31 != 0) |
480 { | 481 { |
506 | 507 |
507 ctx->numBits = 0; | 508 ctx->numBits = 0; |
508 ctx->codeBuffer = 0; | 509 ctx->codeBuffer = 0; |
509 do | 510 do |
510 { | 511 { |
511 final = stbi__zreceive(ctx, 1); | 512 final = dmZReceive(ctx, 1); |
512 type = stbi__zreceive(ctx, 2); | 513 type = dmZReceive(ctx, 2); |
513 if (type == 0) | 514 if (type == 0) |
514 { | 515 { |
515 if ((ret = stbi__parse_uncompressed_block(ctx)) != DMERR_OK) | 516 if ((ret = dmZLibParseUncompresedBlock(ctx)) != DMERR_OK) |
516 return ret; | 517 return ret; |
517 } | 518 } |
518 else | 519 else |
519 if (type == 3) | 520 if (type == 3) |
520 return 0; | 521 return 0; |
521 else | 522 else |
522 { | 523 { |
523 if (type == 1) | 524 if (type == 1) |
524 { | 525 { |
525 // use fixed code lengths | 526 // use fixed code lengths |
526 if ((ret = stbi__zbuild_huffman(&ctx->zlength, stbi__zdefault_length, 288)) != DMERR_OK) | 527 if ((ret = dmZLibBuildHuffmanTables(&ctx->zlength, dm_zdefault_length, 288)) != DMERR_OK) |
527 return ret; | 528 return ret; |
528 | 529 |
529 if ((ret = stbi__zbuild_huffman(&ctx->zdistance, stbi__zdefault_distance, 32)) != DMERR_OK) | 530 if ((ret = dmZLibBuildHuffmanTables(&ctx->zdistance, dm_zdefault_distance, 32)) != DMERR_OK) |
530 return ret; | 531 return ret; |
531 } | 532 } |
532 else | 533 else |
533 if ((ret = stbi__compute_huffman_codes(ctx)) != DMERR_OK) | 534 if ((ret = dmZLibComputeHuffmanCodes(ctx)) != DMERR_OK) |
534 return ret; | 535 return ret; |
535 | 536 |
536 if ((ret = stbi__parse_huffman_block(ctx)) != DMERR_OK) | 537 if ((ret = dmZLibParseHuffmanBlock(ctx)) != DMERR_OK) |
537 return ret; | 538 return ret; |
538 } | 539 } |
539 } | 540 } |
540 while (!final); | 541 while (!final); |
541 | 542 |
542 return DMERR_OK; | 543 return DMERR_OK; |
543 } | 544 } |
544 | |
545 | |
546 Uint8 *stbi_zlib_decode_malloc_guesssize_headerflag( | |
547 const Uint8 *buffer, const size_t len, | |
548 const size_t initialSize, size_t *outLen, | |
549 BOOL parseHeader) | |
550 { | |
551 DMZLibContext ctx; | |
552 Uint8 *outBuf; | |
553 int ret; | |
554 | |
555 if ((outBuf = dmMalloc(initialSize)) == NULL) | |
556 return NULL; | |
557 | |
558 ctx.zbuffer = (Uint8 *) buffer; | |
559 ctx.zbufferEnd = (Uint8 *) buffer + len; | |
560 ctx.zout = outBuf; | |
561 ctx.zoutStart = outBuf; | |
562 ctx.zoutEnd = outBuf + initialSize; | |
563 ctx.expandable = TRUE; | |
564 | |
565 if (parseHeader && (ret = dmZLibParseHeader(&ctx, TRUE)) != DMERR_OK) | |
566 { | |
567 return dmError(ret, | |
568 "Failed to parse zlib header data.\n"); | |
569 } | |
570 | |
571 if ((ret = dmZLibDecode(&ctx)) != DMERR_OK) | |
572 { | |
573 if (outLen) | |
574 *outLen = ctx.zout - ctx.zoutStart; | |
575 | |
576 return ctx.zoutStart; | |
577 } | |
578 else | |
579 { | |
580 dmFree(ctx.zoutStart); | |
581 return NULL; | |
582 } | |
583 } | |
584 | |
585 | |
586 #if 0 | |
587 | |
588 Uint8 *stbi_zlib_decode_malloc(Uint8 const *buffer, int len, int *outlen) | |
589 { | |
590 return stbi_zlib_decode_malloc_guesssize(buffer, len, DM_ZLIB_TMPBUF_SIZE, outlen); | |
591 } | |
592 | |
593 | |
594 int stbi_zlib_decode_buffer(Uint8 *obuffer, size_t olen, Uint8 const *ibuffer, size_t ilen, size_t *res) | |
595 { | |
596 DMZLibContext ctx; | |
597 int ret; | |
598 | |
599 ctx.zbuffer = (Uint8 *) ibuffer; | |
600 ctx.zbufferEnd = (Uint8 *) ibuffer + ilen; | |
601 | |
602 if ((ret = stbi__do_zlib(&a, obuffer, olen, 0, 1)) != DMERR_OK) | |
603 { | |
604 *res = a.zout - a.zoutStart; | |
605 return DMERR_OK; | |
606 } | |
607 else | |
608 return ret; | |
609 } | |
610 | |
611 | |
612 Uint8 *stbi_zlib_decode_noheader_malloc(Uint8 const *buffer, int len, size_t *outlen) | |
613 { | |
614 DMZLibContext ctx; | |
615 Uint8 *p = (Uint8 *) dmMalloc(DM_ZLIB_TMPBUF_SIZE); | |
616 if (p == NULL) | |
617 return NULL; | |
618 | |
619 ctx.zbuffer = (Uint8 *) buffer; | |
620 ctx.zbufferEnd = (Uint8 *) buffer + len; | |
621 | |
622 if (stbi__do_zlib(&ctx, p, DM_ZLIB_TMPBUF_SIZE, 1, 0)) | |
623 { | |
624 if (outlen != NULL) | |
625 *outlen = (int) (ctx.zout - a.zoutStart); | |
626 return a.zoutStart; | |
627 } | |
628 else | |
629 { | |
630 dmFree(a.zoutStart); | |
631 return NULL; | |
632 } | |
633 } | |
634 | |
635 | |
636 int stbi_zlib_decode_noheader_buffer(Uint8 *obuffer, int olen, const Uint8 *ibuffer, int ilen) | |
637 { | |
638 DMZLibContext a; | |
639 | |
640 a.zbuffer = (Uint8 *) ibuffer; | |
641 a.zbufferEnd = (Uint8 *) ibuffer + ilen; | |
642 | |
643 if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) | |
644 return (int) (a.zout - a.zoutStart); | |
645 else | |
646 return -1; | |
647 } | |
648 | |
649 #endif |