pngerror.c (26351B)
1 /* pngerror.c - stub functions for i/o and memory allocation 2 * 3 * Copyright (c) 2018-2025 Cosmin Truta 4 * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson 5 * Copyright (c) 1996-1997 Andreas Dilger 6 * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. 7 * 8 * This code is released under the libpng license. 9 * For conditions of distribution and use, see the disclaimer 10 * and license in png.h 11 * 12 * This file provides a location for all error handling. Users who 13 * need special error handling are expected to write replacement functions 14 * and use png_set_error_fn() to use those functions. See the instructions 15 * at each function. 16 */ 17 18 #include "pngpriv.h" 19 20 #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) 21 22 static PNG_FUNCTION(void /* PRIVATE */, 23 png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), 24 PNG_NORETURN); 25 26 #ifdef PNG_WARNINGS_SUPPORTED 27 static void /* PRIVATE */ 28 png_default_warning(png_const_structrp png_ptr, 29 png_const_charp warning_message); 30 #endif /* WARNINGS */ 31 32 /* This function is called whenever there is a fatal error. This function 33 * should not be changed. If there is a need to handle errors differently, 34 * you should supply a replacement error function and use png_set_error_fn() 35 * to replace the error function at run-time. 36 */ 37 #ifdef PNG_ERROR_TEXT_SUPPORTED 38 PNG_FUNCTION(void,PNGAPI 39 png_error,(png_const_structrp png_ptr, png_const_charp error_message), 40 PNG_NORETURN) 41 { 42 if (png_ptr != NULL && png_ptr->error_fn != NULL) 43 (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), 44 error_message); 45 46 /* If the custom handler doesn't exist, or if it returns, 47 use the default handler, which will not return. */ 48 png_default_error(png_ptr, error_message); 49 } 50 #else 51 PNG_FUNCTION(void,PNGAPI 52 png_err,(png_const_structrp png_ptr),PNG_NORETURN) 53 { 54 /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed 55 * erroneously as '\0', instead of the empty string "". This was 56 * apparently an error, introduced in libpng-1.2.20, and png_default_error 57 * will crash in this case. 58 */ 59 if (png_ptr != NULL && png_ptr->error_fn != NULL) 60 (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), ""); 61 62 /* If the custom handler doesn't exist, or if it returns, 63 use the default handler, which will not return. */ 64 png_default_error(png_ptr, ""); 65 } 66 #endif /* ERROR_TEXT */ 67 68 /* Utility to safely appends strings to a buffer. This never errors out so 69 * error checking is not required in the caller. 70 */ 71 size_t 72 png_safecat(png_charp buffer, size_t bufsize, size_t pos, 73 png_const_charp string) 74 { 75 if (buffer != NULL && pos < bufsize) 76 { 77 if (string != NULL) 78 while (*string != '\0' && pos < bufsize-1) 79 buffer[pos++] = *string++; 80 81 buffer[pos] = '\0'; 82 } 83 84 return pos; 85 } 86 87 #if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) 88 /* Utility to dump an unsigned value into a buffer, given a start pointer and 89 * and end pointer (which should point just *beyond* the end of the buffer!) 90 * Returns the pointer to the start of the formatted string. 91 */ 92 png_charp 93 png_format_number(png_const_charp start, png_charp end, int format, 94 png_alloc_size_t number) 95 { 96 int count = 0; /* number of digits output */ 97 int mincount = 1; /* minimum number required */ 98 int output = 0; /* digit output (for the fixed point format) */ 99 100 *--end = '\0'; 101 102 /* This is written so that the loop always runs at least once, even with 103 * number zero. 104 */ 105 while (end > start && (number != 0 || count < mincount)) 106 { 107 108 static const char digits[] = "0123456789ABCDEF"; 109 110 switch (format) 111 { 112 case PNG_NUMBER_FORMAT_fixed: 113 /* Needs five digits (the fraction) */ 114 mincount = 5; 115 if (output != 0 || number % 10 != 0) 116 { 117 *--end = digits[number % 10]; 118 output = 1; 119 } 120 number /= 10; 121 break; 122 123 case PNG_NUMBER_FORMAT_02u: 124 /* Expects at least 2 digits. */ 125 mincount = 2; 126 /* FALLTHROUGH */ 127 128 case PNG_NUMBER_FORMAT_u: 129 *--end = digits[number % 10]; 130 number /= 10; 131 break; 132 133 case PNG_NUMBER_FORMAT_02x: 134 /* This format expects at least two digits */ 135 mincount = 2; 136 /* FALLTHROUGH */ 137 138 case PNG_NUMBER_FORMAT_x: 139 *--end = digits[number & 0xf]; 140 number >>= 4; 141 break; 142 143 default: /* an error */ 144 number = 0; 145 break; 146 } 147 148 /* Keep track of the number of digits added */ 149 ++count; 150 151 /* Float a fixed number here: */ 152 if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start)) 153 { 154 /* End of the fraction, but maybe nothing was output? In that case 155 * drop the decimal point. If the number is a true zero handle that 156 * here. 157 */ 158 if (output != 0) 159 *--end = '.'; 160 else if (number == 0) /* and !output */ 161 *--end = '0'; 162 } 163 } 164 165 return end; 166 } 167 #endif 168 169 #ifdef PNG_WARNINGS_SUPPORTED 170 /* This function is called whenever there is a non-fatal error. This function 171 * should not be changed. If there is a need to handle warnings differently, 172 * you should supply a replacement warning function and use 173 * png_set_error_fn() to replace the warning function at run-time. 174 */ 175 void PNGAPI 176 png_warning(png_const_structrp png_ptr, png_const_charp warning_message) 177 { 178 int offset = 0; 179 if (png_ptr != NULL && png_ptr->warning_fn != NULL) 180 (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr), 181 warning_message + offset); 182 else 183 png_default_warning(png_ptr, warning_message + offset); 184 } 185 186 /* These functions support 'formatted' warning messages with up to 187 * PNG_WARNING_PARAMETER_COUNT parameters. In the format string the parameter 188 * is introduced by @<number>, where 'number' starts at 1. This follows the 189 * standard established by X/Open for internationalizable error messages. 190 */ 191 void 192 png_warning_parameter(png_warning_parameters p, int number, 193 png_const_charp string) 194 { 195 if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT) 196 (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string); 197 } 198 199 void 200 png_warning_parameter_unsigned(png_warning_parameters p, int number, int format, 201 png_alloc_size_t value) 202 { 203 char buffer[PNG_NUMBER_BUFFER_SIZE] = {0}; 204 png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value)); 205 } 206 207 void 208 png_warning_parameter_signed(png_warning_parameters p, int number, int format, 209 png_int_32 value) 210 { 211 png_alloc_size_t u; 212 png_charp str; 213 char buffer[PNG_NUMBER_BUFFER_SIZE] = {0}; 214 215 /* Avoid overflow by doing the negate in a png_alloc_size_t: */ 216 u = (png_alloc_size_t)value; 217 if (value < 0) 218 u = ~u + 1; 219 220 str = PNG_FORMAT_NUMBER(buffer, format, u); 221 222 if (value < 0 && str > buffer) 223 *--str = '-'; 224 225 png_warning_parameter(p, number, str); 226 } 227 228 void 229 png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, 230 png_const_charp message) 231 { 232 /* The internal buffer is just 192 bytes - enough for all our messages, 233 * overflow doesn't happen because this code checks! If someone figures 234 * out how to send us a message longer than 192 bytes, all that will 235 * happen is that the message will be truncated appropriately. 236 */ 237 size_t i = 0; /* Index in the msg[] buffer: */ 238 char msg[192]; 239 240 /* Each iteration through the following loop writes at most one character 241 * to msg[i++] then returns here to validate that there is still space for 242 * the trailing '\0'. It may (in the case of a parameter) read more than 243 * one character from message[]; it must check for '\0' and continue to the 244 * test if it finds the end of string. 245 */ 246 while (i<(sizeof msg)-1 && *message != '\0') 247 { 248 /* '@' at end of string is now just printed (previously it was skipped); 249 * it is an error in the calling code to terminate the string with @. 250 */ 251 if (p != NULL && *message == '@' && message[1] != '\0') 252 { 253 int parameter_char = *++message; /* Consume the '@' */ 254 static const char valid_parameters[] = "123456789"; 255 int parameter = 0; 256 257 /* Search for the parameter digit, the index in the string is the 258 * parameter to use. 259 */ 260 while (valid_parameters[parameter] != parameter_char && 261 valid_parameters[parameter] != '\0') 262 ++parameter; 263 264 /* If the parameter digit is out of range it will just get printed. */ 265 if (parameter < PNG_WARNING_PARAMETER_COUNT) 266 { 267 /* Append this parameter */ 268 png_const_charp parm = p[parameter]; 269 png_const_charp pend = p[parameter] + (sizeof p[parameter]); 270 271 /* No need to copy the trailing '\0' here, but there is no guarantee 272 * that parm[] has been initialized, so there is no guarantee of a 273 * trailing '\0': 274 */ 275 while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend) 276 msg[i++] = *parm++; 277 278 /* Consume the parameter digit too: */ 279 ++message; 280 continue; 281 } 282 283 /* else not a parameter and there is a character after the @ sign; just 284 * copy that. This is known not to be '\0' because of the test above. 285 */ 286 } 287 288 /* At this point *message can't be '\0', even in the bad parameter case 289 * above where there is a lone '@' at the end of the message string. 290 */ 291 msg[i++] = *message++; 292 } 293 294 /* i is always less than (sizeof msg), so: */ 295 msg[i] = '\0'; 296 297 /* And this is the formatted message. It may be larger than 298 * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these 299 * are not (currently) formatted. 300 */ 301 png_warning(png_ptr, msg); 302 } 303 #endif /* WARNINGS */ 304 305 #ifdef PNG_BENIGN_ERRORS_SUPPORTED 306 void PNGAPI 307 png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) 308 { 309 if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) 310 { 311 # ifdef PNG_READ_SUPPORTED 312 if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && 313 png_ptr->chunk_name != 0) 314 png_chunk_warning(png_ptr, error_message); 315 else 316 # endif 317 png_warning(png_ptr, error_message); 318 } 319 320 else 321 { 322 # ifdef PNG_READ_SUPPORTED 323 if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && 324 png_ptr->chunk_name != 0) 325 png_chunk_error(png_ptr, error_message); 326 else 327 # endif 328 png_error(png_ptr, error_message); 329 } 330 331 # ifndef PNG_ERROR_TEXT_SUPPORTED 332 PNG_UNUSED(error_message) 333 # endif 334 } 335 336 void /* PRIVATE */ 337 png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) 338 { 339 if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0) 340 png_warning(png_ptr, error_message); 341 else 342 png_error(png_ptr, error_message); 343 344 # ifndef PNG_ERROR_TEXT_SUPPORTED 345 PNG_UNUSED(error_message) 346 # endif 347 } 348 349 void /* PRIVATE */ 350 png_app_error(png_const_structrp png_ptr, png_const_charp error_message) 351 { 352 if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0) 353 png_warning(png_ptr, error_message); 354 else 355 png_error(png_ptr, error_message); 356 357 # ifndef PNG_ERROR_TEXT_SUPPORTED 358 PNG_UNUSED(error_message) 359 # endif 360 } 361 #endif /* BENIGN_ERRORS */ 362 363 #define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */ 364 #if defined(PNG_WARNINGS_SUPPORTED) || \ 365 (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)) 366 /* These utilities are used internally to build an error message that relates 367 * to the current chunk. The chunk name comes from png_ptr->chunk_name, 368 * which is used to prefix the message. The message is limited in length 369 * to 63 bytes. The name characters are output as hex digits wrapped in [] 370 * if the character is invalid. 371 */ 372 #define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) 373 static const char png_digit[16] = { 374 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 375 'A', 'B', 'C', 'D', 'E', 'F' 376 }; 377 378 static void /* PRIVATE */ 379 png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp 380 error_message) 381 { 382 png_uint_32 chunk_name = png_ptr->chunk_name; 383 int iout = 0, ishift = 24; 384 385 while (ishift >= 0) 386 { 387 int c = (int)(chunk_name >> ishift) & 0xff; 388 389 ishift -= 8; 390 if (isnonalpha(c) != 0) 391 { 392 buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; 393 buffer[iout++] = png_digit[(c & 0xf0) >> 4]; 394 buffer[iout++] = png_digit[c & 0x0f]; 395 buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; 396 } 397 398 else 399 { 400 buffer[iout++] = (char)c; 401 } 402 } 403 404 if (error_message == NULL) 405 buffer[iout] = '\0'; 406 407 else 408 { 409 int iin = 0; 410 411 buffer[iout++] = ':'; 412 buffer[iout++] = ' '; 413 414 while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0') 415 buffer[iout++] = error_message[iin++]; 416 417 /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */ 418 buffer[iout] = '\0'; 419 } 420 } 421 #endif /* WARNINGS || ERROR_TEXT */ 422 423 #if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) 424 PNG_FUNCTION(void,PNGAPI 425 png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), 426 PNG_NORETURN) 427 { 428 char msg[18+PNG_MAX_ERROR_TEXT]; 429 if (png_ptr == NULL) 430 png_error(png_ptr, error_message); 431 432 else 433 { 434 png_format_buffer(png_ptr, msg, error_message); 435 png_error(png_ptr, msg); 436 } 437 } 438 #endif /* READ && ERROR_TEXT */ 439 440 #ifdef PNG_WARNINGS_SUPPORTED 441 void PNGAPI 442 png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message) 443 { 444 char msg[18+PNG_MAX_ERROR_TEXT]; 445 if (png_ptr == NULL) 446 png_warning(png_ptr, warning_message); 447 448 else 449 { 450 png_format_buffer(png_ptr, msg, warning_message); 451 png_warning(png_ptr, msg); 452 } 453 } 454 #endif /* WARNINGS */ 455 456 #ifdef PNG_READ_SUPPORTED 457 #ifdef PNG_BENIGN_ERRORS_SUPPORTED 458 void PNGAPI 459 png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp 460 error_message) 461 { 462 if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) 463 png_chunk_warning(png_ptr, error_message); 464 465 else 466 png_chunk_error(png_ptr, error_message); 467 468 # ifndef PNG_ERROR_TEXT_SUPPORTED 469 PNG_UNUSED(error_message) 470 # endif 471 } 472 #endif 473 #endif /* READ */ 474 475 void /* PRIVATE */ 476 png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) 477 { 478 # ifndef PNG_WARNINGS_SUPPORTED 479 PNG_UNUSED(message) 480 # endif 481 482 /* This is always supported, but for just read or just write it 483 * unconditionally does the right thing. 484 */ 485 # if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) 486 if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) 487 # endif 488 489 # ifdef PNG_READ_SUPPORTED 490 { 491 if (error < PNG_CHUNK_ERROR) 492 png_chunk_warning(png_ptr, message); 493 494 else 495 png_chunk_benign_error(png_ptr, message); 496 } 497 # endif 498 499 # if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) 500 else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) 501 # endif 502 503 # ifdef PNG_WRITE_SUPPORTED 504 { 505 if (error < PNG_CHUNK_WRITE_ERROR) 506 png_app_warning(png_ptr, message); 507 508 else 509 png_app_error(png_ptr, message); 510 } 511 # endif 512 } 513 514 #ifdef PNG_ERROR_TEXT_SUPPORTED 515 #ifdef PNG_FLOATING_POINT_SUPPORTED 516 PNG_FUNCTION(void, 517 png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN) 518 { 519 # define fixed_message "fixed point overflow in " 520 # define fixed_message_ln ((sizeof fixed_message)-1) 521 unsigned int iin; 522 char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT]; 523 memcpy(msg, fixed_message, fixed_message_ln); 524 iin = 0; 525 if (name != NULL) 526 while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) 527 { 528 msg[fixed_message_ln + iin] = name[iin]; 529 ++iin; 530 } 531 msg[fixed_message_ln + iin] = 0; 532 png_error(png_ptr, msg); 533 } 534 #endif 535 #endif 536 537 #ifdef PNG_SETJMP_SUPPORTED 538 /* This API only exists if ANSI-C style error handling is used, 539 * otherwise it is necessary for png_default_error to be overridden. 540 */ 541 jmp_buf* PNGAPI 542 png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn, 543 size_t jmp_buf_size) 544 { 545 /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value 546 * and it must not change after that. Libpng doesn't care how big the 547 * buffer is, just that it doesn't change. 548 * 549 * If the buffer size is no *larger* than the size of jmp_buf when libpng is 550 * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0 551 * semantics that this call will not fail. If the size is larger, however, 552 * the buffer is allocated and this may fail, causing the function to return 553 * NULL. 554 */ 555 if (png_ptr == NULL) 556 return NULL; 557 558 if (png_ptr->jmp_buf_ptr == NULL) 559 { 560 png_ptr->jmp_buf_size = 0; /* not allocated */ 561 562 if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local)) 563 png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; 564 565 else 566 { 567 png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *, 568 png_malloc_warn(png_ptr, jmp_buf_size)); 569 570 if (png_ptr->jmp_buf_ptr == NULL) 571 return NULL; /* new NULL return on OOM */ 572 573 png_ptr->jmp_buf_size = jmp_buf_size; 574 } 575 } 576 577 else /* Already allocated: check the size */ 578 { 579 size_t size = png_ptr->jmp_buf_size; 580 581 if (size == 0) 582 { 583 size = (sizeof png_ptr->jmp_buf_local); 584 if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local) 585 { 586 /* This is an internal error in libpng: somehow we have been left 587 * with a stack allocated jmp_buf when the application regained 588 * control. It's always possible to fix this up, but for the moment 589 * this is a png_error because that makes it easy to detect. 590 */ 591 png_error(png_ptr, "Libpng jmp_buf still allocated"); 592 /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */ 593 } 594 } 595 596 if (size != jmp_buf_size) 597 { 598 png_warning(png_ptr, "Application jmp_buf size changed"); 599 return NULL; /* caller will probably crash: no choice here */ 600 } 601 } 602 603 /* Finally fill in the function, now we have a satisfactory buffer. It is 604 * valid to change the function on every call. 605 */ 606 png_ptr->longjmp_fn = longjmp_fn; 607 return png_ptr->jmp_buf_ptr; 608 } 609 610 void /* PRIVATE */ 611 png_free_jmpbuf(png_structrp png_ptr) 612 { 613 if (png_ptr != NULL) 614 { 615 jmp_buf *jb = png_ptr->jmp_buf_ptr; 616 617 /* A size of 0 is used to indicate a local, stack, allocation of the 618 * pointer; used here and in png.c 619 */ 620 if (jb != NULL && png_ptr->jmp_buf_size > 0) 621 { 622 623 /* This stuff is so that a failure to free the error control structure 624 * does not leave libpng in a state with no valid error handling: the 625 * free always succeeds, if there is an error it gets ignored. 626 */ 627 if (jb != &png_ptr->jmp_buf_local) 628 { 629 /* Make an internal, libpng, jmp_buf to return here */ 630 jmp_buf free_jmp_buf; 631 632 if (!setjmp(free_jmp_buf)) 633 { 634 png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */ 635 png_ptr->jmp_buf_size = 0; /* stack allocation */ 636 png_ptr->longjmp_fn = longjmp; 637 png_free(png_ptr, jb); /* Return to setjmp on error */ 638 } 639 } 640 } 641 642 /* *Always* cancel everything out: */ 643 png_ptr->jmp_buf_size = 0; 644 png_ptr->jmp_buf_ptr = NULL; 645 png_ptr->longjmp_fn = 0; 646 } 647 } 648 #endif 649 650 /* This is the default error handling function. Note that replacements for 651 * this function MUST NOT RETURN, or the program will likely crash. This 652 * function is used by default, or if the program supplies NULL for the 653 * error function pointer in png_set_error_fn(). 654 */ 655 static PNG_FUNCTION(void /* PRIVATE */, 656 png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), 657 PNG_NORETURN) 658 { 659 #ifdef PNG_CONSOLE_IO_SUPPORTED 660 fprintf(stderr, "libpng error: %s", error_message ? error_message : 661 "undefined"); 662 fprintf(stderr, PNG_STRING_NEWLINE); 663 #else 664 PNG_UNUSED(error_message) /* Make compiler happy */ 665 #endif 666 png_longjmp(png_ptr, 1); 667 } 668 669 PNG_FUNCTION(void,PNGAPI 670 png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN) 671 { 672 #ifdef PNG_SETJMP_SUPPORTED 673 if (png_ptr != NULL && png_ptr->longjmp_fn != NULL && 674 png_ptr->jmp_buf_ptr != NULL) 675 png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val); 676 #else 677 PNG_UNUSED(png_ptr) 678 PNG_UNUSED(val) 679 #endif 680 681 /* If control reaches this point, png_longjmp() must not return. The only 682 * choice is to terminate the whole process (or maybe the thread); to do 683 * this the ANSI-C abort() function is used unless a different method is 684 * implemented by overriding the default configuration setting for 685 * PNG_ABORT(). 686 */ 687 PNG_ABORT(); 688 } 689 690 #ifdef PNG_WARNINGS_SUPPORTED 691 /* This function is called when there is a warning, but the library thinks 692 * it can continue anyway. Replacement functions don't have to do anything 693 * here if you don't want them to. In the default configuration, png_ptr is 694 * not used, but it is passed in case it may be useful. 695 */ 696 static void /* PRIVATE */ 697 png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message) 698 { 699 #ifdef PNG_CONSOLE_IO_SUPPORTED 700 fprintf(stderr, "libpng warning: %s", warning_message); 701 fprintf(stderr, PNG_STRING_NEWLINE); 702 #else 703 PNG_UNUSED(warning_message) /* Make compiler happy */ 704 #endif 705 PNG_UNUSED(png_ptr) /* Make compiler happy */ 706 } 707 #endif /* WARNINGS */ 708 709 /* This function is called when the application wants to use another method 710 * of handling errors and warnings. Note that the error function MUST NOT 711 * return to the calling routine or serious problems will occur. The return 712 * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1) 713 */ 714 void PNGAPI 715 png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr, 716 png_error_ptr error_fn, png_error_ptr warning_fn) 717 { 718 if (png_ptr == NULL) 719 return; 720 721 png_ptr->error_ptr = error_ptr; 722 png_ptr->error_fn = error_fn; 723 #ifdef PNG_WARNINGS_SUPPORTED 724 png_ptr->warning_fn = warning_fn; 725 #else 726 PNG_UNUSED(warning_fn) 727 #endif 728 } 729 730 731 /* This function returns a pointer to the error_ptr associated with the user 732 * functions. The application should free any memory associated with this 733 * pointer before png_write_destroy and png_read_destroy are called. 734 */ 735 png_voidp PNGAPI 736 png_get_error_ptr(png_const_structrp png_ptr) 737 { 738 if (png_ptr == NULL) 739 return NULL; 740 741 return (png_voidp)png_ptr->error_ptr; 742 } 743 744 745 #ifdef PNG_ERROR_NUMBERS_SUPPORTED 746 void PNGAPI 747 png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode) 748 { 749 PNG_UNUSED(png_ptr) 750 PNG_UNUSED(strip_mode) 751 } 752 #endif 753 754 #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ 755 defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) 756 /* Currently the above both depend on SETJMP_SUPPORTED, however it would be 757 * possible to implement without setjmp support just so long as there is some 758 * way to handle the error return here: 759 */ 760 PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI 761 png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message), 762 PNG_NORETURN) 763 { 764 png_const_structrp png_ptr = png_nonconst_ptr; 765 png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); 766 767 /* An error is always logged here, overwriting anything (typically a warning) 768 * that is already there: 769 */ 770 if (image != NULL) 771 { 772 png_safecat(image->message, (sizeof image->message), 0, error_message); 773 image->warning_or_error |= PNG_IMAGE_ERROR; 774 775 /* Retrieve the jmp_buf from within the png_control, making this work for 776 * C++ compilation too is pretty tricky: C++ wants a pointer to the first 777 * element of a jmp_buf, but C doesn't tell us the type of that. 778 */ 779 if (image->opaque != NULL && image->opaque->error_buf != NULL) 780 longjmp(png_control_jmp_buf(image->opaque), 1); 781 782 /* Missing longjmp buffer, the following is to help debugging: */ 783 { 784 size_t pos = png_safecat(image->message, (sizeof image->message), 0, 785 "bad longjmp: "); 786 png_safecat(image->message, (sizeof image->message), pos, 787 error_message); 788 } 789 } 790 791 /* Here on an internal programming error. */ 792 abort(); 793 } 794 795 #ifdef PNG_WARNINGS_SUPPORTED 796 void /* PRIVATE */ PNGCBAPI 797 png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) 798 { 799 png_const_structrp png_ptr = png_nonconst_ptr; 800 png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); 801 802 /* A warning is only logged if there is no prior warning or error. */ 803 if (image->warning_or_error == 0) 804 { 805 png_safecat(image->message, (sizeof image->message), 0, warning_message); 806 image->warning_or_error |= PNG_IMAGE_WARNING; 807 } 808 } 809 #endif 810 811 int /* PRIVATE */ 812 png_safe_execute(png_imagep image, int (*function)(png_voidp), png_voidp arg) 813 { 814 const png_voidp saved_error_buf = image->opaque->error_buf; 815 jmp_buf safe_jmpbuf; 816 817 /* Safely execute function(arg), with png_error returning back here. */ 818 if (setjmp(safe_jmpbuf) == 0) 819 { 820 int result; 821 822 image->opaque->error_buf = safe_jmpbuf; 823 result = function(arg); 824 image->opaque->error_buf = saved_error_buf; 825 826 if (result) 827 return 1; /* success */ 828 } 829 830 /* The function failed either because of a caught png_error and a regular 831 * return of false above or because of an uncaught png_error from the 832 * function itself. Ensure that the error_buf is always set back to the 833 * value saved above: 834 */ 835 image->opaque->error_buf = saved_error_buf; 836 837 /* On the final false return, when about to return control to the caller, the 838 * image is freed (png_image_free does this check but it is duplicated here 839 * for clarity: 840 */ 841 if (saved_error_buf == NULL) 842 png_image_free(image); 843 844 return 0; /* failure */ 845 } 846 #endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */ 847 #endif /* READ || WRITE */