Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/lvandeve/lodepng.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lodepng.cpp')
-rw-r--r--lodepng.cpp920
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;
}