pngtest.c 60.7 KB
Newer Older
D
duke 已提交
1 2 3 4 5
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
6
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
7
 * particular file as subject to the "Classpath" exception as provided
8
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
9 10 11 12 13 14 15 16 17 18 19
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
20 21 22
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
23 24 25 26 27 28 29 30 31
 */

/* pngtest.c - a simple test program to test libpng
 *
 * This file is available under and governed by the GNU General Public
 * License version 2 only, as published by the Free Software Foundation.
 * However, the following notice accompanied the original version of this
 * file and, per its terms, should not be removed:
 *
32
 * Last changed in libpng 1.5.25 [December 3, 2015]
33
 * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
D
duke 已提交
34 35 36
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
 *
B
bae 已提交
37 38 39 40
 * This code is released under the libpng license.
 * For conditions of distribution and use, see the disclaimer
 * and license in png.h
 *
D
duke 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
 * This program reads in a PNG image, writes it out again, and then
 * compares the two files.  If the files are identical, this shows that
 * the basic chunk handling, filtering, and (de)compression code is working
 * properly.  It does not currently test all of the transforms, although
 * it probably should.
 *
 * The program will report "FAIL" in certain legitimate cases:
 * 1) when the compression level or filter selection method is changed.
 * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192.
 * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks
 *    exist in the input file.
 * 4) others not listed here...
 * In these cases, it is best to check with another tool such as "pngcheck"
 * to see what the differences between the two files are.
 *
 * If a filename is given on the command-line, then this file is used
 * for the input, rather than the default "pngtest.png".  This allows
 * testing a wide variety of files easily.  You can also test a number
 * of files at once by typing "pngtest -m file1.png file2.png ..."
 */

B
bae 已提交
62
#define _POSIX_SOURCE 1
D
duke 已提交
63

64 65 66 67 68 69 70 71
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Defined so I can write to a file on gui/windowing platforms */
/*  #define STDERR stderr  */
#define STDERR stdout   /* For DOS */

B
bae 已提交
72
#include "png.h"
73

74 75 76 77 78 79 80 81 82
/* 1.6.1 added support for the configure test harness, which uses 77 to indicate
 * a skipped test, in earlier versions we need to succeed on a skipped test, so:
 */
#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H)
#  define SKIP 77
#else
#  define SKIP 0
#endif

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
/* Known chunks that exist in pngtest.png must be supported or pngtest will fail
 * simply as a result of re-ordering them.  This may be fixed in 1.7
 *
 * 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
 * nothing can be done for an interlaced image (and the code below will fail
 * horribly trying to write extra data after writing garbage).
 */
#if defined PNG_READ_SUPPORTED && /* else nothing can be done */\
   defined PNG_READ_bKGD_SUPPORTED &&\
   defined PNG_READ_cHRM_SUPPORTED &&\
   defined PNG_READ_gAMA_SUPPORTED &&\
   defined PNG_READ_oFFs_SUPPORTED &&\
   defined PNG_READ_pCAL_SUPPORTED &&\
   defined PNG_READ_pHYs_SUPPORTED &&\
   defined PNG_READ_sBIT_SUPPORTED &&\
   defined PNG_READ_sCAL_SUPPORTED &&\
   defined PNG_READ_sRGB_SUPPORTED &&\
   defined PNG_READ_sPLT_SUPPORTED &&\
   defined PNG_READ_tEXt_SUPPORTED &&\
   defined PNG_READ_tIME_SUPPORTED &&\
   defined PNG_READ_zTXt_SUPPORTED &&\
   (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

B
bae 已提交
113 114 115 116
/* Copied from pngpriv.h but only used in error messages below. */
#ifndef PNG_ZBUF_SIZE
#  define PNG_ZBUF_SIZE 8192
#endif
117
#define FCLOSE(file) fclose(file)
D
duke 已提交
118

B
bae 已提交
119 120
#ifndef PNG_STDIO_SUPPORTED
typedef FILE                * png_FILE_p;
D
duke 已提交
121 122
#endif

B
bae 已提交
123
/* Makes pngtest verbose so we can find problems. */
D
duke 已提交
124 125 126 127
#ifndef PNG_DEBUG
#  define PNG_DEBUG 0
#endif

B
bae 已提交
128 129 130 131 132 133 134 135 136 137
#if PNG_DEBUG > 1
#  define pngtest_debug(m)        ((void)fprintf(stderr, m "\n"))
#  define pngtest_debug1(m,p1)    ((void)fprintf(stderr, m "\n", p1))
#  define pngtest_debug2(m,p1,p2) ((void)fprintf(stderr, m "\n", p1, p2))
#else
#  define pngtest_debug(m)        ((void)0)
#  define pngtest_debug1(m,p1)    ((void)0)
#  define pngtest_debug2(m,p1,p2) ((void)0)
#endif

D
duke 已提交
138
#if !PNG_DEBUG
B
bae 已提交
139
#  define SINGLE_ROWBUF_ALLOC  /* Makes buffer overruns easier to nail */
D
duke 已提交
140 141
#endif

142 143 144
#ifndef PNG_UNUSED
#  define PNG_UNUSED(param) (void)param;
#endif
A
azvegint 已提交
145

D
duke 已提交
146 147 148 149
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

B
bae 已提交
150
#ifndef PNG_FLOATING_POINT_SUPPORTED
D
duke 已提交
151 152 153 154 155 156 157 158
#undef PNGTEST_TIMING
#endif

#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

B
bae 已提交
159 160 161 162
#ifdef PNG_TIME_RFC1123_SUPPORTED
#define PNG_tIME_STRING_LENGTH 29
static int tIME_chunk_present = 0;
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
D
duke 已提交
163

164 165 166 167 168 169 170
#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);
A
azvegint 已提交
171

172 173
    if (str == NULL)
        return 0;
A
azvegint 已提交
174

175 176 177 178
    strcpy(ts, str);
    return 1;
}
#endif /* older libpng */
A
azvegint 已提交
179 180
#endif

181 182 183 184 185 186
static int verbose = 0;
static int strict = 0;
static int relaxed = 0;
static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */
static int error_count = 0; /* count calls to png_error */
static int warning_count = 0; /* count calls to png_warning */
D
duke 已提交
187 188 189 190 191 192

/* 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

193 194 195 196 197 198 199 200 201 202 203
/* 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))

B
bae 已提交
204 205 206 207 208
/* Example of using row callbacks to make a simple progress meter */
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;

209
static void PNGCBAPI
D
duke 已提交
210 211
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
{
B
bae 已提交
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;

   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }

   status_dots--;

   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }

   fprintf(stdout, "r");
D
duke 已提交
231 232
}

233 234
#ifdef PNG_WRITE_SUPPORTED
static void PNGCBAPI
D
duke 已提交
235 236
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
{
B
bae 已提交
237 238 239 240
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;

   fprintf(stdout, "w");
D
duke 已提交
241
}
242
#endif
D
duke 已提交
243 244


B
bae 已提交
245
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
246
/* Example of using a user transform callback (doesn't do anything at present).
B
bae 已提交
247
 */
248 249
static void PNGCBAPI
read_user_callback(png_structp png_ptr, png_row_infop row_info, png_bytep data)
D
duke 已提交
250
{
251 252 253
   PNG_UNUSED(png_ptr)
   PNG_UNUSED(row_info)
   PNG_UNUSED(data)
D
duke 已提交
254 255 256
}
#endif

B
bae 已提交
257 258 259 260
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
/* Example of using user transform callback (we don't transform anything,
 * but merely count the zero samples)
 */
D
duke 已提交
261 262 263

static png_uint_32 zero_samples;

264
static void PNGCBAPI
D
duke 已提交
265 266 267
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{
   png_bytep dp = data;
B
bae 已提交
268 269
   if (png_ptr == NULL)
      return;
D
duke 已提交
270

B
bae 已提交
271
   /* Contents of row_info:
D
duke 已提交
272 273 274 275 276 277 278 279
    *  png_uint_32 width      width of row
    *  png_uint_32 rowbytes   number of bytes in row
    *  png_byte color_type    color type of pixels
    *  png_byte bit_depth     bit depth of samples
    *  png_byte channels      number of channels (1-4)
    *  png_byte pixel_depth   bits per pixel (depth*channels)
    */

B
bae 已提交
280
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
D
duke 已提交
281

B
bae 已提交
282
    if (row_info->color_type == 0 || row_info->color_type == 3)
D
duke 已提交
283
    {
B
bae 已提交
284
       int pos = 0;
D
duke 已提交
285
       png_uint_32 n, nstop;
B
bae 已提交
286 287

       for (n = 0, nstop=row_info->width; n<nstop; n++)
D
duke 已提交
288
       {
B
bae 已提交
289
          if (row_info->bit_depth == 1)
D
duke 已提交
290
          {
B
bae 已提交
291 292 293 294
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;

             if (pos == 8)
D
duke 已提交
295 296 297 298 299
             {
                pos = 0;
                dp++;
             }
          }
B
bae 已提交
300 301

          if (row_info->bit_depth == 2)
D
duke 已提交
302
          {
B
bae 已提交
303 304 305 306
             if (((*dp << (pos+=2)) & 0xc0) == 0)
                zero_samples++;

             if (pos == 8)
D
duke 已提交
307 308 309 310 311
             {
                pos = 0;
                dp++;
             }
          }
B
bae 已提交
312 313

          if (row_info->bit_depth == 4)
D
duke 已提交
314
          {
B
bae 已提交
315 316 317 318
             if (((*dp << (pos+=4)) & 0xf0) == 0)
                zero_samples++;

             if (pos == 8)
D
duke 已提交
319 320 321 322 323
             {
                pos = 0;
                dp++;
             }
          }
B
bae 已提交
324 325 326 327 328 329

          if (row_info->bit_depth == 8)
             if (*dp++ == 0)
                zero_samples++;

          if (row_info->bit_depth == 16)
D
duke 已提交
330
          {
B
bae 已提交
331 332
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
D
duke 已提交
333 334 335 336
             dp+=2;
          }
       }
    }
B
bae 已提交
337
    else /* Other color types */
D
duke 已提交
338 339 340 341
    {
       png_uint_32 n, nstop;
       int channel;
       int color_channels = row_info->channels;
342 343
       if (row_info->color_type > 3)
          color_channels--;
D
duke 已提交
344

B
bae 已提交
345
       for (n = 0, nstop=row_info->width; n<nstop; n++)
D
duke 已提交
346 347 348
       {
          for (channel = 0; channel < color_channels; channel++)
          {
B
bae 已提交
349 350 351 352 353
             if (row_info->bit_depth == 8)
                if (*dp++ == 0)
                   zero_samples++;

             if (row_info->bit_depth == 16)
D
duke 已提交
354
             {
B
bae 已提交
355 356 357
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;

D
duke 已提交
358 359 360
                dp+=2;
             }
          }
B
bae 已提交
361
          if (row_info->color_type > 3)
D
duke 已提交
362 363
          {
             dp++;
B
bae 已提交
364 365
             if (row_info->bit_depth == 16)
                dp++;
D
duke 已提交
366 367 368 369
          }
       }
    }
}
370
#endif /* WRITE_USER_TRANSFORM */
D
duke 已提交
371

B
bae 已提交
372
#ifndef PNG_STDIO_SUPPORTED
D
duke 已提交
373
/* START of code to validate stdio-free compilation */
B
bae 已提交
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
/* These copies of the default read/write functions come from pngrio.c and
 * pngwio.c.  They allow "don't include stdio" testing of the library.
 * This is the function that does the actual reading of data.  If you are
 * not reading from a standard C stream, you should create a replacement
 * read_data function and use it at run time with png_set_read_fn(), rather
 * than changing the library.
 */

#ifdef PNG_IO_STATE_SUPPORTED
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
   png_uint_32 io_op);
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
   png_uint_32 io_op)
{
   png_uint_32 io_state = png_get_io_state(png_ptr);
   int err = 0;

   /* Check if the current operation (reading / writing) is as expected. */
   if ((io_state & PNG_IO_MASK_OP) != io_op)
      png_error(png_ptr, "Incorrect operation in I/O state");

   /* Check if the buffer size specific to the current location
    * (file signature / header / data / crc) is as expected.
    */
   switch (io_state & PNG_IO_MASK_LOC)
   {
   case PNG_IO_SIGNATURE:
      if (data_length > 8)
         err = 1;
      break;
   case PNG_IO_CHUNK_HDR:
      if (data_length != 8)
         err = 1;
      break;
   case PNG_IO_CHUNK_DATA:
      break;  /* no restrictions here */
   case PNG_IO_CHUNK_CRC:
      if (data_length != 4)
         err = 1;
      break;
   default:
      err = 1;  /* uninitialized */
   }
419
   if (err != 0)
B
bae 已提交
420 421 422
      png_error(png_ptr, "Bad I/O state or buffer size");
}
#endif
D
duke 已提交
423

B
bae 已提交
424
static void PNGCBAPI
D
duke 已提交
425 426
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
B
bae 已提交
427 428
   png_size_t check = 0;
   png_voidp io_ptr;
D
duke 已提交
429 430 431 432

   /* fread() returns 0 on error, so it is OK to store this in a png_size_t
    * instead of an int, which is what fread() actually returns.
    */
B
bae 已提交
433 434 435 436 437
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
   }
D
duke 已提交
438 439 440

   if (check != length)
   {
B
bae 已提交
441
      png_error(png_ptr, "Read Error");
D
duke 已提交
442
   }
B
bae 已提交
443 444 445 446

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
#endif
D
duke 已提交
447 448
}

B
bae 已提交
449 450
#ifdef PNG_WRITE_FLUSH_SUPPORTED
static void PNGCBAPI
D
duke 已提交
451 452
pngtest_flush(png_structp png_ptr)
{
B
bae 已提交
453 454
   /* Do nothing; fflush() is said to be just a waste of energy. */
   PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
D
duke 已提交
455 456 457 458
}
#endif

/* This is the function that does the actual writing of data.  If you are
B
bae 已提交
459 460 461 462 463
 * not writing to a standard C stream, you should create a replacement
 * write_data function and use it at run time with png_set_write_fn(), rather
 * than changing the library.
 */
static void PNGCBAPI
D
duke 已提交
464 465
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
B
bae 已提交
466 467 468
   png_size_t check;

   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
D
duke 已提交
469 470 471 472 473

   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
B
bae 已提交
474 475 476 477

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
D
duke 已提交
478
}
479
#endif /* !STDIO */
D
duke 已提交
480 481 482 483 484 485

/* This function is called when there is a warning, but the library thinks
 * it can continue anyway.  Replacement functions don't have to do anything
 * here if you don't want to.  In the default configuration, png_ptr is
 * not used, but it is passed in case it may be useful.
 */
486 487 488 489 490
typedef struct
{
   PNG_CONST char *file_name;
}  pngtest_error_parameters;

B
bae 已提交
491
static void PNGCBAPI
D
duke 已提交
492 493 494
pngtest_warning(png_structp png_ptr, png_const_charp message)
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
495 496
   pngtest_error_parameters *test =
      (pngtest_error_parameters*)png_get_error_ptr(png_ptr);
B
bae 已提交
497

498
   ++warning_count;
A
azvegint 已提交
499

500 501 502 503
   if (test != NULL && test->file_name != NULL)
      name = test->file_name;

   fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
D
duke 已提交
504 505 506 507 508 509 510
}

/* This is the default error handling function.  Note that replacements for
 * this function MUST NOT RETURN, or the program will likely crash.  This
 * function is used by default, or if the program supplies NULL for the
 * error function pointer in png_set_error_fn().
 */
B
bae 已提交
511
static void PNGCBAPI
D
duke 已提交
512 513
pngtest_error(png_structp png_ptr, png_const_charp message)
{
514 515
   ++error_count;

D
duke 已提交
516 517
   pngtest_warning(png_ptr, message);
   /* We can return because png_error calls the default handler, which is
B
bae 已提交
518 519
    * actually OK in this case.
    */
D
duke 已提交
520
}
521

D
duke 已提交
522 523 524 525 526 527
/* END of code to validate stdio-free compilation */

/* START of code to validate memory allocation and deallocation */
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG

/* Allocate memory.  For reasonable files, size should never exceed
528
 * 64K.  However, zlib may allocate more than 64K if you don't tell
B
bae 已提交
529 530 531 532 533 534 535
 * it not to.  See zconf.h and png.h for more information.  zlib does
 * need to allocate exactly 64K, so whatever you call here must
 * have the ability to do that.
 *
 * This piece of code can be compiled to validate max 64K allocations
 * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K.
 */
