1 2/* pngtest.c - a simple test program to test libpng 3 * 4 * Last changed in libpng 1.4.1 [February 25, 2010] 5 * Copyright (c) 1998-2010 Glenn Randers-Pehrson 6 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) 7 * (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 * This program reads in a PNG image, writes it out again, and then 14 * compares the two files. If the files are identical, this shows that 15 * the basic chunk handling, filtering, and (de)compression code is working 16 * properly. It does not currently test all of the transforms, although 17 * it probably should. 18 * 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 * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks 23 * exist in the input file. 24 * 4) others not listed here... 25 * 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 * If a filename is given on the command-line, then this file is used 29 * for the input, rather than the default "pngtest.png". This allows 30 * testing a wide variety of files easily. You can also test a number 31 * of files at once by typing "pngtest -m file1.png file2.png ..." 32 */ 33 34#include "png.h" 35#include "pngpriv.h" 36 37# include <stdio.h> 38# include <stdlib.h> 39# define FCLOSE(file) fclose(file) 40 41#ifndef PNG_STDIO_SUPPORTED 42 typedef FILE * png_FILE_p; 43#endif 44 45/* Makes pngtest verbose so we can find problems (needs to be before png.h) */ 46#ifndef PNG_DEBUG 47# define PNG_DEBUG 0 48#endif 49 50#if !PNG_DEBUG 51# define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */ 52#endif 53 54/* Turn on CPU timing 55#define PNGTEST_TIMING 56*/ 57 58#ifndef PNG_FLOATING_POINT_SUPPORTED 59#undef PNGTEST_TIMING 60#endif 61 62#ifdef PNGTEST_TIMING 63static float t_start, t_stop, t_decode, t_encode, t_misc; 64#include <time.h> 65#endif 66 67#ifdef PNG_TIME_RFC1123_SUPPORTED 68#define PNG_tIME_STRING_LENGTH 29 69static int tIME_chunk_present = 0; 70static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; 71#endif 72 73static int verbose = 0; 74 75int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname)); 76 77#ifdef __TURBOC__ 78#include <mem.h> 79#endif 80 81/* Defined so I can write to a file on gui/windowing platforms */ 82/* #define STDERR stderr */ 83#define STDERR stdout /* For DOS */ 84 85/* In case a system header (e.g., on AIX) defined jmpbuf */ 86#ifdef jmpbuf 87# undef jmpbuf 88#endif 89 90/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ 91#ifndef png_jmpbuf 92# define png_jmpbuf(png_ptr) png_ptr->jmpbuf 93#endif 94 95/* Example of using row callbacks to make a simple progress meter */ 96static int status_pass = 1; 97static int status_dots_requested = 0; 98static int status_dots = 1; 99 100void 101read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); 102void 103read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) 104{ 105 if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) 106 return; 107 if (status_pass != pass) 108 { 109 fprintf(stdout, "\n Pass %d: ", pass); 110 status_pass = pass; 111 status_dots = 31; 112 } 113 status_dots--; 114 if (status_dots == 0) 115 { 116 fprintf(stdout, "\n "); 117 status_dots=30; 118 } 119 fprintf(stdout, "r"); 120} 121 122void 123write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); 124void 125write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) 126{ 127 if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) 128 return; 129 fprintf(stdout, "w"); 130} 131 132 133#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED 134/* Example of using user transform callback (we don't transform anything, 135 * but merely examine the row filters. We set this to 256 rather than 136 * 5 in case illegal filter values are present.) 137 */ 138static png_uint_32 filters_used[256]; 139void 140count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data); 141void 142count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) 143{ 144 if (png_ptr != NULL && row_info != NULL) 145 ++filters_used[*(data - 1)]; 146} 147#endif 148 149#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED 150/* Example of using user transform callback (we don't transform anything, 151 * but merely count the zero samples) 152 */ 153 154static png_uint_32 zero_samples; 155 156void 157count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data); 158void 159count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) 160{ 161 png_bytep dp = data; 162 if (png_ptr == NULL)return; 163 164 /* Contents of row_info: 165 * png_uint_32 width width of row 166 * png_uint_32 rowbytes number of bytes in row 167 * png_byte color_type color type of pixels 168 * png_byte bit_depth bit depth of samples 169 * png_byte channels number of channels (1-4) 170 * png_byte pixel_depth bits per pixel (depth*channels) 171 */ 172 173 /* Counts the number of zero samples (or zero pixels if color_type is 3 */ 174 175 if (row_info->color_type == 0 || row_info->color_type == 3) 176 { 177 int pos = 0; 178 png_uint_32 n, nstop; 179 for (n = 0, nstop=row_info->width; n<nstop; n++) 180 { 181 if (row_info->bit_depth == 1) 182 { 183 if (((*dp << pos++ ) & 0x80) == 0) 184 zero_samples++; 185 if (pos == 8) 186 { 187 pos = 0; 188 dp++; 189 } 190 } 191 if (row_info->bit_depth == 2) 192 { 193 if (((*dp << (pos+=2)) & 0xc0) == 0) 194 zero_samples++; 195 if (pos == 8) 196 { 197 pos = 0; 198 dp++; 199 } 200 } 201 if (row_info->bit_depth == 4) 202 { 203 if (((*dp << (pos+=4)) & 0xf0) == 0) 204 zero_samples++; 205 if (pos == 8) 206 { 207 pos = 0; 208 dp++; 209 } 210 } 211 if (row_info->bit_depth == 8) 212 if (*dp++ == 0) 213 zero_samples++; 214 if (row_info->bit_depth == 16) 215 { 216 if ((*dp | *(dp+1)) == 0) 217 zero_samples++; 218 dp+=2; 219 } 220 } 221 } 222 else /* Other color types */ 223 { 224 png_uint_32 n, nstop; 225 int channel; 226 int color_channels = row_info->channels; 227 if (row_info->color_type > 3)color_channels--; 228 229 for (n = 0, nstop=row_info->width; n<nstop; n++) 230 { 231 for (channel = 0; channel < color_channels; channel++) 232 { 233 if (row_info->bit_depth == 8) 234 if (*dp++ == 0) 235 zero_samples++; 236 if (row_info->bit_depth == 16) 237 { 238 if ((*dp | *(dp+1)) == 0) 239 zero_samples++; 240 dp+=2; 241 } 242 } 243 if (row_info->color_type > 3) 244 { 245 dp++; 246 if (row_info->bit_depth == 16) 247 dp++; 248 } 249 } 250 } 251} 252#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */ 253 254static int wrote_question = 0; 255 256#ifndef PNG_STDIO_SUPPORTED 257/* START of code to validate stdio-free compilation */ 258/* These copies of the default read/write functions come from pngrio.c and 259 * pngwio.c. They allow "don't include stdio" testing of the library. 260 * This is the function that does the actual reading of data. If you are 261 * not reading from a standard C stream, you should create a replacement 262 * read_data function and use it at run time with png_set_read_fn(), rather 263 * than changing the library. 264 */ 265 266#ifndef USE_FAR_KEYWORD 267static void 268pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) 269{ 270 png_size_t check = 0; 271 png_voidp io_ptr; 272 273 /* fread() returns 0 on error, so it is OK to store this in a png_size_t 274 * instead of an int, which is what fread() actually returns. 275 */ 276 io_ptr = png_get_io_ptr(png_ptr); 277 if (io_ptr != NULL) 278 { 279 check = fread(data, 1, length, (png_FILE_p)io_ptr); 280 } 281 282 if (check != length) 283 { 284 png_error(png_ptr, "Read Error!"); 285 } 286} 287#else 288/* This is the model-independent version. Since the standard I/O library 289 can't handle far buffers in the medium and small models, we have to copy 290 the data. 291*/ 292 293#define NEAR_BUF_SIZE 1024 294#define MIN(a,b) (a <= b ? a : b) 295 296static void 297pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) 298{ 299 png_size_t check; 300 png_byte *n_data; 301 png_FILE_p io_ptr; 302 303 /* Check if data really is near. If so, use usual code. */ 304 n_data = (png_byte *)CVT_PTR_NOCHECK(data); 305 io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); 306 if ((png_bytep)n_data == data) 307 { 308 check = fread(n_data, 1, length, io_ptr); 309 } 310 else 311 { 312 png_byte buf[NEAR_BUF_SIZE]; 313 png_size_t read, remaining, err; 314 check = 0; 315 remaining = length; 316 do 317 { 318 read = MIN(NEAR_BUF_SIZE, remaining); 319 err = fread(buf, 1, 1, io_ptr); 320 png_memcpy(data, buf, read); /* Copy far buffer to near buffer */ 321 if (err != read) 322 break; 323 else 324 check += err; 325 data += read; 326 remaining -= read; 327 } 328 while (remaining != 0); 329 } 330 if (check != length) 331 png_error(png_ptr, "read Error"); 332} 333#endif /* USE_FAR_KEYWORD */ 334 335#ifdef PNG_WRITE_FLUSH_SUPPORTED 336static void 337pngtest_flush(png_structp png_ptr) 338{ 339 /* Do nothing; fflush() is said to be just a waste of energy. */ 340 png_ptr = png_ptr; /* Stifle compiler warning */ 341} 342#endif 343 344/* This is the function that does the actual writing of data. If you are 345 * not writing to a standard C stream, you should create a replacement 346 * write_data function and use it at run time with png_set_write_fn(), rather 347 * than changing the library. 348 */ 349#ifndef USE_FAR_KEYWORD 350static void 351pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) 352{ 353 png_size_t check; 354 355 check = fwrite(data, 1, length, (png_FILE_p)png_ptr->io_ptr); 356 if (check != length) 357 { 358 png_error(png_ptr, "Write Error"); 359 } 360} 361#else 362/* This is the model-independent version. Since the standard I/O library 363 can't handle far buffers in the medium and small models, we have to copy 364 the data. 365*/ 366 367#define NEAR_BUF_SIZE 1024 368#define MIN(a,b) (a <= b ? a : b) 369 370static void 371pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) 372{ 373 png_size_t check; 374 png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ 375 png_FILE_p io_ptr; 376 377 /* Check if data really is near. If so, use usual code. */ 378 near_data = (png_byte *)CVT_PTR_NOCHECK(data); 379 io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); 380 if ((png_bytep)near_data == data) 381 { 382 check = fwrite(near_data, 1, length, io_ptr); 383 } 384 else 385 { 386 png_byte buf[NEAR_BUF_SIZE]; 387 png_size_t written, remaining, err; 388 check = 0; 389 remaining = length; 390 do 391 { 392 written = MIN(NEAR_BUF_SIZE, remaining); 393 png_memcpy(buf, data, written); /* Copy far buffer to near buffer */ 394 err = fwrite(buf, 1, written, io_ptr); 395 if (err != written) 396 break; 397 else 398 check += err; 399 data += written; 400 remaining -= written; 401 } 402 while (remaining != 0); 403 } 404 if (check != length) 405 { 406 png_error(png_ptr, "Write Error"); 407 } 408} 409#endif /* USE_FAR_KEYWORD */ 410 411/* This function is called when there is a warning, but the library thinks 412 * it can continue anyway. Replacement functions don't have to do anything 413 * here if you don't want to. In the default configuration, png_ptr is 414 * not used, but it is passed in case it may be useful. 415 */ 416static void 417pngtest_warning(png_structp png_ptr, png_const_charp message) 418{ 419 PNG_CONST char *name = "UNKNOWN (ERROR!)"; 420 char *test; 421 test = png_get_error_ptr(png_ptr); 422 if (test == NULL) 423 fprintf(STDERR, "%s: libpng warning: %s\n", name, message); 424 else 425 fprintf(STDERR, "%s: libpng warning: %s\n", test, message); 426} 427 428/* This is the default error handling function. Note that replacements for 429 * this function MUST NOT RETURN, or the program will likely crash. This 430 * function is used by default, or if the program supplies NULL for the 431 * error function pointer in png_set_error_fn(). 432 */ 433static void 434pngtest_error(png_structp png_ptr, png_const_charp message) 435{ 436 pngtest_warning(png_ptr, message); 437 /* We can return because png_error calls the default handler, which is 438 * actually OK in this case. 439 */ 440} 441#endif /* !PNG_STDIO_SUPPORTED */ 442/* END of code to validate stdio-free compilation */ 443 444/* START of code to validate memory allocation and deallocation */ 445#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG 446 447/* Allocate memory. For reasonable files, size should never exceed 448 * 64K. However, zlib may allocate more then 64K if you don't tell 449 * it not to. See zconf.h and png.h for more information. zlib does 450 * need to allocate exactly 64K, so whatever you call here must 451 * have the ability to do that. 452 * 453 * This piece of code can be compiled to validate max 64K allocations 454 * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. 455 */ 456typedef struct memory_information 457{ 458 png_alloc_size_t size; 459 png_voidp pointer; 460 struct memory_information FAR *next; 461} memory_information; 462typedef memory_information FAR *memory_infop; 463 464static memory_infop pinformation = NULL; 465static int current_allocation = 0; 466static int maximum_allocation = 0; 467static int total_allocation = 0; 468static int num_allocations = 0; 469 470png_voidp png_debug_malloc 471 PNGARG((png_structp png_ptr, png_alloc_size_t size)); 472void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); 473 474png_voidp 475png_debug_malloc(png_structp png_ptr, png_alloc_size_t size) 476{ 477 478 /* png_malloc has already tested for NULL; png_create_struct calls 479 * png_debug_malloc directly, with png_ptr == NULL which is OK 480 */ 481 482 if (size == 0) 483 return (NULL); 484 485 /* This calls the library allocator twice, once to get the requested 486 buffer and once to get a new free list entry. */ 487 { 488 /* Disable malloc_fn and free_fn */ 489 memory_infop pinfo; 490 png_set_mem_fn(png_ptr, NULL, NULL, NULL); 491 pinfo = (memory_infop)png_malloc(png_ptr, 492 png_sizeof(*pinfo)); 493 pinfo->size = size; 494 current_allocation += size; 495 total_allocation += size; 496 num_allocations ++; 497 if (current_allocation > maximum_allocation) 498 maximum_allocation = current_allocation; 499 pinfo->pointer = png_malloc(png_ptr, size); 500 /* Restore malloc_fn and free_fn */ 501 png_set_mem_fn(png_ptr, 502 NULL, png_debug_malloc, png_debug_free); 503 if (size != 0 && pinfo->pointer == NULL) 504 { 505 current_allocation -= size; 506 total_allocation -= size; 507 png_error(png_ptr, 508 "out of memory in pngtest->png_debug_malloc"); 509 } 510 pinfo->next = pinformation; 511 pinformation = pinfo; 512 /* Make sure the caller isn't assuming zeroed memory. */ 513 png_memset(pinfo->pointer, 0xdd, pinfo->size); 514 if (verbose) 515 printf("png_malloc %lu bytes at %x\n", (unsigned long)size, 516 pinfo->pointer); 517 return (png_voidp)(pinfo->pointer); 518 } 519} 520 521/* Free a pointer. It is removed from the list at the same time. */ 522void 523png_debug_free(png_structp png_ptr, png_voidp ptr) 524{ 525 if (png_ptr == NULL) 526 fprintf(STDERR, "NULL pointer to png_debug_free.\n"); 527 if (ptr == 0) 528 { 529#if 0 /* This happens all the time. */ 530 fprintf(STDERR, "WARNING: freeing NULL pointer\n"); 531#endif 532 return; 533 } 534 535 /* Unlink the element from the list. */ 536 { 537 memory_infop FAR *ppinfo = &pinformation; 538 for (;;) 539 { 540 memory_infop pinfo = *ppinfo; 541 if (pinfo->pointer == ptr) 542 { 543 *ppinfo = pinfo->next; 544 current_allocation -= pinfo->size; 545 if (current_allocation < 0) 546 fprintf(STDERR, "Duplicate free of memory\n"); 547 /* We must free the list element too, but first kill 548 the memory that is to be freed. */ 549 png_memset(ptr, 0x55, pinfo->size); 550 png_free_default(png_ptr, pinfo); 551 pinfo = NULL; 552 break; 553 } 554 if (pinfo->next == NULL) 555 { 556 fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr); 557 break; 558 } 559 ppinfo = &pinfo->next; 560 } 561 } 562 563 /* Finally free the data. */ 564 if (verbose) 565 printf("Freeing %x\n", ptr); 566 png_free_default(png_ptr, ptr); 567 ptr = NULL; 568} 569#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ 570/* END of code to test memory allocation/deallocation */ 571 572 573/* Demonstration of user chunk support of the sTER and vpAg chunks */ 574#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED 575 576/* (sTER is a public chunk not yet known by libpng. vpAg is a private 577chunk used in ImageMagick to store "virtual page" size). */ 578 579static png_uint_32 user_chunk_data[4]; 580 581 /* 0: sTER mode + 1 582 * 1: vpAg width 583 * 2: vpAg height 584 * 3: vpAg units 585 */ 586 587static int read_user_chunk_callback(png_struct *png_ptr, 588 png_unknown_chunkp chunk) 589{ 590 png_uint_32 591 *my_user_chunk_data; 592 593 /* Return one of the following: 594 * return (-n); chunk had an error 595 * return (0); did not recognize 596 * return (n); success 597 * 598 * The unknown chunk structure contains the chunk data: 599 * png_byte name[5]; 600 * png_byte *data; 601 * png_size_t size; 602 * 603 * Note that libpng has already taken care of the CRC handling. 604 */ 605 606 if (chunk->name[0] == 115 && chunk->name[1] == 84 && /* s T */ 607 chunk->name[2] == 69 && chunk->name[3] == 82) /* E R */ 608 { 609 /* Found sTER chunk */ 610 if (chunk->size != 1) 611 return (-1); /* Error return */ 612 if (chunk->data[0] != 0 && chunk->data[0] != 1) 613 return (-1); /* Invalid mode */ 614 my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); 615 my_user_chunk_data[0]=chunk->data[0]+1; 616 return (1); 617 } 618 619 if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */ 620 chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */ 621 return (0); /* Did not recognize */ 622 623 /* Found ImageMagick vpAg chunk */ 624 625 if (chunk->size != 9) 626 return (-1); /* Error return */ 627 628 my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); 629 630 my_user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data); 631 my_user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4); 632 my_user_chunk_data[3]=(png_uint_32)chunk->data[8]; 633 634 return (1); 635 636} 637#endif 638/* END of code to demonstrate user chunk support */ 639 640/* Test one file */ 641int 642test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) 643{ 644 static png_FILE_p fpin; 645 static png_FILE_p fpout; /* "static" prevents setjmp corruption */ 646 png_structp read_ptr; 647 png_infop read_info_ptr, end_info_ptr; 648#ifdef PNG_WRITE_SUPPORTED 649 png_structp write_ptr; 650 png_infop write_info_ptr; 651 png_infop write_end_info_ptr; 652#else 653 png_structp write_ptr = NULL; 654 png_infop write_info_ptr = NULL; 655 png_infop write_end_info_ptr = NULL; 656#endif 657 png_bytep row_buf; 658 png_uint_32 y; 659 png_uint_32 width, height; 660 int num_pass, pass; 661 int bit_depth, color_type; 662#ifdef PNG_SETJMP_SUPPORTED 663#ifdef USE_FAR_KEYWORD 664 jmp_buf jmpbuf; 665#endif 666#endif 667 668 char inbuf[256], outbuf[256]; 669 670 row_buf = NULL; 671 672 if ((fpin = fopen(inname, "rb")) == NULL) 673 { 674 fprintf(STDERR, "Could not find input file %s\n", inname); 675 return (1); 676 } 677 678 if ((fpout = fopen(outname, "wb")) == NULL) 679 { 680 fprintf(STDERR, "Could not open output file %s\n", outname); 681 FCLOSE(fpin); 682 return (1); 683 } 684 685 png_debug(0, "Allocating read and write structures"); 686#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG 687 read_ptr = 688 png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, 689 NULL, NULL, NULL, 690 (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); 691#else 692 read_ptr = 693 png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 694#endif 695#ifndef PNG_STDIO_SUPPORTED 696 png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, 697 pngtest_warning); 698#endif 699 700#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED 701 user_chunk_data[0] = 0; 702 user_chunk_data[1] = 0; 703 user_chunk_data[2] = 0; 704 user_chunk_data[3] = 0; 705 png_set_read_user_chunk_fn(read_ptr, user_chunk_data, 706 read_user_chunk_callback); 707 708#endif 709#ifdef PNG_WRITE_SUPPORTED 710#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG 711 write_ptr = 712 png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, 713 NULL, NULL, NULL, png_debug_malloc, png_debug_free); 714#else 715 write_ptr = 716 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 717#endif 718#ifndef PNG_STDIO_SUPPORTED 719 png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, 720 pngtest_warning); 721#endif 722#endif 723 png_debug(0, "Allocating read_info, write_info and end_info structures"); 724 read_info_ptr = png_create_info_struct(read_ptr); 725 end_info_ptr = png_create_info_struct(read_ptr); 726#ifdef PNG_WRITE_SUPPORTED 727 write_info_ptr = png_create_info_struct(write_ptr); 728 write_end_info_ptr = png_create_info_struct(write_ptr); 729#endif 730 731#ifdef PNG_SETJMP_SUPPORTED 732 png_debug(0, "Setting jmpbuf for read struct"); 733#ifdef USE_FAR_KEYWORD 734 if (setjmp(jmpbuf)) 735#else 736 if (setjmp(png_jmpbuf(read_ptr))) 737#endif 738 { 739 fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); 740 png_free(read_ptr, row_buf); 741 row_buf = NULL; 742 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); 743#ifdef PNG_WRITE_SUPPORTED 744 png_destroy_info_struct(write_ptr, &write_end_info_ptr); 745 png_destroy_write_struct(&write_ptr, &write_info_ptr); 746#endif 747 FCLOSE(fpin); 748 FCLOSE(fpout); 749 return (1); 750 } 751#ifdef USE_FAR_KEYWORD 752 png_memcpy(png_jmpbuf(read_ptr), jmpbuf, png_sizeof(jmp_buf)); 753#endif 754 755#ifdef PNG_WRITE_SUPPORTED 756 png_debug(0, "Setting jmpbuf for write struct"); 757#ifdef USE_FAR_KEYWORD 758 if (setjmp(jmpbuf)) 759#else 760 if (setjmp(png_jmpbuf(write_ptr))) 761#endif 762 { 763 fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); 764 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); 765 png_destroy_info_struct(write_ptr, &write_end_info_ptr); 766#ifdef PNG_WRITE_SUPPORTED 767 png_destroy_write_struct(&write_ptr, &write_info_ptr); 768#endif 769 FCLOSE(fpin); 770 FCLOSE(fpout); 771 return (1); 772 } 773#ifdef USE_FAR_KEYWORD 774 png_memcpy(png_jmpbuf(write_ptr), jmpbuf, png_sizeof(jmp_buf)); 775#endif 776#endif 777#endif 778 779 png_debug(0, "Initializing input and output streams"); 780#ifdef PNG_STDIO_SUPPORTED 781 png_init_io(read_ptr, fpin); 782# ifdef PNG_WRITE_SUPPORTED 783 png_init_io(write_ptr, fpout); 784# endif 785#else 786 png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); 787# ifdef PNG_WRITE_SUPPORTED 788 png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, 789# ifdef PNG_WRITE_FLUSH_SUPPORTED 790 pngtest_flush); 791# else 792 NULL); 793# endif 794# endif 795#endif 796 if (status_dots_requested == 1) 797 { 798#ifdef PNG_WRITE_SUPPORTED 799 png_set_write_status_fn(write_ptr, write_row_callback); 800#endif 801 png_set_read_status_fn(read_ptr, read_row_callback); 802 } 803 else 804 { 805#ifdef PNG_WRITE_SUPPORTED 806 png_set_write_status_fn(write_ptr, NULL); 807#endif 808 png_set_read_status_fn(read_ptr, NULL); 809 } 810 811#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED 812 { 813 int i; 814 for (i = 0; i<256; i++) 815 filters_used[i] = 0; 816 png_set_read_user_transform_fn(read_ptr, count_filters); 817 } 818#endif 819#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED 820 zero_samples = 0; 821 png_set_write_user_transform_fn(write_ptr, count_zero_samples); 822#endif 823 824#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 825# ifndef PNG_HANDLE_CHUNK_ALWAYS 826# define PNG_HANDLE_CHUNK_ALWAYS 3 827# endif 828 png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, 829 NULL, 0); 830#endif 831#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 832# ifndef PNG_HANDLE_CHUNK_IF_SAFE 833# define PNG_HANDLE_CHUNK_IF_SAFE 2 834# endif 835 png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, 836 NULL, 0); 837#endif 838 839 png_debug(0, "Reading info struct"); 840 png_read_info(read_ptr, read_info_ptr); 841 842 png_debug(0, "Transferring info struct"); 843 { 844 int interlace_type, compression_type, filter_type; 845 846 if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, 847 &color_type, &interlace_type, &compression_type, &filter_type)) 848 { 849 png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, 850#ifdef PNG_WRITE_INTERLACING_SUPPORTED 851 color_type, interlace_type, compression_type, filter_type); 852#else 853 color_type, PNG_INTERLACE_NONE, compression_type, filter_type); 854#endif 855 } 856 } 857#ifdef PNG_FIXED_POINT_SUPPORTED 858#ifdef PNG_cHRM_SUPPORTED 859 { 860 png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, 861 blue_y; 862 if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, 863 &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) 864 { 865 png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, 866 red_y, green_x, green_y, blue_x, blue_y); 867 } 868 } 869#endif 870#ifdef PNG_gAMA_SUPPORTED 871 { 872 png_fixed_point gamma; 873 874 if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) 875 png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); 876 } 877#endif 878#else /* Use floating point versions */ 879#ifdef PNG_FLOATING_POINT_SUPPORTED 880#ifdef PNG_cHRM_SUPPORTED 881 { 882 double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, 883 blue_y; 884 if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, 885 &red_y, &green_x, &green_y, &blue_x, &blue_y)) 886 { 887 png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, 888 red_y, green_x, green_y, blue_x, blue_y); 889 } 890 } 891#endif 892#ifdef PNG_gAMA_SUPPORTED 893 { 894 double gamma; 895 896 if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) 897 png_set_gAMA(write_ptr, write_info_ptr, gamma); 898 } 899#endif 900#endif /* Floating point */ 901#endif /* Fixed point */ 902#ifdef PNG_iCCP_SUPPORTED 903 { 904 png_charp name; 905 png_charp profile; 906 png_uint_32 proflen; 907 int compression_type; 908 909 if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, 910 &profile, &proflen)) 911 { 912 png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, 913 profile, proflen); 914 } 915 } 916#endif 917#ifdef PNG_sRGB_SUPPORTED 918 { 919 int intent; 920 921 if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) 922 png_set_sRGB(write_ptr, write_info_ptr, intent); 923 } 924#endif 925 { 926 png_colorp palette; 927 int num_palette; 928 929 if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) 930 png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); 931 } 932#ifdef PNG_bKGD_SUPPORTED 933 { 934 png_color_16p background; 935 936 if (png_get_bKGD(read_ptr, read_info_ptr, &background)) 937 { 938 png_set_bKGD(write_ptr, write_info_ptr, background); 939 } 940 } 941#endif 942#ifdef PNG_hIST_SUPPORTED 943 { 944 png_uint_16p hist; 945 946 if (png_get_hIST(read_ptr, read_info_ptr, &hist)) 947 png_set_hIST(write_ptr, write_info_ptr, hist); 948 } 949#endif 950#ifdef PNG_oFFs_SUPPORTED 951 { 952 png_int_32 offset_x, offset_y; 953 int unit_type; 954 955 if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, 956 &unit_type)) 957 { 958 png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); 959 } 960 } 961#endif 962#ifdef PNG_pCAL_SUPPORTED 963 { 964 png_charp purpose, units; 965 png_charpp params; 966 png_int_32 X0, X1; 967 int type, nparams; 968 969 if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, 970 &nparams, &units, ¶ms)) 971 { 972 png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, 973 nparams, units, params); 974 } 975 } 976#endif 977#ifdef PNG_pHYs_SUPPORTED 978 { 979 png_uint_32 res_x, res_y; 980 int unit_type; 981 982 if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) 983 png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); 984 } 985#endif 986#ifdef PNG_sBIT_SUPPORTED 987 { 988 png_color_8p sig_bit; 989 990 if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) 991 png_set_sBIT(write_ptr, write_info_ptr, sig_bit); 992 } 993#endif 994#ifdef PNG_sCAL_SUPPORTED 995#ifdef PNG_FLOATING_POINT_SUPPORTED 996 { 997 int unit; 998 double scal_width, scal_height; 999 1000 if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, 1001 &scal_height)) 1002 { 1003 png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); 1004 } 1005 } 1006#else 1007#ifdef PNG_FIXED_POINT_SUPPORTED 1008 { 1009 int unit; 1010 png_charp scal_width, scal_height; 1011 1012 if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, 1013 &scal_height)) 1014 { 1015 png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, 1016 scal_height); 1017 } 1018 } 1019#endif 1020#endif 1021#endif 1022#ifdef PNG_TEXT_SUPPORTED 1023 { 1024 png_textp text_ptr; 1025 int num_text; 1026 1027 if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) 1028 { 1029 png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text); 1030 png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); 1031 } 1032 } 1033#endif 1034#ifdef PNG_tIME_SUPPORTED 1035 { 1036 png_timep mod_time; 1037 1038 if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) 1039 { 1040 png_set_tIME(write_ptr, write_info_ptr, mod_time); 1041#ifdef PNG_TIME_RFC1123_SUPPORTED 1042 /* We have to use png_memcpy instead of "=" because the string 1043 * pointed to by png_convert_to_rfc1123() gets free'ed before 1044 * we use it. 1045 */ 1046 png_memcpy(tIME_string, 1047 png_convert_to_rfc1123(read_ptr, mod_time), 1048 png_sizeof(tIME_string)); 1049 tIME_string[png_sizeof(tIME_string) - 1] = '\0'; 1050 tIME_chunk_present++; 1051#endif /* PNG_TIME_RFC1123_SUPPORTED */ 1052 } 1053 } 1054#endif 1055#ifdef PNG_tRNS_SUPPORTED 1056 { 1057 png_bytep trans_alpha; 1058 int num_trans; 1059 png_color_16p trans_color; 1060 1061 if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans, 1062 &trans_color)) 1063 { 1064 int sample_max = (1 << bit_depth); 1065 /* libpng doesn't reject a tRNS chunk with out-of-range samples */ 1066 if (!((color_type == PNG_COLOR_TYPE_GRAY && 1067 (int)trans_color->gray > sample_max) || 1068 (color_type == PNG_COLOR_TYPE_RGB && 1069 ((int)trans_color->red > sample_max || 1070 (int)trans_color->green > sample_max || 1071 (int)trans_color->blue > sample_max)))) 1072 png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans, 1073 trans_color); 1074 } 1075 } 1076#endif 1077#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 1078 { 1079 png_unknown_chunkp unknowns; 1080 int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, 1081 &unknowns); 1082 if (num_unknowns) 1083 { 1084 png_size_t i; 1085 png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, 1086 num_unknowns); 1087 /* Copy the locations from the read_info_ptr. The automatically 1088 * generated locations in write_info_ptr are wrong because we 1089 * haven't written anything yet. 1090 */ 1091 for (i = 0; i < (png_size_t)num_unknowns; i++) 1092 png_set_unknown_chunk_location(write_ptr, write_info_ptr, i, 1093 unknowns[i].location); 1094 } 1095 } 1096#endif 1097 1098#ifdef PNG_WRITE_SUPPORTED 1099 png_debug(0, "Writing info struct"); 1100 1101/* If we wanted, we could write info in two steps: 1102 * png_write_info_before_PLTE(write_ptr, write_info_ptr); 1103 */ 1104 png_write_info(write_ptr, write_info_ptr); 1105 1106#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED 1107 if (user_chunk_data[0] != 0) 1108 { 1109 png_byte png_sTER[5] = {115, 84, 69, 82, '\0'}; 1110 1111 unsigned char 1112 ster_chunk_data[1]; 1113 1114 if (verbose) 1115 fprintf(STDERR, "\n stereo mode = %lu\n", 1116 (unsigned long)(user_chunk_data[0] - 1)); 1117 ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1); 1118 png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1); 1119 } 1120 if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0) 1121 { 1122 png_byte png_vpAg[5] = {118, 112, 65, 103, '\0'}; 1123 1124 unsigned char 1125 vpag_chunk_data[9]; 1126 1127 if (verbose) 1128 fprintf(STDERR, " vpAg = %lu x %lu, units = %lu\n", 1129 (unsigned long)user_chunk_data[1], 1130 (unsigned long)user_chunk_data[2], 1131 (unsigned long)user_chunk_data[3]); 1132 png_save_uint_32(vpag_chunk_data, user_chunk_data[1]); 1133 png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]); 1134 vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff); 1135 png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9); 1136 } 1137 1138#endif 1139#endif 1140 1141#ifdef SINGLE_ROWBUF_ALLOC 1142 png_debug(0, "Allocating row buffer..."); 1143 row_buf = (png_bytep)png_malloc(read_ptr, 1144 png_get_rowbytes(read_ptr, read_info_ptr)); 1145 png_debug1(0, "0x%08lx", (unsigned long)row_buf); 1146#endif /* SINGLE_ROWBUF_ALLOC */ 1147 png_debug(0, "Writing row data"); 1148 1149#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ 1150 defined(PNG_WRITE_INTERLACING_SUPPORTED) 1151 num_pass = png_set_interlace_handling(read_ptr); 1152# ifdef PNG_WRITE_SUPPORTED 1153 png_set_interlace_handling(write_ptr); 1154# endif 1155#else 1156 num_pass = 1; 1157#endif 1158 1159#ifdef PNGTEST_TIMING 1160 t_stop = (float)clock(); 1161 t_misc += (t_stop - t_start); 1162 t_start = t_stop; 1163#endif 1164 for (pass = 0; pass < num_pass; pass++) 1165 { 1166 png_debug1(0, "Writing row data for pass %d", pass); 1167 for (y = 0; y < height; y++) 1168 { 1169#ifndef SINGLE_ROWBUF_ALLOC 1170 png_debug2(0, "Allocating row buffer (pass %d, y = %ld)...", pass, y); 1171 row_buf = (png_bytep)png_malloc(read_ptr, 1172 png_get_rowbytes(read_ptr, read_info_ptr)); 1173 png_debug2(0, "0x%08lx (%ld bytes)", (unsigned long)row_buf, 1174 png_get_rowbytes(read_ptr, read_info_ptr)); 1175#endif /* !SINGLE_ROWBUF_ALLOC */ 1176 png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1); 1177 1178#ifdef PNG_WRITE_SUPPORTED 1179#ifdef PNGTEST_TIMING 1180 t_stop = (float)clock(); 1181 t_decode += (t_stop - t_start); 1182 t_start = t_stop; 1183#endif 1184 png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); 1185#ifdef PNGTEST_TIMING 1186 t_stop = (float)clock(); 1187 t_encode += (t_stop - t_start); 1188 t_start = t_stop; 1189#endif 1190#endif /* PNG_WRITE_SUPPORTED */ 1191 1192#ifndef SINGLE_ROWBUF_ALLOC 1193 png_debug2(0, "Freeing row buffer (pass %d, y = %ld)", pass, y); 1194 png_free(read_ptr, row_buf); 1195 row_buf = NULL; 1196#endif /* !SINGLE_ROWBUF_ALLOC */ 1197 } 1198 } 1199 1200#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 1201 png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); 1202#endif 1203#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 1204 png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); 1205#endif 1206 1207 png_debug(0, "Reading and writing end_info data"); 1208 1209 png_read_end(read_ptr, end_info_ptr); 1210#ifdef PNG_TEXT_SUPPORTED 1211 { 1212 png_textp text_ptr; 1213 int num_text; 1214 1215 if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0) 1216 { 1217 png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text); 1218 png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); 1219 } 1220 } 1221#endif 1222#ifdef PNG_tIME_SUPPORTED 1223 { 1224 png_timep mod_time; 1225 1226 if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) 1227 { 1228 png_set_tIME(write_ptr, write_end_info_ptr, mod_time); 1229#ifdef PNG_TIME_RFC1123_SUPPORTED 1230 /* We have to use png_memcpy instead of "=" because the string 1231 pointed to by png_convert_to_rfc1123() gets free'ed before 1232 we use it */ 1233 png_memcpy(tIME_string, 1234 png_convert_to_rfc1123(read_ptr, mod_time), 1235 png_sizeof(tIME_string)); 1236 tIME_string[png_sizeof(tIME_string) - 1] = '\0'; 1237 tIME_chunk_present++; 1238#endif /* PNG_TIME_RFC1123_SUPPORTED */ 1239 } 1240 } 1241#endif 1242#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 1243 { 1244 png_unknown_chunkp unknowns; 1245 int num_unknowns; 1246 num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr, 1247 &unknowns); 1248 if (num_unknowns) 1249 { 1250 png_size_t i; 1251 png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, 1252 num_unknowns); 1253 /* Copy the locations from the read_info_ptr. The automatically 1254 * generated locations in write_end_info_ptr are wrong because we 1255 * haven't written the end_info yet. 1256 */ 1257 for (i = 0; i < (png_size_t)num_unknowns; i++) 1258 png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i, 1259 unknowns[i].location); 1260 } 1261 } 1262#endif 1263#ifdef PNG_WRITE_SUPPORTED 1264 png_write_end(write_ptr, write_end_info_ptr); 1265#endif 1266 1267#ifdef PNG_EASY_ACCESS_SUPPORTED 1268 if (verbose) 1269 { 1270 png_uint_32 iwidth, iheight; 1271 iwidth = png_get_image_width(write_ptr, write_info_ptr); 1272 iheight = png_get_image_height(write_ptr, write_info_ptr); 1273 fprintf(STDERR, "\n Image width = %lu, height = %lu\n", 1274 (unsigned long)iwidth, (unsigned long)iheight); 1275 } 1276#endif 1277 1278 png_debug(0, "Destroying data structs"); 1279#ifdef SINGLE_ROWBUF_ALLOC 1280 png_debug(1, "destroying row_buf for read_ptr"); 1281 png_free(read_ptr, row_buf); 1282 row_buf = NULL; 1283#endif /* SINGLE_ROWBUF_ALLOC */ 1284 png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr"); 1285 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); 1286#ifdef PNG_WRITE_SUPPORTED 1287 png_debug(1, "destroying write_end_info_ptr"); 1288 png_destroy_info_struct(write_ptr, &write_end_info_ptr); 1289 png_debug(1, "destroying write_ptr, write_info_ptr"); 1290 png_destroy_write_struct(&write_ptr, &write_info_ptr); 1291#endif 1292 png_debug(0, "Destruction complete."); 1293 1294 FCLOSE(fpin); 1295 FCLOSE(fpout); 1296 1297 png_debug(0, "Opening files for comparison"); 1298 if ((fpin = fopen(inname, "rb")) == NULL) 1299 { 1300 fprintf(STDERR, "Could not find file %s\n", inname); 1301 return (1); 1302 } 1303 1304 if ((fpout = fopen(outname, "rb")) == NULL) 1305 { 1306 fprintf(STDERR, "Could not find file %s\n", outname); 1307 FCLOSE(fpin); 1308 return (1); 1309 } 1310 1311 for (;;) 1312 { 1313 png_size_t num_in, num_out; 1314 1315 num_in = fread(inbuf, 1, 1, fpin); 1316 num_out = fread(outbuf, 1, 1, fpout); 1317 1318 if (num_in != num_out) 1319 { 1320 fprintf(STDERR, "\nFiles %s and %s are of a different size\n", 1321 inname, outname); 1322 if (wrote_question == 0) 1323 { 1324 fprintf(STDERR, 1325 " Was %s written with the same maximum IDAT chunk size (%d bytes),", 1326 inname, PNG_ZBUF_SIZE); 1327 fprintf(STDERR, 1328 "\n filtering heuristic (libpng default), compression"); 1329 fprintf(STDERR, 1330 " level (zlib default),\n and zlib version (%s)?\n\n", 1331 ZLIB_VERSION); 1332 wrote_question = 1; 1333 } 1334 FCLOSE(fpin); 1335 FCLOSE(fpout); 1336 return (0); 1337 } 1338 1339 if (!num_in) 1340 break; 1341 1342 if (png_memcmp(inbuf, outbuf, num_in)) 1343 { 1344 fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); 1345 if (wrote_question == 0) 1346 { 1347 fprintf(STDERR, 1348 " Was %s written with the same maximum IDAT chunk size (%d bytes),", 1349 inname, PNG_ZBUF_SIZE); 1350 fprintf(STDERR, 1351 "\n filtering heuristic (libpng default), compression"); 1352 fprintf(STDERR, 1353 " level (zlib default),\n and zlib version (%s)?\n\n", 1354 ZLIB_VERSION); 1355 wrote_question = 1; 1356 } 1357 FCLOSE(fpin); 1358 FCLOSE(fpout); 1359 return (0); 1360 } 1361 } 1362 1363 FCLOSE(fpin); 1364 FCLOSE(fpout); 1365 1366 return (0); 1367} 1368 1369/* Input and output filenames */ 1370#ifdef RISCOS 1371static PNG_CONST char *inname = "pngtest/png"; 1372static PNG_CONST char *outname = "pngout/png"; 1373#else 1374static PNG_CONST char *inname = "pngtest.png"; 1375static PNG_CONST char *outname = "pngout.png"; 1376#endif 1377 1378int 1379main(int argc, char *argv[]) 1380{ 1381 int multiple = 0; 1382 int ierror = 0; 1383 1384 fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); 1385 fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); 1386 fprintf(STDERR, "%s", png_get_copyright(NULL)); 1387 /* Show the version of libpng used in building the library */ 1388 fprintf(STDERR, " library (%lu):%s", 1389 (unsigned long)png_access_version_number(), 1390 png_get_header_version(NULL)); 1391 /* Show the version of libpng used in building the application */ 1392 fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, 1393 PNG_HEADER_VERSION_STRING); 1394 fprintf(STDERR, " sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n", 1395 (long)png_sizeof(png_struct), (long)png_sizeof(png_info)); 1396 1397 /* Do some consistency checking on the memory allocation settings, I'm 1398 * not sure this matters, but it is nice to know, the first of these 1399 * tests should be impossible because of the way the macros are set 1400 * in pngconf.h 1401 */ 1402#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) 1403 fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n"); 1404#endif 1405 /* I think the following can happen. */ 1406#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K) 1407 fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); 1408#endif 1409 1410 if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) 1411 { 1412 fprintf(STDERR, 1413 "Warning: versions are different between png.h and png.c\n"); 1414 fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); 1415 fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); 1416 ++ierror; 1417 } 1418 1419 if (argc > 1) 1420 { 1421 if (strcmp(argv[1], "-m") == 0) 1422 { 1423 multiple = 1; 1424 status_dots_requested = 0; 1425 } 1426 else if (strcmp(argv[1], "-mv") == 0 || 1427 strcmp(argv[1], "-vm") == 0 ) 1428 { 1429 multiple = 1; 1430 verbose = 1; 1431 status_dots_requested = 1; 1432 } 1433 else if (strcmp(argv[1], "-v") == 0) 1434 { 1435 verbose = 1; 1436 status_dots_requested = 1; 1437 inname = argv[2]; 1438 } 1439 else 1440 { 1441 inname = argv[1]; 1442 status_dots_requested = 0; 1443 } 1444 } 1445 1446 if (!multiple && argc == 3 + verbose) 1447 outname = argv[2 + verbose]; 1448 1449 if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2)) 1450 { 1451 fprintf(STDERR, 1452 "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", 1453 argv[0], argv[0]); 1454 fprintf(STDERR, 1455 " reads/writes one PNG file (without -m) or multiple files (-m)\n"); 1456 fprintf(STDERR, 1457 " with -m %s is used as a temporary file\n", outname); 1458 exit(1); 1459 } 1460 1461 if (multiple) 1462 { 1463 int i; 1464#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG 1465 int allocation_now = current_allocation; 1466#endif 1467 for (i=2; i<argc; ++i) 1468 { 1469 int kerror; 1470 fprintf(STDERR, "\n Testing %s:", argv[i]); 1471 kerror = test_one_file(argv[i], outname); 1472 if (kerror == 0) 1473 { 1474#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED 1475 int k; 1476#endif 1477#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED 1478 fprintf(STDERR, "\n PASS (%lu zero samples)\n", 1479 (unsigned long)zero_samples); 1480#else 1481 fprintf(STDERR, " PASS\n"); 1482#endif 1483#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED 1484 for (k = 0; k<256; k++) 1485 if (filters_used[k]) 1486 fprintf(STDERR, " Filter %d was used %lu times\n", 1487 k, (unsigned long)filters_used[k]); 1488#endif 1489#ifdef PNG_TIME_RFC1123_SUPPORTED 1490 if (tIME_chunk_present != 0) 1491 fprintf(STDERR, " tIME = %s\n", tIME_string); 1492 tIME_chunk_present = 0; 1493#endif /* PNG_TIME_RFC1123_SUPPORTED */ 1494 } 1495 else 1496 { 1497 fprintf(STDERR, " FAIL\n"); 1498 ierror += kerror; 1499 } 1500#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG 1501 if (allocation_now != current_allocation) 1502 fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", 1503 current_allocation - allocation_now); 1504 if (current_allocation != 0) 1505 { 1506 memory_infop pinfo = pinformation; 1507 1508 fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", 1509 current_allocation); 1510 while (pinfo != NULL) 1511 { 1512 fprintf(STDERR, " %lu bytes at %x\n", 1513 (unsigned long)pinfo->size, 1514 (unsigned int) pinfo->pointer); 1515 pinfo = pinfo->next; 1516 } 1517 } 1518#endif 1519 } 1520#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG 1521 fprintf(STDERR, " Current memory allocation: %10d bytes\n", 1522 current_allocation); 1523 fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", 1524 maximum_allocation); 1525 fprintf(STDERR, " Total memory allocation: %10d bytes\n", 1526 total_allocation); 1527 fprintf(STDERR, " Number of allocations: %10d\n", 1528 num_allocations); 1529#endif 1530 } 1531 else 1532 { 1533 int i; 1534 for (i = 0; i<3; ++i) 1535 { 1536 int kerror; 1537#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG 1538 int allocation_now = current_allocation; 1539#endif 1540 if (i == 1) status_dots_requested = 1; 1541 else if (verbose == 0)status_dots_requested = 0; 1542 if (i == 0 || verbose == 1 || ierror != 0) 1543 fprintf(STDERR, "\n Testing %s:", inname); 1544 kerror = test_one_file(inname, outname); 1545 if (kerror == 0) 1546 { 1547 if (verbose == 1 || i == 2) 1548 { 1549#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED 1550 int k; 1551#endif 1552#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED 1553 fprintf(STDERR, "\n PASS (%lu zero samples)\n", 1554 (unsigned long)zero_samples); 1555#else 1556 fprintf(STDERR, " PASS\n"); 1557#endif 1558#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED 1559 for (k = 0; k<256; k++) 1560 if (filters_used[k]) 1561 fprintf(STDERR, " Filter %d was used %lu times\n", 1562 k, (unsigned long)filters_used[k]); 1563#endif 1564#ifdef PNG_TIME_RFC1123_SUPPORTED 1565 if (tIME_chunk_present != 0) 1566 fprintf(STDERR, " tIME = %s\n", tIME_string); 1567#endif /* PNG_TIME_RFC1123_SUPPORTED */ 1568 } 1569 } 1570 else 1571 { 1572 if (verbose == 0 && i != 2) 1573 fprintf(STDERR, "\n Testing %s:", inname); 1574 fprintf(STDERR, " FAIL\n"); 1575 ierror += kerror; 1576 } 1577#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG 1578 if (allocation_now != current_allocation) 1579 fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", 1580 current_allocation - allocation_now); 1581 if (current_allocation != 0) 1582 { 1583 memory_infop pinfo = pinformation; 1584 1585 fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", 1586 current_allocation); 1587 while (pinfo != NULL) 1588 { 1589 fprintf(STDERR, " %lu bytes at %x\n", 1590 (unsigned long)pinfo->size, (unsigned int)pinfo->pointer); 1591 pinfo = pinfo->next; 1592 } 1593 } 1594#endif 1595 } 1596#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG 1597 fprintf(STDERR, " Current memory allocation: %10d bytes\n", 1598 current_allocation); 1599 fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", 1600 maximum_allocation); 1601 fprintf(STDERR, " Total memory allocation: %10d bytes\n", 1602 total_allocation); 1603 fprintf(STDERR, " Number of allocations: %10d\n", 1604 num_allocations); 1605#endif 1606 } 1607 1608#ifdef PNGTEST_TIMING 1609 t_stop = (float)clock(); 1610 t_misc += (t_stop - t_start); 1611 t_start = t_stop; 1612 fprintf(STDERR, " CPU time used = %.3f seconds", 1613 (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); 1614 fprintf(STDERR, " (decoding %.3f,\n", 1615 t_decode/(float)CLOCKS_PER_SEC); 1616 fprintf(STDERR, " encoding %.3f ,", 1617 t_encode/(float)CLOCKS_PER_SEC); 1618 fprintf(STDERR, " other %.3f seconds)\n\n", 1619 t_misc/(float)CLOCKS_PER_SEC); 1620#endif 1621 1622 if (ierror == 0) 1623 fprintf(STDERR, " libpng passes test\n"); 1624 else 1625 fprintf(STDERR, " libpng FAILS test\n"); 1626 return (int)(ierror != 0); 1627} 1628 1629/* Generate a compiler error if there is an old png.h in the search path. */ 1630typedef version_1_4_3 your_png_h_is_not_version_1_4_3; 1631