pngtest.c 50.1 KB
Newer Older
A
Andreas Dilger 已提交
1

G
Guy Schalnat 已提交
2
/* pngtest.c - a simple test program to test libpng
3
 *
4
 * Last changed in libpng 1.5.0 [January 6, 2011]
5
 * Copyright (c) 1998-2011 Glenn Randers-Pehrson
6 7
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8
 *
9
 * This code is released under the libpng license.
10
 * For conditions of distribution and use, see the disclaimer
11
 * and license in png.h
12
 *
13 14 15 16 17 18
 * 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.
 *
19
 * The program will report "FAIL" in certain legitimate cases:
20
 * 1) when the compression level or filter selection method is changed.
21
 * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192.
22 23
 * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks
 *    exist in the input file.
24 25
 * 4) others not listed here...
 * In these cases, it is best to check with another tool such as "pngcheck"
26
 * to see what the differences between the two files are.
27 28 29
 *
 * 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
30 31
 * 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 ..."
32
 */
G
Guy Schalnat 已提交
33

G
[devel]  
Glenn Randers-Pehrson 已提交
34
#include "zlib.h"
35
#include "png.h"
36 37 38 39
/* Copied from pngpriv.h but only used in error messages below. */
#ifndef PNG_ZBUF_SIZE
#  define PNG_ZBUF_SIZE 8192
#endif
40 41
#  include <stdio.h>
#  include <stdlib.h>
42
#  include <string.h>
43
#  define FCLOSE(file) fclose(file)
44

45
#ifndef PNG_STDIO_SUPPORTED
46
typedef FILE                * png_FILE_p;
47 48
#endif

49
/* Makes pngtest verbose so we can find problems. */
A
Andreas Dilger 已提交
50
#ifndef PNG_DEBUG
51 52 53
#  define PNG_DEBUG 0
#endif

54 55 56 57 58 59 60 61 62
#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
63

64
#if !PNG_DEBUG
65
#  define SINGLE_ROWBUF_ALLOC  /* Makes buffer overruns easier to nail */
66
#endif
A
Andreas Dilger 已提交
67

G
[devel]  
Glenn Randers-Pehrson 已提交
68 69 70 71 72 73 74 75 76 77 78
/* The code uses memcmp and memcpy on large objects (typically row pointers) so
 * it is necessary to do soemthing special on certain architectures, note that
 * the actual support for this was effectively removed in 1.4, so only the
 * memory remains in this program:
 */
#define CVT_PTR(ptr)         (ptr)
#define CVT_PTR_NOCHECK(ptr) (ptr)
#define png_memcmp  memcmp
#define png_memcpy  memcpy
#define png_memset  memset

79 80 81 82
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

83
#ifndef PNG_FLOATING_POINT_SUPPORTED
84 85 86
#undef PNGTEST_TIMING
#endif

87 88 89 90 91
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

92
#ifdef PNG_TIME_RFC1123_SUPPORTED
93
#define PNG_tIME_STRING_LENGTH 29
94
static int tIME_chunk_present = 0;
95
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
96 97
#endif

98 99
static int verbose = 0;

100
int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
101

G
Guy Schalnat 已提交
102 103 104 105
#ifdef __TURBOC__
#include <mem.h>
#endif

106
/* Defined so I can write to a file on gui/windowing platforms */
G
Guy Schalnat 已提交
107
/*  #define STDERR stderr  */
108
#define STDERR stdout   /* For DOS */
G
Guy Schalnat 已提交
109

110 111 112 113 114
/* 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

115
/* Example of using row callbacks to make a simple progress meter */
116 117 118
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
119

120
void PNGCBAPI
121
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
122
void PNGCBAPI
123
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
124
{
125 126
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
127

128 129 130 131 132 133
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
134

135
   status_dots--;
136

137 138 139 140 141
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
142

143
   fprintf(stdout, "r");
144
}
145

146
void PNGCBAPI
147
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
148
void PNGCBAPI
149
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
150
{
151 152
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;
153

154
   fprintf(stdout, "w");
155 156 157
}


158
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
159
/* Example of using user transform callback (we don't transform anything,
160 161 162
 * but merely examine the row filters.  We set this to 256 rather than
 * 5 in case illegal filter values are present.)
 */
163
static png_uint_32 filters_used[256];
164
void PNGCBAPI
165
count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data);
166
void PNGCBAPI
167 168
count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{
169
   if (png_ptr != NULL && row_info != NULL)
170
      ++filters_used[*(data - 1)];
171 172 173
}
#endif

174
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
175
/* Example of using user transform callback (we don't transform anything,
176 177
 * but merely count the zero samples)
 */
178

179
static png_uint_32 zero_samples;
180