D
duke 已提交
536 537
typedef struct memory_information
{
B
bae 已提交
538
   png_alloc_size_t          size;
D
duke 已提交
539
   png_voidp                 pointer;
540
   struct memory_information *next;
D
duke 已提交
541
} memory_information;
542
typedef memory_information *memory_infop;
D
duke 已提交
543 544 545 546 547 548 549

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;
static int total_allocation = 0;
static int num_allocations = 0;

B
bae 已提交
550 551 552
png_voidp PNGCBAPI png_debug_malloc PNGARG((png_structp png_ptr,
    png_alloc_size_t size));
void PNGCBAPI png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
D
duke 已提交
553 554

png_voidp
B
bae 已提交
555
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
D
duke 已提交
556 557 558
{

   /* png_malloc has already tested for NULL; png_create_struct calls
B
bae 已提交
559 560
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
D
duke 已提交
561 562 563 564 565 566 567 568 569 570 571

   if (size == 0)
      return (NULL);

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
      /* Disable malloc_fn and free_fn */
      memory_infop pinfo;
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
      pinfo = (memory_infop)png_malloc(png_ptr,
572
         (sizeof *pinfo));
D
duke 已提交
573 574 575 576
      pinfo->size = size;
      current_allocation += size;
      total_allocation += size;
      num_allocations ++;
B
bae 已提交
577

D
duke 已提交
578 579
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
B
bae 已提交
580 581

      pinfo->pointer = png_malloc(png_ptr, size);
D
duke 已提交
582
      /* Restore malloc_fn and free_fn */
B
bae 已提交
583 584 585 586

      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);

D
duke 已提交
587 588 589 590 591
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
         png_error(png_ptr,
B
bae 已提交
592
           "out of memory in pngtest->png_debug_malloc");
D
duke 已提交
593
      }
B
bae 已提交
594

D
duke 已提交
595 596 597
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
598
      memset(pinfo->pointer, 0xdd, pinfo->size);
B
bae 已提交
599

600
      if (verbose != 0)
B
bae 已提交
601 602 603
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
            pinfo->pointer);

D
duke 已提交
604 605 606 607 608
      return (png_voidp)(pinfo->pointer);
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
B
bae 已提交
609
void PNGCBAPI
D
duke 已提交
610 611 612 613
png_debug_free(png_structp png_ptr, png_voidp ptr)
{
   if (png_ptr == NULL)
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
B
bae 已提交
614

D
duke 已提交
615 616 617 618 619 620 621 622 623
   if (ptr == 0)
   {
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
624
   if (pinformation != NULL)
D
duke 已提交
625
   {
626
      memory_infop *ppinfo = &pinformation;
B
bae 已提交
627

D
duke 已提交
628 629 630
      for (;;)
      {
         memory_infop pinfo = *ppinfo;
B
bae 已提交
631

D
duke 已提交
632 633 634 635 636 637 638 639
         if (pinfo->pointer == ptr)
         {
            *ppinfo = pinfo->next;
            current_allocation -= pinfo->size;
            if (current_allocation < 0)
               fprintf(STDERR, "Duplicate free of memory\n");
            /* We must free the list element too, but first kill
               the memory that is to be freed. */
640 641
            memset(ptr, 0x55, pinfo->size);
            free(pinfo);
B
bae 已提交
642
            pinfo = NULL;
D
duke 已提交
643 644
            break;
         }
B
bae 已提交
645

D
duke 已提交
646 647
         if (pinfo->next == NULL)
         {
648
            fprintf(STDERR, "Pointer %p not found\n", ptr);
D
duke 已提交
649 650
            break;
         }
B
bae 已提交
651

D
duke 已提交
652 653 654 655 656
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
657
   if (verbose != 0)
B
bae 已提交
658 659
      printf("Freeing %p\n", ptr);

660 661
   if (ptr != NULL)
      free(ptr);
B
bae 已提交
662
   ptr = NULL;
D
duke 已提交
663
}
664
#endif /* USER_MEM && DEBUG */
D
duke 已提交
665 666
/* END of code to test memory allocation/deallocation */

B
bae 已提交
667

668
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
B
bae 已提交
669 670 671 672 673
/* Demonstration of user chunk support of the sTER and vpAg chunks */

/* (sTER is a public chunk not yet known by libpng.  vpAg is a private
chunk used in ImageMagick to store "virtual page" size).  */

674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
static struct user_chunk_data
{
   png_const_infop info_ptr;
   png_uint_32     vpAg_width, vpAg_height;
   png_byte        vpAg_units;
   png_byte        sTER_mode;
   int             location[2];
}
user_chunk_data;

/* Used for location and order; zero means nothing. */
#define have_sTER   0x01
#define have_vpAg   0x02
#define before_PLTE 0x10
#define before_IDAT 0x20
#define after_IDAT  0x40
B
bae 已提交
690

691 692 693 694 695 696
static void
init_callback_info(png_const_infop info_ptr)
{
   MEMZERO(user_chunk_data);
   user_chunk_data.info_ptr = info_ptr;
}
B
bae 已提交
697

698 699
static int
set_location(png_structp png_ptr, struct user_chunk_data *data, int what)
B
bae 已提交
700
{
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
   int location;

   if ((data->location[0] & what) != 0 || (data->location[1] & what) != 0)
      return 0; /* already have one of these */

   /* Find where we are (the code below zeroes info_ptr to indicate that the
    * chunks before the first IDAT have been read.)
    */
   if (data->info_ptr == NULL) /* after IDAT */
      location = what | after_IDAT;

   else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE) != 0)
      location = what | before_IDAT;

   else
      location = what | before_PLTE;

   if (data->location[0] == 0)
      data->location[0] = location;

   else
      data->location[1] = location;

   return 1; /* handled */
}

static int PNGCBAPI
read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk)
{
   struct user_chunk_data *my_user_chunk_data =
      (struct user_chunk_data*)png_get_user_chunk_ptr(png_ptr);

   if (my_user_chunk_data == NULL)
      png_error(png_ptr, "lost user chunk pointer");
B
bae 已提交
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758

   /* Return one of the following:
    *    return (-n);  chunk had an error
    *    return (0);  did not recognize
    *    return (n);  success
    *
    * The unknown chunk structure contains the chunk data:
    * png_byte name[5];
    * png_byte *data;
    * png_size_t size;
    *
    * Note that libpng has already taken care of the CRC handling.
    */

   if (chunk->name[0] == 115 && chunk->name[1] ==  84 &&     /* s  T */
       chunk->name[2] ==  69 && chunk->name[3] ==  82)       /* E  R */
      {
         /* Found sTER chunk */
         if (chunk->size != 1)
            return (-1); /* Error return */

         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */

759 760 761 762 763 764 765 766
         if (set_location(png_ptr, my_user_chunk_data, have_sTER) != 0)
         {
            my_user_chunk_data->sTER_mode=chunk->data[0];
            return (1);
         }

         else
            return (0); /* duplicate sTER - give it to libpng */
B
bae 已提交
767 768 769 770 771 772 773 774 775 776 777
      }

   if (chunk->name[0] != 118 || chunk->name[1] != 112 ||    /* v  p */
       chunk->name[2] !=  65 || chunk->name[3] != 103)      /* A  g */
      return (0); /* Did not recognize */

   /* Found ImageMagick vpAg chunk */

   if (chunk->size != 9)
      return (-1); /* Error return */

778 779
   if (set_location(png_ptr, my_user_chunk_data, have_vpAg) == 0)
      return (0);  /* duplicate vpAg */
B
bae 已提交
780

781 782 783
   my_user_chunk_data->vpAg_width = png_get_uint_31(png_ptr, chunk->data);
   my_user_chunk_data->vpAg_height = png_get_uint_31(png_ptr, chunk->data + 4);
   my_user_chunk_data->vpAg_units = chunk->data[8];
B
bae 已提交
784 785

   return (1);
786 787 788 789 790 791 792 793 794 795
}

#ifdef PNG_WRITE_SUPPORTED
static void
write_sTER_chunk(png_structp write_ptr)
{
   png_byte sTER[5] = {115,  84,  69,  82, '\0'};

   if (verbose != 0)
      fprintf(STDERR, "\n stereo mode = %d\n", user_chunk_data.sTER_mode);
B
bae 已提交
796

797
   png_write_chunk(write_ptr, sTER, &user_chunk_data.sTER_mode, 1);
B
bae 已提交
798
}
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841

