all repos — mgba @ 9de8f084ba55460b02d300c1dd8b8e6c56f691d5

mGBA Game Boy Advance Emulator

src/third-party/libpng/pngset.c (view raw)

   1
   2/* pngset.c - storage of image information into info struct
   3 *
   4 * Last changed in libpng 1.6.32 [August 24, 2017]
   5 * Copyright (c) 1998-2017 Glenn Randers-Pehrson
   6 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
   7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
   8 *
   9 * This code is released under the libpng license.
  10 * For conditions of distribution and use, see the disclaimer
  11 * and license in png.h
  12 *
  13 * The functions here are used during reads to store data from the file
  14 * into the info struct, and during writes to store application data
  15 * into the info struct for writing into the file.  This abstracts the
  16 * info struct and allows us to change the structure in the future.
  17 */
  18
  19#include "pngpriv.h"
  20
  21#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
  22
  23#ifdef PNG_bKGD_SUPPORTED
  24void PNGAPI
  25png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,
  26    png_const_color_16p background)
  27{
  28   png_debug1(1, "in %s storage function", "bKGD");
  29
  30   if (png_ptr == NULL || info_ptr == NULL || background == NULL)
  31      return;
  32
  33   info_ptr->background = *background;
  34   info_ptr->valid |= PNG_INFO_bKGD;
  35}
  36#endif
  37
  38#ifdef PNG_cHRM_SUPPORTED
  39void PNGFAPI
  40png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
  41    png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,
  42    png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
  43    png_fixed_point blue_x, png_fixed_point blue_y)
  44{
  45   png_xy xy;
  46
  47   png_debug1(1, "in %s storage function", "cHRM fixed");
  48
  49   if (png_ptr == NULL || info_ptr == NULL)
  50      return;
  51
  52   xy.redx = red_x;
  53   xy.redy = red_y;
  54   xy.greenx = green_x;
  55   xy.greeny = green_y;
  56   xy.bluex = blue_x;
  57   xy.bluey = blue_y;
  58   xy.whitex = white_x;
  59   xy.whitey = white_y;
  60
  61   if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy,
  62       2/* override with app values*/) != 0)
  63      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
  64
  65   png_colorspace_sync_info(png_ptr, info_ptr);
  66}
  67
  68void PNGFAPI
  69png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
  70    png_fixed_point int_red_X, png_fixed_point int_red_Y,
  71    png_fixed_point int_red_Z, png_fixed_point int_green_X,
  72    png_fixed_point int_green_Y, png_fixed_point int_green_Z,
  73    png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
  74    png_fixed_point int_blue_Z)
  75{
  76   png_XYZ XYZ;
  77
  78   png_debug1(1, "in %s storage function", "cHRM XYZ fixed");
  79
  80   if (png_ptr == NULL || info_ptr == NULL)
  81      return;
  82
  83   XYZ.red_X = int_red_X;
  84   XYZ.red_Y = int_red_Y;
  85   XYZ.red_Z = int_red_Z;
  86   XYZ.green_X = int_green_X;
  87   XYZ.green_Y = int_green_Y;
  88   XYZ.green_Z = int_green_Z;
  89   XYZ.blue_X = int_blue_X;
  90   XYZ.blue_Y = int_blue_Y;
  91   XYZ.blue_Z = int_blue_Z;
  92
  93   if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace,
  94       &XYZ, 2) != 0)
  95      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
  96
  97   png_colorspace_sync_info(png_ptr, info_ptr);
  98}
  99
 100#  ifdef PNG_FLOATING_POINT_SUPPORTED
 101void PNGAPI
 102png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
 103    double white_x, double white_y, double red_x, double red_y,
 104    double green_x, double green_y, double blue_x, double blue_y)
 105{
 106   png_set_cHRM_fixed(png_ptr, info_ptr,
 107       png_fixed(png_ptr, white_x, "cHRM White X"),
 108       png_fixed(png_ptr, white_y, "cHRM White Y"),
 109       png_fixed(png_ptr, red_x, "cHRM Red X"),
 110       png_fixed(png_ptr, red_y, "cHRM Red Y"),
 111       png_fixed(png_ptr, green_x, "cHRM Green X"),
 112       png_fixed(png_ptr, green_y, "cHRM Green Y"),
 113       png_fixed(png_ptr, blue_x, "cHRM Blue X"),
 114       png_fixed(png_ptr, blue_y, "cHRM Blue Y"));
 115}
 116
 117void PNGAPI
 118png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
 119    double red_Y, double red_Z, double green_X, double green_Y, double green_Z,
 120    double blue_X, double blue_Y, double blue_Z)
 121{
 122   png_set_cHRM_XYZ_fixed(png_ptr, info_ptr,
 123       png_fixed(png_ptr, red_X, "cHRM Red X"),
 124       png_fixed(png_ptr, red_Y, "cHRM Red Y"),
 125       png_fixed(png_ptr, red_Z, "cHRM Red Z"),
 126       png_fixed(png_ptr, green_X, "cHRM Green X"),
 127       png_fixed(png_ptr, green_Y, "cHRM Green Y"),
 128       png_fixed(png_ptr, green_Z, "cHRM Green Z"),
 129       png_fixed(png_ptr, blue_X, "cHRM Blue X"),
 130       png_fixed(png_ptr, blue_Y, "cHRM Blue Y"),
 131       png_fixed(png_ptr, blue_Z, "cHRM Blue Z"));
 132}
 133#  endif /* FLOATING_POINT */
 134
 135#endif /* cHRM */
 136
 137#ifdef PNG_eXIf_SUPPORTED
 138void PNGAPI
 139png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
 140    const png_bytep eXIf_buf)
 141{
 142  png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1");
 143  PNG_UNUSED(info_ptr)
 144  PNG_UNUSED(eXIf_buf)
 145}
 146
 147void PNGAPI
 148png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,
 149    const png_uint_32 num_exif, const png_bytep eXIf_buf)
 150{
 151   int i;
 152
 153   png_debug1(1, "in %s storage function", "eXIf");
 154
 155   if (png_ptr == NULL || info_ptr == NULL)
 156      return;
 157
 158   if (info_ptr->exif)
 159   {
 160      png_free(png_ptr, info_ptr->exif);
 161      info_ptr->exif = NULL;
 162   }
 163
 164   info_ptr->num_exif = num_exif;
 165
 166   info_ptr->exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr,
 167       info_ptr->num_exif));
 168
 169   if (info_ptr->exif == NULL)
 170   {
 171      png_warning(png_ptr, "Insufficient memory for eXIf chunk data");
 172      return;
 173   }
 174
 175   info_ptr->free_me |= PNG_FREE_EXIF;
 176
 177   for (i = 0; i < (int) info_ptr->num_exif; i++)
 178      info_ptr->exif[i] = eXIf_buf[i];
 179
 180   info_ptr->valid |= PNG_INFO_eXIf;
 181}
 182#endif /* eXIf */
 183
 184#ifdef PNG_gAMA_SUPPORTED
 185void PNGFAPI
 186png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
 187    png_fixed_point file_gamma)
 188{
 189   png_debug1(1, "in %s storage function", "gAMA");
 190
 191   if (png_ptr == NULL || info_ptr == NULL)
 192      return;
 193
 194   png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma);
 195   png_colorspace_sync_info(png_ptr, info_ptr);
 196}
 197
 198#  ifdef PNG_FLOATING_POINT_SUPPORTED
 199void PNGAPI
 200png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma)
 201{
 202   png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,
 203       "png_set_gAMA"));
 204}
 205#  endif
 206#endif
 207
 208#ifdef PNG_hIST_SUPPORTED
 209void PNGAPI
 210png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
 211    png_const_uint_16p hist)
 212{
 213   int i;
 214
 215   png_debug1(1, "in %s storage function", "hIST");
 216
 217   if (png_ptr == NULL || info_ptr == NULL)
 218      return;
 219
 220   if (info_ptr->num_palette == 0 || info_ptr->num_palette
 221       > PNG_MAX_PALETTE_LENGTH)
 222   {
 223      png_warning(png_ptr,
 224          "Invalid palette size, hIST allocation skipped");
 225
 226      return;
 227   }
 228
 229   png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
 230
 231   /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
 232    * version 1.2.1
 233    */
 234   info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr,
 235       PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));
 236
 237   if (info_ptr->hist == NULL)
 238   {
 239      png_warning(png_ptr, "Insufficient memory for hIST chunk data");
 240
 241      return;
 242   }
 243
 244   info_ptr->free_me |= PNG_FREE_HIST;
 245
 246   for (i = 0; i < info_ptr->num_palette; i++)
 247      info_ptr->hist[i] = hist[i];
 248
 249   info_ptr->valid |= PNG_INFO_hIST;
 250}
 251#endif
 252
 253void PNGAPI
 254png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,
 255    png_uint_32 width, png_uint_32 height, int bit_depth,
 256    int color_type, int interlace_type, int compression_type,
 257    int filter_type)
 258{
 259   png_debug1(1, "in %s storage function", "IHDR");
 260
 261   if (png_ptr == NULL || info_ptr == NULL)
 262      return;
 263
 264   info_ptr->width = width;
 265   info_ptr->height = height;
 266   info_ptr->bit_depth = (png_byte)bit_depth;
 267   info_ptr->color_type = (png_byte)color_type;
 268   info_ptr->compression_type = (png_byte)compression_type;
 269   info_ptr->filter_type = (png_byte)filter_type;
 270   info_ptr->interlace_type = (png_byte)interlace_type;
 271
 272   png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,
 273       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
 274       info_ptr->compression_type, info_ptr->filter_type);
 275
 276   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
 277      info_ptr->channels = 1;
 278
 279   else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
 280      info_ptr->channels = 3;
 281
 282   else
 283      info_ptr->channels = 1;
 284
 285   if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
 286      info_ptr->channels++;
 287
 288   info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
 289
 290   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
 291}
 292
 293#ifdef PNG_oFFs_SUPPORTED
 294void PNGAPI
 295png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr,
 296    png_int_32 offset_x, png_int_32 offset_y, int unit_type)
 297{
 298   png_debug1(1, "in %s storage function", "oFFs");
 299
 300   if (png_ptr == NULL || info_ptr == NULL)
 301      return;
 302
 303   info_ptr->x_offset = offset_x;
 304   info_ptr->y_offset = offset_y;
 305   info_ptr->offset_unit_type = (png_byte)unit_type;
 306   info_ptr->valid |= PNG_INFO_oFFs;
 307}
 308#endif
 309
 310#ifdef PNG_pCAL_SUPPORTED
 311void PNGAPI
 312png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
 313    png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type,
 314    int nparams, png_const_charp units, png_charpp params)
 315{
 316   png_size_t length;
 317   int i;
 318
 319   png_debug1(1, "in %s storage function", "pCAL");
 320
 321   if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL
 322       || (nparams > 0 && params == NULL))
 323      return;
 324
 325   length = strlen(purpose) + 1;
 326   png_debug1(3, "allocating purpose for info (%lu bytes)",
 327       (unsigned long)length);
 328
 329   /* TODO: validate format of calibration name and unit name */
 330
 331   /* Check that the type matches the specification. */
 332   if (type < 0 || type > 3)
 333   {
 334      png_chunk_report(png_ptr, "Invalid pCAL equation type",
 335            PNG_CHUNK_WRITE_ERROR);
 336      return;
 337   }
 338
 339   if (nparams < 0 || nparams > 255)
 340   {
 341      png_chunk_report(png_ptr, "Invalid pCAL parameter count",
 342            PNG_CHUNK_WRITE_ERROR);
 343      return;
 344   }
 345
 346   /* Validate params[nparams] */
 347   for (i=0; i<nparams; ++i)
 348   {
 349      if (params[i] == NULL ||
 350          !png_check_fp_string(params[i], strlen(params[i])))
 351      {
 352         png_chunk_report(png_ptr, "Invalid format for pCAL parameter",
 353               PNG_CHUNK_WRITE_ERROR);
 354         return;
 355      }
 356   }
 357
 358   info_ptr->pcal_purpose = png_voidcast(png_charp,
 359       png_malloc_warn(png_ptr, length));
 360
 361   if (info_ptr->pcal_purpose == NULL)
 362   {
 363      png_chunk_report(png_ptr, "Insufficient memory for pCAL purpose",
 364            PNG_CHUNK_WRITE_ERROR);
 365      return;
 366   }
 367
 368   memcpy(info_ptr->pcal_purpose, purpose, length);
 369
 370   png_debug(3, "storing X0, X1, type, and nparams in info");
 371   info_ptr->pcal_X0 = X0;
 372   info_ptr->pcal_X1 = X1;
 373   info_ptr->pcal_type = (png_byte)type;
 374   info_ptr->pcal_nparams = (png_byte)nparams;
 375
 376   length = strlen(units) + 1;
 377   png_debug1(3, "allocating units for info (%lu bytes)",
 378       (unsigned long)length);
 379
 380   info_ptr->pcal_units = png_voidcast(png_charp,
 381       png_malloc_warn(png_ptr, length));
 382
 383   if (info_ptr->pcal_units == NULL)
 384   {
 385      png_warning(png_ptr, "Insufficient memory for pCAL units");
 386
 387      return;
 388   }
 389
 390   memcpy(info_ptr->pcal_units, units, length);
 391
 392   info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,
 393       (png_size_t)(((unsigned int)nparams + 1) * (sizeof (png_charp)))));
 394
 395   if (info_ptr->pcal_params == NULL)
 396   {
 397      png_warning(png_ptr, "Insufficient memory for pCAL params");
 398
 399      return;
 400   }
 401
 402   memset(info_ptr->pcal_params, 0, ((unsigned int)nparams + 1) *
 403       (sizeof (png_charp)));
 404
 405   for (i = 0; i < nparams; i++)
 406   {
 407      length = strlen(params[i]) + 1;
 408      png_debug2(3, "allocating parameter %d for info (%lu bytes)", i,
 409          (unsigned long)length);
 410
 411      info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length);
 412
 413      if (info_ptr->pcal_params[i] == NULL)
 414      {
 415         png_warning(png_ptr, "Insufficient memory for pCAL parameter");
 416
 417         return;
 418      }
 419
 420      memcpy(info_ptr->pcal_params[i], params[i], length);
 421   }
 422
 423   info_ptr->valid |= PNG_INFO_pCAL;
 424   info_ptr->free_me |= PNG_FREE_PCAL;
 425}
 426#endif
 427
 428#ifdef PNG_sCAL_SUPPORTED
 429void PNGAPI
 430png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,
 431    int unit, png_const_charp swidth, png_const_charp sheight)
 432{
 433   png_size_t lengthw = 0, lengthh = 0;
 434
 435   png_debug1(1, "in %s storage function", "sCAL");
 436
 437   if (png_ptr == NULL || info_ptr == NULL)
 438      return;
 439
 440   /* Double check the unit (should never get here with an invalid
 441    * unit unless this is an API call.)
 442    */
 443   if (unit != 1 && unit != 2)
 444      png_error(png_ptr, "Invalid sCAL unit");
 445
 446   if (swidth == NULL || (lengthw = strlen(swidth)) == 0 ||
 447       swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw))
 448      png_error(png_ptr, "Invalid sCAL width");
 449
 450   if (sheight == NULL || (lengthh = strlen(sheight)) == 0 ||
 451       sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh))
 452      png_error(png_ptr, "Invalid sCAL height");
 453
 454   info_ptr->scal_unit = (png_byte)unit;
 455
 456   ++lengthw;
 457
 458   png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw);
 459
 460   info_ptr->scal_s_width = png_voidcast(png_charp,
 461       png_malloc_warn(png_ptr, lengthw));
 462
 463   if (info_ptr->scal_s_width == NULL)
 464   {
 465      png_warning(png_ptr, "Memory allocation failed while processing sCAL");
 466
 467      return;
 468   }
 469
 470   memcpy(info_ptr->scal_s_width, swidth, lengthw);
 471
 472   ++lengthh;
 473
 474   png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh);
 475
 476   info_ptr->scal_s_height = png_voidcast(png_charp,
 477       png_malloc_warn(png_ptr, lengthh));
 478
 479   if (info_ptr->scal_s_height == NULL)
 480   {
 481      png_free (png_ptr, info_ptr->scal_s_width);
 482      info_ptr->scal_s_width = NULL;
 483
 484      png_warning(png_ptr, "Memory allocation failed while processing sCAL");
 485
 486      return;
 487   }
 488
 489   memcpy(info_ptr->scal_s_height, sheight, lengthh);
 490
 491   info_ptr->valid |= PNG_INFO_sCAL;
 492   info_ptr->free_me |= PNG_FREE_SCAL;
 493}
 494
 495#  ifdef PNG_FLOATING_POINT_SUPPORTED
 496void PNGAPI
 497png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
 498    double width, double height)
 499{
 500   png_debug1(1, "in %s storage function", "sCAL");
 501
 502   /* Check the arguments. */
 503   if (width <= 0)
 504      png_warning(png_ptr, "Invalid sCAL width ignored");
 505
 506   else if (height <= 0)
 507      png_warning(png_ptr, "Invalid sCAL height ignored");
 508
 509   else
 510   {
 511      /* Convert 'width' and 'height' to ASCII. */
 512      char swidth[PNG_sCAL_MAX_DIGITS+1];
 513      char sheight[PNG_sCAL_MAX_DIGITS+1];
 514
 515      png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width,
 516          PNG_sCAL_PRECISION);
 517      png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height,
 518          PNG_sCAL_PRECISION);
 519
 520      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
 521   }
 522}
 523#  endif
 524
 525#  ifdef PNG_FIXED_POINT_SUPPORTED
 526void PNGAPI
 527png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
 528    png_fixed_point width, png_fixed_point height)
 529{
 530   png_debug1(1, "in %s storage function", "sCAL");
 531
 532   /* Check the arguments. */
 533   if (width <= 0)
 534      png_warning(png_ptr, "Invalid sCAL width ignored");
 535
 536   else if (height <= 0)
 537      png_warning(png_ptr, "Invalid sCAL height ignored");
 538
 539   else
 540   {
 541      /* Convert 'width' and 'height' to ASCII. */
 542      char swidth[PNG_sCAL_MAX_DIGITS+1];
 543      char sheight[PNG_sCAL_MAX_DIGITS+1];
 544
 545      png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width);
 546      png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height);
 547
 548      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
 549   }
 550}
 551#  endif
 552#endif
 553
 554#ifdef PNG_pHYs_SUPPORTED
 555void PNGAPI
 556png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr,
 557    png_uint_32 res_x, png_uint_32 res_y, int unit_type)
 558{
 559   png_debug1(1, "in %s storage function", "pHYs");
 560
 561   if (png_ptr == NULL || info_ptr == NULL)
 562      return;
 563
 564   info_ptr->x_pixels_per_unit = res_x;
 565   info_ptr->y_pixels_per_unit = res_y;
 566   info_ptr->phys_unit_type = (png_byte)unit_type;
 567   info_ptr->valid |= PNG_INFO_pHYs;
 568}
 569#endif
 570
 571void PNGAPI
 572png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
 573    png_const_colorp palette, int num_palette)
 574{
 575
 576   png_uint_32 max_palette_length;
 577
 578   png_debug1(1, "in %s storage function", "PLTE");
 579
 580   if (png_ptr == NULL || info_ptr == NULL)
 581      return;
 582
 583   max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
 584      (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
 585
 586   if (num_palette < 0 || num_palette > (int) max_palette_length)
 587   {
 588      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
 589         png_error(png_ptr, "Invalid palette length");
 590
 591      else
 592      {
 593         png_warning(png_ptr, "Invalid palette length");
 594
 595         return;
 596      }
 597   }
 598
 599   if ((num_palette > 0 && palette == NULL) ||
 600      (num_palette == 0
 601#        ifdef PNG_MNG_FEATURES_SUPPORTED
 602            && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0
 603#        endif
 604      ))
 605   {
 606      png_error(png_ptr, "Invalid palette");
 607   }
 608
 609   /* It may not actually be necessary to set png_ptr->palette here;
 610    * we do it for backward compatibility with the way the png_handle_tRNS
 611    * function used to do the allocation.
 612    *
 613    * 1.6.0: the above statement appears to be incorrect; something has to set
 614    * the palette inside png_struct on read.
 615    */
 616   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
 617
 618   /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
 619    * of num_palette entries, in case of an invalid PNG file or incorrect
 620    * call to png_set_PLTE() with too-large sample values.
 621    */
 622   png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
 623       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
 624
 625   if (num_palette > 0)
 626      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
 627          (sizeof (png_color)));
 628   info_ptr->palette = png_ptr->palette;
 629   info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
 630
 631   info_ptr->free_me |= PNG_FREE_PLTE;
 632
 633   info_ptr->valid |= PNG_INFO_PLTE;
 634}
 635
 636#ifdef PNG_sBIT_SUPPORTED
 637void PNGAPI
 638png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,
 639    png_const_color_8p sig_bit)
 640{
 641   png_debug1(1, "in %s storage function", "sBIT");
 642
 643   if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)
 644      return;
 645
 646   info_ptr->sig_bit = *sig_bit;
 647   info_ptr->valid |= PNG_INFO_sBIT;
 648}
 649#endif
 650
 651#ifdef PNG_sRGB_SUPPORTED
 652void PNGAPI
 653png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)
 654{
 655   png_debug1(1, "in %s storage function", "sRGB");
 656
 657   if (png_ptr == NULL || info_ptr == NULL)
 658      return;
 659
 660   (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent);
 661   png_colorspace_sync_info(png_ptr, info_ptr);
 662}
 663
 664void PNGAPI
 665png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
 666    int srgb_intent)
 667{
 668   png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");
 669
 670   if (png_ptr == NULL || info_ptr == NULL)
 671      return;
 672
 673   if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace,
 674       srgb_intent) != 0)
 675   {
 676      /* This causes the gAMA and cHRM to be written too */
 677      info_ptr->colorspace.flags |=
 678         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
 679   }
 680
 681   png_colorspace_sync_info(png_ptr, info_ptr);
 682}
 683#endif /* sRGB */
 684
 685
 686#ifdef PNG_iCCP_SUPPORTED
 687void PNGAPI
 688png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
 689    png_const_charp name, int compression_type,
 690    png_const_bytep profile, png_uint_32 proflen)
 691{
 692   png_charp new_iccp_name;
 693   png_bytep new_iccp_profile;
 694   png_size_t length;
 695
 696   png_debug1(1, "in %s storage function", "iCCP");
 697
 698   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
 699      return;
 700
 701   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
 702      png_app_error(png_ptr, "Invalid iCCP compression method");
 703
 704   /* Set the colorspace first because this validates the profile; do not
 705    * override previously set app cHRM or gAMA here (because likely as not the
 706    * application knows better than libpng what the correct values are.)  Pass
 707    * the info_ptr color_type field to png_colorspace_set_ICC because in the
 708    * write case it has not yet been stored in png_ptr.
 709    */
 710   {
 711      int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,
 712          proflen, profile, info_ptr->color_type);
 713
 714      png_colorspace_sync_info(png_ptr, info_ptr);
 715
 716      /* Don't do any of the copying if the profile was bad, or inconsistent. */
 717      if (result == 0)
 718         return;
 719
 720      /* But do write the gAMA and cHRM chunks from the profile. */
 721      info_ptr->colorspace.flags |=
 722         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
 723   }
 724
 725   length = strlen(name)+1;
 726   new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));
 727
 728   if (new_iccp_name == NULL)
 729   {
 730      png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");
 731
 732      return;
 733   }
 734
 735   memcpy(new_iccp_name, name, length);
 736   new_iccp_profile = png_voidcast(png_bytep,
 737       png_malloc_warn(png_ptr, proflen));
 738
 739   if (new_iccp_profile == NULL)
 740   {
 741      png_free(png_ptr, new_iccp_name);
 742      png_benign_error(png_ptr,
 743          "Insufficient memory to process iCCP profile");
 744
 745      return;
 746   }
 747
 748   memcpy(new_iccp_profile, profile, proflen);
 749
 750   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
 751
 752   info_ptr->iccp_proflen = proflen;
 753   info_ptr->iccp_name = new_iccp_name;
 754   info_ptr->iccp_profile = new_iccp_profile;
 755   info_ptr->free_me |= PNG_FREE_ICCP;
 756   info_ptr->valid |= PNG_INFO_iCCP;
 757}
 758#endif
 759
 760#ifdef PNG_TEXT_SUPPORTED
 761void PNGAPI
 762png_set_text(png_const_structrp png_ptr, png_inforp info_ptr,
 763    png_const_textp text_ptr, int num_text)
 764{
 765   int ret;
 766   ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
 767
 768   if (ret != 0)
 769      png_error(png_ptr, "Insufficient memory to store text");
 770}
 771
 772int /* PRIVATE */
 773png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
 774    png_const_textp text_ptr, int num_text)
 775{
 776   int i;
 777
 778   png_debug1(1, "in %lx storage function", png_ptr == NULL ? 0xabadca11U :
 779      (unsigned long)png_ptr->chunk_name);
 780
 781   if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)
 782      return(0);
 783
 784   /* Make sure we have enough space in the "text" array in info_struct
 785    * to hold all of the incoming text_ptr objects.  This compare can't overflow
 786    * because max_text >= num_text (anyway, subtract of two positive integers
 787    * can't overflow in any case.)
 788    */
 789   if (num_text > info_ptr->max_text - info_ptr->num_text)
 790   {
 791      int old_num_text = info_ptr->num_text;
 792      int max_text;
 793      png_textp new_text = NULL;
 794
 795      /* Calculate an appropriate max_text, checking for overflow. */
 796      max_text = old_num_text;
 797      if (num_text <= INT_MAX - max_text)
 798      {
 799         max_text += num_text;
 800
 801         /* Round up to a multiple of 8 */
 802         if (max_text < INT_MAX-8)
 803            max_text = (max_text + 8) & ~0x7;
 804
 805         else
 806            max_text = INT_MAX;
 807
 808         /* Now allocate a new array and copy the old members in; this does all
 809          * the overflow checks.
 810          */
 811         new_text = png_voidcast(png_textp,png_realloc_array(png_ptr,
 812             info_ptr->text, old_num_text, max_text-old_num_text,
 813             sizeof *new_text));
 814      }
 815
 816      if (new_text == NULL)
 817      {
 818         png_chunk_report(png_ptr, "too many text chunks",
 819             PNG_CHUNK_WRITE_ERROR);
 820
 821         return 1;
 822      }
 823
 824      png_free(png_ptr, info_ptr->text);
 825
 826      info_ptr->text = new_text;
 827      info_ptr->free_me |= PNG_FREE_TEXT;
 828      info_ptr->max_text = max_text;
 829      /* num_text is adjusted below as the entries are copied in */
 830
 831      png_debug1(3, "allocated %d entries for info_ptr->text", max_text);
 832   }
 833
 834   for (i = 0; i < num_text; i++)
 835   {
 836      size_t text_length, key_len;
 837      size_t lang_len, lang_key_len;
 838      png_textp textp = &(info_ptr->text[info_ptr->num_text]);
 839
 840      if (text_ptr[i].key == NULL)
 841          continue;
 842
 843      if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
 844          text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)
 845      {
 846         png_chunk_report(png_ptr, "text compression mode is out of range",
 847             PNG_CHUNK_WRITE_ERROR);
 848         continue;
 849      }
 850
 851      key_len = strlen(text_ptr[i].key);
 852
 853      if (text_ptr[i].compression <= 0)
 854      {
 855         lang_len = 0;
 856         lang_key_len = 0;
 857      }
 858
 859      else
 860#  ifdef PNG_iTXt_SUPPORTED
 861      {
 862         /* Set iTXt data */
 863
 864         if (text_ptr[i].lang != NULL)
 865            lang_len = strlen(text_ptr[i].lang);
 866
 867         else
 868            lang_len = 0;
 869
 870         if (text_ptr[i].lang_key != NULL)
 871            lang_key_len = strlen(text_ptr[i].lang_key);
 872
 873         else
 874            lang_key_len = 0;
 875      }
 876#  else /* iTXt */
 877      {
 878         png_chunk_report(png_ptr, "iTXt chunk not supported",
 879             PNG_CHUNK_WRITE_ERROR);
 880         continue;
 881      }
 882#  endif
 883
 884      if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
 885      {
 886         text_length = 0;
 887#  ifdef PNG_iTXt_SUPPORTED
 888         if (text_ptr[i].compression > 0)
 889            textp->compression = PNG_ITXT_COMPRESSION_NONE;
 890
 891         else
 892#  endif
 893            textp->compression = PNG_TEXT_COMPRESSION_NONE;
 894      }
 895
 896      else
 897      {
 898         text_length = strlen(text_ptr[i].text);
 899         textp->compression = text_ptr[i].compression;
 900      }
 901
 902      textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr,
 903          key_len + text_length + lang_len + lang_key_len + 4));
 904
 905      if (textp->key == NULL)
 906      {
 907         png_chunk_report(png_ptr, "text chunk: out of memory",
 908             PNG_CHUNK_WRITE_ERROR);
 909
 910         return 1;
 911      }
 912
 913      png_debug2(2, "Allocated %lu bytes at %p in png_set_text",
 914          (unsigned long)(png_uint_32)
 915          (key_len + lang_len + lang_key_len + text_length + 4),
 916          textp->key);
 917
 918      memcpy(textp->key, text_ptr[i].key, key_len);
 919      *(textp->key + key_len) = '\0';
 920
 921      if (text_ptr[i].compression > 0)
 922      {
 923         textp->lang = textp->key + key_len + 1;
 924         memcpy(textp->lang, text_ptr[i].lang, lang_len);
 925         *(textp->lang + lang_len) = '\0';
 926         textp->lang_key = textp->lang + lang_len + 1;
 927         memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
 928         *(textp->lang_key + lang_key_len) = '\0';
 929         textp->text = textp->lang_key + lang_key_len + 1;
 930      }
 931
 932      else
 933      {
 934         textp->lang=NULL;
 935         textp->lang_key=NULL;
 936         textp->text = textp->key + key_len + 1;
 937      }
 938
 939      if (text_length != 0)
 940         memcpy(textp->text, text_ptr[i].text, text_length);
 941
 942      *(textp->text + text_length) = '\0';
 943
 944#  ifdef PNG_iTXt_SUPPORTED
 945      if (textp->compression > 0)
 946      {
 947         textp->text_length = 0;
 948         textp->itxt_length = text_length;
 949      }
 950
 951      else
 952#  endif
 953      {
 954         textp->text_length = text_length;
 955         textp->itxt_length = 0;
 956      }
 957
 958      info_ptr->num_text++;
 959      png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
 960   }
 961
 962   return(0);
 963}
 964#endif
 965
 966#ifdef PNG_tIME_SUPPORTED
 967void PNGAPI
 968png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr,
 969    png_const_timep mod_time)
 970{
 971   png_debug1(1, "in %s storage function", "tIME");
 972
 973   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
 974       (png_ptr->mode & PNG_WROTE_tIME) != 0)
 975      return;
 976
 977   if (mod_time->month == 0   || mod_time->month > 12  ||
 978       mod_time->day   == 0   || mod_time->day   > 31  ||
 979       mod_time->hour  > 23   || mod_time->minute > 59 ||
 980       mod_time->second > 60)
 981   {
 982      png_warning(png_ptr, "Ignoring invalid time value");
 983
 984      return;
 985   }
 986
 987   info_ptr->mod_time = *mod_time;
 988   info_ptr->valid |= PNG_INFO_tIME;
 989}
 990#endif
 991
 992#ifdef PNG_tRNS_SUPPORTED
 993void PNGAPI
 994png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
 995    png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)
 996{
 997   png_debug1(1, "in %s storage function", "tRNS");
 998
 999   if (png_ptr == NULL || info_ptr == NULL)
1000
1001      return;
1002
1003   if (trans_alpha != NULL)
1004   {
1005       /* It may not actually be necessary to set png_ptr->trans_alpha here;
1006        * we do it for backward compatibility with the way the png_handle_tRNS
1007        * function used to do the allocation.
1008        *
1009        * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
1010        * relies on png_set_tRNS storing the information in png_struct
1011        * (otherwise it won't be there for the code in pngrtran.c).
1012        */
1013
1014       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
1015
1016       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
1017       {
1018         /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
1019          info_ptr->trans_alpha = png_voidcast(png_bytep,
1020              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
1021          memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans);
1022       }
1023       png_ptr->trans_alpha = info_ptr->trans_alpha;
1024   }
1025
1026   if (trans_color != NULL)
1027   {
1028#ifdef PNG_WARNINGS_SUPPORTED
1029      if (info_ptr->bit_depth < 16)
1030      {
1031         int sample_max = (1 << info_ptr->bit_depth) - 1;
1032
1033         if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
1034             trans_color->gray > sample_max) ||
1035             (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
1036             (trans_color->red > sample_max ||
1037             trans_color->green > sample_max ||
1038             trans_color->blue > sample_max)))
1039            png_warning(png_ptr,
1040                "tRNS chunk has out-of-range samples for bit_depth");
1041      }
1042#endif
1043
1044      info_ptr->trans_color = *trans_color;
1045
1046      if (num_trans == 0)
1047         num_trans = 1;
1048   }
1049
1050   info_ptr->num_trans = (png_uint_16)num_trans;
1051
1052   if (num_trans != 0)
1053   {
1054      info_ptr->valid |= PNG_INFO_tRNS;
1055      info_ptr->free_me |= PNG_FREE_TRNS;
1056   }
1057}
1058#endif
1059
1060#ifdef PNG_sPLT_SUPPORTED
1061void PNGAPI
1062png_set_sPLT(png_const_structrp png_ptr,
1063    png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)
1064/*
1065 *  entries        - array of png_sPLT_t structures
1066 *                   to be added to the list of palettes
1067 *                   in the info structure.
1068 *
1069 *  nentries       - number of palette structures to be
1070 *                   added.
1071 */
1072{
1073   png_sPLT_tp np;
1074
1075   if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)
1076      return;
1077
1078   /* Use the internal realloc function, which checks for all the possible
1079    * overflows.  Notice that the parameters are (int) and (size_t)
1080    */
1081   np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr,
1082       info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,
1083       sizeof *np));
1084
1085   if (np == NULL)
1086   {
1087      /* Out of memory or too many chunks */
1088      png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
1089
1090      return;
1091   }
1092
1093   png_free(png_ptr, info_ptr->splt_palettes);
1094   info_ptr->splt_palettes = np;
1095   info_ptr->free_me |= PNG_FREE_SPLT;
1096
1097   np += info_ptr->splt_palettes_num;
1098
1099   do
1100   {
1101      png_size_t length;
1102
1103      /* Skip invalid input entries */
1104      if (entries->name == NULL || entries->entries == NULL)
1105      {
1106         /* png_handle_sPLT doesn't do this, so this is an app error */
1107         png_app_error(png_ptr, "png_set_sPLT: invalid sPLT");
1108         /* Just skip the invalid entry */
1109         continue;
1110      }
1111
1112      np->depth = entries->depth;
1113
1114      /* In the event of out-of-memory just return - there's no point keeping
1115       * on trying to add sPLT chunks.
1116       */
1117      length = strlen(entries->name) + 1;
1118      np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length));
1119
1120      if (np->name == NULL)
1121         break;
1122
1123      memcpy(np->name, entries->name, length);
1124
1125      /* IMPORTANT: we have memory now that won't get freed if something else
1126       * goes wrong; this code must free it.  png_malloc_array produces no
1127       * warnings; use a png_chunk_report (below) if there is an error.
1128       */
1129      np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr,
1130          entries->nentries, sizeof (png_sPLT_entry)));
1131
1132      if (np->entries == NULL)
1133      {
1134         png_free(png_ptr, np->name);
1135         np->name = NULL;
1136         break;
1137      }
1138
1139      np->nentries = entries->nentries;
1140      /* This multiply can't overflow because png_malloc_array has already
1141       * checked it when doing the allocation.
1142       */
1143      memcpy(np->entries, entries->entries,
1144          (unsigned int)entries->nentries * sizeof (png_sPLT_entry));
1145
1146      /* Note that 'continue' skips the advance of the out pointer and out
1147       * count, so an invalid entry is not added.
1148       */
1149      info_ptr->valid |= PNG_INFO_sPLT;
1150      ++(info_ptr->splt_palettes_num);
1151      ++np;
1152      ++entries;
1153   }
1154   while (--nentries);
1155
1156   if (nentries > 0)
1157      png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
1158}
1159#endif /* sPLT */
1160
1161#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
1162static png_byte
1163check_location(png_const_structrp png_ptr, int location)
1164{
1165   location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);
1166
1167   /* New in 1.6.0; copy the location and check it.  This is an API
1168    * change; previously the app had to use the
1169    * png_set_unknown_chunk_location API below for each chunk.
1170    */
1171   if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1172   {
1173      /* Write struct, so unknown chunks come from the app */
1174      png_app_warning(png_ptr,
1175          "png_set_unknown_chunks now expects a valid location");
1176      /* Use the old behavior */
1177      location = (png_byte)(png_ptr->mode &
1178          (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));
1179   }
1180
1181   /* This need not be an internal error - if the app calls
1182    * png_set_unknown_chunks on a read pointer it must get the location right.
1183    */
1184   if (location == 0)
1185      png_error(png_ptr, "invalid location in png_set_unknown_chunks");
1186
1187   /* Now reduce the location to the top-most set bit by removing each least
1188    * significant bit in turn.
1189    */
1190   while (location != (location & -location))
1191      location &= ~(location & -location);
1192
1193   /* The cast is safe because 'location' is a bit mask and only the low four
1194    * bits are significant.
1195    */
1196   return (png_byte)location;
1197}
1198
1199void PNGAPI
1200png_set_unknown_chunks(png_const_structrp png_ptr,
1201    png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
1202{
1203   png_unknown_chunkp np;
1204
1205   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
1206       unknowns == NULL)
1207      return;
1208
1209   /* Check for the failure cases where support has been disabled at compile
1210    * time.  This code is hardly ever compiled - it's here because
1211    * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this
1212    * code) but may be meaningless if the read or write handling of unknown
1213    * chunks is not compiled in.
1214    */
1215#  if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \
1216      defined(PNG_READ_SUPPORTED)
1217      if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
1218      {
1219         png_app_error(png_ptr, "no unknown chunk support on read");
1220
1221         return;
1222      }
1223#  endif
1224#  if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \
1225      defined(PNG_WRITE_SUPPORTED)
1226      if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1227      {
1228         png_app_error(png_ptr, "no unknown chunk support on write");
1229
1230         return;
1231      }
1232#  endif
1233
1234   /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that
1235    * unknown critical chunks could be lost with just a warning resulting in
1236    * undefined behavior.  Now png_chunk_report is used to provide behavior
1237    * appropriate to read or write.
1238    */
1239   np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr,
1240       info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
1241       sizeof *np));
1242
1243   if (np == NULL)
1244   {
1245      png_chunk_report(png_ptr, "too many unknown chunks",
1246          PNG_CHUNK_WRITE_ERROR);
1247
1248      return;
1249   }
1250
1251   png_free(png_ptr, info_ptr->unknown_chunks);
1252   info_ptr->unknown_chunks = np; /* safe because it is initialized */
1253   info_ptr->free_me |= PNG_FREE_UNKN;
1254
1255   np += info_ptr->unknown_chunks_num;
1256
1257   /* Increment unknown_chunks_num each time round the loop to protect the
1258    * just-allocated chunk data.
1259    */
1260   for (; num_unknowns > 0; --num_unknowns, ++unknowns)
1261   {
1262      memcpy(np->name, unknowns->name, (sizeof np->name));
1263      np->name[(sizeof np->name)-1] = '\0';
1264      np->location = check_location(png_ptr, unknowns->location);
1265
1266      if (unknowns->size == 0)
1267      {
1268         np->data = NULL;
1269         np->size = 0;
1270      }
1271
1272      else
1273      {
1274         np->data = png_voidcast(png_bytep,
1275             png_malloc_base(png_ptr, unknowns->size));
1276
1277         if (np->data == NULL)
1278         {
1279            png_chunk_report(png_ptr, "unknown chunk: out of memory",
1280                PNG_CHUNK_WRITE_ERROR);
1281            /* But just skip storing the unknown chunk */
1282            continue;
1283         }
1284
1285         memcpy(np->data, unknowns->data, unknowns->size);
1286         np->size = unknowns->size;
1287      }
1288
1289      /* These increments are skipped on out-of-memory for the data - the
1290       * unknown chunk entry gets overwritten if the png_chunk_report returns.
1291       * This is correct in the read case (the chunk is just dropped.)
1292       */
1293      ++np;
1294      ++(info_ptr->unknown_chunks_num);
1295   }
1296}
1297
1298void PNGAPI
1299png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,
1300    int chunk, int location)
1301{
1302   /* This API is pretty pointless in 1.6.0 because the location can be set
1303    * before the call to png_set_unknown_chunks.
1304    *
1305    * TODO: add a png_app_warning in 1.7
1306    */
1307   if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
1308      chunk < info_ptr->unknown_chunks_num)
1309   {
1310      if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
1311      {
1312         png_app_error(png_ptr, "invalid unknown chunk location");
1313         /* Fake out the pre 1.6.0 behavior: */
1314         if (((unsigned int)location & PNG_HAVE_IDAT) != 0) /* undocumented! */
1315            location = PNG_AFTER_IDAT;
1316
1317         else
1318            location = PNG_HAVE_IHDR; /* also undocumented */
1319      }
1320
1321      info_ptr->unknown_chunks[chunk].location =
1322         check_location(png_ptr, location);
1323   }
1324}
1325#endif /* STORE_UNKNOWN_CHUNKS */
1326
1327#ifdef PNG_MNG_FEATURES_SUPPORTED
1328png_uint_32 PNGAPI
1329png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features)
1330{
1331   png_debug(1, "in png_permit_mng_features");
1332
1333   if (png_ptr == NULL)
1334      return 0;
1335
1336   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
1337
1338   return png_ptr->mng_features_permitted;
1339}
1340#endif
1341
1342#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
1343static unsigned int
1344add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep)
1345{
1346   unsigned int i;
1347
1348   /* Utility function: update the 'keep' state of a chunk if it is already in
1349    * the list, otherwise add it to the list.
1350    */
1351   for (i=0; i<count; ++i, list += 5)
1352   {
1353      if (memcmp(list, add, 4) == 0)
1354      {
1355         list[4] = (png_byte)keep;
1356
1357         return count;
1358      }
1359   }
1360
1361   if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)
1362   {
1363      ++count;
1364      memcpy(list, add, 4);
1365      list[4] = (png_byte)keep;
1366   }
1367
1368   return count;
1369}
1370
1371void PNGAPI
1372png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,
1373    png_const_bytep chunk_list, int num_chunks_in)
1374{
1375   png_bytep new_list;
1376   unsigned int num_chunks, old_num_chunks;
1377
1378   if (png_ptr == NULL)
1379      return;
1380
1381   if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST)
1382   {
1383      png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");
1384
1385      return;
1386   }
1387
1388   if (num_chunks_in <= 0)
1389   {
1390      png_ptr->unknown_default = keep;
1391
1392      /* '0' means just set the flags, so stop here */
1393      if (num_chunks_in == 0)
1394        return;
1395   }
1396
1397   if (num_chunks_in < 0)
1398   {
1399      /* Ignore all unknown chunks and all chunks recognized by
1400       * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND
1401       */
1402      static PNG_CONST png_byte chunks_to_ignore[] = {
1403         98,  75,  71,  68, '\0',  /* bKGD */
1404         99,  72,  82,  77, '\0',  /* cHRM */
1405        101,  88,  73, 102, '\0',  /* eXIf */
1406        103,  65,  77,  65, '\0',  /* gAMA */
1407        104,  73,  83,  84, '\0',  /* hIST */
1408        105,  67,  67,  80, '\0',  /* iCCP */
1409        105,  84,  88, 116, '\0',  /* iTXt */
1410        111,  70,  70, 115, '\0',  /* oFFs */
1411        112,  67,  65,  76, '\0',  /* pCAL */
1412        112,  72,  89, 115, '\0',  /* pHYs */
1413        115,  66,  73,  84, '\0',  /* sBIT */
1414        115,  67,  65,  76, '\0',  /* sCAL */
1415        115,  80,  76,  84, '\0',  /* sPLT */
1416        115,  84,  69,  82, '\0',  /* sTER */
1417        115,  82,  71,  66, '\0',  /* sRGB */
1418        116,  69,  88, 116, '\0',  /* tEXt */
1419        116,  73,  77,  69, '\0',  /* tIME */
1420        122,  84,  88, 116, '\0'   /* zTXt */
1421      };
1422
1423      chunk_list = chunks_to_ignore;
1424      num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U;
1425   }
1426
1427   else /* num_chunks_in > 0 */
1428   {
1429      if (chunk_list == NULL)
1430      {
1431         /* Prior to 1.6.0 this was silently ignored, now it is an app_error
1432          * which can be switched off.
1433          */
1434         png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");
1435
1436         return;
1437      }
1438
1439      num_chunks = (unsigned int)num_chunks_in;
1440   }
1441
1442   old_num_chunks = png_ptr->num_chunk_list;
1443   if (png_ptr->chunk_list == NULL)
1444      old_num_chunks = 0;
1445
1446   /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
1447    */
1448   if (num_chunks + old_num_chunks > UINT_MAX/5)
1449   {
1450      png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks");
1451
1452      return;
1453   }
1454
1455   /* If these chunks are being reset to the default then no more memory is
1456    * required because add_one_chunk above doesn't extend the list if the 'keep'
1457    * parameter is the default.
1458    */
1459   if (keep != 0)
1460   {
1461      new_list = png_voidcast(png_bytep, png_malloc(png_ptr,
1462          5 * (num_chunks + old_num_chunks)));
1463
1464      if (old_num_chunks > 0)
1465         memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
1466   }
1467
1468   else if (old_num_chunks > 0)
1469      new_list = png_ptr->chunk_list;
1470
1471   else
1472      new_list = NULL;
1473
1474   /* Add the new chunks together with each one's handling code.  If the chunk
1475    * already exists the code is updated, otherwise the chunk is added to the
1476    * end.  (In libpng 1.6.0 order no longer matters because this code enforces
1477    * the earlier convention that the last setting is the one that is used.)
1478    */
1479   if (new_list != NULL)
1480   {
1481      png_const_bytep inlist;
1482      png_bytep outlist;
1483      unsigned int i;
1484
1485      for (i=0; i<num_chunks; ++i)
1486      {
1487         old_num_chunks = add_one_chunk(new_list, old_num_chunks,
1488             chunk_list+5*i, keep);
1489      }
1490
1491      /* Now remove any spurious 'default' entries. */
1492      num_chunks = 0;
1493      for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
1494      {
1495         if (inlist[4])
1496         {
1497            if (outlist != inlist)
1498               memcpy(outlist, inlist, 5);
1499            outlist += 5;
1500            ++num_chunks;
1501         }
1502      }
1503
1504      /* This means the application has removed all the specialized handling. */
1505      if (num_chunks == 0)
1506      {
1507         if (png_ptr->chunk_list != new_list)
1508            png_free(png_ptr, new_list);
1509
1510         new_list = NULL;
1511      }
1512   }
1513
1514   else
1515      num_chunks = 0;
1516
1517   png_ptr->num_chunk_list = num_chunks;
1518
1519   if (png_ptr->chunk_list != new_list)
1520   {
1521      if (png_ptr->chunk_list != NULL)
1522         png_free(png_ptr, png_ptr->chunk_list);
1523
1524      png_ptr->chunk_list = new_list;
1525   }
1526}
1527#endif
1528
1529#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
1530void PNGAPI
1531png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr,
1532    png_user_chunk_ptr read_user_chunk_fn)
1533{
1534   png_debug(1, "in png_set_read_user_chunk_fn");
1535
1536   if (png_ptr == NULL)
1537      return;
1538
1539   png_ptr->read_user_chunk_fn = read_user_chunk_fn;
1540   png_ptr->user_chunk_ptr = user_chunk_ptr;
1541}
1542#endif
1543
1544#ifdef PNG_INFO_IMAGE_SUPPORTED
1545void PNGAPI
1546png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
1547    png_bytepp row_pointers)
1548{
1549   png_debug1(1, "in %s storage function", "rows");
1550
1551   if (png_ptr == NULL || info_ptr == NULL)
1552      return;
1553
1554   if (info_ptr->row_pointers != NULL &&
1555       (info_ptr->row_pointers != row_pointers))
1556      png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
1557
1558   info_ptr->row_pointers = row_pointers;
1559
1560   if (row_pointers != NULL)
1561      info_ptr->valid |= PNG_INFO_IDAT;
1562}
1563#endif
1564
1565void PNGAPI
1566png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size)
1567{
1568   if (png_ptr == NULL)
1569      return;
1570
1571   if (size == 0 || size > PNG_UINT_31_MAX)
1572      png_error(png_ptr, "invalid compression buffer size");
1573
1574#  ifdef PNG_SEQUENTIAL_READ_SUPPORTED
1575   if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
1576   {
1577      png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */
1578      return;
1579   }
1580#  endif
1581
1582#  ifdef PNG_WRITE_SUPPORTED
1583   if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1584   {
1585      if (png_ptr->zowner != 0)
1586      {
1587         png_warning(png_ptr,
1588             "Compression buffer size cannot be changed because it is in use");
1589
1590         return;
1591      }
1592
1593#ifndef __COVERITY__
1594      /* Some compilers complain that this is always false.  However, it
1595       * can be true when integer overflow happens.
1596       */
1597      if (size > ZLIB_IO_MAX)
1598      {
1599         png_warning(png_ptr,
1600             "Compression buffer size limited to system maximum");
1601         size = ZLIB_IO_MAX; /* must fit */
1602      }
1603#endif
1604
1605      if (size < 6)
1606      {
1607         /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH
1608          * if this is permitted.
1609          */
1610         png_warning(png_ptr,
1611             "Compression buffer size cannot be reduced below 6");
1612
1613         return;
1614      }
1615
1616      if (png_ptr->zbuffer_size != size)
1617      {
1618         png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
1619         png_ptr->zbuffer_size = (uInt)size;
1620      }
1621   }
1622#  endif
1623}
1624
1625void PNGAPI
1626png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)
1627{
1628   if (png_ptr != NULL && info_ptr != NULL)
1629      info_ptr->valid &= (unsigned int)(~mask);
1630}
1631
1632
1633#ifdef PNG_SET_USER_LIMITS_SUPPORTED
1634/* This function was added to libpng 1.2.6 */
1635void PNGAPI
1636png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
1637    png_uint_32 user_height_max)
1638{
1639   /* Images with dimensions larger than these limits will be
1640    * rejected by png_set_IHDR().  To accept any PNG datastream
1641    * regardless of dimensions, set both limits to 0x7fffffff.
1642    */
1643   if (png_ptr == NULL)
1644      return;
1645
1646   png_ptr->user_width_max = user_width_max;
1647   png_ptr->user_height_max = user_height_max;
1648}
1649
1650/* This function was added to libpng 1.4.0 */
1651void PNGAPI
1652png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
1653{
1654   if (png_ptr != NULL)
1655      png_ptr->user_chunk_cache_max = user_chunk_cache_max;
1656}
1657
1658/* This function was added to libpng 1.4.1 */
1659void PNGAPI
1660png_set_chunk_malloc_max (png_structrp png_ptr,
1661    png_alloc_size_t user_chunk_malloc_max)
1662{
1663   if (png_ptr != NULL)
1664      png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
1665}
1666#endif /* ?SET_USER_LIMITS */
1667
1668
1669#ifdef PNG_BENIGN_ERRORS_SUPPORTED
1670void PNGAPI
1671png_set_benign_errors(png_structrp png_ptr, int allowed)
1672{
1673   png_debug(1, "in png_set_benign_errors");
1674
1675   /* If allowed is 1, png_benign_error() is treated as a warning.
1676    *
1677    * If allowed is 0, png_benign_error() is treated as an error (which
1678    * is the default behavior if png_set_benign_errors() is not called).
1679    */
1680
1681   if (allowed != 0)
1682      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
1683         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;
1684
1685   else
1686      png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |
1687         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);
1688}
1689#endif /* BENIGN_ERRORS */
1690
1691#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
1692   /* Whether to report invalid palette index; added at libng-1.5.10.
1693    * It is possible for an indexed (color-type==3) PNG file to contain
1694    * pixels with invalid (out-of-range) indexes if the PLTE chunk has
1695    * fewer entries than the image's bit-depth would allow. We recover
1696    * from this gracefully by filling any incomplete palette with zeros
1697    * (opaque black).  By default, when this occurs libpng will issue
1698    * a benign error.  This API can be used to override that behavior.
1699    */
1700void PNGAPI
1701png_set_check_for_invalid_index(png_structrp png_ptr, int allowed)
1702{
1703   png_debug(1, "in png_set_check_for_invalid_index");
1704
1705   if (allowed > 0)
1706      png_ptr->num_palette_max = 0;
1707
1708   else
1709      png_ptr->num_palette_max = -1;
1710}
1711#endif
1712
1713#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \
1714    defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
1715/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
1716 * and if invalid, correct the keyword rather than discarding the entire
1717 * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in
1718 * length, forbids leading or trailing whitespace, multiple internal spaces,
1719 * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.
1720 *
1721 * The 'new_key' buffer must be 80 characters in size (for the keyword plus a
1722 * trailing '\0').  If this routine returns 0 then there was no keyword, or a
1723 * valid one could not be generated, and the caller must png_error.
1724 */
1725png_uint_32 /* PRIVATE */
1726png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key)
1727{
1728#ifdef PNG_WARNINGS_SUPPORTED
1729   png_const_charp orig_key = key;
1730#endif
1731   png_uint_32 key_len = 0;
1732   int bad_character = 0;
1733   int space = 1;
1734
1735   png_debug(1, "in png_check_keyword");
1736
1737   if (key == NULL)
1738   {
1739      *new_key = 0;
1740      return 0;
1741   }
1742
1743   while (*key && key_len < 79)
1744   {
1745      png_byte ch = (png_byte)*key++;
1746
1747      if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
1748      {
1749         *new_key++ = ch; ++key_len; space = 0;
1750      }
1751
1752      else if (space == 0)
1753      {
1754         /* A space or an invalid character when one wasn't seen immediately
1755          * before; output just a space.
1756          */
1757         *new_key++ = 32; ++key_len; space = 1;
1758
1759         /* If the character was not a space then it is invalid. */
1760         if (ch != 32)
1761            bad_character = ch;
1762      }
1763
1764      else if (bad_character == 0)
1765         bad_character = ch; /* just skip it, record the first error */
1766   }
1767
1768   if (key_len > 0 && space != 0) /* trailing space */
1769   {
1770      --key_len; --new_key;
1771      if (bad_character == 0)
1772         bad_character = 32;
1773   }
1774
1775   /* Terminate the keyword */
1776   *new_key = 0;
1777
1778   if (key_len == 0)
1779      return 0;
1780
1781#ifdef PNG_WARNINGS_SUPPORTED
1782   /* Try to only output one warning per keyword: */
1783   if (*key != 0) /* keyword too long */
1784      png_warning(png_ptr, "keyword truncated");
1785
1786   else if (bad_character != 0)
1787   {
1788      PNG_WARNING_PARAMETERS(p)
1789
1790      png_warning_parameter(p, 1, orig_key);
1791      png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);
1792
1793      png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");
1794   }
1795#else /* !WARNINGS */
1796   PNG_UNUSED(png_ptr)
1797#endif /* !WARNINGS */
1798
1799   return key_len;
1800}
1801#endif /* TEXT || pCAL || iCCP || sPLT */
1802#endif /* READ || WRITE */