/* pngfix.c
*
- * Copyright (c) 2014 John Cunningham Bowler
+ * Copyright (c) 2014-2016 John Cunningham Bowler
*
- * Last changed in libpng 1.6.10 [March 6, 2014]
+ * Last changed in libpng 1.6.21 [January 15, 2016]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*
- * Tool to check and fix the zlib inflate 'too far back' problem, see the usage
- * message for more information.
+ * Tool to check and fix the zlib inflate 'too far back' problem.
+ * See the usage message for more information.
*/
#include <stdlib.h>
#include <stdio.h>
# error "pngfix will not work with libpng prior to 1.6.3"
#endif
-#if defined(PNG_READ_SUPPORTED) && defined(PNG_EASY_ACCESS_SUPPORTED)
+#ifdef PNG_SETJMP_SUPPORTED
+#include <setjmp.h>
+
+#if defined(PNG_READ_SUPPORTED) && defined(PNG_EASY_ACCESS_SUPPORTED) &&\
+ (defined(PNG_READ_DEINTERLACE_SUPPORTED) ||\
+ defined(PNG_READ_INTERLACING_SUPPORTED))
+
/* zlib.h defines the structure z_stream, an instance of which is included
* in this structure and is required for decompressing the LZ compressed
* data in PNG files.
* with older builds.
*/
#if ZLIB_VERNUM < 0x1260
-# define PNGZ_MSG_CAST(s) png_constcast(char*,s)
-# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b)
+# define PNGZ_MSG_CAST(s) constcast(char*,s)
+# define PNGZ_INPUT_CAST(b) constcast(png_bytep,b)
#else
# define PNGZ_MSG_CAST(s) (s)
# define PNGZ_INPUT_CAST(b) (b)
/* Copied from pngpriv.h */
#ifdef __cplusplus
-# define png_voidcast(type, value) static_cast<type>(value)
-# define png_constcast(type, value) const_cast<type>(value)
-# define png_aligncast(type, value) \
+# define voidcast(type, value) static_cast<type>(value)
+# define constcast(type, value) const_cast<type>(value)
+# define aligncast(type, value) \
static_cast<type>(static_cast<void*>(value))
-# define png_aligncastconst(type, value) \
+# define aligncastconst(type, value) \
static_cast<type>(static_cast<const void*>(value))
#else
-# define png_voidcast(type, value) (value)
-# define png_constcast(type, value) ((type)(value))
-# define png_aligncast(type, value) ((void*)(value))
-# define png_aligncastconst(type, value) ((const void*)(value))
+# define voidcast(type, value) (value)
+# define constcast(type, value) ((type)(value))
+# define aligncast(type, value) ((void*)(value))
+# define aligncastconst(type, value) ((const void*)(value))
#endif /* __cplusplus */
#if PNG_LIBPNG_VER < 10700
#define png_zTXt PNG_U32(122, 84, 88, 116)
#endif
-/* The 8 byte signature as a pair of 32 bit quantities */
+/* The 8-byte signature as a pair of 32-bit quantities */
#define sig1 PNG_U32(137, 80, 78, 71)
#define sig2 PNG_U32( 13, 10, 26, 10)
*/
#define UNREACHED 0
-/* 80-bit number handling - a PNG image can be up to (2^31-1)x(2^31-1) 8 byte
+/* 80-bit number handling - a PNG image can be up to (2^31-1)x(2^31-1) 8-byte
* (16-bit RGBA) pixels in size; that's less than 2^65 bytes or 2^68 bits, so
* arithmetic of 80-bit numbers is sufficient. This representation uses an
* arbitrary length array of png_uint_16 digits (0..65535). The representation
a_digits = uarb_mult_digit(acc, a_digits, num, n_digits,
(png_uint_16)(val & 0xffff));
- /* Because n_digits and val are >0 the following must be true: */
- assert(a_digits > 0);
-
val >>= 16;
if (val > 0)
a_digits = uarb_mult_digit(acc+1, a_digits-1, num, n_digits,
(png_uint_16)val) + 1;
+
+ /* Because n_digits and val are >0 the following must be true: */
+ assert(a_digits > 0);
}
return a_digits;
make_random_bytes(png_uint_32* seed, void* pv, size_t size)
{
png_uint_32 u0 = seed[0], u1 = seed[1];
- png_bytep bytes = png_voidcast(png_bytep, pv);
+ png_bytep bytes = voidcast(png_bytep, pv);
/* There are thirty-three bits; the next bit in the sequence is bit-33 XOR
* bit-20. The top 1 bit is in u1, the bottom 32 are in u0.
c &= ~PNG_U32(32,32,0,32);
t = (c & ~0x1f1f1f1f) ^ 0x40404040;
- /* Subtract 65 for each 8 bit quantity, this must not overflow
+ /* Subtract 65 for each 8-bit quantity, this must not overflow
* and each byte must then be in the range 0-25.
*/
c -= PNG_U32(65,65,65,65);
if (length < tail->length) /* arithmetic overflow */
length = tail->length;
-
- next = png_voidcast(IDAT_list*, malloc(IDAT_list_size(NULL, length)));
+
+ next = voidcast(IDAT_list*, malloc(IDAT_list_size(NULL, length)));
CLEAR(*next);
/* The caller must handle this: */
else if (isspace(UCHAR_MAX & *str))
putc('_', out);
-
+
else
fprintf(out, "\\%.3o", *str);
}
list->count = 0;
file->idat->idat_list_tail = list;
}
-
+
/* And fill in the next IDAT information buffer. */
list->lengths[(list->count)++] = file->chunk->chunk_length;
*
* z-rc is the zlib failure code; message is the error message with
* spaces replaced by '-'. The compressed byte count indicates where
- * in the zlib stream the error occured.
+ * in the zlib stream the error occurred.
*/
type_name(zlib->chunk->chunk_type, stdout);
printf(" SKP %s %d %s ", zlib_flevel(zlib), zlib->file_bits,
/* These values are sticky across reset (in addition to the stuff in the
* first block, which is actually constant.)
*/
- zlib->file_bits = 16;
+ zlib->file_bits = 24;
zlib->ok_bits = 16; /* unset */
zlib->cksum = 0; /* set when a checksum error is detected */
zlib->file_bits = file_bits;
/* Check against the existing value - it may not need to be
- * changed.
+ * changed. Note that a bogus file_bits is allowed through once,
+ * to see if it works, but the window_bits value is set to 15,
+ * the maximum.
*/
if (new_bits == 0) /* no change */
- zlib->window_bits = file_bits;
+ zlib->window_bits = ((file_bits > 15) ? 15 : file_bits);
else if (new_bits != file_bits) /* rewrite required */
bIn = (png_byte)((bIn & 0xf) + ((new_bits-8) << 4));
if (bIn != b2)
{
/* If the first byte wasn't changed this indicates an error in
- * the checksum calculation; signal this by setting file_bits
- * (not window_bits) to 0.
+ * the checksum calculation; signal this by setting 'cksum'.
*/
if (zlib->file_bits == zlib->window_bits)
zlib->cksum = 1;
{
struct chunk *chunk = zlib->chunk;
int rc;
-
+
assert(zlib->rewrite_offset < chunk->chunk_length);
rc = zlib_advance(zlib, chunk->chunk_length - zlib->rewrite_offset);
/* This just returns the (file*). The chunk and idat control structures
* don't always exist.
*/
- struct control *control = png_voidcast(struct control*,
+ struct control *control = voidcast(struct control*,
png_get_error_ptr(png_ptr));
return &control->file;
}
static void
allocate(struct file *file, int allocate_idat)
{
- struct control *control = png_voidcast(struct control*, file->alloc_ptr);
+ struct control *control = voidcast(struct control*, file->alloc_ptr);
if (allocate_idat)
{
{
png_structp png_ptr;
png_infop info_ptr = NULL;
- volatile png_bytep row = NULL, display = NULL;
volatile int rc;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, control,
rc = setjmp(control->file.jmpbuf);
if (rc == 0)
{
+# ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ /* Remove any limits on the size of PNG files that can be read,
+ * without this we may reject files based on built-in safety
+ * limits.
+ */
+ png_set_user_limits(png_ptr, 0x7fffffff, 0x7fffffff);
+ png_set_chunk_cache_max(png_ptr, 0);
+ png_set_chunk_malloc_max(png_ptr, 0);
+# endif
+
png_set_read_fn(png_ptr, control, read_callback);
info_ptr = png_create_info_struct(png_ptr);
png_read_info(png_ptr, info_ptr);
{
- png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
-
- row = png_voidcast(png_byte*, malloc(rowbytes));
- display = png_voidcast(png_byte*, malloc(rowbytes));
-
- if (row == NULL || display == NULL)
- png_error(png_ptr, "OOM allocating row buffers");
-
- {
- png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
- int passes = png_set_interlace_handling(png_ptr);
- int pass;
-
- png_start_read_image(png_ptr);
-
- for (pass = 0; pass < passes; ++pass)
- {
- png_uint_32 y = height;
-
- /* NOTE: this trashes the row each time; interlace handling won't
- * work, but this avoids memory thrashing for speed testing.
- */
- while (y-- > 0)
- png_read_row(png_ptr, row, display);
- }
- }
+ png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
+ int passes = png_set_interlace_handling(png_ptr);
+ int pass;
+
+ png_start_read_image(png_ptr);
+
+ for (pass = 0; pass < passes; ++pass)
+ {
+ png_uint_32 y = height;
+
+ /* NOTE: this skips asking libpng to return either version of
+ * the image row, but libpng still reads the rows.
+ */
+ while (y-- > 0)
+ png_read_row(png_ptr, NULL, NULL);
+ }
}
if (control->file.global->verbose)
}
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- if (row != NULL) free(row);
- if (display != NULL) free(display);
return rc;
}
" gAMA, sRGB [all]: These specify the gamma encoding used for the pixel",
" values.",
" cHRM, iCCP [color]: These specify how colors are encoded. iCCP also",
-" specifies the exact encoding of a pixel value however in practice",
-" most programs will ignore it.",
+" specifies the exact encoding of a pixel value; however, in",
+" practice most programs will ignore it.",
" bKGD [transform]: This is used by libpng transforms."
" --max=<number>:",
" Use IDAT chunks sized <number>. If no number is given the the IDAT",
" chunks will be the maximum size permitted; 2^31-1 bytes. If the option",
" is omitted the original chunk sizes will not be changed. When the",
-" option is given --strip=unsafe is set automatically, this may be",
+" option is given --strip=unsafe is set automatically. This may be",
" cancelled if you know that all unknown unsafe-to-copy chunks really are",
" safe to copy across an IDAT size change. This is true of all chunks",
" that have ever been formally proposed as PNG extensions.",
" MESSAGES",
" By default the program only outputs summaries for each file.",
" --quiet (-q):",
-" Do not output the summaries except for files which cannot be read. With",
+" Do not output the summaries except for files that cannot be read. With",
" two --quiets these are not output either.",
" --errors (-e):",
" Output errors from libpng and the program (except too-far-back).",
" the following codes. Notice that the results for each file are combined",
" together - check one file at a time to get a meaningful error code!",
" 0x01: The zlib too-far-back error existed in at least one chunk.",
-" 0x02: At least once chunk had a CRC error.",
+" 0x02: At least one chunk had a CRC error.",
" 0x04: A chunk length was incorrect.",
" 0x08: The file was truncated.",
" Errors less than 16 are potentially recoverable, for a single file if the",
" non-zero code is returned).",
" 0x10: The file could not be read, even with corrections.",
" 0x20: The output file could not be written.",
-" 0x40: An unexpected, potentially internal, error occured.",
+" 0x40: An unexpected, potentially internal, error occurred.",
" If the command line arguments are incorrect the program exits with exit",
" 255. Some older operating systems only support 7-bit exit codes, on those",
" systems it is suggested that this program is first tested by supplying",
" SKP: The chunk was skipped because of a zlib issue (zlib-rc) with",
" explanation 'message'",
" ERR: The read of the file was aborted. The parameters explain why.",
-"$3 status: For 'ERR' the accumulate status code from 'EXIT CODES' above.",
+"$3 status: For 'ERR' the accumulated status code from 'EXIT CODES' above.",
" This is printed as a 2 digit hexadecimal value",
" comp-level: The recorded compression level (FLEVEL) of a zlib stream",
" expressed as a string {supfast,stdfast,default,maximum}",
int
main(int argc, const char **argv)
{
+ char temp_name[FILENAME_MAX+1];
const char * prog = *argv;
const char * outfile = NULL;
const char * suffix = NULL;
else
{
size_t outlen = strlen(*argv);
- char temp_name[FILENAME_MAX+1];
if (outfile == NULL) /* else this takes precedence */
{
int
main(void)
{
- fprintf(stderr, "pngfix does not work without read support\n");
+ fprintf(stderr, "pngfix does not work without read deinterlace support\n");
return 77;
}
#endif /* PNG_READ_SUPPORTED && PNG_EASY_ACCESS_SUPPORTED */
+#else /* No setjmp support */
+int
+main(void)
+{
+ fprintf(stderr, "pngfix does not work without setjmp support\n");
+ return 77;
+}
+#endif /* PNG_SETJMP_SUPPORTED */
+