static void
write_vpAg_chunk(png_structp write_ptr)
{
   png_byte vpAg[5] = {118, 112,  65, 103, '\0'};

   png_byte vpag_chunk_data[9];

   if (verbose != 0)
      fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n",
        (unsigned long)user_chunk_data.vpAg_width,
        (unsigned long)user_chunk_data.vpAg_height,
        user_chunk_data.vpAg_units);

   png_save_uint_32(vpag_chunk_data, user_chunk_data.vpAg_width);
   png_save_uint_32(vpag_chunk_data + 4, user_chunk_data.vpAg_height);
   vpag_chunk_data[8] = user_chunk_data.vpAg_units;
   png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9);
}

static void
write_chunks(png_structp write_ptr, int location)
{
   int i;

   /* Notice that this preserves the original chunk order, however chunks
    * intercepted by the callback will be written *after* chunks passed to
    * libpng.  This will actually reverse a pair of sTER chunks or a pair of
    * vpAg chunks, resulting in an error later.  This is not worth worrying
    * about - the chunks should not be duplicated!
    */
   for (i=0; i<2; ++i)
   {
      if (user_chunk_data.location[i] == (location | have_sTER))
         write_sTER_chunk(write_ptr);

      else if (user_chunk_data.location[i] == (location | have_vpAg))
         write_vpAg_chunk(write_ptr);
   }
}
#endif /* WRITE */
#else /* !READ_USER_CHUNKS */
#  define write_chunks(pp,loc) ((void)0)
B
bae 已提交
842 843 844
#endif
/* END of code to demonstrate user chunk support */

845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
/* START of code to check that libpng has the required text support; this only
 * checks for the write support because if read support is missing the chunk
 * will simply not be reported back to pngtest.
 */
#ifdef PNG_TEXT_SUPPORTED
static void
pngtest_check_text_support(png_structp png_ptr, png_textp text_ptr,
   int num_text)
{
   while (num_text > 0)
   {
      switch (text_ptr[--num_text].compression)
      {
         case PNG_TEXT_COMPRESSION_NONE:
            break;

         case PNG_TEXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_zTXt_SUPPORTED
               ++unsupported_chunks;
               /* In libpng 1.7 this now does an app-error, so stop it: */
               text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
#           endif
            break;

         case PNG_ITXT_COMPRESSION_NONE:
         case PNG_ITXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_iTXt_SUPPORTED
               ++unsupported_chunks;
               text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
#           endif
            break;

         default:
            /* This is an error */
            png_error(png_ptr, "invalid text chunk compression field");
            break;
      }
   }
}
#endif
/* END of code to check that libpng has the required text support */

D
duke 已提交
887
/* Test one file */
888
static int
D
duke 已提交
889 890 891 892
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
{
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
893
   pngtest_error_parameters error_parameters;
D
duke 已提交
894 895 896 897 898 899
   png_structp read_ptr;
   png_infop read_info_ptr, end_info_ptr;
#ifdef PNG_WRITE_SUPPORTED
   png_structp write_ptr;
   png_infop write_info_ptr;
   png_infop write_end_info_ptr;
900 901 902 903
#ifdef PNG_WRITE_FILTER_SUPPORTED
   int interlace_preserved = 1;
#endif /* WRITE_FILTER */
#else /* !WRITE */
D
duke 已提交
904 905 906
   png_structp write_ptr = NULL;
   png_infop write_info_ptr = NULL;
   png_infop write_end_info_ptr = NULL;
907
#endif /* !WRITE */
D
duke 已提交
908 909 910
   png_bytep row_buf;
   png_uint_32 y;
   png_uint_32 width, height;
911 912
   volatile int num_passes;
   int pass;
D
duke 已提交
913 914 915
   int bit_depth, color_type;

   row_buf = NULL;
916
   error_parameters.file_name = inname;
D
duke 已提交
917 918 919 920 921 922 923 924 925 926 927 928 929 930

   if ((fpin = fopen(inname, "rb")) == NULL)
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
      return (1);
   }

   if ((fpout = fopen(outname, "wb")) == NULL)
   {
      fprintf(STDERR, "Could not open output file %s\n", outname);
      FCLOSE(fpin);
      return (1);
   }

B
bae 已提交
931
   pngtest_debug("Allocating read and write structures");
D
duke 已提交
932
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
B
bae 已提交
933 934 935
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
D
duke 已提交
936
#else
B
bae 已提交
937 938
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
D
duke 已提交
939
#endif
940 941
   png_set_error_fn(read_ptr, &error_parameters, pngtest_error,
      pngtest_warning);
B
bae 已提交
942

D
duke 已提交
943 944
#ifdef PNG_WRITE_SUPPORTED
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
B
bae 已提交
945 946 947
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
D
duke 已提交
948
#else
B
bae 已提交
949 950
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
D
duke 已提交
951
#endif
952 953
   png_set_error_fn(write_ptr, &error_parameters, pngtest_error,
      pngtest_warning);
D
duke 已提交
954
#endif
B
bae 已提交
955
   pngtest_debug("Allocating read_info, write_info and end_info structures");
D
duke 已提交
956 957 958 959 960 961 962
   read_info_ptr = png_create_info_struct(read_ptr);
   end_info_ptr = png_create_info_struct(read_ptr);
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
   write_end_info_ptr = png_create_info_struct(write_ptr);
#endif

963 964 965 966 967 968
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
   init_callback_info(read_info_ptr);
   png_set_read_user_chunk_fn(read_ptr, &user_chunk_data,
     read_user_chunk_callback);
#endif

D
duke 已提交
969
#ifdef PNG_SETJMP_SUPPORTED
B
bae 已提交
970
   pngtest_debug("Setting jmpbuf for read struct");
D
duke 已提交
971 972 973
   if (setjmp(png_jmpbuf(read_ptr)))
   {
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
B
bae 已提交
974 975
      png_free(read_ptr, row_buf);
      row_buf = NULL;
D
duke 已提交
976 977 978 979 980 981 982 983 984 985 986
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
#ifdef PNG_WRITE_SUPPORTED
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
#endif
      FCLOSE(fpin);
      FCLOSE(fpout);
      return (1);
   }

#ifdef PNG_WRITE_SUPPORTED
B
bae 已提交
987 988
   pngtest_debug("Setting jmpbuf for write struct");

D
duke 已提交
989 990 991 992 993 994 995 996 997 998 999 1000
   if (setjmp(png_jmpbuf(write_ptr)))
   {
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
#ifdef PNG_WRITE_SUPPORTED
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
#endif
      FCLOSE(fpin);
      FCLOSE(fpout);
      return (1);
   }
A
azvegint 已提交
1001
#endif
A
azvegint 已提交
1002
#endif
1003 1004 1005 1006 1007 1008 1009 1010 1011

   if (strict != 0)
   {
      /* Treat png_benign_error() as errors on read */
      png_set_benign_errors(read_ptr, 0);

#ifdef PNG_WRITE_SUPPORTED
      /* Treat them as errors on write */
      png_set_benign_errors(write_ptr, 0);
D
duke 已提交
1012 1013
#endif

1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
      /* if strict is not set, then app warnings and errors are treated as
       * warnings in release builds, but not in unstable builds; this can be
       * changed with '--relaxed'.
       */
   }

   else if (relaxed != 0)
   {
      /* Allow application (pngtest) errors and warnings to pass */
      png_set_benign_errors(read_ptr, 1);

#ifdef PNG_WRITE_SUPPORTED
      png_set_benign_errors(write_ptr, 1);
#endif
   }

B
bae 已提交
1030 1031
   pngtest_debug("Initializing input and output streams");
#ifdef PNG_STDIO_SUPPORTED
D
duke 已提交
1032 1033 1034 1035 1036 1037 1038 1039
   png_init_io(read_ptr, fpin);
#  ifdef PNG_WRITE_SUPPORTED
   png_init_io(write_ptr, fpout);
#  endif
#else
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
#  ifdef PNG_WRITE_SUPPORTED
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
B
bae 已提交
1040
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
D
duke 已提交
1041 1042 1043 1044 1045 1046
      pngtest_flush);
#    else
      NULL);
#    endif
#  endif
#endif
B
bae 已提交
1047 1048

   if (status_dots_requested == 1)