181
void PNGCBAPI
182
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
183
void PNGCBAPI
184
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
185 186
{
   png_bytep dp = data;
187 188
   if (png_ptr == NULL)
      return;
189

190
   /* Contents of row_info:
191 192 193 194 195 196 197 198
    *  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)
    */

199
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
200

201
    if (row_info->color_type == 0 || row_info->color_type == 3)
202
    {
203
       int pos = 0;
204
       png_uint_32 n, nstop;
205

206
       for (n = 0, nstop=row_info->width; n<nstop; n++)
207
       {
208
          if (row_info->bit_depth == 1)
209
          {
210 211
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;
212

213
             if (pos == 8)
214
             {
215
                pos = 0;
216 217
                dp++;
             }
218
          }
219

220
          if (row_info->bit_depth == 2)
221
          {
222 223
             if (((*dp << (pos+=2)) & 0xc0) == 0)
                zero_samples++;
224

225
             if (pos == 8)
226
             {
227
                pos = 0;
228 229
                dp++;
             }
230
          }
231

232
          if (row_info->bit_depth == 4)
233
          {
234 235
             if (((*dp << (pos+=4)) & 0xf0) == 0)
                zero_samples++;
236

237
             if (pos == 8)
238
             {
239
                pos = 0;
240 241
                dp++;
             }
242
          }
243

244
          if (row_info->bit_depth == 8)
245 246
             if (*dp++ == 0)
                zero_samples++;
247

248
          if (row_info->bit_depth == 16)
249
          {
250 251
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
252 253 254 255
             dp+=2;
          }
       }
    }
256
    else /* Other color types */
257
    {
258
       png_uint_32 n, nstop;
259 260
       int channel;
       int color_channels = row_info->channels;
261
       if (row_info->color_type > 3)color_channels--;
262

263
       for (n = 0, nstop=row_info->width; n<nstop; n++)
264 265 266
       {
          for (channel = 0; channel < color_channels; channel++)
          {
267
             if (row_info->bit_depth == 8)
268 269
                if (*dp++ == 0)
                   zero_samples++;
270

271
             if (row_info->bit_depth == 16)
272
             {
273 274
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;
275

276 277 278
                dp+=2;
             }
          }
279
          if (row_info->color_type > 3)
280 281
          {
             dp++;
282 283
             if (row_info->bit_depth == 16)
                dp++;
284 285 286 287
          }
       }
    }
}
288
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
289

290
static int wrote_question = 0;
291

292
#ifndef PNG_STDIO_SUPPORTED
293
/* START of code to validate stdio-free compilation */
294 295 296 297 298 299 300
/* 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.
 */
301

302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
#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 */
   }
   if (err)
      png_error(png_ptr, "Bad I/O state or buffer size");
}
#endif

344
#ifndef USE_FAR_KEYWORD
345
static void PNGCBAPI
346
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
347
{
348 349
   png_size_t check = 0;
   png_voidp io_ptr;
350 351 352 353

   /* 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.
    */
354 355 356 357 358
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
   }
359

360 361
   if (check != length)
   {
362
      png_error(png_ptr, "Read Error");
363
   }
364 365 366 367

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
#endif
368
}
G
Guy Schalnat 已提交
369
#else
370
/* This is the model-independent version. Since the standard I/O library
371 372 373
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/
374

375 376
#define NEAR_BUF_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)
377

378
static void PNGCBAPI
379
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
380
{
381
   png_size_t check;
382
   png_byte *n_data;
383
   png_FILE_p io_ptr;
384 385 386

   /* Check if data really is near. If so, use usual code. */
   n_data = (png_byte *)CVT_PTR_NOCHECK(data);
387
   io_ptr = (png_FILE_p)CVT_PTR(png_get_io_ptr(png_ptr));
388 389
   if ((png_bytep)n_data == data)
   {
390
      check = fread(n_data, 1, length, io_ptr);
391 392 393 394 395 396 397
   }
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t read, remaining, err;
      check = 0;
      remaining = length;
398

399 400 401
      do
      {
         read = MIN(NEAR_BUF_SIZE, remaining);
402
         err = fread(buf, 1, 1, io_ptr);
403
         png_memcpy(data, buf, read); /* Copy far buffer to near buffer */
404
         if (err != read)
405 406 407 408 409 410 411 412
            break;
         else
            check += err;
         data += read;
         remaining -= read;
      }
      while (remaining != 0);
   }
413

414
   if (check != length)
415 416 417 418 419
      png_error(png_ptr, "Read Error");

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
#endif
420
}
421
#endif /* USE_FAR_KEYWORD */
G
Guy Schalnat 已提交
422

423
#ifdef PNG_WRITE_FLUSH_SUPPORTED
424
static void PNGCBAPI
425
pngtest_flush(png_structp png_ptr)
426
{
427
   /* Do nothing; fflush() is said to be just a waste of energy. */
428
   PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
429 430
}
#endif
G
Guy Schalnat 已提交
431

432
/* This is the function that does the actual writing of data.  If you are
433 434 435 436
 * 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.
 */
437
#ifndef USE_FAR_KEYWORD
438
static void PNGCBAPI
439
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
440
{
441
   png_size_t check;
442

443
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
444

445 446 447 448
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
449 450 451 452

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
453 454
}
#else
455
/* This is the model-independent version. Since the standard I/O library
456 457 458 459 460 461 462
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/

#define NEAR_BUF_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)

463
static void PNGCBAPI
464
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
465
{
466
   png_size_t check;
467
   png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
468
   png_FILE_p io_ptr;
469 470 471

   /* Check if data really is near. If so, use usual code. */
   near_data = (png_byte *)CVT_PTR_NOCHECK(data);
472
   io_ptr = (png_FILE_p)CVT_PTR(png_get_io_ptr(png_ptr));
