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