1b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* pngimage.c
2b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *
3b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Copyright (c) 2014 John Cunningham Bowler
4b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *
5b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Last changed in libpng 1.6.10 [March 6, 2014]
6b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *
7b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * This code is released under the libpng license.
8b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * For conditions of distribution and use, see the disclaimer
9b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * and license in png.h
10b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *
11b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Test the png_read_png and png_write_png interfaces.  Given a PNG file load it
12b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * using png_read_png and then write with png_write_png.  Test all possible
13b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * transforms.
14b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */
15b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <stdarg.h>
16b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <stdlib.h>
17b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <string.h>
18b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <errno.h>
19b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <stdio.h>
20b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#include <assert.h>
21b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
22b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
23b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  include <config.h>
24b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
25b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
26b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* Define the following to use this test against your installed libpng, rather
27b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * than the one being built here:
28b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */
29b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_FREESTANDING_TESTS
30b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  include <png.h>
31b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
32b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  include "../../png.h"
33b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
34b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
35b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifndef PNG_SETJMP_SUPPORTED
36b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  include <setjmp.h> /* because png.h did *not* include this */
37b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
38b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
39b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#if defined(PNG_INFO_IMAGE_SUPPORTED) && defined(PNG_SEQUENTIAL_READ_SUPPORTED)
40b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* If a transform is valid on both read and write this implies that if the
41b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * transform is applied to read it must also be applied on write to produce
42b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * meaningful data.  This is because these transforms when performed on read
43b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * produce data with a memory format that does not correspond to a PNG format.
44b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *
45b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * Most of these transforms are invertible; after applying the transform on
46b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * write the result is the original PNG data that would have would have been
47b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * read if no transform were applied.
48b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *
49b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * The exception is _SHIFT, which destroys the low order bits marked as not
50b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * significant in a PNG with the sBIT chunk.
51b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *
52b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * The following table lists, for each transform, the conditions under which it
53b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * is expected to do anything.  Conditions are defined as follows:
54b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *
55b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 1) Color mask bits required - simply a mask to AND with color_type; one of
56b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *    these must be present for the transform to fire, except that 0 means
57b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *    'always'.
58b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 2) Color mask bits which must be absent - another mask - none of these must
59b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *    be present.
60b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 3) Bit depths - a mask of component bit depths for the transform to fire.
61b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 4) 'read' - the transform works in png_read_png.
62b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 5) 'write' - the transform works in png_write_png.
63b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * 6) PNG_INFO_chunk; a mask of the chunks that must be present for the
64b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *    transform to fire.  All must be present - the requirement is that
65b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *    png_get_valid() & mask == mask, so if mask is 0 there is no requirement.
66b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *
67b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * The condition refers to the original image state - if multiple transforms are
68b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * used together it is possible to cause a transform that wouldn't fire on the
69b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * original image to fire.
70b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */
71b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic struct transform_info
72b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
73b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   const char *name;
74b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int         transform;
75b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_uint_32 valid_chunks;
76b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define CHUNK_NONE 0
77b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define CHUNK_sBIT PNG_INFO_sBIT
78b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define CHUNK_tRNS PNG_INFO_tRNS
79b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_byte    color_mask_required;
80b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_byte    color_mask_absent;
81b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define COLOR_MASK_X   0
82b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define COLOR_MASK_P   PNG_COLOR_MASK_PALETTE
83b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define COLOR_MASK_C   PNG_COLOR_MASK_COLOR
84b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define COLOR_MASK_A   PNG_COLOR_MASK_ALPHA
85b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define COLOR_MASK_ALL (PALETTE+COLOR+ALPHA)  /* absent = gray, no alpha */
86b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_byte    bit_depths;
87b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define BD_ALL  (1 + 2 + 4 + 8 + 16)
88b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define BD_PAL  (1 + 2 + 4 + 8)
89b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define BD_LOW  (1 + 2 + 4)
90b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define BD_16   16
91b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define BD_TRUE (8+16) /* i.e. true-color depths */
92b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_byte    when;
93b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define TRANSFORM_R  1
94b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define TRANSFORM_W  2
95b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#     define TRANSFORM_RW 3
96b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_byte    tested; /* the transform was tested somewhere */
97b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari} transform_info[] =
98b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
99b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* List ALL the PNG_TRANSFORM_ macros here.  Check for support using the READ
100b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * macros; even if the transform is supported on write it cannot be tested
101b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * without the read support.
102b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
103b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define T(name,chunk,cm_required,cm_absent,bd,when)\
104b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {  #name, PNG_TRANSFORM_ ## name, CHUNK_ ## chunk,\
105b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      COLOR_MASK_ ## cm_required, COLOR_MASK_ ## cm_absent, BD_ ## bd,\
106b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      TRANSFORM_ ## when, 0/*!tested*/ }
107b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
108b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
109b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(STRIP_16,            NONE, X,   X,   16,  R),
110b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* drops the bottom 8 bits when bit depth is 16 */
111b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
112b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
113b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(STRIP_ALPHA,         NONE, A,   X,  ALL,  R),
114b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* removes the alpha channel if present */
115b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
116b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_PACK_SUPPORTED
117b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_PACK TRANSFORM_RW
118b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
119b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_PACK TRANSFORM_R
120b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
121b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_PACK_SUPPORTED
122b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(PACKING,             NONE, X,   X,  LOW, RW_PACK),
123b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* unpacks low-bit-depth components into 1 byte per component on read,
124b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * reverses this on write.
125b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
126b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
127b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
128b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_PACKSWAP TRANSFORM_RW
129b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
130b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_PACKSWAP TRANSFORM_R
131b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
132b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_PACKSWAP_SUPPORTED
133b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(PACKSWAP,            NONE, X,   X,  LOW, RW_PACKSWAP),
134b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* reverses the order of low-bit-depth components packed into a byte */
135b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
136b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_EXPAND_SUPPORTED
137b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(EXPAND,              NONE, P,   X,  ALL,  R),
138b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* expands PLTE PNG files to RGB (no tRNS) or RGBA (tRNS) *
139b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * Note that the 'EXPAND' transform does lots of different things: */
140b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(EXPAND,              NONE, X,   C,  ALL,  R),
141b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* expands grayscale PNG files to RGB, or RGBA */
142b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(EXPAND,              tRNS, X,   A,  ALL,  R),
143b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* expands the tRNS chunk in files without alpha */
144b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
145b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_INVERT_SUPPORTED
146b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_INVERT TRANSFORM_RW
147b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
148b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_INVERT TRANSFORM_R
149b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
150b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_INVERT_SUPPORTED
151b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(INVERT_MONO,         NONE, X,   C,  ALL, RW_INVERT),
152b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* converts gray-scale components to 1..0 from 0..1 */
153b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
154b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_SHIFT_SUPPORTED
155b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_SHIFT TRANSFORM_RW
156b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
157b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_SHIFT TRANSFORM_R
158b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
159b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_SHIFT_SUPPORTED
160b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(SHIFT,               sBIT, X,   X,  ALL, RW_SHIFT),
161b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* reduces component values to the original range based on the sBIT chunk,
162b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * this is only partially reversible - the low bits are lost and cannot be
163b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * recovered on write.  In fact write code replicates the bits to generate
164b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * new low-order bits.
165b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
166b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
167b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_BGR_SUPPORTED
168b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_BGR TRANSFORM_RW
169b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
170b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_BGR TRANSFORM_R
171b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
172b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_BGR_SUPPORTED
173b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(BGR,                 NONE, C,   P, TRUE, RW_BGR),
174b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* reverses the rgb component values of true-color pixels */
175b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
176b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
177b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_SWAP_ALPHA TRANSFORM_RW
178b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
179b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_SWAP_ALPHA TRANSFORM_R
180b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
181b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
182b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(SWAP_ALPHA,          NONE, A,   X, TRUE, RW_SWAP_ALPHA),
183b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* swaps the alpha channel of RGBA or GA pixels to the front - ARGB or
184b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * AG, on write reverses the process.
185b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
186b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
187b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_SWAP_SUPPORTED
188b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_SWAP TRANSFORM_RW
189b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
190b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_SWAP TRANSFORM_R
191b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
192b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_SWAP_SUPPORTED
193b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(SWAP_ENDIAN,         NONE, X,   P,   16, RW_SWAP),
194b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* byte-swaps 16-bit component values */
195b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
196b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
197b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_INVERT_ALPHA TRANSFORM_RW
198b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
199b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define TRANSFORM_RW_INVERT_ALPHA TRANSFORM_R
200b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
201b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
202b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(INVERT_ALPHA,        NONE, A,   X, TRUE, RW_INVERT_ALPHA),
203b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* converts an alpha channel from 0..1 to 1..0 */
204b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
205b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_FILLER_SUPPORTED
206b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(STRIP_FILLER_BEFORE, NONE, A,   P, TRUE,  W), /* 'A' for a filler! */
207b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* on write skips a leading filler channel; testing requires data with a
208b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * filler channel so this is produced from RGBA or GA images by removing
209b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * the 'alpha' flag from the color type in place.
210b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
211b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(STRIP_FILLER_AFTER,  NONE, A,   P, TRUE,  W),
212b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* on write strips a trailing filler channel */
213b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
214b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
215b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(GRAY_TO_RGB,         NONE, X,   C,  ALL,  R),
216b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* expands grayscale images to RGB, also causes the palette part of
217b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * 'EXPAND' to happen.  Low bit depth grayscale images are expanded to
218b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * 8-bits per component and no attempt is made to convert the image to a
219b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * palette image.  While this transform is partially reversible
220b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * png_write_png does not currently support this.
221b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
222b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(GRAY_TO_RGB,         NONE, P,   X,  ALL,  R),
223b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* The 'palette' side effect mentioned above; a bit bogus but this is the
224b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * way the libpng code works.
225b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
226b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
227b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_EXPAND_16_SUPPORTED
228b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(EXPAND_16,           NONE, X,   X,  PAL,  R),
229b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* expands images to 16-bits per component, as a side effect expands
230b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * palette images to RGB and expands the tRNS chunk if present, so it can
231b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * modify 16-bit per component images as well:
232b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
233b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(EXPAND_16,           tRNS, X,   A,   16,  R),
234b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* side effect of EXPAND_16 - expands the tRNS chunk in an RGB or G 16-bit
235b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * image.
236b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
237b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
238b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
239b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   T(SCALE_16,            NONE, X,   X,   16,  R)
240b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* scales 16-bit components to 8-bits. */
241b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
242b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
243b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#undef T
244b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari};
245b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
246b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define ARRAY_SIZE(a) ((sizeof a)/(sizeof a[0]))
247b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define TTABLE_SIZE ARRAY_SIZE(transform_info)
248b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
249b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* Some combinations of options that should be reversible are not; these cases
250b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * are bugs.
251b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */
252b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic int known_bad_combos[][2] =
253b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
254b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* problem, antidote */
255b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   { PNG_TRANSFORM_SHIFT | PNG_TRANSFORM_INVERT_ALPHA, 0/*antidote*/ }
256b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari};
257b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
258b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic int
259b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariis_combo(int transforms)
260b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
261b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return transforms & (transforms-1); /* non-zero if more than one set bit */
262b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
263b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
264b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic int
265b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurarifirst_transform(int transforms)
266b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
267b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return transforms & -transforms; /* lowest set bit */
268b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
269b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
270b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic int
271b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariis_bad_combo(int transforms)
272b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
273b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   unsigned int i;
274b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
275b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   for (i=0; i<ARRAY_SIZE(known_bad_combos); ++i)
276b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
277b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      int combo = known_bad_combos[i][0];
278b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
279b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if ((combo & transforms) == combo &&
280b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         (transforms & known_bad_combos[i][1]) == 0)
281b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         return 1;
282b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
283b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
284b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return 0; /* combo is ok */
285b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
286b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
287b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic const char *
288b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraritransform_name(int t)
289b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* The name, if 't' has multiple bits set the name of the lowest set bit is
290b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * returned.
291b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
292b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
293b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   unsigned int i;
294b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
295b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   t &= -t; /* first set bit */
296b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
297b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   for (i=0; i<TTABLE_SIZE; ++i)
298b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
299b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if ((transform_info[i].transform & t) != 0)
300b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         return transform_info[i].name;
301b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
302b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
303b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return "invalid transform";
304b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
305b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
306b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* Variables calculated by validate_T below and used to record all the supported
307b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * transforms.  Need (unsigned int) here because of the places where these
308b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * values are used (unsigned compares in the 'exhaustive' iterator.)
309b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */
310b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic unsigned int read_transforms, write_transforms, rw_transforms;
311b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
312b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
313b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurarivalidate_T(void)
314b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Validate the above table - this just builds the above values */
315b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
316b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   unsigned int i;
317b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
318b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   for (i=0; i<TTABLE_SIZE; ++i)
319b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
320b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (transform_info[i].when & TRANSFORM_R)
321b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         read_transforms |= transform_info[i].transform;
322b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
323b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (transform_info[i].when & TRANSFORM_W)
324b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         write_transforms |= transform_info[i].transform;
325b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
326b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
327b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Reversible transforms are those which are supported on both read and
328b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * write.
329b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
330b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   rw_transforms = read_transforms & write_transforms;
331b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
332b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
333b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* FILE DATA HANDLING
334b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *    The original file is cached in memory.  During write the output file is
335b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *    written to memory.
336b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *
337b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *    In both cases the file data is held in a linked list of buffers - not all
338b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari *    of these are in use at any time.
339b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */
340b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristruct buffer_list
341b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
342b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct buffer_list *next;         /* next buffer in list */
343b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_byte            buffer[1024]; /* the actual buffer */
344b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari};
345b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
346b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristruct buffer
347b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
348b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct buffer_list  *last;       /* last buffer in use */
349b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   size_t               end_count;  /* bytes in the last buffer */
350b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct buffer_list  *current;    /* current buffer being read */
351b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   size_t               read_count; /* count of bytes read from current */
352b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct buffer_list   first;      /* the very first buffer */
353b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari};
354b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
355b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
356b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraribuffer_init(struct buffer *buffer)
357b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Call this only once for a given buffer */
358b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
359b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer->first.next = NULL;
360b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer->last = NULL;
361b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer->current = NULL;
362b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
363b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
364b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_SUPPORTED
365b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
366b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraribuffer_start_write(struct buffer *buffer)
367b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
368b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer->last = &buffer->first;
369b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer->end_count = 0;
370b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer->current = NULL;
371b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
372b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
373b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
374b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
375b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraribuffer_start_read(struct buffer *buffer)
376b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
377b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer->current = &buffer->first;
378b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer->read_count = 0;
379b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
380b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
381b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef ENOMEM /* required by POSIX 1003.1 */
382b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define MEMORY ENOMEM
383b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
384b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define MEMORY ERANGE /* required by ANSI-C */
385b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
386b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic struct buffer *
387b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariget_buffer(png_structp pp)
388b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Used from libpng callbacks to get the current buffer */
389b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
390b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return (struct buffer*)png_get_io_ptr(pp);
391b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
392b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
393b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define NEW(type) ((type *)malloc(sizeof (type)))
394b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
395b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic struct buffer_list *
396b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraribuffer_extend(struct buffer_list *current)
397b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
398b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct buffer_list *add;
399b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
400b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   assert(current->next == NULL);
401b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
402b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   add = NEW(struct buffer_list);
403b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (add == NULL)
404b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      return NULL;
405b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
406b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   add->next = NULL;
407b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   current->next = add;
408b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
409b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return add;
410b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
411b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
412b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* Load a buffer from a file; does the equivalent of buffer_start_write.  On a
413b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * read error returns an errno value, else returns 0.
414b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */
415b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic int
416b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraribuffer_from_file(struct buffer *buffer, FILE *fp)
417b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
418b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct buffer_list *last = &buffer->first;
419b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   size_t count = 0;
420b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
421b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   for (;;)
422b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
423b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      size_t r = fread(last->buffer+count, 1/*size*/,
424b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         (sizeof last->buffer)-count, fp);
425b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
426b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (r > 0)
427b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
428b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         count += r;
429b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
430b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if (count >= sizeof last->buffer)
431b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
432b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            assert(count == sizeof last->buffer);
433b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            count = 0;
434b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
435b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (last->next == NULL)
436b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            {
437b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               last = buffer_extend(last);
438b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               if (last == NULL)
439b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  return MEMORY;
440b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            }
441b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
442b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            else
443b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               last = last->next;
444b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
445b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
446b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
447b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else /* fread failed - probably end of file */
448b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
449b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if (feof(fp))
450b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
451b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            buffer->last = last;
452b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            buffer->end_count = count;
453b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            return 0; /* no error */
454b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
455b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
456b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* Some kind of funky error; errno should be non-zero */
457b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         return errno == 0 ? ERANGE : errno;
458b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
459b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
460b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
461b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
462b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* This structure is used to control the test of a single file. */
463b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraritypedef enum
464b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
465b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   VERBOSE,        /* switches on all messages */
466b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   INFORMATION,
467b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   WARNINGS,       /* switches on warnings */
468b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   LIBPNG_WARNING,
469b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   APP_WARNING,
470b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   ERRORS,         /* just errors */
471b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   APP_FAIL,       /* continuable error - no need to longjmp */
472b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   LIBPNG_ERROR,   /* this and higher cause a longjmp */
473b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   LIBPNG_BUG,     /* erroneous behavior in libpng */
474b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   APP_ERROR,      /* such as out-of-memory in a callback */
475b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   QUIET,          /* no normal messages */
476b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   USER_ERROR,     /* such as file-not-found */
477b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   INTERNAL_ERROR
478b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari} error_level;
479b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define LEVEL_MASK      0xf   /* where the level is in 'options' */
480b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
481b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define EXHAUSTIVE      0x010 /* Test all combinations of active options */
482b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define STRICT          0x020 /* Fail on warnings as well as errors */
483b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define LOG             0x040 /* Log pass/fail to stdout */
484b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define CONTINUE        0x080 /* Continue on APP_FAIL errors */
485b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define SKIP_BUGS       0x100 /* Skip over known bugs */
486b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define LOG_SKIPPED     0x200 /* Log skipped bugs */
487b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define FIND_BAD_COMBOS 0x400 /* Attempt to deduce bad combos */
488b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
489b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* Result masks apply to the result bits in the 'results' field below; these
490b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * bits are simple 1U<<error_level.  A pass requires either nothing worse than
491b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * warnings (--relaxes) or nothing worse than information (--strict)
492b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */
493b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define RESULT_STRICT(r)   (((r) & ~((1U<<WARNINGS)-1)) == 0)
494b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#define RESULT_RELAXED(r)  (((r) & ~((1U<<ERRORS)-1)) == 0)
495b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
496b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristruct display
497b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
498b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   jmp_buf        error_return;      /* Where to go to on error */
499b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
500b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   const char    *filename;          /* The name of the original file */
501b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   const char    *operation;         /* Operation being performed */
502b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int            transforms;        /* Transform used in operation */
503b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_uint_32    options;           /* See display_log below */
504b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_uint_32    results;           /* A mask of errors seen */
505b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
506b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
507b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_structp    original_pp;       /* used on the original read */
508b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_infop      original_ip;       /* set by the original read */
509b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
510b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_size_t     original_rowbytes; /* of the original rows: */
511b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_bytepp     original_rows;     /* from the original read */
512b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
513b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Original chunks valid */
514b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_uint_32    chunks;
515b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
516b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Original IHDR information */
517b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_uint_32    width;
518b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_uint_32    height;
519b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int            bit_depth;
520b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int            color_type;
521b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int            interlace_method;
522b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int            compression_method;
523b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int            filter_method;
524b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
525b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Derived information for the original image. */
526b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int            active_transforms;  /* transforms that do something on read */
527b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int            ignored_transforms; /* transforms that should do nothing */
528b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
529b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Used on a read, both the original read and when validating a written
530b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * image.
531b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
532b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_structp    read_pp;
533b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_infop      read_ip;
534b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
535b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  ifdef PNG_WRITE_SUPPORTED
536b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* Used to write a new image (the original info_ptr is used) */
537b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      png_structp   write_pp;
538b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      struct buffer written_file;   /* where the file gets written */
539b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  endif
540b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
541b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct buffer  original_file;     /* Data read from the original file */
542b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari};
543b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
544b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
545b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraridisplay_init(struct display *dp)
546b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Call this only once right at the start to initialize the control
547b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * structure, the (struct buffer) lists are maintained across calls - the
548b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * memory is not freed.
549b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
550b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
551b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   memset(dp, 0, sizeof *dp);
552b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->options = WARNINGS; /* default to !verbose, !quiet */
553b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->filename = NULL;
554b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->operation = NULL;
555b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->original_pp = NULL;
556b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->original_ip = NULL;
557b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->original_rows = NULL;
558b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->read_pp = NULL;
559b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->read_ip = NULL;
560b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer_init(&dp->original_file);
561b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
562b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  ifdef PNG_WRITE_SUPPORTED
563b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      dp->write_pp = NULL;
564b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      buffer_init(&dp->written_file);
565b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  endif
566b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
567b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
568b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
569b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraridisplay_clean_read(struct display *dp)
570b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
571b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (dp->read_pp != NULL)
572b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      png_destroy_read_struct(&dp->read_pp, &dp->read_ip, NULL);
573b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
574b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
575b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_SUPPORTED
576b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
577b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraridisplay_clean_write(struct display *dp)
578b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
579b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (dp->write_pp != NULL)
580b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         png_destroy_write_struct(&dp->write_pp, NULL);
581b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
582b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
583b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
584b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
585b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraridisplay_clean(struct display *dp)
586b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
587b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  ifdef PNG_WRITE_SUPPORTED
588b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_clean_write(dp);
589b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  endif
590b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   display_clean_read(dp);
591b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
592b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->original_rowbytes = 0;
593b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->original_rows = NULL;
594b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->chunks = 0;
595b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
596b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_destroy_read_struct(&dp->original_pp, &dp->original_ip, NULL);
597b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* leave the filename for error detection */
598b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->results = 0; /* reset for next time */
599b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
600b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
601b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic struct display *
602b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariget_dp(png_structp pp)
603b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* The display pointer is always stored in the png_struct error pointer */
604b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
605b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct display *dp = (struct display*)png_get_error_ptr(pp);
606b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
607b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (dp == NULL)
608b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
609b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      fprintf(stderr, "pngimage: internal error (no display)\n");
610b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      exit(99); /* prevents a crash */
611b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
612b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
613b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return dp;
614b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
615b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
616b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* error handling */
617b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef __GNUC__
618b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define VGATTR __attribute__((__format__ (__printf__,3,4)))
619b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Required to quiet GNUC warnings when the compiler sees a stdarg function
620b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * that calls one of the stdio v APIs.
621b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
622b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
623b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define VGATTR
624b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
625b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void VGATTR
626b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraridisplay_log(struct display *dp, error_level level, const char *fmt, ...)
627b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* 'level' is as above, fmt is a stdio style format string.  This routine
628b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * does not return if level is above LIBPNG_WARNING
629b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
630b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
631b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->results |= 1U << level;
632b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
633b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (level > (error_level)(dp->options & LEVEL_MASK))
634b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
635b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      const char *lp;
636b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      va_list ap;
637b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
638b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      switch (level)
639b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
640b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         case INFORMATION:    lp = "information"; break;
641b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         case LIBPNG_WARNING: lp = "warning(libpng)"; break;
642b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         case APP_WARNING:    lp = "warning(pngimage)"; break;
643b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         case APP_FAIL:       lp = "error(continuable)"; break;
644b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         case LIBPNG_ERROR:   lp = "error(libpng)"; break;
645b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         case LIBPNG_BUG:     lp = "bug(libpng)"; break;
646b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         case APP_ERROR:      lp = "error(pngimage)"; break;
647b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         case USER_ERROR:     lp = "error(user)"; break;
648b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
649b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         case INTERNAL_ERROR: /* anything unexpected is an internal error: */
650b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         case VERBOSE: case WARNINGS: case ERRORS: case QUIET:
651b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         default:             lp = "bug(pngimage)"; break;
652b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
653b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
654b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      fprintf(stderr, "%s: %s: %s",
655b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         dp->filename != NULL ? dp->filename : "<stdin>", lp, dp->operation);
656b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
657b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (dp->transforms != 0)
658b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
659b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         int tr = dp->transforms;
660b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
661b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if (is_combo(tr))
662b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            fprintf(stderr, "(0x%x)", tr);
663b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
664b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         else
665b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            fprintf(stderr, "(%s)", transform_name(tr));
666b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
667b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
668b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      fprintf(stderr, ": ");
669b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
670b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      va_start(ap, fmt);
671b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      vfprintf(stderr, fmt, ap);
672b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      va_end(ap);
673b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
674b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      fputc('\n', stderr);
675b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
676b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* else do not output any message */
677b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
678b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Errors cause this routine to exit to the fail code */
679b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE)))
680b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      longjmp(dp->error_return, level);
681b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
682b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
683b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* error handler callbacks for libpng */
684b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI
685b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraridisplay_warning(png_structp pp, png_const_charp warning)
686b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
687b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   display_log(get_dp(pp), LIBPNG_WARNING, "%s", warning);
688b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
689b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
690b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI
691b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraridisplay_error(png_structp pp, png_const_charp error)
692b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
693b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct display *dp = get_dp(pp);
694b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
695b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   display_log(dp, LIBPNG_ERROR, "%s", error);
696b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
697b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
698b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
699b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraridisplay_cache_file(struct display *dp, const char *filename)
700b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Does the initial cache of the file. */
701b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
702b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   FILE *fp;
703b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int ret;
704b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
705b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->filename = filename;
706b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
707b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (filename != NULL)
708b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
709b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      fp = fopen(filename, "rb");
710b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (fp == NULL)
711b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         display_log(dp, USER_ERROR, "open failed: %s", strerror(errno));
712b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
713b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
714b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   else
715b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      fp = stdin;
716b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
717b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   ret = buffer_from_file(&dp->original_file, fp);
718b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
719b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   fclose(fp);
720b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
721b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (ret != 0)
722b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, APP_ERROR, "read failed: %s", strerror(ret));
723b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
724b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
725b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
726b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraribuffer_read(struct display *dp, struct buffer *bp, png_bytep data,
727b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_size_t size)
728b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
729b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct buffer_list *last = bp->current;
730b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   size_t read_count = bp->read_count;
731b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
732b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   while (size > 0)
733b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
734b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      size_t avail;
735b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
736b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (last == NULL ||
737b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         (last == bp->last && read_count >= bp->end_count))
738b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
739b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         display_log(dp, USER_ERROR, "file truncated (%lu bytes)",
740b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            (unsigned long)size);
741b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /*NOTREACHED*/
742b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         break;
743b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
744b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
745b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (read_count >= sizeof last->buffer)
746b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
747b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* Move to the next buffer: */
748b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         last = last->next;
749b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         read_count = 0;
750b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         bp->current = last; /* Avoid update outside the loop */
751b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
752b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* And do a sanity check (the EOF case is caught above) */
753b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if (last == NULL)
754b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
755b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            display_log(dp, INTERNAL_ERROR, "damaged buffer list");
756b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            /*NOTREACHED*/
757b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            break;
758b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
759b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
760b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
761b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      avail = (sizeof last->buffer) - read_count;
762b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (avail > size)
763b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         avail = size;
764b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
765b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      memcpy(data, last->buffer + read_count, avail);
766b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      read_count += avail;
767b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      size -= avail;
768b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      data += avail;
769b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
770b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
771b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   bp->read_count = read_count;
772b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
773b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
774b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI
775b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariread_function(png_structp pp, png_bytep data, png_size_t size)
776b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
777b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer_read(get_dp(pp), get_buffer(pp), data, size);
778b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
779b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
780b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
781b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariread_png(struct display *dp, struct buffer *bp, const char *operation,
782b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int transforms)
783b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
784b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_structp pp;
785b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_infop   ip;
786b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
787b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* This cleans out any previous read and sets operation and transforms to
788b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * empty.
789b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
790b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   display_clean_read(dp);
791b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
792b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (operation != NULL) /* else this is a verify and do not overwrite info */
793b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
794b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      dp->operation = operation;
795b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      dp->transforms = transforms;
796b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
797b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
798b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->read_pp = pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, dp,
799b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_error, display_warning);
800b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (pp == NULL)
801b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, LIBPNG_ERROR, "failed to create read struct");
802b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
803b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* The png_read_png API requires us to make the info struct, but it does the
804b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * call to png_read_info.
805b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
806b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->read_ip = ip = png_create_info_struct(pp);
807b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (ip == NULL)
808b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, LIBPNG_ERROR, "failed to create info struct");
809b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
810b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  ifdef PNG_SET_USER_LIMITS_SUPPORTED
811b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* Remove the user limits, if any */
812b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      png_set_user_limits(pp, 0x7fffffff, 0x7fffffff);
813b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  endif
814b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
815b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Set the IO handling */
816b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer_start_read(bp);
817b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_set_read_fn(pp, bp, read_function);
818b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
819b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_read_png(pp, ip, transforms, NULL/*params*/);
820b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
821b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#if 0 /* crazy debugging */
822b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
823b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      png_bytep pr = png_get_rows(pp, ip)[0];
824b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      size_t rb = png_get_rowbytes(pp, ip);
825b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      size_t cb;
826b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      char c = ' ';
827b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
828b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      fprintf(stderr, "%.4x %2d (%3lu bytes):", transforms, png_get_bit_depth(pp,ip), (unsigned long)rb);
829b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
830b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      for (cb=0; cb<rb; ++cb)
831b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         fputc(c, stderr), fprintf(stderr, "%.2x", pr[cb]), c='.';
832b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
833b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      fputc('\n', stderr);
834b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
835b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
836b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
837b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
838b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
839b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariupdate_display(struct display *dp)
840b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* called once after the first read to update all the info, original_pp and
841b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * original_ip must have been filled in.
842b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
843b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
844b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_structp pp;
845b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_infop   ip;
846b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
847b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Now perform the initial read with a 0 tranform. */
848b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   read_png(dp, &dp->original_file, "original read", 0/*no transform*/);
849b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
850b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Move the result to the 'original' fields */
851b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->original_pp = pp = dp->read_pp, dp->read_pp = NULL;
852b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->original_ip = ip = dp->read_ip, dp->read_ip = NULL;
853b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
854b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->original_rowbytes = png_get_rowbytes(pp, ip);
855b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (dp->original_rowbytes == 0)
856b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, LIBPNG_BUG, "png_get_rowbytes returned 0");
857b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
858b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->chunks = png_get_valid(pp, ip, 0xffffffff);
859b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if ((dp->chunks & PNG_INFO_IDAT) == 0) /* set by png_read_png */
860b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, LIBPNG_BUG, "png_read_png did not set IDAT flag");
861b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
862b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->original_rows = png_get_rows(pp, ip);
863b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (dp->original_rows == NULL)
864b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, LIBPNG_BUG, "png_read_png did not create row buffers");
865b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
866b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (!png_get_IHDR(pp, ip,
867b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      &dp->width, &dp->height, &dp->bit_depth, &dp->color_type,
868b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      &dp->interlace_method, &dp->compression_method, &dp->filter_method))
869b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, LIBPNG_BUG, "png_get_IHDR failed");
870b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
871b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* 'active' transforms are discovered based on the original image format;
872b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * running one active transform can activate others.  At present the code
873b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * does not attempt to determine the closure.
874b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
875b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
876b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      png_uint_32 chunks = dp->chunks;
877b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      int active = 0, inactive = 0;
878b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      int ct = dp->color_type;
879b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      int bd = dp->bit_depth;
880b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      unsigned int i;
881b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
882b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      for (i=0; i<TTABLE_SIZE; ++i)
883b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
884b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         int transform = transform_info[i].transform;
885b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
886b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if ((transform_info[i].valid_chunks == 0 ||
887b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               (transform_info[i].valid_chunks & chunks) != 0) &&
888b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            (transform_info[i].color_mask_required & ct) ==
889b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               transform_info[i].color_mask_required &&
890b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            (transform_info[i].color_mask_absent & ct) == 0 &&
891b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            (transform_info[i].bit_depths & bd) != 0 &&
892b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            (transform_info[i].when & TRANSFORM_R) != 0)
893b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            active |= transform;
894b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
895b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         else if ((transform_info[i].when & TRANSFORM_R) != 0)
896b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            inactive |= transform;
897b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
898b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
899b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* Some transforms appear multiple times in the table; the 'active' status
900b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * is the logical OR of these and the inactive status must be adjusted to
901b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * take this into account.
902b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
903b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      inactive &= ~active;
904b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
905b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      dp->active_transforms = active;
906b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      dp->ignored_transforms = inactive; /* excluding write-only transforms */
907b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
908b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (active == 0)
909b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         display_log(dp, INTERNAL_ERROR, "bad transform table");
910b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
911b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
912b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
913b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic int
914b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraricompare_read(struct display *dp, int applied_transforms)
915b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
916b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Compare the png_info from read_ip with original_info */
917b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   size_t rowbytes;
918b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_uint_32 width, height;
919b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int bit_depth, color_type;
920b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int interlace_method, compression_method, filter_method;
921b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   const char *e = NULL;
922b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
923b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_get_IHDR(dp->read_pp, dp->read_ip, &width, &height, &bit_depth,
924b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      &color_type, &interlace_method, &compression_method, &filter_method);
925b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
926b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  define C(item) if (item != dp->item) \
927b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, APP_WARNING, "IHDR " #item "(%lu) changed to %lu",\
928b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         (unsigned long)dp->item, (unsigned long)item), e = #item
929b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
930b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* The IHDR should be identical: */
931b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   C(width);
932b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   C(height);
933b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   C(bit_depth);
934b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   C(color_type);
935b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   C(interlace_method);
936b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   C(compression_method);
937b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   C(filter_method);
938b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
939b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* 'e' remains set to the name of the last thing changed: */
940b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (e)
941b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, APP_ERROR, "IHDR changed (%s)", e);
942b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
943b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* All the chunks from the original PNG should be preserved in the output PNG
944b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * because the PNG format has not been changed.
945b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
946b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
947b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      unsigned long chunks =
948b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         png_get_valid(dp->read_pp, dp->read_ip, 0xffffffff);
949b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
950b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (chunks != dp->chunks)
951b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         display_log(dp, APP_FAIL, "PNG chunks changed from 0x%lx to 0x%lx",
952b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            (unsigned long)dp->chunks, chunks);
953b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
954b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
955b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* rowbytes should be the same */
956b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   rowbytes = png_get_rowbytes(dp->read_pp, dp->read_ip);
957b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
958b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* NOTE: on 64-bit systems this may trash the top bits of rowbytes,
959b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * which could lead to weird error messages.
960b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
961b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (rowbytes != dp->original_rowbytes)
962b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, APP_ERROR, "PNG rowbytes changed from %lu to %lu",
963b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         (unsigned long)dp->original_rowbytes, (unsigned long)rowbytes);
964b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
965b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* The rows should be the same too, unless the applied transforms includes
966b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * the shift transform, in which case low bits may have been lost.
967b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
968b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
969b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      png_bytepp rows = png_get_rows(dp->read_pp, dp->read_ip);
970b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      unsigned int mask;  /* mask (if not zero) for the final byte */
971b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
972b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (bit_depth < 8)
973b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
974b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* Need the stray bits at the end, this depends only on the low bits
975b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * of the image width; overflow does not matter.  If the width is an
976b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * exact multiple of 8 bits this gives a mask of 0, not 0xff.
977b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          */
978b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         mask = 0xff & (0xff00 >> ((bit_depth * width) & 7));
979b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
980b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
981b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else
982b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         mask = 0;
983b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
984b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (rows == NULL)
985b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         display_log(dp, LIBPNG_BUG, "png_get_rows returned NULL");
986b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
987b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if ((applied_transforms & PNG_TRANSFORM_SHIFT) == 0 ||
988b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         (dp->active_transforms & PNG_TRANSFORM_SHIFT) == 0 ||
989b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         color_type == PNG_COLOR_TYPE_PALETTE)
990b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
991b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         unsigned long y;
992b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
993b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         for (y=0; y<height; ++y)
994b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
995b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            png_bytep row = rows[y];
996b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            png_bytep orig = dp->original_rows[y];
997b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
998b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (memcmp(row, orig, rowbytes-(mask != 0)) != 0 || (mask != 0 &&
999b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               ((row[rowbytes-1] & mask) != (orig[rowbytes-1] & mask))))
1000b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            {
1001b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               size_t x;
1002b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1003b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               /* Find the first error */
1004b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               for (x=0; x<rowbytes-1; ++x) if (row[x] != orig[x])
1005b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  break;
1006b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1007b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               display_log(dp, APP_FAIL,
1008b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  "byte(%lu,%lu) changed 0x%.2x -> 0x%.2x",
1009b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  (unsigned long)x, (unsigned long)y, orig[x], row[x]);
1010b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               return 0; /* don't keep reporting failed rows on 'continue' */
1011b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            }
1012b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1013b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
1014b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1015b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else
1016b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
1017b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         unsigned long y;
1018b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         int bpp;   /* bits-per-pixel then bytes-per-pixel */
1019b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* components are up to 8 bytes in size */
1020b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         png_byte sig_bits[8];
1021b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         png_color_8p sBIT;
1022b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1023b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if (png_get_sBIT(dp->read_pp, dp->read_ip, &sBIT) != PNG_INFO_sBIT)
1024b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            display_log(dp, INTERNAL_ERROR,
1025b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               "active shift transform but no sBIT in file");
1026b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1027b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         switch (color_type)
1028b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1029b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            case PNG_COLOR_TYPE_GRAY:
1030b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[0] = sBIT->gray;
1031b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               bpp = bit_depth;
1032b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1033b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1034b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            case PNG_COLOR_TYPE_GA:
1035b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[0] = sBIT->gray;
1036b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[1] = sBIT->alpha;
1037b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               bpp = 2 * bit_depth;
1038b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1039b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1040b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            case PNG_COLOR_TYPE_RGB:
1041b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[0] = sBIT->red;
1042b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[1] = sBIT->green;
1043b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[2] = sBIT->blue;
1044b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               bpp = 3 * bit_depth;
1045b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1046b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1047b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            case PNG_COLOR_TYPE_RGBA:
1048b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[0] = sBIT->red;
1049b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[1] = sBIT->green;
1050b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[2] = sBIT->blue;
1051b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[3] = sBIT->alpha;
1052b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               bpp = 4 * bit_depth;
1053b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1054b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1055b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            default:
1056b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               display_log(dp, LIBPNG_ERROR, "invalid colour type %d",
1057b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  color_type);
1058b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               /*NOTREACHED*/
1059b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               bpp = 0;
1060b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1061b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1062b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1063b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1064b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            int b;
1065b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1066b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            for (b=0; 8*b<bpp; ++b)
1067b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            {
1068b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               /* libpng should catch this; if not there is a security issue
1069b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                * because an app (like this one) may overflow an array. In fact
1070b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                * libpng doesn't catch this at present.
1071b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                */
1072b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               if (sig_bits[b] == 0 || sig_bits[b] > bit_depth/*!palette*/)
1073b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  display_log(dp, LIBPNG_BUG,
1074b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                     "invalid sBIT[%u]  value %d returned for PNG bit depth %d",
1075b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                     b, sig_bits[b], bit_depth);
1076b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            }
1077b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1078b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1079b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if (bpp < 8 && bpp != bit_depth)
1080b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1081b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            /* sanity check; this is a grayscale PNG; something is wrong in the
1082b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari             * code above.
1083b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari             */
1084b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            display_log(dp, INTERNAL_ERROR, "invalid bpp %u for bit_depth %u",
1085b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               bpp, bit_depth);
1086b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1087b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1088b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         switch (bit_depth)
1089b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1090b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            int b;
1091b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1092b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            case 16: /* Two bytes per component, bit-endian */
1093b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               for (b = (bpp >> 4); b > 0; )
1094b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               {
1095b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  unsigned int sig = (unsigned int)(0xffff0000 >> sig_bits[b]);
1096b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1097b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  sig_bits[2*b+1] = (png_byte)sig;
1098b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  sig_bits[2*b+0] = (png_byte)(sig >> 8); /* big-endian */
1099b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               }
1100b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1101b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1102b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            case 8: /* One byte per component */
1103b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               for (b=0; b*8 < bpp; ++b)
1104b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  sig_bits[b] = (png_byte)(0xff00 >> sig_bits[b]);
1105b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1106b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1107b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            case 1: /* allowed, but dumb */
1108b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               /* Value is 1 */
1109b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[0] = 0xff;
1110b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1111b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1112b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            case 2: /* Replicate 4 times */
1113b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               /* Value is 1 or 2 */
1114b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               b = 0x3 & ((0x3<<2) >> sig_bits[0]);
1115b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               b |= b << 2;
1116b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               b |= b << 4;
1117b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[0] = (png_byte)b;
1118b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1119b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1120b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            case 4: /* Relicate twice */
1121b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               /* Value is 1, 2, 3 or 4 */
1122b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               b = 0xf & ((0xf << 4) >> sig_bits[0]);
1123b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               b |= b << 4;
1124b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               sig_bits[0] = (png_byte)b;
1125b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1126b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1127b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            default:
1128b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               display_log(dp, LIBPNG_BUG, "invalid bit depth %d", bit_depth);
1129b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               break;
1130b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1131b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1132b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* Convert bpp to bytes; this gives '1' for low-bit depth grayscale,
1133b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * where there are multiple pixels per byte.
1134b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          */
1135b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         bpp = (bpp+7) >> 3;
1136b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1137b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* The mask can be combined with sig_bits[0] */
1138b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if (mask != 0)
1139b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1140b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            mask &= sig_bits[0];
1141b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1142b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (bpp != 1 || mask == 0)
1143b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               display_log(dp, INTERNAL_ERROR, "mask calculation error %u, %u",
1144b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  bpp, mask);
1145b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1146b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1147b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         for (y=0; y<height; ++y)
1148b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1149b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            png_bytep row = rows[y];
1150b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            png_bytep orig = dp->original_rows[y];
1151b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            unsigned long x;
1152b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1153b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            for (x=0; x<(width-(mask!=0)); ++x)
1154b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            {
1155b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               int b;
1156b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1157b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               for (b=0; b<bpp; ++b)
1158b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               {
1159b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  if ((*row++ & sig_bits[b]) != (*orig++ & sig_bits[b]))
1160b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  {
1161b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                     display_log(dp, APP_FAIL,
1162b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                        "significant bits at (%lu[%u],%lu) changed %.2x->%.2x",
1163b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                        x, b, y, orig[-1], row[-1]);
1164b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                     return 0;
1165b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  }
1166b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               }
1167b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            }
1168b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1169b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (mask != 0 && (*row & mask) != (*orig & mask))
1170b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            {
1171b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               display_log(dp, APP_FAIL,
1172b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  "significant bits at (%lu[end],%lu) changed", x, y);
1173b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               return 0;
1174b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            }
1175b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         } /* for y */
1176b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
1177b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
1178b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1179b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return 1; /* compare succeeded */
1180b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
1181b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1182b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_SUPPORTED
1183b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
1184b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraribuffer_write(struct display *dp, struct buffer *buffer, png_bytep data,
1185b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_size_t size)
1186b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Generic write function used both from the write callback provided to
1187b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * libpng and from the generic read code.
1188b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
1189b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
1190b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Write the data into the buffer, adding buffers as required */
1191b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct buffer_list *last = buffer->last;
1192b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   size_t end_count = buffer->end_count;
1193b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1194b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   while (size > 0)
1195b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
1196b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      size_t avail;
1197b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1198b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (end_count >= sizeof last->buffer)
1199b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
1200b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if (last->next == NULL)
1201b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1202b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            last = buffer_extend(last);
1203b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1204b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (last == NULL)
1205b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               display_log(dp, APP_ERROR, "out of memory saving file");
1206b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1207b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1208b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         else
1209b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            last = last->next;
1210b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1211b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         buffer->last = last; /* avoid the need to rewrite every time */
1212b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         end_count = 0;
1213b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
1214b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1215b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      avail = (sizeof last->buffer) - end_count;
1216b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (avail > size)
1217b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         avail = size;
1218b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1219b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      memcpy(last->buffer + end_count, data, avail);
1220b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      end_count += avail;
1221b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      size -= avail;
1222b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      data += avail;
1223b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
1224b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1225b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer->end_count = end_count;
1226b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
1227b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1228b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void PNGCBAPI
1229b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariwrite_function(png_structp pp, png_bytep data, png_size_t size)
1230b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
1231b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer_write(get_dp(pp), get_buffer(pp), data, size);
1232b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
1233b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1234b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
1235b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariwrite_png(struct display *dp, png_infop ip, int transforms)
1236b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
1237b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   display_clean_write(dp); /* safety */
1238b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1239b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   buffer_start_write(&dp->written_file);
1240b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->operation = "write";
1241b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->transforms = transforms;
1242b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1243b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->write_pp = png_create_write_struct(PNG_LIBPNG_VER_STRING, dp,
1244b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_error, display_warning);
1245b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1246b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (dp->write_pp == NULL)
1247b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, APP_ERROR, "failed to create write png_struct");
1248b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1249b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_set_write_fn(dp->write_pp, &dp->written_file, write_function,
1250b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      NULL/*flush*/);
1251b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1252b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  ifdef PNG_SET_USER_LIMITS_SUPPORTED
1253b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* Remove the user limits, if any */
1254b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      png_set_user_limits(dp->write_pp, 0x7fffffff, 0x7fffffff);
1255b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  endif
1256b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1257b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Certain transforms require the png_info to be zapped to allow the
1258b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * transform to work correctly.
1259b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
1260b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (transforms & (PNG_TRANSFORM_PACKING|
1261b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                     PNG_TRANSFORM_STRIP_FILLER|
1262b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                     PNG_TRANSFORM_STRIP_FILLER_BEFORE))
1263b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
1264b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      int ct = dp->color_type;
1265b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1266b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (transforms & (PNG_TRANSFORM_STRIP_FILLER|
1267b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                        PNG_TRANSFORM_STRIP_FILLER_BEFORE))
1268b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         ct &= ~PNG_COLOR_MASK_ALPHA;
1269b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1270b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      png_set_IHDR(dp->write_pp, ip, dp->width, dp->height, dp->bit_depth, ct,
1271b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         dp->interlace_method, dp->compression_method, dp->filter_method);
1272b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
1273b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1274b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_write_png(dp->write_pp, ip, transforms, NULL/*params*/);
1275b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1276b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Clean it on the way out - if control returns to the caller then the
1277b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * written_file contains the required data.
1278b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
1279b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   display_clean_write(dp);
1280b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
1281b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* WRITE_SUPPORTED */
1282b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1283b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic int
1284b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariskip_transform(struct display *dp, int tr)
1285b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Helper to test for a bad combo and log it if it is skipped */
1286b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
1287b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if ((dp->options & SKIP_BUGS) != 0 && is_bad_combo(tr))
1288b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
1289b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* Log this to stdout if logging is on, otherwise just do an information
1290b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * display_log.
1291b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
1292b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if ((dp->options & LOG_SKIPPED) != 0)
1293b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
1294b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         printf("SKIP: %s transforms ", dp->filename);
1295b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1296b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         while (tr != 0)
1297b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1298b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            int next = first_transform(tr);
1299b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            tr &= ~next;
1300b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1301b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            printf("%s", transform_name(next));
1302b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (tr != 0)
1303b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               putchar('+');
1304b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1305b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1306b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         putchar('\n');
1307b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
1308b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1309b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else
1310b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         display_log(dp, INFORMATION, "%s: skipped known bad combo 0x%x",
1311b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            dp->filename, tr);
1312b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1313b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      return 1; /* skip */
1314b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
1315b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1316b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return 0; /* don't skip */
1317b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
1318b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1319b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic void
1320b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraritest_one_file(struct display *dp, const char *filename)
1321b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
1322b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* First cache the file and update the display original file
1323b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * information for the new file.
1324b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
1325b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->operation = "cache file";
1326b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->transforms = 0;
1327b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   display_cache_file(dp, filename);
1328b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   update_display(dp);
1329b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1330b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* First test: if there are options that should be ignored for this file
1331b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * verify that they really are ignored.
1332b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
1333b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (dp->ignored_transforms != 0)
1334b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
1335b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      read_png(dp, &dp->original_file, "ignored transforms",
1336b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         dp->ignored_transforms);
1337b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1338b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* The result should be identical to the original_rows */
1339b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (!compare_read(dp, 0/*transforms applied*/))
1340b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         return; /* no point testing more */
1341b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
1342b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1343b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_SUPPORTED
1344b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Second test: write the original PNG data out to a new file (to test the
1345b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * write side) then read the result back in and make sure that it hasn't
1346b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * changed.
1347b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
1348b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   dp->operation = "write";
1349b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   write_png(dp, dp->original_ip, 0/*transforms*/);
1350b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   read_png(dp, &dp->written_file, NULL, 0/*transforms*/);
1351b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (!compare_read(dp, 0/*transforms applied*/))
1352b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      return;
1353b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
1354b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1355b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Third test: the active options.  Test each in turn, or, with the
1356b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    * EXHAUSTIVE option, test all possible combinations.
1357b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari    */
1358b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
1359b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* Use unsigned int here because the code below to increment through all
1360b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * the possibilities exhaustively has to use a compare and that must be
1361b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       * unsigned, because some transforms are negative on a 16-bit system.
1362b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari       */
1363b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      unsigned int active = dp->active_transforms;
1364b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      const int exhaustive = (dp->options & EXHAUSTIVE) != 0;
1365b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      unsigned int current = first_transform(active);
1366b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      unsigned int bad_transforms = 0;
1367b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      unsigned int bad_combo = ~0U;    /* bitwise AND of failing transforms */
1368b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      unsigned int bad_combo_list = 0; /* bitwise OR of failures */
1369b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1370b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      for (;;)
1371b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
1372b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         read_png(dp, &dp->original_file, "active transforms", current);
1373b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1374b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* If this involved any irreversible transformations then if we write
1375b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * it out with just the reversible transformations and read it in again
1376b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * with the same transforms we should get the same thing.  At present
1377b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * this isn't done - it just seems like a waste of time and it would
1378b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * require two sets of read png_struct/png_info.
1379b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          *
1380b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * If there were no irreversible transformations then if we write it
1381b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * out and read it back in again (without the reversible transforms)
1382b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * we should get back to the place where we started.
1383b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          */
1384b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_WRITE_SUPPORTED
1385b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if ((current & write_transforms) == current)
1386b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1387b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            /* All transforms reversible: write the PNG with the transformations
1388b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari             * reversed, then read it back in with no transformations.  The
1389b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari             * result should be the same as the original apart from the loss of
1390b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari             * low order bits because of the SHIFT/sBIT transform.
1391b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari             */
1392b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            dp->operation = "reversible transforms";
1393b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            write_png(dp, dp->read_ip, current);
1394b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1395b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            /* And if this is read back in, because all the transformations were
1396b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari             * reversible, the result should be the same.
1397b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari             */
1398b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            read_png(dp, &dp->written_file, NULL, 0);
1399b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (!compare_read(dp, current/*for the SHIFT/sBIT transform*/))
1400b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            {
1401b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               /* This set of transforms failed.  If a single bit is set - if
1402b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                * there is just one transform - don't include this in further
1403b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                * 'exhaustive' tests.  Notice that each transform is tested on
1404b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                * its own before testing combos in the exhaustive case.
1405b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                */
1406b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               if (is_combo(current))
1407b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               {
1408b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  bad_combo &= current;
1409b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  bad_combo_list |= current;
1410b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               }
1411b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1412b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               else
1413b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  bad_transforms |= current;
1414b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            }
1415b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1416b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
1417b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1418b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* Now move to the next transform */
1419b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if (exhaustive) /* all combinations */
1420b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1421b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            unsigned int next = current;
1422b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1423b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            do
1424b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            {
1425b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               if (next == read_transforms) /* Everything tested */
1426b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  goto combo;
1427b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1428b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               ++next;
1429b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            }  /* skip known bad combos if the relevant option is set; skip
1430b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                * combos involving known bad single transforms in all cases.
1431b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                */
1432b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            while (  (next & read_transforms) <= current
1433b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  || (next & active) == 0 /* skip cases that do nothing */
1434b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  || (next & bad_transforms) != 0
1435b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  || skip_transform(dp, next));
1436b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1437b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            assert((next & read_transforms) == next);
1438b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            current = next;
1439b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1440b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1441b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         else /* one at a time */
1442b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1443b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            active &= ~current;
1444b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1445b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (active == 0)
1446b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               goto combo;
1447b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1448b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            current = first_transform(active);
1449b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1450b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
1451b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1452b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraricombo:
1453b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (dp->options & FIND_BAD_COMBOS)
1454b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
1455b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* bad_combos identifies the combos that occur in all failing cases;
1456b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * bad_combo_list identifies transforms that do not prevent the
1457b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * failure.
1458b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          */
1459b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         if (bad_combo != ~0U)
1460b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            printf("%s[0x%x]: PROBLEM: 0x%x[0x%x] ANTIDOTE: 0x%x\n",
1461b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               dp->filename, active, bad_combo, bad_combo_list,
1462b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               rw_transforms & ~bad_combo_list);
1463b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1464b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         else
1465b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            printf("%s: no %sbad combos found\n", dp->filename,
1466b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               (dp->options & SKIP_BUGS) ? "additional " : "");
1467b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
1468b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
1469b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
1470b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1471b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic int
1472b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurarido_test(struct display *dp, const char *file)
1473b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* Exists solely to isolate the setjmp clobbers */
1474b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
1475b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int ret = setjmp(dp->error_return);
1476b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1477b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (ret == 0)
1478b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
1479b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      test_one_file(dp, file);
1480b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      return 0;
1481b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
1482b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1483b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   else if (ret < ERRORS) /* shouldn't longjmp on warnings */
1484b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret);
1485b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1486b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return ret;
1487b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
1488b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1489b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariint
1490b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurarimain(const int argc, const char * const * const argv)
1491b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
1492b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   /* For each file on the command line test it with a range of transforms */
1493b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int option_end, ilog = 0;
1494b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   struct display d;
1495b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1496b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   validate_T();
1497b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   display_init(&d);
1498b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1499b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   for (option_end=1; option_end<argc; ++option_end)
1500b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
1501b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      const char *name = argv[option_end];
1502b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1503b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      if (strcmp(name, "--verbose") == 0)
1504b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options = (d.options & ~LEVEL_MASK) | VERBOSE;
1505b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1506b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--warnings") == 0)
1507b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options = (d.options & ~LEVEL_MASK) | WARNINGS;
1508b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1509b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--errors") == 0)
1510b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options = (d.options & ~LEVEL_MASK) | ERRORS;
1511b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1512b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--quiet") == 0)
1513b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options = (d.options & ~LEVEL_MASK) | QUIET;
1514b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1515b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--exhaustive") == 0)
1516b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options |= EXHAUSTIVE;
1517b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1518b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--fast") == 0)
1519b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options &= ~EXHAUSTIVE;
1520b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1521b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--strict") == 0)
1522b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options |= STRICT;
1523b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1524b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--relaxed") == 0)
1525b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options &= ~STRICT;
1526b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1527b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--log") == 0)
1528b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
1529b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         ilog = option_end; /* prevent display */
1530b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options |= LOG;
1531b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
1532b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1533b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--nolog") == 0)
1534b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options &= ~LOG;
1535b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1536b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--continue") == 0)
1537b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options |= CONTINUE;
1538b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1539b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--stop") == 0)
1540b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options &= ~CONTINUE;
1541b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1542b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--skip-bugs") == 0)
1543b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options |= SKIP_BUGS;
1544b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1545b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--test-all") == 0)
1546b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options &= ~SKIP_BUGS;
1547b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1548b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--log-skipped") == 0)
1549b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options |= LOG_SKIPPED;
1550b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1551b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--nolog-skipped") == 0)
1552b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options &= ~LOG_SKIPPED;
1553b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1554b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--find-bad-combos") == 0)
1555b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options |= FIND_BAD_COMBOS;
1556b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1557b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (strcmp(name, "--nofind-bad-combos") == 0)
1558b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         d.options &= ~FIND_BAD_COMBOS;
1559b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1560b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else if (name[0] == '-' && name[1] == '-')
1561b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
1562b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         fprintf(stderr, "pngimage: %s: unknown option\n", name);
1563b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         return 99;
1564b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
1565b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1566b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      else
1567b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         break; /* Not an option */
1568b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
1569b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1570b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
1571b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      int i;
1572b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      int errors = 0;
1573b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1574b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      for (i=option_end; i<argc; ++i)
1575b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      {
1576b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1577b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            int ret = do_test(&d, argv[i]);
1578b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1579b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (ret > QUIET) /* abort on user or internal error */
1580b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               return 99;
1581b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1582b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1583b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* Here on any return, including failures, except user/internal issues
1584b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          */
1585b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         {
1586b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            const int pass = (d.options & STRICT) ?
1587b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               RESULT_STRICT(d.results) : RESULT_RELAXED(d.results);
1588b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1589b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (!pass)
1590b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               ++errors;
1591b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1592b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            if (d.options & LOG)
1593b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            {
1594b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               int j;
1595b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1596b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               printf("%s: pngimage ", pass ? "PASS" : "FAIL");
1597b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1598b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               for (j=1; j<option_end; ++j) if (j != ilog)
1599b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari                  printf("%s ", argv[j]);
1600b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1601b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari               printf("%s\n", d.filename);
1602b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari            }
1603b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         }
1604b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1605b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         display_clean(&d);
1606b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      }
1607b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
1608b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      return errors != 0;
1609b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
1610b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
1611b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else /* !PNG_INFO_IMAGE_SUPPORTED || !PNG_READ_SUPPORTED */
1612b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariint
1613b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurarimain(void)
1614b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
1615b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   fprintf(stderr, "pngimage: no support for png_read/write_image\n");
1616b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   return 77;
1617b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
1618b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
1619