473

474 475
   if ((png_bytep)near_data == data)
   {
476
      check = fwrite(near_data, 1, length, io_ptr);
477
   }
478

479 480 481 482 483 484
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t written, remaining, err;
      check = 0;
      remaining = length;
485

486 487 488
      do
      {
         written = MIN(NEAR_BUF_SIZE, remaining);
489
         png_memcpy(buf, data, written); /* Copy far buffer to near buffer */
490
         err = fwrite(buf, 1, written, io_ptr);
491 492 493 494 495 496 497 498 499
         if (err != written)
            break;
         else
            check += err;
         data += written;
         remaining -= written;
      }
      while (remaining != 0);
   }
500

501 502 503 504
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
505 506 507 508

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
509
}
510
#endif /* USE_FAR_KEYWORD */
511 512 513 514 515 516

/* 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.
 */
517
static void PNGCBAPI
518
pngtest_warning(png_structp png_ptr, png_const_charp message)
519 520
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
521 522
   char *test;
   test = png_get_error_ptr(png_ptr);
523

524 525
   if (test == NULL)
     fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
526

527 528
   else
     fprintf(STDERR, "%s: libpng warning: %s\n", test, message);
529 530 531 532 533 534 535
}

/* 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().
 */
536
static void PNGCBAPI
537
pngtest_error(png_structp png_ptr, png_const_charp message)
538
{
539
   pngtest_warning(png_ptr, message);
540
   /* We can return because png_error calls the default handler, which is
541 542
    * actually OK in this case.
    */
543
}
544
#endif /* !PNG_STDIO_SUPPORTED */
545 546
/* END of code to validate stdio-free compilation */

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

/* Allocate memory.  For reasonable files, size should never exceed
551 552 553 554 555 556 557 558
 * 64K.  However, zlib may allocate more then 64K if you don't tell
 * 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.
 */
559 560
typedef struct memory_information
{
561
   png_alloc_size_t          size;
562
   png_voidp                 pointer;
563 564 565 566 567 568 569
   struct memory_information FAR *next;
} memory_information;
typedef memory_information FAR *memory_infop;

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

573 574 575
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));
576 577

png_voidp
578
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
579
{
580

581
   /* png_malloc has already tested for NULL; png_create_struct calls
582 583
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
584

585
   if (size == 0)
586
      return (NULL);
587 588 589 590

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
591
      /* Disable malloc_fn and free_fn */
592
      memory_infop pinfo;
593
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
594 595
      pinfo = (memory_infop)png_malloc(png_ptr,
         png_sizeof(*pinfo));
596 597
      pinfo->size = size;
      current_allocation += size;
598 599
      total_allocation += size;
      num_allocations ++;
600

601 602
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
603

604
      pinfo->pointer = png_malloc(png_ptr, size);
605
      /* Restore malloc_fn and free_fn */
606

607 608
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
609

610 611 612 613
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
614
         png_error(png_ptr,
615
           "out of memory in pngtest->png_debug_malloc");
616
      }
617

618 619 620 621
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
      png_memset(pinfo->pointer, 0xdd, pinfo->size);
622

623
      if (verbose)
624
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
625
            pinfo->pointer);
626

627
      return (png_voidp)(pinfo->pointer);
628 629 630 631
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
632
void PNGCBAPI
633
png_debug_free(png_structp png_ptr, png_voidp ptr)
634 635
{
   if (png_ptr == NULL)
636
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
637

638 639
   if (ptr == 0)
   {
640 641 642 643 644 645 646 647 648
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
   {
      memory_infop FAR *ppinfo = &pinformation;
649

650 651
      for (;;)
      {
652
         memory_infop pinfo = *ppinfo;
653

654 655
         if (pinfo->pointer == ptr)
         {
656 657 658 659 660
            *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
661
               the memory that is to be freed. */
662
            png_memset(ptr, 0x55, pinfo->size);
663
            png_free_default(png_ptr, pinfo);
664
            pinfo = NULL;
665 666
            break;
         }
667

668 669
         if (pinfo->next == NULL)
         {
670
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
671 672
            break;
         }
673

674 675 676 677 678
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
679
   if (verbose)
680
      printf("Freeing %p\n", ptr);
681

682
   png_free_default(png_ptr, ptr);
683
   ptr = NULL;
684
}
685
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
686 687
/* END of code to test memory allocation/deallocation */

688 689

/* Demonstration of user chunk support of the sTER and vpAg chunks */
690
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
691

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

static png_uint_32 user_chunk_data[4];

697 698 699 700
    /* 0: sTER mode + 1
     * 1: vpAg width
     * 2: vpAg height
     * 3: vpAg units
701 702
     */

703
static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr,
704 705
   png_unknown_chunkp chunk)
{
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
   png_uint_32
     *my_user_chunk_data;

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

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

732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
         my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr);
         my_user_chunk_data[0]=chunk->data[0]+1;
         return (1);
      }

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

   my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr);

   my_user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data);
   my_user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4);
   my_user_chunk_data[3]=(png_uint_32)chunk->data[8];

   return (1);
753 754 755 756 757

}
#endif
/* END of code to demonstrate user chunk support */

