media/libpng/pngerror.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial