Improve, refactor and clean up pngtest.c

Improve:
The pngtest program used to be rather relaxed upon seeing invalid
parameters in callbacks: it either ignored them, or it bailed out
of the callbacks, essentially sweeping the bug under the rug.
But no more. Now it terminates with a severe `png_error`, in which
it says what's broken and where.

Improve:
`PNG_DEBUG`, defined externally at build time, and defaulting to zero,
was assumed to be non-negative. Now it's checked.

Clean up:
In a very distant past, the pngtest program used to "travel" across
libpng versions, on its own, not necessarily accompanied by the actual
library version that it was meant to test. However, this stopped being
the case, and now is as good a time as any to remove the compatibility
workarounds that had made the aforementioned "travel" possible.

Other chores include:
 * The refactoring of the user-defined chunk handling routines;
 * The cleanup of an unnecessary use of volatile;
 * The various cosmetic improvements of code and comments.
This commit is contained in:
Cosmin Truta 2024-02-02 21:32:48 +02:00
parent ce1f1f001e
commit 9138be341b

360
pngtest.c
View File

@ -37,64 +37,62 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/* Defined so I can write to a file on gui/windowing platforms */ #ifdef PNG_ZLIB_HEADER
/* #define STDERR stderr */ # include PNG_ZLIB_HEADER /* defined by pnglibconf.h from 1.7 */
#define STDERR stdout /* For DOS */ #else
# include <zlib.h>
#endif
#include "png.h" #include "png.h"
/* 1.6.1 added support for the configure test harness, which uses 77 to indicate /* KEEPME in libpng-1.6.x */
* a skipped test, in earlier versions and cmake builds we need to succeed on #define STDERR stdout
* a skipped test, so:
/* In version 1.6.1, we added support for the configure test harness, which
* uses 77 to indicate a skipped test. On the other hand, in cmake build tests,
* we still need to succeed on a skipped test, so:
*/ */
#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H) #if defined(HAVE_CONFIG_H)
# define SKIP 77 # define SKIP 77
#else #else
# define SKIP 0 # define SKIP 0
#endif #endif
/* Known chunks that exist in pngtest.png must be supported or pngtest will fail /* Known chunks that exist in pngtest.png must be supported, or pngtest will
* simply as a result of re-ordering them. This may be fixed in 1.7 * fail simply as a result of re-ordering them. This may be fixed in the next
* generation of libpng.
* *
* pngtest allocates a single row buffer for each row and overwrites it, * pngtest allocates a single row buffer for each row and overwrites it,
* therefore if the write side doesn't support the writing of interlaced images * therefore if the write side doesn't support the writing of interlaced images
* nothing can be done for an interlaced image (and the code below will fail * nothing can be done for an interlaced image (and the code below will fail
* horribly trying to write extra data after writing garbage). * horribly trying to write extra data after writing garbage).
*/ */
#if defined PNG_READ_SUPPORTED && /* else nothing can be done */\ #if defined PNG_READ_SUPPORTED && /* else nothing can be done */ \
defined PNG_READ_bKGD_SUPPORTED &&\ defined PNG_READ_bKGD_SUPPORTED && \
defined PNG_READ_cHRM_SUPPORTED &&\ defined PNG_READ_cHRM_SUPPORTED && \
defined PNG_READ_gAMA_SUPPORTED &&\ defined PNG_READ_gAMA_SUPPORTED && \
defined PNG_READ_oFFs_SUPPORTED &&\ defined PNG_READ_oFFs_SUPPORTED && \
defined PNG_READ_pCAL_SUPPORTED &&\ defined PNG_READ_pCAL_SUPPORTED && \
defined PNG_READ_pHYs_SUPPORTED &&\ defined PNG_READ_pHYs_SUPPORTED && \
defined PNG_READ_sBIT_SUPPORTED &&\ defined PNG_READ_sBIT_SUPPORTED && \
defined PNG_READ_sCAL_SUPPORTED &&\ defined PNG_READ_sCAL_SUPPORTED && \
defined PNG_READ_sRGB_SUPPORTED &&\ defined PNG_READ_sRGB_SUPPORTED && \
defined PNG_READ_sPLT_SUPPORTED &&\ defined PNG_READ_sPLT_SUPPORTED && \
defined PNG_READ_tEXt_SUPPORTED &&\ defined PNG_READ_tEXt_SUPPORTED && \
defined PNG_READ_tIME_SUPPORTED &&\ defined PNG_READ_tIME_SUPPORTED && \
defined PNG_READ_zTXt_SUPPORTED &&\ defined PNG_READ_zTXt_SUPPORTED && \
(defined PNG_WRITE_INTERLACING_SUPPORTED || PNG_LIBPNG_VER >= 10700) (defined PNG_WRITE_INTERLACING_SUPPORTED || PNG_LIBPNG_VER >= 10700)
#ifdef PNG_ZLIB_HEADER
# include PNG_ZLIB_HEADER /* defined by pnglibconf.h from 1.7 */
#else
# include "zlib.h"
#endif
/* Copied from pngpriv.h but only used in error messages below. */ /* Copied from pngpriv.h but only used in error messages below. */
#ifndef PNG_ZBUF_SIZE #ifndef PNG_ZBUF_SIZE
# define PNG_ZBUF_SIZE 8192 # define PNG_ZBUF_SIZE 8192
#endif #endif
#define FCLOSE(file) fclose(file)
#ifndef PNG_STDIO_SUPPORTED #ifndef PNG_STDIO_SUPPORTED
typedef FILE * png_FILE_p; typedef FILE * png_FILE_p;
#endif #endif
/* Makes pngtest verbose so we can find problems. */
#ifndef PNG_DEBUG #ifndef PNG_DEBUG
# define PNG_DEBUG 0 # define PNG_DEBUG 0
#endif #endif
@ -109,12 +107,12 @@ typedef FILE * png_FILE_p;
# define pngtest_debug2(m,p1,p2) ((void)0) # define pngtest_debug2(m,p1,p2) ((void)0)
#endif #endif
#if !PNG_DEBUG #if PNG_DEBUG == 0
# define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */ # define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */
#endif #endif
#ifndef PNG_UNUSED #if PNG_DEBUG < 0
# define PNG_UNUSED(param) (void)param; # error "Bad PNG_DEBUG value"
#endif #endif
/* Turn on CPU timing /* Turn on CPU timing
@ -131,25 +129,8 @@ static float t_start, t_stop, t_decode, t_encode, t_misc;
#endif #endif
#ifdef PNG_TIME_RFC1123_SUPPORTED #ifdef PNG_TIME_RFC1123_SUPPORTED
#define PNG_tIME_STRING_LENGTH 29
static int tIME_chunk_present = 0; static int tIME_chunk_present = 0;
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; static char tIME_string[] = "tIME chunk is not present";
#if PNG_LIBPNG_VER < 10619
#define png_convert_to_rfc1123_buffer(ts, t) tIME_to_str(read_ptr, ts, t)
static int
tIME_to_str(png_structp png_ptr, png_charp ts, png_const_timep t)
{
png_const_charp str = png_convert_to_rfc1123(png_ptr, t);
if (str == NULL)
return 0;
strcpy(ts, str);
return 1;
}
#endif /* older libpng */
#endif #endif
static int verbose = 0; static int verbose = 0;
@ -160,22 +141,6 @@ static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */
static int error_count = 0; /* count calls to png_error */ static int error_count = 0; /* count calls to png_error */
static int warning_count = 0; /* count calls to png_warning */ static int warning_count = 0; /* count calls to png_warning */
/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
#ifndef png_jmpbuf
# define png_jmpbuf(png_ptr) png_ptr->jmpbuf
#endif
/* Defines for unknown chunk handling if required. */
#ifndef PNG_HANDLE_CHUNK_ALWAYS
# define PNG_HANDLE_CHUNK_ALWAYS 3
#endif
#ifndef PNG_HANDLE_CHUNK_IF_SAFE
# define PNG_HANDLE_CHUNK_IF_SAFE 2
#endif
/* Utility to save typing/errors, the argument must be a name */
#define MEMZERO(var) ((void)memset(&var, 0, sizeof var))
/* Example of using row callbacks to make a simple progress meter */ /* Example of using row callbacks to make a simple progress meter */
static int status_pass = 1; static int status_pass = 1;
static int status_dots_requested = 0; static int status_dots_requested = 0;
@ -184,8 +149,13 @@ static int status_dots = 1;
static void PNGCBAPI static void PNGCBAPI
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
{ {
if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) /* The callback should always receive correct parameters. */
return; if (png_ptr == NULL)
png_error(png_ptr, "read_row_callback: bad png_ptr");
if (row_number > PNG_UINT_31_MAX)
png_error(png_ptr, "read_row_callback: bad row number");
if (pass < 0 || pass > 7)
png_error(png_ptr, "read_row_callback: bad pass");
if (status_pass != pass) if (status_pass != pass)
{ {
@ -199,7 +169,7 @@ read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
if (status_dots == 0) if (status_dots == 0)
{ {
fprintf(stdout, "\n "); fprintf(stdout, "\n ");
status_dots=30; status_dots = 30;
} }
fprintf(stdout, "r"); fprintf(stdout, "r");
@ -209,8 +179,13 @@ read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
static void PNGCBAPI static void PNGCBAPI
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
{ {
if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) /* The callback should always receive correct parameters. */
return; if (png_ptr == NULL)
png_error(png_ptr, "write_row_callback: bad png_ptr");
if (row_number > PNG_UINT_31_MAX)
png_error(png_ptr, "write_row_callback: bad row number");
if (pass < 0 || pass > 7)
png_error(png_ptr, "write_row_callback: bad pass");
fprintf(stdout, "w"); fprintf(stdout, "w");
} }
@ -223,9 +198,13 @@ write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
static void PNGCBAPI static void PNGCBAPI
read_user_callback(png_structp png_ptr, png_row_infop row_info, png_bytep data) read_user_callback(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{ {
PNG_UNUSED(png_ptr) /* The callback should always receive correct parameters. */
PNG_UNUSED(row_info) if (png_ptr == NULL)
PNG_UNUSED(data) png_error(png_ptr, "read_user_callback: bad png_ptr");
if (row_info == NULL)
png_error(png_ptr, "read_user_callback: bad row info");
if (data == NULL)
png_error(png_ptr, "read_user_callback: bad data");
} }
#endif #endif
@ -240,8 +219,14 @@ static void PNGCBAPI
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{ {
png_bytep dp = data; png_bytep dp = data;
/* The callback should always receive correct parameters. */
if (png_ptr == NULL) if (png_ptr == NULL)
return; png_error(png_ptr, "count_zero_samples: bad png_ptr");
if (row_info == NULL)
png_error(png_ptr, "count_zero_samples: bad row info");
if (data == NULL)
png_error(png_ptr, "count_zero_samples: bad data");
/* Contents of row_info: /* Contents of row_info:
* png_uint_32 width width of row * png_uint_32 width width of row
@ -259,7 +244,7 @@ count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
int pos = 0; int pos = 0;
png_uint_32 n, nstop; png_uint_32 n, nstop;
for (n = 0, nstop=row_info->width; n<nstop; n++) for (n = 0, nstop = row_info->width; n < nstop; n++)
{ {
if (row_info->bit_depth == 1) if (row_info->bit_depth == 1)
{ {
@ -305,7 +290,7 @@ count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{ {
if ((*dp | *(dp+1)) == 0) if ((*dp | *(dp+1)) == 0)
zero_samples++; zero_samples++;
dp+=2; dp += 2;
} }
} }
} }
@ -317,7 +302,7 @@ count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
if (row_info->color_type > 3) if (row_info->color_type > 3)
color_channels--; color_channels--;
for (n = 0, nstop=row_info->width; n<nstop; n++) for (n = 0, nstop = row_info->width; n < nstop; n++)
{ {
for (channel = 0; channel < color_channels; channel++) for (channel = 0; channel < color_channels; channel++)
{ {
@ -330,7 +315,7 @@ count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
if ((*dp | *(dp+1)) == 0) if ((*dp | *(dp+1)) == 0)
zero_samples++; zero_samples++;
dp+=2; dp += 2;
} }
} }
if (row_info->color_type > 3) if (row_info->color_type > 3)
@ -356,9 +341,6 @@ count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
#ifdef PNG_IO_STATE_SUPPORTED #ifdef PNG_IO_STATE_SUPPORTED
void void
pngtest_check_io_state(png_structp png_ptr, size_t data_length,
png_uint_32 io_op);
void
pngtest_check_io_state(png_structp png_ptr, size_t data_length, pngtest_check_io_state(png_structp png_ptr, size_t data_length,
png_uint_32 io_op) png_uint_32 io_op)
{ {
@ -372,7 +354,7 @@ pngtest_check_io_state(png_structp png_ptr, size_t data_length,
/* Check if the buffer size specific to the current location /* Check if the buffer size specific to the current location
* (file signature / header / data / crc) is as expected. * (file signature / header / data / crc) is as expected.
*/ */
switch (io_state & PNG_IO_MASK_LOC) switch ((io_state & PNG_IO_MASK_LOC) != 0)
{ {
case PNG_IO_SIGNATURE: case PNG_IO_SIGNATURE:
if (data_length > 8) if (data_length > 8)
@ -402,19 +384,18 @@ pngtest_read_data(png_structp png_ptr, png_bytep data, size_t length)
size_t check = 0; size_t check = 0;
png_voidp io_ptr; png_voidp io_ptr;
if (png_ptr == NULL)
png_error(png_ptr, "pngtest_read_data: bad png_ptr");
/* fread() returns 0 on error, so it is OK to store this in a size_t /* fread() returns 0 on error, so it is OK to store this in a size_t
* instead of an int, which is what fread() actually returns. * instead of an int, which is what fread() actually returns.
*/ */
io_ptr = png_get_io_ptr(png_ptr); io_ptr = png_get_io_ptr(png_ptr);
if (io_ptr != NULL) if (io_ptr != NULL)
{
check = fread(data, 1, length, (png_FILE_p)io_ptr); check = fread(data, 1, length, (png_FILE_p)io_ptr);
}
if (check != length) if (check != length)
{
png_error(png_ptr, "Read Error"); png_error(png_ptr, "Read Error");
}
#ifdef PNG_IO_STATE_SUPPORTED #ifdef PNG_IO_STATE_SUPPORTED
pngtest_check_io_state(png_ptr, length, PNG_IO_READING); pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
@ -425,8 +406,10 @@ pngtest_read_data(png_structp png_ptr, png_bytep data, size_t length)
static void PNGCBAPI static void PNGCBAPI
pngtest_flush(png_structp png_ptr) pngtest_flush(png_structp png_ptr)
{ {
if (png_ptr == NULL)
png_error(png_ptr, "pngtest_flush: bad png_ptr");
/* Do nothing; fflush() is said to be just a waste of energy. */ /* Do nothing; fflush() is said to be just a waste of energy. */
PNG_UNUSED(png_ptr) /* Stifle compiler warning */
} }
#endif #endif
@ -440,12 +423,13 @@ pngtest_write_data(png_structp png_ptr, png_bytep data, size_t length)
{ {
size_t check; size_t check;
if (png_ptr == NULL)
png_error(png_ptr, "pngtest_write_data: bad png_ptr");
check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr)); check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
if (check != length) if (check != length)
{
png_error(png_ptr, "Write Error"); png_error(png_ptr, "Write Error");
}
#ifdef PNG_IO_STATE_SUPPORTED #ifdef PNG_IO_STATE_SUPPORTED
pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING); pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
@ -548,7 +532,7 @@ PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
pinfo->size = size; pinfo->size = size;
current_allocation += size; current_allocation += size;
total_allocation += size; total_allocation += size;
num_allocations ++; ++num_allocations;
if (current_allocation > maximum_allocation) if (current_allocation > maximum_allocation)
maximum_allocation = current_allocation; maximum_allocation = current_allocation;
@ -646,15 +630,14 @@ png_debug_free(png_structp png_ptr, png_voidp ptr)
/* (sTER is a public chunk not yet known by libpng. vpAg is a private /* (sTER is a public chunk not yet known by libpng. vpAg is a private
chunk used in ImageMagick to store "virtual page" size). */ chunk used in ImageMagick to store "virtual page" size). */
static struct user_chunk_data typedef struct user_chunk_info_def
{ {
png_const_infop info_ptr; png_const_infop info_ptr;
png_uint_32 vpAg_width, vpAg_height; png_uint_32 vpAg_width, vpAg_height;
png_byte vpAg_units; png_byte vpAg_units;
png_byte sTER_mode; png_byte sTER_mode;
int location[2]; int location[2];
} } user_chunk_info;
user_chunk_data;
/* Used for location and order; zero means nothing. */ /* Used for location and order; zero means nothing. */
#define have_sTER 0x01 #define have_sTER 0x01
@ -664,37 +647,38 @@ user_chunk_data;
#define after_IDAT 0x40 #define after_IDAT 0x40
static void static void
init_callback_info(png_const_infop info_ptr) init_user_chunk_info(png_const_infop info_ptr, user_chunk_info *chunk_data)
{ {
MEMZERO(user_chunk_data); memset(chunk_data, 0, sizeof(*chunk_data));
user_chunk_data.info_ptr = info_ptr; chunk_data->info_ptr = info_ptr;
} }
static int static int
set_location(png_structp png_ptr, struct user_chunk_data *data, int what) set_chunk_location(png_structp png_ptr, user_chunk_info *chunk_data, int what)
{ {
int location; int location;
if ((data->location[0] & what) != 0 || (data->location[1] & what) != 0) if ((chunk_data->location[0] & what) != 0 ||
return 0; /* already have one of these */ (chunk_data->location[1] & what) != 0)
return 0; /* we already have one of these */
/* Find where we are (the code below zeroes info_ptr to indicate that the /* Find where we are (the code below zeroes info_ptr to indicate that the
* chunks before the first IDAT have been read.) * chunks before the first IDAT have been read.)
*/ */
if (data->info_ptr == NULL) /* after IDAT */ if (chunk_data->info_ptr == NULL) /* after IDAT */
location = what | after_IDAT; location = what | after_IDAT;
else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE) != 0) else if (png_get_valid(png_ptr, chunk_data->info_ptr, PNG_INFO_PLTE) != 0)
location = what | before_IDAT; location = what | before_IDAT;
else else
location = what | before_PLTE; location = what | before_PLTE;
if (data->location[0] == 0) if (chunk_data->location[0] == 0)
data->location[0] = location; chunk_data->location[0] = location;
else else
data->location[1] = location; chunk_data->location[1] = location;
return 1; /* handled */ return 1; /* handled */
} }
@ -702,11 +686,11 @@ set_location(png_structp png_ptr, struct user_chunk_data *data, int what)
static int PNGCBAPI static int PNGCBAPI
read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk) read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk)
{ {
struct user_chunk_data *my_user_chunk_data = user_chunk_info *my_user_chunk_data =
(struct user_chunk_data*)png_get_user_chunk_ptr(png_ptr); (user_chunk_info*)png_get_user_chunk_ptr(png_ptr);
if (my_user_chunk_data == NULL) if (my_user_chunk_data == NULL)
png_error(png_ptr, "lost user chunk pointer"); png_error(png_ptr, "lost pointer to user chunk data");
/* Return one of the following: /* Return one of the following:
* return -n; chunk had an error * return -n; chunk had an error
@ -731,9 +715,9 @@ read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk)
if (chunk->data[0] != 0 && chunk->data[0] != 1) if (chunk->data[0] != 0 && chunk->data[0] != 1)
return -1; /* Invalid mode */ return -1; /* Invalid mode */
if (set_location(png_ptr, my_user_chunk_data, have_sTER) != 0) if (set_chunk_location(png_ptr, my_user_chunk_data, have_sTER) != 0)
{ {
my_user_chunk_data->sTER_mode=chunk->data[0]; my_user_chunk_data->sTER_mode = chunk->data[0];
return 1; return 1;
} }
@ -750,7 +734,7 @@ read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk)
if (chunk->size != 9) if (chunk->size != 9)
return -1; /* Error return */ return -1; /* Error return */
if (set_location(png_ptr, my_user_chunk_data, have_vpAg) == 0) if (set_chunk_location(png_ptr, my_user_chunk_data, have_vpAg) == 0)
return 0; /* duplicate vpAg */ return 0; /* duplicate vpAg */
my_user_chunk_data->vpAg_width = png_get_uint_31(png_ptr, chunk->data); my_user_chunk_data->vpAg_width = png_get_uint_31(png_ptr, chunk->data);
@ -762,18 +746,18 @@ read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk)
#ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_SUPPORTED
static void static void
write_sTER_chunk(png_structp write_ptr) write_sTER_chunk(png_structp write_ptr, user_chunk_info *data)
{ {
png_byte sTER[5] = {115, 84, 69, 82, '\0'}; png_byte sTER[5] = {115, 84, 69, 82, '\0'};
if (verbose != 0) if (verbose != 0)
fprintf(STDERR, "\n stereo mode = %d\n", user_chunk_data.sTER_mode); fprintf(STDERR, "\n stereo mode = %d\n", data->sTER_mode);
png_write_chunk(write_ptr, sTER, &user_chunk_data.sTER_mode, 1); png_write_chunk(write_ptr, sTER, &data->sTER_mode, 1);
} }
static void static void
write_vpAg_chunk(png_structp write_ptr) write_vpAg_chunk(png_structp write_ptr, user_chunk_info *data)
{ {
png_byte vpAg[5] = {118, 112, 65, 103, '\0'}; png_byte vpAg[5] = {118, 112, 65, 103, '\0'};
@ -781,18 +765,18 @@ write_vpAg_chunk(png_structp write_ptr)
if (verbose != 0) if (verbose != 0)
fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n", fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n",
(unsigned long)user_chunk_data.vpAg_width, (unsigned long)data->vpAg_width,
(unsigned long)user_chunk_data.vpAg_height, (unsigned long)data->vpAg_height,
user_chunk_data.vpAg_units); data->vpAg_units);
png_save_uint_32(vpag_chunk_data, user_chunk_data.vpAg_width); png_save_uint_32(vpag_chunk_data, data->vpAg_width);
png_save_uint_32(vpag_chunk_data + 4, user_chunk_data.vpAg_height); png_save_uint_32(vpag_chunk_data + 4, data->vpAg_height);
vpag_chunk_data[8] = user_chunk_data.vpAg_units; vpag_chunk_data[8] = data->vpAg_units;
png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9); png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9);
} }
static void static void
write_chunks(png_structp write_ptr, int location) write_chunks(png_structp write_ptr, user_chunk_info *data, int location)
{ {
int i; int i;
@ -802,13 +786,13 @@ write_chunks(png_structp write_ptr, int location)
* vpAg chunks, resulting in an error later. This is not worth worrying * vpAg chunks, resulting in an error later. This is not worth worrying
* about - the chunks should not be duplicated! * about - the chunks should not be duplicated!
*/ */
for (i=0; i<2; ++i) for (i = 0; i < 2; ++i)
{ {
if (user_chunk_data.location[i] == (location | have_sTER)) if (data->location[i] == (location | have_sTER))
write_sTER_chunk(write_ptr); write_sTER_chunk(write_ptr, data);
else if (user_chunk_data.location[i] == (location | have_vpAg)) else if (data->location[i] == (location | have_vpAg))
write_vpAg_chunk(write_ptr); write_vpAg_chunk(write_ptr, data);
} }
} }
#endif /* WRITE */ #endif /* WRITE */
@ -883,9 +867,9 @@ test_one_file(const char *inname, const char *outname)
png_bytep row_buf; png_bytep row_buf;
png_uint_32 y; png_uint_32 y;
png_uint_32 width, height; png_uint_32 width, height;
volatile int num_passes;
int pass;
int bit_depth, color_type; int bit_depth, color_type;
user_chunk_info my_user_chunk_data;
int pass, num_passes;
row_buf = NULL; row_buf = NULL;
error_parameters.file_name = inname; error_parameters.file_name = inname;
@ -899,7 +883,7 @@ test_one_file(const char *inname, const char *outname)
if ((fpout = fopen(outname, "wb")) == NULL) if ((fpout = fopen(outname, "wb")) == NULL)
{ {
fprintf(STDERR, "Could not open output file %s\n", outname); fprintf(STDERR, "Could not open output file %s\n", outname);
FCLOSE(fpin); fclose(fpin);
return 1; return 1;
} }
@ -936,8 +920,8 @@ test_one_file(const char *inname, const char *outname)
#endif #endif
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED #ifdef PNG_READ_USER_CHUNKS_SUPPORTED
init_callback_info(read_info_ptr); init_user_chunk_info(read_info_ptr, &my_user_chunk_data);
png_set_read_user_chunk_fn(read_ptr, &user_chunk_data, png_set_read_user_chunk_fn(read_ptr, &my_user_chunk_data,
read_user_chunk_callback); read_user_chunk_callback);
#endif #endif
@ -957,8 +941,8 @@ test_one_file(const char *inname, const char *outname)
png_destroy_info_struct(write_ptr, &write_end_info_ptr); png_destroy_info_struct(write_ptr, &write_end_info_ptr);
png_destroy_write_struct(&write_ptr, &write_info_ptr); png_destroy_write_struct(&write_ptr, &write_info_ptr);
#endif #endif
FCLOSE(fpin); fclose(fpin);
FCLOSE(fpout); fclose(fpout);
return 1; return 1;
} }
@ -977,8 +961,8 @@ test_one_file(const char *inname, const char *outname)
fprintf(STDERR, " destroying write structs\n"); fprintf(STDERR, " destroying write structs\n");
png_destroy_info_struct(write_ptr, &write_end_info_ptr); png_destroy_info_struct(write_ptr, &write_end_info_ptr);
png_destroy_write_struct(&write_ptr, &write_info_ptr); png_destroy_write_struct(&write_ptr, &write_info_ptr);
FCLOSE(fpin); fclose(fpin);
FCLOSE(fpout); fclose(fpout);
return 1; return 1;
} }
#endif #endif
@ -1064,13 +1048,13 @@ test_one_file(const char *inname, const char *outname)
#endif #endif
#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
/* Preserve all the unknown chunks, if possible. If this is disabled then, /* Preserve all the unknown chunks, if possible. If this is disabled, then
* even if the png_{get,set}_unknown_chunks stuff is enabled, we can't use * even if the png_{get,set}_unknown_chunks stuff is enabled, we can't use
* libpng to *save* the unknown chunks on read (because we can't switch the * libpng to *save* the unknown chunks on read (because we can't switch the
* save option on!) * save option on!)
* *
* Notice that if SET_UNKNOWN_CHUNKS is *not* supported read will discard all * Notice that if SET_UNKNOWN_CHUNKS is *not* supported, the reader will
* unknown chunks and write will write them all. * discard all unknown chunks, and the writer will write them all.
*/ */
#ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED #ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
@ -1091,7 +1075,7 @@ test_one_file(const char *inname, const char *outname)
* remove the info_ptr (which is only used to determine position relative to * remove the info_ptr (which is only used to determine position relative to
* PLTE) here to indicate that we are after the IDAT. * PLTE) here to indicate that we are after the IDAT.
*/ */
user_chunk_data.info_ptr = NULL; my_user_chunk_data.info_ptr = NULL;
#endif #endif
pngtest_debug("Transferring info struct"); pngtest_debug("Transferring info struct");
@ -1207,14 +1191,12 @@ test_one_file(const char *inname, const char *outname)
png_color_16p background; png_color_16p background;
if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0) if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0)
{
png_set_bKGD(write_ptr, write_info_ptr, background); png_set_bKGD(write_ptr, write_info_ptr, background);
}
} }
#endif #endif
#ifdef PNG_READ_eXIf_SUPPORTED #ifdef PNG_READ_eXIf_SUPPORTED
{ {
png_bytep exif=NULL; png_bytep exif = NULL;
png_uint_32 exif_length; png_uint_32 exif_length;
if (png_get_eXIf_1(read_ptr, read_info_ptr, &exif_length, &exif) != 0) if (png_get_eXIf_1(read_ptr, read_info_ptr, &exif_length, &exif) != 0)
@ -1243,9 +1225,7 @@ test_one_file(const char *inname, const char *outname)
if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
&unit_type) != 0) &unit_type) != 0)
{
png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
}
} }
#endif #endif
#ifdef PNG_pCAL_SUPPORTED #ifdef PNG_pCAL_SUPPORTED
@ -1257,10 +1237,8 @@ test_one_file(const char *inname, const char *outname)
if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
&nparams, &units, &params) != 0) &nparams, &units, &params) != 0)
{
png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
nparams, units, params); nparams, units, params);
}
} }
#endif #endif
#ifdef PNG_pHYs_SUPPORTED #ifdef PNG_pHYs_SUPPORTED
@ -1290,9 +1268,7 @@ test_one_file(const char *inname, const char *outname)
if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
&scal_height) != 0) &scal_height) != 0)
{
png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
}
} }
#else #else
#ifdef PNG_FIXED_POINT_SUPPORTED #ifdef PNG_FIXED_POINT_SUPPORTED
@ -1315,11 +1291,9 @@ test_one_file(const char *inname, const char *outname)
{ {
png_sPLT_tp entries; png_sPLT_tp entries;
int num_entries = (int) png_get_sPLT(read_ptr, read_info_ptr, &entries); int num_entries = png_get_sPLT(read_ptr, read_info_ptr, &entries);
if (num_entries) if (num_entries != 0)
{
png_set_sPLT(write_ptr, write_info_ptr, entries, num_entries); png_set_sPLT(write_ptr, write_info_ptr, entries, num_entries);
}
} }
#endif #endif
@ -1339,7 +1313,7 @@ test_one_file(const char *inname, const char *outname)
int i; int i;
fprintf(STDERR,"\n"); fprintf(STDERR,"\n");
for (i=0; i<num_text; i++) for (i = 0; i < num_text; i++)
{ {
fprintf(STDERR," Text compression[%d]=%d\n", fprintf(STDERR," Text compression[%d]=%d\n",
i, text_ptr[i].compression); i, text_ptr[i].compression);
@ -1401,22 +1375,8 @@ test_one_file(const char *inname, const char *outname)
&unknowns); &unknowns);
if (num_unknowns != 0) if (num_unknowns != 0)
{
png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
num_unknowns); num_unknowns);
#if PNG_LIBPNG_VER < 10600
/* Copy the locations from the read_info_ptr. The automatically
* generated locations in write_end_info_ptr are wrong prior to 1.6.0
* because they are reset from the write pointer (removed in 1.6.0).
*/
{
int i;
for (i = 0; i < num_unknowns; i++)
png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
unknowns[i].location);
}
#endif
}
} }
#endif #endif
@ -1428,15 +1388,15 @@ test_one_file(const char *inname, const char *outname)
*/ */
png_write_info_before_PLTE(write_ptr, write_info_ptr); png_write_info_before_PLTE(write_ptr, write_info_ptr);
write_chunks(write_ptr, before_PLTE); /* before PLTE */ write_chunks(write_ptr, &my_user_chunk_data, before_PLTE); /* before PLTE */
png_write_info(write_ptr, write_info_ptr); png_write_info(write_ptr, write_info_ptr);
write_chunks(write_ptr, before_IDAT); /* after PLTE */ write_chunks(write_ptr, &my_user_chunk_data, before_IDAT); /* after PLTE */
png_write_info(write_ptr, write_end_info_ptr); png_write_info(write_ptr, write_end_info_ptr);
write_chunks(write_ptr, after_IDAT); /* after IDAT */ write_chunks(write_ptr, &my_user_chunk_data, after_IDAT); /* after IDAT */
#ifdef PNG_COMPRESSION_COMPAT #ifdef PNG_COMPRESSION_COMPAT
/* Test the 'compatibility' setting here, if it is available. */ /* Test the 'compatibility' setting here, if it is available. */
@ -1559,7 +1519,7 @@ test_one_file(const char *inname, const char *outname)
int i; int i;
fprintf(STDERR,"\n"); fprintf(STDERR,"\n");
for (i=0; i<num_text; i++) for (i = 0; i < num_text; i++)
{ {
fprintf(STDERR," Text compression[%d]=%d\n", fprintf(STDERR," Text compression[%d]=%d\n",
i, text_ptr[i].compression); i, text_ptr[i].compression);
@ -1572,7 +1532,7 @@ test_one_file(const char *inname, const char *outname)
#endif #endif
#ifdef PNG_READ_eXIf_SUPPORTED #ifdef PNG_READ_eXIf_SUPPORTED
{ {
png_bytep exif=NULL; png_bytep exif = NULL;
png_uint_32 exif_length; png_uint_32 exif_length;
if (png_get_eXIf_1(read_ptr, end_info_ptr, &exif_length, &exif) != 0) if (png_get_eXIf_1(read_ptr, end_info_ptr, &exif_length, &exif) != 0)
@ -1615,22 +1575,8 @@ test_one_file(const char *inname, const char *outname)
&unknowns); &unknowns);
if (num_unknowns != 0) if (num_unknowns != 0)
{
png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
num_unknowns); num_unknowns);
#if PNG_LIBPNG_VER < 10600
/* Copy the locations from the read_info_ptr. The automatically
* generated locations in write_end_info_ptr are wrong prior to 1.6.0
* because they are reset from the write pointer (removed in 1.6.0).
*/
{
int i;
for (i = 0; i < num_unknowns; i++)
png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
unknowns[i].location);
}
#endif
}
} }
#endif #endif
@ -1649,7 +1595,7 @@ test_one_file(const char *inname, const char *outname)
* There seems to be no way round this, however vpAg/sTER are not expected * There seems to be no way round this, however vpAg/sTER are not expected
* after IDAT. * after IDAT.
*/ */
write_chunks(write_ptr, after_IDAT); write_chunks(write_ptr, &my_user_chunk_data, after_IDAT);
png_write_end(write_ptr, write_end_info_ptr); png_write_end(write_ptr, write_end_info_ptr);
#endif #endif
@ -1681,8 +1627,8 @@ test_one_file(const char *inname, const char *outname)
#endif #endif
pngtest_debug("Destruction complete."); pngtest_debug("Destruction complete.");
FCLOSE(fpin); fclose(fpin);
FCLOSE(fpout); fclose(fpout);
/* Summarize any warnings or errors and in 'strict' mode fail the test. /* Summarize any warnings or errors and in 'strict' mode fail the test.
* Unsupported chunks can result in warnings, in that case ignore the strict * Unsupported chunks can result in warnings, in that case ignore the strict
@ -1728,7 +1674,7 @@ test_one_file(const char *inname, const char *outname)
if ((fpout = fopen(outname, "rb")) == NULL) if ((fpout = fopen(outname, "rb")) == NULL)
{ {
fprintf(STDERR, "Could not find file %s\n", outname); fprintf(STDERR, "Could not find file %s\n", outname);
FCLOSE(fpin); fclose(fpin);
return 1; return 1;
} }
@ -1764,8 +1710,8 @@ test_one_file(const char *inname, const char *outname)
wrote_question = 1; wrote_question = 1;
} }
FCLOSE(fpin); fclose(fpin);
FCLOSE(fpout); fclose(fpout);
if (strict != 0 && unsupported_chunks == 0) if (strict != 0 && unsupported_chunks == 0)
return 1; return 1;
@ -1796,8 +1742,8 @@ test_one_file(const char *inname, const char *outname)
wrote_question = 1; wrote_question = 1;
} }
FCLOSE(fpin); fclose(fpin);
FCLOSE(fpout); fclose(fpout);
/* NOTE: the unsupported_chunks escape is permitted here because /* NOTE: the unsupported_chunks escape is permitted here because
* unsupported text chunk compression will result in the compression * unsupported text chunk compression will result in the compression
@ -1814,8 +1760,8 @@ test_one_file(const char *inname, const char *outname)
} }
#endif /* WRITE && WRITE_FILTER */ #endif /* WRITE && WRITE_FILTER */
FCLOSE(fpin); fclose(fpin);
FCLOSE(fpout); fclose(fpout);
return 0; return 0;
} }
@ -1901,7 +1847,7 @@ main(int argc, char *argv[])
inname = argv[2]; inname = argv[2];
strict++; strict++;
relaxed = 0; relaxed = 0;
multiple=1; multiple = 1;
} }
else if (strcmp(argv[1], "--relaxed") == 0) else if (strcmp(argv[1], "--relaxed") == 0)
@ -1911,7 +1857,7 @@ main(int argc, char *argv[])
inname = argv[2]; inname = argv[2];
strict = 0; strict = 0;
relaxed++; relaxed++;
multiple=1; multiple = 1;
} }
else if (strcmp(argv[1], "--xfail") == 0) else if (strcmp(argv[1], "--xfail") == 0)
{ {
@ -1921,7 +1867,7 @@ main(int argc, char *argv[])
strict = 0; strict = 0;
xfail++; xfail++;
relaxed++; relaxed++;
multiple=1; multiple = 1;
} }
else else
@ -1953,7 +1899,7 @@ main(int argc, char *argv[])
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
int allocation_now = current_allocation; int allocation_now = current_allocation;
#endif #endif
for (i=2; i<argc; ++i) for (i = 2; i < argc; ++i)
{ {
int kerror; int kerror;
fprintf(STDERR, "\n Testing %s:", argv[i]); fprintf(STDERR, "\n Testing %s:", argv[i]);
@ -2024,7 +1970,7 @@ main(int argc, char *argv[])
else else
{ {
int i; int i;
for (i = 0; i<3; ++i) for (i = 0; i < 3; ++i)
{ {
int kerror; int kerror;
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
@ -2152,7 +2098,7 @@ main(int argc, char *argv[])
(unsigned long) png_get_chunk_malloc_max(dummy_ptr)); (unsigned long) png_get_chunk_malloc_max(dummy_ptr));
png_destroy_read_struct(&dummy_ptr, NULL, NULL); png_destroy_read_struct(&dummy_ptr, NULL, NULL);
return (int)(ierror != 0); return (ierror != 0);
} }
#else #else
int int