758
/* Test one file */
759 760
int
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
761
{
762 763
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
764 765 766 767 768 769 770 771 772 773 774
   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;
#else
   png_structp write_ptr = NULL;
   png_infop write_info_ptr = NULL;
   png_infop write_end_info_ptr = NULL;
#endif
G
Guy Schalnat 已提交
775
   png_bytep row_buf;
G
Guy Schalnat 已提交
776
   png_uint_32 y;
A
Andreas Dilger 已提交
777 778 779
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
780
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
781
#ifdef USE_FAR_KEYWORD
782
   jmp_buf png_jmpbuf;
783
#endif
784
#endif
785

786
   char inbuf[256], outbuf[256];
G
Guy Schalnat 已提交
787

788
   row_buf = NULL;
G
Guy Schalnat 已提交
789

A
Andreas Dilger 已提交
790
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
791 792
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
793
      return (1);
G
Guy Schalnat 已提交
794 795
   }

A
Andreas Dilger 已提交
796
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
797
   {
G
Guy Schalnat 已提交
798
      fprintf(STDERR, "Could not open output file %s\n", outname);
799
      FCLOSE(fpin);
800
      return (1);
G
Guy Schalnat 已提交
801 802
   }

803
   pngtest_debug("Allocating read and write structures");
804
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
805 806
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
807
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
808
#else
809 810
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
811
#endif
812
#ifndef PNG_STDIO_SUPPORTED
813 814
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
815
#endif
816

817
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
818 819 820 821 822 823
   user_chunk_data[0] = 0;
   user_chunk_data[1] = 0;
   user_chunk_data[2] = 0;
   user_chunk_data[3] = 0;
   png_set_read_user_chunk_fn(read_ptr, user_chunk_data,
     read_user_chunk_callback);
824

825
#endif
826
#ifdef PNG_WRITE_SUPPORTED
827
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
828 829 830
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
831
#else
832 833
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
834
#endif
835
#ifndef PNG_STDIO_SUPPORTED
836 837
   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
838
#endif
839
#endif
840
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
841
   read_info_ptr = png_create_info_struct(read_ptr);
842
   end_info_ptr = png_create_info_struct(read_ptr);
843 844
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
845
   write_end_info_ptr = png_create_info_struct(write_ptr);
846
#endif
G
Guy Schalnat 已提交
847

848
#ifdef PNG_SETJMP_SUPPORTED
849
   pngtest_debug("Setting jmpbuf for read struct");
A
Andreas Dilger 已提交
850
#ifdef USE_FAR_KEYWORD
851
   if (setjmp(png_jmpbuf))
A
Andreas Dilger 已提交
852
#else
853
   if (setjmp(png_jmpbuf(read_ptr)))
A
Andreas Dilger 已提交
854
#endif
G
Guy Schalnat 已提交
855
   {
856
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
857 858
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
859
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
860
#ifdef PNG_WRITE_SUPPORTED
861
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
862
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
863
#endif
864 865
      FCLOSE(fpin);
      FCLOSE(fpout);
866
      return (1);
G
Guy Schalnat 已提交
867
   }
868
#ifdef USE_FAR_KEYWORD
869
   png_memcpy(png_jmpbuf(read_ptr), png_jmpbuf, png_sizeof(jmp_buf));
870
#endif
A
Andreas Dilger 已提交
871

872
#ifdef PNG_WRITE_SUPPORTED
873
   pngtest_debug("Setting jmpbuf for write struct");
A
Andreas Dilger 已提交
874
#ifdef USE_FAR_KEYWORD
875

876
   if (setjmp(png_jmpbuf))
A
Andreas Dilger 已提交
877
#else
878
   if (setjmp(png_jmpbuf(write_ptr)))
A
Andreas Dilger 已提交
879
#endif
G
Guy Schalnat 已提交
880
   {
881
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
882
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
883
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
884
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
885
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
886
#endif
887 888
      FCLOSE(fpin);
      FCLOSE(fpout);
889
      return (1);
G
Guy Schalnat 已提交
890
   }
891

A
Andreas Dilger 已提交
892
#ifdef USE_FAR_KEYWORD
893
   png_memcpy(png_jmpbuf(write_ptr), png_jmpbuf, png_sizeof(jmp_buf));
894
#endif
895
#endif
A
Andreas Dilger 已提交
896
#endif
897

898
   pngtest_debug("Initializing input and output streams");
899
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
900
   png_init_io(read_ptr, fpin);
901
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
902
   png_init_io(write_ptr, fpout);
903
#  endif
904
#else
905
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
906
#  ifdef PNG_WRITE_SUPPORTED
907
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
908
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
909
      pngtest_flush);
910
#    else
911
      NULL);
912 913
#    endif
#  endif
914
#endif
915

916
   if (status_dots_requested == 1)