D
duke 已提交
1049 1050 1051 1052 1053 1054
   {
#ifdef PNG_WRITE_SUPPORTED
      png_set_write_status_fn(write_ptr, write_row_callback);
#endif
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
B
bae 已提交
1055

D
duke 已提交
1056 1057 1058
   else
   {
#ifdef PNG_WRITE_SUPPORTED
B
bae 已提交
1059
      png_set_write_status_fn(write_ptr, NULL);
D
duke 已提交
1060
#endif
B
bae 已提交
1061
      png_set_read_status_fn(read_ptr, NULL);
D
duke 已提交
1062 1063
   }

B
bae 已提交
1064
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1065
   png_set_read_user_transform_fn(read_ptr, read_user_callback);
D
duke 已提交
1066
#endif
B
bae 已提交
1067 1068
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
   zero_samples = 0;
D
duke 已提交
1069 1070 1071
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif

1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
   /* 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
    * libpng to *save* the unknown chunks on read (because we can't switch the
    * save option on!)
    *
    * Notice that if SET_UNKNOWN_CHUNKS is *not* supported read will discard all
    * unknown chunks and write will write them all.
    */
#ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
D
duke 已提交
1082
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
B
bae 已提交
1083
      NULL, 0);
D
duke 已提交
1084
#endif
B
bae 已提交
1085
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1086
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS,
B
bae 已提交
1087
      NULL, 0);
1088
#endif
D
duke 已提交
1089 1090
#endif

B
bae 已提交
1091
   pngtest_debug("Reading info struct");
D
duke 已提交
1092 1093
   png_read_info(read_ptr, read_info_ptr);

1094 1095 1096 1097 1098 1099 1100 1101 1102
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
   /* This is a bit of a hack; there is no obvious way in the callback function
    * to determine that the chunks before the first IDAT have been read, so
    * remove the info_ptr (which is only used to determine position relative to
    * PLTE) here to indicate that we are after the IDAT.
    */
   user_chunk_data.info_ptr = NULL;
#endif

B
bae 已提交
1103
   pngtest_debug("Transferring info struct");
D
duke 已提交
1104 1105 1106 1107
   {
      int interlace_type, compression_type, filter_type;

      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
1108
          &color_type, &interlace_type, &compression_type, &filter_type) != 0)
D
duke 已提交
1109 1110 1111
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
            color_type, interlace_type, compression_type, filter_type);
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
         /* num_passes may not be available below if interlace support is not
          * provided by libpng for both read and write.
          */
         switch (interlace_type)
         {
            case PNG_INTERLACE_NONE:
               num_passes = 1;
               break;

            case PNG_INTERLACE_ADAM7:
               num_passes = 7;
               break;

            default:
               png_error(read_ptr, "invalid interlace type");
               /*NOT REACHED*/
         }
D
duke 已提交
1129
      }
1130 1131 1132

      else
         png_error(read_ptr, "png_get_IHDR failed");
D
duke 已提交
1133
   }
B
bae 已提交
1134 1135
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
D
duke 已提交
1136 1137 1138
   {
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
B
bae 已提交
1139 1140

      if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y,
1141
         &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
D
duke 已提交
1142 1143 1144 1145 1146 1147
      {
         png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
            red_y, green_x, green_y, blue_x, blue_y);
      }
   }
#endif
B
bae 已提交
1148
#ifdef PNG_gAMA_SUPPORTED
D
duke 已提交
1149 1150 1151
   {
      png_fixed_point gamma;

1152
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma) != 0)
D
duke 已提交
1153 1154 1155 1156
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
   }
#endif
#else /* Use floating point versions */
B
bae 已提交
1157 1158
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
D
duke 已提交
1159 1160 1161
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
B
bae 已提交
1162

D
duke 已提交
1163
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
1164
         &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
D
duke 已提交
1165 1166 1167 1168 1169 1170
      {
         png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
            red_y, green_x, green_y, blue_x, blue_y);
      }
   }
#endif
B
bae 已提交
1171
#ifdef PNG_gAMA_SUPPORTED
D
duke 已提交
1172 1173 1174
   {
      double gamma;

1175
      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma) != 0)
D
duke 已提交
1176 1177 1178
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
B
bae 已提交
1179 1180 1181
#endif /* Floating point */
#endif /* Fixed point */
#ifdef PNG_iCCP_SUPPORTED
D
duke 已提交
1182 1183
   {
      png_charp name;
B
bae 已提交
1184
      png_bytep profile;
D
duke 已提交
1185 1186 1187 1188
      png_uint_32 proflen;
      int compression_type;

      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
1189
                      &profile, &proflen) != 0)
D
duke 已提交
1190 1191 1192 1193 1194 1195
      {
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
      }
   }
#endif
B
bae 已提交
1196
#ifdef PNG_sRGB_SUPPORTED
D
duke 已提交
1197 1198 1199
   {
      int intent;

1200
      if (png_get_sRGB(read_ptr, read_info_ptr, &intent) != 0)
D
duke 已提交
1201 1202 1203 1204 1205 1206 1207
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
#endif
   {
      png_colorp palette;
      int num_palette;

1208
      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette) != 0)
D
duke 已提交
1209 1210
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
   }
B
bae 已提交
1211
#ifdef PNG_bKGD_SUPPORTED
D
duke 已提交
1212 1213 1214
   {
      png_color_16p background;

1215
      if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0)
D
duke 已提交
1216 1217 1218 1219 1220
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
B
bae 已提交
1221
#ifdef PNG_hIST_SUPPORTED
D
duke 已提交
1222 1223 1224
   {
      png_uint_16p hist;

1225
      if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0)
D
duke 已提交
1226 1227 1228
         png_set_hIST(write_ptr, write_info_ptr, hist);
   }
#endif
B
bae 已提交
1229
#ifdef PNG_oFFs_SUPPORTED
D
duke 已提交
1230 1231 1232 1233
   {
      png_int_32 offset_x, offset_y;
      int unit_type;

B
bae 已提交
1234
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1235
          &unit_type) != 0)
D
duke 已提交
1236 1237 1238 1239 1240
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
B
bae 已提交
1241
#ifdef PNG_pCAL_SUPPORTED
D
duke 已提交
1242 1243 1244 1245 1246 1247 1248
   {
      png_charp purpose, units;
      png_charpp params;
      png_int_32 X0, X1;
      int type, nparams;

      if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
1249
         &nparams, &units, &params) != 0)
D
duke 已提交
1250 1251 1252 1253 1254 1255
      {
         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
            nparams, units, params);
      }
   }
#endif
B
bae 已提交
1256
#ifdef PNG_pHYs_SUPPORTED
D
duke 已提交
1257 1258 1259 1260
   {
      png_uint_32 res_x, res_y;
      int unit_type;

1261 1262
      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y,
          &unit_type) != 0)
D
duke 已提交
1263 1264 1265
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
B
bae 已提交
1266
#ifdef PNG_sBIT_SUPPORTED
D
duke 已提交
1267 1268 1269
   {
      png_color_8p sig_bit;

1270
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0)
D
duke 已提交
1271 1272 1273
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
   }
#endif
B
bae 已提交
1274
#ifdef PNG_sCAL_SUPPORTED
1275 1276
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
D
duke 已提交
1277 1278 1279 1280 1281
   {
      int unit;
      double scal_width, scal_height;

      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
1282
         &scal_height) != 0)
D
duke 已提交
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
      {
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
      }
   }
#else
#ifdef PNG_FIXED_POINT_SUPPORTED
   {
      int unit;
      png_charp scal_width, scal_height;

      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
1294
          &scal_height) != 0)
D
duke 已提交
1295
      {
B
bae 已提交
1296 1297
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
D
duke 已提交
1298 1299 1300 1301 1302
      }
   }
#endif
#endif
#endif
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315

#ifdef PNG_sPLT_SUPPORTED
   {
       png_sPLT_tp entries;

       int num_entries = (int) png_get_sPLT(read_ptr, read_info_ptr, &entries);
       if (num_entries)
       {
           png_set_sPLT(write_ptr, write_info_ptr, entries, num_entries);
       }
   }
#endif

