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