917
   {
918
#ifdef PNG_WRITE_SUPPORTED
919
      png_set_write_status_fn(write_ptr, write_row_callback);
920
#endif
921 922
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
923

924 925
   else
   {
926
#ifdef PNG_WRITE_SUPPORTED
927
      png_set_write_status_fn(write_ptr, NULL);
928
#endif
929
      png_set_read_status_fn(read_ptr, NULL);
930 931
   }

932
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
933
   {
934
      int i;
935

936 937
      for (i = 0; i<256; i++)
         filters_used[i] = 0;
938

939
      png_set_read_user_transform_fn(read_ptr, count_filters);
940 941
   }
#endif
942
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
943
   zero_samples = 0;
944 945
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
946

947
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
948 949 950
#  ifndef PNG_HANDLE_CHUNK_ALWAYS
#    define PNG_HANDLE_CHUNK_ALWAYS       3
#  endif
951 952
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
953
#endif
954
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
955 956 957
#  ifndef PNG_HANDLE_CHUNK_IF_SAFE
#    define PNG_HANDLE_CHUNK_IF_SAFE      2
#  endif
958 959
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
      NULL, 0);
960 961
#endif

962
   pngtest_debug("Reading info struct");
A
Andreas Dilger 已提交
963
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
964

965
   pngtest_debug("Transferring info struct");
A
Andreas Dilger 已提交
966 967
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
968

A
Andreas Dilger 已提交
969 970 971 972
      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
          &color_type, &interlace_type, &compression_type, &filter_type))
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
973
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
974
            color_type, interlace_type, compression_type, filter_type);
975 976 977
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
978 979
      }
   }
980 981
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
982
   {
983
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
984
         blue_y;
985

986 987
      if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y,
         &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y))
A
Andreas Dilger 已提交
988
      {
989 990
         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);
A
Andreas Dilger 已提交
991
      }
G
Guy Schalnat 已提交
992
   }
A
Andreas Dilger 已提交
993
#endif
994
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
995
   {
996
      png_fixed_point gamma;
G
Guy Schalnat 已提交
997

998 999
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
1000 1001
   }
#endif
1002
#else /* Use floating point versions */
1003 1004
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
1005 1006 1007
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
1008

1009 1010 1011 1012 1013 1014 1015 1016
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
         &red_y, &green_x, &green_y, &blue_x, &blue_y))
      {
         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
1017
#ifdef PNG_gAMA_SUPPORTED
1018 1019 1020 1021 1022 1023 1024
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
1025 1026
#endif /* Floating point */
#endif /* Fixed point */
1027
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
1028
   {
1029
      png_charp name;
G
[devel]  
Glenn Randers-Pehrson 已提交
1030
      png_bytep profile;
1031
      png_uint_32 proflen;
1032
      int compression_type;
A
Andreas Dilger 已提交
1033

1034 1035
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
1036
      {
1037 1038
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
1039
      }
G
Guy Schalnat 已提交
1040
   }
1041
#endif
1042
#ifdef PNG_sRGB_SUPPORTED
1043
   {
1044
      int intent;
1045 1046 1047 1048

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
1049
#endif
1050 1051 1052 1053 1054 1055 1056
   {
      png_colorp palette;
      int num_palette;

      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
   }
1057
#ifdef PNG_bKGD_SUPPORTED
1058 1059 1060 1061 1062 1063 1064 1065 1066
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1067
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1068
   {
A
Andreas Dilger 已提交
1069 1070 1071 1072
      png_uint_16p hist;

      if (png_get_hIST(read_ptr, read_info_ptr, &hist))
         png_set_hIST(write_ptr, write_info_ptr, hist);
G
Guy Schalnat 已提交
1073
   }
A
Andreas Dilger 已提交
1074
#endif
1075
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1076
   {
1077
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1078
      int unit_type;
G
Guy Schalnat 已提交
1079

1080
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1081
          &unit_type))
A
Andreas Dilger 已提交
1082 1083 1084 1085 1086
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1087
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
   {
      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,
         &nparams, &units, &params))
      {
         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
            nparams, units, params);
      }
   }
#endif
1102
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1103 1104 1105 1106 1107 1108 1109 1110
   {
      png_uint_32 res_x, res_y;
      int unit_type;

      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
1111
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1112
   {
1113
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1114

1115 1116
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1117
   }
1118
#endif
1119
#ifdef PNG_sCAL_SUPPORTED
1120
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
1121
   {
1122
      int unit;
1123
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1124

1125 1126
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
         &scal_height))
G
Guy Schalnat 已提交
1127
      {
1128
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1129 1130 1131
      }
   }
#else
1132
#ifdef PNG_FIXED_POINT_SUPPORTED
1133
   {
1134
      int unit;
1135
      png_charp scal_width, scal_height;
1136

1137 1138
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
          &scal_height))
1139
      {
1140 1141
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1142 1143
      }
   }
G
Guy Schalnat 已提交
1144
#endif
1145 1146
#endif
#endif
1147
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1148 1149 1150 1151 1152 1153
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
      {
1154
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
A
Andreas Dilger 已提交
1155 1156 1157 1158
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1159
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1160 1161 1162 1163 1164 1165
   {
      png_timep mod_time;

      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1166
#ifdef PNG_TIME_RFC1123_SUPPORTED
1167
         /* We have to use png_memcpy instead of "=" because the string
1168 1169 1170
          * pointed to by png_convert_to_rfc1123() gets free'ed before
          * we use it.
          */
1171 1172 1173
         png_memcpy(tIME_string,
                    png_convert_to_rfc1123(read_ptr, mod_time),
                    png_sizeof(tIME_string));
1174

1175
         tIME_string[png_sizeof(tIME_string) - 1] = '\0';
1176 1177
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1178
      }
A
Andreas Dilger 已提交
1179 1180
   }
