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