diff options
Diffstat (limited to 'Build/source/libs/libpng/libpng-1.6.18/contrib/tools')
10 files changed, 6117 insertions, 0 deletions
diff --git a/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/README.txt b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/README.txt new file mode 100644 index 00000000000..5ddae02ce9b --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/README.txt @@ -0,0 +1,26 @@ +This directory (contrib/tools) contains tools used by the authors of libpng. + +Code and data placed in this directory is not required to build libpng, +however the code in this directory has been used to generate data or code in +the body of the libpng source. The source code identifies where this has +been done. Code in this directory may not compile on all operating systems +that libpng supports. + +NO COPYRIGHT RIGHTS ARE CLAIMED TO ANY OF THE FILES IN THIS DIRECTORY. + +To the extent possible under law, the authors have waived all copyright and +related or neighboring rights to this work. This work is published from: +United States. + +The files may be used freely in any way. + +The source code and comments in this directory are the original work of the +people named below. No other person or organization has made contributions to +the work in this directory. + +ORIGINAL AUTHORS + The following people have contributed to the code in this directory. None + of the people below claim any rights with regard to the contents of this + directory. + + John Bowler <jbowler@acm.org> diff --git a/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/checksum-icc.c b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/checksum-icc.c new file mode 100644 index 00000000000..581e7088a62 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/checksum-icc.c @@ -0,0 +1,102 @@ +/* checksum-icc.c + * + * Copyright (c) 2013 John Cunningham Bowler + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Generate crc32 and adler32 checksums of the given input files, used to + * generate check-codes for use when matching ICC profiles within libpng. + */ +#include <stdio.h> + +#include <zlib.h> + +static int +read_one_file(FILE *ip, const char *name) +{ + uLong length = 0; + uLong a32 = adler32(0, NULL, 0); + uLong c32 = crc32(0, NULL, 0); + Byte header[132]; + + for (;;) + { + int ch = getc(ip); + Byte b; + + if (ch == EOF) break; + + b = (Byte)ch; + + if (length < sizeof header) + header[length] = b; + + ++length; + a32 = adler32(a32, &b, 1); + c32 = crc32(c32, &b, 1); + } + + if (ferror(ip)) + return 0; + + /* Success */ + printf("PNG_ICC_CHECKSUM(0x%8.8lx, 0x%8.8lx,\n PNG_MD5(" + "0x%2.2x%2.2x%2.2x%2.2x, 0x%2.2x%2.2x%2.2x%2.2x, 0x%2.2x%2.2x%2.2x%2.2x," + " 0x%2.2x%2.2x%2.2x%2.2x), %d,\n" + " \"%4.4d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d\", %lu, \"%s\")\n", + (unsigned long)a32, (unsigned long)c32, + header[84], header[85], header[86], header[87], + header[88], header[89], header[90], header[91], + header[92], header[93], header[94], header[95], + header[96], header[97], header[98], header[99], +# define u16(x) (header[x] * 256 + header[x+1]) +# define u32(x) (u16(x) * 65536 + u16(x+2)) + u32(64), u16(24), u16(26), u16(28), u16(30), u16(32), u16(34), + (unsigned long)length, name); + + return 1; +} + +int main(int argc, char **argv) +{ + int err = 0; + + printf("/* adler32, crc32, MD5[16], intent, date, length, file-name */\n"); + + if (argc > 1) + { + int i; + + for (i=1; i<argc; ++i) + { + FILE *ip = fopen(argv[i], "rb"); + + if (ip == NULL || !read_one_file(ip, argv[i])) + { + err = 1; + perror(argv[i]); + fprintf(stderr, "%s: read error\n", argv[i]); + printf("/* ERROR: %s */\n", argv[i]); + } + + (void)fclose(ip); + } + } + + else + { + if (!read_one_file(stdin, "-")) + { + err = 1; + perror("stdin"); + fprintf(stderr, "stdin: read error\n"); + printf("/* ERROR: stdin */\n"); + } + } + + return err; +} diff --git a/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/chkfmt b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/chkfmt new file mode 100755 index 00000000000..9da6475fd4e --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/chkfmt @@ -0,0 +1,137 @@ +#!/bin/sh +# +# Check the format of the source files in the current directory - checks for a +# line length of 80 characters max and no tab characters. +# +# Optionally arguments are files or directories to check. +# +# -v: output the long lines (makes fixing them easier) +# -e: spawn an editor for each file that needs a change ($EDITOR must be +# defined). When using -e the script MUST be run from an interactive +# command line. +verbose= +edit= +vers= +test "$1" = "-v" && { + shift + verbose=yes +} +test "$1" = "-e" && { + shift + if test -n "$EDITOR" + then + edit=yes + + # Copy the standard streams for the editor + exec 3>&0 4>&1 5>&2 + else + echo "chkfmt -e: EDITOR must be defined" >&2 + exit 1 + fi +} + +# Function to edit a single file - if the file isn't changed ask the user +# whether or not to continue. This stuff only works if the script is run from +# the command line (otherwise, don't specify -e or you will be sorry). +doed(){ + cp "$file" "$file".orig + "$EDITOR" "$file" 0>&3 1>&4 2>&5 3>&- 4>&- 5>&- || exit 1 + if cmp -s "$file".orig "$file" + then + rm "$file".orig + echo -n "$file: file not changed, type anything to continue: " >&5 + read ans 0>&3 + test -n "$ans" || return 1 + fi + return 0 +} + +# In beta versions the version string which appears in files can be a little +# long and cause spuriously overlong lines. To avoid this subtitute the version +# string with a 'standard' version a.b.cc before checking for long lines. +if test -r png.h +then + vers="`sed -n -e \ + 's/^#define PNG_LIBPNG_VER_STRING .\([0-9]\.[0-9]\.[0-9][0-9a-z]*\).$/\1/p' \ + png.h`" + echo "chkfmt: checking version $vers" +fi +if test -z "$vers" +then + echo "chkfmt: png.h not found, ignoring version number" >&2 +fi + +test -n "$1" || set -- . +find "$@" \( -type d \( -name '.git' -o -name '.libs' -o -name 'projects' \) \ + -prune \) -o \( -type f \ + ! -name '*.[oa]' ! -name '*.l[oa]' ! -name '*.png' ! -name '*.out' \ + ! -name '*.jpg' ! -name '*.patch' ! -name '*.obj' ! -name '*.exe' \ + ! -name '*.com' ! -name '*.tar.*' ! -name '*.zip' ! -name '*.ico' \ + ! -name '*.res' ! -name '*.rc' ! -name '*.mms' ! -name '*.rej' \ + ! -name '*.dsp' ! -name '*.orig' ! -name '*.dfn' ! -name '*.swp' \ + ! -name '~*' ! -name '*.3' \ + ! -name 'missing' ! -name 'mkinstalldirs' ! -name 'depcomp' \ + ! -name 'aclocal.m4' ! -name 'install-sh' ! -name 'Makefile.in' \ + ! -name 'ltmain.sh' ! -name 'config*' -print \) | { + st=0 + while read file + do + case "$file" in + *.mak|*[Mm]akefile.*|*[Mm]akefile) + # Makefiles require tabs, dependency lines can be this long. + check_tabs= + line_length=100;; + *.awk) + # Includes literal tabs + check_tabs= + # The following is arbitrary + line_length=132;; + *contrib/*/*.[ch]) + check_tabs=yes + line_length=96;; + *) + check_tabs=yes + line_length=80;; + esac + + # Note that vers can only contain 0-9, . and a-z + if test -n "$vers" + then + sed -e "s/$vers/a.b.cc/g" "$file" >"$file".$$ + else + cp "$file" "$file".$$ + fi + splt="`fold -$line_length "$file".$$ | diff -c "$file".$$ -`" + rm "$file".$$ + + if test -n "$splt" + then + echo "$file: lines too long" + st=1 + if test -n "$EDITOR" -a -n "$edit" + then + doed "$file" || exit 1 + elif test -n "$verbose" + then + echo "$splt" + fi + fi + if test -n "$check_tabs" + then + tab="`tr -c -d '\t' <"$file"`" + if test -n "$tab" + then + echo "$file: file contains tab characters" + st=1 + if test -n "$EDITOR" -a -n "$edit" + then + doed "$file" || exit 1 + elif test -n "$verbose" + then + echo "$splt" + fi + fi + fi + done + exit $st +} diff --git a/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/cvtcolor.c b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/cvtcolor.c new file mode 100644 index 00000000000..e6793c7d596 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/cvtcolor.c @@ -0,0 +1,188 @@ +/*- + * convert.c + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * + * COPYRIGHT: Written by John Cunningham Bowler, 2013. + * To the extent possible under law, the author has waived all copyright and + * related or neighboring rights to this work. This work is published from: + * United States. + * + * Convert 8-bit sRGB or 16-bit linear values to another format. + */ +#define _ISOC99_SOURCE 1 + +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <stdio.h> + +#include <fenv.h> + +#include "sRGB.h" + +static void +usage(const char *prog) +{ + fprintf(stderr, + "%s: usage: %s [-linear|-sRGB] [-gray|-color] component{1,4}\n", + prog, prog); + exit(1); +} + +unsigned long +component(const char *prog, const char *arg, int issRGB) +{ + char *ep; + unsigned long c = strtoul(arg, &ep, 0); + + if (ep <= arg || *ep || c > 65535 || (issRGB && c > 255)) + { + fprintf(stderr, "%s: %s: invalid component value (%lu)\n", prog, arg, c); + usage(prog); + } + + return c; +} + +int +main(int argc, const char **argv) +{ + const char *prog = *argv++; + int to_linear = 0, to_gray = 0, to_color = 0; + int channels = 0; + double c[4]; + + /* FE_TONEAREST is the IEEE754 round to nearest, preferring even, mode; i.e. + * everything rounds to the nearest value except that '.5' rounds to the + * nearest even value. + */ + fesetround(FE_TONEAREST); + + c[3] = c[2] = c[1] = c[0] = 0; + + while (--argc > 0 && **argv == '-') + { + const char *arg = 1+*argv++; + + if (strcmp(arg, "sRGB") == 0) + to_linear = 0; + + else if (strcmp(arg, "linear") == 0) + to_linear = 1; + + else if (strcmp(arg, "gray") == 0) + to_gray = 1, to_color = 0; + + else if (strcmp(arg, "color") == 0) + to_gray = 0, to_color = 1; + + else + usage(prog); + } + + switch (argc) + { + default: + usage(prog); + break; + + case 4: + c[3] = component(prog, argv[3], to_linear); + ++channels; + case 3: + c[2] = component(prog, argv[2], to_linear); + ++channels; + case 2: + c[1] = component(prog, argv[1], to_linear); + ++channels; + case 1: + c[0] = component(prog, argv[0], to_linear); + ++channels; + break; + } + + if (to_linear) + { + int i; + int components = channels; + + if ((components & 1) == 0) + --components; + + for (i=0; i<components; ++i) c[i] = linear_from_sRGB(c[i] / 255); + if (components < channels) + c[components] = c[components] / 255; + } + + else + { + int i; + for (i=0; i<4; ++i) c[i] /= 65535; + + if ((channels & 1) == 0) + { + double alpha = c[channels-1]; + + if (alpha > 0) + for (i=0; i<channels-1; ++i) c[i] /= alpha; + else + for (i=0; i<channels-1; ++i) c[i] = 1; + } + } + + if (to_gray) + { + if (channels < 3) + { + fprintf(stderr, "%s: too few channels (%d) for -gray\n", + prog, channels); + usage(prog); + } + + c[0] = YfromRGB(c[0], c[1], c[2]); + channels -= 2; + } + + if (to_color) + { + if (channels > 2) + { + fprintf(stderr, "%s: too many channels (%d) for -color\n", + prog, channels); + usage(prog); + } + + c[3] = c[1]; /* alpha, if present */ + c[2] = c[1] = c[0]; + } + + if (to_linear) + { + int i; + if ((channels & 1) == 0) + { + double alpha = c[channels-1]; + for (i=0; i<channels-1; ++i) c[i] *= alpha; + } + + for (i=0; i<channels; ++i) c[i] = nearbyint(c[i] * 65535); + } + + else /* to sRGB */ + { + int i = (channels+1)&~1; + while (--i >= 0) + c[i] = sRGB_from_linear(c[i]); + + for (i=0; i<channels; ++i) c[i] = nearbyint(c[i] * 255); + } + + { + int i; + for (i=0; i<channels; ++i) printf(" %g", c[i]); + } + printf("\n"); + + return 0; +} diff --git a/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/genpng.c b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/genpng.c new file mode 100644 index 00000000000..44102b4d69b --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/genpng.c @@ -0,0 +1,867 @@ +/*- genpng + * + * COPYRIGHT: Written by John Cunningham Bowler, 2015. + * To the extent possible under law, the author has waived all copyright and + * related or neighboring rights to this work. This work is published from: + * United States. + * + * Generate a PNG with an alpha channel, correctly. + * + * This is a test case generator; the resultant PNG files are only of interest + * to those of us who care about whether the edges of circles are green, red, + * or yellow. + * + * The program generates an RGB+Alpha PNG of a given size containing the given + * shapes on a transparent background: + * + * genpng width height { shape } + * shape ::= color width shape x1 y1 x2 y2 + * + * 'color' is: + * + * black white red green yellow blue brown purple pink orange gray cyan + * + * The point is to have colors that are linguistically meaningful plus that old + * bugbear of the department store dress murders, Cyan, the only color we argue + * about. + * + * 'shape' is: + * + * circle: an ellipse + * square: a rectangle + * line: a straight line + * + * Each shape is followed by four numbers, these are two points in the output + * coordinate space (as real numbers) which describe the circle, square, or + * line. The shape is filled if it is preceded by 'filled' (not valid for + * 'line') or is drawn with a line, in which case the width of the line must + * precede the shape. + * + * The whole set of information can be repeated as many times as desired: + * + * shape ::= color width shape x1 y1 x2 y2 + * + * color ::= black|white|red|green|yellow|blue + * color ::= brown|purple|pink|orange|gray|cyan + * width ::= filled + * width ::= <number> + * shape ::= circle|square|line + * x1 ::= <number> + * x2 ::= <number> + * y1 ::= <number> + * y2 ::= <number> + * + * The output PNG is generated by down-sampling a 4x supersampled image using + * a bi-cubic filter. The bi-cubic has a 2 (output) pixel width, so an 8x8 + * array of super-sampled points contribute to each output pixel. The value of + * a super-sampled point is found using an unfiltered, aliased, infinite + * precision image: Each shape from the last to the first is checked to see if + * the point is in the drawn area and, if it is, the color of the point is the + * color of the shape and the alpha is 1, if not the previous shape is checked. + * + * This is an aliased algorithm because no filtering is done; a point is either + * inside or outside each shape and 'close' points do not contribute to the + * sample. The down-sampling is relied on to correct the error of not using + * a filter. + * + * The line end-caps are 'flat'; they go through the points. The square line + * joins are mitres; the outside of the lines are continued to the point of + * intersection. + */ +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> + +/* Normally use <png.h> here to get the installed libpng, but this is done to + * ensure the code picks up the local libpng implementation: + */ +#include "../../png.h" + +#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) + +static const struct color +{ + const char *name; + double red; + double green; + double blue; +} colors[] = +/* color ::= black|white|red|green|yellow|blue + * color ::= brown|purple|pink|orange|gray|cyan + */ +{ + { "black", 0, 0, 0 }, + { "white", 1, 1, 1 }, + { "red", 1, 0, 0 }, + { "green", 0, 1, 0 }, + { "yellow", 1, 1, 0 }, + { "blue", 0, 0, 1 }, + { "brown", .5, .125, 0 }, + { "purple", 1, 0, 1 }, + { "pink", 1, .5, .5 }, + { "orange", 1, .5, 0 }, + { "gray", 0, .5, .5 }, + { "cyan", 0, 1, 1 } +}; +#define color_count ((sizeof colors)/(sizeof colors[0])) + +static const struct color * +color_of(const char *arg) +{ + int icolor = color_count; + + while (--icolor >= 0) + { + if (strcmp(colors[icolor].name, arg) == 0) + return colors+icolor; + } + + fprintf(stderr, "genpng: invalid color %s\n", arg); + exit(1); +} + +static double +width_of(const char *arg) +{ + if (strcmp(arg, "filled") == 0) + return 0; + + else + { + char *ep = NULL; + double w = strtod(arg, &ep); + + if (ep != NULL && *ep == 0 && w > 0) + return w; + } + + fprintf(stderr, "genpng: invalid line width %s\n", arg); + exit(1); +} + +static double +coordinate_of(const char *arg) +{ + char *ep = NULL; + double w = strtod(arg, &ep); + + if (ep != NULL && *ep == 0) + return w; + + fprintf(stderr, "genpng: invalid coordinate value %s\n", arg); + exit(1); +} + +struct arg; /* forward declaration */ + +typedef int (*shape_fn_ptr)(const struct arg *arg, double x, double y); + /* A function to determine if (x,y) is inside the shape. + * + * There are two implementations: + * + * inside_fn: returns true if the point is inside + * check_fn: returns; + * -1: the point is outside the shape by more than the filter width (2) + * 0: the point may be inside the shape + * +1: the point is inside the shape by more than the filter width + */ +#define OUTSIDE (-1) +#define INSIDE (1) + +struct arg +{ + const struct color *color; + shape_fn_ptr inside_fn; + shape_fn_ptr check_fn; + double width; /* line width, 0 for 'filled' */ + double x1, y1, x2, y2; +}; + +/* IMPLEMENTATION NOTE: + * + * We want the contribution of each shape to the sample corresponding to each + * pixel. This could be obtained by super sampling the image to infinite + * dimensions, finding each point within the shape and assigning that a value + * '1' while leaving every point outside the shape with value '0' then + * downsampling to the image size with sinc; computationally very expensive. + * + * Approximations are as follows: + * + * 1) If the pixel coordinate is within the shape assume the sample has the + * shape color and is opaque, else assume there is no contribution from + * the shape. + * + * This is the equivalent of aliased rendering or resampling an image with + * a block filter. The maximum error in the calculated alpha (which will + * always be 0 or 1) is 0.5. + * + * 2) If the shape is within a square of size 1x1 centered on the pixel assume + * that the shape obscures an amount of the pixel equal to its area within + * that square. + * + * This is the equivalent of 'pixel coverage' alpha calculation or resampling + * an image with a bi-linear filter. The maximum error is over 0.2, but the + * results are often acceptable. + * + * This can be approximated by applying (1) to a super-sampled image then + * downsampling with a bi-linear filter. The error in the super-sampled + * image is 0.5 per sample, but the resampling reduces this. + * + * 3) Use a better filter with a super-sampled image; in the limit this is the + * sinc() approach. + * + * 4) Do the geometric calculation; a bivariate definite integral across the + * shape, unfortunately this means evaluating Si(x), the integral of sinc(x), + * which is still a lot of math. + * + * This code uses approach (3) with a bi-cubic filter and 8x super-sampling + * and method (1) for the super-samples. This means that the sample is either + * 0 or 1, depending on whether the sub-pixel is within or outside the shape. + * The bi-cubic weights are also fixed and the 16 required weights are + * pre-computed here (note that the 'scale' setting will need to be changed if + * 'super' is increased). + * + * The code also calculates a sum to the edge of the filter. This is not + * currently used by could be used to optimize the calculation. + */ +#if 0 /* bc code */ +scale=10 +super=8 +define bicubic(x) { + if (x <= 1) return (1.5*x - 2.5)*x*x + 1; + if (x < 2) return (((2.5 - 0.5*x)*x - 4)*x + 2); + return 0; +} +define sum(x) { + auto s; + s = 0; + while (x < 2*super) { + s = s + bicubic(x/super); + x = x + 1; + } + return s; +} +define results(x) { + auto b, s; + b = bicubic(x/super); + s = sum(x); + + print " /*", x, "*/ { ", b, ", ", s, " }"; + return 1; +} +x=0 +while (x<2*super) { + x = x + results(x) + if (x < 2*super) print "," + print "\n" +} +quit +#endif + +#define BICUBIC1(x) /* |x| <= 1 */ ((1.5*(x)* - 2.5)*(x)*(x) + 1) +#define BICUBIC2(x) /* 1 < |x| < 2 */ (((2.5 - 0.5*(x))*(x) - 4)*(x) + 2) +#define FILTER_WEIGHT 9 /* Twice the first sum below */ +#define FILTER_WIDTH 2 /* Actually half the width; -2..+2 */ +#define FILTER_STEPS 8 /* steps per filter unit */ +static const double +bicubic[16][2] = +{ + /* These numbers are exact; the weight for the filter is 1/9, but this + * would make the numbers inexact, so it is not included here. + */ + /* bicubic sum */ + /* 0*/ { 1.0000000000, 4.5000000000 }, + /* 1*/ { .9638671875, 3.5000000000 }, + /* 2*/ { .8671875000, 2.5361328125 }, + /* 3*/ { .7275390625, 1.6689453125 }, + /* 4*/ { .5625000000, .9414062500 }, + /* 5*/ { .3896484375, .3789062500 }, + /* 6*/ { .2265625000, -.0107421875 }, + /* 7*/ { .0908203125, -.2373046875 }, + /* 8*/ { 0, -.3281250000 }, + /* 9*/ { -.0478515625, -.3281250000 }, + /*10*/ { -.0703125000, -.2802734375 }, + /*11*/ { -.0732421875, -.2099609375 }, + /*12*/ { -.0625000000, -.1367187500 }, + /*13*/ { -.0439453125, -.0742187500 }, + /*14*/ { -.0234375000, -.0302734375 }, + /*15*/ { -.0068359375, -.0068359375 } +}; + +static double +alpha_calc(const struct arg *arg, double x, double y) +{ + /* For [x-2..x+2],[y-2,y+2] calculate the weighted bicubic given a function + * which tells us whether a point is inside or outside the shape. First + * check if we need to do this at all: + */ + switch (arg->check_fn(arg, x, y)) + { + case OUTSIDE: + return 0; /* all samples outside the shape */ + + case INSIDE: + return 1; /* all samples inside the shape */ + + default: + { + int dy; + double alpha = 0; + +# define FILTER_D (FILTER_WIDTH*FILTER_STEPS-1) + for (dy=-FILTER_D; dy<=FILTER_D; ++dy) + { + double wy = bicubic[abs(dy)][0]; + + if (wy != 0) + { + double alphay = 0; + int dx; + + for (dx=-FILTER_D; dx<=FILTER_D; ++dx) + { + double wx = bicubic[abs(dx)][0]; + + if (wx != 0 && arg->inside_fn(arg, x+dx/16, y+dy/16)) + alphay += wx; + } + + alpha += wy * alphay; + } + } + + /* This needs to be weighted for each dimension: */ + return alpha / (FILTER_WEIGHT*FILTER_WEIGHT); + } + } +} + +/* These are the shape functions. */ +/* "square", + * { inside_square_filled, check_square_filled }, + * { inside_square, check_square } + */ +static int +square_check(double x, double y, double x1, double y1, double x2, double y2) + /* Is x,y inside the square (x1,y1)..(x2,y2)? */ +{ + /* Do a modified Cohen-Sutherland on one point, bit patterns that indicate + * 'outside' are: + * + * x<x1 | x<y1 | x<x2 | x<y2 + * 0 x 0 x To the right + * 1 x 1 x To the left + * x 0 x 0 Below + * x 1 x 1 Above + * + * So 'inside' is (x<x1) != (x<x2) && (y<y1) != (y<y2); + */ + return ((x<x1) ^ (x<x2)) & ((y<y1) ^ (y<y2)); +} + +static int +inside_square_filled(const struct arg *arg, double x, double y) +{ + return square_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2); +} + +static int +square_check_line(const struct arg *arg, double x, double y, double w) + /* Check for a point being inside the boundaries implied by the given arg + * and assuming a width 2*w each side of the boundaries. This returns the + * 'check' INSIDE/OUTSIDE/0 result but note the semantics: + * + * +--------------+ + * | | OUTSIDE + * | INSIDE | + * | | + * +--------------+ + * + * And '0' means within the line boundaries. + */ +{ + double cx = (arg->x1+arg->x2)/2; + double wx = fabs(arg->x1-arg->x2)/2; + double cy = (arg->y1+arg->y2)/2; + double wy = fabs(arg->y1-arg->y2)/2; + + if (square_check(x, y, cx-wx-w, cy-wy-w, cx+wx+w, cy+wy+w)) + { + /* Inside, but maybe too far; check for the redundant case where + * the lines overlap: + */ + wx -= w; + wy -= w; + if (wx > 0 && wy > 0 && square_check(x, y, cx-wx, cy-wy, cx+wx, cy+wy)) + return INSIDE; /* between (inside) the boundary lines. */ + + return 0; /* inside the lines themselves. */ + } + + return OUTSIDE; /* outside the boundary lines. */ +} + +static int +check_square_filled(const struct arg *arg, double x, double y) +{ + /* The filter extends +/-FILTER_WIDTH each side of each output point, so + * the check has to expand and contract the square by that amount; '0' + * means close enough to the edge of the square that the bicubic filter has + * to be run, OUTSIDE means alpha==0, INSIDE means alpha==1. + */ + return square_check_line(arg, x, y, FILTER_WIDTH); +} + +static int +inside_square(const struct arg *arg, double x, double y) +{ + /* Return true if within the drawn lines, else false, no need to distinguish + * INSIDE vs OUTSIDE here: + */ + return square_check_line(arg, x, y, arg->width/2) == 0; +} + +static int +check_square(const struct arg *arg, double x, double y) +{ + /* So for this function a result of 'INSIDE' means inside the actual lines. + */ + double w = arg->width/2; + + if (square_check_line(arg, x, y, w+FILTER_WIDTH) == 0) + { + /* Somewhere close to the boundary lines. If far enough inside one of + * them then we can return INSIDE: + */ + w -= FILTER_WIDTH; + + if (w > 0 && square_check_line(arg, x, y, w) == 0) + return INSIDE; + + /* Point is somewhere in the filter region: */ + return 0; + } + + else /* Inside or outside the square by more than w+FILTER_WIDTH. */ + return OUTSIDE; +} + +/* "circle", + * { inside_circle_filled, check_circle_filled }, + * { inside_circle, check_circle } + * + * The functions here are analoguous to the square ones; however, they check + * the corresponding ellipse as opposed to the rectangle. + */ +static int +circle_check(double x, double y, double x1, double y1, double x2, double y2) +{ + if (square_check(x, y, x1, y1, x2, y2)) + { + /* Inside the square, so maybe inside the circle too: */ + const double cx = (x1 + x2)/2; + const double cy = (y1 + y2)/2; + const double dx = x1 - x2; + const double dy = y1 - y2; + + x = (x - cx)/dx; + y = (y - cy)/dy; + + /* It is outside if the distance from the center is more than half the + * diameter: + */ + return x*x+y*y < .25; + } + + return 0; /* outside */ +} + +static int +inside_circle_filled(const struct arg *arg, double x, double y) +{ + return circle_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2); +} + +static int +circle_check_line(const struct arg *arg, double x, double y, double w) + /* Check for a point being inside the boundaries implied by the given arg + * and assuming a width 2*w each side of the boundaries. This function has + * the same semantic as square_check_line but tests the circle. + */ +{ + double cx = (arg->x1+arg->x2)/2; + double wx = fabs(arg->x1-arg->x2)/2; + double cy = (arg->y1+arg->y2)/2; + double wy = fabs(arg->y1-arg->y2)/2; + + if (circle_check(x, y, cx-wx-w, cy-wy-w, cx+wx+w, cy+wy+w)) + { + /* Inside, but maybe too far; check for the redundant case where + * the lines overlap: + */ + wx -= w; + wy -= w; + if (wx > 0 && wy > 0 && circle_check(x, y, cx-wx, cy-wy, cx+wx, cy+wy)) + return INSIDE; /* between (inside) the boundary lines. */ + + return 0; /* inside the lines themselves. */ + } + + return OUTSIDE; /* outside the boundary lines. */ +} + +static int +check_circle_filled(const struct arg *arg, double x, double y) +{ + return circle_check_line(arg, x, y, FILTER_WIDTH); +} + +static int +inside_circle(const struct arg *arg, double x, double y) +{ + return circle_check_line(arg, x, y, arg->width/2) == 0; +} + +static int +check_circle(const struct arg *arg, double x, double y) +{ + /* Exactly as the 'square' code. */ + double w = arg->width/2; + + if (circle_check_line(arg, x, y, w+FILTER_WIDTH) == 0) + { + w -= FILTER_WIDTH; + + if (w > 0 && circle_check_line(arg, x, y, w) == 0) + return INSIDE; + + /* Point is somewhere in the filter region: */ + return 0; + } + + else /* Inside or outside the square by more than w+FILTER_WIDTH. */ + return OUTSIDE; +} + +/* "line", + * { NULL, NULL }, There is no 'filled' line. + * { inside_line, check_line } + */ +static int +line_check(double x, double y, double x1, double y1, double x2, double y2, + double w, double expand) +{ + /* Shift all the points to (arg->x1, arg->y1) */ + double lx = x2 - x1; + double ly = y2 - y1; + double len2 = lx*lx + ly*ly; + double cross, dot; + + x -= x1; + y -= y1; + + /* The dot product is the distance down the line, the cross product is + * the distance away from the line: + * + * distance = |cross| / sqrt(len2) + */ + cross = x * ly - y * lx; + + /* If 'distance' is more than w the point is definitely outside the line: + * + * distance >= w + * |cross| >= w * sqrt(len2) + * cross^2 >= w^2 * len2: + */ + if (cross*cross >= (w+expand)*(w+expand)*len2) + return 0; /* outside */ + + /* Now find the distance *along* the line; this comes from the dot product + * lx.x+ly.y. The actual distance (in pixels) is: + * + * distance = dot / sqrt(len2) + */ + dot = lx * x + ly * y; + + /* The test for 'outside' is: + * + * distance < 0 || distance > sqrt(len2) + * -> dot / sqrt(len2) > sqrt(len2) + * -> dot > len2 + * + * But 'expand' is used for the filter width and needs to be handled too: + */ + return dot > -expand && dot < len2+expand; +} + +static int +inside_line(const struct arg *arg, double x, double y) +{ + return line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2, 0); +} + +static int +check_line(const struct arg *arg, double x, double y) +{ + /* The end caps of the line must be checked too; it's not enough just to + * widen the line by FILTER_WIDTH; 'expand' exists for this purpose: + */ + if (line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2, + FILTER_WIDTH)) + { + /* Inside the line+filter; far enough inside that the filter isn't + * required? + */ + if (arg->width > 2*FILTER_WIDTH && + line_check(x, y, arg->x1, arg->y1, arg->x2, arg->y2, arg->width/2, + -FILTER_WIDTH)) + return INSIDE; + + return 0; + } + + return OUTSIDE; +} + +static const struct +{ + const char *name; + shape_fn_ptr function[2/*fill,line*/][2]; +# define FN_INSIDE 0 +# define FN_CHECK 1 +} shape_defs[] = +{ + { "square", + { { inside_square_filled, check_square_filled }, + { inside_square, check_square } } + }, + { "circle", + { { inside_circle_filled, check_circle_filled }, + { inside_circle, check_circle } } + }, + { "line", + { { NULL, NULL }, + { inside_line, check_line } } + } +}; + +#define shape_count ((sizeof shape_defs)/(sizeof shape_defs[0])) + +static shape_fn_ptr +shape_of(const char *arg, double width, int f) +{ + unsigned int i; + + for (i=0; i<shape_count; ++i) if (strcmp(shape_defs[i].name, arg) == 0) + { + shape_fn_ptr fn = shape_defs[i].function[width != 0][f]; + + if (fn != NULL) + return fn; + + fprintf(stderr, "genpng: %s %s not supported\n", + width == 0 ? "filled" : "unfilled", arg); + exit(1); + } + + fprintf(stderr, "genpng: %s: not a valid shape name\n", arg); + exit(1); +} + +static void +parse_arg(struct arg *arg, const char **argv/*7 arguments*/) +{ + /* shape ::= color width shape x1 y1 x2 y2 */ + arg->color = color_of(argv[0]); + arg->width = width_of(argv[1]); + arg->inside_fn = shape_of(argv[2], arg->width, FN_INSIDE); + arg->check_fn = shape_of(argv[2], arg->width, FN_CHECK); + arg->x1 = coordinate_of(argv[3]); + arg->y1 = coordinate_of(argv[4]); + arg->x2 = coordinate_of(argv[5]); + arg->y2 = coordinate_of(argv[6]); +} + +static png_uint_32 +read_wh(const char *name, const char *str) + /* read a PNG width or height */ +{ + char *ep = NULL; + unsigned long ul = strtoul(str, &ep, 10); + + if (ep != NULL && *ep == 0 && ul > 0 && ul <= 0x7fffffff) + return (png_uint_32)/*SAFE*/ul; + + fprintf(stderr, "genpng: %s: invalid number %s\n", name, str); + exit(1); +} + +static void +pixel(png_uint_16p p, struct arg *args, int nargs, double x, double y) +{ + /* Fill in the pixel by checking each shape (args[nargs]) for effects on + * the corresponding sample: + */ + double r=0, g=0, b=0, a=0; + + while (--nargs >= 0 && a != 1) + { + /* NOTE: alpha_calc can return a value outside the range 0..1 with the + * bicubic filter. + */ + const double alpha = alpha_calc(args+nargs, x, y) * (1-a); + + r += alpha * args[nargs].color->red; + g += alpha * args[nargs].color->green; + b += alpha * args[nargs].color->blue; + a += alpha; + } + + /* 'a' may be negative or greater than 1; if it is, negative clamp the + * pixel to 0 if >1 clamp r/g/b: + */ + if (a > 0) + { + if (a > 1) + { + if (r > 1) r = 1; + if (g > 1) g = 1; + if (b > 1) b = 1; + a = 1; + } + + /* And fill in the pixel: */ + p[0] = (png_uint_16)/*SAFE*/round(r * 65535); + p[1] = (png_uint_16)/*SAFE*/round(g * 65535); + p[2] = (png_uint_16)/*SAFE*/round(b * 65535); + p[3] = (png_uint_16)/*SAFE*/round(a * 65535); + } + + else + p[3] = p[2] = p[1] = p[0] = 0; +} + +int +main(int argc, const char **argv) +{ + int convert_to_8bit = 0; + + /* There is one option: --8bit: */ + if (argc > 1 && strcmp(argv[1], "--8bit") == 0) + --argc, ++argv, convert_to_8bit = 1; + + if (argc >= 3) + { + png_uint_16p buffer; + int nshapes; + png_image image; +# define max_shapes 256 + struct arg arg_list[max_shapes]; + + /* The libpng Simplified API write code requires a fully initialized + * structure. + */ + memset(&image, 0, sizeof image); + image.version = PNG_IMAGE_VERSION; + image.opaque = NULL; + image.width = read_wh("width", argv[1]); + image.height = read_wh("height", argv[2]); + image.format = PNG_FORMAT_LINEAR_RGB_ALPHA; + image.flags = 0; + image.colormap_entries = 0; + + /* Check the remainder of the arguments */ + for (nshapes=0; 3+7*(nshapes+1) <= argc && nshapes < max_shapes; + ++nshapes) + parse_arg(arg_list+nshapes, argv+3+7*nshapes); + + if (3+7*nshapes != argc) + { + fprintf(stderr, "genpng: %s: too many arguments\n", argv[3+7*nshapes]); + return 1; + } + + /* Create the buffer: */ + buffer = malloc(PNG_IMAGE_SIZE(image)); + + if (buffer != NULL) + { + png_uint_32 y; + + /* Write each row... */ + for (y=0; y<image.height; ++y) + { + png_uint_32 x; + + /* Each pixel in each row: */ + for (x=0; x<image.width; ++x) + pixel(buffer + 4*(x + y*image.width), arg_list, nshapes, x, y); + } + + /* Write the result (to stdout) */ + if (png_image_write_to_stdio(&image, stdout, convert_to_8bit, + buffer, 0/*row_stride*/, NULL/*colormap*/)) + { + free(buffer); + return 0; /* success */ + } + + else + fprintf(stderr, "genpng: write stdout: %s\n", image.message); + + free(buffer); + } + + else + fprintf(stderr, "genpng: out of memory: %lu bytes\n", + (unsigned long)PNG_IMAGE_SIZE(image)); + } + + else + { + /* Wrong number of arguments */ + fprintf(stderr, "genpng: usage: genpng [--8bit] width height {shape}\n" + " Generate a transparent PNG in RGBA (truecolor+alpha) format\n" + " containing the given shape or shapes. Shapes are defined:\n" + "\n" + " shape ::= color width shape x1 y1 x2 y2\n" + " color ::= black|white|red|green|yellow|blue\n" + " color ::= brown|purple|pink|orange|gray|cyan\n" + " width ::= filled|<number>\n" + " shape ::= circle|square|line\n" + " x1,x2 ::= <number>\n" + " y1,y2 ::= <number>\n" + "\n" + " Numbers are floating point numbers describing points relative to\n" + " the top left of the output PNG as pixel coordinates. The 'width'\n" + " parameter is either the width of the line (in output pixels) used\n" + " to draw the shape or 'filled' to indicate that the shape should\n" + " be filled with the color.\n" + "\n" + " Colors are interpreted loosely to give access to the eight full\n" + " intensity RGB values:\n" + "\n" + " black, red, green, blue, yellow, cyan, purple, white,\n" + "\n" + " Cyan is full intensity blue+green; RGB(0,1,1), plus the following\n" + " lower intensity values:\n" + "\n" + " brown: red+orange: RGB(0.5, 0.125, 0) (dark red+orange)\n" + " pink: red+white: RGB(1.0, 0.5, 0.5)\n" + " orange: red+yellow: RGB(1.0, 0.5, 0)\n" + " gray: black+white: RGB(0.5, 0.5, 0.5)\n" + "\n" + " The RGB values are selected to make detection of aliasing errors\n" + " easy. The names are selected to make the description of errors\n" + " easy.\n" + "\n" + " The PNG is written to stdout, if --8bit is given a 32bpp RGBA sRGB\n" + " file is produced, otherwise a 64bpp RGBA linear encoded file is\n" + " written.\n"); + } + + return 1; +} +#endif /* SIMPLIFIED_WRITE && STDIO */ diff --git a/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/intgamma.sh b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/intgamma.sh new file mode 100644 index 00000000000..41c5d6dd278 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/intgamma.sh @@ -0,0 +1,110 @@ +#!/bin/sh +# +# intgamma.sh +# +# Last changed in libpng 1.6.0 [February 14, 2013] +# +# COPYRIGHT: Written by John Cunningham Bowler, 2013. +# To the extent possible under law, the author has waived all copyright and +# related or neighboring rights to this work. This work is published from: +# United States. +# +# Shell script to generate png.c 8-bit and 16-bit log tables (see the code in +# png.c for details). +# +# This script uses the "bc" arbitrary precision calculator to calculate 32-bit +# fixed point values of logarithms appropriate to finding the log of an 8-bit +# (0..255) value and a similar table for the exponent calculation. +# +# "bc" must be on the path when the script is executed, and the math library +# (-lm) must be available +# +# function to print out a list of numbers as integers; the function truncates +# the integers which must be one-per-line +function print(){ + awk 'BEGIN{ + str = "" + } + { + sub("\\.[0-9]*$", "") + if ($0 == "") + $0 = "0" + + if (str == "") + t = " " $0 "U" + else + t = str ", " $0 "U" + + if (length(t) >= 80) { + print str "," + str = " " $0 "U" + } else + str = t + } + END{ + print str + }' +} +# +# The logarithm table. +cat <<END +/* 8-bit log table: png_8bit_l2[128] + * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to + * 255, so it's the base 2 logarithm of a normalized 8-bit floating point + * mantissa. The numbers are 32-bit fractions. + */ +static const png_uint_32 +png_8bit_l2[128] = +{ +END +# +bc -lqws <<END | print +f=65536*65536/l(2) +for (i=128;i<256;++i) { .5 - l(i/255)*f; } +END +echo '};' +echo +# +# The exponent table. +cat <<END +/* The 'exp()' case must invert the above, taking a 20-bit fixed point + * logarithmic value and returning a 16 or 8-bit number as appropriate. In + * each case only the low 16 bits are relevant - the fraction - since the + * integer bits (the top 4) simply determine a shift. + * + * The worst case is the 16-bit distinction between 65535 and 65534; this + * requires perhaps spurious accuracy in the decoding of the logarithm to + * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance + * of getting this accuracy in practice. + * + * To deal with this the following exp() function works out the exponent of the + * frational part of the logarithm by using an accurate 32-bit value from the + * top four fractional bits then multiplying in the remaining bits. + */ +static const png_uint_32 +png_32bit_exp[16] = +{ +END +# +bc -lqws <<END | print +f=l(2)/16 +for (i=0;i<16;++i) { + x = .5 + e(-i*f)*2^32; + if (x >= 2^32) x = 2^32-1; + x; +} +END +echo '};' +echo +# +# And the table of adjustment values. +cat <<END +/* Adjustment table; provided to explain the numbers in the code below. */ +#if 0 +END +bc -lqws <<END | awk '{ printf "%5d %s\n", 12-NR, $0 }' +for (i=11;i>=0;--i){ + (1 - e(-(2^i)/65536*l(2))) * 2^(32-i) +} +END +echo '#endif' diff --git a/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/makesRGB.c b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/makesRGB.c new file mode 100644 index 00000000000..e66c9f1576b --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/makesRGB.c @@ -0,0 +1,430 @@ +/* makesRGB.c -- build sRGB-to-linear and linear-to-sRGB conversion tables + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * + * COPYRIGHT: Written by John Cunningham Bowler, 2013. + * To the extent possible under law, the author has waived all copyright and + * related or neighboring rights to this work. This work is published from: + * United States. + * + * Make a table to convert 8-bit sRGB encoding values into the closest 16-bit + * linear value. + * + * Make two tables to take a linear value scaled to 255*65535 and return an + * approximation to the 8-bit sRGB encoded value. Calculate the error in these + * tables and display it. + */ +#define _C99_SOURCE 1 +#include <stdio.h> +#include <math.h> +#include <stdlib.h> + +/* pngpriv.h includes the definition of 'PNG_sRGB_FROM_LINEAR' which is required + * to verify the actual code. + */ +#include "../../pngpriv.h" + +#include "sRGB.h" + +/* The tables are declared 'const' in pngpriv.h, so this redefines the tables to + * be used. + */ +#define png_sRGB_table sRGB_table +#define png_sRGB_base sRGB_base +#define png_sRGB_delta sRGB_delta + +static png_uint_16 png_sRGB_table[256]; +static png_uint_16 png_sRGB_base[512]; +static png_byte png_sRGB_delta[512]; + +static const unsigned int max_input = 255*65535; + +double +fsRGB(double l) +{ + return sRGB_from_linear(l/max_input); +} + +double +sRGB(unsigned int i) +{ + return fsRGB(i); +} + +double +finvsRGB(unsigned int i) +{ + return 65535 * linear_from_sRGB(i/255.); +} + +png_uint_16 +invsRGB(unsigned int i) +{ + unsigned int x = nearbyint(finvsRGB(i)); + + if (x > 65535) + { + fprintf(stderr, "invsRGB(%u) overflows to %u\n", i, x); + exit(1); + } + + return (png_uint_16)x; +} + +int +main(int argc, char **argv) +{ + unsigned int i, i16, ibase; + double min_error = 0; + double max_error = 0; + double min_error16 = 0; + double max_error16 = 0; + double adjust; + double adjust_lo = 0.4, adjust_hi = 0.6, adjust_mid = 0.5; + unsigned int ec_lo = 0, ec_hi = 0, ec_mid = 0; + unsigned int error_count = 0; + unsigned int error_count16 = 0; + int test_only = 0; + + if (argc > 1) + test_only = strcmp("--test", argv[1]) == 0; + + /* Initialize the encoding table first. */ + for (i=0; i<256; ++i) + { + png_sRGB_table[i] = invsRGB(i); + } + + /* Now work out the decoding tables (this is where the error comes in because + * there are 512 set points and 512 straight lines between them.) + */ + for (;;) + { + if (ec_lo == 0) + adjust = adjust_lo; + + else if (ec_hi == 0) + adjust = adjust_hi; + + else if (ec_mid == 0) + adjust = adjust_mid; + + else if (ec_mid < ec_hi) + adjust = (adjust_mid + adjust_hi)/2; + + else if (ec_mid < ec_lo) + adjust = (adjust_mid + adjust_lo)/2; + + else + { + fprintf(stderr, "not reached: %u .. %u .. %u\n", ec_lo, ec_mid, ec_hi); + exit(1); + } + + /* Calculate the table using the current 'adjust' */ + for (i=0; i<=511; ++i) + { + double lo = 255 * sRGB(i << 15); + double hi = 255 * sRGB((i+1) << 15); + unsigned int calc; + + calc = nearbyint((lo+adjust) * 256); + if (calc > 65535) + { + fprintf(stderr, "table[%d][0]: overflow %08x (%d)\n", i, calc, + calc); + exit(1); + } + png_sRGB_base[i] = calc; + + calc = nearbyint((hi-lo) * 32); + if (calc > 255) + { + fprintf(stderr, "table[%d][1]: overflow %08x (%d)\n", i, calc, + calc); + exit(1); + } + png_sRGB_delta[i] = calc; + } + + /* Check the 16-bit linear values alone: */ + error_count16 = 0; + for (i16=0; i16 <= 65535; ++i16) + { + unsigned int i = 255*i16; + unsigned int iexact = nearbyint(255*sRGB(i)); + unsigned int icalc = PNG_sRGB_FROM_LINEAR(i); + + if (icalc != iexact) + ++error_count16; + } + + /* Now try changing the adjustment. */ + if (ec_lo == 0) + ec_lo = error_count16; + + else if (ec_hi == 0) + ec_hi = error_count16; + + else if (ec_mid == 0) + { + ec_mid = error_count16; + printf("/* initial error counts: %u .. %u .. %u */\n", ec_lo, ec_mid, + ec_hi); + } + + else if (error_count16 < ec_mid) + { + printf("/* adjust (mid ): %f: %u -> %u */\n", adjust, ec_mid, + error_count16); + ec_mid = error_count16; + adjust_mid = adjust; + } + + else if (adjust < adjust_mid && error_count16 < ec_lo) + { + printf("/* adjust (low ): %f: %u -> %u */\n", adjust, ec_lo, + error_count16); + ec_lo = error_count16; + adjust_lo = adjust; + } + + else if (adjust > adjust_mid && error_count16 < ec_hi) + { + printf("/* adjust (high): %f: %u -> %u */\n", adjust, ec_hi, + error_count16); + ec_hi = error_count16; + adjust_hi = adjust; + } + + else + { + adjust = adjust_mid; + printf("/* adjust: %f: %u */\n", adjust, ec_mid); + break; + } + } + + /* For each entry in the table try to adjust it to minimize the error count + * in that entry. Each entry corresponds to 128 input values. + */ + for (ibase=0; ibase<65536; ibase+=128) + { + png_uint_16 base = png_sRGB_base[ibase >> 7], trybase = base, ob=base; + png_byte delta = png_sRGB_delta[ibase >> 7], trydelta = delta, od=delta; + unsigned int ecbase = 0, eco; + + for (;;) + { + png_sRGB_base[ibase >> 7] = trybase; + png_sRGB_delta[ibase >> 7] = trydelta; + + /* Check the 16-bit linear values alone: */ + error_count16 = 0; + for (i16=ibase; i16 < ibase+128; ++i16) + { + unsigned int i = 255*i16; + unsigned int iexact = nearbyint(255*sRGB(i)); + unsigned int icalc = PNG_sRGB_FROM_LINEAR(i); + + if (icalc != iexact) + ++error_count16; + } + + if (error_count16 == 0) + break; + + if (ecbase == 0) + { + eco = ecbase = error_count16; + ++trybase; /* First test */ + } + + else if (error_count16 < ecbase) + { + if (trybase > base) + { + base = trybase; + ++trybase; + } + else if (trybase < base) + { + base = trybase; + --trybase; + } + else if (trydelta > delta) + { + delta = trydelta; + ++trydelta; + } + else if (trydelta < delta) + { + delta = trydelta; + --trydelta; + } + else + { + fprintf(stderr, "makesRGB: impossible\n"); + exit(1); + } + ecbase = error_count16; + } + + else + { + if (trybase > base) + trybase = base-1; + else if (trybase < base) + { + trybase = base; + ++trydelta; + } + else if (trydelta > delta) + trydelta = delta-1; + else if (trydelta < delta) + break; /* end of tests */ + } + } + + png_sRGB_base[ibase >> 7] = base; + png_sRGB_delta[ibase >> 7] = delta; + if (base != ob || delta != od) + { + printf("/* table[%u]={%u,%u} -> {%u,%u} %u -> %u errors */\n", + ibase>>7, ob, od, base, delta, eco, ecbase); + } + else if (0) + printf("/* table[%u]={%u,%u} %u errors */\n", ibase>>7, ob, od, + ecbase); + } + + /* Only do the full (slow) test at the end: */ + min_error = -.4999; + max_error = .4999; + error_count = 0; + + for (i=0; i <= max_input; ++i) + { + unsigned int iexact = nearbyint(255*sRGB(i)); + unsigned int icalc = PNG_sRGB_FROM_LINEAR(i); + + if (icalc != iexact) + { + double err = 255*sRGB(i) - icalc; + + if (err > (max_error+.001) || err < (min_error-.001)) + { + printf( + "/* 0x%08x: exact: %3d, got: %3d [tables: %08x, %08x] (%f) */\n", + i, iexact, icalc, png_sRGB_base[i>>15], + png_sRGB_delta[i>>15], err); + } + + ++error_count; + if (err > max_error) + max_error = err; + else if (err < min_error) + min_error = err; + } + } + + /* Re-check the 16-bit cases too, including the warning if there is an error + * bigger than 1. + */ + error_count16 = 0; + max_error16 = 0; + min_error16 = 0; + for (i16=0; i16 <= 65535; ++i16) + { + unsigned int i = 255*i16; + unsigned int iexact = nearbyint(255*sRGB(i)); + unsigned int icalc = PNG_sRGB_FROM_LINEAR(i); + + if (icalc != iexact) + { + double err = 255*sRGB(i) - icalc; + + ++error_count16; + if (err > max_error16) + max_error16 = err; + else if (err < min_error16) + min_error16 = err; + + if (abs(icalc - iexact) > 1) + printf( + "/* 0x%04x: exact: %3d, got: %3d [tables: %08x, %08x] (%f) */\n", + i16, iexact, icalc, png_sRGB_base[i>>15], + png_sRGB_delta[i>>15], err); + } + } + + /* Check the round trip for each 8-bit sRGB value. */ + for (i16=0; i16 <= 255; ++i16) + { + unsigned int i = 255 * png_sRGB_table[i16]; + unsigned int iexact = nearbyint(255*sRGB(i)); + unsigned int icalc = PNG_sRGB_FROM_LINEAR(i); + + if (i16 != iexact) + { + fprintf(stderr, "8-bit rounding error: %d -> %d\n", i16, iexact); + exit(1); + } + + if (icalc != i16) + { + double finv = finvsRGB(i16); + + printf("/* 8-bit roundtrip error: %d -> %f -> %d(%f) */\n", + i16, finv, icalc, fsRGB(255*finv)); + } + } + + + printf("/* error: %g - %g, %u (%g%%) of readings inexact */\n", + min_error, max_error, error_count, (100.*error_count)/max_input); + printf("/* 16-bit error: %g - %g, %u (%g%%) of readings inexact */\n", + min_error16, max_error16, error_count16, (100.*error_count16)/65535); + + if (!test_only) + { + printf("PNG_CONST png_uint_16 png_sRGB_table[256] =\n{\n "); + for (i=0; i<255; ) + { + do + { + printf("%d,", png_sRGB_table[i++]); + } + while ((i & 0x7) != 0 && i<255); + if (i<255) printf("\n "); + } + printf("%d\n};\n\n", png_sRGB_table[i]); + + + printf("PNG_CONST png_uint_16 png_sRGB_base[512] =\n{\n "); + for (i=0; i<511; ) + { + do + { + printf("%d,", png_sRGB_base[i++]); + } + while ((i & 0x7) != 0 && i<511); + if (i<511) printf("\n "); + } + printf("%d\n};\n\n", png_sRGB_base[i]); + + printf("PNG_CONST png_byte png_sRGB_delta[512] =\n{\n "); + for (i=0; i<511; ) + { + do + { + printf("%d,", png_sRGB_delta[i++]); + } + while ((i & 0xf) != 0 && i<511); + if (i<511) printf("\n "); + } + printf("%d\n};\n\n", png_sRGB_delta[i]); + } + + return 0; +} diff --git a/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/png-fix-itxt.c b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/png-fix-itxt.c new file mode 100644 index 00000000000..5730d9f792d --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/png-fix-itxt.c @@ -0,0 +1,164 @@ + +/* png-fix-itxt version 1.0.0 + * + * Copyright 2015 Glenn Randers-Pehrson + * Last changed in libpng 1.6.18 [July 23, 2015] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Usage: + * + * png-fix-itxt.exe < bad.png > good.png + * + * Fixes a PNG file written with libpng-1.6.0 or 1.6.1 that has one or more + * uncompressed iTXt chunks. Assumes that the actual length is greater + * than or equal to the value in the length byte, and that the CRC is + * correct for the actual length. This program hunts for the CRC and + * adjusts the length byte accordingly. It is not an error to process a + * PNG file that has no iTXt chunks or one that has valid iTXt chunks; + * such files will simply be copied. + * + * Requires zlib (for crc32 and Z_NULL); build with + * + * gcc -O -o png-fix-itxt png-fix-itxt.c -lz + * + * If you need to handle iTXt chunks larger than 500000 kbytes you must + * rebuild png-fix-itxt with a larger values of MAX_LENGTH (or a smaller value + * if you know you will never encounter such huge iTXt chunks). + */ + +#include <stdio.h> +#include <zlib.h> + +#define MAX_LENGTH 500000 + +/* Read one character (inchar), also return octet (c), break if EOF */ +#define GETBREAK inchar=getchar(); \ + c=(inchar & 0xffU);\ + if (inchar != c) break +int +main(void) +{ + unsigned int i; + unsigned char buf[MAX_LENGTH]; + unsigned long crc; + unsigned char c; + int inchar; + +/* Skip 8-byte signature */ + for (i=8; i; i--) + { + GETBREAK; + putchar(c); + } + +if (inchar == c) /* !EOF */ +for (;;) + { + /* Read the length */ + unsigned long length; /* must be 32 bits! */ + GETBREAK; buf[0] = c; length = c; length <<= 8; + GETBREAK; buf[1] = c; length += c; length <<= 8; + GETBREAK; buf[2] = c; length += c; length <<= 8; + GETBREAK; buf[3] = c; length += c; + + /* Read the chunkname */ + GETBREAK; buf[4] = c; + GETBREAK; buf[5] = c; + GETBREAK; buf[6] = c; + GETBREAK; buf[7] = c; + + + /* The iTXt chunk type expressed as integers is (105, 84, 88, 116) */ + if (buf[4] == 105 && buf[5] == 84 && buf[6] == 88 && buf[7] == 116) + { + if (length >= MAX_LENGTH-12) + break; /* To do: handle this more gracefully */ + + /* Initialize the CRC */ + crc = crc32(0, Z_NULL, 0); + + /* Copy the data bytes */ + for (i=8; i < length + 12; i++) + { + GETBREAK; buf[i] = c; + } + + if (inchar != c) /* EOF */ + break; + + /* Calculate the CRC */ + crc = crc32(crc, buf+4, (uInt)length+4); + + for (;;) + { + /* Check the CRC */ + if (((crc >> 24) & 0xffU) == buf[length+8] && + ((crc >> 16) & 0xffU) == buf[length+9] && + ((crc >> 8) & 0xffU) == buf[length+10] && + ((crc ) & 0xffU) == buf[length+11]) + break; + + length++; + + if (length >= MAX_LENGTH-12) + break; + + GETBREAK; + buf[length+11] = c; + + /* Update the CRC */ + crc = crc32(crc, buf+7+length, 1); + } + + if (inchar != c) /* EOF */ + break; + + /* Update length bytes */ + buf[0] = (unsigned char)((length >> 24) & 0xffU); + buf[1] = (unsigned char)((length >> 16) & 0xffU); + buf[2] = (unsigned char)((length >> 8) & 0xffU); + buf[3] = (unsigned char)((length ) & 0xffU); + + /* Write the fixed iTXt chunk (length, name, data, crc) */ + for (i=0; i<length+12; i++) + putchar(buf[i]); + } + + else + { + if (inchar != c) /* EOF */ + break; + + /* Copy bytes that were already read (length and chunk name) */ + for (i=0; i<8; i++) + putchar(buf[i]); + + /* Copy data bytes and CRC */ + for (i=8; i< length+12; i++) + { + GETBREAK; + putchar(c); + } + + if (inchar != c) /* EOF */ + { + break; + } + + /* The IEND chunk type expressed as integers is (73, 69, 78, 68) */ + if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68) + break; + } + + if (inchar != c) /* EOF */ + break; + + if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68) + break; + } + + return 0; +} diff --git a/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/pngfix.c b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/pngfix.c new file mode 100644 index 00000000000..2489ac374f7 --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/pngfix.c @@ -0,0 +1,4045 @@ +/* pngfix.c + * + * Copyright (c) 2014-2015 John Cunningham Bowler + * + * Last changed in libpng 1.6.18 [July 23, 2015] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Tool to check and fix the zlib inflate 'too far back' problem. + * See the usage message for more information. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> +#include <errno.h> +#include <assert.h> + +#define implies(x,y) assert(!(x) || (y)) + +#ifdef __GNUC__ + /* This is used to fix the error: + * + * pngfix.c: + * In function 'zlib_advance': + * pngfix.c:181:13: error: assuming signed overflow does not + * occur when simplifying conditional to constant [-Werror=strict-overflow] + */ +# define FIX_GCC volatile +#else +# define FIX_GCC +#endif + +#define PROGRAM_NAME "pngfix" + +/* Define the following to use this program against your installed libpng, + * rather than the one being built here: + */ +#ifdef PNG_FREESTANDING_TESTS +# include <png.h> +#else +# include "../../png.h" +#endif + +#if PNG_LIBPNG_VER < 10603 /* 1.6.3 */ +# error "pngfix will not work with libpng prior to 1.6.3" +#endif + +#ifdef PNG_SETJMP_SUPPORTED +#include <setjmp.h> + +#if defined(PNG_READ_SUPPORTED) && defined(PNG_EASY_ACCESS_SUPPORTED) +/* zlib.h defines the structure z_stream, an instance of which is included + * in this structure and is required for decompressing the LZ compressed + * data in PNG files. + */ +#ifndef ZLIB_CONST + /* We must ensure that zlib uses 'const' in declarations. */ +# define ZLIB_CONST +#endif +#include <zlib.h> +#ifdef const + /* zlib.h sometimes #defines const to nothing, undo this. */ +# undef const +#endif + +/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility + * with older builds. + */ +#if ZLIB_VERNUM < 0x1260 +# define PNGZ_MSG_CAST(s) constcast(char*,s) +# define PNGZ_INPUT_CAST(b) constcast(png_bytep,b) +#else +# define PNGZ_MSG_CAST(s) (s) +# define PNGZ_INPUT_CAST(b) (b) +#endif + +#ifndef PNG_MAXIMUM_INFLATE_WINDOW +# error "pngfix not supported in this libpng version" +#endif + +#if ZLIB_VERNUM >= 0x1240 + +/* Copied from pngpriv.h */ +#ifdef __cplusplus +# define voidcast(type, value) static_cast<type>(value) +# define constcast(type, value) const_cast<type>(value) +# define aligncast(type, value) \ + static_cast<type>(static_cast<void*>(value)) +# define aligncastconst(type, value) \ + static_cast<type>(static_cast<const void*>(value)) +#else +# define voidcast(type, value) (value) +# define constcast(type, value) ((type)(value)) +# define aligncast(type, value) ((void*)(value)) +# define aligncastconst(type, value) ((const void*)(value)) +#endif /* __cplusplus */ + +#if PNG_LIBPNG_VER < 10700 +/* Chunk tags (copied from pngpriv.h) */ +#define PNG_32b(b,s) ((png_uint_32)(b) << (s)) +#define PNG_U32(b1,b2,b3,b4) \ + (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) + +/* Constants for known chunk types. */ +#define png_IDAT PNG_U32( 73, 68, 65, 84) +#define png_IEND PNG_U32( 73, 69, 78, 68) +#define png_IHDR PNG_U32( 73, 72, 68, 82) +#define png_PLTE PNG_U32( 80, 76, 84, 69) +#define png_bKGD PNG_U32( 98, 75, 71, 68) +#define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ +#define png_gAMA PNG_U32(103, 65, 77, 65) +#define png_gIFg PNG_U32(103, 73, 70, 103) +#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ +#define png_gIFx PNG_U32(103, 73, 70, 120) +#define png_hIST PNG_U32(104, 73, 83, 84) +#define png_iCCP PNG_U32(105, 67, 67, 80) +#define png_iTXt PNG_U32(105, 84, 88, 116) +#define png_oFFs PNG_U32(111, 70, 70, 115) +#define png_pCAL PNG_U32(112, 67, 65, 76) +#define png_pHYs PNG_U32(112, 72, 89, 115) +#define png_sBIT PNG_U32(115, 66, 73, 84) +#define png_sCAL PNG_U32(115, 67, 65, 76) +#define png_sPLT PNG_U32(115, 80, 76, 84) +#define png_sRGB PNG_U32(115, 82, 71, 66) +#define png_sTER PNG_U32(115, 84, 69, 82) +#define png_tEXt PNG_U32(116, 69, 88, 116) +#define png_tIME PNG_U32(116, 73, 77, 69) +#define png_tRNS PNG_U32(116, 82, 78, 83) +#define png_zTXt PNG_U32(122, 84, 88, 116) +#endif + +/* The 8 byte signature as a pair of 32 bit quantities */ +#define sig1 PNG_U32(137, 80, 78, 71) +#define sig2 PNG_U32( 13, 10, 26, 10) + +/* Is the chunk critical? */ +#define CRITICAL(chunk) (((chunk) & PNG_U32(32,0,0,0)) == 0) + +/* Is it safe to copy? */ +#define SAFE_TO_COPY(chunk) (((chunk) & PNG_U32(0,0,0,32)) != 0) + +/* Fix ups for builds with limited read support */ +#ifndef PNG_ERROR_TEXT_SUPPORTED +# define png_error(a,b) png_err(a) +#endif + +/********************************* UTILITIES **********************************/ +/* UNREACHED is a value to cause an assert to fail. Because of the way the + * assert macro is written the string "UNREACHED" is produced in the error + * message. + */ +#define UNREACHED 0 + +/* 80-bit number handling - a PNG image can be up to (2^31-1)x(2^31-1) 8 byte + * (16-bit RGBA) pixels in size; that's less than 2^65 bytes or 2^68 bits, so + * arithmetic of 80-bit numbers is sufficient. This representation uses an + * arbitrary length array of png_uint_16 digits (0..65535). The representation + * is little endian. + * + * The arithmetic functions take zero to two uarb values together with the + * number of digits in those values and write the result to the given uarb + * (always the first argument) returning the number of digits in the result. + * If the result is negative the return value is also negative (this would + * normally be an error). + */ +typedef png_uint_16 udigit; /* A 'unum' is an array of these */ +typedef png_uint_16p uarb; +typedef png_const_uint_16p uarbc; + +#define UDIGITS(unum) ((sizeof unum)/(sizeof (udigit)) + /* IMPORTANT: only apply this to an array, applied to a pointer the result + * will typically be '2', which is not useful. + */ + +static int +uarb_set(uarb result, png_alloc_size_t val) + /* Set (initialize) 'result' to 'val'. The size required for 'result' must + * be determined by the caller from a knowledge of the maximum for 'val'. + */ +{ + int ndigits = 0; + + while (val > 0) + { + result[ndigits++] = (png_uint_16)(val & 0xffff); + val >>= 16; + } + + return ndigits; +} + +static int +uarb_copy(uarb to, uarb from, int idigits) + /* Copy a uarb, may reduce the digit count */ +{ + int d, odigits; + + for (d=odigits=0; d<idigits; ++d) + if ((to[d] = from[d]) != 0) + odigits = d+1; + + return odigits; +} + +static int +uarb_inc(uarb num, int in_digits, png_int_32 add) + /* This is a signed 32-bit add, except that to avoid overflow the value added + * or subtracted must be no more than 2^31-65536. A negative result + * indicates a negative number (which is an error below). The size of + * 'num' should be max(in_digits+1,2) for arbitrary 'add' but can be just + * in_digits+1 if add is known to be in the range -65535..65535. + */ +{ + FIX_GCC int out_digits = 0; + + while (out_digits < in_digits) + { + add += num[out_digits]; + num[out_digits++] = (png_uint_16)(add & 0xffff); + add >>= 16; + } + + while (add != 0 && add != (-1)) + { + num[out_digits++] = (png_uint_16)(add & 0xffff); + add >>= 16; + } + + if (add == 0) + { + while (out_digits > 0 && num[out_digits-1] == 0) + --out_digits; + return out_digits; /* may be 0 */ + } + + else /* negative result */ + { + while (out_digits > 1 && num[out_digits-1] == 0xffff) + --out_digits; + + return -out_digits; + } +} + +static int +uarb_add32(uarb num, int in_digits, png_uint_32 add) + /* As above but this works with any 32-bit value and only does 'add' */ +{ + if (in_digits > 0) + { + in_digits = uarb_inc(num, in_digits, add & 0xffff); + return uarb_inc(num+1, in_digits-1, add >> 16)+1; + } + + return uarb_set(num, add); +} + +static int +uarb_mult_digit(uarb acc, int a_digits, uarb num, FIX_GCC int n_digits, + png_uint_16 val) + /* Primitive one-digit multiply - 'val' must be 0..65535. Note that this + * primitive is a multiply and accumulate - the result of *num * val is added + * to *acc. + * + * This is a one-digit multiply, so the product may be up to one digit longer + * than 'num', however the add to 'acc' means that the caller must ensure + * that 'acc' is at least one digit longer than this *and* at least one digit + * longer than the current length of 'acc'. (Or the caller must otherwise + * ensure 'adigits' is adequate from knowledge of the values.) + */ +{ + /* The digits in *acc, *num and val are in the range 0..65535, so the + * result below is at most (65535*65535)+2*65635 = 65535*(65535+2), which is + * exactly 0xffffffff. + */ + if (val > 0 && n_digits > 0) /* Else the product is 0 */ + { + png_uint_32 carry = 0; + int out_digits = 0; + + while (out_digits < n_digits || carry > 0) + { + if (out_digits < a_digits) + carry += acc[out_digits]; + + if (out_digits < n_digits) + carry += (png_uint_32)num[out_digits] * val; + + acc[out_digits++] = (png_uint_16)(carry & 0xffff); + carry >>= 16; + } + + /* So carry is 0 and all the input digits have been consumed. This means + * that it is possible to skip any remaining digits in acc. + */ + if (out_digits > a_digits) + return out_digits; + } + + return a_digits; +} + +static int +uarb_mult32(uarb acc, int a_digits, uarb num, int n_digits, png_uint_32 val) + /* calculate acc += num * val, 'val' may be any 32-bit value, 'acc' and 'num' + * may be any value, returns the number of digits in 'acc'. + */ +{ + if (n_digits > 0 && val > 0) + { + a_digits = uarb_mult_digit(acc, a_digits, num, n_digits, + (png_uint_16)(val & 0xffff)); + + /* Because n_digits and val are >0 the following must be true: */ + assert(a_digits > 0); + + val >>= 16; + if (val > 0) + a_digits = uarb_mult_digit(acc+1, a_digits-1, num, n_digits, + (png_uint_16)val) + 1; + } + + return a_digits; +} + +static int +uarb_shift(uarb inout, int ndigits, unsigned int right_shift) + /* Shift inout right by right_shift bits, right_shift must be in the range + * 1..15 + */ +{ + FIX_GCC int i = ndigits; + png_uint_16 carry = 0; + + assert(right_shift >= 1 && right_shift <= 15); + + while (--i >= 0) + { + png_uint_16 temp = (png_uint_16)(carry | (inout[i] >> right_shift)); + + /* Bottom bits to top bits of carry */ + carry = (png_uint_16)((inout[i] << (16-right_shift)) & 0xffff); + + inout[i] = temp; + + /* The shift may reduce ndigits */ + if (i == ndigits-1 && temp == 0) + ndigits = i; + } + + return ndigits; +} + +static int +uarb_cmp(uarb a, int adigits, uarb b, int bdigits) + /* Return -1/0/+1 according as a<b/a==b/a>b */ +{ + if (adigits < bdigits) + return -1; + + if (adigits > bdigits) + return 1; + + while (adigits-- > 0) + if (a[adigits] < b[adigits]) + return -1; + + else if (a[adigits] > b[adigits]) + return 1; + + return 0; +} + +#if 0 /*UNUSED*/ +static int +uarb_eq32(uarb num, int digits, png_uint_32 val) + /* Return true if the uarb is equal to 'val' */ +{ + switch (digits) + { + case 0: return val == 0; + case 1: return val == num[0]; + case 2: return (val & 0xffff) == num[0] && (val >> 16) == num[1]; + default: return 0; + } +} +#endif + +static void +uarb_printx(uarb num, int digits, FILE *out) + /* Print 'num' as a hexadecimal number (easier than decimal!) */ +{ + while (digits > 0) + if (num[--digits] > 0) + { + fprintf(out, "0x%x", num[digits]); + + while (digits > 0) + fprintf(out, "%.4x", num[--digits]); + } + + else if (digits == 0) /* the number is 0 */ + fputs("0x0", out); +} + +static void +uarb_print(uarb num, int digits, FILE *out) + /* Prints 'num' as a decimal if it will fit in an unsigned long, else as a + * hexadecimal number. Notice that the results vary for images over 4GByte + * in a system dependent way, and the hexadecimal form doesn't work very well + * in awk script input. + * + * + * TODO: write uarb_div10 + */ +{ + if (digits * sizeof (udigit) > sizeof (unsigned long)) + uarb_printx(num, digits, out); + + else + { + unsigned long n = 0; + + while (digits > 0) + n = (n << 16) + num[--digits]; + + fprintf(out, "%lu", n); + } +} + +/* Generate random bytes. This uses a boring repeatable algorithm and it + * is implemented here so that it gives the same set of numbers on every + * architecture. It's a linear congruential generator (Knuth or Sedgewick + * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and + * Hill, "The Art of Electronics" (Pseudo-Random Bit Sequences and Noise + * Generation.) + * + * (Copied from contrib/libtests/pngvalid.c) + */ +static void +make_random_bytes(png_uint_32* seed, void* pv, size_t size) +{ + png_uint_32 u0 = seed[0], u1 = seed[1]; + png_bytep bytes = voidcast(png_bytep, pv); + + /* There are thirty-three bits; the next bit in the sequence is bit-33 XOR + * bit-20. The top 1 bit is in u1, the bottom 32 are in u0. + */ + size_t i; + for (i=0; i<size; ++i) + { + /* First generate 8 new bits then shift them in at the end. */ + png_uint_32 u = ((u0 >> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff; + u1 <<= 8; + u1 |= u0 >> 24; + u0 <<= 8; + u0 |= u; + *bytes++ = (png_byte)u; + } + + seed[0] = u0; + seed[1] = u1; +} + +/* Clear an object to a random value. */ +static void +clear(void *pv, size_t size) +{ + static png_uint_32 clear_seed[2] = { 0x12345678, 0x9abcdef0 }; + make_random_bytes(clear_seed, pv, size); +} + +#define CLEAR(object) clear(&(object), sizeof (object)) + +/* Copied from unreleased 1.7 code. + * + * CRC checking uses a local pre-built implementation of the Ethernet CRC32. + * This is to avoid a function call to the zlib DLL and to optimize the + * byte-by-byte case. + */ +static png_uint_32 crc_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +}; + +/* The CRC calculated here *IS* conditioned, the corresponding value used by + * zlib and the result value is obtained by XORing with CRC_INIT, which is also + * the first value that must be passed in (for the first byte) to crc_one_byte. + */ +#define CRC_INIT 0xffffffff + +static png_uint_32 +crc_one_byte(png_uint_32 crc, int b) +{ + return crc_table[(crc ^ b) & 0xff] ^ (crc >> 8); +} + +static png_uint_32 +crc_init_4(png_uint_32 value) +{ + /* This is an alternative to the algorithm used in zlib, which requires four + * separate tables to parallelize the four byte operations, it only works for + * a CRC of the first four bytes of the stream, but this is what happens in + * the parser below where length+chunk-name is read and chunk-name used to + * initialize the CRC. Notice that the calculation here avoids repeated + * conditioning (xor with 0xffffffff) by storing the conditioned value. + */ + png_uint_32 crc = crc_table[(~value >> 24)] ^ 0xffffff; + + crc = crc_table[(crc ^ (value >> 16)) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ (value >> 8)) & 0xff] ^ (crc >> 8); + return crc_table[(crc ^ value) & 0xff] ^ (crc >> 8); +} + +static int +chunk_type_valid(png_uint_32 c) + /* Bit whacking approach to chunk name validation that is intended to avoid + * branches. The cost is that it uses a lot of 32-bit constants, which might + * be bad on some architectures. + */ +{ + png_uint_32 t; + + /* Remove bit 5 from all but the reserved byte; this means every + * 8-bit unit must be in the range 65-90 to be valid. So bit 5 + * must be zero, bit 6 must be set and bit 7 zero. + */ + c &= ~PNG_U32(32,32,0,32); + t = (c & ~0x1f1f1f1f) ^ 0x40404040; + + /* Subtract 65 for each 8 bit quantity, this must not overflow + * and each byte must then be in the range 0-25. + */ + c -= PNG_U32(65,65,65,65); + t |=c ; + + /* Subtract 26, handling the overflow which should set the top + * three bits of each byte. + */ + c -= PNG_U32(25,25,25,26); + t |= ~c; + + return (t & 0xe0e0e0e0) == 0; +} + +/**************************** CONTROL INFORMATION *****************************/ + +/* Information about a sequence of IDAT chunks, the chunks have been re-synced + * using sync_stream below and the new lengths are recorded here. Because the + * number of chunks is unlimited this is handled using a linked list of these + * structures. + */ +struct IDAT_list +{ + struct IDAT_list *next; /* Linked list */ + unsigned int length; /* Actual length of the array below */ + unsigned int count; /* Number of entries that are valid */ +# define IDAT_INIT_LENGTH 16 + png_uint_32 lengths[IDAT_INIT_LENGTH]; +}; + +static void +IDAT_list_init(struct IDAT_list *list) +{ + CLEAR(*list); + + list->next = NULL; + list->length = IDAT_INIT_LENGTH; +} + +static size_t +IDAT_list_size(struct IDAT_list *list, unsigned int length) + /* Return the size in bytes of an IDAT_list of the given length. */ +{ + if (list != NULL) + length = list->length; + + return sizeof *list - sizeof list->lengths + + length * sizeof list->lengths[0]; +} + +static void +IDAT_list_end(struct IDAT_list *IDAT_list) +{ + struct IDAT_list *list = IDAT_list->next; + + CLEAR(*IDAT_list); + + while (list != NULL) + { + struct IDAT_list *next = list->next; + + clear(list, IDAT_list_size(list, 0)); + free(list); + list = next; + } +} + +static struct IDAT_list * +IDAT_list_extend(struct IDAT_list *tail) +{ + /* Use the previous cached value if available. */ + struct IDAT_list *next = tail->next; + + if (next == NULL) + { + /* Insert a new, malloc'ed, block of IDAT information buffers, this + * one twice as large as the previous one: + */ + unsigned int length = 2 * tail->length; + + if (length < tail->length) /* arithmetic overflow */ + length = tail->length; + + next = voidcast(IDAT_list*, malloc(IDAT_list_size(NULL, length))); + CLEAR(*next); + + /* The caller must handle this: */ + if (next == NULL) + return NULL; + + next->next = NULL; + next->length = length; + tail->next = next; + } + + return next; +} + +/* GLOBAL CONTROL STRUCTURE */ +struct global +{ + /* PUBLIC GLOBAL VARIABLES: OWNER INITIALIZE */ + unsigned int errors :1; /* print file errors to stderr */ + unsigned int warnings :1; /* print libpng warnings to stderr */ + unsigned int optimize_zlib :1; /* Run optimization search */ + unsigned int quiet :2; /* don't output summaries */ + unsigned int verbose :3; /* various internal tracking */ + unsigned int skip :3; /* Non-critical chunks to skip */ +# define SKIP_NONE 0 +# define SKIP_BAD_CRC 1 /* Chunks with a bad CRC */ +# define SKIP_UNSAFE 2 /* Chunks not safe to copy */ +# define SKIP_UNUSED 3 /* Chunks not used by libpng */ +# define SKIP_TRANSFORM 4 /* Chunks only used in transforms */ +# define SKIP_COLOR 5 /* Everything but tRNS, sBIT, gAMA and sRGB */ +# define SKIP_ALL 6 /* Everything but tRNS and sBIT */ + + png_uint_32 idat_max; /* 0 to perform no re-chunking */ + + int status_code; /* Accumulated status code */ +# define TOO_FAR_BACK 0x01 /* found a too-far-back error */ +# define CRC_ERROR 0x02 /* fixed an invalid CRC */ +# define STREAM_ERROR 0x04 /* damaged PNG stream (may be fixable) */ +# define TRUNCATED 0x08 /* truncated but still readable */ +# define FILE_ERROR 0x10 /* could not read the file */ +# define WRITE_ERROR 0x20 /* write error (this terminates the read) */ +# define INTERNAL_ERROR 0x40 /* internal limits/errors encountered */ + + /* PUBLIC GLOBAL VARIABLES: USED INTERNALLY BY IDAT READ CODE */ + struct IDAT_list idat_cache; /* Cache of file IDAT information buffers */ + /* The structure is shared across all uses of this global control + * structure to avoid reallocation between IDAT streams. + */ +}; + +static int +global_end(struct global *global) +{ + + int rc; + + IDAT_list_end(&global->idat_cache); + rc = global->status_code; + CLEAR(*global); + return rc; +} + +static void +global_init(struct global *global) + /* Call this once (and only once) to initialize the control */ +{ + CLEAR(*global); + + /* Globals */ + global->errors = 0; + global->warnings = 0; + global->quiet = 0; + global->verbose = 0; + global->idat_max = 0; /* no re-chunking of IDAT */ + global->optimize_zlib = 0; + global->skip = SKIP_NONE; + global->status_code = 0; + + IDAT_list_init(&global->idat_cache); +} + +static int +skip_chunk_type(const struct global *global, png_uint_32 type) + /* Return true if this chunk is to be skipped according to the --strip + * option. This code needs to recognize all known ancillary chunks in order + * to handle the --strip=unsafe option. + */ +{ + /* Never strip critical chunks: */ + if (CRITICAL(type)) + return 0; + + switch (type) + { + /* Chunks that are treated as, effectively, critical because they affect + * correct interpretation of the pixel values: + */ + case png_tRNS: case png_sBIT: + return 0; + + /* Chunks that specify gamma encoding which should therefore only be + * removed the the user insists: + */ + case png_gAMA: case png_sRGB: + if (global->skip >= SKIP_ALL) + return 1; + return 0; + + /* Chunks that affect color interpretation - not used by libpng and rarely + * used by applications, but technically still required for correct + * interpretation of the image data: + */ + case png_cHRM: case png_iCCP: + if (global->skip >= SKIP_COLOR) + return 1; + return 0; + + /* Other chunks that are used by libpng in image transformations (as + * opposed to known chunks that have get/set APIs but are not otherwise + * used.) + */ + case png_bKGD: + if (global->skip >= SKIP_TRANSFORM) + return 1; + return 0; + + /* All other chunks that libpng knows about and affect neither image + * interpretation nor libpng transforms - chunks that are effectively + * unused by libpng even though libpng might recognize and store them. + */ + case png_fRAc: case png_gIFg: case png_gIFt: case png_gIFx: case png_hIST: + case png_iTXt: case png_oFFs: case png_pCAL: case png_pHYs: case png_sCAL: + case png_sPLT: case png_sTER: case png_tEXt: case png_tIME: case png_zTXt: + if (global->skip >= SKIP_UNUSED) + return 1; + return 0; + + /* Chunks that libpng does not know about (notice that this depends on the + * list above including all known chunks!) The decision here depends on + * whether the safe-to-copy bit is set in the chunk type. + */ + default: + if (SAFE_TO_COPY(type)) + { + if (global->skip >= SKIP_UNUSED) /* as above */ + return 1; + } + + else if (global->skip >= SKIP_UNSAFE) + return 1; + + return 0; + } +} + +/* PER-FILE CONTROL STRUCTURE */ +struct chunk; +struct IDAT; +struct file +{ + /* ANCESTORS */ + struct global *global; + + /* PUBLIC PER-FILE VARIABLES: CALLER INITIALIZE */ + const char * file_name; + const char * out_name; /* Name of output file (if required) */ + + /* PUBLIC PER-FILE VARIABLES: SET BY PNG READ CODE */ + /* File specific result codes */ + int status_code; /* Set to a bit mask of the following: */ + int read_errno; /* Records a read error errno */ + int write_errno; /* Records a write error errno */ + + /* IHDR information */ + png_uint_32 width; + png_uint_32 height; + png_byte bit_depth; + png_byte color_type; + png_byte compression_method; + png_byte filter_method; + png_byte interlace_method; + + udigit image_bytes[5]; + int image_digits; + + /* PROTECTED PER-FILE VARIABLES: USED BY THE READ CODE */ + FILE * file; /* Original PNG file */ + FILE * out; /* If a new one is being written */ + jmp_buf jmpbuf; /* Set while reading a PNG */ + + /* PROTECTED CHUNK SPECIFIC VARIABLES: USED BY CHUNK CODE */ + /* The following variables are used during reading to record the length, type + * and data position of the *next* chunk or, right at the start, the + * signature (in length,type). + * + * When a chunk control structure is instantiated these values are copied + * into the structure and can then be overritten with the data for the next + * chunk. + */ + fpos_t data_pos; /* Position of first byte of chunk data */ + png_uint_32 length; /* First word (length or signature start) */ + png_uint_32 type; /* Second word (type or signature end) */ + png_uint_32 crc; /* Running chunk CRC (used by read_chunk) */ + + /* These counts are maintained by the read and write routines below and are + * reset by the chunk handling code. They record the total number of bytes + * read or written for the chunk, including the header (length,type) bytes. + */ + png_uint_32 read_count; /* Count of bytes read (in the chunk) */ + png_uint_32 write_count; /* Count of bytes written (in the chunk) */ + int state; /* As defined here: */ +# define STATE_SIGNATURE 0 /* The signature is being written */ +# define STATE_CHUNKS 1 /* Non-IDAT chunks are being written */ +# define STATE_IDAT 2 /* An IDAT stream is being written */ + + /* Two pointers used to enable clean-up in the event of fatal errors and to + * hold state about the parser process (only one of each at present.) + */ + struct chunk * chunk; + struct IDAT * idat; + + /* Interface to allocate a new chunk or IDAT control structure. The result + * is returned by setting one or other of the above variables. Note that the + * relevant initializer is called by the allocator function. The alloc_ptr + * is used only by the implementation of the allocate function. + */ + void * alloc_ptr; + void (*alloc)(struct file*,int idat); + /* idat: allocate IDAT not chunk */ +}; + +/* Valid longjmp (stop) codes are: */ +#define LIBPNG_WARNING_CODE 1 /* generic png_error */ +#define LIBPNG_ERROR_CODE 2 /* generic png_error */ +#define ZLIB_ERROR_CODE 3 /* generic zlib error */ +#define INVALID_ERROR_CODE 4 /* detected an invalid PNG */ +#define READ_ERROR_CODE 5 /* read failed */ +#define WRITE_ERROR_CODE 6 /* error in write */ +#define UNEXPECTED_ERROR_CODE 7 /* unexpected (internal?) error */ + +static void +emit_string(const char *str, FILE *out) + /* Print a string with spaces replaced by '_' and non-printing characters by + * an octal escape. + */ +{ + for (; *str; ++str) + if (isgraph(UCHAR_MAX & *str)) + putc(*str, out); + + else if (isspace(UCHAR_MAX & *str)) + putc('_', out); + + else + fprintf(out, "\\%.3o", *str); +} + +static const char * +strcode(int code) +{ + switch (code) + { + case LIBPNG_WARNING_CODE: return "warning"; + case LIBPNG_ERROR_CODE: return "libpng"; + case ZLIB_ERROR_CODE: return "zlib"; + case INVALID_ERROR_CODE: return "invalid"; + case READ_ERROR_CODE: return "read"; + case WRITE_ERROR_CODE: return "write"; + case UNEXPECTED_ERROR_CODE: return "unexpected"; + default: return "INVALID"; + } +} + +static void +emit_error(struct file *file, int code, const char *what) + /* Generic error message routine, takes a 'stop' code but can be used + * elsewhere. Always outputs a message. + */ +{ + const char *reason; + int err = 0; + + switch (code) + { + case LIBPNG_WARNING_CODE: reason = "libpng warning:"; break; + case LIBPNG_ERROR_CODE: reason = "libpng error:"; break; + case ZLIB_ERROR_CODE: reason = "zlib error:"; break; + case INVALID_ERROR_CODE: reason = "invalid"; break; + case READ_ERROR_CODE: reason = "read failure:"; + err = file->read_errno; + break; + case WRITE_ERROR_CODE: reason = "write error"; + err = file->write_errno; + break; + case UNEXPECTED_ERROR_CODE: reason = "unexpected error:"; + err = file->read_errno; + if (err == 0) + err = file->write_errno; + break; + default: reason = "INVALID (internal error):"; break; + } + + if (err != 0) + fprintf(stderr, "%s: %s %s [%s]\n", file->file_name, reason, what, + strerror(err)); + + else + fprintf(stderr, "%s: %s %s\n", file->file_name, reason, what); +} + +static void chunk_end(struct chunk **); +static void IDAT_end(struct IDAT **); + +static int +file_end(struct file *file) +{ + int rc; + + /* If either of the chunk pointers are set end them here, the IDAT structure + * must be deallocated first as it may deallocate the chunk structure. + */ + if (file->idat != NULL) + IDAT_end(&file->idat); + + if (file->chunk != NULL) + chunk_end(&file->chunk); + + rc = file->status_code; + + if (file->file != NULL) + (void)fclose(file->file); + + if (file->out != NULL) + { + /* NOTE: this is bitwise |, all the following functions must execute and + * must succeed. + */ + if (ferror(file->out) | fflush(file->out) | fclose(file->out)) + { + perror(file->out_name); + emit_error(file, READ_ERROR_CODE, "output write error"); + rc |= WRITE_ERROR; + } + } + + /* Accumulate the result codes */ + file->global->status_code |= rc; + + CLEAR(*file); + + return rc; /* status code: non-zero on read or write error */ +} + +static int +file_init(struct file *file, struct global *global, const char *file_name, + const char *out_name, void *alloc_ptr, void (*alloc)(struct file*,int)) + /* Initialize a file control structure. This will open the given files as + * well. The status code returned is 0 on success, non zero (using the flags + * above) on a file open error. + */ +{ + CLEAR(*file); + file->global = global; + + file->file_name = file_name; + file->out_name = out_name; + file->status_code = 0; + file->read_errno = 0; + file->write_errno = 0; + + file->file = NULL; + file->out = NULL; + /* jmpbuf is garbage: must be set by read_png */ + + file->read_count = 0; + file->state = STATE_SIGNATURE; + + file->chunk = NULL; + file->idat = NULL; + + file->alloc_ptr = alloc_ptr; + file->alloc = alloc; + + /* Open the files: */ + assert(file_name != NULL); + file->file = fopen(file_name, "rb"); + + if (file->file == NULL) + { + file->read_errno = errno; + file->status_code |= FILE_ERROR; + /* Always output: please give a readable file! */ + perror(file_name); + return FILE_ERROR; + } + + if (out_name != NULL) + { + file->out = fopen(out_name, "wb"); + + if (file->out == NULL) + { + file->write_errno = errno; + file->status_code |= WRITE_ERROR; + perror(out_name); + return WRITE_ERROR; + } + } + + return 0; +} + +static void +log_error(struct file *file, int code, const char *what) + /* Like emit_error but checks the global 'errors' flag */ +{ + if (file->global->errors) + emit_error(file, code, what); +} + +static char +type_char(png_uint_32 v) +{ + /* In fact because chunk::chunk_type is validated prior to any call to this + * function it will always return a-zA-Z, but the extra codes are just there + * to help in finding internal (programming) errors. Note that the code only + * ever considers the low 7 bits of the value (so it is not necessary for the + * type_name function to mask of the byte.) + */ + if (v & 32) + return "!abcdefghijklmnopqrstuvwxyz56789"[(v-96)&31]; + + else + return "@ABCDEFGHIJKLMNOPQRSTUVWXYZ01234"[(v-64)&31]; +} + +static void +type_name(png_uint_32 type, FILE *out) +{ + putc(type_char(type >> 24), out); + putc(type_char(type >> 16), out); + putc(type_char(type >> 8), out); + putc(type_char(type ), out); +} + +static void +type_sep(FILE *out) +{ + putc(':', out); + putc(' ', out); +} + +static png_uint_32 current_type(struct file *file, int code); + +PNG_NORETURN static void +stop(struct file *file, int code, const char *what) + /* Return control when a PNG file cannot be read. This outputs an 'ERR' + * summary line too. + */ +{ + log_error(file, code, what); + + /* The chunk being read is typically identified by file->chunk or, if this is + * NULL, by file->type. This may be wrong if libpng reads ahead, but this + * only happens with IDAT where libpng reads the header then jumps around + * finding errors in the previous chunks. We know that is happening because + * we are at the start of the IDAT (i.e. no IDAT data has yet been written.) + * + * SUMMARY FORMAT (stop): + * + * IDAT ERR status code read-errno write-errno message file + * + * 'uncompressed' will be 0 if there was a problem in the IHDR. The errno + * values are emit_string(strerror(errno)). + */ + if (file->global->quiet < 2) /* need two quiets to stop this. */ + { + png_uint_32 type; + + if (file->chunk != NULL) + type = current_type(file, code); /* Gropes in struct chunk and IDAT */ + + else + type = file->type; + + if (type) + type_name(type, stdout); + + else /* magic: an IDAT header, produces bogons for too many IDATs */ + fputs("HEAD", stdout); /* not a registered chunk! */ + + printf(" ERR %.2x %s ", file->status_code, strcode(code)); + /* This only works one strerror at a time, because of the way strerror is + * implemented. + */ + emit_string(strerror(file->read_errno), stdout); + putc(' ', stdout); + emit_string(strerror(file->write_errno), stdout); + putc(' ', stdout); + emit_string(what, stdout); + putc(' ', stdout); + fputs(file->file_name, stdout); + putc('\n', stdout); + } + + file->status_code |= FILE_ERROR; + longjmp(file->jmpbuf, code); +} + +PNG_NORETURN static void +stop_invalid(struct file *file, const char *what) +{ + stop(file, INVALID_ERROR_CODE, what); +} + +static void +type_message(struct file *file, png_uint_32 type, const char *what) + /* Error message for a chunk; the chunk name comes from 'type' */ +{ + if (file->global->errors) + { + fputs(file->file_name, stderr); + type_sep(stderr); + type_name(type, stderr); + type_sep(stderr); + fputs(what, stderr); + putc('\n', stderr); + } +} + +/* Input file positioning - we jump around in the input file while reading + * stuff, these wrappers deal with the error handling. + */ +static void +file_getpos(struct file *file, fpos_t *pos) +{ + if (fgetpos(file->file, pos)) + { + /* This is unexpected, so perror it */ + perror(file->file_name); + stop(file, READ_ERROR_CODE, "fgetpos"); + } +} + +static void +file_setpos(struct file *file, const fpos_t *pos) +{ + if (fsetpos(file->file, pos)) + { + perror(file->file_name); + stop(file, READ_ERROR_CODE, "fsetpos"); + } +} + +static void +getpos(struct file *file) + /* Get the current position and store it in 'data_pos'. The corresponding + * setpos() function is chunk specific because it uses the copy of the + * position for the specific chunk. + */ +{ + file_getpos(file, &file->data_pos); +} + + +/* Read utility - read a single byte, returns a value in the range 0..255 or EOF + * on a read error. In the latter case status_code and read_errno are updated + * appropriately. + */ +static int +read_byte(struct file *file) +{ + int ch = getc(file->file); + + if (ch >= 0 && ch <= 255) + { + ++(file->read_count); + return ch; + } + + else if (ch != EOF) + { + file->status_code |= INTERNAL_ERROR; + file->read_errno = ERANGE; /* out of range character */ + + /* This is very unexpected; an error message is always output: */ + emit_error(file, UNEXPECTED_ERROR_CODE, "file read"); + } + +# ifdef EINTR + else if (errno == EINTR) /* Interrupted, try again */ + { + errno = 0; + return read_byte(file); + } +# endif + + else + { + /* An error, it doesn't really matter what the error is but it gets + * recorded anyway. + */ + if (ferror(file->file)) + file->read_errno = errno; + + else if (feof(file->file)) + file->read_errno = 0; /* I.e. a regular EOF, no error */ + + else /* unexpected */ + file->read_errno = EDOM; + } + + /* 'TRUNCATED' is used for all cases of failure to read a byte, because of + * the way libpng works a byte read is never attempted unless the byte is + * expected to be there, so EOF should not occur. + */ + file->status_code |= TRUNCATED; + return EOF; +} + +static png_byte +reread_byte(struct file *file) + /* Read a byte when an error is not expected to happen because the byte has + * been read before without error. + */ +{ + int ch = getc(file->file); + + if (errno != 0) + file->read_errno = errno; + + if (ch < 0 || ch > 255) + stop(file, UNEXPECTED_ERROR_CODE, "reread"); + + return (png_byte)ch; +} + +static png_uint_32 +reread_4(struct file *file) + /* The same but for a four byte quantity */ +{ + png_uint_32 result = 0; + int i = 0; + + while (++i <= 4) + result = (result << 8) + reread_byte(file); + + return result; +} + +static void +skip_12(struct file *file) + /* Skip exactly 12 bytes in the input stream - used to skip a CRC and chunk + * header that has been read before. + */ +{ + /* Since the chunks were read before this shouldn't fail: */ + if (fseek(file->file, 12, SEEK_CUR) != 0) + { + if (errno != 0) + file->read_errno = errno; + + stop(file, UNEXPECTED_ERROR_CODE, "reskip"); + } +} + +static void +write_byte(struct file *file, int b) + /* Write one byte to the output - this causes a fatal error if the write + * fails and the read of this PNG file immediately terminates. Just + * increments the write count if there is no output file. + */ +{ + if (file->out != NULL) + { + if (putc(b, file->out) != b) + { + file->write_errno = errno; + file->status_code |= WRITE_ERROR; + stop(file, WRITE_ERROR_CODE, "write byte"); + } + } + + ++(file->write_count); +} + +/* Derivatives of the read/write functions. */ +static unsigned int +read_4(struct file *file, png_uint_32 *pu) + /* Read four bytes, returns the number of bytes read successfully and, if all + * four bytes are read, assigns the result to *pu. + */ +{ + unsigned int i = 0; + png_uint_32 val = 0; + + do + { + int ch = read_byte(file); + + if (ch == EOF) + return i; + + val = (val << 8) + ch; + } while (++i < 4); + + *pu = val; + return i; +} + +/* CRC handling - read but calculate the CRC while doing so. */ +static int +crc_read_many(struct file *file, png_uint_32 length) + /* Reads 'length' bytes and updates the CRC, returns true on success, false + * if the input is truncated. + */ +{ + if (length > 0) + { + png_uint_32 crc = file->crc; + + do + { + int ch = read_byte(file); + + if (ch == EOF) + return 0; /* Truncated */ + + crc = crc_one_byte(crc, ch); + } + while (--length > 0); + + file->crc = crc; + } + + return 1; /* OK */ +} + +static int +calc_image_size(struct file *file) + /* Fill in the image_bytes field given the IHDR information, calls stop on + * error. + */ +{ + png_uint_16 pd = file->bit_depth; + + switch (file->color_type) + { + default: + stop_invalid(file, "IHDR: colour type"); + + invalid_bit_depth: + stop_invalid(file, "IHDR: bit depth"); + + case 0: /* g */ + if (pd != 1 && pd != 2 && pd != 4 && pd != 8 && pd != 16) + goto invalid_bit_depth; + break; + + case 3: + if (pd != 1 && pd != 2 && pd != 4 && pd != 8) + goto invalid_bit_depth; + break; + + case 2: /* rgb */ + if (pd != 8 && pd != 16) + goto invalid_bit_depth; + + pd = (png_uint_16)(pd * 3); + break; + + case 4: /* ga */ + if (pd != 8 && pd != 16) + goto invalid_bit_depth; + + pd = (png_uint_16)(pd * 2); + break; + + case 6: /* rgba */ + if (pd != 8 && pd != 16) + goto invalid_bit_depth; + + pd = (png_uint_16)(pd * 4); + break; + } + + if (file->width < 1 || file->width > 0x7fffffff) + stop_invalid(file, "IHDR: width"); + + else if (file->height < 1 || file->height > 0x7fffffff) + stop_invalid(file, "IHDR: height"); + + else if (file->compression_method != 0) + stop_invalid(file, "IHDR: compression method"); + + else if (file->filter_method != 0) + stop_invalid(file, "IHDR: filter method"); + + else switch (file->interlace_method) + { + case PNG_INTERLACE_ADAM7: + /* Interlacing makes the image larger because of the replication of + * both the filter byte and the padding to a byte boundary. + */ + { + int pass; + int image_digits = 0; + udigit row_width[2], row_bytes[3]; + + for (pass=0; pass<=6; ++pass) + { + png_uint_32 pw = PNG_PASS_COLS(file->width, pass); + + if (pw > 0) + { + int digits; + + /* calculate 1+((pw*pd+7)>>3) in row_bytes */ + digits = uarb_mult_digit(row_bytes, uarb_set(row_bytes, 7), + row_width, uarb_set(row_width, pw), pd); + digits = uarb_shift(row_bytes, digits, 3); + digits = uarb_inc(row_bytes, digits, 1); + + /* Add row_bytes * pass-height to the file image_bytes field + */ + image_digits = uarb_mult32(file->image_bytes, image_digits, + row_bytes, digits, + PNG_PASS_ROWS(file->height, pass)); + } + } + + file->image_digits = image_digits; + } + break; + + case PNG_INTERLACE_NONE: + { + int digits; + udigit row_width[2], row_bytes[3]; + + /* As above, but use image_width in place of the pass width: */ + digits = uarb_mult_digit(row_bytes, uarb_set(row_bytes, 7), + row_width, uarb_set(row_width, file->width), pd); + digits = uarb_shift(row_bytes, digits, 3); + digits = uarb_inc(row_bytes, digits, 1); + + /* Set row_bytes * image-height to the file image_bytes field */ + file->image_digits = uarb_mult32(file->image_bytes, 0, + row_bytes, digits, file->height); + } + break; + + default: + stop_invalid(file, "IHDR: interlace method"); + } + + assert(file->image_digits >= 1 && file->image_digits <= 5); + return 1; +} + +/* PER-CHUNK CONTROL STRUCTURE + * This structure is instantiated for each chunk, except for the IDAT chunks + * where one chunk control structure is used for the whole of a single stream of + * IDAT chunks (see the IDAT control structure below). + */ +struct chunk +{ + /* ANCESTORS */ + struct file * file; + struct global * global; + + /* PUBLIC IDAT INFORMATION: SET BY THE ZLIB CODE */ + udigit uncompressed_bytes[5]; + int uncompressed_digits; + udigit compressed_bytes[5]; + int compressed_digits; + + /* PUBLIC PER-CHUNK INFORMATION: USED BY CHUNK READ CODE */ + /* This information is filled in by chunk_init from the data in the file + * control structure, but chunk_length may be changed later. + */ + fpos_t chunk_data_pos; /* Position of first byte of chunk data */ + png_uint_32 chunk_length; /* From header (or modified below) */ + png_uint_32 chunk_type; /* From header */ + + /* PUBLIC PER-CHUNK INFORMATION: FOR THE CHUNK WRITE CODE */ + png_uint_32 write_crc; /* Output CRC (may differ from read_crc) */ + png_uint_32 rewrite_offset; /* Count of bytes before rewrite. */ + int rewrite_length; /* Number of bytes left to change */ + png_byte rewrite_buffer[2]; /* Buffer of new byte values */ +}; + +static void +chunk_message(struct chunk *chunk, const char *message) +{ + type_message(chunk->file, chunk->chunk_type, message); +} + +static void +chunk_end(struct chunk **chunk_var) +{ + struct chunk *chunk = *chunk_var; + + *chunk_var = NULL; + CLEAR(*chunk); +} + +static void +chunk_init(struct chunk * const chunk, struct file * const file) + /* When a chunk is initialized the file length/type/pos are copied into the + * corresponding chunk fields and the new chunk is registered in the file + * structure. There can only be one chunk at a time. + * + * NOTE: this routine must onely be called from the file alloc routine! + */ +{ + assert(file->chunk == NULL); + + CLEAR(*chunk); + + chunk->file = file; + chunk->global = file->global; + + chunk->chunk_data_pos = file->data_pos; + chunk->chunk_length = file->length; + chunk->chunk_type = file->type; + + /* Compresssed/uncompressed size information (from the zlib control structure + * that is used to check the compressed data in a chunk.) + */ + chunk->uncompressed_digits = 0; + chunk->compressed_digits = 0; + + file->chunk = chunk; +} + +static png_uint_32 +current_type(struct file *file, int code) + /* Guess the actual chunk type that causes a stop() */ +{ + /* This may return png_IDAT for errors detected (late) in the header; that + * includes any inter-chunk consistency check that libpng performs. Assume + * that if the chunk_type is png_IDAT and the file write count is 8 this is + * what is happening. + */ + if (file->chunk != NULL) + { + png_uint_32 type = file->chunk->chunk_type; + + /* This is probably wrong for the excess IDATs case, because then libpng + * whines about too many of them (apparently in some cases erroneously) + * when the header is read. + */ + if (code <= LIBPNG_ERROR_CODE && type == png_IDAT && + file->write_count == 8) + type = 0; /* magic */ + + return type; + } + + else + return file->type; +} + +static void +setpos(struct chunk *chunk) + /* Reset the position to 'chunk_data_pos' - the start of the data for this + * chunk. As a side effect the read_count in the file is reset to 8, just + * after the length/type header. + */ +{ + chunk->file->read_count = 8; + file_setpos(chunk->file, &chunk->chunk_data_pos); +} + +/* Specific chunk handling - called for each chunk header, all special chunk + * processing is initiated in these functions. + */ +/* The next functions handle special processing for those chunks with LZ data, + * the data is identified and checked for validity. If there are problems which + * cannot be corrected the routines return false, otherwise true (although + * modification to the zlib header may be required.) + * + * The compressed data is in zlib format (RFC1950) and consequently has a + * minimum length of 7 bytes. + */ +static int zlib_check(struct file *file, png_uint_32 offset); + +static int +process_zTXt_iCCP(struct file *file) + /* zTXt and iCCP have exactly the same form - keyword, null, compression + * method then compressed data. + */ +{ + struct chunk *chunk = file->chunk; + png_uint_32 length; + png_uint_32 index = 0; + + assert(chunk != NULL && file->idat == NULL); + length = chunk->chunk_length; + setpos(chunk); + + while (length >= 9) + { + --length; + ++index; + if (reread_byte(file) == 0) /* keyword null terminator */ + { + --length; + ++index; + (void)reread_byte(file); /* compression method */ + return zlib_check(file, index); + } + } + + chunk_message(chunk, "too short"); + return 0; /* skip */ +} + +static int +process_iTXt(struct file *file) +{ + /* Like zTXt but more fields. */ + struct chunk *chunk = file->chunk; + png_uint_32 length; + png_uint_32 index = 0; + + assert(chunk != NULL && file->idat == NULL); + length = chunk->chunk_length; + setpos(chunk); + + while (length >= 5) + { + --length; + ++index; + if (reread_byte(file) == 0) /* keyword null terminator */ + { + --length; + ++index; + if (reread_byte(file) == 0) /* uncompressed text */ + return 1; /* nothing to check */ + + --length; + ++index; + (void)reread_byte(file); /* compression method */ + + /* Skip the language tag (null terminated). */ + while (length >= 9) + { + --length; + ++index; + if (reread_byte(file) == 0) /* terminator */ + { + /* Skip the translated keyword */ + while (length >= 8) + { + --length; + ++index; + if (reread_byte(file) == 0) /* terminator */ + return zlib_check(file, index); + } + } + } + + /* Ran out of bytes in the compressed case. */ + break; + } + } + + log_error(file, INVALID_ERROR_CODE, "iTXt chunk length"); + + return 0; /* skip */ +} + +/* IDAT READ/WRITE CONTROL STRUCTURE */ +struct IDAT +{ + /* ANCESTORS */ + struct file * file; + struct global * global; + + /* PROTECTED IDAT INFORMATION: SET BY THE IDAT READ CODE */ + struct IDAT_list *idat_list_head; /* START of the list of IDAT information */ + struct IDAT_list *idat_list_tail; /* *END* of the list of IDAT information */ + + /* PROTECTED IDAT INFORMATION: USED BY THE IDAT WRITE CODE */ + struct IDAT_list *idat_cur; /* Current list entry */ + unsigned int idat_count; /* And the *current* index into the list */ + png_uint_32 idat_index; /* Index of *next* input byte to write */ + png_uint_32 idat_length; /* Cache of current chunk length */ +}; + +/* NOTE: there is currently no IDAT_reset, so a stream cannot contain more than + * one IDAT sequence (i.e. MNG is not supported). + */ + +static void +IDAT_end(struct IDAT **idat_var) +{ + struct IDAT *idat = *idat_var; + struct file *file = idat->file; + + *idat_var = NULL; + + CLEAR(*idat); + + assert(file->chunk != NULL); + chunk_end(&file->chunk); + + /* Regardless of why the IDAT was killed set the state back to CHUNKS (it may + * already be CHUNKS because the state isn't changed until process_IDAT + * returns; a stop will cause IDAT_end to be entered in state CHUNKS!) + */ + file->state = STATE_CHUNKS; +} + +static void +IDAT_init(struct IDAT * const idat, struct file * const file) + /* When the chunk is png_IDAT instantiate an IDAT control structure in place + * of a chunk control structure. The IDAT will instantiate a chunk control + * structure using the file alloc routine. + * + * NOTE: this routine must only be called from the file alloc routine! + */ +{ + assert(file->chunk == NULL); + assert(file->idat == NULL); + + CLEAR(*idat); + + idat->file = file; + idat->global = file->global; + + /* Initialize the tail to the pre-allocated buffer and set the count to 0 + * (empty.) + */ + idat->global->idat_cache.count = 0; + idat->idat_list_head = idat->idat_list_tail = &idat->global->idat_cache; + + /* Now the chunk. The allocator calls the initializer of the new chunk and + * stores the result in file->chunk: + */ + file->alloc(file, 0/*chunk*/); + assert(file->chunk != NULL); + + /* And store this for cleanup (and to check for double alloc or failure to + * free.) + */ + file->idat = idat; +} + +static png_uint_32 +rechunk_length(struct IDAT *idat) + /* Return the length for the next IDAT chunk, taking into account + * rechunking. + */ +{ + png_uint_32 len = idat->global->idat_max; + + if (len == 0) /* use original chunk lengths */ + { + const struct IDAT_list *cur; + unsigned int count; + + if (idat->idat_index == 0) /* at the new chunk (first time) */ + return idat->idat_length; /* use the cache */ + + /* Otherwise rechunk_length is called at the end of a chunk for the length + * of the next one. + */ + cur = idat->idat_cur; + count = idat->idat_count; + + assert(idat->idat_index == idat->idat_length && + idat->idat_length == cur->lengths[count]); + + /* Return length of the *next* chunk */ + if (++count < cur->count) + return cur->lengths[count]; + + /* End of this list */ + assert(cur != idat->idat_list_tail); + cur = cur->next; + assert(cur != NULL && cur->count > 0); + return cur->lengths[0]; + } + + else /* rechunking */ + { + /* The chunk size is the lesser of file->idat_max and the number + * of remaining bytes. + */ + png_uint_32 have = idat->idat_length - idat->idat_index; + + if (len > have) + { + struct IDAT_list *cur = idat->idat_cur; + unsigned int j = idat->idat_count+1; /* the next IDAT in the list */ + + do + { + /* Add up the remaining bytes. This can't overflow because the + * individual lengths are always <= 0x7fffffff, so when we add two + * of them overflow is not possible. + */ + assert(cur != NULL); + + for (;;) + { + /* NOTE: IDAT_list::count here, not IDAT_list::length */ + for (; j < cur->count; ++j) + { + have += cur->lengths[j]; + if (len <= have) + return len; + } + + /* If this was the end return the count of the available bytes */ + if (cur == idat->idat_list_tail) + return have; + + cur = cur->next; + j = 0; + } + } + while (len > have); + } + + return len; + } +} + +static int +process_IDAT(struct file *file) + /* Process the IDAT stream, this is the more complex than the preceding + * cases because the compressed data is spread across multiple IDAT chunks + * (typically). Rechunking of the data is not handled here; all this + * function does is establish whether the zlib header needs to be modified. + * + * Initially the function returns false, indicating that the chunk should not + * be written. It does this until the last IDAT chunk is passed in, then it + * checks the zlib data and returns true. + * + * It does not return false on a fatal error; it calls stop instead. + * + * The caller must have an instantiated (IDAT) control structure and it must + * have extent over the whole read of the IDAT stream. For a PNG this means + * the whole PNG read, for MNG it could have lesser extent. + */ +{ + struct IDAT_list *list; + + assert(file->idat != NULL && file->chunk != NULL); + + /* We need to first check the entire sequence of IDAT chunks to ensure the + * stream is in sync. Do this by building a list of all the chunks and + * recording the length of each because the length may have been fixed up by + * sync_stream below. + * + * At the end of the list of chunks, where the type of the next chunk is not + * png_IDAT, process the whole stream using the list data to check validity + * then return control to the start and rewrite everything. + */ + list = file->idat->idat_list_tail; + + if (list->count == list->length) + { + list = IDAT_list_extend(list); + + if (list == NULL) + stop(file, READ_ERROR_CODE, "out of memory"); + + /* Move to the next block */ + list->count = 0; + file->idat->idat_list_tail = list; + } + + /* And fill in the next IDAT information buffer. */ + list->lengths[(list->count)++] = file->chunk->chunk_length; + + /* The type of the next chunk was recorded in the file control structure by + * the caller, if this is png_IDAT return 'skip' to the caller. + */ + if (file->type == png_IDAT) + return 0; /* skip this for the moment */ + + /* This is the final IDAT chunk, so run the tests to check for the too far + * back error and possibly optimize the window bits. This means going back + * to the start of the first chunk data, which is stored in the original + * chunk allocation. + */ + setpos(file->chunk); + + if (zlib_check(file, 0)) + { + struct IDAT *idat; + int cmp; + + /* The IDAT stream was successfully uncompressed; see whether it + * contained the correct number of bytes of image data. + */ + cmp = uarb_cmp(file->image_bytes, file->image_digits, + file->chunk->uncompressed_bytes, file->chunk->uncompressed_digits); + + if (cmp < 0) + type_message(file, png_IDAT, "extra uncompressed data"); + + else if (cmp > 0) + stop(file, LIBPNG_ERROR_CODE, "IDAT: uncompressed data too small"); + + /* Return the stream to the start of the first IDAT chunk; the length + * is set in the write case below but the input chunk variables must be + * set (once) here: + */ + setpos(file->chunk); + + idat = file->idat; + idat->idat_cur = idat->idat_list_head; + idat->idat_length = idat->idat_cur->lengths[0]; + idat->idat_count = 0; /* Count of chunks read in current list */ + idat->idat_index = 0; /* Index into chunk data */ + + /* Update the chunk length to the correct value for the IDAT chunk: */ + file->chunk->chunk_length = rechunk_length(idat); + + /* Change the state to writing IDAT chunks */ + file->state = STATE_IDAT; + + return 1; + } + + else /* Failure to decompress the IDAT stream; give up. */ + stop(file, ZLIB_ERROR_CODE, "could not uncompress IDAT"); +} + +/* ZLIB CONTROL STRUCTURE */ +struct zlib +{ + /* ANCESTORS */ + struct IDAT * idat; /* NOTE: May be NULL */ + struct chunk * chunk; + struct file * file; + struct global *global; + + /* GLOBAL ZLIB INFORMATION: SET BY THE CALLER */ + png_uint_32 rewrite_offset; + + /* GLOBAL ZLIB INFORMATION: SET BY THE ZLIB READ CODE */ + udigit compressed_bytes[5]; + int compressed_digits; + udigit uncompressed_bytes[5]; + int uncompressed_digits; + int file_bits; /* window bits from the file */ + int ok_bits; /* Set <16 on a successful read */ + int cksum; /* Set on a checksum error */ + + /* PROTECTED ZLIB INFORMATION: USED BY THE ZLIB ROUTINES */ + z_stream z; + png_uint_32 extra_bytes; /* Count of extra compressed bytes */ + int state; + int rc; /* Last return code */ + int window_bits; /* 0 if no change */ + png_byte header[2]; +}; + +static const char * +zlib_flevel(struct zlib *zlib) +{ + switch (zlib->header[1] >> 6) + { + case 0: return "supfast"; + case 1: return "stdfast"; + case 2: return "default"; + case 3: return "maximum"; + default: assert(UNREACHED); + } + + return "COMPILER BUG"; +} + +static const char * +zlib_rc(struct zlib *zlib) + /* Return a string for the zlib return code */ +{ + switch (zlib->rc) + { + case Z_OK: return "Z_OK"; + case Z_STREAM_END: return "Z_STREAM_END"; + case Z_NEED_DICT: return "Z_NEED_DICT"; + case Z_ERRNO: return "Z_ERRNO"; + case Z_STREAM_ERROR: return "Z_STREAM_ERROR"; + case Z_DATA_ERROR: return "Z_DATA_ERROR"; + case Z_MEM_ERROR: return "Z_MEM_ERROR"; + case Z_BUF_ERROR: return "Z_BUF_ERROR"; + case Z_VERSION_ERROR: return "Z_VERSION_ERROR"; + default: return "Z_*INVALID_RC*"; + } +} + +static void +zlib_message(struct zlib *zlib, int unexpected) + /* Output a message given a zlib rc */ +{ + if (zlib->global->errors) + { + const char *reason = zlib->z.msg; + + if (reason == NULL) + reason = "[no message]"; + + fputs(zlib->file->file_name, stderr); + type_sep(stderr); + type_name(zlib->chunk->chunk_type, stderr); + fprintf(stderr, ": %szlib error: %d (%s) (%s)\n", + unexpected ? "unexpected " : "", zlib->rc, zlib_rc(zlib), reason); + } +} + +static void +zlib_end(struct zlib *zlib) +{ + /* Output the summary line now; this ensures a summary line always gets + * output regardless of the manner of exit. + */ + if (!zlib->global->quiet) + { + if (zlib->ok_bits < 16) /* stream was read ok */ + { + const char *reason; + + if (zlib->cksum) + reason = "CHK"; /* checksum error */ + + else if (zlib->ok_bits > zlib->file_bits) + reason = "TFB"; /* fixing a too-far-back error */ + + else if (zlib->ok_bits == zlib->file_bits) + reason = "OK "; + + else + reason = "OPT"; /* optimizing window bits */ + + /* SUMMARY FORMAT (for a successful zlib inflate): + * + * IDAT reason flevel file-bits ok-bits compressed uncompressed file + */ + type_name(zlib->chunk->chunk_type, stdout); + printf(" %s %s %d %d ", reason, zlib_flevel(zlib), zlib->file_bits, + zlib->ok_bits); + uarb_print(zlib->compressed_bytes, zlib->compressed_digits, stdout); + putc(' ', stdout); + uarb_print(zlib->uncompressed_bytes, zlib->uncompressed_digits, + stdout); + putc(' ', stdout); + fputs(zlib->file->file_name, stdout); + putc('\n', stdout); + } + + else + { + /* This is a zlib read error; the chunk will be skipped. For an IDAT + * stream this will also cause a fatal read error (via stop()). + * + * SUMMARY FORMAT: + * + * IDAT SKP flevel file-bits z-rc compressed message file + * + * z-rc is the zlib failure code; message is the error message with + * spaces replaced by '-'. The compressed byte count indicates where + * in the zlib stream the error occurred. + */ + type_name(zlib->chunk->chunk_type, stdout); + printf(" SKP %s %d %s ", zlib_flevel(zlib), zlib->file_bits, + zlib_rc(zlib)); + uarb_print(zlib->compressed_bytes, zlib->compressed_digits, stdout); + putc(' ', stdout); + emit_string(zlib->z.msg ? zlib->z.msg : "[no_message]", stdout); + putc(' ', stdout); + fputs(zlib->file->file_name, stdout); + putc('\n', stdout); + } + } + + if (zlib->state >= 0) + { + zlib->rc = inflateEnd(&zlib->z); + + if (zlib->rc != Z_OK) + zlib_message(zlib, 1/*unexpected*/); + } + + CLEAR(*zlib); +} + +static int +zlib_reset(struct zlib *zlib, int window_bits) + /* Reinitializes a zlib with a different window_bits */ +{ + assert(zlib->state >= 0); /* initialized by zlib_init */ + + zlib->z.next_in = Z_NULL; + zlib->z.avail_in = 0; + zlib->z.next_out = Z_NULL; + zlib->z.avail_out = 0; + + zlib->window_bits = window_bits; + zlib->compressed_digits = 0; + zlib->uncompressed_digits = 0; + + zlib->state = 0; /* initialized, once */ + zlib->rc = inflateReset2(&zlib->z, 0); + if (zlib->rc != Z_OK) + { + zlib_message(zlib, 1/*unexpected*/); + return 0; + } + + return 1; +} + +static int +zlib_init(struct zlib *zlib, struct IDAT *idat, struct chunk *chunk, + int window_bits, png_uint_32 offset) + /* Initialize a zlib_control; the result is true/false */ +{ + CLEAR(*zlib); + + zlib->idat = idat; + zlib->chunk = chunk; + zlib->file = chunk->file; + zlib->global = chunk->global; + zlib->rewrite_offset = offset; /* never changed for this zlib */ + + /* *_out does not need to be set: */ + zlib->z.next_in = Z_NULL; + zlib->z.avail_in = 0; + zlib->z.zalloc = Z_NULL; + zlib->z.zfree = Z_NULL; + zlib->z.opaque = Z_NULL; + + zlib->state = -1; + zlib->window_bits = window_bits; + + zlib->compressed_digits = 0; + zlib->uncompressed_digits = 0; + + /* These values are sticky across reset (in addition to the stuff in the + * first block, which is actually constant.) + */ + zlib->file_bits = 16; + zlib->ok_bits = 16; /* unset */ + zlib->cksum = 0; /* set when a checksum error is detected */ + + /* '0' means use the header; inflateInit2 should always succeed because it + * does nothing apart from allocating the internal zstate. + */ + zlib->rc = inflateInit2(&zlib->z, 0); + if (zlib->rc != Z_OK) + { + zlib_message(zlib, 1/*unexpected*/); + return 0; + } + + else + { + zlib->state = 0; /* initialized */ + return 1; + } +} + +static int +max_window_bits(uarbc size, int ndigits) + /* Return the zlib stream window bits required for data of the given size. */ +{ + png_uint_16 cb; + + if (ndigits > 1) + return 15; + + cb = size[0]; + + if (cb > 16384) return 15; + if (cb > 8192) return 14; + if (cb > 4096) return 13; + if (cb > 2048) return 12; + if (cb > 1024) return 11; + if (cb > 512) return 10; + if (cb > 256) return 9; + return 8; +} + +static int +zlib_advance(struct zlib *zlib, png_uint_32 nbytes) + /* Read nbytes compressed bytes; the stream will be initialized if required. + * Bytes are always being reread and errors are fatal. The return code is as + * follows: + * + * -1: saw the "too far back" error + * 0: ok, keep going + * 1: saw Z_STREAM_END (zlib->extra_bytes indicates too much data) + * 2: a zlib error that cannot be corrected (error message already + * output if required.) + */ +# define ZLIB_TOO_FAR_BACK (-1) +# define ZLIB_OK 0 +# define ZLIB_STREAM_END 1 +# define ZLIB_FATAL 2 +{ + int state = zlib->state; + int endrc = ZLIB_OK; + png_uint_32 in_bytes = 0; + struct file *file = zlib->file; + + assert(state >= 0); + + while (in_bytes < nbytes && endrc == ZLIB_OK) + { + png_uint_32 out_bytes; + int flush; + png_byte bIn = reread_byte(file); + png_byte bOut; + + switch (state) + { + case 0: /* first header byte */ + { + int file_bits = 8+(bIn >> 4); + int new_bits = zlib->window_bits; + + zlib->file_bits = file_bits; + + /* Check against the existing value - it may not need to be + * changed. + */ + if (new_bits == 0) /* no change */ + zlib->window_bits = file_bits; + + else if (new_bits != file_bits) /* rewrite required */ + bIn = (png_byte)((bIn & 0xf) + ((new_bits-8) << 4)); + } + + zlib->header[0] = bIn; + zlib->state = state = 1; + break; + + case 1: /* second header byte */ + { + int b2 = bIn & 0xe0; /* top 3 bits */ + + /* The checksum calculation, on the first 11 bits: */ + b2 += 0x1f - ((zlib->header[0] << 8) + b2) % 0x1f; + + /* Update the checksum byte if required: */ + if (bIn != b2) + { + /* If the first byte wasn't changed this indicates an error in + * the checksum calculation; signal this by setting file_bits + * (not window_bits) to 0. + */ + if (zlib->file_bits == zlib->window_bits) + zlib->cksum = 1; + + bIn = (png_byte)b2; + } + } + + zlib->header[1] = bIn; + zlib->state = state = 2; + break; + + default: /* After the header bytes */ + break; + } + + /* For some streams, perhaps only those compressed with 'superfast + * compression' (which results in a lot of copying) Z_BUF_ERROR can happen + * immediately after all output has been flushed on the next input byte. + * This is handled below when Z_BUF_ERROR is detected by adding an output + * byte. + */ + zlib->z.next_in = &bIn; + zlib->z.avail_in = 1; + zlib->z.next_out = &bOut; + zlib->z.avail_out = 0; /* Initially */ + + /* Initially use Z_NO_FLUSH in an attempt to persuade zlib to look at this + * byte without confusing what is going on with output. + */ + flush = Z_NO_FLUSH; + out_bytes = 0; + + /* NOTE: expression 3 is only evaluted on 'continue', because of the + * 'break' at the end of this loop below. + */ + for (;endrc == ZLIB_OK; + flush = Z_SYNC_FLUSH, + zlib->z.next_out = &bOut, + zlib->z.avail_out = 1, + ++out_bytes) + { + zlib->rc = inflate(&zlib->z, flush); + out_bytes -= zlib->z.avail_out; + + switch (zlib->rc) + { + case Z_BUF_ERROR: + if (zlib->z.avail_out == 0) + continue; /* Try another output byte. */ + + if (zlib->z.avail_in == 0) + break; /* Try another input byte */ + + /* Both avail_out and avail_in are 1 yet zlib returned a code + * indicating no progress was possible. This is unexpected. + */ + zlib_message(zlib, 1/*unexpected*/); + endrc = ZLIB_FATAL; /* stop processing */ + break; + + case Z_OK: + /* Zlib is supposed to have made progress: */ + assert(zlib->z.avail_out == 0 || zlib->z.avail_in == 0); + continue; + + case Z_STREAM_END: + /* This is the successful end. */ + zlib->state = 3; /* end of stream */ + endrc = ZLIB_STREAM_END; + break; + + case Z_NEED_DICT: + zlib_message(zlib, 0/*stream error*/); + endrc = ZLIB_FATAL; + break; + + case Z_DATA_ERROR: + /* The too far back error can be corrected, others cannot: */ + if (zlib->z.msg != NULL && + strcmp(zlib->z.msg, "invalid distance too far back") == 0) + { + endrc = ZLIB_TOO_FAR_BACK; + break; + } + /* FALL THROUGH */ + + default: + zlib_message(zlib, 0/*stream error*/); + endrc = ZLIB_FATAL; + break; + } /* switch (inflate rc) */ + + /* Control gets here when further output is not possible; endrc may + * still be ZLIB_OK if more input is required. + */ + break; + } /* for (output bytes) */ + + /* Keep a running count of output byte produced: */ + zlib->uncompressed_digits = uarb_add32(zlib->uncompressed_bytes, + zlib->uncompressed_digits, out_bytes); + + /* Keep going, the loop will terminate when endrc is no longer set to + * ZLIB_OK or all the input bytes have been consumed; meanwhile keep + * adding input bytes. + */ + assert(zlib->z.avail_in == 0 || endrc != ZLIB_OK); + + in_bytes += 1 - zlib->z.avail_in; + } /* while (input bytes) */ + + assert(in_bytes == nbytes || endrc != ZLIB_OK); + + /* Update the running total of input bytes consumed */ + zlib->compressed_digits = uarb_add32(zlib->compressed_bytes, + zlib->compressed_digits, in_bytes - zlib->z.avail_in); + + /* At the end of the stream update the chunk with the accumulated + * information if it is an improvement: + */ + if (endrc == ZLIB_STREAM_END && zlib->window_bits < zlib->ok_bits) + { + struct chunk *chunk = zlib->chunk; + + chunk->uncompressed_digits = uarb_copy(chunk->uncompressed_bytes, + zlib->uncompressed_bytes, zlib->uncompressed_digits); + chunk->compressed_digits = uarb_copy(chunk->compressed_bytes, + zlib->compressed_bytes, zlib->compressed_digits); + chunk->rewrite_buffer[0] = zlib->header[0]; + chunk->rewrite_buffer[1] = zlib->header[1]; + + if (zlib->window_bits != zlib->file_bits || zlib->cksum) + { + /* A rewrite is required */ + chunk->rewrite_offset = zlib->rewrite_offset; + chunk->rewrite_length = 2; + } + + else + { + chunk->rewrite_offset = 0; + chunk->rewrite_length = 0; + } + + if (in_bytes < nbytes) + chunk_message(chunk, "extra compressed data"); + + zlib->extra_bytes = nbytes - in_bytes; + zlib->ok_bits = zlib->window_bits; + } + + return endrc; +} + +static int +zlib_run(struct zlib *zlib) + /* Like zlib_advance but also handles a stream of IDAT chunks. */ +{ + /* The 'extra_bytes' field is set by zlib_advance if there is extra + * compressed data in the chunk it handles (if it sees Z_STREAM_END before + * all the input data has been used.) This function uses the value to update + * the correct chunk length, so the problem should only ever be detected once + * for each chunk. zlib_advance outputs the error message, though see the + * IDAT specific check below. + */ + zlib->extra_bytes = 0; + + if (zlib->idat != NULL) + { + struct IDAT_list *list = zlib->idat->idat_list_head; + struct IDAT_list *last = zlib->idat->idat_list_tail; + int skip = 0; + + /* 'rewrite_offset' is the offset of the LZ data within the chunk, for + * IDAT it should be 0: + */ + assert(zlib->rewrite_offset == 0); + + /* Process each IDAT_list in turn; the caller has left the stream + * positioned at the start of the first IDAT chunk data. + */ + for (;;) + { + const unsigned int count = list->count; + unsigned int i; + + for (i = 0; i<count; ++i) + { + int rc; + + if (skip > 0) /* Skip CRC and next IDAT header */ + skip_12(zlib->file); + + skip = 12; /* for the next time */ + + rc = zlib_advance(zlib, list->lengths[i]); + + switch (rc) + { + case ZLIB_OK: /* keep going */ + break; + + case ZLIB_STREAM_END: /* stop */ + /* There may be extra chunks; if there are and one of them is + * not zero length output the 'extra data' message. Only do + * this check if errors are being output. + */ + if (zlib->global->errors && zlib->extra_bytes == 0) + { + struct IDAT_list *check = list; + int j = i+1, jcount = count; + + for (;;) + { + for (; j<jcount; ++j) + if (check->lengths[j] > 0) + { + chunk_message(zlib->chunk, + "extra compressed data"); + goto end_check; + } + + if (check == last) + break; + + check = check->next; + jcount = check->count; + j = 0; + } + } + + end_check: + /* Terminate the list at the current position, reducing the + * length of the last IDAT too if required. + */ + list->lengths[i] -= zlib->extra_bytes; + list->count = i+1; + zlib->idat->idat_list_tail = list; + /* FALL THROUGH */ + + default: + return rc; + } + } + + /* At the end of the compressed data and Z_STREAM_END was not seen. */ + if (list == last) + return ZLIB_OK; + + list = list->next; + } + } + + else + { + struct chunk *chunk = zlib->chunk; + int rc; + + assert(zlib->rewrite_offset < chunk->chunk_length); + + rc = zlib_advance(zlib, chunk->chunk_length - zlib->rewrite_offset); + + /* The extra bytes in the chunk are handled now by adjusting the chunk + * length to exclude them; the zlib data is always stored at the end of + * the PNG chunk (although clearly this is not necessary.) zlib_advance + * has already output a warning message. + */ + chunk->chunk_length -= zlib->extra_bytes; + return rc; + } +} + +static int /* global function; not a member function */ +zlib_check(struct file *file, png_uint_32 offset) + /* Check the stream of zlib compressed data in either idat (if given) or (if + * not) chunk. In fact it is zlib_run that handles the difference in reading + * a single chunk and a list of IDAT chunks. + * + * In either case the input file must be positioned at the first byte of zlib + * compressed data (the first header byte). + * + * The return value is true on success, including the case where the zlib + * header may need to be rewritten, and false on an unrecoverable error. + * + * In the case of IDAT chunks 'offset' should be 0. + */ +{ + fpos_t start_pos; + struct zlib zlib; + + /* Record the start of the LZ data to allow a re-read. */ + file_getpos(file, &start_pos); + + /* First test the existing (file) window bits: */ + if (zlib_init(&zlib, file->idat, file->chunk, 0/*window bits*/, offset)) + { + int min_bits, max_bits, rc; + + /* The first run using the existing window bits. */ + rc = zlib_run(&zlib); + + switch (rc) + { + case ZLIB_TOO_FAR_BACK: + /* too far back error */ + file->status_code |= TOO_FAR_BACK; + min_bits = zlib.window_bits + 1; + max_bits = 15; + break; + + case ZLIB_STREAM_END: + if (!zlib.global->optimize_zlib && + zlib.window_bits == zlib.file_bits && !zlib.cksum) + { + /* The trivial case where the stream is ok and optimization was + * not requested. + */ + zlib_end(&zlib); + return 1; + } + + max_bits = max_window_bits(zlib.uncompressed_bytes, + zlib.uncompressed_digits); + if (zlib.ok_bits < max_bits) + max_bits = zlib.ok_bits; + min_bits = 8; + + /* cksum is set if there is an error in the zlib header checksum + * calculation in the original file (and this may be the only reason + * a rewrite is required). We can't rely on the file window bits in + * this case, so do the optimization anyway. + */ + if (zlib.cksum) + chunk_message(zlib.chunk, "zlib checkum"); + break; + + + case ZLIB_OK: + /* Truncated stream; unrecoverable, gets converted to ZLIB_FATAL */ + zlib.z.msg = PNGZ_MSG_CAST("[truncated]"); + zlib_message(&zlib, 0/*expected*/); + /* FALL THROUGH */ + + default: + /* Unrecoverable error; skip the chunk; a zlib_message has already + * been output. + */ + zlib_end(&zlib); + return 0; + } + + /* Optimize window bits or fix a too-far-back error. min_bits and + * max_bits have been set appropriately, ok_bits records the bit value + * known to work. + */ + while (min_bits < max_bits || max_bits < zlib.ok_bits/*if 16*/) + { + int test_bits = (min_bits + max_bits) >> 1; + + if (zlib_reset(&zlib, test_bits)) + { + file_setpos(file, &start_pos); + rc = zlib_run(&zlib); + + switch (rc) + { + case ZLIB_TOO_FAR_BACK: + min_bits = test_bits+1; + if (min_bits > max_bits) + { + /* This happens when the stream really is damaged and it + * contains a distance code that addresses bytes before + * the start of the uncompressed data. + */ + assert(test_bits == 15); + + /* Output the error that wasn't output before: */ + if (zlib.z.msg == NULL) + zlib.z.msg = PNGZ_MSG_CAST( + "invalid distance too far back"); + zlib_message(&zlib, 0/*stream error*/); + zlib_end(&zlib); + return 0; + } + break; + + case ZLIB_STREAM_END: /* success */ + max_bits = test_bits; + break; + + default: + /* A fatal error; this happens if a too-far-back error was + * hiding a more serious error, zlib_advance has already + * output a zlib_message. + */ + zlib_end(&zlib); + return 0; + } + } + + else /* inflateReset2 failed */ + { + zlib_end(&zlib); + return 0; + } + } + + /* The loop guarantees this */ + assert(zlib.ok_bits == max_bits); + zlib_end(&zlib); + return 1; + } + + else /* zlib initialization failed - skip the chunk */ + { + zlib_end(&zlib); + return 0; + } +} + +/***************************** LIBPNG CALLBACKS *******************************/ +/* The strategy here is to run a regular libpng PNG file read but examine the + * input data (from the file) before passing it to libpng so as to be aware of + * the state we expect libpng to be in. Warning and error callbacks are also + * intercepted so that they can be quieted and interpreted. Interpretation + * depends on a somewhat risky string match for known error messages; let us + * hope that this can be fixed in the next version of libpng. + * + * The control structure is pointed to by the libpng error pointer. It contains + * that set of structures which must persist across multiple read callbacks, + * which is pretty much everything except the 'zlib' control structure. + * + * The file structure is instantiated in the caller of the per-file routine, but + * the per-file routine contains the chunk and IDAT control structures. + */ +/* The three routines read_chunk, process_chunk and sync_stream can only be + * called via a call to read_chunk and only exit at a return from process_chunk. + * These routines could have been written as one confusing large routine, + * instead this code relies on the compiler to do tail call elimination. The + * possible calls are as follows: + * + * read_chunk + * -> sync_stream + * -> process_chunk + * -> process_chunk + * -> read_chunk + * returns + */ +static void read_chunk(struct file *file); +static void +process_chunk(struct file *file, png_uint_32 file_crc, png_uint_32 next_length, + png_uint_32 next_type) + /* Called when the chunk data has been read, next_length and next_type + * will be set for the next chunk (or 0 if this is IEND). + * + * When this routine returns, chunk_length and chunk_type will be set for the + * next chunk to write because if a chunk is skipped this return calls back + * to read_chunk. + */ +{ + const png_uint_32 type = file->type; + + if (file->global->verbose > 1) + { + fputs(" ", stderr); + type_name(file->type, stderr); + fprintf(stderr, " %lu 0x%.8x 0x%.8x\n", (unsigned long)file->length, + file->crc ^ 0xffffffff, file_crc); + } + + /* The basic structure seems correct but the CRC may not match, in this + * case assume that it is simply a bad CRC, either wrongly calculated or + * because of damaged stream data. + */ + if ((file->crc ^ 0xffffffff) != file_crc) + { + /* The behavior is set by the 'skip' setting; if it is anything other + * than SKIP_BAD_CRC ignore the bad CRC and return the chunk, with a + * corrected CRC and possibly processed, to libpng. Otherwise skip the + * chunk, which will result in a fatal error if the chunk is critical. + */ + file->status_code |= CRC_ERROR; + + /* Ignore the bad CRC */ + if (file->global->skip != SKIP_BAD_CRC) + type_message(file, type, "bad CRC"); + + /* This will cause an IEND with a bad CRC to stop */ + else if (CRITICAL(type)) + stop(file, READ_ERROR_CODE, "bad CRC in critical chunk"); + + else + { + type_message(file, type, "skipped: bad CRC"); + + /* NOTE: this cannot be reached for IEND because it is critical. */ + goto skip_chunk; + } + } + + /* Check for other 'skip' cases and handle these; these only apply to + * ancillary chunks (and not tRNS, which should probably have been a critical + * chunk.) + */ + if (skip_chunk_type(file->global, type)) + goto skip_chunk; + + /* The chunk may still be skipped if problems are detected in the LZ data, + * however the LZ data check requires a chunk. Handle this by instantiating + * a chunk unless an IDAT is already instantiated (IDAT control structures + * instantiate their own chunk.) + */ + if (type != png_IDAT) + file->alloc(file, 0/*chunk*/); + + else if (file->idat == NULL) + file->alloc(file, 1/*IDAT*/); + + else + { + /* The chunk length must be updated for process_IDAT */ + assert(file->chunk != NULL); + assert(file->chunk->chunk_type == png_IDAT); + file->chunk->chunk_length = file->length; + } + + /* Record the 'next' information too, now that the original values for + * this chunk have been copied. Notice that the IDAT chunks only make a + * copy of the position of the first chunk, this is fine - process_IDAT does + * not need the position of this chunk. + */ + file->length = next_length; + file->type = next_type; + getpos(file); + + /* Do per-type processing, note that if this code does not return from the + * function the chunk will be skipped. The rewrite is cancelled here so that + * it can be set in the per-chunk processing. + */ + file->chunk->rewrite_length = 0; + file->chunk->rewrite_offset = 0; + switch (type) + { + default: + return; + + case png_IHDR: + /* Read this now and update the control structure with the information + * it contains. The header is validated completely to ensure this is a + * PNG. + */ + { + struct chunk *chunk = file->chunk; + + if (chunk->chunk_length != 13) + stop_invalid(file, "IHDR length"); + + /* Read all the IHDR information and validate it. */ + setpos(chunk); + file->width = reread_4(file); + file->height = reread_4(file); + file->bit_depth = reread_byte(file); + file->color_type = reread_byte(file); + file->compression_method = reread_byte(file); + file->filter_method = reread_byte(file); + file->interlace_method = reread_byte(file); + + /* This validates all the fields, and calls stop_invalid if + * there is a problem. + */ + calc_image_size(file); + } + return; + + /* Ancillary chunks that require further processing: */ + case png_zTXt: case png_iCCP: + if (process_zTXt_iCCP(file)) + return; + chunk_end(&file->chunk); + file_setpos(file, &file->data_pos); + break; + + case png_iTXt: + if (process_iTXt(file)) + return; + chunk_end(&file->chunk); + file_setpos(file, &file->data_pos); + break; + + case png_IDAT: + if (process_IDAT(file)) + return; + /* First pass: */ + assert(next_type == png_IDAT); + break; + } + + /* Control reaches this point if the chunk must be skipped. For chunks other + * than IDAT this means that the zlib compressed data is fatally damanged and + * the chunk will not be passed to libpng. For IDAT it means that the end of + * the IDAT stream has not yet been reached and we must handle the next + * (IDAT) chunk. If the LZ data in an IDAT stream cannot be read 'stop' must + * be used to halt parsing of the PNG. + */ + read_chunk(file); + return; + + /* This is the generic code to skip the current chunk; simply jump to the + * next one. + */ +skip_chunk: + file->length = next_length; + file->type = next_type; + getpos(file); + read_chunk(file); +} + +static png_uint_32 +get32(png_bytep buffer, int offset) + /* Read a 32-bit value from an 8-byte circular buffer (used only below). + */ +{ + return + (buffer[ offset & 7] << 24) + + (buffer[(offset+1) & 7] << 16) + + (buffer[(offset+2) & 7] << 8) + + (buffer[(offset+3) & 7] ); +} + +static void +sync_stream(struct file *file) + /* The stream seems to be messed up, attempt to resync from the current chunk + * header. Executes stop on a fatal error, otherwise calls process_chunk. + */ +{ + png_uint_32 file_crc; + + file->status_code |= STREAM_ERROR; + + if (file->global->verbose) + { + fputs(" SYNC ", stderr); + type_name(file->type, stderr); + putc('\n', stderr); + } + + /* Return to the start of the chunk data */ + file_setpos(file, &file->data_pos); + file->read_count = 8; + + if (read_4(file, &file_crc) == 4) /* else completely truncated */ + { + /* Ignore the recorded chunk length, proceed through the data looking for + * a leading sequence of bytes that match the CRC in the following four + * bytes. Each time a match is found check the next 8 bytes for a valid + * length, chunk-type pair. + */ + png_uint_32 length; + png_uint_32 type = file->type; + png_uint_32 crc = crc_init_4(type); + png_byte buffer[8]; + unsigned int nread = 0, nused = 0; + + for (length=0; length <= 0x7fffffff; ++length) + { + int ch; + + if ((crc ^ 0xffffffff) == file_crc) + { + /* A match on the CRC; for IEND this is sufficient, but for anything + * else expect a following chunk header. + */ + if (type == png_IEND) + { + file->length = length; + process_chunk(file, file_crc, 0, 0); + return; + } + + else + { + /* Need 8 bytes */ + while (nread < 8+nused) + { + ch = read_byte(file); + if (ch == EOF) + goto truncated; + buffer[(nread++) & 7] = (png_byte)ch; + } + + /* Prevent overflow */ + nread -= nused & ~7; + nused -= nused & ~7; /* or, nused &= 7 ;-) */ + + /* Examine the 8 bytes for a valid chunk header. */ + { + png_uint_32 next_length = get32(buffer, nused); + + if (next_length < 0x7fffffff) + { + png_uint_32 next_type = get32(buffer, nused+4); + + if (chunk_type_valid(next_type)) + { + file->read_count -= 8; + process_chunk(file, file_crc, next_length, next_type); + return; + } + } + + /* Not valid, keep going. */ + } + } + } + + /* This catches up with the circular buffer which gets filled above + * while checking a chunk header. This code is slightly tricky - if + * the chunk_type is IEND the buffer will never be used, if it is not + * the code will always read ahead exactly 8 bytes and pass this on to + * process_chunk. So the invariant that IEND leaves the file position + * after the IEND CRC and other chunk leave it after the *next* chunk + * header is not broken. + */ + if (nread <= nused) + { + ch = read_byte(file); + + if (ch == EOF) + goto truncated; + } + + else + ch = buffer[(++nused) & 7]; + + crc = crc_one_byte(crc, file_crc >> 24); + file_crc = (file_crc << 8) + ch; + } + + /* Control gets to here if when 0x7fffffff bytes (plus 8) have been read, + * ok, treat this as a damaged stream too: + */ + } + +truncated: + stop(file, READ_ERROR_CODE, "damaged PNG stream"); +} + +static void +read_chunk(struct file *file) + /* On entry file::data_pos must be set to the position of the first byte + * of the chunk data *and* the input file must be at this position. This + * routine (via process_chunk) instantiates a chunk or IDAT control structure + * based on file::length and file::type and also resets these fields and + * file::data_pos for the chunk after this one. For an IDAT chunk the whole + * stream of IDATs will be read, until something other than an IDAT is + * encountered, and the file fields will be set for the chunk after the end + * of the stream of IDATs. + * + * For IEND the file::type field will be set to 0, and nothing beyond the end + * of the IEND chunk will have been read. + */ +{ + png_uint_32 length = file->length; + png_uint_32 type = file->type; + + /* After IEND file::type is set to 0, if libpng attempts to read + * more data at this point this is a bug in libpng. + */ + if (type == 0) + stop(file, UNEXPECTED_ERROR_CODE, "read beyond IEND"); + + if (file->global->verbose > 2) + { + fputs(" ", stderr); + type_name(type, stderr); + fprintf(stderr, " %lu\n", (unsigned long)length); + } + + /* Start the read_crc calculation with the chunk type, then read to the end + * of the chunk data (without processing it in any way) to check that it is + * all there and calculate the CRC. + */ + file->crc = crc_init_4(type); + if (crc_read_many(file, length)) /* else it was truncated */ + { + png_uint_32 file_crc; /* CRC read from file */ + unsigned int nread = read_4(file, &file_crc); + + if (nread == 4) + { + if (type != png_IEND) /* do not read beyond IEND */ + { + png_uint_32 next_length; + + nread += read_4(file, &next_length); + if (nread == 8 && next_length <= 0x7fffffff) + { + png_uint_32 next_type; + + nread += read_4(file, &next_type); + + if (nread == 12 && chunk_type_valid(next_type)) + { + /* Adjust the read count back to the correct value for this + * chunk. + */ + file->read_count -= 8; + process_chunk(file, file_crc, next_length, next_type); + return; + } + } + } + + else /* IEND */ + { + process_chunk(file, file_crc, 0, 0); + return; + } + } + } + + /* Control gets to here if the the stream seems invalid or damaged in some + * way. Either there was a problem reading all the expected data (this + * chunk's data, its CRC and the length and type of the next chunk) or the + * next chunk length/type are invalid. Notice that the cases that end up + * here all correspond to cases that would otherwise terminate the read of + * the PNG file. + */ + sync_stream(file); +} + +/* This returns a file* from a png_struct in an implementation specific way. */ +static struct file *get_control(png_const_structrp png_ptr); + +static void PNGCBAPI +error_handler(png_structp png_ptr, png_const_charp message) +{ + stop(get_control(png_ptr), LIBPNG_ERROR_CODE, message); +} + +static void PNGCBAPI +warning_handler(png_structp png_ptr, png_const_charp message) +{ + struct file *file = get_control(png_ptr); + + if (file->global->warnings) + emit_error(file, LIBPNG_WARNING_CODE, message); +} + +/* Read callback - this is where the work gets done to check the stream before + * passing it to libpng + */ +static void PNGCBAPI +read_callback(png_structp png_ptr, png_bytep buffer, size_t count) + /* Return 'count' bytes to libpng in 'buffer' */ +{ + struct file *file = get_control(png_ptr); + png_uint_32 type, length; /* For the chunk be *WRITTEN* */ + struct chunk *chunk; + + /* libpng should always ask for at least one byte */ + if (count == 0) + stop(file, UNEXPECTED_ERROR_CODE, "read callback for 0 bytes"); + + /* The callback always reads ahead by 8 bytes - the signature or chunk header + * - these bytes are stored in chunk_length and chunk_type. This block is + * executed once for the signature and once for the first chunk right at the + * start. + */ + if (file->read_count < 8) + { + assert(file->read_count == 0); + assert((file->status_code & TRUNCATED) == 0); + + (void)read_4(file, &file->length); + + if (file->read_count == 4) + (void)read_4(file, &file->type); + + if (file->read_count < 8) + { + assert((file->status_code & TRUNCATED) != 0); + stop(file, READ_ERROR_CODE, "not a PNG (too short)"); + } + + if (file->state == STATE_SIGNATURE) + { + if (file->length != sig1 || file->type != sig2) + stop(file, LIBPNG_ERROR_CODE, "not a PNG (signature)"); + + /* Else write it (this is the initialization of write_count, prior to + * this it contains CLEAR garbage.) + */ + file->write_count = 0; + } + + else + { + assert(file->state == STATE_CHUNKS); + + /* The first chunk must be a well formed IHDR (this could be relaxed to + * use the checks in process_chunk, but that seems unnecessary.) + */ + if (file->length != 13 || file->type != png_IHDR) + stop(file, LIBPNG_ERROR_CODE, "not a PNG (IHDR)"); + + /* The position of the data must be stored too */ + getpos(file); + } + } + + /* Retrieve previous state (because the read callbacks are made pretty much + * byte-by-byte in the sequential reader prior to 1.7). + */ + chunk = file->chunk; + + if (chunk != NULL) + { + length = chunk->chunk_length; + type = chunk->chunk_type; + } + + else + { + /* This is the signature case; for IDAT and other chunks these values will + * be overwritten when read_chunk is called below. + */ + length = file->length; + type = file->type; + } + + do + { + png_uint_32 b; + + /* Complete the read of a chunk; as a side effect this also instantiates + * a chunk control structure and sets the file length/type/data_pos fields + * for the *NEXT* chunk header. + * + * NOTE: at an IDAT any following IDAT chunks will also be read and the + * next_ fields will refer to the chunk after the last IDAT. + * + * NOTE: read_chunk only returns when it has read a chunk that must now be + * written. + */ + if (file->state != STATE_SIGNATURE && chunk == NULL) + { + assert(file->read_count == 8); + assert(file->idat == NULL); + read_chunk(file); + chunk = file->chunk; + assert(chunk != NULL); + + /* Do the initialization that was not done before. */ + length = chunk->chunk_length; + type = chunk->chunk_type; + + /* And start writing the new chunk. */ + file->write_count = 0; + } + + /* The chunk_ fields describe a chunk that must be written, or hold the + * signature. Write the header first. In the signature case this + * rewrites the signature. + */ + switch (file->write_count) + { + case 0: b = length >> 24; break; + case 1: b = length >> 16; break; + case 2: b = length >> 8; break; + case 3: b = length ; break; + + case 4: b = type >> 24; break; + case 5: b = type >> 16; break; + case 6: b = type >> 8; break; + case 7: b = type ; break; + + case 8: + /* The header has been written. If this is really the signature + * that's all that is required and we can go to normal chunk + * processing. + */ + if (file->state == STATE_SIGNATURE) + { + /* The signature has been written, the tail call to read_callback + * below (it's just a goto to the start with a decent compiler) + * will read the IHDR header ahead and validate it. + */ + assert(length == sig1 && type == sig2); + file->read_count = 0; /* Forces a header read */ + file->state = STATE_CHUNKS; /* IHDR: checked above */ + read_callback(png_ptr, buffer, count); + return; + } + + else + { + assert(chunk != NULL); + + /* Set up for write, notice that repositioning the input stream + * is only necessary if something is to be read from it. Also + * notice that for the IDAT stream this must only happen once - + * on the first IDAT - to get back to the start of the list and + * this is done inside process_IDAT: + */ + chunk->write_crc = crc_init_4(type); + if (file->state != STATE_IDAT && length > 0) + setpos(chunk); + } + /* FALL THROUGH */ + + default: + assert(chunk != NULL); + + /* NOTE: the arithmetic below overflows and gives a large positive + * png_uint_32 value until the whole chunk data has been written. + */ + switch (file->write_count - length) + { + /* Write the chunk data, normally this just comes from + * the file. The only exception is for that part of a + * chunk which is zlib data and which must be rewritten, + * and IDAT chunks which can be completely + * reconstructed. + */ + default: + if (file->state == STATE_IDAT) + { + struct IDAT *idat = file->idat; + + assert(idat != NULL); + + /* Read an IDAT byte from the input stream of IDAT chunks. + * Because the IDAT stream can be re-chunked this stream is + * held in the struct IDAT members. The chunk members, in + * particular chunk_length (and therefore the length local) + * refer to the output chunk. + */ + while (idat->idat_index >= idat->idat_length) + { + /* Advance one chunk */ + struct IDAT_list *cur = idat->idat_cur; + + assert(idat->idat_index == idat->idat_length); + assert(cur != NULL && cur->count > 0); + + /* NOTE: IDAT_list::count here, not IDAT_list::length */ + if (++(idat->idat_count) >= cur->count) + { + assert(idat->idat_count == cur->count); + + /* Move on to the next IDAT_list: */ + cur = cur->next; + + /* This is an internal error - read beyond the end of + * the pre-calculated stream. + */ + if (cur == NULL || cur->count == 0) + stop(file, UNEXPECTED_ERROR_CODE, + "read beyond end of IDAT"); + + idat->idat_count = 0; + idat->idat_cur = cur; + } + + idat->idat_index = 0; + /* Zero length IDAT chunks are permitted, so the length + * here may be 0. + */ + idat->idat_length = cur->lengths[idat->idat_count]; + + /* And skip 12 bytes to the next chunk data */ + skip_12(file); + } + + /* The index is always that of the next byte, the rest of + * the information is always the current IDAT chunk and the + * current list. + */ + ++(idat->idat_index); + } + + /* Read the byte from the stream. */ + b = reread_byte(file); + + /* If the byte must be rewritten handle that here */ + if (chunk->rewrite_length > 0) + { + if (chunk->rewrite_offset > 0) + --(chunk->rewrite_offset); + + else + { + b = chunk->rewrite_buffer[0]; + memmove(chunk->rewrite_buffer, chunk->rewrite_buffer+1, + (sizeof chunk->rewrite_buffer)- + (sizeof chunk->rewrite_buffer[0])); + + --(chunk->rewrite_length); + } + } + + chunk->write_crc = crc_one_byte(chunk->write_crc, b); + break; + + /* The CRC is written at: + * + * chunk_write == chunk_length+8..chunk_length+11 + * + * so 8 to 11. The CRC is not (yet) conditioned. + */ + case 8: b = chunk->write_crc >> 24; goto write_crc; + case 9: b = chunk->write_crc >> 16; goto write_crc; + case 10: b = chunk->write_crc >> 8; goto write_crc; + case 11: + /* This must happen before the chunk_end below: */ + b = chunk->write_crc; + + if (file->global->verbose > 2) + { + fputs(" ", stderr); + type_name(type, stderr); + fprintf(stderr, " %lu 0x%.8x\n", (unsigned long)length, + chunk->write_crc ^ 0xffffffff); + } + + /* The IDAT stream is written without a call to read_chunk + * until the end is reached. rechunk_length() calculates the + * length of the output chunks. Control gets to this point at + * the end of an *output* chunk - the length calculated by + * rechunk_length. If this corresponds to the end of the + * input stream stop writing IDAT chunks, otherwise continue. + */ + if (file->state == STATE_IDAT && + (file->idat->idat_index < file->idat->idat_length || + 1+file->idat->idat_count < file->idat->idat_cur->count || + file->idat->idat_cur != file->idat->idat_list_tail)) + { + /* Write another IDAT chunk. Call rechunk_length to + * calculate the length required. + */ + length = chunk->chunk_length = rechunk_length(file->idat); + assert(type == png_IDAT); + file->write_count = 0; /* for the new chunk */ + --(file->write_count); /* fake out the increment below */ + } + + else + { + /* Entered at the end of a non-IDAT chunk and at the end of + * the IDAT stream. The rewrite should have been cleared. + */ + if (chunk->rewrite_length > 0 || chunk->rewrite_offset > 0) + stop(file, UNEXPECTED_ERROR_CODE, "pending rewrite"); + + /* This is the last byte so reset chunk_read for the next + * chunk and move the input file to the position after the + * *next* chunk header if required. + */ + file->read_count = 8; + file_setpos(file, &file->data_pos); + + if (file->idat == NULL) + chunk_end(&file->chunk); + + else + IDAT_end(&file->idat); + } + + write_crc: + b ^= 0xff; /* conditioning */ + break; + } + break; + } + + /* Write one byte */ + b &= 0xff; + *buffer++ = (png_byte)b; + --count; + write_byte(file, (png_byte)b); /* increments chunk_write */ + } + while (count > 0); +} + +/* Bundle the file and an uninitialized chunk and IDAT control structure + * together to allow implementation of the chunk/IDAT allocate routine. + */ +struct control +{ + struct file file; + struct chunk chunk; + struct IDAT idat; +}; + +static int +control_end(struct control *control) +{ + return file_end(&control->file); +} + +static struct file * +get_control(png_const_structrp png_ptr) +{ + /* This just returns the (file*). The chunk and idat control structures + * don't always exist. + */ + struct control *control = voidcast(struct control*, + png_get_error_ptr(png_ptr)); + return &control->file; +} + +static void +allocate(struct file *file, int allocate_idat) +{ + struct control *control = voidcast(struct control*, file->alloc_ptr); + + if (allocate_idat) + { + assert(file->idat == NULL); + IDAT_init(&control->idat, file); + } + + else /* chunk */ + { + assert(file->chunk == NULL); + chunk_init(&control->chunk, file); + } +} + +static int +control_init(struct control *control, struct global *global, + const char *file_name, const char *out_name) + /* This wraps file_init(&control::file) and simply returns the result from + * file_init. + */ +{ + return file_init(&control->file, global, file_name, out_name, control, + allocate); +} + +static int +read_png(struct control *control) + /* Read a PNG, return 0 on success else an error (status) code; a bit mask as + * defined for file::status_code as above. + */ +{ + png_structp png_ptr; + png_infop info_ptr = NULL; + volatile int rc; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, control, + error_handler, warning_handler); + + if (png_ptr == NULL) + { + /* This is not really expected. */ + log_error(&control->file, LIBPNG_ERROR_CODE, "OOM allocating png_struct"); + control->file.status_code |= INTERNAL_ERROR; + return LIBPNG_ERROR_CODE; + } + + rc = setjmp(control->file.jmpbuf); + if (rc == 0) + { +# ifdef PNG_SET_USER_LIMITS_SUPPORTED + /* Remove any limits on the size of PNG files that can be read, + * without this we may reject files based on built-in safety + * limits. + */ + png_set_user_limits(png_ptr, 0x7fffffff, 0x7fffffff); + png_set_chunk_cache_max(png_ptr, 0); + png_set_chunk_malloc_max(png_ptr, 0); +# endif + + png_set_read_fn(png_ptr, control, read_callback); + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + png_error(png_ptr, "OOM allocating info structure"); + + if (control->file.global->verbose) + fprintf(stderr, " INFO\n"); + + png_read_info(png_ptr, info_ptr); + + { + png_uint_32 height = png_get_image_height(png_ptr, info_ptr); + int passes = png_set_interlace_handling(png_ptr); + int pass; + + png_start_read_image(png_ptr); + + for (pass = 0; pass < passes; ++pass) + { + png_uint_32 y = height; + + /* NOTE: this skips asking libpng to return either version of + * the image row, but libpng still reads the rows. + */ + while (y-- > 0) + png_read_row(png_ptr, NULL, NULL); + } + } + + if (control->file.global->verbose) + fprintf(stderr, " END\n"); + + /* Make sure to read to the end of the file: */ + png_read_end(png_ptr, info_ptr); + } + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return rc; +} + +static int +one_file(struct global *global, const char *file_name, const char *out_name) +{ + int rc; + struct control control; + + if (global->verbose) + fprintf(stderr, "FILE %s -> %s\n", file_name, + out_name ? out_name : "<none>"); + + /* Although control_init can return a failure code the structure is always + * initialized, so control_end can be used to accumulate any status codes. + */ + rc = control_init(&control, global, file_name, out_name); + + if (rc == 0) + rc = read_png(&control); + + rc |= control_end(&control); + + return rc; +} + +static void +usage(const char *prog) +{ + /* ANSI C-90 limits strings to 509 characters, so use a string array: */ + size_t i; + static const char *usage_string[] = { +" Tests, optimizes and optionally fixes the zlib header in PNG files.", +" Optionally, when fixing, strips ancilliary chunks from the file.", +0, +"OPTIONS", +" OPERATION", +" By default files are just checked for readability with a summary of the", +" of zlib issues founds for each compressed chunk and the IDAT stream in", +" the file.", +" --optimize (-o):", +" Find the smallest deflate window size for the compressed data.", +" --strip=[none|crc|unsafe|unused|transform|color|all]:", +" none (default): Retain all chunks.", +" crc: Remove chunks with a bad CRC.", +" unsafe: Remove chunks that may be unsafe to retain if the image data", +" is modified. This is set automatically if --max is given but", +" may be cancelled by a later --strip=none.", +" unused: Remove chunks not used by libpng when decoding an image.", +" This retains any chunks that might be used by libpng image", +" transformations.", +" transform: unused+bKGD.", +" color: transform+iCCP and cHRM.", +" all: color+gAMA and sRGB.", +" Only ancillary chunks are ever removed. In addition the tRNS and sBIT", +" chunks are never removed as they affect exact interpretation of the", +" image pixel values. The following known chunks are treated specially", +" by the above options:", +" gAMA, sRGB [all]: These specify the gamma encoding used for the pixel", +" values.", +" cHRM, iCCP [color]: These specify how colors are encoded. iCCP also", +" specifies the exact encoding of a pixel value; however, in", +" practice most programs will ignore it.", +" bKGD [transform]: This is used by libpng transforms." +" --max=<number>:", +" Use IDAT chunks sized <number>. If no number is given the the IDAT", +" chunks will be the maximum size permitted; 2^31-1 bytes. If the option", +" is omitted the original chunk sizes will not be changed. When the", +" option is given --strip=unsafe is set automatically. This may be", +" cancelled if you know that all unknown unsafe-to-copy chunks really are", +" safe to copy across an IDAT size change. This is true of all chunks", +" that have ever been formally proposed as PNG extensions.", +" MESSAGES", +" By default the program only outputs summaries for each file.", +" --quiet (-q):", +" Do not output the summaries except for files that cannot be read. With", +" two --quiets these are not output either.", +" --errors (-e):", +" Output errors from libpng and the program (except too-far-back).", +" --warnings (-w):", +" Output warnings from libpng.", +" OUTPUT", +" By default nothing is written.", +" --out=<file>:", +" Write the optimized/corrected version of the next PNG to <file>. This", +" overrides the following two options", +" --suffix=<suffix>:", +" Set --out=<name><suffix> for all following files unless overridden on", +" a per-file basis by explicit --out.", +" --prefix=<prefix>:", +" Set --out=<prefix><name> for all the following files unless overridden", +" on a per-file basis by explicit --out.", +" These two options can be used together to produce a suffix and prefix.", +" INTERNAL OPTIONS", +#if 0 /*NYI*/ +#ifdef PNG_MAXIMUM_INFLATE_WINDOW +" --test:", +" Test the PNG_MAXIMUM_INFLATE_WINDOW option. Setting this disables", +" output as this would produce a broken file.", +#endif +#endif +0, +"EXIT CODES", +" *** SUBJECT TO CHANGE ***", +" The program exit code is value in the range 0..127 holding a bit mask of", +" the following codes. Notice that the results for each file are combined", +" together - check one file at a time to get a meaningful error code!", +" 0x01: The zlib too-far-back error existed in at least one chunk.", +" 0x02: At least one chunk had a CRC error.", +" 0x04: A chunk length was incorrect.", +" 0x08: The file was truncated.", +" Errors less than 16 are potentially recoverable, for a single file if the", +" exit code is less than 16 the file could be read (with corrections if a", +" non-zero code is returned).", +" 0x10: The file could not be read, even with corrections.", +" 0x20: The output file could not be written.", +" 0x40: An unexpected, potentially internal, error occurred.", +" If the command line arguments are incorrect the program exits with exit", +" 255. Some older operating systems only support 7-bit exit codes, on those", +" systems it is suggested that this program is first tested by supplying", +" invalid arguments.", +0, +"DESCRIPTION", +" " PROGRAM_NAME ":", +" checks each PNG file on the command line for errors. By default errors are", +" not output and the program just returns an exit code and prints a summary.", +" With the --quiet (-q) option the summaries are suppressed too and the", +" program only outputs unexpected errors (internal errors and file open", +" errors).", +" Various known problems in PNG files are fixed while the file is being read", +" The exit code says what problems were fixed. In particular the zlib error:", +0, +" \"invalid distance too far back\"", +0, +" caused by an incorrect optimization of a zlib stream is fixed in any", +" compressed chunk in which it is encountered. An integrity problem of the", +" PNG stream caused by a bug in libpng which wrote an incorrect chunk length", +" is also fixed. Chunk CRC errors are automatically fixed up.", +0, +" Setting one of the \"OUTPUT\" options causes the possibly modified file to", +" be written to a new file.", +0, +" Notice that some PNG files with the zlib optimization problem can still be", +" read by libpng under some circumstances. This program will still detect", +" and, if requested, correct the error.", +0, +" The program will reliably process all files on the command line unless", +" either an invalid argument causes the usage message (this message) to be", +" produced or the program crashes.", +0, +" The summary lines describe issues encountered with the zlib compressed", +" stream of a chunk. They have the following format, which is SUBJECT TO", +" CHANGE in the future:", +0, +" chunk reason comp-level p1 p2 p3 p4 file", +0, +" p1 through p4 vary according to the 'reason'. There are always 8 space", +" separated fields. Reasons specific formats are:", +0, +" chunk ERR status code read-errno write-errno message file", +" chunk SKP comp-level file-bits zlib-rc compressed message file", +" chunk ??? comp-level file-bits ok-bits compressed uncompress file", +0, +" The various fields are", +0, +"$1 chunk: The chunk type of a chunk in the file or 'HEAD' if a problem", +" is reported by libpng at the start of the IDAT stream.", +"$2 reason: One of:", +" CHK: A zlib header checksum was detected and fixed.", +" TFB: The zlib too far back error was detected and fixed.", +" OK : No errors were detected in the zlib stream and optimization", +" was not requested, or was not possible.", +" OPT: The zlib stream window bits value could be improved (and was).", +" SKP: The chunk was skipped because of a zlib issue (zlib-rc) with", +" explanation 'message'", +" ERR: The read of the file was aborted. The parameters explain why.", +"$3 status: For 'ERR' the accumulated status code from 'EXIT CODES' above.", +" This is printed as a 2 digit hexadecimal value", +" comp-level: The recorded compression level (FLEVEL) of a zlib stream", +" expressed as a string {supfast,stdfast,default,maximum}", +"$4 code: The file exit code; where stop was called, as a fairly terse", +" string {warning,libpng,zlib,invalid,read,write,unexpected}.", +" file-bits: The zlib window bits recorded in the file.", +"$5 read-errno: A system errno value from a read translated by strerror(3).", +" zlib-rc: A zlib return code as a string (see zlib.h).", +" ok-bits: The smallest zlib window bits value that works.", +"$6 write-errno:A system errno value from a write translated by strerror(3).", +" compressed: The count of compressed bytes in the zlib stream, when the", +" reason is 'SKP'; this is a count of the bytes read from the", +" stream when the fatal error was encountered.", +"$7 message: An error message (spaces replaced by _, as in all parameters),", +" uncompress: The count of bytes from uncompressing the zlib stream; this", +" may not be the same as the number of bytes in the image.", +"$8 file: The name of the file (this may contain spaces).", +}; + + fprintf(stderr, "Usage: %s {[options] png-file}\n", prog); + + for (i=0; i < (sizeof usage_string)/(sizeof usage_string[0]); ++i) + { + if (usage_string[i] != 0) + fputs(usage_string[i], stderr); + + fputc('\n', stderr); + } + + exit(255); +} + +int +main(int argc, const char **argv) +{ + char temp_name[FILENAME_MAX+1]; + const char * prog = *argv; + const char * outfile = NULL; + const char * suffix = NULL; + const char * prefix = NULL; + int done = 0; /* if at least one file is processed */ + struct global global; + + global_init(&global); + + while (--argc > 0) + { + ++argv; + + if (strcmp(*argv, "--debug") == 0) + { + /* To help debugging problems: */ + global.errors = global.warnings = 1; + global.quiet = 0; + global.verbose = 7; + } + + else if (strncmp(*argv, "--max=", 6) == 0) + { + global.idat_max = (png_uint_32)atol(6+*argv); + + if (global.skip < SKIP_UNSAFE) + global.skip = SKIP_UNSAFE; + } + + else if (strcmp(*argv, "--max") == 0) + { + global.idat_max = 0x7fffffff; + + if (global.skip < SKIP_UNSAFE) + global.skip = SKIP_UNSAFE; + } + + else if (strcmp(*argv, "--optimize") == 0 || strcmp(*argv, "-o") == 0) + global.optimize_zlib = 1; + + else if (strncmp(*argv, "--out=", 6) == 0) + outfile = 6+*argv; + + else if (strncmp(*argv, "--suffix=", 9) == 0) + suffix = 9+*argv; + + else if (strncmp(*argv, "--prefix=", 9) == 0) + prefix = 9+*argv; + + else if (strcmp(*argv, "--strip=none") == 0) + global.skip = SKIP_NONE; + + else if (strcmp(*argv, "--strip=crc") == 0) + global.skip = SKIP_BAD_CRC; + + else if (strcmp(*argv, "--strip=unsafe") == 0) + global.skip = SKIP_UNSAFE; + + else if (strcmp(*argv, "--strip=unused") == 0) + global.skip = SKIP_UNUSED; + + else if (strcmp(*argv, "--strip=transform") == 0) + global.skip = SKIP_TRANSFORM; + + else if (strcmp(*argv, "--strip=color") == 0) + global.skip = SKIP_COLOR; + + else if (strcmp(*argv, "--strip=all") == 0) + global.skip = SKIP_ALL; + + else if (strcmp(*argv, "--errors") == 0 || strcmp(*argv, "-e") == 0) + global.errors = 1; + + else if (strcmp(*argv, "--warnings") == 0 || strcmp(*argv, "-w") == 0) + global.warnings = 1; + + else if (strcmp(*argv, "--quiet") == 0 || strcmp(*argv, "-q") == 0) + { + if (global.quiet) + global.quiet = 2; + + else + global.quiet = 1; + } + + else if (strcmp(*argv, "--verbose") == 0 || strcmp(*argv, "-v") == 0) + ++global.verbose; + +#if 0 + /* NYI */ +# ifdef PNG_MAXIMUM_INFLATE_WINDOW + else if (strcmp(*argv, "--test") == 0) + ++set_option; +# endif +#endif + + else if ((*argv)[0] == '-') + usage(prog); + + else + { + size_t outlen = strlen(*argv); + + if (outfile == NULL) /* else this takes precedence */ + { + /* Consider the prefix/suffix options */ + if (prefix != NULL) + { + size_t prefixlen = strlen(prefix); + + if (prefixlen+outlen > FILENAME_MAX) + { + fprintf(stderr, "%s: output file name too long: %s%s%s\n", + prog, prefix, *argv, suffix ? suffix : ""); + global.status_code |= WRITE_ERROR; + continue; + } + + memcpy(temp_name, prefix, prefixlen); + memcpy(temp_name+prefixlen, *argv, outlen); + outlen += prefixlen; + outfile = temp_name; + } + + else if (suffix != NULL) + memcpy(temp_name, *argv, outlen); + + temp_name[outlen] = 0; + + if (suffix != NULL) + { + size_t suffixlen = strlen(suffix); + + if (outlen+suffixlen > FILENAME_MAX) + { + fprintf(stderr, "%s: output file name too long: %s%s\n", + prog, *argv, suffix); + global.status_code |= WRITE_ERROR; + continue; + } + + memcpy(temp_name+outlen, suffix, suffixlen); + outlen += suffixlen; + temp_name[outlen] = 0; + outfile = temp_name; + } + } + + (void)one_file(&global, *argv, outfile); + ++done; + outfile = NULL; + } + } + + if (!done) + usage(prog); + + return global_end(&global); +} + +#else /* ZLIB_VERNUM < 0x1240 */ +int +main(void) +{ + fprintf(stderr, + "pngfix needs libpng with a zlib >=1.2.4 (not 0x%x)\n", + ZLIB_VERNUM); + return 77; +} +#endif /* ZLIB_VERNUM */ + +#else /* No read support */ + +int +main(void) +{ + fprintf(stderr, "pngfix does not work without read support\n"); + return 77; +} +#endif /* PNG_READ_SUPPORTED && PNG_EASY_ACCESS_SUPPORTED */ +#else /* No setjmp support */ +int +main(void) +{ + fprintf(stderr, "pngfix does not work without setjmp support\n"); + return 77; +} +#endif /* PNG_SETJMP_SUPPORTED */ + diff --git a/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/sRGB.h b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/sRGB.h new file mode 100644 index 00000000000..22c8f7c0e3d --- /dev/null +++ b/Build/source/libs/libpng/libpng-1.6.18/contrib/tools/sRGB.h @@ -0,0 +1,48 @@ +/*- + * sRGB.h + * + * Last changed in libpng 1.6.0 [February 14, 2013] + * + * COPYRIGHT: Written by John Cunningham Bowler, 2013. + * To the extent possible under law, the author has waived all copyright and + * related or neighboring rights to this work. This work is published from: + * United States. + * + * Utility file; not actually a header, this contains definitions of sRGB + * calculation functions for inclusion in those test programs that need them. + * + * All routines take and return a floating point value in the range + * 0 to 1.0, doing a calculation according to the sRGB specification + * (in fact the source of the numbers is the wikipedia article at + * http://en.wikipedia.org/wiki/SRGB). + */ +static double +sRGB_from_linear(double l) +{ + if (l <= 0.0031308) + l *= 12.92; + + else + l = 1.055 * pow(l, 1/2.4) - 0.055; + + return l; +} + +static double +linear_from_sRGB(double s) +{ + if (s <= 0.04045) + return s / 12.92; + + else + return pow((s+0.055)/1.055, 2.4); +} + +static double +YfromRGB(double r, double g, double b) +{ + /* Use the sRGB (rounded) coefficients for Rlinear, Glinear, Blinear to get + * the CIE Y value (also linear). + */ + return 0.2126 * r + 0.7152 * g + 0.0722 * b; +} |