#endif
1181
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1182
   {
1183
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1184
      int num_trans;
1185
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1186

1187
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1188
         &trans_color))
A
Andreas Dilger 已提交
1189
      {
1190
         int sample_max = (1 << bit_depth);
1191
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1192
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1193
             (int)trans_color->gray > sample_max) ||
1194
             (color_type == PNG_COLOR_TYPE_RGB &&
1195 1196 1197
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1198
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1199
               trans_color);
A
Andreas Dilger 已提交
1200 1201 1202
      }
   }
#endif
1203
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1204 1205
   {
      png_unknown_chunkp unknowns;
1206
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1207
         &unknowns);
1208

1209 1210
      if (num_unknowns)
      {
1211
         int i;
1212 1213
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1214
         /* Copy the locations from the read_info_ptr.  The automatically
1215 1216 1217
          * generated locations in write_info_ptr are wrong because we
          * haven't written anything yet.
          */
1218
         for (i = 0; i < num_unknowns; i++)
1219 1220
           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
             unknowns[i].location);
1221 1222 1223
      }
   }
#endif
A
Andreas Dilger 已提交
1224

1225
#ifdef PNG_WRITE_SUPPORTED
1226
   pngtest_debug("Writing info struct");
1227 1228

/* If we wanted, we could write info in two steps:
1229
 * png_write_info_before_PLTE(write_ptr, write_info_ptr);
1230
 */
A
Andreas Dilger 已提交
1231
   png_write_info(write_ptr, write_info_ptr);
1232

1233
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
1234 1235
   if (user_chunk_data[0] != 0)
   {
1236
      png_byte png_sTER[5] = {115,  84,  69,  82, '\0'};
1237

1238 1239
      unsigned char
        ster_chunk_data[1];
1240

1241 1242 1243
      if (verbose)
         fprintf(STDERR, "\n stereo mode = %lu\n",
           (unsigned long)(user_chunk_data[0] - 1));
1244

1245 1246
      ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1);
      png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1);
1247
   }
1248

1249 1250
   if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
   {
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260
      png_byte png_vpAg[5] = {118, 112,  65, 103, '\0'};

      unsigned char
        vpag_chunk_data[9];

      if (verbose)
         fprintf(STDERR, " vpAg = %lu x %lu, units = %lu\n",
           (unsigned long)user_chunk_data[1],
           (unsigned long)user_chunk_data[2],
           (unsigned long)user_chunk_data[3]);
1261

1262 1263 1264 1265
      png_save_uint_32(vpag_chunk_data, user_chunk_data[1]);
      png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]);
      vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff);
      png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9);
1266 1267 1268
   }

#endif
1269
#endif
A
Andreas Dilger 已提交
1270

1271
#ifdef SINGLE_ROWBUF_ALLOC
1272
   pngtest_debug("Allocating row buffer...");
1273
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1274
      png_get_rowbytes(read_ptr, read_info_ptr));
1275

1276
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1277
#endif /* SINGLE_ROWBUF_ALLOC */
1278
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1279

1280 1281
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1282
   num_pass = png_set_interlace_handling(read_ptr);
1283
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1284
   png_set_interlace_handling(write_ptr);
1285
#  endif
1286
#else
1287
   num_pass = 1;
1288
#endif
A
Andreas Dilger 已提交
1289

1290 1291 1292 1293 1294
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1295 1296
   for (pass = 0; pass < num_pass; pass++)
   {
1297
      pngtest_debug1("Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1298 1299
      for (y = 0; y < height; y++)
      {
1300
#ifndef SINGLE_ROWBUF_ALLOC
1301
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1302 1303
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1304

1305
         pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf,
1306
            png_get_rowbytes(read_ptr, read_info_ptr));
1307

1308
#endif /* !SINGLE_ROWBUF_ALLOC */
1309
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1310 1311

#ifdef PNG_WRITE_SUPPORTED
1312 1313 1314 1315 1316
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1317
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1318 1319 1320 1321 1322
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1323 1324 1325
#endif /* PNG_WRITE_SUPPORTED */

#ifndef SINGLE_ROWBUF_ALLOC
1326
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1327
         png_free(read_ptr, row_buf);
1328
         row_buf = NULL;
1329
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1330 1331 1332
      }
   }

1333
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1334
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1335
#endif
1336
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1337
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1338 1339
#endif

1340
   pngtest_debug("Reading and writing end_info data");
1341

A
Andreas Dilger 已提交
1342
   png_read_end(read_ptr, end_info_ptr);
