From d4d8f1aa786571af4a90a41b3db048043f114629 Mon Sep 17 00:00:00 2001 From: Lode Date: Mon, 15 Jan 2018 01:26:30 +0100 Subject: allow optionally ignoring a few more recoverable errors --- lodepng.cpp | 25 +++++++++++++++++++------ lodepng.h | 11 +++++++++-- lodepng_unittest.cpp | 2 +- lodepng_util.cpp | 4 ++-- lodepng_util.h | 2 +- pngdetail.cpp | 49 ++++++++++++++++++++++++++++++++++++------------- 6 files changed, 68 insertions(+), 25 deletions(-) diff --git a/lodepng.cpp b/lodepng.cpp index 37b0562..6998910 100644 --- a/lodepng.cpp +++ b/lodepng.cpp @@ -1,7 +1,7 @@ /* -LodePNG version 20170917 +LodePNG version 20180114 -Copyright (c) 2005-2017 Lode Vandevenne +Copyright (c) 2005-2018 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -39,7 +39,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 = "20170917"; +const char* LODEPNG_VERSION_STRING = "20180114"; /* This source file is built up in the following large parts. The code sections @@ -4565,12 +4565,20 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* data; /*the data in the chunk*/ /*error: size of the in buffer too small to contain next chunk*/ - if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30); + if((size_t)((chunk - in) + 12) > insize || chunk < in) + { + if(state->decoder.ignore_end) break; /*other errors may still happen though*/ + CERROR_BREAK(state->error, 30); + } /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ chunkLength = lodepng_chunk_length(chunk); /*error: chunk length larger than the max PNG chunk size*/ - if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63); + if(chunkLength > 2147483647) + { + if(state->decoder.ignore_end) break; /*other errors may still happen though*/ + CERROR_BREAK(state->error, 63); + } if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) { @@ -4657,7 +4665,10 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, else /*it's not an implemented chunk type, so ignore it: skip over the data*/ { /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ - if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69); + if(!state->decoder.ignore_critical && !lodepng_chunk_ancillary(chunk)) + { + CERROR_BREAK(state->error, 69); + } unknown = 1; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS @@ -4822,6 +4833,8 @@ void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) settings->remember_unknown_chunks = 0; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ settings->ignore_crc = 0; + settings->ignore_critical = 0; + settings->ignore_end = 0; lodepng_decompress_settings_init(&settings->zlibsettings); } diff --git a/lodepng.h b/lodepng.h index d633bfa..cf6667c 100644 --- a/lodepng.h +++ b/lodepng.h @@ -1,7 +1,7 @@ /* -LodePNG version 20170917 +LodePNG version 20180114 -Copyright (c) 2005-2017 Lode Vandevenne +Copyright (c) 2005-2018 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -255,6 +255,7 @@ const char* lodepng_error_text(unsigned code); typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; struct LodePNGDecompressSettings { + /* Check LodePNGDecoderSettings for more ignorable errors */ unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ /*use custom zlib decoder instead of built in one (default: null)*/ @@ -520,7 +521,10 @@ typedef struct LodePNGDecoderSettings { LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + /* Check LodePNGDecompressSettings for more ignorable errors */ unsigned ignore_crc; /*ignore CRC checksums*/ + unsigned ignore_critical; /*ignore unknown critical chunks*/ + unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND chunk, too large chunk, ...)*/ unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ @@ -1567,6 +1571,8 @@ For decoding: state.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums state.decoder.zlibsettings.custom_...: use custom inflate function state.decoder.ignore_crc: ignore CRC checksums +state.decoder.ignore_critical: ignore unknown critical chunks +state.decoder.ignore_end: ignore missing IEND chunk. May fail if this corruption causes other errors state.decoder.color_convert: convert internal PNG color to chosen one state.decoder.read_text_chunks: whether to read in text metadata chunks state.decoder.remember_unknown_chunks: whether to read in unknown chunks @@ -1608,6 +1614,7 @@ yyyymmdd. Some changes aren't backwards compatible. Those are indicated with a (!) symbol. +*) 14 jan 2018: allow optionally ignoring a few more recoverable errors *) 17 sep 2017: fix memory leak for some encoder input error cases *) 27 nov 2016: grey+alpha auto color model detection bugfix *) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort). diff --git a/lodepng_unittest.cpp b/lodepng_unittest.cpp index 5d11b2d..975f2b4 100644 --- a/lodepng_unittest.cpp +++ b/lodepng_unittest.cpp @@ -28,7 +28,7 @@ freely, subject to the following restrictions: /* Testing instructions: -*) Ensure no tests commented out below +*) Ensure no tests commented out below or early return in doMain *) Compile with g++ with all warnings and run the unit test g++ lodepng.cpp lodepng_util.cpp lodepng_unittest.cpp -Wall -Wextra -Wshadow -pedantic -ansi -O3 && ./a.out diff --git a/lodepng_util.cpp b/lodepng_util.cpp index 76efdea..9d86686 100644 --- a/lodepng_util.cpp +++ b/lodepng_util.cpp @@ -1,7 +1,7 @@ /* LodePNG Utils -Copyright (c) 2005-2014 Lode Vandevenne +Copyright (c) 2005-2018 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -52,9 +52,9 @@ unsigned getChunkInfo(std::vector& names, std::vector& size if(std::string(type).size() != 4) return 1; unsigned length = lodepng_chunk_length(chunk); - if(chunk + length + 12 > end) return 1; names.push_back(type); sizes.push_back(length); + if(chunk + length + 12 > end) return 1; next = lodepng_chunk_next_const(chunk); if (next <= chunk) return 1; // integer overflow diff --git a/lodepng_util.h b/lodepng_util.h index 236ad46..19fcbcb 100644 --- a/lodepng_util.h +++ b/lodepng_util.h @@ -1,7 +1,7 @@ /* LodePNG Utils -Copyright (c) 2005-2014 Lode Vandevenne +Copyright (c) 2005-2018 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/pngdetail.cpp b/pngdetail.cpp index f0a5158..00aa9dd 100644 --- a/pngdetail.cpp +++ b/pngdetail.cpp @@ -1,7 +1,7 @@ /* LodePNG pngdetail -Copyright (c) 2005-2015 Lode Vandevenne +Copyright (c) 2005-2018 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -797,6 +797,11 @@ unsigned showFileInfo(const std::string& filename, const Options& options) std::vector image; unsigned w, h; + if(options.show_png_info) + { + std::cout << "pngdetail version: " << LODEPNG_VERSION_STRING << std::endl; + } + unsigned error = lodepng::load_file(buffer, filename); //load the image file with given filename if(error) @@ -810,27 +815,45 @@ unsigned showFileInfo(const std::string& filename, const Options& options) state.info_raw.bitdepth = 16; error = lodepng::decode(image, w, h, state, buffer); - // In case of checksum errors, disable checksums - while (error == 57 || error == 58) { + // In case of checksum errors and some other ignorable errors, report it but ignore it and retry + while (error) { + std::cerr << "Decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + unsigned error2 = error; if(error == 57) { - std::cout << "Error: invalid CRC checksum" << std::endl; + std::cerr << "Ignoring the error: enabling ignore_crc" << std::endl; state.decoder.ignore_crc = 1; error = lodepng::decode(image, w, h, state, buffer); } - - if(error == 58) + else if(error == 58) { - std::cout << "Error: invalid Adler32 checksum" << std::endl; + std::cerr << "Ignoring the error: enabling ignore_adler32" << std::endl; state.decoder.zlibsettings.ignore_adler32 = 1; error = lodepng::decode(image, w, h, state, buffer); } - } - - if(error) - { - std::cout << "Decoder error " << error << ": " << lodepng_error_text(error) << std::endl; - // Do not return: some sections may still show partial info about a corrupted PNG. + else if(error == 69) + { + std::cerr << "Ignoring the error: enabling ignore_critical" << std::endl; + state.decoder.ignore_critical = 1; + error = lodepng::decode(image, w, h, state, buffer); + } + else if(error == 30 || error == 63) + { + std::cerr << "Ignoring the error: enabling ignore_end" << std::endl; + state.decoder.ignore_end = 1; + error = lodepng::decode(image, w, h, state, buffer); + } + else + { + if(error == 0) std::cerr << "This error is unrecoverable" << std::endl; + break; // other error that we cannot ignore + } + if(error == 0) std::cerr << "Successfully ignored the error" << std::endl; + if(error == error2) + { + std::cerr << "Failed to ignore the error" << std::endl; + break; // avoid infinite loop if ignoring did not fix the error code + } } bool extra_newlines = false; -- cgit v1.2.3