Mercurial > hg > dmlib
diff src/dmzlib.c @ 958:985225a93aeb
Add error code parameter to dmError() and dmErrorVA().
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 27 Feb 2015 03:58:25 +0200 |
parents | 6b2f41844580 |
children | 1832ac20edb2 |
line wrap: on
line diff
--- a/src/dmzlib.c Fri Feb 27 02:21:57 2015 +0200 +++ b/src/dmzlib.c Fri Feb 27 03:58:25 2015 +0200 @@ -8,15 +8,7 @@ #define DM_ZLIB_TMPBUF_SIZE (16 * 1024) -#define STBI_ASSERT(x) // dummy - - -static int stbi__err(const char *s, const char *p) -{ - (void) s; - (void) p; - return 0; -} +#define DMSTBI_ASSERT(x) // dummy // @TODO: should statically initialize these for optimal thread safety @@ -57,21 +49,21 @@ static inline int stbi__bit_reverse_n(int v, int bits) { - STBI_ASSERT(bits <= 16); + DMSTBI_ASSERT(bits <= 16); // to bit reverse n bits, reverse 16 and shift // e.g. 11 bits, bit reverse and shift away 5 return stbi__bit_reverse_16(v) >> (16 - bits); } -static int stbi__zbuild_huffman(DMZHuffmanContext * z, const Uint8 * sizelist, const int num) +static int stbi__zbuild_huffman(DMZHuffmanContext * ctx, const Uint8 * sizelist, const int num) { int i, k = 0; int code, next_code[16], sizes[17]; // DEFLATE spec for generating codes memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); + memset(ctx->fast, 0, sizeof(ctx->fast)); for (i = 0; i < num; i++) sizes[sizelist[i]]++; @@ -80,41 +72,47 @@ for (i = 1; i < 16; i++) { if (sizes[i] > (1 << i)) - return stbi__err("fail!", "omg!"); + { + return dmError(DMERR_INTERNAL, + "Sizes assert failed while building Huffman codes.\n"); + } } code = 0; for (i = 1; i < 16; i++) { next_code[i] = code; - z->firstCode[i] = (Uint16) code; - z->firstSymbol[i] = (Uint16) k; + ctx->firstCode[i] = (Uint16) code; + ctx->firstSymbol[i] = (Uint16) k; code = (code + sizes[i]); if (sizes[i] && code - 1 >= (1 << i)) - return stbi__err("bad codelengths", "Corrupt JPEG"); + { + return dmError(DMERR_INVALID_DATA, + "Bad Huffman code lengths.\n"); + } - z->maxCode[i] = code << (16 - i); // preshift for inner loop + ctx->maxCode[i] = code << (16 - i); // preshift for inner loop code <<= 1; k += sizes[i]; } - z->maxCode[16] = 0x10000; // sentinel + ctx->maxCode[16] = 0x10000; // sentinel for (i = 0; i < num; i++) { int s = sizelist[i]; if (s) { - int c = next_code[s] - z->firstCode[s] + z->firstSymbol[s]; + int c = next_code[s] - ctx->firstCode[s] + ctx->firstSymbol[s]; Uint16 fastv = (Uint16) ((s << 9) | i); - z->size[c] = (Uint8) s; - z->value[c] = (Uint16) i; + ctx->size[c] = (Uint8) s; + ctx->value[c] = (Uint16) i; if (s <= STBI__ZFAST_BITS) { int k = stbi__bit_reverse_n(next_code[s], s); while (k < STBI__ZFAST_SIZE) { - z->fast[k] = fastv; + ctx->fast[k] = fastv; k += (1 << s); } } @@ -125,103 +123,123 @@ } -static inline Uint8 stbi__zget8(DMZLibContext * z) +static inline Uint8 stbi__zget8(DMZLibContext * ctx) { - if (z->zbuffer >= z->zbuffer_end) + if (ctx->zbuffer >= ctx->zbufferEnd) return 0; - return *z->zbuffer++; + return *ctx->zbuffer++; } -static void stbi__fill_bits(DMZLibContext * z) +static void stbi__fill_bits(DMZLibContext * ctx) { do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= stbi__zget8(z) << z->num_bits; - z->num_bits += 8; + DMSTBI_ASSERT(ctx->codeBuffer < (1U << ctx->numBits)); + ctx->codeBuffer |= stbi__zget8(ctx) << ctx->numBits; + ctx->numBits += 8; } - while (z->num_bits <= 24); + while (ctx->numBits <= 24); } -static inline unsigned int stbi__zreceive(DMZLibContext * z, int n) +static inline unsigned int stbi__zreceive(DMZLibContext * ctx, int n) { - unsigned int k; - if (z->num_bits < n) - stbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; + unsigned int val; + + if (ctx->numBits < n) + stbi__fill_bits(ctx); + + val = ctx->codeBuffer & ((1 << n) - 1); + ctx->codeBuffer >>= n; + ctx->numBits -= n; + + return val; } -static int stbi__zhuffman_decode_slowpath(DMZLibContext * a, DMZHuffmanContext * z) +static int stbi__zhuffman_decode_slowpath(DMZLibContext * ctx, DMZHuffmanContext * huff, int *val) { int b, s, k; // not resolved by fast table, so compute it the slow way // use jpeg approach, which requires MSbits at top - k = stbi__bit_reverse_16(a->code_buffer); + k = stbi__bit_reverse_16(ctx->codeBuffer); for (s = STBI__ZFAST_BITS + 1; ; s++) { - if (k < z->maxCode[s]) break; + if (k < huff->maxCode[s]) + break; } if (s == 16) - return -1; // invalid code! + { + return dmError(DMERR_DATA_ERROR, + "Bad Huffman code.\n"); + } // code size is s, so: - b = (k >> (16 - s)) - z->firstCode[s] + z->firstSymbol[s]; - STBI_ASSERT(z->size[b] == s); - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; + b = (k >> (16 - s)) - huff->firstCode[s] + huff->firstSymbol[s]; + DMSTBI_ASSERT(huff->size[b] == s); + + ctx->codeBuffer >>= s; + ctx->numBits -= s; + *val = huff->value[b]; + + return DMERR_OK; } -static inline int stbi__zhuffman_decode(DMZLibContext * a, DMZHuffmanContext * z) +static inline int stbi__zhuffman_decode(DMZLibContext * ctx, DMZHuffmanContext * huff, int *val) { int b; - if (a->num_bits < 16) - stbi__fill_bits(a); + if (ctx->numBits < 16) + stbi__fill_bits(ctx); - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + b = huff->fast[ctx->codeBuffer & STBI__ZFAST_MASK]; if (b) { int s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; + ctx->codeBuffer >>= s; + ctx->numBits -= s; + *val = b & 511; + return DMERR_OK; } - return stbi__zhuffman_decode_slowpath(a, z); + + return stbi__zhuffman_decode_slowpath(ctx, huff, val); } -static int stbi__zexpand(DMZLibContext * z, char *zout, int n) // need to make room for n bytes +static int stbi__zexpand(DMZLibContext * ctx, Uint8 *zout, size_t n) { - char *q; - int cur, limit; - z->zout = zout; + Uint8 *newBuf; + size_t cur, limit; + + ctx->zout = zout; - if (!z->z_expandable) - return stbi__err("output buffer limit", "Corrupt PNG"); + if (!ctx->expandable) + { + return dmError(DMERR_BOUNDS, + "Output buffer limit hit, and is not expandable.\n"); + } - cur = (int) (z->zout - z->zout_start); - limit = (int) (z->zout_end - z->zout_start); + cur = ctx->zout - ctx->zoutStart; + limit = ctx->zoutEnd - ctx->zoutStart; while (cur + n > limit) limit *= 2; - if ((q = (char *) dmRealloc(z->zout_start, limit)) == NULL) - return stbi__err("outofmem", "Out of memory"); + if ((newBuf = (Uint8 *) dmRealloc(ctx->zoutStart, limit)) == NULL) + { + return dmError(DMERR_MALLOC, + "Could not reallocate buffer.\n"); + } - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; + ctx->zoutStart = newBuf; + ctx->zout = newBuf + cur; + ctx->zoutEnd = newBuf + limit; + + return DMERR_OK; } @@ -254,22 +272,23 @@ static int stbi__parse_huffman_block(DMZLibContext * a) { - char *zout = a->zout; + Uint8 *zout = a->zout; for (;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); + int z, ret; + if ((ret = stbi__zhuffman_decode(a, &a->zlength, &z)) != DMERR_OK) + return ret; + if (z < 256) { - if (z < 0) - return stbi__err("bad huffman code", "Corrupt PNG"); // error in huffman codes + if (zout >= a->zoutEnd) + { + if ((ret = stbi__zexpand(a, zout, 1)) != DMERR_OK) + return ret; - if (zout >= a->zout_end) - { - if (!stbi__zexpand(a, zout, 1)) - return 0; zout = a->zout; } - *zout++ = (char) z; + *zout++ = (Uint8) z; } else { @@ -278,7 +297,7 @@ if (z == 256) { a->zout = zout; - return 1; + return DMERR_OK; } z -= 257; @@ -286,18 +305,20 @@ if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) - return stbi__err("bad huffman code", "Corrupt PNG"); + if ((ret = stbi__zhuffman_decode(a, &a->zdistance, &z)) != DMERR_OK) + return ret; dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) - return stbi__err("bad dist", "Corrupt PNG"); + if (zout - a->zoutStart < dist) + { + return dmError(DMERR_DATA_ERROR, + "Bad Huffman block distance.\n"); + } - if (zout + len > a->zout_end) + if (zout + len > a->zoutEnd) { if (!stbi__zexpand(a, zout, len)) return 0; @@ -331,9 +352,9 @@ DMZHuffmanContext z_codelength; Uint8 lencodes[286 + 32 + 137]; //padding for maximum single op Uint8 codelength_sizes[19]; - int i, n; + int i, n, ret; - int hlit = stbi__zreceive(a, 5) + 257; + int hlit = stbi__zreceive(a, 5) + 257; int hdist = stbi__zreceive(a, 5) + 1; int hclen = stbi__zreceive(a, 4) + 4; @@ -344,15 +365,18 @@ int s = stbi__zreceive(a, 3); codelength_sizes[length_dezigzag[i]] = (Uint8) s; } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) - return 0; + if ((ret = stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) != DMERR_OK) + return ret; n = 0; while (n < hlit + hdist) { - int c = stbi__zhuffman_decode(a, &z_codelength); - STBI_ASSERT(c >= 0 && c < 19); + int c; + if ((ret = stbi__zhuffman_decode(a, &z_codelength, &c)) != DMERR_OK) + return ret; + + DMSTBI_ASSERT(c >= 0 && c < 19); if (c < 16) lencodes[n++] = (Uint8) c; @@ -379,14 +403,18 @@ } if (n != hlit + hdist) - return stbi__err("bad codelengths", "Corrupt PNG"); + { + return dmError(DMERR_DATA_ERROR, + "Bad huffman codelengths.\n"); + } - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) - return 0; + if ((ret = stbi__zbuild_huffman(&a->zlength, lencodes, hlit)) != DMERR_OK) + return ret; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes + hlit, hdist)) - return 0; - return 1; + if ((ret = stbi__zbuild_huffman(&a->zdistance, lencodes + hlit, hdist)) != DMERR_OK) + return ret; + + return DMERR_OK; } @@ -395,80 +423,97 @@ Uint8 header[4]; int len, nlen, k; - if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); // discard + if (a->numBits & 7) + stbi__zreceive(a, a->numBits & 7); // discard // drain the bit-packed data into header k = 0; - while (a->num_bits > 0) + while (a->numBits > 0) { - header[k++] = (Uint8) (a->code_buffer & 255); // suppress MSVC run-time check - a->code_buffer >>= 8; - a->num_bits -= 8; + header[k++] = (Uint8) (a->codeBuffer & 255); // suppress MSVC run-time check + a->codeBuffer >>= 8; + a->numBits -= 8; } - STBI_ASSERT(a->num_bits == 0); + DMSTBI_ASSERT(a->numBits == 0); // now fill header the normal way while (k < 4) header[k++] = stbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; + len = (header[1] << 8) | header[0]; + nlen = (header[3] << 8) | header[2]; if (nlen != (len ^ 0xffff)) - return stbi__err("zlib corrupt", "Corrupt PNG"); + { + return dmError(DMERR_DATA_ERROR, + "Compressed data corrupt.\n"); + } - if (a->zbuffer + len > a->zbuffer_end) - return stbi__err("read past buffer", "Corrupt PNG"); + if (a->zbuffer + len > a->zbufferEnd) + { + return dmError(DMERR_BOUNDS, + "Read past buffer, probably corrupt compressed data.\n"); + } - if (a->zout + len > a->zout_end && !stbi__zexpand(a, a->zout, len)) - return 0; + if (a->zout + len > a->zoutEnd && !stbi__zexpand(a, a->zout, len)) + { + return dmError(DMERR_DATA_ERROR, + "XXXX TODO"); + } memcpy(a->zout, a->zbuffer, len); a->zbuffer += len; - a->zout += len; - return 1; + a->zout += len; + + return DMERR_OK; } -static int stbi__parse_zlib_header(DMZLibContext * a) +int dmZLibParseHeader(DMZLibContext * ctx, BOOL checkPNG) { - int cmf = stbi__zget8(a); + int cmf = stbi__zget8(ctx); + int flags = stbi__zget8(ctx); int cm = cmf & 15; - int flg = stbi__zget8(a); // int cinfo = cmf >> 4; - if ((cmf * 256 + flg) % 31 != 0) - return stbi__err("bad zlib header", "Corrupt PNG"); // zlib spec + if ((cmf * 256 + flags) % 31 != 0) + { + return dmError(DMERR_INVALID_DATA, + "Bad zlib header."); + } - if (flg & 32) - return stbi__err("no preset dict", "Corrupt PNG"); // preset dictionary not allowed in png + if (checkPNG && (flags & 32)) + { + // preset dictionary not allowed in png + return dmError(DMERR_NOT_SUPPORTED, + "Preset dictionary not allowed in PNG.\n"); + } - if (cm != 8) - return stbi__err("bad compression", "Corrupt PNG"); // DEFLATE required for png + if (checkPNG && cm != 8) + { + return dmError(DMERR_INVALID_DATA, + "Bad or unsupported compression type.\n"); + } // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; + return DMERR_OK; } -static int stbi__parse_zlib(DMZLibContext * a, BOOL parse_header) +int dmZLibDecode(DMZLibContext * ctx) { - int final, type; + int final, type, ret; - if (parse_header && !stbi__parse_zlib_header(a)) - return 0; - - a->num_bits = 0; - a->code_buffer = 0; + ctx->numBits = 0; + ctx->codeBuffer = 0; do { - final = stbi__zreceive(a, 1); - type = stbi__zreceive(a, 2); + final = stbi__zreceive(ctx, 1); + type = stbi__zreceive(ctx, 2); if (type == 0) { - if (!stbi__parse_uncompressed_block(a)) - return 0; + if ((ret = stbi__parse_uncompressed_block(ctx)) != DMERR_OK) + return ret; } else if (type == 3) @@ -478,136 +523,127 @@ if (type == 1) { // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length, stbi__zdefault_length, 288)) - return 0; + if ((ret = stbi__zbuild_huffman(&ctx->zlength, stbi__zdefault_length, 288)) != DMERR_OK) + return ret; - if (!stbi__zbuild_huffman - (&a->z_distance, stbi__zdefault_distance, 32)) - return 0; + if ((ret = stbi__zbuild_huffman(&ctx->zdistance, stbi__zdefault_distance, 32)) != DMERR_OK) + return ret; } else - { - if (!stbi__compute_huffman_codes(a)) - return 0; - } - if (!stbi__parse_huffman_block(a)) - return 0; + if ((ret = stbi__compute_huffman_codes(ctx)) != DMERR_OK) + return ret; + + if ((ret = stbi__parse_huffman_block(ctx)) != DMERR_OK) + return ret; } } while (!final); - return 1; + + return DMERR_OK; } -static int stbi__do_zlib(DMZLibContext * a, char *obuf, int olen, int exp, - BOOL parse_header) +Uint8 *stbi_zlib_decode_malloc_guesssize_headerflag( + const Uint8 *buffer, const size_t len, + const size_t initialSize, size_t *outLen, + BOOL parseHeader) { - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; + DMZLibContext ctx; + Uint8 *outBuf; + int ret; - return stbi__parse_zlib(a, parse_header); -} - + if ((outBuf = dmMalloc(initialSize)) == NULL) + return NULL; -char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - DMZLibContext a; - char *p = (char *) dmMalloc(initial_size); - if (p == NULL) - return NULL; - a.zbuffer = (Uint8 *) buffer; - a.zbuffer_end = (Uint8 *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, 1)) + ctx.zbuffer = (Uint8 *) buffer; + ctx.zbufferEnd = (Uint8 *) buffer + len; + ctx.zout = outBuf; + ctx.zoutStart = outBuf; + ctx.zoutEnd = outBuf + initialSize; + ctx.expandable = TRUE; + + if (parseHeader && (ret = dmZLibParseHeader(&ctx, TRUE)) != DMERR_OK) { - if (outlen) - *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; + return dmError(ret, + "Failed to parse zlib header data.\n"); + } + + if ((ret = dmZLibDecode(&ctx)) != DMERR_OK) + { + if (outLen) + *outLen = ctx.zout - ctx.zoutStart; + + return ctx.zoutStart; } else { - dmFree(a.zout_start); + dmFree(ctx.zoutStart); return NULL; } } -char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +#if 0 + +Uint8 *stbi_zlib_decode_malloc(Uint8 const *buffer, int len, int *outlen) { return stbi_zlib_decode_malloc_guesssize(buffer, len, DM_ZLIB_TMPBUF_SIZE, outlen); } -char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, - int len, int initial_size, int *outlen, BOOL parse_header) +int stbi_zlib_decode_buffer(Uint8 *obuffer, size_t olen, Uint8 const *ibuffer, size_t ilen, size_t *res) { - DMZLibContext a; - char *p = (char *) dmMalloc(initial_size); + DMZLibContext ctx; + int ret; + + ctx.zbuffer = (Uint8 *) ibuffer; + ctx.zbufferEnd = (Uint8 *) ibuffer + ilen; + + if ((ret = stbi__do_zlib(&a, obuffer, olen, 0, 1)) != DMERR_OK) + { + *res = a.zout - a.zoutStart; + return DMERR_OK; + } + else + return ret; +} + + +Uint8 *stbi_zlib_decode_noheader_malloc(Uint8 const *buffer, int len, size_t *outlen) +{ + DMZLibContext ctx; + Uint8 *p = (Uint8 *) dmMalloc(DM_ZLIB_TMPBUF_SIZE); if (p == NULL) return NULL; - a.zbuffer = (Uint8 *) buffer; - a.zbuffer_end = (Uint8 *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) + ctx.zbuffer = (Uint8 *) buffer; + ctx.zbufferEnd = (Uint8 *) buffer + len; + + if (stbi__do_zlib(&ctx, p, DM_ZLIB_TMPBUF_SIZE, 1, 0)) { - if (outlen) - *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; + if (outlen != NULL) + *outlen = (int) (ctx.zout - a.zoutStart); + return a.zoutStart; } else { - dmFree(a.zout_start); + dmFree(a.zoutStart); return NULL; } } -int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +int stbi_zlib_decode_noheader_buffer(Uint8 *obuffer, int olen, const Uint8 *ibuffer, int ilen) { DMZLibContext a; + a.zbuffer = (Uint8 *) ibuffer; - a.zbuffer_end = (Uint8 *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); + a.zbufferEnd = (Uint8 *) ibuffer + ilen; + + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zoutStart); else return -1; } - -char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - DMZLibContext a; - char *p = (char *) dmMalloc(DM_ZLIB_TMPBUF_SIZE); - if (p == NULL) - return NULL; - - a.zbuffer = (Uint8 *) buffer; - a.zbuffer_end = (Uint8 *) buffer + len; - - if (stbi__do_zlib(&a, p, DM_ZLIB_TMPBUF_SIZE, 1, 0)) - { - if (outlen != NULL) - *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } - else - { - dmFree(a.zout_start); - return NULL; - } -} - - -int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - DMZLibContext a; - - a.zbuffer = (Uint8 *) ibuffer; - a.zbuffer_end = (Uint8 *) ibuffer + ilen; - - if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; -} +#endif