1343
#ifdef PNG_TEXT_SUPPORTED
1344 1345 1346 1347 1348 1349
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1350
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1351 1352 1353 1354
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1355
#ifdef PNG_tIME_SUPPORTED
1356 1357 1358 1359 1360 1361
   {
      png_timep mod_time;

      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1362
#ifdef PNG_TIME_RFC1123_SUPPORTED
1363
         /* We have to use png_memcpy instead of "=" because the string
1364 1365
            pointed to by png_convert_to_rfc1123() gets free'ed before
            we use it */
1366 1367 1368
         png_memcpy(tIME_string,
                    png_convert_to_rfc1123(read_ptr, mod_time),
                    png_sizeof(tIME_string));
1369

1370
         tIME_string[png_sizeof(tIME_string) - 1] = '\0';
1371 1372 1373 1374
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1375
#endif
1376
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1377 1378
   {
      png_unknown_chunkp unknowns;
1379
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1380
         &unknowns);
1381

1382 1383
      if (num_unknowns)
      {
1384
         int i;
1385 1386
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1387
         /* Copy the locations from the read_info_ptr.  The automatically
1388 1389 1390
          * generated locations in write_end_info_ptr are wrong because we
          * haven't written the end_info yet.
          */
1391
         for (i = 0; i < num_unknowns; i++)
1392 1393
           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
             unknowns[i].location);
1394 1395
      }
   }
1396
#endif
1397
#ifdef PNG_WRITE_SUPPORTED
1398
   png_write_end(write_ptr, write_end_info_ptr);
1399
#endif
1400

1401
#ifdef PNG_EASY_ACCESS_SUPPORTED
1402
   if (verbose)
1403 1404 1405 1406
   {
      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);
1407
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1408
         (unsigned long)iwidth, (unsigned long)iheight);
1409 1410
   }
#endif
G
Guy Schalnat 已提交
1411

1412
   pngtest_debug("Destroying data structs");
1413
#ifdef SINGLE_ROWBUF_ALLOC
1414
   pngtest_debug("destroying row_buf for read_ptr");
1415
   png_free(read_ptr, row_buf);
1416
   row_buf = NULL;
1417
#endif /* SINGLE_ROWBUF_ALLOC */
1418
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1419
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1420
#ifdef PNG_WRITE_SUPPORTED
1421
   pngtest_debug("destroying write_end_info_ptr");
1422
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1423
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1424
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1425
#endif
1426
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1427

1428 1429
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1430

1431
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1432
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1433
   {
G
Guy Schalnat 已提交
1434
      fprintf(STDERR, "Could not find file %s\n", inname);
1435
      return (1);
G
Guy Schalnat 已提交
1436 1437
   }

A
Andreas Dilger 已提交
1438
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1439
   {
G
Guy Schalnat 已提交
1440
      fprintf(STDERR, "Could not find file %s\n", outname);
1441
      FCLOSE(fpin);
1442
      return (1);
G
Guy Schalnat 已提交
1443
   }
A
Andreas Dilger 已提交
1444

1445
   for (;;)
G
Guy Schalnat 已提交
1446
   {
A
Andreas Dilger 已提交
1447
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
1448

1449 1450
         num_in = fread(inbuf, 1, 1, fpin);
         num_out = fread(outbuf, 1, 1, fpout);
G
Guy Schalnat 已提交
1451 1452 1453

      if (num_in != num_out)
      {
1454
         fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
G
Guy Schalnat 已提交
1455
                 inname, outname);
1456

1457
         if (wrote_question == 0)
1458 1459
         {
            fprintf(STDERR,
1460
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1461
              inname, PNG_ZBUF_SIZE);
1462
            fprintf(STDERR,
1463
              "\n   filtering heuristic (libpng default), compression");
1464
            fprintf(STDERR,
1465
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1466
              ZLIB_VERSION);
1467
            wrote_question = 1;
1468
         }
1469

1470 1471
         FCLOSE(fpin);
         FCLOSE(fpout);
1472
         return (0);
G
Guy Schalnat 已提交
1473 1474 1475 1476 1477
      }

      if (!num_in)
         break;

A
Andreas Dilger 已提交
1478
      if (png_memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
1479
      {
1480
         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1481

1482
         if (wrote_question == 0)
1483 1484
         {
            fprintf(STDERR,
1485
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1486
                 inname, PNG_ZBUF_SIZE);
1487
            fprintf(STDERR,
1488
              "\n   filtering heuristic (libpng default), compression");
1489
            fprintf(STDERR,
1490
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1491
              ZLIB_VERSION);
1492
            wrote_question = 1;
1493
         }
1494

1495 1496
         FCLOSE(fpin);
         FCLOSE(fpout);
1497
         return (0);
G
Guy Schalnat 已提交
1498 1499 1500
      }
   }

1501 1502
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1503

1504
   return (0);
G
Guy Schalnat 已提交
1505
}
G
Guy Schalnat 已提交
1506

1507
/* Input and output filenames */
1508
#ifdef RISCOS
1509 1510
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1511
#else
1512 1513
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1514 1515 1516 1517 1518 1519 1520 1521
#endif

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

1522
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1523
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1524
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1525
   /* Show the version of libpng used in building the library */
1526 1527
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1528
      png_get_header_version(NULL));
1529

1530
   /* Show the version of libpng used in building the application */
1531
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1532
      PNG_HEADER_VERSION_STRING);
1533 1534

   /* Do some consistency checking on the memory allocation settings, I'm
1535 1536 1537 1538
    * 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
    */
1539
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1540
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1541
#endif
1542
   /* I think the following can happen. */
1543
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1544
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1545
#endif
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557

   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)
   {
1558
      if (strcmp(argv[1], "-m") == 0)
1559
      {
1560
         multiple = 1;
1561 1562
         status_dots_requested = 0;
      }
1563

1564 1565 1566 1567 1568
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1569
         status_dots_requested = 1;
1570
      }
