/lib_png/base/libpng-1.6.16/contrib/libtests/pngvalid.c
C | 10595 lines | 7015 code | 1570 blank | 2010 comment | 1600 complexity | e1d608dbe15242bcd4d13bdfda584db7 MD5 | raw file
Possible License(s): Zlib, BSD-3-Clause, CC0-1.0, GPL-3.0, GPL-2.0, CPL-1.0, MPL-2.0-no-copyleft-exception, LGPL-2.0, LGPL-2.1, LGPL-3.0, 0BSD, Cube
Large files files are truncated, but you can click here to view the full file
- /* pngvalid.c - validate libpng by constructing then reading png files.
- *
- * Last changed in libpng 1.6.14 [October 23, 2014]
- * Copyright (c) 2014 Glenn Randers-Pehrson
- * Written by John Cunningham Bowler
- *
- * This code is released under the libpng license.
- * For conditions of distribution and use, see the disclaimer
- * and license in png.h
- *
- * NOTES:
- * This is a C program that is intended to be linked against libpng. It
- * generates bitmaps internally, stores them as PNG files (using the
- * sequential write code) then reads them back (using the sequential
- * read code) and validates that the result has the correct data.
- *
- * The program can be modified and extended to test the correctness of
- * transformations performed by libpng.
- */
- #define _POSIX_SOURCE 1
- #define _ISOC99_SOURCE 1 /* For floating point */
- #define _GNU_SOURCE 1 /* For the floating point exception extension */
- #include <signal.h>
- #include <stdio.h>
- #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
- # include <config.h>
- #endif
- #ifdef HAVE_FEENABLEEXCEPT /* from config.h, if included */
- # include <fenv.h>
- #endif
- #ifndef FE_DIVBYZERO
- # define FE_DIVBYZERO 0
- #endif
- #ifndef FE_INVALID
- # define FE_INVALID 0
- #endif
- #ifndef FE_OVERFLOW
- # define FE_OVERFLOW 0
- #endif
- /* Define the following to use this test against your installed libpng, rather
- * than the one being built here:
- */
- #ifdef PNG_FREESTANDING_TESTS
- # include <png.h>
- #else
- # include "../../png.h"
- #endif
- #ifdef PNG_ZLIB_HEADER
- # include PNG_ZLIB_HEADER
- #else
- # include <zlib.h> /* For crc32 */
- #endif
- /* 1.6.1 added support for the configure test harness, which uses 77 to indicate
- * a skipped test, in earlier versions we need to succeed on a skipped test, so:
- */
- #if PNG_LIBPNG_VER < 10601
- # define SKIP 0
- #else
- # define SKIP 77
- #endif
- /* pngvalid requires write support and one of the fixed or floating point APIs.
- */
- #if defined(PNG_WRITE_SUPPORTED) &&\
- (defined(PNG_FIXED_POINT_SUPPORTED) || defined(PNG_FLOATING_POINT_SUPPORTED))
- #if PNG_LIBPNG_VER < 10500
- /* This deliberately lacks the PNG_CONST. */
- typedef png_byte *png_const_bytep;
- /* This is copied from 1.5.1 png.h: */
- #define PNG_INTERLACE_ADAM7_PASSES 7
- #define PNG_PASS_START_ROW(pass) (((1U&~(pass))<<(3-((pass)>>1)))&7)
- #define PNG_PASS_START_COL(pass) (((1U& (pass))<<(3-(((pass)+1)>>1)))&7)
- #define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3)
- #define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3)
- #define PNG_PASS_ROWS(height, pass) (((height)+(((1<<PNG_PASS_ROW_SHIFT(pass))\
- -1)-PNG_PASS_START_ROW(pass)))>>PNG_PASS_ROW_SHIFT(pass))
- #define PNG_PASS_COLS(width, pass) (((width)+(((1<<PNG_PASS_COL_SHIFT(pass))\
- -1)-PNG_PASS_START_COL(pass)))>>PNG_PASS_COL_SHIFT(pass))
- #define PNG_ROW_FROM_PASS_ROW(yIn, pass) \
- (((yIn)<<PNG_PASS_ROW_SHIFT(pass))+PNG_PASS_START_ROW(pass))
- #define PNG_COL_FROM_PASS_COL(xIn, pass) \
- (((xIn)<<PNG_PASS_COL_SHIFT(pass))+PNG_PASS_START_COL(pass))
- #define PNG_PASS_MASK(pass,off) ( \
- ((0x110145AFU>>(((7-(off))-(pass))<<2)) & 0xFU) | \
- ((0x01145AF0U>>(((7-(off))-(pass))<<2)) & 0xF0U))
- #define PNG_ROW_IN_INTERLACE_PASS(y, pass) \
- ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1)
- #define PNG_COL_IN_INTERLACE_PASS(x, pass) \
- ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1)
- /* These are needed too for the default build: */
- #define PNG_WRITE_16BIT_SUPPORTED
- #define PNG_READ_16BIT_SUPPORTED
- /* This comes from pnglibconf.h afer 1.5: */
- #define PNG_FP_1 100000
- #define PNG_GAMMA_THRESHOLD_FIXED\
- ((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1))
- #endif
- #if PNG_LIBPNG_VER < 10600
- /* 1.6.0 constifies many APIs, the following exists to allow pngvalid to be
- * compiled against earlier versions.
- */
- # define png_const_structp png_structp
- #endif
- #include <float.h> /* For floating point constants */
- #include <stdlib.h> /* For malloc */
- #include <string.h> /* For memcpy, memset */
- #include <math.h> /* For floor */
- /* Unused formal parameter errors are removed using the following macro which is
- * expected to have no bad effects on performance.
- */
- #ifndef UNUSED
- # if defined(__GNUC__) || defined(_MSC_VER)
- # define UNUSED(param) (void)param;
- # else
- # define UNUSED(param)
- # endif
- #endif
- /***************************** EXCEPTION HANDLING *****************************/
- #ifdef PNG_FREESTANDING_TESTS
- # include <cexcept.h>
- #else
- # include "../visupng/cexcept.h"
- #endif
- #ifdef __cplusplus
- # define this not_the_cpp_this
- # define new not_the_cpp_new
- # define voidcast(type, value) static_cast<type>(value)
- #else
- # define voidcast(type, value) (value)
- #endif /* __cplusplus */
- struct png_store;
- define_exception_type(struct png_store*);
- /* The following are macros to reduce typing everywhere where the well known
- * name 'the_exception_context' must be defined.
- */
- #define anon_context(ps) struct exception_context *the_exception_context = \
- &(ps)->exception_context
- #define context(ps,fault) anon_context(ps); png_store *fault
- /* This macro returns the number of elements in an array as an (unsigned int),
- * it is necessary to avoid the inability of certain versions of GCC to use
- * the value of a compile-time constant when performing range checks. It must
- * be passed an array name.
- */
- #define ARRAY_SIZE(a) ((unsigned int)((sizeof (a))/(sizeof (a)[0])))
- /******************************* UTILITIES ************************************/
- /* Error handling is particularly problematic in production code - error
- * handlers often themselves have bugs which lead to programs that detect
- * minor errors crashing. The following functions deal with one very
- * common class of errors in error handlers - attempting to format error or
- * warning messages into buffers that are too small.
- */
- static size_t safecat(char *buffer, size_t bufsize, size_t pos,
- PNG_CONST char *cat)
- {
- while (pos < bufsize && cat != NULL && *cat != 0)
- buffer[pos++] = *cat++;
- if (pos >= bufsize)
- pos = bufsize-1;
- buffer[pos] = 0;
- return pos;
- }
- static size_t safecatn(char *buffer, size_t bufsize, size_t pos, int n)
- {
- char number[64];
- sprintf(number, "%d", n);
- return safecat(buffer, bufsize, pos, number);
- }
- #ifdef PNG_READ_TRANSFORMS_SUPPORTED
- static size_t safecatd(char *buffer, size_t bufsize, size_t pos, double d,
- int precision)
- {
- char number[64];
- sprintf(number, "%.*f", precision, d);
- return safecat(buffer, bufsize, pos, number);
- }
- #endif
- static PNG_CONST char invalid[] = "invalid";
- static PNG_CONST char sep[] = ": ";
- static PNG_CONST char *colour_types[8] =
- {
- "grayscale", invalid, "truecolour", "indexed-colour",
- "grayscale with alpha", invalid, "truecolour with alpha", invalid
- };
- #ifdef PNG_READ_SUPPORTED
- /* Convert a double precision value to fixed point. */
- static png_fixed_point
- fix(double d)
- {
- d = floor(d * PNG_FP_1 + .5);
- return (png_fixed_point)d;
- }
- #endif /* PNG_READ_SUPPORTED */
- /* Generate random bytes. This uses a boring repeatable algorithm and it
- * is implemented here so that it gives the same set of numbers on every
- * architecture. It's a linear congruential generator (Knuth or Sedgewick
- * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and
- * Hill, "The Art of Electronics" (Pseudo-Random Bit Sequences and Noise
- * Generation.)
- */
- static void
- make_random_bytes(png_uint_32* seed, void* pv, size_t size)
- {
- png_uint_32 u0 = seed[0], u1 = seed[1];
- png_bytep bytes = voidcast(png_bytep, pv);
- /* There are thirty three bits, the next bit in the sequence is bit-33 XOR
- * bit-20. The top 1 bit is in u1, the bottom 32 are in u0.
- */
- size_t i;
- for (i=0; i<size; ++i)
- {
- /* First generate 8 new bits then shift them in at the end. */
- png_uint_32 u = ((u0 >> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff;
- u1 <<= 8;
- u1 |= u0 >> 24;
- u0 <<= 8;
- u0 |= u;
- *bytes++ = (png_byte)u;
- }
- seed[0] = u0;
- seed[1] = u1;
- }
- static void
- make_four_random_bytes(png_uint_32* seed, png_bytep bytes)
- {
- make_random_bytes(seed, bytes, 4);
- }
- #ifdef PNG_READ_SUPPORTED
- static void
- randomize(void *pv, size_t size)
- {
- static png_uint_32 random_seed[2] = {0x56789abc, 0xd};
- make_random_bytes(random_seed, pv, size);
- }
- #define RANDOMIZE(this) randomize(&(this), sizeof (this))
- static unsigned int
- random_mod(unsigned int max)
- {
- unsigned int x;
- RANDOMIZE(x);
- return x % max; /* 0 .. max-1 */
- }
- #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
- static int
- random_choice(void)
- {
- unsigned char x;
- RANDOMIZE(x);
- return x & 1;
- }
- #endif
- #endif /* PNG_READ_SUPPORTED */
- /* A numeric ID based on PNG file characteristics. The 'do_interlace' field
- * simply records whether pngvalid did the interlace itself or whether it
- * was done by libpng. Width and height must be less than 256. 'palette' is an
- * index of the palette to use for formats with a palette (0 otherwise.)
- */
- #define FILEID(col, depth, palette, interlace, width, height, do_interlace) \
- ((png_uint_32)((col) + ((depth)<<3) + ((palette)<<8) + ((interlace)<<13) + \
- (((do_interlace)!=0)<<15) + ((width)<<16) + ((height)<<24)))
- #define COL_FROM_ID(id) ((png_byte)((id)& 0x7U))
- #define DEPTH_FROM_ID(id) ((png_byte)(((id) >> 3) & 0x1fU))
- #define PALETTE_FROM_ID(id) (((id) >> 8) & 0x1f)
- #define INTERLACE_FROM_ID(id) ((int)(((id) >> 13) & 0x3))
- #define DO_INTERLACE_FROM_ID(id) ((int)(((id)>>15) & 1))
- #define WIDTH_FROM_ID(id) (((id)>>16) & 0xff)
- #define HEIGHT_FROM_ID(id) (((id)>>24) & 0xff)
- /* Utility to construct a standard name for a standard image. */
- static size_t
- standard_name(char *buffer, size_t bufsize, size_t pos, png_byte colour_type,
- int bit_depth, unsigned int npalette, int interlace_type,
- png_uint_32 w, png_uint_32 h, int do_interlace)
- {
- pos = safecat(buffer, bufsize, pos, colour_types[colour_type]);
- if (npalette > 0)
- {
- pos = safecat(buffer, bufsize, pos, "[");
- pos = safecatn(buffer, bufsize, pos, npalette);
- pos = safecat(buffer, bufsize, pos, "]");
- }
- pos = safecat(buffer, bufsize, pos, " ");
- pos = safecatn(buffer, bufsize, pos, bit_depth);
- pos = safecat(buffer, bufsize, pos, " bit");
- if (interlace_type != PNG_INTERLACE_NONE)
- {
- pos = safecat(buffer, bufsize, pos, " interlaced");
- if (do_interlace)
- pos = safecat(buffer, bufsize, pos, "(pngvalid)");
- else
- pos = safecat(buffer, bufsize, pos, "(libpng)");
- }
- if (w > 0 || h > 0)
- {
- pos = safecat(buffer, bufsize, pos, " ");
- pos = safecatn(buffer, bufsize, pos, w);
- pos = safecat(buffer, bufsize, pos, "x");
- pos = safecatn(buffer, bufsize, pos, h);
- }
- return pos;
- }
- static size_t
- standard_name_from_id(char *buffer, size_t bufsize, size_t pos, png_uint_32 id)
- {
- return standard_name(buffer, bufsize, pos, COL_FROM_ID(id),
- DEPTH_FROM_ID(id), PALETTE_FROM_ID(id), INTERLACE_FROM_ID(id),
- WIDTH_FROM_ID(id), HEIGHT_FROM_ID(id), DO_INTERLACE_FROM_ID(id));
- }
- /* Convenience API and defines to list valid formats. Note that 16 bit read and
- * write support is required to do 16 bit read tests (we must be able to make a
- * 16 bit image to test!)
- */
- #ifdef PNG_WRITE_16BIT_SUPPORTED
- # define WRITE_BDHI 4
- # ifdef PNG_READ_16BIT_SUPPORTED
- # define READ_BDHI 4
- # define DO_16BIT
- # endif
- #else
- # define WRITE_BDHI 3
- #endif
- #ifndef DO_16BIT
- # define READ_BDHI 3
- #endif
- /* The following defines the number of different palettes to generate for
- * each log bit depth of a colour type 3 standard image.
- */
- #define PALETTE_COUNT(bit_depth) ((bit_depth) > 4 ? 1U : 16U)
- static int
- next_format(png_bytep colour_type, png_bytep bit_depth,
- unsigned int* palette_number, int no_low_depth_gray)
- {
- if (*bit_depth == 0)
- {
- *colour_type = 0;
- if (no_low_depth_gray)
- *bit_depth = 8;
- else
- *bit_depth = 1;
- *palette_number = 0;
- return 1;
- }
- if (*colour_type == 3)
- {
- /* Add multiple palettes for colour type 3. */
- if (++*palette_number < PALETTE_COUNT(*bit_depth))
- return 1;
- *palette_number = 0;
- }
- *bit_depth = (png_byte)(*bit_depth << 1);
- /* Palette images are restricted to 8 bit depth */
- if (*bit_depth <= 8
- #ifdef DO_16BIT
- || (*colour_type != 3 && *bit_depth <= 16)
- #endif
- )
- return 1;
- /* Move to the next color type, or return 0 at the end. */
- switch (*colour_type)
- {
- case 0:
- *colour_type = 2;
- *bit_depth = 8;
- return 1;
- case 2:
- *colour_type = 3;
- *bit_depth = 1;
- return 1;
- case 3:
- *colour_type = 4;
- *bit_depth = 8;
- return 1;
- case 4:
- *colour_type = 6;
- *bit_depth = 8;
- return 1;
- default:
- return 0;
- }
- }
- #ifdef PNG_READ_TRANSFORMS_SUPPORTED
- static unsigned int
- sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth,
- png_uint_32 x, unsigned int sample_index)
- {
- png_uint_32 bit_index, result;
- /* Find a sample index for the desired sample: */
- x *= bit_depth;
- bit_index = x;
- if ((colour_type & 1) == 0) /* !palette */
- {
- if (colour_type & 2)
- bit_index *= 3;
- if (colour_type & 4)
- bit_index += x; /* Alpha channel */
- /* Multiple channels; select one: */
- if (colour_type & (2+4))
- bit_index += sample_index * bit_depth;
- }
- /* Return the sample from the row as an integer. */
- row += bit_index >> 3;
- result = *row;
- if (bit_depth == 8)
- return result;
- else if (bit_depth > 8)
- return (result << 8) + *++row;
- /* Less than 8 bits per sample. */
- bit_index &= 7;
- return (result >> (8-bit_index-bit_depth)) & ((1U<<bit_depth)-1);
- }
- #endif /* PNG_READ_TRANSFORMS_SUPPORTED */
- /* Copy a single pixel, of a given size, from one buffer to another -
- * while this is basically bit addressed there is an implicit assumption
- * that pixels 8 or more bits in size are byte aligned and that pixels
- * do not otherwise cross byte boundaries. (This is, so far as I know,
- * universally true in bitmap computer graphics. [JCB 20101212])
- *
- * NOTE: The to and from buffers may be the same.
- */
- static void
- pixel_copy(png_bytep toBuffer, png_uint_32 toIndex,
- png_const_bytep fromBuffer, png_uint_32 fromIndex, unsigned int pixelSize)
- {
- /* Assume we can multiply by 'size' without overflow because we are
- * just working in a single buffer.
- */
- toIndex *= pixelSize;
- fromIndex *= pixelSize;
- if (pixelSize < 8) /* Sub-byte */
- {
- /* Mask to select the location of the copied pixel: */
- unsigned int destMask = ((1U<<pixelSize)-1) << (8-pixelSize-(toIndex&7));
- /* The following read the entire pixels and clears the extra: */
- unsigned int destByte = toBuffer[toIndex >> 3] & ~destMask;
- unsigned int sourceByte = fromBuffer[fromIndex >> 3];
- /* Don't rely on << or >> supporting '0' here, just in case: */
- fromIndex &= 7;
- if (fromIndex > 0) sourceByte <<= fromIndex;
- if ((toIndex & 7) > 0) sourceByte >>= toIndex & 7;
- toBuffer[toIndex >> 3] = (png_byte)(destByte | (sourceByte & destMask));
- }
- else /* One or more bytes */
- memmove(toBuffer+(toIndex>>3), fromBuffer+(fromIndex>>3), pixelSize>>3);
- }
- #ifdef PNG_READ_SUPPORTED
- /* Copy a complete row of pixels, taking into account potential partial
- * bytes at the end.
- */
- static void
- row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth)
- {
- memcpy(toBuffer, fromBuffer, bitWidth >> 3);
- if ((bitWidth & 7) != 0)
- {
- unsigned int mask;
- toBuffer += bitWidth >> 3;
- fromBuffer += bitWidth >> 3;
- /* The remaining bits are in the top of the byte, the mask is the bits to
- * retain.
- */
- mask = 0xff >> (bitWidth & 7);
- *toBuffer = (png_byte)((*toBuffer & mask) | (*fromBuffer & ~mask));
- }
- }
- /* Compare pixels - they are assumed to start at the first byte in the
- * given buffers.
- */
- static int
- pixel_cmp(png_const_bytep pa, png_const_bytep pb, png_uint_32 bit_width)
- {
- #if PNG_LIBPNG_VER < 10506
- if (memcmp(pa, pb, bit_width>>3) == 0)
- {
- png_uint_32 p;
- if ((bit_width & 7) == 0) return 0;
- /* Ok, any differences? */
- p = pa[bit_width >> 3];
- p ^= pb[bit_width >> 3];
- if (p == 0) return 0;
- /* There are, but they may not be significant, remove the bits
- * after the end (the low order bits in PNG.)
- */
- bit_width &= 7;
- p >>= 8-bit_width;
- if (p == 0) return 0;
- }
- #else
- /* From libpng-1.5.6 the overwrite should be fixed, so compare the trailing
- * bits too:
- */
- if (memcmp(pa, pb, (bit_width+7)>>3) == 0)
- return 0;
- #endif
- /* Return the index of the changed byte. */
- {
- png_uint_32 where = 0;
- while (pa[where] == pb[where]) ++where;
- return 1+where;
- }
- }
- #endif /* PNG_READ_SUPPORTED */
- /*************************** BASIC PNG FILE WRITING ***************************/
- /* A png_store takes data from the sequential writer or provides data
- * to the sequential reader. It can also store the result of a PNG
- * write for later retrieval.
- */
- #define STORE_BUFFER_SIZE 500 /* arbitrary */
- typedef struct png_store_buffer
- {
- struct png_store_buffer* prev; /* NOTE: stored in reverse order */
- png_byte buffer[STORE_BUFFER_SIZE];
- } png_store_buffer;
- #define FILE_NAME_SIZE 64
- typedef struct store_palette_entry /* record of a single palette entry */
- {
- png_byte red;
- png_byte green;
- png_byte blue;
- png_byte alpha;
- } store_palette_entry, store_palette[256];
- typedef struct png_store_file
- {
- struct png_store_file* next; /* as many as you like... */
- char name[FILE_NAME_SIZE];
- png_uint_32 id; /* must be correct (see FILEID) */
- png_size_t datacount; /* In this (the last) buffer */
- png_store_buffer data; /* Last buffer in file */
- int npalette; /* Number of entries in palette */
- store_palette_entry* palette; /* May be NULL */
- } png_store_file;
- /* The following is a pool of memory allocated by a single libpng read or write
- * operation.
- */
- typedef struct store_pool
- {
- struct png_store *store; /* Back pointer */
- struct store_memory *list; /* List of allocated memory */
- png_byte mark[4]; /* Before and after data */
- /* Statistics for this run. */
- png_alloc_size_t max; /* Maximum single allocation */
- png_alloc_size_t current; /* Current allocation */
- png_alloc_size_t limit; /* Highest current allocation */
- png_alloc_size_t total; /* Total allocation */
- /* Overall statistics (retained across successive runs). */
- png_alloc_size_t max_max;
- png_alloc_size_t max_limit;
- png_alloc_size_t max_total;
- } store_pool;
- typedef struct png_store
- {
- /* For cexcept.h exception handling - simply store one of these;
- * the context is a self pointer but it may point to a different
- * png_store (in fact it never does in this program.)
- */
- struct exception_context
- exception_context;
- unsigned int verbose :1;
- unsigned int treat_warnings_as_errors :1;
- unsigned int expect_error :1;
- unsigned int expect_warning :1;
- unsigned int saw_warning :1;
- unsigned int speed :1;
- unsigned int progressive :1; /* use progressive read */
- unsigned int validated :1; /* used as a temporary flag */
- int nerrors;
- int nwarnings;
- int noptions; /* number of options below: */
- struct {
- unsigned char option; /* option number, 0..30 */
- unsigned char setting; /* setting (unset,invalid,on,off) */
- } options[16];
- char test[128]; /* Name of test */
- char error[256];
- /* Read fields */
- png_structp pread; /* Used to read a saved file */
- png_infop piread;
- png_store_file* current; /* Set when reading */
- png_store_buffer* next; /* Set when reading */
- png_size_t readpos; /* Position in *next */
- png_byte* image; /* Buffer for reading interlaced images */
- png_size_t cb_image; /* Size of this buffer */
- png_size_t cb_row; /* Row size of the image(s) */
- png_uint_32 image_h; /* Number of rows in a single image */
- store_pool read_memory_pool;
- /* Write fields */
- png_store_file* saved;
- png_structp pwrite; /* Used when writing a new file */
- png_infop piwrite;
- png_size_t writepos; /* Position in .new */
- char wname[FILE_NAME_SIZE];
- png_store_buffer new; /* The end of the new PNG file being written. */
- store_pool write_memory_pool;
- store_palette_entry* palette;
- int npalette;
- } png_store;
- /* Initialization and cleanup */
- static void
- store_pool_mark(png_bytep mark)
- {
- static png_uint_32 store_seed[2] = { 0x12345678, 1};
- make_four_random_bytes(store_seed, mark);
- }
- #ifdef PNG_READ_SUPPORTED
- /* Use this for random 32 bit values; this function makes sure the result is
- * non-zero.
- */
- static png_uint_32
- random_32(void)
- {
- for (;;)
- {
- png_byte mark[4];
- png_uint_32 result;
- store_pool_mark(mark);
- result = png_get_uint_32(mark);
- if (result != 0)
- return result;
- }
- }
- #endif /* PNG_READ_SUPPORTED */
- static void
- store_pool_init(png_store *ps, store_pool *pool)
- {
- memset(pool, 0, sizeof *pool);
- pool->store = ps;
- pool->list = NULL;
- pool->max = pool->current = pool->limit = pool->total = 0;
- pool->max_max = pool->max_limit = pool->max_total = 0;
- store_pool_mark(pool->mark);
- }
- static void
- store_init(png_store* ps)
- {
- memset(ps, 0, sizeof *ps);
- init_exception_context(&ps->exception_context);
- store_pool_init(ps, &ps->read_memory_pool);
- store_pool_init(ps, &ps->write_memory_pool);
- ps->verbose = 0;
- ps->treat_warnings_as_errors = 0;
- ps->expect_error = 0;
- ps->expect_warning = 0;
- ps->saw_warning = 0;
- ps->speed = 0;
- ps->progressive = 0;
- ps->validated = 0;
- ps->nerrors = ps->nwarnings = 0;
- ps->pread = NULL;
- ps->piread = NULL;
- ps->saved = ps->current = NULL;
- ps->next = NULL;
- ps->readpos = 0;
- ps->image = NULL;
- ps->cb_image = 0;
- ps->cb_row = 0;
- ps->image_h = 0;
- ps->pwrite = NULL;
- ps->piwrite = NULL;
- ps->writepos = 0;
- ps->new.prev = NULL;
- ps->palette = NULL;
- ps->npalette = 0;
- ps->noptions = 0;
- }
- static void
- store_freebuffer(png_store_buffer* psb)
- {
- if (psb->prev)
- {
- store_freebuffer(psb->prev);
- free(psb->prev);
- psb->prev = NULL;
- }
- }
- static void
- store_freenew(png_store *ps)
- {
- store_freebuffer(&ps->new);
- ps->writepos = 0;
- if (ps->palette != NULL)
- {
- free(ps->palette);
- ps->palette = NULL;
- ps->npalette = 0;
- }
- }
- static void
- store_storenew(png_store *ps)
- {
- png_store_buffer *pb;
- if (ps->writepos != STORE_BUFFER_SIZE)
- png_error(ps->pwrite, "invalid store call");
- pb = voidcast(png_store_buffer*, malloc(sizeof *pb));
- if (pb == NULL)
- png_error(ps->pwrite, "store new: OOM");
- *pb = ps->new;
- ps->new.prev = pb;
- ps->writepos = 0;
- }
- static void
- store_freefile(png_store_file **ppf)
- {
- if (*ppf != NULL)
- {
- store_freefile(&(*ppf)->next);
- store_freebuffer(&(*ppf)->data);
- (*ppf)->datacount = 0;
- if ((*ppf)->palette != NULL)
- {
- free((*ppf)->palette);
- (*ppf)->palette = NULL;
- (*ppf)->npalette = 0;
- }
- free(*ppf);
- *ppf = NULL;
- }
- }
- /* Main interface to file storeage, after writing a new PNG file (see the API
- * below) call store_storefile to store the result with the given name and id.
- */
- static void
- store_storefile(png_store *ps, png_uint_32 id)
- {
- png_store_file *pf = voidcast(png_store_file*, malloc(sizeof *pf));
- if (pf == NULL)
- png_error(ps->pwrite, "storefile: OOM");
- safecat(pf->name, sizeof pf->name, 0, ps->wname);
- pf->id = id;
- pf->data = ps->new;
- pf->datacount = ps->writepos;
- ps->new.prev = NULL;
- ps->writepos = 0;
- pf->palette = ps->palette;
- pf->npalette = ps->npalette;
- ps->palette = 0;
- ps->npalette = 0;
- /* And save it. */
- pf->next = ps->saved;
- ps->saved = pf;
- }
- /* Generate an error message (in the given buffer) */
- static size_t
- store_message(png_store *ps, png_const_structp pp, char *buffer, size_t bufsize,
- size_t pos, PNG_CONST char *msg)
- {
- if (pp != NULL && pp == ps->pread)
- {
- /* Reading a file */
- pos = safecat(buffer, bufsize, pos, "read: ");
- if (ps->current != NULL)
- {
- pos = safecat(buffer, bufsize, pos, ps->current->name);
- pos = safecat(buffer, bufsize, pos, sep);
- }
- }
- else if (pp != NULL && pp == ps->pwrite)
- {
- /* Writing a file */
- pos = safecat(buffer, bufsize, pos, "write: ");
- pos = safecat(buffer, bufsize, pos, ps->wname);
- pos = safecat(buffer, bufsize, pos, sep);
- }
- else
- {
- /* Neither reading nor writing (or a memory error in struct delete) */
- pos = safecat(buffer, bufsize, pos, "pngvalid: ");
- }
- if (ps->test[0] != 0)
- {
- pos = safecat(buffer, bufsize, pos, ps->test);
- pos = safecat(buffer, bufsize, pos, sep);
- }
- pos = safecat(buffer, bufsize, pos, msg);
- return pos;
- }
- /* Verbose output to the error stream: */
- static void
- store_verbose(png_store *ps, png_const_structp pp, png_const_charp prefix,
- png_const_charp message)
- {
- char buffer[512];
- if (prefix)
- fputs(prefix, stderr);
- (void)store_message(ps, pp, buffer, sizeof buffer, 0, message);
- fputs(buffer, stderr);
- fputc('\n', stderr);
- }
- /* Log an error or warning - the relevant count is always incremented. */
- static void
- store_log(png_store* ps, png_const_structp pp, png_const_charp message,
- int is_error)
- {
- /* The warning is copied to the error buffer if there are no errors and it is
- * the first warning. The error is copied to the error buffer if it is the
- * first error (overwriting any prior warnings).
- */
- if (is_error ? (ps->nerrors)++ == 0 :
- (ps->nwarnings)++ == 0 && ps->nerrors == 0)
- store_message(ps, pp, ps->error, sizeof ps->error, 0, message);
- if (ps->verbose)
- store_verbose(ps, pp, is_error ? "error: " : "warning: ", message);
- }
- #ifdef PNG_READ_SUPPORTED
- /* Internal error function, called with a png_store but no libpng stuff. */
- static void
- internal_error(png_store *ps, png_const_charp message)
- {
- store_log(ps, NULL, message, 1 /* error */);
- /* And finally throw an exception. */
- {
- struct exception_context *the_exception_context = &ps->exception_context;
- Throw ps;
- }
- }
- #endif /* PNG_READ_SUPPORTED */
- /* Functions to use as PNG callbacks. */
- static void PNGCBAPI
- store_error(png_structp ppIn, png_const_charp message) /* PNG_NORETURN */
- {
- png_const_structp pp = ppIn;
- png_store *ps = voidcast(png_store*, png_get_error_ptr(pp));
- if (!ps->expect_error)
- store_log(ps, pp, message, 1 /* error */);
- /* And finally throw an exception. */
- {
- struct exception_context *the_exception_context = &ps->exception_context;
- Throw ps;
- }
- }
- static void PNGCBAPI
- store_warning(png_structp ppIn, png_const_charp message)
- {
- png_const_structp pp = ppIn;
- png_store *ps = voidcast(png_store*, png_get_error_ptr(pp));
- if (!ps->expect_warning)
- store_log(ps, pp, message, 0 /* warning */);
- else
- ps->saw_warning = 1;
- }
- /* These somewhat odd functions are used when reading an image to ensure that
- * the buffer is big enough, the png_structp is for errors.
- */
- /* Return a single row from the correct image. */
- static png_bytep
- store_image_row(PNG_CONST png_store* ps, png_const_structp pp, int nImage,
- png_uint_32 y)
- {
- png_size_t coffset = (nImage * ps->image_h + y) * (ps->cb_row + 5) + 2;
- if (ps->image == NULL)
- png_error(pp, "no allocated image");
- if (coffset + ps->cb_row + 3 > ps->cb_image)
- png_error(pp, "image too small");
- return ps->image + coffset;
- }
- static void
- store_image_free(png_store *ps, png_const_structp pp)
- {
- if (ps->image != NULL)
- {
- png_bytep image = ps->image;
- if (image[-1] != 0xed || image[ps->cb_image] != 0xfe)
- {
- if (pp != NULL)
- png_error(pp, "png_store image overwrite (1)");
- else
- store_log(ps, NULL, "png_store image overwrite (2)", 1);
- }
- ps->image = NULL;
- ps->cb_image = 0;
- --image;
- free(image);
- }
- }
- static void
- store_ensure_image(png_store *ps, png_const_structp pp, int nImages,
- png_size_t cbRow, png_uint_32 cRows)
- {
- png_size_t cb = nImages * cRows * (cbRow + 5);
- if (ps->cb_image < cb)
- {
- png_bytep image;
- store_image_free(ps, pp);
- /* The buffer is deliberately mis-aligned. */
- image = voidcast(png_bytep, malloc(cb+2));
- if (image == NULL)
- {
- /* Called from the startup - ignore the error for the moment. */
- if (pp == NULL)
- return;
- png_error(pp, "OOM allocating image buffer");
- }
- /* These magic tags are used to detect overwrites above. */
- ++image;
- image[-1] = 0xed;
- image[cb] = 0xfe;
- ps->image = image;
- ps->cb_image = cb;
- }
- /* We have an adequate sized image; lay out the rows. There are 2 bytes at
- * the start and three at the end of each (this ensures that the row
- * alignment starts out odd - 2+1 and changes for larger images on each row.)
- */
- ps->cb_row = cbRow;
- ps->image_h = cRows;
- /* For error checking, the whole buffer is set to 10110010 (0xb2 - 178).
- * This deliberately doesn't match the bits in the size test image which are
- * outside the image; these are set to 0xff (all 1). To make the row
- * comparison work in the 'size' test case the size rows are pre-initialized
- * to the same value prior to calling 'standard_row'.
- */
- memset(ps->image, 178, cb);
- /* Then put in the marks. */
- while (--nImages >= 0)
- {
- png_uint_32 y;
- for (y=0; y<cRows; ++y)
- {
- png_bytep row = store_image_row(ps, pp, nImages, y);
- /* The markers: */
- row[-2] = 190;
- row[-1] = 239;
- row[cbRow] = 222;
- row[cbRow+1] = 173;
- row[cbRow+2] = 17;
- }
- }
- }
- #ifdef PNG_READ_SUPPORTED
- static void
- store_image_check(PNG_CONST png_store* ps, png_const_structp pp, int iImage)
- {
- png_const_bytep image = ps->image;
- if (image[-1] != 0xed || image[ps->cb_image] != 0xfe)
- png_error(pp, "image overwrite");
- else
- {
- png_size_t cbRow = ps->cb_row;
- png_uint_32 rows = ps->image_h;
- image += iImage * (cbRow+5) * ps->image_h;
- image += 2; /* skip image first row markers */
- while (rows-- > 0)
- {
- if (image[-2] != 190 || image[-1] != 239)
- png_error(pp, "row start overwritten");
- if (image[cbRow] != 222 || image[cbRow+1] != 173 ||
- image[cbRow+2] != 17)
- png_error(pp, "row end overwritten");
- image += cbRow+5;
- }
- }
- }
- #endif /* PNG_READ_SUPPORTED */
- static void PNGCBAPI
- store_write(png_structp ppIn, png_bytep pb, png_size_t st)
- {
- png_const_structp pp = ppIn;
- png_store *ps = voidcast(png_store*, png_get_io_ptr(pp));
- if (ps->pwrite != pp)
- png_error(pp, "store state damaged");
- while (st > 0)
- {
- size_t cb;
- if (ps->writepos >= STORE_BUFFER_SIZE)
- store_storenew(ps);
- cb = st;
- if (cb > STORE_BUFFER_SIZE - ps->writepos)
- cb = STORE_BUFFER_SIZE - ps->writepos;
- memcpy(ps->new.buffer + ps->writepos, pb, cb);
- pb += cb;
- st -= cb;
- ps->writepos += cb;
- }
- }
- static void PNGCBAPI
- store_flush(png_structp ppIn)
- {
- UNUSED(ppIn) /*DOES NOTHING*/
- }
- #ifdef PNG_READ_SUPPORTED
- static size_t
- store_read_buffer_size(png_store *ps)
- {
- /* Return the bytes available for read in the current buffer. */
- if (ps->next != &ps->current->data)
- return STORE_BUFFER_SIZE;
- return ps->current->datacount;
- }
- #ifdef PNG_READ_TRANSFORMS_SUPPORTED
- /* Return total bytes available for read. */
- static size_t
- store_read_buffer_avail(png_store *ps)
- {
- if (ps->current != NULL && ps->next != NULL)
- {
- png_store_buffer *next = &ps->current->data;
- size_t cbAvail = ps->current->datacount;
- while (next != ps->next && next != NULL)
- {
- next = next->prev;
- cbAvail += STORE_BUFFER_SIZE;
- }
- if (next != ps->next)
- png_error(ps->pread, "buffer read error");
- if (cbAvail > ps->readpos)
- return cbAvail - ps->readpos;
- }
- return 0;
- }
- #endif
- static int
- store_read_buffer_next(png_store *ps)
- {
- png_store_buffer *pbOld = ps->next;
- png_store_buffer *pbNew = &ps->current->data;
- if (pbOld != pbNew)
- {
- while (pbNew != NULL && pbNew->prev != pbOld)
- pbNew = pbNew->prev;
- if (pbNew != NULL)
- {
- ps->next = pbNew;
- ps->readpos = 0;
- return 1;
- }
- png_error(ps->pread, "buffer lost");
- }
- return 0; /* EOF or error */
- }
- /* Need separate implementation and callback to allow use of the same code
- * during progressive read, where the io_ptr is set internally by libpng.
- */
- static void
- store_read_imp(png_store *ps, png_bytep pb, png_size_t st)
- {
- if (ps->current == NULL || ps->next == NULL)
- png_error(ps->pread, "store state damaged");
- while (st > 0)
- {
- size_t cbAvail = store_read_buffer_size(ps) - ps->readpos;
- if (cbAvail > 0)
- {
- if (cbAvail > st) cbAvail = st;
- memcpy(pb, ps->next->buffer + ps->readpos, cbAvail);
- st -= cbAvail;
- pb += cbAvail;
- ps->readpos += cbAvail;
- }
- else if (!store_read_buffer_next(ps))
- png_error(ps->pread, "read beyond end of file");
- }
- }
- static void PNGCBAPI
- store_read(png_structp ppIn, png_bytep pb, png_size_t st)
- {
- png_const_structp pp = ppIn;
- png_store *ps = voidcast(png_store*, png_get_io_ptr(pp));
- if (ps == NULL || ps->pread != pp)
- png_error(pp, "bad store read call");
- store_read_imp(ps, pb, st);
- }
- static void
- store_progressive_read(png_store *ps, png_structp pp, png_infop pi)
- {
- /* Notice that a call to store_read will cause this function to fail because
- * readpos will be set.
- */
- if (ps->pread != pp || ps->current == NULL || ps->next == NULL)
- png_error(pp, "store state damaged (progressive)");
- do
- {
- if (ps->readpos != 0)
- png_error(pp, "store_read called during progressive read");
- png_process_data(pp, pi, ps->next->buffer, store_read_buffer_size(ps));
- }
- while (store_read_buffer_next(ps));
- }
- #endif /* PNG_READ_SUPPORTED */
- /* The caller must fill this in: */
- static store_palette_entry *
- store_write_palette(png_store *ps, int npalette)
- {
- if (ps->pwrite == NULL)
- store_log(ps, NULL, "attempt to write palette without write stream", 1);
- if (ps->palette != NULL)
- png_error(ps->pwrite, "multiple store_write_palette calls");
- /* This function can only return NULL if called with '0'! */
- if (npalette > 0)
- {
- ps->palette = voidcast(store_palette_entry*, malloc(npalette *
- sizeof *ps->palette));
- if (ps->palette == NULL)
- png_error(ps->pwrite, "store new palette: OOM");
- ps->npalette = npalette;
- }
- return ps->palette;
- }
- #ifdef PNG_READ_SUPPORTED
- static store_palette_entry *
- store_current_palette(png_store *ps, int *npalette)
- {
- /* This is an internal error (the call has been made outside a read
- * operation.)
- */
- if (ps->current == NULL)
- store_log(ps, ps->pread, "no current stream for palette", 1);
- /* The result may be null if there is no palette. */
- *npalette = ps->current->npalette;
- return ps->current->palette;
- }
- #endif /* PNG_READ_SUPPORTED */
- /***************************** MEMORY MANAGEMENT*** ***************************/
- #ifdef PNG_USER_MEM_SUPPORTED
- /* A store_memory is simply the header for an allocated block of memory. The
- * pointer returned to libpng is just after the end of the header block, the
- * allocated memory is followed by a second copy of the 'mark'.
- */
- typedef struct store_memory
- {
- store_pool *pool; /* Originating pool */
- struct store_memory *next; /* Singly linked list */
- png_alloc_size_t size; /* Size of memory allocated */
- png_byte mark[4]; /* ID marker */
- } store_memory;
- /* Handle a fatal error in memory allocation. This calls png_error if the
- * libpng struct is non-NULL, else it outputs a message and returns. This means
- * that a memory problem while libpng is running will abort (png_error) the
- * handling of particular file while one in cleanup (after the destroy of the
- * struct has returned) will simply keep going and free (or attempt to free)
- * all the memory.
- */
- static void
- store_pool_error(png_store *ps, png_const_structp pp, PNG_CONST char *msg)
- {
- if (pp != NULL)
- png_error(pp, msg);
- /* Else we have to do it ourselves. png_error eventually calls store_log,
- * above. store_log accepts a NULL png_structp - it just changes what gets
- * output by store_message.
- */
- store_log(ps, pp, msg, 1 /* error */);
- }
- static void
- store_memory_free(png_const_structp pp, store_pool *pool, store_memory *memory)
- {
- /* Note that pp may be NULL (see store_pool_delete below), the caller has
- * found 'memory' in pool->list *and* unlinked this entry, so this is a valid
- * pointer (for sure), but the contents may have been trashed.
- */
- if (memory->pool != pool)
- store_pool_error(pool->store, pp, "memory corrupted (pool)");
- else if (memcmp(memory->mark, pool->mark, sizeof memory->mark) != 0)
- store_pool_error(pool->store, pp, "memory corrupted (start)");
- /* It should be safe to read the size field now. */
- else
- {
- png_alloc_size_t cb = memory->size;
- if (cb > pool->max)
- store_pool_error(pool->store, pp, "memory corrupted (size)");
- else if (memcmp((png_bytep)(memory+1)+cb, pool->mark, sizeof pool->mark)
- != 0)
- store_pool_error(pool->store, pp, "memory corrupted (end)");
- /* Finally give the library a chance to find problems too: */
- else
- {
- pool->current -= cb;
- free(memory);
- }
- }
- }
- static void
- store_pool_delete(png_store *ps, store_pool *pool)
- {
- if (pool->list != NULL)
- {
- fprintf(stderr, "%s: %s %s: memory lost (list follows):\n", ps->test,
- pool == &ps->read_memory_pool ? "read" : "write",
- pool == &ps->read_memory_pool ? (ps->current != NULL ?
- ps->current->name : "unknown file") : ps->wname);
- ++ps->nerrors;
- do
- {
- store_memory *next = pool->list;
- pool->list = next->next;
- next->next = NULL;
- fprintf(stderr, "\t%lu bytes @ %p\n",
- (unsigned long)next->size, (PNG_CONST void*)(next+1));
- /* The NULL means this will always return, even if the memory is
- * corrupted.
- */
- store_memory_free(NULL, pool, next);
- }
- while (pool->list != NULL);
- }
- /* And reset the other fields too for the next time. */
- if (pool->max > pool->max_max) pool->max_max = pool->max;
- pool->max = 0;
- if (pool->current != 0) /* unexpected internal error */
- fprintf(stderr, "%s: %s %s: memory counter mismatch (internal error)\n",
- ps->test, pool == &ps->read_memory_pool ? "read" : "write",
- pool == &ps->read_memory_pool ? (ps->current != NULL ?
- ps->current->name : "unknown file") : ps->wname);
- pool->current = 0;
- if (pool->limit > pool->max_limit)
- pool->max_limit = pool->limit;
- pool->limit = 0;
- if (pool->total > pool->max_total)
- pool->max_total = pool->total;
- pool->total = 0;
- /* Get a new mark too. */
- store_pool_mark(pool->mark);
- }
- /* The memory callbacks: */
- static png_voidp PNGCBAPI
- store_malloc(png_structp ppIn, png_alloc_size_t cb)
- {
- png_const_structp pp = ppIn;
- store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp));
- store_memory *new = voidcast(store_memory*, malloc(cb + (sizeof *new) +
- (sizeof pool->mark)));
- if (new != NULL)
- {
- if (cb > pool->max)
- pool->max = cb;
- pool->current += cb;
- if (pool->current > pool->limit)
- pool->limit = pool->current;
- pool->total += cb;
- new->size = cb;
- memcpy(new->mark, pool->mark, sizeof new->mark);
- memcpy((png_byte*)(new+1) + cb, pool->mark, sizeof pool->mark);
- new->pool = pool;
- new->next = pool->list;
- pool->list = new;
- ++new;
- }
- else
- {
- /* NOTE: the PNG user malloc function cannot use the png_ptr it is passed
- * other than to retrieve the allocation pointer! libpng calls the
- * store_malloc callback in two basic cases:
- *
- * 1) From png_malloc; png_malloc will do a png_error itself if NULL is
- * returned.
- * 2) From png_struct or png_info structure creation; png_malloc is
- * to return so cleanup can be performed.
- *
- * To handle this store_malloc can log a message, but can't do anything
- * else.
- */
- store_log(pool->store, pp, "out of memory", 1 /* is_error */);
- }
- return new;
- }
- static void PNGCBAPI
- store_free(png_structp ppIn, png_voidp memory)
- {
- png_const_structp pp = ppIn;
- store_pool *pool = voidcast(store_pool*, png_get_mem_ptr(pp));
- store_memory *this = voidcast(store_memory*, memory), **test;
- /* Because libpng calls store_free with a dummy png_struct when deleting
- * png_struct or png_info via png_destroy_struct_2 it is necessary to check
- * the passed in png_structp to ensure it is valid, and not pass it to
- * png_error if it is not.
- */
- if (pp != pool->store->pread && pp != pool->store->pwrite)
- pp = NULL;
- /* First check that this 'memory' really is valid memory - it must be in the
- * pool list. If it is, use the shared memory_free function to free it.
- */
- --this;
- for (test = &pool->list; *test != this; test = &(*test)->next)
- {
- if (*test == NULL)
- {
- store_pool_error(pool->store, pp, "bad pointer to free");
- return;
- }
- }
- /* Unlink this entry, *test == this. */
- *test = this->next;
- this->next = NULL;
- store_memory_free(pp, pool, this);
- }
- #endif /* PNG_USER_MEM_SUPPORTED */
- /* Setup functions. */
- /* Cleanup when aborting a write or after storing the new file. */
- static void
- store_write_reset(png_store *ps)
- {
- if (ps->pwrite != NULL)
- {
- anon_context(ps);
- Try
- png_destroy_write_struct(&ps->pwrite, &ps->piwrite);
- Catch_anonymous
- {
- /* memory corruption: continue. */
- }
- ps->pwrite = NULL;
- ps->piwrite = NULL;
- }
- /* And make sure that all the memory has been freed - this will output
- * spurious errors in the case of memory corruption above, but this is safe.
- */
- # ifdef PNG_USER_MEM_SUPPORTED
- store_pool_delete(ps, &ps->write_memory_pool);
- # endif
- store_freenew(ps);
- }
- /* The following is the main write function, it returns a png_struct and,
- * optionally, a png_info suitable for writiing a new PNG file. Use
- * store_storefile above to record this file after it has been written. The
- * returned libpng structures as destroyed by store_write_reset above.
- */
- static png_structp
- set_store_for_write(png_store *ps, png_infopp ppi,
- PNG_CONST char * volatile name)
- {
- anon_context(ps);
- Try
- {
- if (ps->pwrite != NULL)
- png_error(ps->pwrite, "write store already in use");
- store_write_reset(ps);
- safecat(ps->wname, sizeof ps->wname, 0, name);
- /* Don't do the slow memory checks if doing a speed test, also if user
- * memory is not supported we can't do it anyway.
- */
- # ifdef PNG_USER_MEM_SUPPORTED
- if (!ps->speed)
- ps->pwrite = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
- ps, store_error, store_warning, &ps->write_memory_pool,
- store_malloc, store_free);
- else
- # endif
- ps->pwrite = png_create_write_struct(png_get_libpng_ver(NULL),
- ps, store_error, store_warning);
- png_set_write_fn(ps->pwrite, ps, store_write, store_flush);
- # ifdef PNG_SET_OPTION_SUPPORTED
- {
- int opt;
- for (opt=0; opt<ps->noptions; ++opt)
- if (png_set_option(ps->pwrite, ps->options[opt].option,
- ps->options[opt].setting) == PNG_OPTION_INVALID)
- png_error(ps->pwrite, "png option invalid");
- }
- # endif
- if (ppi != NULL)
- *ppi = ps->piwrite = png_create_info_struct(ps->pwrite);
- }
- Catch_anonymous
- return NULL;
- return ps->pwrite;
- }
- /* Cleanup when finished reading (either due to error or in the success case).
- * This routine exists even when there is no read support to make the code
- * tidier (avoid a mass of ifdefs) and so easier to maintain.
- */
- static void
- store_read_reset(png_store *ps)
- {
- # ifdef PNG_READ_SUPPORTED
- if (ps->pread != NULL)
- {
- anon_context(ps);
- Try
- png_destroy_read_struct(&ps->pread, &ps->piread, NULL);
- Catch_anonymous
- {
- /* error already output: continue */
- }
- ps->pread = NULL;
- ps->piread = NULL;
- }
- # endif
- # ifdef PNG_USER_MEM_SUPPORTED
- /* Always do this to be safe. */
- store_pool_delete(ps, &ps->read_memory_pool);
- # endif
- ps->current = NULL;
- ps->next = NULL;
- ps->readpos = 0;
- ps->validated = 0;
- }
- #ifdef PNG_READ_SUPPORTED
- static void
- store_read_set(png_store *ps, png_uint_32 id)
- {
- png_store_file *pf = ps->saved;
- while (pf != NULL)
- {
- if (pf->id == id)
- {
- ps->current = pf;
- ps->next = NULL;
- store_read_buffer_next(ps);
- return;
- }
- pf = pf->next;
- }
- {
- size_t pos;
- char msg[FILE_NAME_SIZE+64];
- pos = standard_name_from_id(msg, sizeof msg, 0, id);
- pos = safecat(msg, sizeof msg, pos, ": file not found");
- png_error(ps->pread, msg);
- }
- }
- /* The main interface for reading a saved file - pass the id number of the file
- * to retrieve. Ids must be unique or the earlier file will be hidden. The API
- * returns a png_struct and, optionally, a png_info. Both of these will be
- * destroyed by store_read_reset above.
- */
- static png_structp
- set_store_for_read(png_store *ps, png_infopp ppi, png_uint_32 id,
- PNG_CONST char *name)
- {
- /* Set the name for png_error */
- safecat(ps->test, sizeof ps->test, 0, name);
- if (ps->pread != NULL)
- png_error(ps->pread, "read store already in use");
- store_read_reset(ps);
- /* Both the create APIs can return NULL if used in their default mode
- * (because there is no other way of handling an error because the jmp_buf
- * by default is stored in png_struct and that has not been allocated!)
- * However, given that store_error works correctly in these circumstances
- * we don't ever expect NULL in this program.
- */
- # ifdef PNG_USER_MEM_SUPPORTED
- if (!ps->speed)
- ps->pread = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, ps,
- store_error, store_warning, &ps->read_memory_pool, store_malloc,
- store_free);
- else
- # endif
- ps->pread = png_create_read_struct(PNG_LIBPNG_VER_STRING, ps, store_error,
- store_warning);
- if (ps->pread == NULL)
- {
- struct exception_context *the_exception_context = &ps->exception_context;
- store_log(ps, NULL, "png_create_read_struct returned NULL (unexpected)",
- 1 /*error*/);
- Throw ps;
- }
- # ifdef PNG_SET_OPTION_SUPPORTED
- {
- int opt;
- for (opt=0; opt<ps->noptions; ++opt)
- if (png_set_option(ps->pread, ps->options[opt].option,
- ps->options[opt].setting) == PNG_OPTION_INVALID)
- png_error(ps->pread, "png option invalid");
- }
- # endif
- store_read_set(ps, id);
- if (ppi != NULL)
- *ppi = ps->piread = png_create_info_struct(ps->pread);
- return ps->pread;
- }
- #endif /* PNG_READ_SUPPORTED */
- /* The overall cleanup of a store simply calls the above then removes all the
- * saved files. This does not delete the store itself.
- */
- static void
- store_delete(png_store *ps)
- {
- store_write_reset(ps);
- store_read_reset(ps);
- store_freefile(&ps->saved);
- store_image_free(ps, NULL);
- }
- /*********************** PNG FILE MODIFICATION ON READ ************************/
- /* Files may be modified on read. The following structure contains a complete
- * png_store together with extra members to handle modification and a special
- * read callback for libpng. To use this the 'modifications' field must be set
- * to a list of png_modification structures that actually perform the
- * modification, otherwise a png_modifier is functionally equivalent to a
- * png_store. There is a special read function, set_modifier_for_read, which
- * replaces set_store_for_read.
- */
- typedef enum modifier_state
- {
- modifier_start, /* Initial value */
- modifier_signature, /* Have a signature */
- modifier_IHDR /* Have an IHDR */
- } modifier_state;
- typedef struct CIE_color
- {
- /* A single CIE tristimulus value, representing the unique response of a
- * standard observer to a variety of light spectra. The observer recognizes
- * all spectra that produce this response as the same color, therefore this
- * is effectively a description of a color.
- */
- …
Large files files are truncated, but you can click here to view the full file