B
bae 已提交
1316
#ifdef PNG_TEXT_SUPPORTED
D
duke 已提交
1317 1318 1319 1320 1321 1322
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
      {
B
bae 已提交
1323
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338

         pngtest_check_text_support(read_ptr, text_ptr, num_text);

         if (verbose != 0)
         {
            int i;

            printf("\n");
            for (i=0; i<num_text; i++)
            {
               printf("   Text compression[%d]=%d\n",
                     i, text_ptr[i].compression);
            }
         }

D
duke 已提交
1339 1340 1341 1342
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
B
bae 已提交
1343
#ifdef PNG_tIME_SUPPORTED
D
duke 已提交
1344 1345 1346
   {
      png_timep mod_time;

1347
      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time) != 0)
D
duke 已提交
1348 1349
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
B
bae 已提交
1350
#ifdef PNG_TIME_RFC1123_SUPPORTED
1351 1352 1353 1354 1355 1356 1357 1358
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
            tIME_string[(sizeof tIME_string) - 1] = '\0';

         else
         {
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
         }
B
bae 已提交
1359

D
duke 已提交
1360
         tIME_chunk_present++;
1361
#endif /* TIME_RFC1123 */
D
duke 已提交
1362 1363 1364
      }
   }
#endif
B
bae 已提交
1365
#ifdef PNG_tRNS_SUPPORTED
D
duke 已提交
1366
   {
B
bae 已提交
1367
      png_bytep trans_alpha;
D
duke 已提交
1368
      int num_trans;
B
bae 已提交
1369
      png_color_16p trans_color;
D
duke 已提交
1370

B
bae 已提交
1371
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1372
         &trans_color) != 0)
D
duke 已提交
1373
      {
B
bae 已提交
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
         int sample_max = (1 << bit_depth);
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
             (int)trans_color->gray > sample_max) ||
             (color_type == PNG_COLOR_TYPE_RGB &&
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
               trans_color);
D
duke 已提交
1384 1385 1386
      }
   }
#endif
B
bae 已提交
1387
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
D
duke 已提交
1388 1389
   {
      png_unknown_chunkp unknowns;
B
bae 已提交
1390
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
D
duke 已提交
1391
         &unknowns);
B
bae 已提交
1392

1393
      if (num_unknowns != 0)
D
duke 已提交
1394 1395 1396
      {
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1397
#if PNG_LIBPNG_VER < 10600
B
bae 已提交
1398
         /* Copy the locations from the read_info_ptr.  The automatically
1399 1400
          * 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).
B
bae 已提交
1401
          */
1402 1403 1404 1405 1406 1407 1408
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
                unknowns[i].location);
         }
#endif
D
duke 已提交
1409 1410 1411 1412 1413
      }
   }
#endif

#ifdef PNG_WRITE_SUPPORTED
B
bae 已提交
1414
   pngtest_debug("Writing info struct");
D
duke 已提交
1415

1416 1417 1418 1419
   /* Write the info in two steps so that if we write the 'unknown' chunks here
    * they go to the correct place.
    */
   png_write_info_before_PLTE(write_ptr, write_info_ptr);
A
azvegint 已提交
1420

1421
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
A
azvegint 已提交
1422

1423
   png_write_info(write_ptr, write_info_ptr);
B
bae 已提交
1424

1425
   write_chunks(write_ptr, before_IDAT); /* after PLTE */
D
duke 已提交
1426 1427 1428
#endif

#ifdef SINGLE_ROWBUF_ALLOC
B
bae 已提交
1429
   pngtest_debug("Allocating row buffer...");
D
duke 已提交
1430 1431
   row_buf = (png_bytep)png_malloc(read_ptr,
      png_get_rowbytes(read_ptr, read_info_ptr));
B
bae 已提交
1432 1433

   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
D
duke 已提交
1434
#endif /* SINGLE_ROWBUF_ALLOC */
B
bae 已提交
1435
   pngtest_debug("Writing row data");
D
duke 已提交
1436

1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
#if defined(PNG_READ_INTERLACING_SUPPORTED) &&\
   defined(PNG_WRITE_INTERLACING_SUPPORTED)
   /* Both must be defined for libpng to be able to handle the interlace,
    * otherwise it gets handled below by simply reading and writing the passes
    * directly.
    */
   if (png_set_interlace_handling(read_ptr) != num_passes)
      png_error(write_ptr,
            "png_set_interlace_handling(read): wrong pass count ");
   if (png_set_interlace_handling(write_ptr) != num_passes)
      png_error(write_ptr,
            "png_set_interlace_handling(write): wrong pass count ");
#else /* png_set_interlace_handling not called on either read or write */
#  define calc_pass_height
#endif /* not using libpng interlace handling */
D
duke 已提交
1452 1453 1454 1455 1456 1457

#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
1458
   for (pass = 0; pass < num_passes; pass++)
D
duke 已提交
1459
   {
1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477
#     ifdef calc_pass_height
         png_uint_32 pass_height;

         if (num_passes == 7) /* interlaced */
         {
            if (PNG_PASS_COLS(width, pass) > 0)
               pass_height = PNG_PASS_ROWS(height, pass);

            else
               pass_height = 0;
         }

         else /* not interlaced */
            pass_height = height;
#     else
#        define pass_height height
#     endif

B
bae 已提交
1478
      pngtest_debug1("Writing row data for pass %d", pass);
1479
      for (y = 0; y < pass_height; y++)
D
duke 已提交
1480 1481
      {
#ifndef SINGLE_ROWBUF_ALLOC
B
bae 已提交
1482
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1483

D
duke 已提交
1484 1485
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
B
bae 已提交
1486

1487 1488
         pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
            (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
B
bae 已提交
1489

D
duke 已提交
1490
#endif /* !SINGLE_ROWBUF_ALLOC */
B
bae 已提交
1491
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
D
duke 已提交
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504

#ifdef PNG_WRITE_SUPPORTED
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1505
#endif /* WRITE */
D
duke 已提交
1506 1507

#ifndef SINGLE_ROWBUF_ALLOC
B
bae 已提交
1508
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
D
duke 已提交
1509
         png_free(read_ptr, row_buf);
B
bae 已提交
1510
         row_buf = NULL;
D
duke 已提交
1511 1512 1513 1514
#endif /* !SINGLE_ROWBUF_ALLOC */
      }
   }

1515 1516 1517 1518 1519 1520 1521
#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
#  ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
      png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
#  endif
#  ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
      png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
#  endif
D
duke 已提交
1522 1523
#endif

B
bae 已提交
1524
   pngtest_debug("Reading and writing end_info data");
D
duke 已提交
1525 1526

   png_read_end(read_ptr, end_info_ptr);
B
bae 已提交
1527
#ifdef PNG_TEXT_SUPPORTED
D
duke 已提交
1528 1529 1530 1531 1532 1533
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
B
bae 已提交
1534
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549

         pngtest_check_text_support(read_ptr, text_ptr, num_text);

         if (verbose != 0)
         {
            int i;

            printf("\n");
            for (i=0; i<num_text; i++)
            {
               printf("   Text compression[%d]=%d\n",
                     i, text_ptr[i].compression);
            }
         }

D
duke 已提交
1550 1551 1552 1553
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
B
bae 已提交
1554
#ifdef PNG_tIME_SUPPORTED
D
duke 已提交
1555 1556 1557
   {
      png_timep mod_time;

1558
      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time) != 0)
D
duke 已提交
1559 1560
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
B
bae 已提交
1561
#ifdef PNG_TIME_RFC1123_SUPPORTED
1562 1563 1564 1565 1566 1567 1568 1569 1570
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
            tIME_string[(sizeof tIME_string) - 1] = '\0';

         else
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }

D
duke 已提交
1571
         tIME_chunk_present++;
1572
#endif /* TIME_RFC1123 */
D
duke 已提交
1573 1574 1575
      }
   }
#endif
B
bae 已提交
1576
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
D
duke 已提交
1577 1578
   {
      png_unknown_chunkp unknowns;
B
bae 已提交
1579
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
D
duke 已提交
1580
         &unknowns);
B
bae 已提交
1581

1582
      if (num_unknowns != 0)
D
duke 已提交
1583 1584 1585
      {
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1586
#if PNG_LIBPNG_VER < 10600
B
bae 已提交
1587
         /* Copy the locations from the read_info_ptr.  The automatically
1588 1589
          * 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).
B
bae 已提交
1590
          */
1591 1592 1593 1594 1595 1596 1597
         {
            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
D
duke 已提交
1598 1599 1600
      }
   }
#endif
1601

D
duke 已提交
1602
#ifdef PNG_WRITE_SUPPORTED
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
   /* Normally one would use Z_DEFAULT_STRATEGY for text compression.
    * This is here just to make pngtest replicate the results from libpng
    * versions prior to 1.5.4, and to test this new API.
    */
   png_set_text_compression_strategy(write_ptr, Z_FILTERED);