1571

1572 1573 1574
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1575
         status_dots_requested = 1;
1576 1577
         inname = argv[2];
      }
1578

1579
      else
1580
      {
1581
         inname = argv[1];
1582 1583
         status_dots_requested = 0;
      }
1584 1585
   }

1586 1587
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1588

1589
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1590
   {
1591 1592
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1593
        argv[0], argv[0]);
1594 1595 1596 1597
     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);
1598 1599 1600 1601 1602 1603
     exit(1);
   }

   if (multiple)
   {
      int i;
1604
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1605 1606
      int allocation_now = current_allocation;
#endif
1607
      for (i=2; i<argc; ++i)
1608
      {
1609
         int kerror;
1610
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1611
         kerror = test_one_file(argv[i], outname);
1612
         if (kerror == 0)
1613
         {
1614 1615 1616
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1617
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1618
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1619
               (unsigned long)zero_samples);
1620
#else
1621
            fprintf(STDERR, " PASS\n");
1622
#endif
1623
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1624 1625
            for (k = 0; k<256; k++)
               if (filters_used[k])
1626
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1627
                     k, (unsigned long)filters_used[k]);
1628
#endif
1629
#ifdef PNG_TIME_RFC1123_SUPPORTED
1630 1631
         if (tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n", tIME_string);
1632

1633 1634 1635
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1636

1637 1638
         else
         {
1639 1640
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1641
         }
1642
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1643 1644
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1645
               current_allocation - allocation_now);
1646

1647 1648
         if (current_allocation != 0)
         {
1649 1650 1651 1652
            memory_infop pinfo = pinformation;

            fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
               current_allocation);
1653

1654 1655
            while (pinfo != NULL)
            {
1656
               fprintf(STDERR, " %lu bytes at %x\n",
1657
                 (unsigned long)pinfo->size,
1658
                 (unsigned int)pinfo->pointer);
1659
               pinfo = pinfo->next;
1660
            }
1661
         }
1662 1663
#endif
      }
1664
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1665
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1666
            current_allocation);
1667
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1668
            maximum_allocation);
1669 1670 1671 1672
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1673
#endif
1674
   }
1675

1676 1677
   else
   {
1678
      int i;
1679
      for (i = 0; i<3; ++i)
1680
      {
1681
         int kerror;
1682
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1683 1684
         int allocation_now = current_allocation;
#endif
1685 1686 1687 1688 1689 1690
         if (i == 1)
            status_dots_requested = 1;

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

1691
         if (i == 0 || verbose == 1 || ierror != 0)
1692
            fprintf(STDERR, "\n Testing %s:", inname);
1693

1694
         kerror = test_one_file(inname, outname);
1695

1696
         if (kerror == 0)
1697
         {
1698
            if (verbose == 1 || i == 2)
1699
            {
1700
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1701
                int k;
1702
#endif
1703
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1704
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1705
                   (unsigned long)zero_samples);
1706 1707 1708
#else
                fprintf(STDERR, " PASS\n");
#endif
1709
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1710 1711
                for (k = 0; k<256; k++)
                   if (filters_used[k])
1712
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1713
                         k, (unsigned long)filters_used[k]);
1714
#endif
1715
#ifdef PNG_TIME_RFC1123_SUPPORTED
1716 1717
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1718 1719
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1720
         }
1721

1722 1723
         else
         {
1724
            if (verbose == 0 && i != 2)
1725
               fprintf(STDERR, "\n Testing %s:", inname);
1726

1727 1728
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1729
         }
1730
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1731 1732
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1733
               current_allocation - allocation_now);
1734

1735 1736
         if (current_allocation != 0)
         {
1737
             memory_infop pinfo = pinformation;
1738

1739 1740
             fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
                current_allocation);
1741

1742 1743
             while (pinfo != NULL)
             {
1744 1745
                fprintf(STDERR, " %lu bytes at %x\n",
                   (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
1746 1747 1748 1749
                pinfo = pinfo->next;
             }
          }
#endif
1750
       }
1751
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1752
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1753
          current_allocation);
1754
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1755
          maximum_allocation);
1756 1757 1758 1759
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1760
#endif
1761 1762
   }

1763 1764 1765 1766
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1767
   fprintf(STDERR, " CPU time used = %.3f seconds",
1768
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1769
   fprintf(STDERR, " (decoding %.3f,\n",
1770
      t_decode/(float)CLOCKS_PER_SEC);
1771
   fprintf(STDERR, "        encoding %.3f ,",
1772
      t_encode/(float)CLOCKS_PER_SEC);
1773
   fprintf(STDERR, " other %.3f seconds)\n\n",
1774 1775 1776
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1777
   if (ierror == 0)
1778
      fprintf(STDERR, " libpng passes test\n");
1779

1780
   else
1781
      fprintf(STDERR, " libpng FAILS test\n");
1782

1783
   return (int)(ierror != 0);
1784
}
1785

1786
/* Generate a compiler error if there is an old png.h in the search path. */
1787
typedef png_libpng_version_1_5_3beta01 Your_png_h_is_not_version_1_5_3beta01;