Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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