1 /* pngimage.c 2 * 3 * Copyright (c) 2015,2016 John Cunningham Bowler 4 * 5 * Last changed in libpng 1.6.24 [August 4, 2016] 6 * 7 * This code is released under the libpng license. 8 * For conditions of distribution and use, see the disclaimer 9 * and license in png.h 10 * 11 * Test the png_read_png and png_write_png interfaces. Given a PNG file load it 12 * using png_read_png and then write with png_write_png. Test all possible 13 * transforms. 14 */ 15 #include <stdarg.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <errno.h> 19 #include <stdio.h> 20 #include <assert.h> 21 22 #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) 23 # include <config.h> 24 #endif 25 26 /* Define the following to use this test against your installed libpng, rather 27 * than the one being built here: 28 */ 29 #ifdef PNG_FREESTANDING_TESTS 30 # include <png.h> 31 #else 32 # include "../../png.h" 33 #endif 34 35 #ifndef PNG_SETJMP_SUPPORTED 36 # include <setjmp.h> /* because png.h did *not* include this */ 37 #endif 38 39 /* 1.6.1 added support for the configure test harness, which uses 77 to indicate 40 * a skipped test, in earlier versions we need to succeed on a skipped test, so: 41 */ 42 #if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H) 43 # define SKIP 77 44 #else 45 # define SKIP 0 46 #endif 47 48 #if PNG_LIBPNG_VER < 10700 49 /* READ_PNG and WRITE_PNG were not defined, so: */ 50 # ifdef PNG_INFO_IMAGE_SUPPORTED 51 # ifdef PNG_SEQUENTIAL_READ_SUPPORTED 52 # define PNG_READ_PNG_SUPPORTED 53 # endif /* SEQUENTIAL_READ */ 54 # ifdef PNG_WRITE_SUPPORTED 55 # define PNG_WRITE_PNG_SUPPORTED 56 # endif /* WRITE */ 57 # endif /* INFO_IMAGE */ 58 #endif /* pre 1.7.0 */ 59 60 #ifdef PNG_READ_PNG_SUPPORTED 61 /* If a transform is valid on both read and write this implies that if the 62 * transform is applied to read it must also be applied on write to produce 63 * meaningful data. This is because these transforms when performed on read 64 * produce data with a memory format that does not correspond to a PNG format. 65 * 66 * Most of these transforms are invertible; after applying the transform on 67 * write the result is the original PNG data that would have would have been 68 * read if no transform were applied. 69 * 70 * The exception is _SHIFT, which destroys the low order bits marked as not 71 * significant in a PNG with the sBIT chunk. 72 * 73 * The following table lists, for each transform, the conditions under which it 74 * is expected to do anything. Conditions are defined as follows: 75 * 76 * 1) Color mask bits required - simply a mask to AND with color_type; one of 77 * these must be present for the transform to fire, except that 0 means 78 * 'always'. 79 * 2) Color mask bits which must be absent - another mask - none of these must 80 * be present. 81 * 3) Bit depths - a mask of component bit depths for the transform to fire. 82 * 4) 'read' - the transform works in png_read_png. 83 * 5) 'write' - the transform works in png_write_png. 84 * 6) PNG_INFO_chunk; a mask of the chunks that must be present for the 85 * transform to fire. All must be present - the requirement is that 86 * png_get_valid() & mask == mask, so if mask is 0 there is no requirement. 87 * 88 * The condition refers to the original image state - if multiple transforms are 89 * used together it is possible to cause a transform that wouldn't fire on the 90 * original image to fire. 91 */ 92 static struct transform_info 93 { 94 const char *name; 95 int transform; 96 png_uint_32 valid_chunks; 97 # define CHUNK_NONE 0 98 # define CHUNK_sBIT PNG_INFO_sBIT 99 # define CHUNK_tRNS PNG_INFO_tRNS 100 png_byte color_mask_required; 101 png_byte color_mask_absent; 102 # define COLOR_MASK_X 0 103 # define COLOR_MASK_P PNG_COLOR_MASK_PALETTE 104 # define COLOR_MASK_C PNG_COLOR_MASK_COLOR 105 # define COLOR_MASK_A PNG_COLOR_MASK_ALPHA 106 # define COLOR_MASK_ALL (PALETTE+COLOR+ALPHA) /* absent = gray, no alpha */ 107 png_byte bit_depths; 108 # define BD_ALL (1 + 2 + 4 + 8 + 16) 109 # define BD_PAL (1 + 2 + 4 + 8) 110 # define BD_LOW (1 + 2 + 4) 111 # define BD_16 16 112 # define BD_TRUE (8+16) /* i.e. true-color depths */ 113 png_byte when; 114 # define TRANSFORM_R 1 115 # define TRANSFORM_W 2 116 # define TRANSFORM_RW 3 117 png_byte tested; /* the transform was tested somewhere */ 118 } transform_info[] = 119 { 120 /* List ALL the PNG_TRANSFORM_ macros here. Check for support using the READ 121 * macros; even if the transform is supported on write it cannot be tested 122 * without the read support. 123 */ 124 # define T(name,chunk,cm_required,cm_absent,bd,when)\ 125 { #name, PNG_TRANSFORM_ ## name, CHUNK_ ## chunk,\ 126 COLOR_MASK_ ## cm_required, COLOR_MASK_ ## cm_absent, BD_ ## bd,\ 127 TRANSFORM_ ## when, 0/*!tested*/ } 128 129 #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED 130 T(STRIP_16, NONE, X, X, 16, R), 131 /* drops the bottom 8 bits when bit depth is 16 */ 132 #endif 133 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED 134 T(STRIP_ALPHA, NONE, A, X, ALL, R), 135 /* removes the alpha channel if present */ 136 #endif 137 #ifdef PNG_WRITE_PACK_SUPPORTED 138 # define TRANSFORM_RW_PACK TRANSFORM_RW 139 #else 140 # define TRANSFORM_RW_PACK TRANSFORM_R 141 #endif 142 #ifdef PNG_READ_PACK_SUPPORTED 143 T(PACKING, NONE, X, X, LOW, RW_PACK), 144 /* unpacks low-bit-depth components into 1 byte per component on read, 145 * reverses this on write. 146 */ 147 #endif 148 #ifdef PNG_WRITE_PACKSWAP_SUPPORTED 149 # define TRANSFORM_RW_PACKSWAP TRANSFORM_RW 150 #else 151 # define TRANSFORM_RW_PACKSWAP TRANSFORM_R 152 #endif 153 #ifdef PNG_READ_PACKSWAP_SUPPORTED 154 T(PACKSWAP, NONE, X, X, LOW, RW_PACKSWAP), 155 /* reverses the order of low-bit-depth components packed into a byte */ 156 #endif 157 #ifdef PNG_READ_EXPAND_SUPPORTED 158 T(EXPAND, NONE, P, X, ALL, R), 159 /* expands PLTE PNG files to RGB (no tRNS) or RGBA (tRNS) * 160 * Note that the 'EXPAND' transform does lots of different things: */ 161 T(EXPAND, NONE, X, C, ALL, R), 162 /* expands grayscale PNG files to RGB, or RGBA */ 163 T(EXPAND, tRNS, X, A, ALL, R), 164 /* expands the tRNS chunk in files without alpha */ 165 #endif 166 #ifdef PNG_WRITE_INVERT_SUPPORTED 167 # define TRANSFORM_RW_INVERT TRANSFORM_RW 168 #else 169 # define TRANSFORM_RW_INVERT TRANSFORM_R 170 #endif 171 #ifdef PNG_READ_INVERT_SUPPORTED 172 T(INVERT_MONO, NONE, X, C, ALL, RW_INVERT), 173 /* converts gray-scale components to 1..0 from 0..1 */ 174 #endif 175 #ifdef PNG_WRITE_SHIFT_SUPPORTED 176 # define TRANSFORM_RW_SHIFT TRANSFORM_RW 177 #else 178 # define TRANSFORM_RW_SHIFT TRANSFORM_R 179 #endif 180 #ifdef PNG_READ_SHIFT_SUPPORTED 181 T(SHIFT, sBIT, X, X, ALL, RW_SHIFT), 182 /* reduces component values to the original range based on the sBIT chunk, 183 * this is only partially reversible - the low bits are lost and cannot be 184 * recovered on write. In fact write code replicates the bits to generate 185 * new low-order bits. 186 */ 187 #endif 188 #ifdef PNG_WRITE_BGR_SUPPORTED 189 # define TRANSFORM_RW_BGR TRANSFORM_RW 190 #else 191 # define TRANSFORM_RW_BGR TRANSFORM_R 192 #endif 193 #ifdef PNG_READ_BGR_SUPPORTED 194 T(BGR, NONE, C, P, TRUE, RW_BGR), 195 /* reverses the rgb component values of true-color pixels */ 196 #endif 197 #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED 198 # define TRANSFORM_RW_SWAP_ALPHA TRANSFORM_RW 199 #else 200 # define TRANSFORM_RW_SWAP_ALPHA TRANSFORM_R 201 #endif 202 #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED 203 T(SWAP_ALPHA, NONE, A, X, TRUE, RW_SWAP_ALPHA), 204 /* swaps the alpha channel of RGBA or GA pixels to the front - ARGB or 205 * AG, on write reverses the process. 206 */ 207 #endif 208 #ifdef PNG_WRITE_SWAP_SUPPORTED 209 # define TRANSFORM_RW_SWAP TRANSFORM_RW 210 #else 211 # define TRANSFORM_RW_SWAP TRANSFORM_R 212 #endif 213 #ifdef PNG_READ_SWAP_SUPPORTED 214 T(SWAP_ENDIAN, NONE, X, P, 16, RW_SWAP), 215 /* byte-swaps 16-bit component values */ 216 #endif 217 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED 218 # define TRANSFORM_RW_INVERT_ALPHA TRANSFORM_RW 219 #else 220 # define TRANSFORM_RW_INVERT_ALPHA TRANSFORM_R 221 #endif 222 #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED 223 T(INVERT_ALPHA, NONE, A, X, TRUE, RW_INVERT_ALPHA), 224 /* converts an alpha channel from 0..1 to 1..0 */ 225 #endif 226 #ifdef PNG_WRITE_FILLER_SUPPORTED 227 T(STRIP_FILLER_BEFORE, NONE, A, P, TRUE, W), /* 'A' for a filler! */ 228 /* on write skips a leading filler channel; testing requires data with a 229 * filler channel so this is produced from RGBA or GA images by removing 230 * the 'alpha' flag from the color type in place. 231 */ 232 T(STRIP_FILLER_AFTER, NONE, A, P, TRUE, W), 233 /* on write strips a trailing filler channel */ 234 #endif 235 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED 236 T(GRAY_TO_RGB, NONE, X, C, ALL, R), 237 /* expands grayscale images to RGB, also causes the palette part of 238 * 'EXPAND' to happen. Low bit depth grayscale images are expanded to 239 * 8-bits per component and no attempt is made to convert the image to a 240 * palette image. While this transform is partially reversible 241 * png_write_png does not currently support this. 242 */ 243 T(GRAY_TO_RGB, NONE, P, X, ALL, R), 244 /* The 'palette' side effect mentioned above; a bit bogus but this is the 245 * way the libpng code works. 246 */ 247 #endif 248 #ifdef PNG_READ_EXPAND_16_SUPPORTED 249 T(EXPAND_16, NONE, X, X, PAL, R), 250 /* expands images to 16-bits per component, as a side effect expands 251 * palette images to RGB and expands the tRNS chunk if present, so it can 252 * modify 16-bit per component images as well: 253 */ 254 T(EXPAND_16, tRNS, X, A, 16, R), 255 /* side effect of EXPAND_16 - expands the tRNS chunk in an RGB or G 16-bit 256 * image. 257 */ 258 #endif 259 #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED 260 T(SCALE_16, NONE, X, X, 16, R), 261 /* scales 16-bit components to 8-bits. */ 262 #endif 263 264 { NULL /*name*/, 0, 0, 0, 0, 0, 0, 0/*!tested*/ } 265 266 #undef T 267 }; 268 269 #define ARRAY_SIZE(a) ((sizeof a)/(sizeof a[0])) 270 #define TTABLE_SIZE ARRAY_SIZE(transform_info) 271 272 /* Some combinations of options that should be reversible are not; these cases 273 * are bugs. 274 */ 275 static int known_bad_combos[][2] = 276 { 277 /* problem, antidote */ 278 { PNG_TRANSFORM_SHIFT | PNG_TRANSFORM_INVERT_ALPHA, 0/*antidote*/ } 279 }; 280 281 static int 282 is_combo(int transforms) 283 { 284 return transforms & (transforms-1); /* non-zero if more than one set bit */ 285 } 286 287 static int 288 first_transform(int transforms) 289 { 290 return transforms & -transforms; /* lowest set bit */ 291 } 292 293 static int 294 is_bad_combo(int transforms) 295 { 296 unsigned int i; 297 298 for (i=0; i<ARRAY_SIZE(known_bad_combos); ++i) 299 { 300 int combo = known_bad_combos[i][0]; 301 302 if ((combo & transforms) == combo && 303 (transforms & known_bad_combos[i][1]) == 0) 304 return 1; 305 } 306 307 return 0; /* combo is ok */ 308 } 309 310 static const char * 311 transform_name(int t) 312 /* The name, if 't' has multiple bits set the name of the lowest set bit is 313 * returned. 314 */ 315 { 316 unsigned int i; 317 318 t &= -t; /* first set bit */ 319 320 for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL) 321 { 322 if ((transform_info[i].transform & t) != 0) 323 return transform_info[i].name; 324 } 325 326 return "invalid transform"; 327 } 328 329 /* Variables calculated by validate_T below and used to record all the supported 330 * transforms. Need (unsigned int) here because of the places where these 331 * values are used (unsigned compares in the 'exhaustive' iterator.) 332 */ 333 static unsigned int read_transforms, write_transforms, rw_transforms; 334 335 static void 336 validate_T(void) 337 /* Validate the above table - this just builds the above values */ 338 { 339 unsigned int i; 340 341 for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL) 342 { 343 if (transform_info[i].when & TRANSFORM_R) 344 read_transforms |= transform_info[i].transform; 345 346 if (transform_info[i].when & TRANSFORM_W) 347 write_transforms |= transform_info[i].transform; 348 } 349 350 /* Reversible transforms are those which are supported on both read and 351 * write. 352 */ 353 rw_transforms = read_transforms & write_transforms; 354 } 355 356 /* FILE DATA HANDLING 357 * The original file is cached in memory. During write the output file is 358 * written to memory. 359 * 360 * In both cases the file data is held in a linked list of buffers - not all 361 * of these are in use at any time. 362 */ 363 #define NEW(type) ((type *)malloc(sizeof (type))) 364 #define DELETE(ptr) (free(ptr)) 365 366 struct buffer_list 367 { 368 struct buffer_list *next; /* next buffer in list */ 369 png_byte buffer[1024]; /* the actual buffer */ 370 }; 371 372 struct buffer 373 { 374 struct buffer_list *last; /* last buffer in use */ 375 size_t end_count; /* bytes in the last buffer */ 376 struct buffer_list *current; /* current buffer being read */ 377 size_t read_count; /* count of bytes read from current */ 378 struct buffer_list first; /* the very first buffer */ 379 }; 380 381 static void 382 buffer_init(struct buffer *buffer) 383 /* Call this only once for a given buffer */ 384 { 385 buffer->first.next = NULL; 386 buffer->last = NULL; 387 buffer->current = NULL; 388 } 389 390 static void 391 buffer_destroy_list(struct buffer_list *list) 392 { 393 if (list != NULL) 394 { 395 struct buffer_list *next = list->next; 396 DELETE(list); 397 buffer_destroy_list(next); 398 } 399 } 400 401 static void 402 buffer_destroy(struct buffer *buffer) 403 { 404 struct buffer_list *list = buffer->first.next; 405 buffer_init(buffer); 406 buffer_destroy_list(list); 407 } 408 409 #ifdef PNG_WRITE_PNG_SUPPORTED 410 static void 411 buffer_start_write(struct buffer *buffer) 412 { 413 buffer->last = &buffer->first; 414 buffer->end_count = 0; 415 buffer->current = NULL; 416 } 417 #endif 418 419 static void 420 buffer_start_read(struct buffer *buffer) 421 { 422 buffer->current = &buffer->first; 423 buffer->read_count = 0; 424 } 425 426 #ifdef ENOMEM /* required by POSIX 1003.1 */ 427 # define MEMORY ENOMEM 428 #else 429 # define MEMORY ERANGE /* required by ANSI-C */ 430 #endif 431 static struct buffer * 432 get_buffer(png_structp pp) 433 /* Used from libpng callbacks to get the current buffer */ 434 { 435 return (struct buffer*)png_get_io_ptr(pp); 436 } 437 438 static struct buffer_list * 439 buffer_extend(struct buffer_list *current) 440 { 441 struct buffer_list *add; 442 443 assert(current->next == NULL); 444 445 add = NEW(struct buffer_list); 446 if (add == NULL) 447 return NULL; 448 449 add->next = NULL; 450 current->next = add; 451 452 return add; 453 } 454 455 /* Load a buffer from a file; does the equivalent of buffer_start_write. On a 456 * read error returns an errno value, else returns 0. 457 */ 458 static int 459 buffer_from_file(struct buffer *buffer, FILE *fp) 460 { 461 struct buffer_list *last = &buffer->first; 462 size_t count = 0; 463 464 for (;;) 465 { 466 size_t r = fread(last->buffer+count, 1/*size*/, 467 (sizeof last->buffer)-count, fp); 468 469 if (r > 0) 470 { 471 count += r; 472 473 if (count >= sizeof last->buffer) 474 { 475 assert(count == sizeof last->buffer); 476 count = 0; 477 478 if (last->next == NULL) 479 { 480 last = buffer_extend(last); 481 if (last == NULL) 482 return MEMORY; 483 } 484 485 else 486 last = last->next; 487 } 488 } 489 490 else /* fread failed - probably end of file */ 491 { 492 if (feof(fp)) 493 { 494 buffer->last = last; 495 buffer->end_count = count; 496 return 0; /* no error */ 497 } 498 499 /* Some kind of funky error; errno should be non-zero */ 500 return errno == 0 ? ERANGE : errno; 501 } 502 } 503 } 504 505 /* This structure is used to control the test of a single file. */ 506 typedef enum 507 { 508 VERBOSE, /* switches on all messages */ 509 INFORMATION, 510 WARNINGS, /* switches on warnings */ 511 LIBPNG_WARNING, 512 APP_WARNING, 513 ERRORS, /* just errors */ 514 APP_FAIL, /* continuable error - no need to longjmp */ 515 LIBPNG_ERROR, /* this and higher cause a longjmp */ 516 LIBPNG_BUG, /* erroneous behavior in libpng */ 517 APP_ERROR, /* such as out-of-memory in a callback */ 518 QUIET, /* no normal messages */ 519 USER_ERROR, /* such as file-not-found */ 520 INTERNAL_ERROR 521 } error_level; 522 #define LEVEL_MASK 0xf /* where the level is in 'options' */ 523 524 #define EXHAUSTIVE 0x010 /* Test all combinations of active options */ 525 #define STRICT 0x020 /* Fail on warnings as well as errors */ 526 #define LOG 0x040 /* Log pass/fail to stdout */ 527 #define CONTINUE 0x080 /* Continue on APP_FAIL errors */ 528 #define SKIP_BUGS 0x100 /* Skip over known bugs */ 529 #define LOG_SKIPPED 0x200 /* Log skipped bugs */ 530 #define FIND_BAD_COMBOS 0x400 /* Attempt to deduce bad combos */ 531 #define LIST_COMBOS 0x800 /* List combos by name */ 532 533 /* Result masks apply to the result bits in the 'results' field below; these 534 * bits are simple 1U<<error_level. A pass requires either nothing worse than 535 * warnings (--relaxes) or nothing worse than information (--strict) 536 */ 537 #define RESULT_STRICT(r) (((r) & ~((1U<<WARNINGS)-1)) == 0) 538 #define RESULT_RELAXED(r) (((r) & ~((1U<<ERRORS)-1)) == 0) 539 540 struct display 541 { 542 jmp_buf error_return; /* Where to go to on error */ 543 544 const char *filename; /* The name of the original file */ 545 const char *operation; /* Operation being performed */ 546 int transforms; /* Transform used in operation */ 547 png_uint_32 options; /* See display_log below */ 548 png_uint_32 results; /* A mask of errors seen */ 549 550 551 png_structp original_pp; /* used on the original read */ 552 png_infop original_ip; /* set by the original read */ 553 554 png_size_t original_rowbytes; /* of the original rows: */ 555 png_bytepp original_rows; /* from the original read */ 556 557 /* Original chunks valid */ 558 png_uint_32 chunks; 559 560 /* Original IHDR information */ 561 png_uint_32 width; 562 png_uint_32 height; 563 int bit_depth; 564 int color_type; 565 int interlace_method; 566 int compression_method; 567 int filter_method; 568 569 /* Derived information for the original image. */ 570 int active_transforms; /* transforms that do something on read */ 571 int ignored_transforms; /* transforms that should do nothing */ 572 573 /* Used on a read, both the original read and when validating a written 574 * image. 575 */ 576 png_structp read_pp; 577 png_infop read_ip; 578 579 # ifdef PNG_WRITE_PNG_SUPPORTED 580 /* Used to write a new image (the original info_ptr is used) */ 581 png_structp write_pp; 582 struct buffer written_file; /* where the file gets written */ 583 # endif 584 585 struct buffer original_file; /* Data read from the original file */ 586 }; 587 588 static void 589 display_init(struct display *dp) 590 /* Call this only once right at the start to initialize the control 591 * structure, the (struct buffer) lists are maintained across calls - the 592 * memory is not freed. 593 */ 594 { 595 memset(dp, 0, sizeof *dp); 596 dp->options = WARNINGS; /* default to !verbose, !quiet */ 597 dp->filename = NULL; 598 dp->operation = NULL; 599 dp->original_pp = NULL; 600 dp->original_ip = NULL; 601 dp->original_rows = NULL; 602 dp->read_pp = NULL; 603 dp->read_ip = NULL; 604 buffer_init(&dp->original_file); 605 606 # ifdef PNG_WRITE_PNG_SUPPORTED 607 dp->write_pp = NULL; 608 buffer_init(&dp->written_file); 609 # endif 610 } 611 612 static void 613 display_clean_read(struct display *dp) 614 { 615 if (dp->read_pp != NULL) 616 png_destroy_read_struct(&dp->read_pp, &dp->read_ip, NULL); 617 } 618 619 #ifdef PNG_WRITE_PNG_SUPPORTED 620 static void 621 display_clean_write(struct display *dp) 622 { 623 if (dp->write_pp != NULL) 624 png_destroy_write_struct(&dp->write_pp, NULL); 625 } 626 #endif 627 628 static void 629 display_clean(struct display *dp) 630 { 631 # ifdef PNG_WRITE_PNG_SUPPORTED 632 display_clean_write(dp); 633 # endif 634 display_clean_read(dp); 635 636 dp->original_rowbytes = 0; 637 dp->original_rows = NULL; 638 dp->chunks = 0; 639 640 png_destroy_read_struct(&dp->original_pp, &dp->original_ip, NULL); 641 /* leave the filename for error detection */ 642 dp->results = 0; /* reset for next time */ 643 } 644 645 static void 646 display_destroy(struct display *dp) 647 { 648 /* Release any memory held in the display. */ 649 # ifdef PNG_WRITE_PNG_SUPPORTED 650 buffer_destroy(&dp->written_file); 651 # endif 652 653 buffer_destroy(&dp->original_file); 654 } 655 656 static struct display * 657 get_dp(png_structp pp) 658 /* The display pointer is always stored in the png_struct error pointer */ 659 { 660 struct display *dp = (struct display*)png_get_error_ptr(pp); 661 662 if (dp == NULL) 663 { 664 fprintf(stderr, "pngimage: internal error (no display)\n"); 665 exit(99); /* prevents a crash */ 666 } 667 668 return dp; 669 } 670 671 /* error handling */ 672 #ifdef __GNUC__ 673 # define VGATTR __attribute__((__format__ (__printf__,3,4))) 674 /* Required to quiet GNUC warnings when the compiler sees a stdarg function 675 * that calls one of the stdio v APIs. 676 */ 677 #else 678 # define VGATTR 679 #endif 680 static void VGATTR 681 display_log(struct display *dp, error_level level, const char *fmt, ...) 682 /* 'level' is as above, fmt is a stdio style format string. This routine 683 * does not return if level is above LIBPNG_WARNING 684 */ 685 { 686 dp->results |= 1U << level; 687 688 if (level > (error_level)(dp->options & LEVEL_MASK)) 689 { 690 const char *lp; 691 va_list ap; 692 693 switch (level) 694 { 695 case INFORMATION: lp = "information"; break; 696 case LIBPNG_WARNING: lp = "warning(libpng)"; break; 697 case APP_WARNING: lp = "warning(pngimage)"; break; 698 case APP_FAIL: lp = "error(continuable)"; break; 699 case LIBPNG_ERROR: lp = "error(libpng)"; break; 700 case LIBPNG_BUG: lp = "bug(libpng)"; break; 701 case APP_ERROR: lp = "error(pngimage)"; break; 702 case USER_ERROR: lp = "error(user)"; break; 703 704 case INTERNAL_ERROR: /* anything unexpected is an internal error: */ 705 case VERBOSE: case WARNINGS: case ERRORS: case QUIET: 706 default: lp = "bug(pngimage)"; break; 707 } 708 709 fprintf(stderr, "%s: %s: %s", 710 dp->filename != NULL ? dp->filename : "<stdin>", lp, dp->operation); 711 712 if (dp->transforms != 0) 713 { 714 int tr = dp->transforms; 715 716 if (is_combo(tr)) 717 { 718 if (dp->options & LIST_COMBOS) 719 { 720 int trx = tr; 721 722 fprintf(stderr, "("); 723 if (trx) 724 { 725 int start = 0; 726 727 while (trx) 728 { 729 int trz = trx & -trx; 730 731 if (start) fprintf(stderr, "+"); 732 fprintf(stderr, "%s", transform_name(trz)); 733 start = 1; 734 trx &= ~trz; 735 } 736 } 737 738 else 739 fprintf(stderr, "-"); 740 fprintf(stderr, ")"); 741 } 742 743 else 744 fprintf(stderr, "(0x%x)", tr); 745 } 746 747 else 748 fprintf(stderr, "(%s)", transform_name(tr)); 749 } 750 751 fprintf(stderr, ": "); 752 753 va_start(ap, fmt); 754 vfprintf(stderr, fmt, ap); 755 va_end(ap); 756 757 fputc('\n', stderr); 758 } 759 /* else do not output any message */ 760 761 /* Errors cause this routine to exit to the fail code */ 762 if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE))) 763 longjmp(dp->error_return, level); 764 } 765 766 /* error handler callbacks for libpng */ 767 static void PNGCBAPI 768 display_warning(png_structp pp, png_const_charp warning) 769 { 770 display_log(get_dp(pp), LIBPNG_WARNING, "%s", warning); 771 } 772 773 static void PNGCBAPI 774 display_error(png_structp pp, png_const_charp error) 775 { 776 struct display *dp = get_dp(pp); 777 778 display_log(dp, LIBPNG_ERROR, "%s", error); 779 } 780 781 static void 782 display_cache_file(struct display *dp, const char *filename) 783 /* Does the initial cache of the file. */ 784 { 785 FILE *fp; 786 int ret; 787 788 dp->filename = filename; 789 790 if (filename != NULL) 791 { 792 fp = fopen(filename, "rb"); 793 if (fp == NULL) 794 display_log(dp, USER_ERROR, "open failed: %s", strerror(errno)); 795 } 796 797 else 798 fp = stdin; 799 800 ret = buffer_from_file(&dp->original_file, fp); 801 802 fclose(fp); 803 804 if (ret != 0) 805 display_log(dp, APP_ERROR, "read failed: %s", strerror(ret)); 806 } 807 808 static void 809 buffer_read(struct display *dp, struct buffer *bp, png_bytep data, 810 png_size_t size) 811 { 812 struct buffer_list *last = bp->current; 813 size_t read_count = bp->read_count; 814 815 while (size > 0) 816 { 817 size_t avail; 818 819 if (last == NULL || 820 (last == bp->last && read_count >= bp->end_count)) 821 { 822 display_log(dp, USER_ERROR, "file truncated (%lu bytes)", 823 (unsigned long)size); 824 /*NOTREACHED*/ 825 break; 826 } 827 828 else if (read_count >= sizeof last->buffer) 829 { 830 /* Move to the next buffer: */ 831 last = last->next; 832 read_count = 0; 833 bp->current = last; /* Avoid update outside the loop */ 834 835 /* And do a sanity check (the EOF case is caught above) */ 836 if (last == NULL) 837 { 838 display_log(dp, INTERNAL_ERROR, "damaged buffer list"); 839 /*NOTREACHED*/ 840 break; 841 } 842 } 843 844 avail = (sizeof last->buffer) - read_count; 845 if (avail > size) 846 avail = size; 847 848 memcpy(data, last->buffer + read_count, avail); 849 read_count += avail; 850 size -= avail; 851 data += avail; 852 } 853 854 bp->read_count = read_count; 855 } 856 857 static void PNGCBAPI 858 read_function(png_structp pp, png_bytep data, png_size_t size) 859 { 860 buffer_read(get_dp(pp), get_buffer(pp), data, size); 861 } 862 863 static void 864 read_png(struct display *dp, struct buffer *bp, const char *operation, 865 int transforms) 866 { 867 png_structp pp; 868 png_infop ip; 869 870 /* This cleans out any previous read and sets operation and transforms to 871 * empty. 872 */ 873 display_clean_read(dp); 874 875 if (operation != NULL) /* else this is a verify and do not overwrite info */ 876 { 877 dp->operation = operation; 878 dp->transforms = transforms; 879 } 880 881 dp->read_pp = pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, dp, 882 display_error, display_warning); 883 if (pp == NULL) 884 display_log(dp, LIBPNG_ERROR, "failed to create read struct"); 885 886 /* The png_read_png API requires us to make the info struct, but it does the 887 * call to png_read_info. 888 */ 889 dp->read_ip = ip = png_create_info_struct(pp); 890 if (ip == NULL) 891 display_log(dp, LIBPNG_ERROR, "failed to create info struct"); 892 893 # ifdef PNG_SET_USER_LIMITS_SUPPORTED 894 /* Remove the user limits, if any */ 895 png_set_user_limits(pp, 0x7fffffff, 0x7fffffff); 896 # endif 897 898 /* Set the IO handling */ 899 buffer_start_read(bp); 900 png_set_read_fn(pp, bp, read_function); 901 902 png_read_png(pp, ip, transforms, NULL/*params*/); 903 904 #if 0 /* crazy debugging */ 905 { 906 png_bytep pr = png_get_rows(pp, ip)[0]; 907 size_t rb = png_get_rowbytes(pp, ip); 908 size_t cb; 909 char c = ' '; 910 911 fprintf(stderr, "%.4x %2d (%3lu bytes):", transforms, png_get_bit_depth(pp,ip), (unsigned long)rb); 912 913 for (cb=0; cb<rb; ++cb) 914 fputc(c, stderr), fprintf(stderr, "%.2x", pr[cb]), c='.'; 915 916 fputc('\n', stderr); 917 } 918 #endif 919 } 920 921 static void 922 update_display(struct display *dp) 923 /* called once after the first read to update all the info, original_pp and 924 * original_ip must have been filled in. 925 */ 926 { 927 png_structp pp; 928 png_infop ip; 929 930 /* Now perform the initial read with a 0 tranform. */ 931 read_png(dp, &dp->original_file, "original read", 0/*no transform*/); 932 933 /* Move the result to the 'original' fields */ 934 dp->original_pp = pp = dp->read_pp, dp->read_pp = NULL; 935 dp->original_ip = ip = dp->read_ip, dp->read_ip = NULL; 936 937 dp->original_rowbytes = png_get_rowbytes(pp, ip); 938 if (dp->original_rowbytes == 0) 939 display_log(dp, LIBPNG_BUG, "png_get_rowbytes returned 0"); 940 941 dp->chunks = png_get_valid(pp, ip, 0xffffffff); 942 if ((dp->chunks & PNG_INFO_IDAT) == 0) /* set by png_read_png */ 943 display_log(dp, LIBPNG_BUG, "png_read_png did not set IDAT flag"); 944 945 dp->original_rows = png_get_rows(pp, ip); 946 if (dp->original_rows == NULL) 947 display_log(dp, LIBPNG_BUG, "png_read_png did not create row buffers"); 948 949 if (!png_get_IHDR(pp, ip, 950 &dp->width, &dp->height, &dp->bit_depth, &dp->color_type, 951 &dp->interlace_method, &dp->compression_method, &dp->filter_method)) 952 display_log(dp, LIBPNG_BUG, "png_get_IHDR failed"); 953 954 /* 'active' transforms are discovered based on the original image format; 955 * running one active transform can activate others. At present the code 956 * does not attempt to determine the closure. 957 */ 958 { 959 png_uint_32 chunks = dp->chunks; 960 int active = 0, inactive = 0; 961 int ct = dp->color_type; 962 int bd = dp->bit_depth; 963 unsigned int i; 964 965 for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL) 966 { 967 int transform = transform_info[i].transform; 968 969 if ((transform_info[i].valid_chunks == 0 || 970 (transform_info[i].valid_chunks & chunks) != 0) && 971 (transform_info[i].color_mask_required & ct) == 972 transform_info[i].color_mask_required && 973 (transform_info[i].color_mask_absent & ct) == 0 && 974 (transform_info[i].bit_depths & bd) != 0 && 975 (transform_info[i].when & TRANSFORM_R) != 0) 976 active |= transform; 977 978 else if ((transform_info[i].when & TRANSFORM_R) != 0) 979 inactive |= transform; 980 } 981 982 /* Some transforms appear multiple times in the table; the 'active' status 983 * is the logical OR of these and the inactive status must be adjusted to 984 * take this into account. 985 */ 986 inactive &= ~active; 987 988 dp->active_transforms = active; 989 dp->ignored_transforms = inactive; /* excluding write-only transforms */ 990 } 991 } 992 993 static int 994 compare_read(struct display *dp, int applied_transforms) 995 { 996 /* Compare the png_info from read_ip with original_info */ 997 size_t rowbytes; 998 png_uint_32 width, height; 999 int bit_depth, color_type; 1000 int interlace_method, compression_method, filter_method; 1001 const char *e = NULL; 1002 1003 png_get_IHDR(dp->read_pp, dp->read_ip, &width, &height, &bit_depth, 1004 &color_type, &interlace_method, &compression_method, &filter_method); 1005 1006 # define C(item) if (item != dp->item) \ 1007 display_log(dp, APP_WARNING, "IHDR " #item "(%lu) changed to %lu",\ 1008 (unsigned long)dp->item, (unsigned long)item), e = #item 1009 1010 /* The IHDR should be identical: */ 1011 C(width); 1012 C(height); 1013 C(bit_depth); 1014 C(color_type); 1015 C(interlace_method); 1016 C(compression_method); 1017 C(filter_method); 1018 1019 /* 'e' remains set to the name of the last thing changed: */ 1020 if (e) 1021 display_log(dp, APP_ERROR, "IHDR changed (%s)", e); 1022 1023 /* All the chunks from the original PNG should be preserved in the output PNG 1024 * because the PNG format has not been changed. 1025 */ 1026 { 1027 unsigned long chunks = 1028 png_get_valid(dp->read_pp, dp->read_ip, 0xffffffff); 1029 1030 if (chunks != dp->chunks) 1031 display_log(dp, APP_FAIL, "PNG chunks changed from 0x%lx to 0x%lx", 1032 (unsigned long)dp->chunks, chunks); 1033 } 1034 1035 /* rowbytes should be the same */ 1036 rowbytes = png_get_rowbytes(dp->read_pp, dp->read_ip); 1037 1038 /* NOTE: on 64-bit systems this may trash the top bits of rowbytes, 1039 * which could lead to weird error messages. 1040 */ 1041 if (rowbytes != dp->original_rowbytes) 1042 display_log(dp, APP_ERROR, "PNG rowbytes changed from %lu to %lu", 1043 (unsigned long)dp->original_rowbytes, (unsigned long)rowbytes); 1044 1045 /* The rows should be the same too, unless the applied transforms includes 1046 * the shift transform, in which case low bits may have been lost. 1047 */ 1048 { 1049 png_bytepp rows = png_get_rows(dp->read_pp, dp->read_ip); 1050 unsigned int mask; /* mask (if not zero) for the final byte */ 1051 1052 if (bit_depth < 8) 1053 { 1054 /* Need the stray bits at the end, this depends only on the low bits 1055 * of the image width; overflow does not matter. If the width is an 1056 * exact multiple of 8 bits this gives a mask of 0, not 0xff. 1057 */ 1058 mask = 0xff & (0xff00 >> ((bit_depth * width) & 7)); 1059 } 1060 1061 else 1062 mask = 0; 1063 1064 if (rows == NULL) 1065 display_log(dp, LIBPNG_BUG, "png_get_rows returned NULL"); 1066 1067 if ((applied_transforms & PNG_TRANSFORM_SHIFT) == 0 || 1068 (dp->active_transforms & PNG_TRANSFORM_SHIFT) == 0 || 1069 color_type == PNG_COLOR_TYPE_PALETTE) 1070 { 1071 unsigned long y; 1072 1073 for (y=0; y<height; ++y) 1074 { 1075 png_bytep row = rows[y]; 1076 png_bytep orig = dp->original_rows[y]; 1077 1078 if (memcmp(row, orig, rowbytes-(mask != 0)) != 0 || (mask != 0 && 1079 ((row[rowbytes-1] & mask) != (orig[rowbytes-1] & mask)))) 1080 { 1081 size_t x; 1082 1083 /* Find the first error */ 1084 for (x=0; x<rowbytes-1; ++x) if (row[x] != orig[x]) 1085 break; 1086 1087 display_log(dp, APP_FAIL, 1088 "byte(%lu,%lu) changed 0x%.2x -> 0x%.2x", 1089 (unsigned long)x, (unsigned long)y, orig[x], row[x]); 1090 return 0; /* don't keep reporting failed rows on 'continue' */ 1091 } 1092 } 1093 } 1094 1095 else 1096 # ifdef PNG_sBIT_SUPPORTED 1097 { 1098 unsigned long y; 1099 int bpp; /* bits-per-pixel then bytes-per-pixel */ 1100 /* components are up to 8 bytes in size */ 1101 png_byte sig_bits[8]; 1102 png_color_8p sBIT; 1103 1104 if (png_get_sBIT(dp->read_pp, dp->read_ip, &sBIT) != PNG_INFO_sBIT) 1105 display_log(dp, INTERNAL_ERROR, 1106 "active shift transform but no sBIT in file"); 1107 1108 switch (color_type) 1109 { 1110 case PNG_COLOR_TYPE_GRAY: 1111 sig_bits[0] = sBIT->gray; 1112 bpp = bit_depth; 1113 break; 1114 1115 case PNG_COLOR_TYPE_GA: 1116 sig_bits[0] = sBIT->gray; 1117 sig_bits[1] = sBIT->alpha; 1118 bpp = 2 * bit_depth; 1119 break; 1120 1121 case PNG_COLOR_TYPE_RGB: 1122 sig_bits[0] = sBIT->red; 1123 sig_bits[1] = sBIT->green; 1124 sig_bits[2] = sBIT->blue; 1125 bpp = 3 * bit_depth; 1126 break; 1127 1128 case PNG_COLOR_TYPE_RGBA: 1129 sig_bits[0] = sBIT->red; 1130 sig_bits[1] = sBIT->green; 1131 sig_bits[2] = sBIT->blue; 1132 sig_bits[3] = sBIT->alpha; 1133 bpp = 4 * bit_depth; 1134 break; 1135 1136 default: 1137 display_log(dp, LIBPNG_ERROR, "invalid colour type %d", 1138 color_type); 1139 /*NOTREACHED*/ 1140 bpp = 0; 1141 break; 1142 } 1143 1144 { 1145 int b; 1146 1147 for (b=0; 8*b<bpp; ++b) 1148 { 1149 /* libpng should catch this; if not there is a security issue 1150 * because an app (like this one) may overflow an array. In fact 1151 * libpng doesn't catch this at present. 1152 */ 1153 if (sig_bits[b] == 0 || sig_bits[b] > bit_depth/*!palette*/) 1154 display_log(dp, LIBPNG_BUG, 1155 "invalid sBIT[%u] value %d returned for PNG bit depth %d", 1156 b, sig_bits[b], bit_depth); 1157 } 1158 } 1159 1160 if (bpp < 8 && bpp != bit_depth) 1161 { 1162 /* sanity check; this is a grayscale PNG; something is wrong in the 1163 * code above. 1164 */ 1165 display_log(dp, INTERNAL_ERROR, "invalid bpp %u for bit_depth %u", 1166 bpp, bit_depth); 1167 } 1168 1169 switch (bit_depth) 1170 { 1171 int b; 1172 1173 case 16: /* Two bytes per component, big-endian */ 1174 for (b = (bpp >> 4); b > 0; --b) 1175 { 1176 unsigned int sig = (unsigned int)(0xffff0000 >> sig_bits[b]); 1177 1178 sig_bits[2*b+1] = (png_byte)sig; 1179 sig_bits[2*b+0] = (png_byte)(sig >> 8); /* big-endian */ 1180 } 1181 break; 1182 1183 case 8: /* One byte per component */ 1184 for (b=0; b*8 < bpp; ++b) 1185 sig_bits[b] = (png_byte)(0xff00 >> sig_bits[b]); 1186 break; 1187 1188 case 1: /* allowed, but dumb */ 1189 /* Value is 1 */ 1190 sig_bits[0] = 0xff; 1191 break; 1192 1193 case 2: /* Replicate 4 times */ 1194 /* Value is 1 or 2 */ 1195 b = 0x3 & ((0x3<<2) >> sig_bits[0]); 1196 b |= b << 2; 1197 b |= b << 4; 1198 sig_bits[0] = (png_byte)b; 1199 break; 1200 1201 case 4: /* Relicate twice */ 1202 /* Value is 1, 2, 3 or 4 */ 1203 b = 0xf & ((0xf << 4) >> sig_bits[0]); 1204 b |= b << 4; 1205 sig_bits[0] = (png_byte)b; 1206 break; 1207 1208 default: 1209 display_log(dp, LIBPNG_BUG, "invalid bit depth %d", bit_depth); 1210 break; 1211 } 1212 1213 /* Convert bpp to bytes; this gives '1' for low-bit depth grayscale, 1214 * where there are multiple pixels per byte. 1215 */ 1216 bpp = (bpp+7) >> 3; 1217 1218 /* The mask can be combined with sig_bits[0] */ 1219 if (mask != 0) 1220 { 1221 mask &= sig_bits[0]; 1222 1223 if (bpp != 1 || mask == 0) 1224 display_log(dp, INTERNAL_ERROR, "mask calculation error %u, %u", 1225 bpp, mask); 1226 } 1227 1228 for (y=0; y<height; ++y) 1229 { 1230 png_bytep row = rows[y]; 1231 png_bytep orig = dp->original_rows[y]; 1232 unsigned long x; 1233 1234 for (x=0; x<(width-(mask!=0)); ++x) 1235 { 1236 int b; 1237 1238 for (b=0; b<bpp; ++b) 1239 { 1240 if ((*row++ & sig_bits[b]) != (*orig++ & sig_bits[b])) 1241 { 1242 display_log(dp, APP_FAIL, 1243 "significant bits at (%lu[%u],%lu) changed %.2x->%.2x", 1244 x, b, y, orig[-1], row[-1]); 1245 return 0; 1246 } 1247 } 1248 } 1249 1250 if (mask != 0 && (*row & mask) != (*orig & mask)) 1251 { 1252 display_log(dp, APP_FAIL, 1253 "significant bits at (%lu[end],%lu) changed", x, y); 1254 return 0; 1255 } 1256 } /* for y */ 1257 } 1258 # else /* !sBIT */ 1259 display_log(dp, INTERNAL_ERROR, 1260 "active shift transform but no sBIT support"); 1261 # endif /* !sBIT */ 1262 } 1263 1264 return 1; /* compare succeeded */ 1265 } 1266 1267 #ifdef PNG_WRITE_PNG_SUPPORTED 1268 static void 1269 buffer_write(struct display *dp, struct buffer *buffer, png_bytep data, 1270 png_size_t size) 1271 /* Generic write function used both from the write callback provided to 1272 * libpng and from the generic read code. 1273 */ 1274 { 1275 /* Write the data into the buffer, adding buffers as required */ 1276 struct buffer_list *last = buffer->last; 1277 size_t end_count = buffer->end_count; 1278 1279 while (size > 0) 1280 { 1281 size_t avail; 1282 1283 if (end_count >= sizeof last->buffer) 1284 { 1285 if (last->next == NULL) 1286 { 1287 last = buffer_extend(last); 1288 1289 if (last == NULL) 1290 display_log(dp, APP_ERROR, "out of memory saving file"); 1291 } 1292 1293 else 1294 last = last->next; 1295 1296 buffer->last = last; /* avoid the need to rewrite every time */ 1297 end_count = 0; 1298 } 1299 1300 avail = (sizeof last->buffer) - end_count; 1301 if (avail > size) 1302 avail = size; 1303 1304 memcpy(last->buffer + end_count, data, avail); 1305 end_count += avail; 1306 size -= avail; 1307 data += avail; 1308 } 1309 1310 buffer->end_count = end_count; 1311 } 1312 1313 static void PNGCBAPI 1314 write_function(png_structp pp, png_bytep data, png_size_t size) 1315 { 1316 buffer_write(get_dp(pp), get_buffer(pp), data, size); 1317 } 1318 1319 static void 1320 write_png(struct display *dp, png_infop ip, int transforms) 1321 { 1322 display_clean_write(dp); /* safety */ 1323 1324 buffer_start_write(&dp->written_file); 1325 dp->operation = "write"; 1326 dp->transforms = transforms; 1327 1328 dp->write_pp = png_create_write_struct(PNG_LIBPNG_VER_STRING, dp, 1329 display_error, display_warning); 1330 1331 if (dp->write_pp == NULL) 1332 display_log(dp, APP_ERROR, "failed to create write png_struct"); 1333 1334 png_set_write_fn(dp->write_pp, &dp->written_file, write_function, 1335 NULL/*flush*/); 1336 1337 # ifdef PNG_SET_USER_LIMITS_SUPPORTED 1338 /* Remove the user limits, if any */ 1339 png_set_user_limits(dp->write_pp, 0x7fffffff, 0x7fffffff); 1340 # endif 1341 1342 /* Certain transforms require the png_info to be zapped to allow the 1343 * transform to work correctly. 1344 */ 1345 if (transforms & (PNG_TRANSFORM_PACKING| 1346 PNG_TRANSFORM_STRIP_FILLER| 1347 PNG_TRANSFORM_STRIP_FILLER_BEFORE)) 1348 { 1349 int ct = dp->color_type; 1350 1351 if (transforms & (PNG_TRANSFORM_STRIP_FILLER| 1352 PNG_TRANSFORM_STRIP_FILLER_BEFORE)) 1353 ct &= ~PNG_COLOR_MASK_ALPHA; 1354 1355 png_set_IHDR(dp->write_pp, ip, dp->width, dp->height, dp->bit_depth, ct, 1356 dp->interlace_method, dp->compression_method, dp->filter_method); 1357 } 1358 1359 png_write_png(dp->write_pp, ip, transforms, NULL/*params*/); 1360 1361 /* Clean it on the way out - if control returns to the caller then the 1362 * written_file contains the required data. 1363 */ 1364 display_clean_write(dp); 1365 } 1366 #endif /* WRITE_PNG */ 1367 1368 static int 1369 skip_transform(struct display *dp, int tr) 1370 /* Helper to test for a bad combo and log it if it is skipped */ 1371 { 1372 if ((dp->options & SKIP_BUGS) != 0 && is_bad_combo(tr)) 1373 { 1374 /* Log this to stdout if logging is on, otherwise just do an information 1375 * display_log. 1376 */ 1377 if ((dp->options & LOG_SKIPPED) != 0) 1378 { 1379 printf("SKIP: %s transforms ", dp->filename); 1380 1381 while (tr != 0) 1382 { 1383 int next = first_transform(tr); 1384 tr &= ~next; 1385 1386 printf("%s", transform_name(next)); 1387 if (tr != 0) 1388 putchar('+'); 1389 } 1390 1391 putchar('\n'); 1392 } 1393 1394 else 1395 display_log(dp, INFORMATION, "%s: skipped known bad combo 0x%x", 1396 dp->filename, tr); 1397 1398 return 1; /* skip */ 1399 } 1400 1401 return 0; /* don't skip */ 1402 } 1403 1404 static void 1405 test_one_file(struct display *dp, const char *filename) 1406 { 1407 /* First cache the file and update the display original file 1408 * information for the new file. 1409 */ 1410 dp->operation = "cache file"; 1411 dp->transforms = 0; 1412 display_cache_file(dp, filename); 1413 update_display(dp); 1414 1415 /* First test: if there are options that should be ignored for this file 1416 * verify that they really are ignored. 1417 */ 1418 if (dp->ignored_transforms != 0) 1419 { 1420 read_png(dp, &dp->original_file, "ignored transforms", 1421 dp->ignored_transforms); 1422 1423 /* The result should be identical to the original_rows */ 1424 if (!compare_read(dp, 0/*transforms applied*/)) 1425 return; /* no point testing more */ 1426 } 1427 1428 #ifdef PNG_WRITE_PNG_SUPPORTED 1429 /* Second test: write the original PNG data out to a new file (to test the 1430 * write side) then read the result back in and make sure that it hasn't 1431 * changed. 1432 */ 1433 dp->operation = "write"; 1434 write_png(dp, dp->original_ip, 0/*transforms*/); 1435 read_png(dp, &dp->written_file, NULL, 0/*transforms*/); 1436 if (!compare_read(dp, 0/*transforms applied*/)) 1437 return; 1438 #endif 1439 1440 /* Third test: the active options. Test each in turn, or, with the 1441 * EXHAUSTIVE option, test all possible combinations. 1442 */ 1443 { 1444 /* Use unsigned int here because the code below to increment through all 1445 * the possibilities exhaustively has to use a compare and that must be 1446 * unsigned, because some transforms are negative on a 16-bit system. 1447 */ 1448 unsigned int active = dp->active_transforms; 1449 const int exhaustive = (dp->options & EXHAUSTIVE) != 0; 1450 unsigned int current = first_transform(active); 1451 unsigned int bad_transforms = 0; 1452 unsigned int bad_combo = ~0U; /* bitwise AND of failing transforms */ 1453 unsigned int bad_combo_list = 0; /* bitwise OR of failures */ 1454 1455 for (;;) 1456 { 1457 read_png(dp, &dp->original_file, "active transforms", current); 1458 1459 /* If this involved any irreversible transformations then if we write 1460 * it out with just the reversible transformations and read it in again 1461 * with the same transforms we should get the same thing. At present 1462 * this isn't done - it just seems like a waste of time and it would 1463 * require two sets of read png_struct/png_info. 1464 * 1465 * If there were no irreversible transformations then if we write it 1466 * out and read it back in again (without the reversible transforms) 1467 * we should get back to the place where we started. 1468 */ 1469 #ifdef PNG_WRITE_PNG_SUPPORTED 1470 if ((current & write_transforms) == current) 1471 { 1472 /* All transforms reversible: write the PNG with the transformations 1473 * reversed, then read it back in with no transformations. The 1474 * result should be the same as the original apart from the loss of 1475 * low order bits because of the SHIFT/sBIT transform. 1476 */ 1477 dp->operation = "reversible transforms"; 1478 write_png(dp, dp->read_ip, current); 1479 1480 /* And if this is read back in, because all the transformations were 1481 * reversible, the result should be the same. 1482 */ 1483 read_png(dp, &dp->written_file, NULL, 0); 1484 if (!compare_read(dp, current/*for the SHIFT/sBIT transform*/)) 1485 { 1486 /* This set of transforms failed. If a single bit is set - if 1487 * there is just one transform - don't include this in further 1488 * 'exhaustive' tests. Notice that each transform is tested on 1489 * its own before testing combos in the exhaustive case. 1490 */ 1491 if (is_combo(current)) 1492 { 1493 bad_combo &= current; 1494 bad_combo_list |= current; 1495 } 1496 1497 else 1498 bad_transforms |= current; 1499 } 1500 } 1501 #endif 1502 1503 /* Now move to the next transform */ 1504 if (exhaustive) /* all combinations */ 1505 { 1506 unsigned int next = current; 1507 1508 do 1509 { 1510 if (next == read_transforms) /* Everything tested */ 1511 goto combo; 1512 1513 ++next; 1514 } /* skip known bad combos if the relevant option is set; skip 1515 * combos involving known bad single transforms in all cases. 1516 */ 1517 while ( (next & read_transforms) <= current 1518 || (next & active) == 0 /* skip cases that do nothing */ 1519 || (next & bad_transforms) != 0 1520 || skip_transform(dp, next)); 1521 1522 assert((next & read_transforms) == next); 1523 current = next; 1524 } 1525 1526 else /* one at a time */ 1527 { 1528 active &= ~current; 1529 1530 if (active == 0) 1531 goto combo; 1532 1533 current = first_transform(active); 1534 } 1535 } 1536 1537 combo: 1538 if (dp->options & FIND_BAD_COMBOS) 1539 { 1540 /* bad_combos identifies the combos that occur in all failing cases; 1541 * bad_combo_list identifies transforms that do not prevent the 1542 * failure. 1543 */ 1544 if (bad_combo != ~0U) 1545 printf("%s[0x%x]: PROBLEM: 0x%x[0x%x] ANTIDOTE: 0x%x\n", 1546 dp->filename, active, bad_combo, bad_combo_list, 1547 rw_transforms & ~bad_combo_list); 1548 1549 else 1550 printf("%s: no %sbad combos found\n", dp->filename, 1551 (dp->options & SKIP_BUGS) ? "additional " : ""); 1552 } 1553 } 1554 } 1555 1556 static int 1557 do_test(struct display *dp, const char *file) 1558 /* Exists solely to isolate the setjmp clobbers */ 1559 { 1560 int ret = setjmp(dp->error_return); 1561 1562 if (ret == 0) 1563 { 1564 test_one_file(dp, file); 1565 return 0; 1566 } 1567 1568 else if (ret < ERRORS) /* shouldn't longjmp on warnings */ 1569 display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret); 1570 1571 return ret; 1572 } 1573 1574 int 1575 main(const int argc, const char * const * const argv) 1576 { 1577 /* For each file on the command line test it with a range of transforms */ 1578 int option_end, ilog = 0; 1579 struct display d; 1580 1581 validate_T(); 1582 display_init(&d); 1583 1584 for (option_end=1; option_end<argc; ++option_end) 1585 { 1586 const char *name = argv[option_end]; 1587 1588 if (strcmp(name, "--verbose") == 0) 1589 d.options = (d.options & ~LEVEL_MASK) | VERBOSE; 1590 1591 else if (strcmp(name, "--warnings") == 0) 1592 d.options = (d.options & ~LEVEL_MASK) | WARNINGS; 1593 1594 else if (strcmp(name, "--errors") == 0) 1595 d.options = (d.options & ~LEVEL_MASK) | ERRORS; 1596 1597 else if (strcmp(name, "--quiet") == 0) 1598 d.options = (d.options & ~LEVEL_MASK) | QUIET; 1599 1600 else if (strcmp(name, "--exhaustive") == 0) 1601 d.options |= EXHAUSTIVE; 1602 1603 else if (strcmp(name, "--fast") == 0) 1604 d.options &= ~EXHAUSTIVE; 1605 1606 else if (strcmp(name, "--strict") == 0) 1607 d.options |= STRICT; 1608 1609 else if (strcmp(name, "--relaxed") == 0) 1610 d.options &= ~STRICT; 1611 1612 else if (strcmp(name, "--log") == 0) 1613 { 1614 ilog = option_end; /* prevent display */ 1615 d.options |= LOG; 1616 } 1617 1618 else if (strcmp(name, "--nolog") == 0) 1619 d.options &= ~LOG; 1620 1621 else if (strcmp(name, "--continue") == 0) 1622 d.options |= CONTINUE; 1623 1624 else if (strcmp(name, "--stop") == 0) 1625 d.options &= ~CONTINUE; 1626 1627 else if (strcmp(name, "--skip-bugs") == 0) 1628 d.options |= SKIP_BUGS; 1629 1630 else if (strcmp(name, "--test-all") == 0) 1631 d.options &= ~SKIP_BUGS; 1632 1633 else if (strcmp(name, "--log-skipped") == 0) 1634 d.options |= LOG_SKIPPED; 1635 1636 else if (strcmp(name, "--nolog-skipped") == 0) 1637 d.options &= ~LOG_SKIPPED; 1638 1639 else if (strcmp(name, "--find-bad-combos") == 0) 1640 d.options |= FIND_BAD_COMBOS; 1641 1642 else if (strcmp(name, "--nofind-bad-combos") == 0) 1643 d.options &= ~FIND_BAD_COMBOS; 1644 1645 else if (strcmp(name, "--list-combos") == 0) 1646 d.options |= LIST_COMBOS; 1647 1648 else if (strcmp(name, "--nolist-combos") == 0) 1649 d.options &= ~LIST_COMBOS; 1650 1651 else if (name[0] == '-' && name[1] == '-') 1652 { 1653 fprintf(stderr, "pngimage: %s: unknown option\n", name); 1654 return 99; 1655 } 1656 1657 else 1658 break; /* Not an option */ 1659 } 1660 1661 { 1662 int i; 1663 int errors = 0; 1664 1665 for (i=option_end; i<argc; ++i) 1666 { 1667 { 1668 int ret = do_test(&d, argv[i]); 1669 1670 if (ret > QUIET) /* abort on user or internal error */ 1671 return 99; 1672 } 1673 1674 /* Here on any return, including failures, except user/internal issues 1675 */ 1676 { 1677 const int pass = (d.options & STRICT) ? 1678 RESULT_STRICT(d.results) : RESULT_RELAXED(d.results); 1679 1680 if (!pass) 1681 ++errors; 1682 1683 if (d.options & LOG) 1684 { 1685 int j; 1686 1687 printf("%s: pngimage ", pass ? "PASS" : "FAIL"); 1688 1689 for (j=1; j<option_end; ++j) if (j != ilog) 1690 printf("%s ", argv[j]); 1691 1692 printf("%s\n", d.filename); 1693 } 1694 } 1695 1696 display_clean(&d); 1697 } 1698 1699 /* Release allocated memory */ 1700 display_destroy(&d); 1701 1702 return errors != 0; 1703 } 1704 } 1705 #else /* !READ_PNG */ 1706 int 1707 main(void) 1708 { 1709 fprintf(stderr, "pngimage: no support for png_read/write_image\n"); 1710 return SKIP; 1711 } 1712 #endif 1713