diff options
Diffstat (limited to 'lodepng.cpp')
-rw-r--r-- | lodepng.cpp | 920 |
1 files changed, 463 insertions, 457 deletions
diff --git a/lodepng.cpp b/lodepng.cpp index 2ef6766..1130afe 100644 --- a/lodepng.cpp +++ b/lodepng.cpp @@ -1,5 +1,5 @@ /* -LodePNG version 20200219 +LodePNG version 20200306 Copyright (c) 2005-2020 Lode Vandevenne @@ -44,7 +44,7 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ #endif /*_MSC_VER */ -const char* LODEPNG_VERSION_STRING = "20200219"; +const char* LODEPNG_VERSION_STRING = "20200306"; /* This source file is built up in the following large parts. The code sections @@ -231,7 +231,7 @@ static void uivector_cleanup(void* p) { static unsigned uivector_resize(uivector* p, size_t size) { size_t allocsize = size * sizeof(unsigned); if(allocsize > p->allocsize) { - size_t newsize = (allocsize > p->allocsize * 2u) ? allocsize : ((allocsize * 3u) >> 1u); + size_t newsize = allocsize + (p->allocsize >> 1u); void* data = lodepng_realloc(p->data, newsize); if(data) { p->allocsize = newsize; @@ -269,7 +269,7 @@ typedef struct ucvector { /*returns 1 if success, 0 if failure ==> nothing done*/ static unsigned ucvector_resize(ucvector* p, size_t size) { if(size > p->allocsize) { - size_t newsize = (size > p->allocsize * 2u) ? size : ((size * 3u) >> 1u); + size_t newsize = size + (p->allocsize >> 1u); void* data = lodepng_realloc(p->data, newsize); if(data) { p->allocsize = newsize; @@ -281,38 +281,12 @@ static unsigned ucvector_resize(ucvector* p, size_t size) { return 1; /*success*/ } -#ifdef LODEPNG_COMPILE_PNG - -static void ucvector_cleanup(void* p) { - ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; - lodepng_free(((ucvector*)p)->data); - ((ucvector*)p)->data = NULL; -} - -static void ucvector_init(ucvector* p) { - p->data = NULL; - p->size = p->allocsize = 0; -} -#endif /*LODEPNG_COMPILE_PNG*/ - -#ifdef LODEPNG_COMPILE_ZLIB -/*you can both convert from vector to buffer&size and vice versa. If you use -init_buffer to take over a buffer and size, it is not needed to use cleanup*/ -static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) { - p->data = buffer; - p->allocsize = p->size = size; -} -#endif /*LODEPNG_COMPILE_ZLIB*/ - -#if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER) -/*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned ucvector_push_back(ucvector* p, unsigned char c) { - if(!ucvector_resize(p, p->size + 1)) return 0; - p->data[p->size - 1] = c; - return 1; +static ucvector ucvector_init(unsigned char* buffer, size_t size) { + ucvector v; + v.data = buffer; + v.allocsize = v.size = size; + return v; } -#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ - /* ////////////////////////////////////////////////////////////////////////// */ @@ -325,19 +299,19 @@ static void string_cleanup(char** out) { *out = NULL; } -/* dynamically allocates a new string with a copy of the null terminated input text */ -static char* alloc_string(const char* in) { - size_t insize = lodepng_strlen(in); +static char* alloc_string_sized(const char* in, size_t insize) { char* out = (char*)lodepng_malloc(insize + 1); if(out) { - size_t i; - for(i = 0; i != insize; ++i) { - out[i] = in[i]; - } - out[i] = 0; + lodepng_memcpy(out, in, insize); + out[insize] = 0; } return out; } + +/* dynamically allocates a new string with a copy of the null terminated input text */ +static char* alloc_string(const char* in) { + return alloc_string_sized(in, lodepng_strlen(in)); +} #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ #endif /*LODEPNG_COMPILE_PNG*/ @@ -434,18 +408,21 @@ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const typedef struct { ucvector* data; - size_t bp; + unsigned char bp; /*ok to overflow, indicates bit pos inside byte*/ } LodePNGBitWriter; -void LodePNGBitWriter_init(LodePNGBitWriter* writer, ucvector* data) { +static void LodePNGBitWriter_init(LodePNGBitWriter* writer, ucvector* data) { writer->data = data; writer->bp = 0; } /*TODO: this ignores potential out of memory errors*/ -#define WRITEBIT(/*size_t**/ writer, /*unsigned char*/ bit){\ +#define WRITEBIT(writer, bit){\ /* append new byte */\ - if(((writer->bp) & 7u) == 0) ucvector_push_back(writer->data, (unsigned char)0);\ + if(((writer->bp) & 7u) == 0) {\ + if(!ucvector_resize(writer->data, writer->data->size + 1)) return;\ + writer->data->data[writer->data->size - 1] = 0;\ + }\ (writer->data->data[writer->data->size - 1]) |= (bit << ((writer->bp) & 7u));\ ++writer->bp;\ } @@ -455,7 +432,7 @@ static void writeBits(LodePNGBitWriter* writer, unsigned value, size_t nbits) { if(nbits == 1) { /* compiler should statically compile this case if nbits == 1 */ WRITEBIT(writer, value); } else { - /* TODO: increase output size nly once here rather than in each WRITEBIT */ + /* TODO: increase output size only once here rather than in each WRITEBIT */ size_t i; for(i = 0; i != nbits; ++i) { WRITEBIT(writer, (unsigned char)((value >> i) & 1)); @@ -610,7 +587,8 @@ unsigned lode_png_test_bitreader(const unsigned char* data, size_t size, size_t numsteps, const size_t* steps, unsigned* result) { size_t i; LodePNGBitReader reader; - LodePNGBitReader_init(&reader, data, size); + unsigned error = LodePNGBitReader_init(&reader, data, size); + if(error) return 0; for(i = 0; i < numsteps; i++) { size_t step = steps[i]; unsigned ok; @@ -716,7 +694,7 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { if(!maxlens) return 83; /*alloc fail*/ /* compute maxlens: max total bit length of symbols sharing prefix in the first table*/ - for(i = 0; i < headsize; ++i) maxlens[i] = 0; + lodepng_memset(maxlens, 0, headsize * sizeof(*maxlens)); for(i = 0; i < tree->numcodes; i++) { unsigned symbol = tree->codes[i]; unsigned l = tree->lengths[i]; @@ -1281,7 +1259,7 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, } /*inflate a block with dynamic of fixed Huffman tree. btype must be 1 or 2.*/ -static unsigned inflateHuffmanBlock(ucvector* out, size_t* pos, LodePNGBitReader* reader, +static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, unsigned btype) { unsigned error = 0; HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ @@ -1299,10 +1277,8 @@ static unsigned inflateHuffmanBlock(ucvector* out, size_t* pos, LodePNGBitReader ensureBits25(reader, 20); /* up to 15 for the huffman symbol, up to 5 for the length extra bits */ code_ll = huffmanDecodeSymbol(reader, &tree_ll); if(code_ll <= 255) /*literal symbol*/ { - /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/ - if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/); - out->data[*pos] = (unsigned char)code_ll; - ++(*pos); + if(!ucvector_resize(out, out->size + 1)) ERROR_BREAK(83 /*alloc fail*/); + out->data[out->size - 1] = (unsigned char)code_ll; } else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ { unsigned code_d, distance; unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ @@ -1338,21 +1314,20 @@ static unsigned inflateHuffmanBlock(ucvector* out, size_t* pos, LodePNGBitReader } /*part 5: fill in all the out[n] values based on the length and dist*/ - start = (*pos); + start = out->size; if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ backward = start - distance; - if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/); + if(!ucvector_resize(out, out->size + length)) ERROR_BREAK(83 /*alloc fail*/); if(distance < length) { size_t forward; - lodepng_memcpy(out->data + *pos, out->data + backward, distance); - *pos += distance; + lodepng_memcpy(out->data + start, out->data + backward, distance); + start += distance; for(forward = distance; forward < length; ++forward) { - out->data[(*pos)++] = out->data[backward++]; + out->data[start++] = out->data[backward++]; } } else { - lodepng_memcpy(out->data + *pos, out->data + backward, length); - *pos += length; + lodepng_memcpy(out->data + start, out->data + backward, length); } } else if(code_ll == 256) { break; /*end code, break the loop*/ @@ -1374,8 +1349,8 @@ static unsigned inflateHuffmanBlock(ucvector* out, size_t* pos, LodePNGBitReader return error; } -static unsigned inflateNoCompression(ucvector* out, size_t* pos, - LodePNGBitReader* reader, const LodePNGDecompressSettings* settings) { +static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader, + const LodePNGDecompressSettings* settings) { size_t bytepos; size_t size = reader->size; unsigned LEN, NLEN, error = 0; @@ -1393,13 +1368,12 @@ static unsigned inflateNoCompression(ucvector* out, size_t* pos, return 21; /*error: NLEN is not one's complement of LEN*/ } - if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ + if(!ucvector_resize(out, out->size + LEN)) return 83; /*alloc fail*/ /*read the literal data: LEN bytes are now stored in the out buffer*/ if(bytepos + LEN > size) return 23; /*error: reading outside of in buffer*/ - lodepng_memcpy(out->data + *pos, reader->data + bytepos, LEN); - *pos += LEN; + lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN); bytepos += LEN; reader->bp = bytepos << 3u; @@ -1411,7 +1385,6 @@ static unsigned lodepng_inflatev(ucvector* out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { unsigned BFINAL = 0; - size_t pos = 0; /*byte position in the out buffer*/ LodePNGBitReader reader; unsigned error = LodePNGBitReader_init(&reader, in, insize); @@ -1424,8 +1397,8 @@ static unsigned lodepng_inflatev(ucvector* out, BTYPE = readBits(&reader, 2); if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ - else if(BTYPE == 0) error = inflateNoCompression(out, &pos, &reader, settings); /*no compression*/ - else error = inflateHuffmanBlock(out, &pos, &reader, BTYPE); /*compression, BTYPE 01 or 10*/ + else if(BTYPE == 0) error = inflateNoCompression(out, &reader, settings); /*no compression*/ + else error = inflateHuffmanBlock(out, &reader, BTYPE); /*compression, BTYPE 01 or 10*/ if(error) return error; } @@ -1436,22 +1409,21 @@ static unsigned lodepng_inflatev(ucvector* out, unsigned lodepng_inflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { - unsigned error; - ucvector v; - ucvector_init_buffer(&v, *out, *outsize); - error = lodepng_inflatev(&v, in, insize, settings); + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_inflatev(&v, in, insize, settings); *out = v.data; *outsize = v.size; return error; } -static unsigned inflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, +static unsigned inflatev(ucvector* out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { if(settings->custom_inflate) { - return settings->custom_inflate(out, outsize, in, insize, settings); + unsigned error = settings->custom_inflate(&out->data, &out->size, in, insize, settings); + out->allocsize = out->size; + return error; } else { - return lodepng_inflate(out, outsize, in, insize, settings); + return lodepng_inflatev(out, in, insize, settings); } } @@ -1493,10 +1465,15 @@ static void addLengthDistance(uivector* values, size_t length, size_t distance) unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); - uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); - uivector_push_back(values, extra_length); - uivector_push_back(values, dist_code); - uivector_push_back(values, extra_distance); + size_t pos = values->size; + /*TODO: return error when this fails (out of memory)*/ + unsigned ok = uivector_resize(values, values->size + 4); + if(ok) { + values->data[pos + 0] = length_code + FIRST_LENGTH_CODE_INDEX; + values->data[pos + 1] = extra_length; + values->data[pos + 2] = dist_code; + values->data[pos + 3] = extra_distance; + } } /*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 @@ -1758,31 +1735,30 @@ static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, s /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ - size_t i, j, numdeflateblocks = (datasize + 65534u) / 65535u; + size_t i, numdeflateblocks = (datasize + 65534u) / 65535u; unsigned datapos = 0; for(i = 0; i != numdeflateblocks; ++i) { unsigned BFINAL, BTYPE, LEN, NLEN; unsigned char firstbyte; + size_t pos = out->size; BFINAL = (i == numdeflateblocks - 1); BTYPE = 0; - firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1u) << 1u) + ((BTYPE & 2u) << 1u)); - ucvector_push_back(out, firstbyte); - LEN = 65535; if(datasize - datapos < 65535u) LEN = (unsigned)datasize - datapos; NLEN = 65535 - LEN; - ucvector_push_back(out, (unsigned char)(LEN & 255)); - ucvector_push_back(out, (unsigned char)(LEN >> 8u)); - ucvector_push_back(out, (unsigned char)(NLEN & 255)); - ucvector_push_back(out, (unsigned char)(NLEN >> 8u)); + if(!ucvector_resize(out, out->size + LEN + 5)) return 83; /*alloc fail*/ - /*Decompressed data*/ - for(j = 0; j < 65535 && datapos < datasize; ++j) { - ucvector_push_back(out, data[datapos++]); - } + firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1u) << 1u) + ((BTYPE & 2u) << 1u)); + out->data[pos + 0] = firstbyte; + out->data[pos + 1] = (unsigned char)(LEN & 255); + out->data[pos + 2] = (unsigned char)(LEN >> 8u); + out->data[pos + 3] = (unsigned char)(NLEN & 255); + out->data[pos + 4] = (unsigned char)(NLEN >> 8u); + lodepng_memcpy(out->data + pos + 5, data + datapos, LEN); + datapos += LEN; } return 0; @@ -2129,10 +2105,8 @@ static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t unsigned lodepng_deflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { - unsigned error; - ucvector v; - ucvector_init_buffer(&v, *out, *outsize); - error = lodepng_deflatev(&v, in, insize, settings); + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_deflatev(&v, in, insize, settings); *out = v.data; *outsize = v.size; return error; @@ -2185,8 +2159,9 @@ static unsigned adler32(const unsigned char* data, unsigned len) { #ifdef LODEPNG_COMPILE_DECODER -unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGDecompressSettings* settings) { +static unsigned lodepng_zlib_decompressv(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) { unsigned error = 0; unsigned CM, CINFO, FDICT; @@ -2213,24 +2188,45 @@ unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const uns return 26; } - error = inflate(out, outsize, in + 2, insize - 2, settings); + error = inflatev(out, in + 2, insize - 2, settings); if(error) return error; if(!settings->ignore_adler32) { unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); - unsigned checksum = adler32(*out, (unsigned)(*outsize)); + unsigned checksum = adler32(out->data, (unsigned)(out->size)); if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ } return 0; /*no error*/ } -static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGDecompressSettings* settings) { + +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) { + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_zlib_decompressv(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +/*expected_size is expected output size, to avoid intermediate allocations. Set to 0 if not known. */ +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size, + const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { if(settings->custom_zlib) { return settings->custom_zlib(out, outsize, in, insize, settings); } else { - return lodepng_zlib_decompress(out, outsize, in, insize, settings); + unsigned error; + ucvector v = ucvector_init(*out, *outsize); + if(expected_size) { + /*reserve the memory to avoid intermediate reallocations*/ + ucvector_resize(&v, *outsize + expected_size); + v.size = *outsize; + } + error = lodepng_zlib_decompressv(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; } } @@ -2290,9 +2286,10 @@ static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsign #else /*no LODEPNG_COMPILE_ZLIB*/ #ifdef LODEPNG_COMPILE_DECODER -static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGDecompressSettings* settings) { +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size, + const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + (void)expected_size; return settings->custom_zlib(out, outsize, in, insize, settings); } #endif /*LODEPNG_COMPILE_DECODER*/ @@ -2543,18 +2540,18 @@ const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const } } -unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk) { +unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk) { unsigned i; size_t total_chunk_length, new_length; unsigned char *chunk_start, *new_buffer; if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return 77; - if(lodepng_addofl(*outlength, total_chunk_length, &new_length)) return 77; + if(lodepng_addofl(*outsize, total_chunk_length, &new_length)) return 77; new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); if(!new_buffer) return 83; /*alloc fail*/ (*out) = new_buffer; - (*outlength) = new_length; + (*outsize) = new_length; chunk_start = &(*out)[new_length - total_chunk_length]; for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i]; @@ -2562,30 +2559,36 @@ unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsi return 0; } -unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, - const char* type, const unsigned char* data) { - unsigned i; - unsigned char *chunk, *new_buffer; - size_t new_length = *outlength; +/*Sets length and name and allocates the space for data and crc but does not +set data or crc yet. Returns the start of the chunk in chunk. The start of +the data is at chunk + 8. To finalize chunk, add the data, then use +lodepng_chunk_generate_crc */ +static unsigned lodepng_chunk_init(unsigned char** chunk, + ucvector* out, + unsigned length, const char* type) { + size_t new_length = out->size; if(lodepng_addofl(new_length, length, &new_length)) return 77; if(lodepng_addofl(new_length, 12, &new_length)) return 77; - new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); - if(!new_buffer) return 83; /*alloc fail*/ - (*out) = new_buffer; - (*outlength) = new_length; - chunk = &(*out)[(*outlength) - length - 12]; + if(!ucvector_resize(out, new_length)) return 83; /*alloc fail*/ + *chunk = out->data + new_length - length - 12u; /*1: length*/ - lodepng_set32bitInt(chunk, (unsigned)length); + lodepng_set32bitInt(*chunk, length); /*2: chunk name (4 letters)*/ - chunk[4] = (unsigned char)type[0]; - chunk[5] = (unsigned char)type[1]; - chunk[6] = (unsigned char)type[2]; - chunk[7] = (unsigned char)type[3]; + lodepng_memcpy(*chunk + 4, type, 4); + + return 0; +} + +/* like lodepng_chunk_create but with custom allocsize */ +static unsigned lodepng_chunk_createv(ucvector* out, + unsigned length, const char* type, const unsigned char* data) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, length, type)); /*3: the data*/ - for(i = 0; i != length; ++i) chunk[8 + i] = data[i]; + lodepng_memcpy(chunk + 8, data, length); /*4: CRC (of the chunkname characters and the data)*/ lodepng_chunk_generate_crc(chunk); @@ -2593,6 +2596,15 @@ unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned l return 0; } +unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, + unsigned length, const char* type, const unsigned char* data) { + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_chunk_createv(&v, length, type, data); + *out = v.data; + *outsize = v.size; + return error; +} + /* ////////////////////////////////////////////////////////////////////////// */ /* / Color types, channels, bits / */ /* ////////////////////////////////////////////////////////////////////////// */ @@ -2869,11 +2881,7 @@ static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { return 0; } -void lodepng_clear_text(LodePNGInfo* info) { - LodePNGText_cleanup(info); -} - -unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) { +static unsigned lodepng_add_text_sized(LodePNGInfo* info, const char* key, const char* str, size_t size) { char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); @@ -2883,13 +2891,21 @@ unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) { if(!new_keys || !new_strings) return 83; /*alloc fail*/ ++info->text_num; - info->text_keys[info->text_num - 1] = alloc_string(key); - info->text_strings[info->text_num - 1] = alloc_string(str); + info->text_strings[info->text_num - 1] = alloc_string_sized(str, size); + if(!info->text_keys[info->text_num - 1] || !info->text_strings[info->text_num - 1]) return 83; /*alloc fail*/ return 0; } +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) { + return lodepng_add_text_sized(info, key, str, lodepng_strlen(str)); +} + +void lodepng_clear_text(LodePNGInfo* info) { + LodePNGText_cleanup(info); +} + /******************************************************************************/ static void LodePNGIText_init(LodePNGInfo* info) { @@ -2932,8 +2948,8 @@ void lodepng_clear_itext(LodePNGInfo* info) { LodePNGIText_cleanup(info); } -unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, - const char* transkey, const char* str) { +static unsigned lodepng_add_itext_sized(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str, size_t size) { char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); @@ -2951,11 +2967,16 @@ unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langt info->itext_keys[info->itext_num - 1] = alloc_string(key); info->itext_langtags[info->itext_num - 1] = alloc_string(langtag); info->itext_transkeys[info->itext_num - 1] = alloc_string(transkey); - info->itext_strings[info->itext_num - 1] = alloc_string(str); + info->itext_strings[info->itext_num - 1] = alloc_string_sized(str, size); return 0; } +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str) { + return lodepng_add_itext_sized(info, key, langtag, transkey, str, lodepng_strlen(str)); +} + /* same as set but does not delete */ static unsigned lodepng_assign_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size) { if(profile_size == 0) return 100; /*invalid ICC profile size*/ @@ -3493,7 +3514,7 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, if(lodepng_color_mode_equal(mode_out, mode_in)) { size_t numbytes = lodepng_get_raw_size(w, h, mode_in); - for(i = 0; i != numbytes; ++i) out[i] = in[i]; + lodepng_memcpy(out, in, numbytes); return 0; } @@ -3512,7 +3533,7 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, even in case there are duplicate colors in the palette.*/ if(mode_in->colortype == LCT_PALETTE && mode_in->bitdepth == mode_out->bitdepth) { size_t numbytes = lodepng_get_raw_size(w, h, mode_in); - for(i = 0; i != numbytes; ++i) out[i] = in[i]; + lodepng_memcpy(out, in, numbytes); return 0; } } @@ -3690,7 +3711,7 @@ unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, /*Check if the 16-bit input is truly 16-bit*/ if(mode_in->bitdepth == 16 && !sixteen) { - unsigned short r, g, b, a; + unsigned short r = 0, g = 0, b = 0, a = 0; for(i = 0; i != numpixels; ++i) { getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || @@ -4148,7 +4169,7 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan } } break; - default: return 36; /*error: nonexistent filter type given*/ + default: return 36; /*error: invalid filter type given*/ } return 0; } @@ -4389,7 +4410,6 @@ static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, siz static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { unsigned error = 0; char *key = 0, *str = 0; - unsigned i; while(!error) /*not really a while loop, only used to break on error*/ { unsigned length, string2_begin; @@ -4403,8 +4423,8 @@ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, siz key = (char*)lodepng_malloc(length + 1); if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + lodepng_memcpy(key, data, length); key[length] = 0; - for(i = 0; i != length; ++i) key[i] = (char)data[i]; string2_begin = length + 1; /*skip keyword null terminator*/ @@ -4412,8 +4432,8 @@ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, siz str = (char*)lodepng_malloc(length + 1); if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ + lodepng_memcpy(str, data + string2_begin, length); str[length] = 0; - for(i = 0; i != length; ++i) str[i] = (char)data[string2_begin + i]; error = lodepng_add_text(info, key, str); @@ -4430,13 +4450,11 @@ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, siz static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, const unsigned char* data, size_t chunkLength) { unsigned error = 0; - unsigned i; unsigned length, string2_begin; char *key = 0; - ucvector decoded; - - ucvector_init(&decoded); + unsigned char* str = 0; + size_t size = 0; while(!error) /*not really a while loop, only used to break on error*/ { for(length = 0; length < chunkLength && data[length] != 0; ++length) ; @@ -4446,8 +4464,8 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSetting key = (char*)lodepng_malloc(length + 1); if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + lodepng_memcpy(key, data, length); key[length] = 0; - for(i = 0; i != length; ++i) key[i] = (char)data[i]; if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ @@ -4456,19 +4474,16 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSetting length = (unsigned)chunkLength - string2_begin; /*will fail if zlib error, e.g. if length is too small*/ - error = zlib_decompress(&decoded.data, &decoded.size, - &data[string2_begin], + error = zlib_decompress(&str, &size, 0, &data[string2_begin], length, zlibsettings); if(error) break; - ucvector_push_back(&decoded, 0); - - error = lodepng_add_text(info, key, (char*)decoded.data); + error = lodepng_add_text_sized(info, key, (char*)str, size); break; } lodepng_free(key); - ucvector_cleanup(&decoded); + lodepng_free(str); return error; } @@ -4481,8 +4496,6 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting unsigned length, begin, compressed; char *key = 0, *langtag = 0, *transkey = 0; - ucvector decoded; - ucvector_init(&decoded); /* TODO: only use in case of compressed text */ while(!error) /*not really a while loop, only used to break on error*/ { /*Quick check if the chunk length isn't too small. Even without check @@ -4497,8 +4510,8 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting key = (char*)lodepng_malloc(length + 1); if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + lodepng_memcpy(key, data, length); key[length] = 0; - for(i = 0; i != length; ++i) key[i] = (char)data[i]; /*read the compression method*/ compressed = data[length + 1]; @@ -4515,8 +4528,8 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting langtag = (char*)lodepng_malloc(length + 1); if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ + lodepng_memcpy(langtag, data + begin, length); langtag[length] = 0; - for(i = 0; i != length; ++i) langtag[i] = (char)data[begin + i]; /*read the transkey*/ begin += length + 1; @@ -4526,8 +4539,8 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting transkey = (char*)lodepng_malloc(length + 1); if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ + lodepng_memcpy(transkey, data + begin, length); transkey[length] = 0; - for(i = 0; i != length; ++i) transkey[i] = (char)data[begin + i]; /*read the actual text*/ begin += length + 1; @@ -4535,29 +4548,23 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting length = (unsigned)chunkLength < begin ? 0 : (unsigned)chunkLength - begin; if(compressed) { + unsigned char* str = 0; + size_t size = 0; /*will fail if zlib error, e.g. if length is too small*/ - error = zlib_decompress(&decoded.data, &decoded.size, - &data[begin], + error = zlib_decompress(&str, &size, 0, &data[begin], length, zlibsettings); - if(error) break; - if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size; - ucvector_push_back(&decoded, 0); + if(!error) error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)str, size); + lodepng_free(str); } else { - if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); - - decoded.data[length] = 0; - for(i = 0; i != length; ++i) decoded.data[i] = data[begin + i]; + error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)(data + begin), length); } - error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); - break; } lodepng_free(key); lodepng_free(langtag); lodepng_free(transkey); - ucvector_cleanup(&decoded); return error; } @@ -4625,9 +4632,9 @@ static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecompressSetting const unsigned char* data, size_t chunkLength) { unsigned error = 0; unsigned i; + size_t size = 0; unsigned length, string2_begin; - ucvector decoded; info->iccp_defined = 1; if(info->iccp_name) lodepng_clear_icc(info); @@ -4648,24 +4655,11 @@ static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecompressSetting if(string2_begin > chunkLength) return 75; /*no null termination, corrupt?*/ length = (unsigned)chunkLength - string2_begin; - ucvector_init(&decoded); - error = zlib_decompress(&decoded.data, &decoded.size, + error = zlib_decompress(&info->iccp_profile, &size, 0, &data[string2_begin], length, zlibsettings); - if(!error) { - if(decoded.size) { - info->iccp_profile_size = decoded.size; - info->iccp_profile = (unsigned char*)lodepng_malloc(decoded.size); - if(info->iccp_profile) { - lodepng_memcpy(info->iccp_profile, decoded.data, decoded.size); - } else { - error = 83; /* alloc fail */ - } - } else { - error = 100; /*invalid ICC profile size*/ - } - } - ucvector_cleanup(&decoded); + info->iccp_profile_size = size; + if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/ return error; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ @@ -4728,8 +4722,8 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { unsigned char IEND = 0; const unsigned char* chunk; - size_t i; - ucvector idat; /*the data from idat chunks*/ + unsigned char* idat; /*the data from idat chunks, zlib compressed*/ + size_t idatsize = 0; unsigned char* scanlines = 0; size_t scanlines_size = 0, expected_size = 0; size_t outsize = 0; @@ -4752,7 +4746,10 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, CERROR_RETURN(state->error, 92); /*overflow possible due to amount of pixels*/ } - ucvector_init(&idat); + /*the input filesize is a safe upper bound for the sum of idat chunks size*/ + idat = (unsigned char*)lodepng_malloc(insize); + if(!idat) CERROR_RETURN(state->error, 83); /*alloc fail*/ + chunk = &in[33]; /*first byte of the first chunk after the header*/ /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. @@ -4785,11 +4782,11 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, /*IDAT chunk, containing compressed image data*/ if(lodepng_chunk_type_equals(chunk, "IDAT")) { - size_t oldsize = idat.size; size_t newsize; - if(lodepng_addofl(oldsize, chunkLength, &newsize)) CERROR_BREAK(state->error, 95); - if(!ucvector_resize(&idat, newsize)) CERROR_BREAK(state->error, 83 /*alloc fail*/); - for(i = 0; i != chunkLength; ++i) idat.data[oldsize + i] = data[i]; + if(lodepng_addofl(idatsize, chunkLength, &newsize)) CERROR_BREAK(state->error, 95); + if(newsize > insize) CERROR_BREAK(state->error, 95); + lodepng_memcpy(idat + idatsize, data, chunkLength); + idatsize += chunkLength; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS critical_pos = 3; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ @@ -4878,38 +4875,29 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, state->error = 106; /* error: PNG file must have PLTE chunk if color type is palette */ } - /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. - If the decompressed size does not match the prediction, the image must be corrupt.*/ - if(state->info_png.interlace_method == 0) { - size_t bpp = lodepng_get_bpp(&state->info_png.color); - expected_size = lodepng_get_raw_size_idat(*w, *h, bpp); - } else { - size_t bpp = lodepng_get_bpp(&state->info_png.color); - /*Adam-7 interlaced: expected size is the sum of the 7 sub-images sizes*/ - expected_size = 0; - expected_size += lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, bpp); - if(*w > 4) expected_size += lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, bpp); - expected_size += lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, bpp); - if(*w > 2) expected_size += lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, bpp); - expected_size += lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, bpp); - if(*w > 1) expected_size += lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, bpp); - expected_size += lodepng_get_raw_size_idat((*w + 0), (*h + 0) >> 1, bpp); - } if(!state->error) { - /* This allocated data will be realloced by zlib_decompress, initially at - smaller size again. But the fact that it's already allocated at full size - here speeds the multiple reallocs up. TODO: make zlib_decompress support - receiving already allocated buffer with expected size instead. */ - scanlines = (unsigned char*)lodepng_malloc(expected_size); - if(!scanlines) state->error = 83; /*alloc fail*/ - scanlines_size = 0; - } - if(!state->error) { - state->error = zlib_decompress(&scanlines, &scanlines_size, idat.data, - idat.size, &state->decoder.zlibsettings); - if(!state->error && scanlines_size != expected_size) state->error = 91; /*decompressed size doesn't match prediction*/ + /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. + If the decompressed size does not match the prediction, the image must be corrupt.*/ + if(state->info_png.interlace_method == 0) { + size_t bpp = lodepng_get_bpp(&state->info_png.color); + expected_size = lodepng_get_raw_size_idat(*w, *h, bpp); + } else { + size_t bpp = lodepng_get_bpp(&state->info_png.color); + /*Adam-7 interlaced: expected size is the sum of the 7 sub-images sizes*/ + expected_size = 0; + expected_size += lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, bpp); + if(*w > 4) expected_size += lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, bpp); + expected_size += lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, bpp); + if(*w > 2) expected_size += lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, bpp); + expected_size += lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, bpp); + if(*w > 1) expected_size += lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, bpp); + expected_size += lodepng_get_raw_size_idat((*w + 0), (*h + 0) >> 1, bpp); + } + + state->error = zlib_decompress(&scanlines, &scanlines_size, expected_size, idat, idatsize, &state->decoder.zlibsettings); } - ucvector_cleanup(&idat); + if(!state->error && scanlines_size != expected_size) state->error = 91; /*decompressed size doesn't match prediction*/ + lodepng_free(idat); if(!state->error) { outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); @@ -5054,28 +5042,21 @@ void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) { /* / PNG Encoder / */ /* ////////////////////////////////////////////////////////////////////////// */ -/*chunkName must be string of 4 characters*/ -static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) { - CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data)); - out->allocsize = out->size; /*fix the allocsize again*/ - return 0; -} -static void writeSignature(ucvector* out) { +static unsigned writeSignature(ucvector* out) { + size_t pos = out->size; + const unsigned char signature[] = {137, 80, 78, 71, 13, 10, 26, 10}; /*8 bytes PNG signature, aka the magic bytes*/ - ucvector_push_back(out, 137); - ucvector_push_back(out, 80); - ucvector_push_back(out, 78); - ucvector_push_back(out, 71); - ucvector_push_back(out, 13); - ucvector_push_back(out, 10); - ucvector_push_back(out, 26); - ucvector_push_back(out, 10); + if(!ucvector_resize(out, out->size + 8)) return 83; /*alloc fail*/ + lodepng_memcpy(out->data + pos, signature, 8); + return 0; } static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) { - unsigned char data[13]; + unsigned char *chunk, *data; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 13, "IHDR")); + data = chunk + 8; lodepng_set32bitInt(data + 0, w); /*width*/ lodepng_set32bitInt(data + 4, h); /*height*/ @@ -5085,244 +5066,267 @@ static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, data[11] = 0; /*filter method*/ data[12] = interlace_method; /*interlace method*/ - return addChunk(out, "IHDR", data, sizeof(data)); + lodepng_chunk_generate_crc(chunk); + return 0; } +/* only adds the chunk if needed (there is a key or palette with alpha) */ static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) { - unsigned error = 0; - size_t i; - ucvector PLTE; - ucvector_init(&PLTE); - for(i = 0; i != info->palettesize * 4; ++i) { + unsigned char* chunk; + size_t i, j = 8; + + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, info->palettesize * 3, "PLTE")); + + for(i = 0; i != info->palettesize; ++i) { /*add all channels except alpha channel*/ - if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); + chunk[j++] = info->palette[i * 4 + 0]; + chunk[j++] = info->palette[i * 4 + 1]; + chunk[j++] = info->palette[i * 4 + 2]; } - error = addChunk(out, "PLTE", PLTE.data, PLTE.size); - ucvector_cleanup(&PLTE); - return error; + lodepng_chunk_generate_crc(chunk); + return 0; } static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) { - unsigned error = 0; - size_t i; - ucvector tRNS; - ucvector_init(&tRNS); + unsigned char* chunk = 0; + if(info->colortype == LCT_PALETTE) { - size_t amount = info->palettesize; + size_t i, amount = info->palettesize; /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ for(i = info->palettesize; i != 0; --i) { - if(info->palette[4 * (i - 1) + 3] == 255) --amount; - else break; + if(info->palette[4 * (i - 1) + 3] != 255) break; + --amount; + } + if(amount) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, amount, "tRNS")); + /*add the alpha channel values from the palette*/ + for(i = 0; i != amount; ++i) chunk[8 + i] = info->palette[4 * i + 3]; } - /*add only alpha channel*/ - for(i = 0; i != amount; ++i) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); } else if(info->colortype == LCT_GREY) { if(info->key_defined) { - ucvector_push_back(&tRNS, (unsigned char)(info->key_r >> 8)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_r & 255)); + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "tRNS")); + chunk[8] = (unsigned char)(info->key_r >> 8); + chunk[9] = (unsigned char)(info->key_r & 255); } } else if(info->colortype == LCT_RGB) { if(info->key_defined) { - ucvector_push_back(&tRNS, (unsigned char)(info->key_r >> 8)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_r & 255)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_g >> 8)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_g & 255)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_b >> 8)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_b & 255)); + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 6, "tRNS")); + chunk[8] = (unsigned char)(info->key_r >> 8); + chunk[9] = (unsigned char)(info->key_r & 255); + chunk[10] = (unsigned char)(info->key_g >> 8); + chunk[11] = (unsigned char)(info->key_g & 255); + chunk[12] = (unsigned char)(info->key_b >> 8); + chunk[13] = (unsigned char)(info->key_b & 255); } } - error = addChunk(out, "tRNS", tRNS.data, tRNS.size); - ucvector_cleanup(&tRNS); - - return error; + if(chunk) lodepng_chunk_generate_crc(chunk); + return 0; } static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, LodePNGCompressSettings* zlibsettings) { - ucvector zlibdata; unsigned error = 0; + unsigned char* zlib = 0; + size_t zlibsize = 0; - /*compress with the Zlib compressor*/ - ucvector_init(&zlibdata); - error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); - if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); - ucvector_cleanup(&zlibdata); - + error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings); + if(!error) { + error = lodepng_chunk_createv(out, zlibsize, "IDAT", zlib); + } + lodepng_free(zlib); return error; } static unsigned addChunk_IEND(ucvector* out) { - unsigned error = 0; - error = addChunk(out, "IEND", 0, 0); - return error; + return lodepng_chunk_createv(out, 0, "IEND", 0); } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) { - unsigned error = 0; - size_t i; - ucvector text; - ucvector_init(&text); - for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)keyword[i]); - if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ - ucvector_push_back(&text, 0); /*0 termination char*/ - for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)textstring[i]); - error = addChunk(out, "tEXt", text.data, text.size); - ucvector_cleanup(&text); - - return error; + unsigned char* chunk = 0; + size_t keysize = lodepng_strlen(keyword), textsize = lodepng_strlen(textstring); + size_t size = keysize + 1 + textsize; + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, size, "tEXt")); + lodepng_memcpy(chunk + 8, keyword, keysize); + chunk[8 + keysize] = 0; /*null termination char*/ + lodepng_memcpy(chunk + 9 + keysize, textstring, textsize); + lodepng_chunk_generate_crc(chunk); + return 0; } static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, LodePNGCompressSettings* zlibsettings) { unsigned error = 0; - ucvector data, compressed; - size_t i, textsize = lodepng_strlen(textstring); - - ucvector_init(&data); - ucvector_init(&compressed); - for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); - if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ - ucvector_push_back(&data, 0); /*0 termination char*/ - ucvector_push_back(&data, 0); /*compression method: 0*/ - - error = zlib_compress(&compressed.data, &compressed.size, + unsigned char* chunk = 0; + unsigned char* compressed = 0; + size_t compressedsize = 0; + size_t textsize = lodepng_strlen(textstring); + size_t keysize = lodepng_strlen(keyword); + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + + error = zlib_compress(&compressed, &compressedsize, (const unsigned char*)textstring, textsize, zlibsettings); if(!error) { - for(i = 0; i != compressed.size; ++i) ucvector_push_back(&data, compressed.data[i]); - error = addChunk(out, "zTXt", data.data, data.size); + size_t size = keysize + 2 + compressedsize; + error = lodepng_chunk_init(&chunk, out, size, "zTXt"); + } + if(!error) { + lodepng_memcpy(chunk + 8, keyword, keysize); + chunk[8 + keysize] = 0; /*null termination char*/ + chunk[9 + keysize] = 0; /*compression method: 0*/ + lodepng_memcpy(chunk + 10 + keysize, compressed, compressedsize); + lodepng_chunk_generate_crc(chunk); } - ucvector_cleanup(&compressed); - ucvector_cleanup(&data); + lodepng_free(compressed); return error; } -static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, +static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyword, const char* langtag, const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) { unsigned error = 0; - ucvector data; - size_t i, textsize = lodepng_strlen(textstring); - - ucvector_init(&data); - - for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); - if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ - ucvector_push_back(&data, 0); /*null termination char*/ - ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ - ucvector_push_back(&data, 0); /*compression method*/ - for(i = 0; langtag[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)langtag[i]); - ucvector_push_back(&data, 0); /*null termination char*/ - for(i = 0; transkey[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)transkey[i]); - ucvector_push_back(&data, 0); /*null termination char*/ - - if(compressed) { - ucvector compressed_data; - ucvector_init(&compressed_data); - error = zlib_compress(&compressed_data.data, &compressed_data.size, + unsigned char* chunk = 0; + unsigned char* compressed = 0; + size_t compressedsize = 0; + size_t textsize = lodepng_strlen(textstring); + size_t keysize = lodepng_strlen(keyword), langsize = lodepng_strlen(langtag), transsize = lodepng_strlen(transkey); + + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + + if(compress) { + error = zlib_compress(&compressed, &compressedsize, (const unsigned char*)textstring, textsize, zlibsettings); - if(!error) { - for(i = 0; i != compressed_data.size; ++i) ucvector_push_back(&data, compressed_data.data[i]); + } + if(!error) { + size_t size = keysize + 3 + langsize + 1 + transsize + 1 + (compress ? compressedsize : textsize); + error = lodepng_chunk_init(&chunk, out, size, "iTXt"); + } + if(!error) { + size_t pos = 8; + lodepng_memcpy(chunk + pos, keyword, keysize); + pos += keysize; + chunk[pos++] = 0; /*null termination char*/ + chunk[pos++] = (compress ? 1 : 0); /*compression flag*/ + chunk[pos++] = 0; /*compression method: 0*/ + lodepng_memcpy(chunk + pos, langtag, langsize); + pos += langsize; + chunk[pos++] = 0; /*null termination char*/ + lodepng_memcpy(chunk + pos, transkey, transsize); + pos += transsize; + chunk[pos++] = 0; /*null termination char*/ + if(compress) { + lodepng_memcpy(chunk + pos, compressed, compressedsize); + } else { + lodepng_memcpy(chunk + pos, textstring, textsize); } - ucvector_cleanup(&compressed_data); - } else /*not compressed*/ { - for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)textstring[i]); + lodepng_chunk_generate_crc(chunk); } - if(!error) error = addChunk(out, "iTXt", data.data, data.size); - ucvector_cleanup(&data); + lodepng_free(compressed); return error; } static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) { - unsigned char data[6]; - size_t size = 0; + unsigned char* chunk = 0; if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { - data[0] = (unsigned char)(info->background_r >> 8); - data[1] = (unsigned char)(info->background_r & 255); - size = 2; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "bKGD")); + chunk[8] = (unsigned char)(info->background_r >> 8); + chunk[9] = (unsigned char)(info->background_r & 255); } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { - data[0] = (unsigned char)(info->background_r >> 8); - data[1] = (unsigned char)(info->background_r & 255); - data[2] = (unsigned char)(info->background_g >> 8); - data[3] = (unsigned char)(info->background_g & 255); - data[4] = (unsigned char)(info->background_b >> 8); - data[5] = (unsigned char)(info->background_b & 255); - size = 6; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 6, "bKGD")); + chunk[8] = (unsigned char)(info->background_r >> 8); + chunk[9] = (unsigned char)(info->background_r & 255); + chunk[10] = (unsigned char)(info->background_g >> 8); + chunk[11] = (unsigned char)(info->background_g & 255); + chunk[12] = (unsigned char)(info->background_b >> 8); + chunk[13] = (unsigned char)(info->background_b & 255); } else if(info->color.colortype == LCT_PALETTE) { - data[0] =(unsigned char)(info->background_r & 255); /*palette index*/ - size = 1; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 1, "bKGD")); + chunk[8] = (unsigned char)(info->background_r & 255); /*palette index*/ } - return addChunk(out, "bKGD", data, size); + if(chunk) lodepng_chunk_generate_crc(chunk); + return 0; } static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) { - unsigned char data[7]; - data[0] = (unsigned char)(time->year >> 8); - data[1] = (unsigned char)(time->year & 255); - data[2] = (unsigned char)time->month; - data[3] = (unsigned char)time->day; - data[4] = (unsigned char)time->hour; - data[5] = (unsigned char)time->minute; - data[6] = (unsigned char)time->second; - return addChunk(out, "tIME", data, sizeof(data)); + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 7, "tIME")); + chunk[8] = (unsigned char)(time->year >> 8); + chunk[9] = (unsigned char)(time->year & 255); + chunk[10] = (unsigned char)time->month; + chunk[11] = (unsigned char)time->day; + chunk[12] = (unsigned char)time->hour; + chunk[13] = (unsigned char)time->minute; + chunk[14] = (unsigned char)time->second; + lodepng_chunk_generate_crc(chunk); + return 0; } static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) { - unsigned char data[9]; - lodepng_set32bitInt(data + 0, info->phys_x); - lodepng_set32bitInt(data + 4, info->phys_y); data[8] = info->phys_unit; - return addChunk(out, "pHYs", data, sizeof(data)); + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 9, "pHYs")); + lodepng_set32bitInt(chunk + 8, info->phys_x); + lodepng_set32bitInt(chunk + 12, info->phys_y); + chunk[16] = info->phys_unit; + lodepng_chunk_generate_crc(chunk); + return 0; } static unsigned addChunk_gAMA(ucvector* out, const LodePNGInfo* info) { - unsigned char data[4]; - lodepng_set32bitInt(data, info->gama_gamma); - return addChunk(out, "gAMA", data, sizeof(data)); + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, "gAMA")); + lodepng_set32bitInt(chunk + 8, info->gama_gamma); + lodepng_chunk_generate_crc(chunk); + return 0; } static unsigned addChunk_cHRM(ucvector* out, const LodePNGInfo* info) { - unsigned char data[32]; - lodepng_set32bitInt(data + 0, info->chrm_white_x); - lodepng_set32bitInt(data + 4, info->chrm_white_y); - lodepng_set32bitInt(data + 8, info->chrm_red_x); - lodepng_set32bitInt(data + 12, info->chrm_red_y); - lodepng_set32bitInt(data + 16, info->chrm_green_x); - lodepng_set32bitInt(data + 20, info->chrm_green_y); - lodepng_set32bitInt(data + 24, info->chrm_blue_x); - lodepng_set32bitInt(data + 28, info->chrm_blue_y); - return addChunk(out, "cHRM", data, sizeof(data)); + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 32, "cHRM")); + lodepng_set32bitInt(chunk + 8, info->chrm_white_x); + lodepng_set32bitInt(chunk + 12, info->chrm_white_y); + lodepng_set32bitInt(chunk + 16, info->chrm_red_x); + lodepng_set32bitInt(chunk + 20, info->chrm_red_y); + lodepng_set32bitInt(chunk + 24, info->chrm_green_x); + lodepng_set32bitInt(chunk + 28, info->chrm_green_y); + lodepng_set32bitInt(chunk + 32, info->chrm_blue_x); + lodepng_set32bitInt(chunk + 36, info->chrm_blue_y); + lodepng_chunk_generate_crc(chunk); + return 0; } static unsigned addChunk_sRGB(ucvector* out, const LodePNGInfo* info) { unsigned char data = info->srgb_intent; - return addChunk(out, "sRGB", &data, 1); + return lodepng_chunk_createv(out, 1, "sRGB", &data); } static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCompressSettings* zlibsettings) { unsigned error = 0; - ucvector data, compressed; - size_t i; - - ucvector_init(&data); - ucvector_init(&compressed); - for(i = 0; info->iccp_name[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)info->iccp_name[i]); - if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ - ucvector_push_back(&data, 0); /*0 termination char*/ - ucvector_push_back(&data, 0); /*compression method: 0*/ + unsigned char* chunk = 0; + unsigned char* compressed = 0; + size_t compressedsize = 0; + size_t keysize = lodepng_strlen(info->iccp_name); - error = zlib_compress(&compressed.data, &compressed.size, + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + error = zlib_compress(&compressed, &compressedsize, info->iccp_profile, info->iccp_profile_size, zlibsettings); if(!error) { - for(i = 0; i != compressed.size; ++i) ucvector_push_back(&data, compressed.data[i]); - error = addChunk(out, "iCCP", data.data, data.size); + size_t size = keysize + 2 + compressedsize; + error = lodepng_chunk_init(&chunk, out, size, "iCCP"); + } + if(!error) { + lodepng_memcpy(chunk + 8, info->iccp_name, keysize); + chunk[8 + keysize] = 0; /*null termination char*/ + chunk[9 + keysize] = 0; /*compression method: 0*/ + lodepng_memcpy(chunk + 10 + keysize, compressed, compressedsize); + lodepng_chunk_generate_crc(chunk); } - ucvector_cleanup(&compressed); - ucvector_cleanup(&data); + lodepng_free(compressed); return error; } @@ -5368,17 +5372,18 @@ static void filterScanline(unsigned char* out, const unsigned char* scanline, co for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]); } break; - default: return; /*nonexistent filter type given*/ + default: return; /*invalid filter type given*/ } } -/* integer binary logarithm */ +/* integer binary logarithm, max return value is 31 */ static size_t ilog2(size_t i) { size_t result = 0; - while(i >= 65536) { result += 16; i >>= 16; } - while(i >= 256) { result += 8; i >>= 8; } - while(i >= 16) { result += 4; i >>= 4; } - while(i >= 2) { result += 1; i >>= 1; } + if(i >= 65536) { result += 16; i >>= 16; } + if(i >= 256) { result += 8; i >>= 8; } + if(i >= 16) { result += 4; i >>= 4; } + if(i >= 4) { result += 2; i >>= 2; } + if(i >= 2) { result += 1; /*i >>= 1;*/ } return result; } @@ -5730,29 +5735,6 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const return error; } -/* -palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... -returns 0 if the palette is opaque, -returns 1 if the palette has a single color with alpha 0 ==> color key -returns 2 if the palette is semi-translucent. -*/ -static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) { - size_t i; - unsigned key = 0; - unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ - for(i = 0; i != palettesize; ++i) { - if(!key && palette[4 * i + 3] == 0) { - r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2]; - key = 1; - i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/ - } - else if(palette[4 * i + 3] != 255) return 2; - /*when key, no opaque RGB may have key's RGB*/ - else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2; - } - return key; -} - #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) { unsigned char* inchunk = data; @@ -5790,11 +5772,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, LodePNGState* state) { unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ size_t datasize = 0; - ucvector outv; + ucvector outv = ucvector_init(NULL, 0); LodePNGInfo info; const LodePNGInfo* info_png = &state->info_png; - ucvector_init(&outv); lodepng_info_init(&info); /*provide some proper output values if error will happen*/ @@ -5809,17 +5790,17 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, goto cleanup; } if(state->encoder.zlibsettings.btype > 2) { - state->error = 61; /*error: nonexistent btype*/ + state->error = 61; /*error: invalid btype*/ goto cleanup; } if(info_png->interlace_method > 1) { - state->error = 71; /*error: nonexistent interlace mode*/ + state->error = 71; /*error: invalid interlace mode*/ goto cleanup; } state->error = checkColorValidity(info_png->color.colortype, info_png->color.bitdepth); - if(state->error) goto cleanup; /*error: nonexistent color type given*/ + if(state->error) goto cleanup; /*error: invalid color type given*/ state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); - if(state->error) goto cleanup; /*error: nonexistent color type given*/ + if(state->error) goto cleanup; /*error: invalid color type given*/ /* color convert and compute scanline filter types */ lodepng_info_copy(&info, &state->info_png); @@ -5901,9 +5882,11 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, size_t i; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*write signature and chunks*/ - writeSignature(&outv); + state->error = writeSignature(&outv); + if(state->error) goto cleanup; /*IHDR*/ - addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); + state->error = addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); + if(state->error) goto cleanup; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*unknown chunks between IHDR and PLTE*/ if(info.unknown_chunks_data[0]) { @@ -5911,25 +5894,36 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, if(state->error) goto cleanup; } /*color profile chunks must come before PLTE */ - if(info.iccp_defined) addChunk_iCCP(&outv, &info, &state->encoder.zlibsettings); - if(info.srgb_defined) addChunk_sRGB(&outv, &info); - if(info.gama_defined) addChunk_gAMA(&outv, &info); - if(info.chrm_defined) addChunk_cHRM(&outv, &info); + if(info.iccp_defined) { + state->error = addChunk_iCCP(&outv, &info, &state->encoder.zlibsettings); + if(state->error) goto cleanup; + } + if(info.srgb_defined) { + state->error = addChunk_sRGB(&outv, &info); + if(state->error) goto cleanup; + } + if(info.gama_defined) { + state->error = addChunk_gAMA(&outv, &info); + if(state->error) goto cleanup; + } + if(info.chrm_defined) { + state->error = addChunk_cHRM(&outv, &info); + if(state->error) goto cleanup; + } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*PLTE*/ if(info.color.colortype == LCT_PALETTE) { - addChunk_PLTE(&outv, &info.color); + state->error = addChunk_PLTE(&outv, &info.color); + if(state->error) goto cleanup; } if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) { - addChunk_PLTE(&outv, &info.color); - } - /*tRNS*/ - if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0) { - addChunk_tRNS(&outv, &info.color); - } - if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined) { - addChunk_tRNS(&outv, &info.color); + /*force_palette means: write suggested palette for truecolor in PLTE chunk*/ + state->error = addChunk_PLTE(&outv, &info.color); + if(state->error) goto cleanup; } + /*tRNS (this will only add if when necessary) */ + state->error = addChunk_tRNS(&outv, &info.color); + if(state->error) goto cleanup; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*bKGD (must come between PLTE and the IDAt chunks*/ if(info.background_defined) { @@ -5937,7 +5931,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, if(state->error) goto cleanup; } /*pHYs (must come before the IDAT chunks)*/ - if(info.phys_defined) addChunk_pHYs(&outv, &info); + if(info.phys_defined) { + state->error = addChunk_pHYs(&outv, &info); + if(state->error) goto cleanup; + } /*unknown chunks between PLTE and IDAT*/ if(info.unknown_chunks_data[1]) { @@ -5950,7 +5947,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, if(state->error) goto cleanup; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*tIME*/ - if(info.time_defined) addChunk_tIME(&outv, &info.time); + if(info.time_defined) { + state->error = addChunk_tIME(&outv, &info.time); + if(state->error) goto cleanup; + } /*tEXt and/or zTXt*/ for(i = 0; i != info.text_num; ++i) { if(lodepng_strlen(info.text_keys[i]) > 79) { @@ -5962,9 +5962,11 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, goto cleanup; } if(state->encoder.text_compression) { - addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); + state->error = addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); + if(state->error) goto cleanup; } else { - addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + state->error = addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + if(state->error) goto cleanup; } } /*LodePNG version id in text chunk*/ @@ -5980,7 +5982,8 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, } } if(already_added_id_text == 0) { - addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + state->error = addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + if(state->error) goto cleanup; } } /*iTXt*/ @@ -5993,9 +5996,11 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, state->error = 67; /*text chunk too small*/ goto cleanup; } - addChunk_iTXt(&outv, state->encoder.text_compression, - info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], - &state->encoder.zlibsettings); + state->error = addChunk_iTXt( + &outv, state->encoder.text_compression, + info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], + &state->encoder.zlibsettings); + if(state->error) goto cleanup; } /*unknown chunks between IDAT and IEND*/ @@ -6004,7 +6009,8 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, if(state->error) goto cleanup; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - addChunk_IEND(&outv); + state->error = addChunk_IEND(&outv); + if(state->error) goto cleanup; } cleanup: @@ -6092,7 +6098,7 @@ const char* lodepng_error_text(unsigned code) { case 14: return "problem while processing dynamic deflate block"; case 15: return "problem while processing dynamic deflate block"; /*this error could happen if there are only 0 or 1 symbols present in the huffman code:*/ - case 16: return "nonexistent code while processing dynamic deflate block"; + case 16: return "invalid code while processing dynamic deflate block"; case 17: return "end of out buffer memory reached while inflating"; case 18: return "invalid distance code while inflating"; case 19: return "end of out buffer memory reached while inflating"; @@ -6155,8 +6161,8 @@ const char* lodepng_error_text(unsigned code) { case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; - case 71: return "nonexistent interlace mode given to encoder (must be 0 or 1)"; - case 72: return "while decoding, nonexistent compression method encountering in zTXt or iTXt chunk (it must be 0)"; + case 71: return "invalid interlace mode given to encoder (must be 0 or 1)"; + case 72: return "while decoding, invalid compression method encountering in zTXt or iTXt chunk (it must be 0)"; case 73: return "invalid tIME chunk size"; case 74: return "invalid pHYs chunk size"; /*length could be wrong, or data chopped off*/ @@ -6228,7 +6234,7 @@ unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, si const LodePNGDecompressSettings& settings) { unsigned char* buffer = 0; size_t buffersize = 0; - unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings); + unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings); if(buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); @@ -6287,7 +6293,7 @@ State& State::operator=(const State& other) { unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const unsigned char* in, size_t insize, LodePNGColorType colortype, unsigned bitdepth) { - unsigned char* buffer; + unsigned char* buffer = 0; unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); if(buffer && !error) { State state; @@ -6295,8 +6301,8 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const state.info_raw.bitdepth = bitdepth; size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); out.insert(out.end(), &buffer[0], &buffer[buffersize]); - lodepng_free(buffer); } + lodepng_free(buffer); return error; } |