#endif

   /* When the unknown vpAg/sTER chunks are written by pngtest the only way to
    * do it is to write them *before* calling png_write_end.  When unknown
    * chunks are written by libpng, however, they are written just before IEND.
    * There seems to be no way round this, however vpAg/sTER are not expected
    * after IDAT.
    */
   write_chunks(write_ptr, after_IDAT);

D
duke 已提交
1619 1620 1621 1622
   png_write_end(write_ptr, write_end_info_ptr);
#endif

#ifdef PNG_EASY_ACCESS_SUPPORTED
1623
   if (verbose != 0)
D
duke 已提交
1624 1625 1626 1627
   {
      png_uint_32 iwidth, iheight;
      iwidth = png_get_image_width(write_ptr, write_info_ptr);
      iheight = png_get_image_height(write_ptr, write_info_ptr);
B
bae 已提交
1628
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
D
duke 已提交
1629 1630 1631 1632
         (unsigned long)iwidth, (unsigned long)iheight);
   }
#endif

B
bae 已提交
1633
   pngtest_debug("Destroying data structs");
D
duke 已提交
1634
#ifdef SINGLE_ROWBUF_ALLOC
B
bae 已提交
1635
   pngtest_debug("destroying row_buf for read_ptr");
D
duke 已提交
1636
   png_free(read_ptr, row_buf);
B
bae 已提交
1637
   row_buf = NULL;
D
duke 已提交
1638
#endif /* SINGLE_ROWBUF_ALLOC */
B
bae 已提交
1639
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
D
duke 已提交
1640 1641
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
#ifdef PNG_WRITE_SUPPORTED
B
bae 已提交
1642
   pngtest_debug("destroying write_end_info_ptr");
D
duke 已提交
1643
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
B
bae 已提交
1644
   pngtest_debug("destroying write_ptr, write_info_ptr");
D
duke 已提交
1645 1646
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
#endif
B
bae 已提交
1647
   pngtest_debug("Destruction complete.");
D
duke 已提交
1648 1649 1650 1651

   FCLOSE(fpin);
   FCLOSE(fpout);

1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685
   /* Summarize any warnings or errors and in 'strict' mode fail the test.
    * Unsupported chunks can result in warnings, in that case ignore the strict
    * setting, otherwise fail the test on warnings as well as errors.
    */
   if (error_count > 0)
   {
      /* We don't really expect to get here because of the setjmp handling
       * above, but this is safe.
       */
      fprintf(STDERR, "\n  %s: %d libpng errors found (%d warnings)",
         inname, error_count, warning_count);

      if (strict != 0)
         return (1);
   }

#  ifdef PNG_WRITE_SUPPORTED
      /* If there is no write support nothing was written! */
      else if (unsupported_chunks > 0)
      {
         fprintf(STDERR, "\n  %s: unsupported chunks (%d)%s",
            inname, unsupported_chunks, strict ? ": IGNORED --strict!" : "");
      }
#  endif

   else if (warning_count > 0)
   {
      fprintf(STDERR, "\n  %s: %d libpng warnings found",
         inname, warning_count);

      if (strict != 0)
         return (1);
   }

B
bae 已提交
1686
   pngtest_debug("Opening files for comparison");
D
duke 已提交
1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699
   if ((fpin = fopen(inname, "rb")) == NULL)
   {
      fprintf(STDERR, "Could not find file %s\n", inname);
      return (1);
   }

   if ((fpout = fopen(outname, "rb")) == NULL)
   {
      fprintf(STDERR, "Could not find file %s\n", outname);
      FCLOSE(fpin);
      return (1);
   }

1700 1701 1702
#if defined (PNG_WRITE_SUPPORTED) /* else nothing was written */ &&\
    defined (PNG_WRITE_FILTER_SUPPORTED)
   if (interlace_preserved != 0) /* else the files will be changed */
D
duke 已提交
1703
   {
1704
      for (;;)
A
azvegint 已提交
1705
      {
1706 1707 1708 1709 1710 1711
         static int wrote_question = 0;
         png_size_t num_in, num_out;
         char inbuf[256], outbuf[256];

         num_in = fread(inbuf, 1, sizeof inbuf, fpin);
         num_out = fread(outbuf, 1, sizeof outbuf, fpout);
A
azvegint 已提交
1712

1713
         if (num_in != num_out)
A
azvegint 已提交
1714
         {
1715 1716 1717 1718 1719 1720
            fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
                    inname, outname);

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
D
duke 已提交
1721
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1722 1723 1724 1725 1726 1727 1728 1729
                 inname, PNG_ZBUF_SIZE);
               fprintf(STDERR,
                 "\n   filtering heuristic (libpng default), compression");
               fprintf(STDERR,
                 " level (zlib default),\n   and zlib version (%s)?\n\n",
                 ZLIB_VERSION);
               wrote_question = 1;
            }
D
duke 已提交
1730

1731 1732
            FCLOSE(fpin);
            FCLOSE(fpout);
D
duke 已提交
1733

1734 1735
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
A
azvegint 已提交
1736

1737 1738 1739 1740 1741 1742
            else
              return (0);
         }

         if (num_in == 0)
            break;
B
bae 已提交
1743

1744
         if (memcmp(inbuf, outbuf, num_in))
D
duke 已提交
1745
         {
1746 1747 1748 1749 1750 1751
            fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
               outname);

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
D
duke 已提交
1752
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1753 1754 1755 1756 1757 1758 1759 1760
                    inname, PNG_ZBUF_SIZE);
               fprintf(STDERR,
                 "\n   filtering heuristic (libpng default), compression");
               fprintf(STDERR,
                 " level (zlib default),\n   and zlib version (%s)?\n\n",
                 ZLIB_VERSION);
               wrote_question = 1;
            }
A
azvegint 已提交
1761

1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775
            FCLOSE(fpin);
            FCLOSE(fpout);

            /* NOTE: the unsupported_chunks escape is permitted here because
             * unsupported text chunk compression will result in the compression
             * mode being changed (to NONE) yet, in the test case, the result
             * can be exactly the same size!
             */
            if (strict != 0 && unsupported_chunks == 0)
              return (1);

            else
              return (0);
         }
D
duke 已提交
1776 1777
      }
   }
1778
#endif /* WRITE && WRITE_FILTER */
D
duke 已提交
1779 1780 1781 1782 1783 1784 1785

   FCLOSE(fpin);
   FCLOSE(fpout);

   return (0);
}

B
bae 已提交
1786
/* Input and output filenames */
D
duke 已提交
1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800
#ifdef RISCOS
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
#else
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
#endif

int
main(int argc, char *argv[])
{
   int multiple = 0;
   int ierror = 0;

1801 1802
   png_structp dummy_ptr;

B
bae 已提交
1803
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
D
duke 已提交
1804
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
B
bae 已提交
1805
   fprintf(STDERR, "%s", png_get_copyright(NULL));
D
duke 已提交
1806
   /* Show the version of libpng used in building the library */
B
bae 已提交
1807
   fprintf(STDERR, " library (%lu):%s",
D
duke 已提交
1808 1809
      (unsigned long)png_access_version_number(),
      png_get_header_version(NULL));
B
bae 已提交
1810

D
duke 已提交
1811
   /* Show the version of libpng used in building the application */
B
bae 已提交
1812
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
D
duke 已提交
1813 1814 1815
      PNG_HEADER_VERSION_STRING);

   /* Do some consistency checking on the memory allocation settings, I'm
B
bae 已提交
1816 1817 1818 1819
    * not sure this matters, but it is nice to know, the first of these
    * tests should be impossible because of the way the macros are set
    * in pngconf.h
    */
D
duke 已提交
1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
#endif
   /* I think the following can happen. */
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
#endif

   if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
   {
      fprintf(STDERR,
         "Warning: versions are different between png.h and png.c\n");
      fprintf(STDERR, "  png.h version: %s\n", PNG_LIBPNG_VER_STRING);
      fprintf(STDERR, "  png.c version: %s\n\n", png_libpng_ver);
      ++ierror;
   }

   if (argc > 1)
   {
      if (strcmp(argv[1], "-m") == 0)
      {
         multiple = 1;
         status_dots_requested = 0;
      }
B
bae 已提交
1844

D
duke 已提交
1845 1846 1847 1848 1849 1850 1851
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
         status_dots_requested = 1;
      }
B
bae 已提交
1852

D
duke 已提交
1853 1854 1855 1856 1857 1858
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
         status_dots_requested = 1;
         inname = argv[2];
      }
B
bae 已提交
1859

1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
         relaxed = 0;
      }

      else if (strcmp(argv[1], "--relaxed") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict = 0;
         relaxed++;
      }

D
duke 已提交
1878 1879 1880 1881 1882 1883 1884
      else
      {
         inname = argv[1];
         status_dots_requested = 0;
      }
   }

1885
   if (multiple == 0 && argc == 3 + verbose)
B
bae 已提交
1886
     outname = argv[2 + verbose];
D
duke 已提交
1887

1888 1889
   if ((multiple == 0 && argc > 3 + verbose) ||
       (multiple != 0 && argc < 2))
D
duke 已提交
1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900
   {
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
        argv[0], argv[0]);
     fprintf(STDERR,
       "  reads/writes one PNG file (without -m) or multiple files (-m)\n");
     fprintf(STDERR,
       "  with -m %s is used as a temporary file\n", outname);
     exit(1);
   }

1901
   if (multiple != 0)
D
duke 已提交
1902 1903 1904 1905 1906 1907 1908 1909
   {
      int i;
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
      int allocation_now = current_allocation;
#endif
      for (i=2; i<argc; ++i)
      {
         int kerror;
B
bae 已提交
1910
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1911 1912 1913
#if PNG_DEBUG > 0
         fprintf(STDERR, "\n");
#endif
D
duke 已提交
1914 1915 1916
         kerror = test_one_file(argv[i], outname);
         if (kerror == 0)
         {
B
bae 已提交
1917
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
D
duke 已提交
1918 1919 1920 1921 1922
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
               (unsigned long)zero_samples);
#else
            fprintf(STDERR, " PASS\n");
#endif
B
bae 已提交
1923
#ifdef PNG_TIME_RFC1123_SUPPORTED
1924 1925
            if (tIME_chunk_present != 0)
               fprintf(STDERR, " tIME = %s\n", tIME_string);
B
bae 已提交
1926

1927 1928
            tIME_chunk_present = 0;
#endif /* TIME_RFC1123 */
D
duke 已提交
1929
         }
B
bae 已提交
1930

D
duke 已提交
1931 1932 1933 1934 1935 1936 1937 1938
         else
         {
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
         }
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
B
bae 已提交
1939 1940
               current_allocation - allocation_now);

D
duke 已提交
1941 1942 1943 1944 1945 1946
         if (current_allocation != 0)
         {
            memory_infop pinfo = pinformation;

            fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
               current_allocation);
B
bae 已提交
1947

D
duke 已提交
1948 1949
            while (pinfo != NULL)
            {
1950
               fprintf(STDERR, " %lu bytes at %p\n",
B
bae 已提交
1951
                 (unsigned long)pinfo->size,
1952
                 pinfo->pointer);
D
duke 已提交
1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968
               pinfo = pinfo->next;
            }
         }
#endif
      }
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
            current_allocation);
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
            maximum_allocation);
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
#endif
   }
B
bae 已提交
1969

D
duke 已提交
1970 1971 1972
   else
   {
      int i;
B
bae 已提交
1973
      for (i = 0; i<3; ++i)
D
duke 已提交
1974 1975 1976 1977 1978
      {
         int kerror;
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
         int allocation_now = current_allocation;
#endif
B
bae 已提交
1979 1980 1981 1982 1983 1984
         if (i == 1)
            status_dots_requested = 1;

         else if (verbose == 0)
            status_dots_requested = 0;

D
duke 已提交
1985
         if (i == 0 || verbose == 1 || ierror != 0)
1986
         {
B
bae 已提交
1987
            fprintf(STDERR, "\n Testing %s:", inname);
1988 1989 1990 1991
#if PNG_DEBUG > 0
            fprintf(STDERR, "\n");
#endif
         }
B
bae 已提交
1992

D
duke 已提交
1993
         kerror = test_one_file(inname, outname);
B
bae 已提交
1994 1995

         if (kerror == 0)
D
duke 已提交
1996
         {
B
bae 已提交
1997
            if (verbose == 1 || i == 2)
D
duke 已提交
1998
            {
B
bae 已提交
1999
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
D
duke 已提交
2000 2001 2002 2003 2004
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
                   (unsigned long)zero_samples);
#else
                fprintf(STDERR, " PASS\n");
#endif
B
bae 已提交
2005 2006 2007
#ifdef PNG_TIME_RFC1123_SUPPORTED
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
2008
#endif /* TIME_RFC1123 */
D
duke 已提交
2009 2010
            }
         }
B
bae 已提交
2011

D
duke 已提交
2012 2013
         else
         {
B
bae 已提交
2014
            if (verbose == 0 && i != 2)
2015
            {
B
bae 已提交
2016
               fprintf(STDERR, "\n Testing %s:", inname);
2017 2018 2019 2020
#if PNG_DEBUG > 0
               fprintf(STDERR, "\n");
#endif
            }
B
bae 已提交
2021

D
duke 已提交
2022 2023 2024 2025 2026 2027
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
         }
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
B
bae 已提交
2028 2029
               current_allocation - allocation_now);

D
duke 已提交
2030 2031 2032 2033 2034 2035
         if (current_allocation != 0)
         {
             memory_infop pinfo = pinformation;

             fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
                current_allocation);
B
bae 已提交
2036

D
duke 已提交
2037 2038
             while (pinfo != NULL)
             {
2039 2040
                fprintf(STDERR, " %lu bytes at %p\n",
                   (unsigned long)pinfo->size, pinfo->pointer);
D
duke 已提交
2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061
                pinfo = pinfo->next;
             }
          }
#endif
       }
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
          current_allocation);
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
          maximum_allocation);
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
#endif
   }

#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
B
bae 已提交
2062
   fprintf(STDERR, " CPU time used = %.3f seconds",
D
duke 已提交
2063
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
B
bae 已提交
2064
   fprintf(STDERR, " (decoding %.3f,\n",
D
duke 已提交
2065
      t_decode/(float)CLOCKS_PER_SEC);
B
bae 已提交
2066
   fprintf(STDERR, "        encoding %.3f ,",
D
duke 已提交
2067
      t_encode/(float)CLOCKS_PER_SEC);
B
bae 已提交
2068
   fprintf(STDERR, " other %.3f seconds)\n\n",
D
duke 已提交
2069 2070 2071 2072
      t_misc/(float)CLOCKS_PER_SEC);
#endif

   if (ierror == 0)
B
bae 已提交
2073 2074
      fprintf(STDERR, " libpng passes test\n");

D
duke 已提交
2075
   else
B
bae 已提交
2076 2077
      fprintf(STDERR, " libpng FAILS test\n");

2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095
   dummy_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   fprintf(STDERR, " Default limits:\n");
   fprintf(STDERR, "  width_max  = %lu\n",
      (unsigned long) png_get_user_width_max(dummy_ptr));
   fprintf(STDERR, "  height_max = %lu\n",
      (unsigned long) png_get_user_height_max(dummy_ptr));
   if (png_get_chunk_cache_max(dummy_ptr) == 0)
      fprintf(STDERR, "  cache_max  = unlimited\n");
   else
      fprintf(STDERR, "  cache_max  = %lu\n",
         (unsigned long) png_get_chunk_cache_max(dummy_ptr));
   if (png_get_chunk_malloc_max(dummy_ptr) == 0)
      fprintf(STDERR, "  malloc_max = unlimited\n");
   else
      fprintf(STDERR, "  malloc_max = %lu\n",
         (unsigned long) png_get_chunk_malloc_max(dummy_ptr));
   png_destroy_read_struct(&dummy_ptr, NULL, NULL);

D
duke 已提交
2096 2097
   return (int)(ierror != 0);
}
2098 2099 2100 2101 2102 2103 2104
#else
int
main(void)
{
   fprintf(STDERR,
      " test ignored because libpng was not built with read support\n");
   /* And skip this test */
2105
   return SKIP;
2106 2107
}
#endif
D
duke 已提交
2108 2109

/* Generate a compiler error if there is an old png.h in the search path. */
2110
typedef png_libpng_version_1_6_23 Your_png_h_is_not_version_1_6_23;