From ebc4c9db72653f00f410795635eaae2f52a91cd4 Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Thu, 16 Feb 2006 17:47:00 -0600 Subject: [PATCH] Imported from pngcrush-1.6.2.tar --- ChangeLog.txt | 355 ++ INSTALL.txt | 27 - Makefile | 73 + Makefile.ext-zlib | 72 + Makefile.gcc | 55 - Makefile.msc | 57 - Makefile.solaris | 70 + README.txt | 321 -- adler32.c | 147 +- cexcept.h | 115 +- compress.c | 15 +- crc32.c | 489 ++- crc32.h | 441 +++ deflate.c | 740 +++- deflate.h | 33 +- example.c | 565 +++ gzio.c | 551 +-- infback.c | 623 ++++ infblock.c | 398 -- infblock.h | 39 - infcodes.c | 257 -- infcodes.h | 27 - inffast.c | 454 ++- inffast.h | 12 +- inffixed.h | 241 +- inflate.c | 1695 +++++++-- inflate.h | 115 + inftrees.c | 692 ++-- inftrees.h | 87 +- infutil.c | 87 - infutil.h | 98 - minigzip.c | 322 ++ png.c | 91 +- png.h | 215 +- pngconf.h | 205 +- pngcrush.c | 8786 +++++++++++++++++++++++---------------------- pngcrush.h | 148 + pngerror.c | 46 +- pnggccrd.c | 51 +- pngget.c | 53 +- pngmem.c | 101 +- pngpread.c | 103 +- pngread.c | 128 +- pngrio.c | 4 +- pngrtran.c | 134 +- pngrutil.c | 254 +- pngset.c | 161 +- pngtest.c | 1554 ++++++++ pngtrans.c | 40 +- pngvcrd.c | 70 +- pngwio.c | 4 +- pngwrite.c | 70 +- pngwtran.c | 26 +- pngwutil.c | 109 +- trees.c | 117 +- uncompr.c | 9 +- zconf.h | 287 +- zconf.in.h | 332 ++ zlib.h | 676 +++- zutil.c | 132 +- zutil.h | 121 +- 61 files changed, 14984 insertions(+), 8316 deletions(-) create mode 100644 ChangeLog.txt delete mode 100644 INSTALL.txt create mode 100644 Makefile create mode 100644 Makefile.ext-zlib delete mode 100644 Makefile.gcc delete mode 100644 Makefile.msc create mode 100644 Makefile.solaris delete mode 100644 README.txt create mode 100644 crc32.h create mode 100644 example.c create mode 100644 infback.c delete mode 100644 infblock.c delete mode 100644 infblock.h delete mode 100644 infcodes.c delete mode 100644 infcodes.h create mode 100644 inflate.h delete mode 100644 infutil.c delete mode 100644 infutil.h create mode 100644 minigzip.c create mode 100644 pngtest.c create mode 100644 zconf.in.h diff --git a/ChangeLog.txt b/ChangeLog.txt new file mode 100644 index 000000000..2266feaac --- /dev/null +++ b/ChangeLog.txt @@ -0,0 +1,355 @@ +Change log: + +Version 1.6.2 (built with libpng-1.2.8 and zlib-1.2.3) + + Fixed bug with "PNG_ROWBYTES" usage, introduced in version 1.6.0. + The bug could cause a crash and only affects the "nolib" builds. + + Converted C++ style (// ...) comments to C style (/* ... */). + + Defined TOO_FAR == 32767 in deflate.c (again). The definition was + omitted from version 1.6.0 when zlib was upgraded to version 1.2.3. + +Version 1.6.1 (distributed as 1.6.0, built with libpng-1.2.8 and zlib-1.2.3) + + Copied non-exported libpng functions from libpng into pngcrush, to make + pngcrush play more nicely with shared libpng. These are #ifdef'ed out + when a static library is being built with the bundled libpng and + pngcrush.h is included. + +Version 1.6.0-grr (built with libpng-1.2.4 and zlib-1.1.4pc or zlib-1.2.2) + + Moved ChangeLog out of pngcrush.c comments and into a separate file. + + Filtered pngcrush.c through "indent -kr" and "expand" for readability. + + Moved 550 lines of usage/help/copyright/license/version info to separate + function(s) and cleaned up significantly. + + Added some comments for ease of navigation and readability. + + Stripped out a bunch of ancient-libpng compatibility stuff. + + Defined PNG_UINT_* macros (pngcrush.h for now). + + Fixed unknown-chunk handling ("-rem alla" and "-rem gifx" now work). + + Created modified version of makefile that supports external zlib. + + Added support for methods using Z_RLE zlib strategy (zlib 1.2.x only). + + Documented -huffman option in usage screen. + + Added IDAT statistics to final per-file summary. + + Added utime() support to give output files same timestamps as input files. + +Version 1.5.10 (built with libpng-1.2.4 and zlib-1.1.4pc) + + Fixed bug, introduced in 1.5.9, that caused defaults for method 0 to + be used instead of copying the original image, when the original was + already smallest. + +Version 1.5.9 (built with libpng-1.2.4beta3 and zlib-1.1.4pc) + + Work around CPU timer wraparound at 2G microseconds. + + Upgraded zlib from 1.1.3 to 1.1.4. Pngcrush is believed not to + be vulnerable to the zlib-1.1.3 buffer-overflow bug. + + Choose the first instance of smallest IDAT instead of the last, + for faster final recompression, suggested by TSamuel. + +Version 1.5.8 (built with libpng-1.2.1) + + Added -trns_a option for entering a tRNS array. + +Version 1.5.7 (built with libpng-1.2.0) + + Added setargv.obj to Makefile.msc to expand wildcards, e.g., *.png + + Use constant string "pngcrush" instead of argv[0] when appropriate. + + Only check stats for infile==outfile once per input file, or not at all + if "-nofilecheck" option is present or if a directory was created. + + Fixed bugs with changing bit_depth of grayscale images. + +Version 1.5.6 (built with libpng-1.0.12) + + Eliminated extra "Removed the cHNK chunk" messages generated by version + 1.5.5 when "-rem alla" or "-rem allb" is used. + + All unknown chunks including safe-to-copy chunks are now removed in + response to the "-rem alla" or "-rem allb" options. + + Issue a warning if the user tries "-cc" option when it is not supported. + +Version 1.5.5 (built with libpng-1.0.12) + + Reset reduce_to_gray and it_is_opaque flags prior to processing each + image. + + Enable removal of safe-to-copy chunks that are being handled as unknown + e.g., "-rem time". + +Version 1.5.4 (built with libpng-1.0.11) + + Added 262 to the length of uncompressed data when calculating + required_window_size, to account for zlib/deflate implementation. + + Added "-bit_depth n" to the help screen. + + Call png_set_packing() when increasing bit_depth to 2 or 4. + + Added warning about not overwriting an existing tRNS chunk. + + Reduced the memory usage + + Write 500K IDAT chunks even when system libpng is being used. + + Ignore all-zero cHRM chunks, with a warning. + +Version 1.5.3 (built with libpng-1.0.9beta5) + + Added "-loco" option (writes MNG files with filter_method 64) + + "-dir" and "-ext" options are no longer mutually exclusive, e.g.: + pngcrush -loco -dir Crushed -ext .mng *.png + +Version 1.5.2 (built with libpng-1.0.9beta1) + + Added "-iccp" option. + + Increased the zlib memory level, which improves compression (typically + about 1.3 percent for photos) at the expense of increased memory usage. + + Enabled the "-max max_idat_size" option, even when max_idat_size + exceeds the default 1/2 megabyte size. + + Added missing "png_ptr" argument to png_error() call + + Added "-loco" option, to enable the LOCO color transformation + (R->R-G, G, B->B-G) while writing a MNG with filter_method 64. Undo + the transformation and write the regular PNG filter_method (0) if the + MNG filter_method 64 is detected. + + Revised the "-help" output slightly and improved the "-version" output. + + The "-already[_crushed]" option is now ignored if the "-force" option + is present or if chunks are being added, deleted, or modified. + + Improved "things_have_changed" behavior (now, when set in a particular + file, it is not set for all remaining files) + +Version 1.5.1 (built with libpng-1.0.8) + + Disabled color counting by default and made it controllable with new + -cc and -no_cc commandline arguments. + + Added some #ifdef PNGCRUSH_COUNT_COLORS around code that needs it. + + Revised count_colors() attempting to avoid stack corruption that has + been observed on RedHat 6.2 + + Added the word "irrevocably" to the license and changed "without fee" + to "without payment of any fee". + +Version 1.5.0 (built with libpng-1.0.8) + + After encountering an image with a bad Photoshop iCCP chunk, pngcrush + 1.4.5 through 1.4.8 write sRGB and gAMA=45455 chunks in all + remaining PNG files on the command line. This has been fixed so the + correction is only applied to the particular bad input file. + +Version 1.4.8 (built with libpng-1.0.8rc1) + + Detect and remove all-opaque alpha channel. + Detect and reduce all-gray truecolor images to grayscale. + +Version 1.4.7 (built with libpng-1.0.8rc1) + + Restored the "-ext" option that was inadvertently overridden with + a new "-exit" option in version 1.4.6 ("-exit" is used to force an + "exit" instead of a "return" from the main program). + +Version 1.4.6 (built with libpng-1.0.8rc1) + + Fixed bug in color-counting of noninterlaced images. + + Added capability of processing multiple rows at a time (disabled by + default because it turns out to be no faster). + + Replaced "return" statements in main() with "exit" statements. + Force exit instead of return with "-exit" argument. + + Added the UCITA disclaimers to the help output. + +Version 1.4.5 (built with libpng-1.0.7rc2 and cexcept-1.0.0) + + Added color-counting and palette-building capability (enable by + defining PNGCRUSH_COUNT_COLORS). In a future version, this will + give pngcrush the ability to reduce RGBA images to indexed-color + or grayscale when fewer than 257 RGBA combinations are present, + and no color is present that requires 16-bit precision. For now, + it only reports the frequencies. + + Added "-fix" option, for fixing bad CRC's and other correctable + conditions. + + Write sBIT.alpha=1 when adding an opaque alpha channel and sBIT + is present. + + Identify the erroneous 2615-byte sRGB monitor profile being written + by Photoshop 5.5, which causes many apps to crash, and replace it with + an sRGB chunk. + + Added a check for input and output on different devices before rejecting + the output file as being the same as the input file based on inode. + + Added some UCITA language to the disclaimer. + +Version 1.4.4 (built with libpng-1.0.6i and cexcept-0.6.3) + + Can be built on RISC OS platforms, thanks to Darren Salt. + +Version 1.4.3 (built with libpng-1.0.6h and cexcept-0.6.3) + + Reduced scope of Try/Catch blocks to avoid nesting them, and + removed returns from within the Try blocks, where they are not + allowed. + + Removed direct access to the png structure when possible, and isolated + the remaining direct accesses to the png structure into new + png_get_compression_buffer_size(), png_set_compression_buffer_size(), + and png_set_unknown_chunk_location() functions that were installed + in libpng version 1.0.6g. + +Version 1.4.2 (built with libpng-1.0.6f and cexcept-0.6.0) + + Removes extra IDAT chunks (such as found in some POV-ray PNGs) with + a warning instead of bailing out (this feature requires libpng-1.0.6f + or later, compiled with "#define PNG_ABORT()"). + + Removed old setjmp interface entirely. + +Version 1.4.1 (built with libpng-1.0.6e and cexcept-0.6.0) + + Uses cexcept.h for error handling instead of libpng's built-in + setjmp/longjmp mechanism. See http://cexcept.sf.net/ + + Pngcrush.c will now run when compiled with old versions of libpng back + to version 0.96, although some features will not be available. + +Version 1.4.0 (built with libpng-1.0.6 + libpng-1.0.6-patch-a) + +Version 1.3.6 (built with libpng-1.0.5v) + + RGB to Grayscale conversion is more accurate (15-bit instead of 8-bit) + and now uses only integer arithmetic. + + #ifdef'ed out PNG_READ_DITHER + + Changed "Compressed" to "Uncompressed" in help for -itxt. + + Stifled some compiler warnings + +Version 1.3.5 (built with libpng-1.0.5s) + + Add test on stat_buf.st_size to verify fpin==fpout, because stat in + MSVC++6.0 standard version returns stat_buf.st_ino=0 for all files. + + Revised pngcrush.h to make it easier to control PNG_ZBUF_SIZE and + PNG_NO_FLOATING_POINT_SUPPORTED from a makefile. + + Restored ability to enter "replace_gamma" value as a float even when + floating point arithmetic is not enabled. + + Enabled removing tEXt, zTXt, or iTXt chunks by chunk type, i.e., + "-rem tEXt" only removes tEXt chunks, while "-rem text" removes all + three types of text chunk. + + Removed definition of TOO_FAR from pngcrush.h + + Uses new libpng error handler; if a file has errors, pngcrush now will + continue on and compress the remaining files instead of bailing out. + +Version 1.3.4 (built with libpng-1.0.5m) + + Do not allow pngcrush to overwrite the input file. + +Version 1.3.3 (built with libpng-1.0.5m) + + Restored ability to enter gamma as a float even when floating point + arithmetic is not enabled. + +Version 1.3.2 (built with libpng-1.0.5k) + + Renamed "dirname" to "directory_name" to avoid conflict with "dirname" + that appears in string.h on some platforms. + + Fixed "PNG_NO_FLOAING_POINT" typo in pngcrush.h + + #ifdef'ed out parts of the help screen for options that are unsupported. + +Version 1.3.1 (built with libpng-1.0.5k): Eliminated some spurious warnings + that were being issued by libpng-1.0.5j. Added -itxt, -ztxt, and + -zitxt descriptions to the help screen. + + Dropped explicit support for pCAL, hIST, sCAL, sPLT, iCCP, tIME, and + cHRM chunks and handle them as unknown but safe-to-copy instead, using + new png_handle_as_unknown function available in libpng-1.0.5k. + +Version 1.3.0 (built with libpng-1.0.5j): Added support for handling + unknown chunks. + + pngcrush is now fixed-point only, unless PNG_NO_FLOATING_POINT_SUPPORTED + is undefined in pngcrush.h. + + Added support for the iCCP, iTXt, sCAL, and sPLT chunks, which + are now supported by libpng (since libpng-1.0.5j). None of these have + been adequately tested. + + #ifdef'ed out more unused code (weighted filters and progressive read; + this saves about 15k in the size of the executable). + + Moved the special definitions from pngconf.h into a new pngcrush.h + + Disallow 256-byte compression window size when writing, to work around + an apparent zlib bug. Either deflate was producing incorrect results in a + 21x21 4-bit image or inflate was decoding it incorrectly; the uncompressed + stream is 252 bytes, which is uncomfortably close to the resulting + 256-byte compression window. This workaround can be removed when zlib + is fixed. + + The "-m method" can be used any of the 124 methods, without having to + specify the filter, level, and strategy, instead of just the first 10. + +Version 1.2.1 (built with libpng-1.0.5f): Fixed -srgb parameter so it + really does take an argument, and so it continues to use "0" if an + integer does not follow the -srgb. + + Added "-plte_len n" argument for truncating the PLTE. Be sure not to + truncate it to less than the greatest index actually appearing in IDAT. + +Version 1.2.0: Removed registration requirement. Added open source + license. Redefined TOO_FAR=32k in deflate.c. + +Changes prior to going "open source": + +Version 1.1.8: built with libpng-1.0.5a. Runs OK with pngvcrd.c. + +Version 1.1.7: added ability to add tEXt/zTXt chunks. Fixed bug with +closing a file that wasn't opened when using "pngcrush -n". Fixed +bug with tEXt/zTXt chunks after IDAT not being copied. +Added alpha to the displayed palette table. Rebuilt with libpng-1.0.5. + +Version 1.1.6: fixed bug with one file left open after each image is +processed + +Version 1.1.5: Shorten or remove tRNS chunks that are all opaque or have +opaque entries at the end. Added timing report. + +Version 1.1.4: added ability to restrict brute_force to one or more filter + types, compression levels, or compression strategies. + diff --git a/INSTALL.txt b/INSTALL.txt deleted file mode 100644 index 9b3a80f6f..000000000 --- a/INSTALL.txt +++ /dev/null @@ -1,27 +0,0 @@ - -There are sample Makefile.gcc and Makefile.msc for pngcrush, which you can use -by typing, for example - - make -f Makefile.gcc - -However, all you should need to do is enter the pngcrush-n.n.n -directory and type - - cc -O -o pngcrush *.c -lm - cp pngcrush /usr/local/bin # or wherever you want - -You might want to create your own Makefile if you are planning to do -something more complicated, like loading with your system's shared -libraries for libpng and zlib. - -Here's a command for compiling on SGI IRIX: - - cc -n32 -fullwarn -O2 -IPA:plimit=256 -OPT:Olimit=0 -o pngcrush *.c -lm - cp pngcrush /usr/local/bin - -On a PC with DJGCC, you can type - - gcc -O3 -Wall -funroll-loops -o pngcrush *.c - copy /B pmodstub.exe + pngcrush pngcrush.exe - -then put pngcrush.exe wherever you want. diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..ca2f6d987 --- /dev/null +++ b/Makefile @@ -0,0 +1,73 @@ +# Sample makefile for pngcrush using gcc and GNU make. +# Glenn Randers-Pehrson +# Last modified: 19 February 2005 +# +# Invoke this makefile from a shell prompt in the usual way; for example: +# +# make -f makefile.gcc +# +# This makefile builds a statically linked executable. + +# macros -------------------------------------------------------------------- + +GAS_VERSION := $(shell as --version | grep "GNU assembler" | sed -e 's/GNU assembler //' -e 's/ .*//') + +# uncomment these 2 lines only if you are using an external copy of zlib: +#ZINC = ../../zlib +#ZLIB = ../../zlib + +CC = gcc +LD = gcc +RM = rm -f +#CFLAGS = -I. -O -Wall +#CFLAGS = -I. -O3 -fomit-frame-pointer -Wall -DPNG_USE_PNGGCCRD +CFLAGS = -I. -O3 -fomit-frame-pointer -Wall -DPNG_USE_PNGGCCRD \ + -DGAS_VERSION="\"${GAS_VERSION}\"" +#CFLAGS = -I${ZINC} -I. -O3 -fomit-frame-pointer -Wall -DPNG_USE_PNGGCCRD \ +# -DGAS_VERSION="\"${GAS_VERSION}\"" +# [note that -Wall is a gcc-specific compilation flag ("all warnings on")] +LDFLAGS = +O = .o +E = + +PNGCRUSH = pngcrush + +LIBS = -lm +#LIBS = -L${ZLIB} -lz -lm +#LIBS = ${ZLIB}/libz.a -lm + +# uncomment these 4 lines only if you are NOT using an external copy of zlib: +ZHDR = zlib.h +ZOBJS = adler32$(O) compress$(O) crc32$(O) deflate$(O) gzio$(O) \ + infback$(O) inffast$(O) inflate$(O) inftrees$(O) \ + trees$(O) uncompr$(O) zutil$(O) + +OBJS = pngcrush$(O) png$(O) pngerror$(O) pngget$(O) pngmem$(O) \ + pngpread$(O) pngread$(O) pngrio$(O) pngrtran$(O) pngrutil$(O) \ + pngset$(O) pngtrans$(O) pngwio$(O) pngwrite$(O) pnggccrd$(O) \ + pngwtran$(O) pngwutil$(O) $(ZOBJS) + +EXES = $(PNGCRUSH)$(E) + + +# implicit make rules ------------------------------------------------------- + +.c$(O): png.h pngconf.h pngcrush.h cexcept.h $(ZHDR) + $(CC) -c $(CFLAGS) $< + + +# dependencies -------------------------------------------------------------- + +all: $(EXES) + + +pngcrush$(O): pngcrush.c png.h pngconf.h pngcrush.h cexcept.h $(ZHDR) + $(CC) -c $(CFLAGS) $< + +$(PNGCRUSH)$(E): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +# maintenance --------------------------------------------------------------- + +clean: + $(RM) $(EXES) $(OBJS) diff --git a/Makefile.ext-zlib b/Makefile.ext-zlib new file mode 100644 index 000000000..4f19b8dc4 --- /dev/null +++ b/Makefile.ext-zlib @@ -0,0 +1,72 @@ +# Sample makefile for pngcrush using gcc and GNU make. +# Glenn Randers-Pehrson +# Last modified: 19 February 2005 +# +# Invoke this makefile from a shell prompt in the usual way; for example: +# +# make -f makefile.gcc +# +# This makefile builds a statically linked executable. + +# macros -------------------------------------------------------------------- + +GAS_VERSION := $(shell as --version | grep "GNU assembler" | sed -e 's/GNU assembler //' -e 's/ .*//') + +ZINC = ../../zlib +ZLIB = ../../zlib + +CC = gcc +LD = gcc +RM = rm -f +#CFLAGS = -I. -O -Wall +#CFLAGS = -I. -O3 -fomit-frame-pointer -Wall -DPNG_USE_PNGGCCRD +#CFLAGS = -I. -O3 -fomit-frame-pointer -Wall -DPNG_USE_PNGGCCRD \ +# -DGAS_VERSION="\"${GAS_VERSION}\"" +CFLAGS = -I${ZINC} -I. -O3 -fomit-frame-pointer -Wall -DPNG_USE_PNGGCCRD \ + -DGAS_VERSION="\"${GAS_VERSION}\"" +# [note that -Wall is a gcc-specific compilation flag ("all warnings on")] +LDFLAGS = +O = .o +E = + +PNGCRUSH = pngcrush-zlib + +#LIBS = -lm +#LIBS = -L${ZLIB} -lz -lm +LIBS = ${ZLIB}/libz.a -lm + +# uncomment these 4 lines only if you are NOT using an external copy of zlib: +#ZHDR = zlib.h +#ZOBJS = adler32$(O) crc32$(O) deflate$(O) gzio$(O) \ +# infblock$(O) infcodes$(O) inffast$(O) inflate$(O) inftrees$(O) \ +# infutil$(O) trees$(O) zutil$(O) + +OBJS = pngcrush$(O) png$(O) pngerror$(O) pngget$(O) pngmem$(O) \ + pngpread$(O) pngread$(O) pngrio$(O) pngrtran$(O) pngrutil$(O) \ + pngset$(O) pngtrans$(O) pngwio$(O) pngwrite$(O) pnggccrd$(O) \ + pngwtran$(O) pngwutil$(O) $(ZOBJS) + +EXES = $(PNGCRUSH)$(E) + + +# implicit make rules ------------------------------------------------------- + +.c$(O): png.h pngconf.h pngcrush.h cexcept.h $(ZHDR) + $(CC) -c $(CFLAGS) $< + + +# dependencies -------------------------------------------------------------- + +all: $(EXES) + + +pngcrush$(O): pngcrush.c png.h pngconf.h pngcrush.h cexcept.h $(ZHDR) + $(CC) -c $(CFLAGS) $< + +$(PNGCRUSH)$(E): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +# maintenance --------------------------------------------------------------- + +clean: + $(RM) $(EXES) $(OBJS) diff --git a/Makefile.gcc b/Makefile.gcc deleted file mode 100644 index 976e86351..000000000 --- a/Makefile.gcc +++ /dev/null @@ -1,55 +0,0 @@ -# Sample makefile for pngcrush using gcc and make. -# Glenn Randers-Pehrson -# Last modified: 7 December 1999 -# -# Invoke this makefile from a shell prompt in the usual way; for example: -# -# make -f makefile.unx -# -# This makefile builds a statically linked executable. - -# macros -------------------------------------------------------------------- - -CC = gcc -LD = gcc -RM = rm -f -CFLAGS = -I. -O -Wall -# [note that -Wall is a gcc-specific compilation flag ("all warnings on")] -LDFLAGS = -O = .o -E = - -PNGCRUSH = pngcrush - -LIBS = -lm - -OBJS = $(PNGCRUSH)$(O) adler32$(O) crc32$(O) deflate$(O) gzio$(O) \ - infblock$(O) infcodes$(O) inffast$(O) inflate$(O) inftrees$(O) \ - infutil$(O) png$(O) pngerror$(O) pngget$(O) pngmem$(O) \ - pngpread$(O) pngread$(O) pngrio$(O) pngrtran$(O) pngrutil$(O) \ - pngset$(O) pngtrans$(O) pngwio$(O) pngwrite$(O) pnggccrd$(O) \ - pngwtran$(O) pngwutil$(O) trees$(O) zutil$(O) - -EXES = $(PNGCRUSH)$(E) - - -# implicit make rules ------------------------------------------------------- - -.c$(O): png.h pngconf.h zlib.h pngcrush.h cexcept.h - $(CC) -c $(CFLAGS) $< - - -# dependencies -------------------------------------------------------------- - -all: $(EXES) - - -$(PNGCRUSH)$(E): $(OBJS) - $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) - -$(PNGCRUSH)$(O): $(PNGCRUSH).c png.h pngconf.h zlib.h pngcrush.h cexcept.h - -# maintenance --------------------------------------------------------------- - -clean: - $(RM) $(EXES) $(OBJS) diff --git a/Makefile.msc b/Makefile.msc deleted file mode 100644 index 8ae8327fc..000000000 --- a/Makefile.msc +++ /dev/null @@ -1,57 +0,0 @@ -# Sample makefile for pngcrush using Microsoft (Visual) C compiler. -# Author: Cosmin Truta -# Derived from Makefile.gcc by Glenn Randers-Pehrson -# Last modified: 14 January 2000 -# -# Invoke this makefile from a console prompt in the usual way; for example: -# -# nmake -f Makefile.msc -# -# This makefile builds a statically linked executable. - -# macros -------------------------------------------------------------------- - -CC = cl -nologo -LD = link -nologo setargv.obj -RM = del -CFLAGS = -I. -DPNG_ZBUF_SIZE=0x080000 -DWIN32 -O2 -LDFLAGS = -O = .obj -E = .exe - -PNGCRUSH = pngcrush - -LIBS = - -OBJS = $(PNGCRUSH)$(O) adler32$(O) crc32$(O) deflate$(O) gzio$(O) \ - infblock$(O) infcodes$(O) inffast$(O) inflate$(O) inftrees$(O) \ - infutil$(O) png$(O) pngerror$(O) pngget$(O) pngmem$(O) \ - pngpread$(O) pngread$(O) pngrio$(O) pngrtran$(O) pngrutil$(O) \ - pngset$(O) pngtrans$(O) pngvcrd$(O) pngwio$(O) pngwrite$(O) \ - pngwtran$(O) pngwutil$(O) trees$(O) zutil$(O) - -EXES = $(PNGCRUSH)$(E) - - -# implicit make rules ------------------------------------------------------- - -.c$(O): - $(CC) -c $(CFLAGS) $< - - -# dependencies -------------------------------------------------------------- - -all: $(EXES) - - -$(PNGCRUSH)$(E): $(OBJS) - $(LD) $(LDFLAGS) -out:$@ $(OBJS) $(LIBS) - -$(PNGCRUSH)$(O): $(PNGCRUSH).c png.h pngconf.h zlib.h pngcrush.h cexcept.h - -# maintenance --------------------------------------------------------------- - -clean: - $(RM) *$(O) - $(RM) $(PNGCRUSH)$(E) - diff --git a/Makefile.solaris b/Makefile.solaris new file mode 100644 index 000000000..509cf2e3a --- /dev/null +++ b/Makefile.solaris @@ -0,0 +1,70 @@ +# Sample makefile for pngcrush using gcc and GNU make. +# Glenn Randers-Pehrson +# Last modified: 19 February 2005 +# +# Invoke this makefile from a shell prompt in the usual way; for example: +# +# make -f makefile.gcc +# +# This makefile builds a statically linked executable. + +# macros -------------------------------------------------------------------- + +# uncomment these 2 lines only if you are using an external copy of zlib: +#ZINC = ../../zlib +#ZLIB = ../../zlib + +CC = gcc +LD = gcc +RM = rm -f +#CFLAGS = -I. -O -Wall +#CFLAGS = -I. -O3 -fomit-frame-pointer -Wall -DPNG_USE_PNGGCCRD +CFLAGS = -I. -O3 -fomit-frame-pointer -Wall +#CFLAGS = -I${ZINC} -I. -O3 -fomit-frame-pointer -Wall -DPNG_USE_PNGGCCRD \ +# -DGAS_VERSION="\"${GAS_VERSION}\"" +# [note that -Wall is a gcc-specific compilation flag ("all warnings on")] +LDFLAGS = +O = .o +E = + +PNGCRUSH = pngcrush + +LIBS = -lm +#LIBS = -L${ZLIB} -lz -lm +#LIBS = ${ZLIB}/libz.a -lm + +# uncomment these 4 lines only if you are NOT using an external copy of zlib: +ZHDR = zlib.h +ZOBJS = adler32$(O) compress$(O) crc32$(O) deflate$(O) gzio$(O) \ + infback$(O) inffast$(O) inflate$(O) inftrees$(O) \ + trees$(O) uncompr$(O) zutil$(O) + +OBJS = pngcrush$(O) png$(O) pngerror$(O) pngget$(O) pngmem$(O) \ + pngpread$(O) pngread$(O) pngrio$(O) pngrtran$(O) pngrutil$(O) \ + pngset$(O) pngtrans$(O) pngwio$(O) pngwrite$(O) pnggccrd$(O) \ + pngwtran$(O) pngwutil$(O) $(ZOBJS) + +EXES = $(PNGCRUSH)$(E) + + +# implicit make rules ------------------------------------------------------- + +.c$(O): png.h pngconf.h pngcrush.h cexcept.h $(ZHDR) + $(CC) -c $(CFLAGS) $< + + +# dependencies -------------------------------------------------------------- + +all: $(EXES) + + +pngcrush$(O): pngcrush.c png.h pngconf.h pngcrush.h cexcept.h $(ZHDR) + $(CC) -c $(CFLAGS) $< + +$(PNGCRUSH)$(E): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +# maintenance --------------------------------------------------------------- + +clean: + $(RM) $(EXES) $(OBJS) diff --git a/README.txt b/README.txt deleted file mode 100644 index 66105d1b9..000000000 --- a/README.txt +++ /dev/null @@ -1,321 +0,0 @@ -Pngcrush documentation - -This is is a copy of the copyright notice, disclaimer, and license, for -your convenience (the actual notice appears in the file pngcrush.c; in -case of any discrepancy, the copy in pngcrush.c shall prevail): - -/* - * COPYRIGHT NOTICE, DISCLAIMER, AND LICENSE: - * - * If you have modified this source, you may insert additional notices - * immediately after this sentence. - * - * Copyright (C) 1998-2002 Glenn Randers-Pehrson (randeg@alum.rpi.edu) - * - * The pngcrush computer program is supplied "AS IS". The Author disclaims all - * warranties, expressed or implied, including, without limitation, the - * warranties of merchantability and of fitness for any purpose. The - * Author assumes no liability for direct, indirect, incidental, special, - * exemplary, or consequential damages, which may result from the use of - * the computer program, even if advised of the possibility of such damage. - * There is no warranty against interference with your enjoyment of the - * computer program or against infringement. There is no warranty that my - * efforts or the computer program will fulfill any of your particular purposes - * or needs. This computer program is provided with all faults, and the entire - * risk of satisfactory quality, performance, accuracy, and effort is with - * the user. - * - * Permission is hereby irrevocably granted to everyone to use, copy, modify, - * and distribute this source code, or portions hereof, for any purpose, - * without payment of any fee, subject to the following restrictions: - * - * 1. The origin of this source code must not be misrepresented. - * - * 2. Altered versions must be plainly marked as such and must not be - * misrepresented as being the original source. - * - * 3. This Copyright notice, disclaimer, and license may not be removed - * or altered from any source or altered source distribution. - */ - -This is the output of "pngcrush" and "pngcrush -help": - - - | pngcrush 1.5.10, Copyright (C) 1998-2002 Glenn Randers-Pehrson - | This is a free, open-source program. Permission is irrevocably - | granted to everyone to use this version of pngcrush without - | payment of any fee. - | Executable name is pngcrush - | It was built with libpng version 1.2.4, and is - | running with libpng version 1.2.4 - July 8, 2002 (header) - | Copyright (C) 1998-2002 Glenn Randers-Pehrson, - | Copyright (C) 1996, 1997 Andreas Dilger, - | Copyright (C) 1995, Guy Eric Schalnat, Group 42 Inc., - | and zlib version 1.1.4pc, Copyright (C) 1998, - | Jean-loup Gailly and Mark Adler. - - -usage: pngcrush [options] infile.png outfile.png - pngcrush -e ext [other options] files.png ... - pngcrush -d dir [other options] files.png ... -options: - -already already_crushed_size [e.g., 8192] - -bit_depth depth (bit_depth to use in output file) - -brute (Use brute-force, try 114 different methods [11-124]) - -c color_type of output file [0, 2, 4, or 6] - -d directory_name (where output files will go) - -double_gamma (used for fixing gamma in PhotoShop 5.0/5.02 files) - -e extension (used for creating output filename) - -f user_filter [0-5] - -fix (fix otherwise fatal conditions such as bad CRCs) - -force (Write a new output file even if larger than input) - -g gamma (float or fixed*100000, e.g., 0.45455 or 45455) - -iccp length "Profile Name" iccp_file - -itxt b[efore_IDAT]|a[fter_IDAT] "keyword" "text" - -l zlib_compression_level [0-9] - -loco ("loco crush" truecolor PNGs) - -m method [0 through 200] - -max maximum_IDAT_size [default 8192] - -nofilecheck (do not check for infile.png == outfile.png) - -n (no save; does not do compression or write output PNG) - -plte_len n (truncate PLTE) - -q (quiet) - -reduce (do lossless color type or bit depth reduction) - -rem chunkname (or "alla" or "allb") --replace_gamma gamma (float or fixed*100000) even if gAMA is present. - -res dpi - -save (keep all copy-unsafe chunks) - -srgb [0, 1, 2, or 3] - -text b[efore_IDAT]|a[fter_IDAT] "keyword" "text" - -trns_array n trns[0] trns[1] .. trns[n-1] - -trns index red green blue gray - -v (display more detailed information) - -version (display the pngcrush version) - -w compression_window_size [32, 16, 8, 4, 2, 1, 512] - -z zlib_strategy [0, 1, or 2] - -zmem zlib_compression_mem_level [1-9, default 9] - -zitxt b[efore_IDAT]|a[fter_IDAT] "keyword" "text" - -ztxt b[efore_IDAT]|a[fter_IDAT] "keyword" "text" - -h (help and legal notices) - -p (pause) - - -options (Note: any option can be spelled out for clarity, e.g., - "pngcrush -dir New -method 7 -remove bkgd *.png" - is the same as "pngcrush -d New -m 7 -rem bkgd *.png"): - - -already already_crushed_size [e.g., 8192] - - If file has an IDAT greater than this size, it - will be considered to be already crushed and will - not be processed, unless you are making other changes - or the "-force" option is present. - - -bit_depth depth (bit_depth to use in output file) - - Default output depth is same as input depth. - - -brute (Use brute-force, try 114 different methods [11-124]) - - Very time-consuming and generally not worthwhile. - You can restrict this option to certain filter types, - compression levels, or strategies by following it with - "-f filter", "-l level", or "-z strategy". - - -c color_type of output file [0, 2, 4, or 6] - - Color type for the output file. Future versions - will also allow color_type 3, if there are 256 or - fewer colors present in the input file. Color types - 4 and 6 are padded with an opaque alpha channel if - the input file does not have alpha information. - You can use 0 or 4 to convert color to grayscale. - Use 0 or 2 to delete an unwanted alpha channel. - Default is to use same color type as the input file. - - -d directory_name (where output files will go) - - If a directory name is given, then the output - files are placed in it, with the same filenames as - those of the original files. For example, - you would type 'pngcrush -directory CRUSHED *.png' - to get *.png => CRUSHED/*.png - - -double_gamma (used for fixing gamma in PhotoShop 5.0/5.02 files) - - It has been claimed that the PS5 bug is actually - more complex than that, in some unspecified way. - - -e extension (used for creating output filename) - - e.g., -ext .new means *.png => *.new - and -e _C.png means *.png => *_C.png - - -f user_filter [0-5] - - filter to use with the method specified in the - preceding '-m method' or '-brute_force' argument. - 0: none; 1-4: use specified filter; 5: adaptive. - - -fix (fix otherwise fatal conditions such as bad CRCs) - - -force (Write a new output file even if larger than input) - - Otherwise the input file will be copied to output - if it is smaller than any generated file and no chunk - additions, removals, or changes were requested. - - -g gamma (float or fixed*100000, e.g., 0.45455 or 45455) - - Value to insert in gAMA chunk, only if the input - file has no gAMA chunk. To replace an existing - gAMA chunk, use the '-replace_gamma' option. - - -iccp length "Profile Name" iccp_file - - file with ICC profile to insert in an iCCP chunk. - - -itxt b[efore_IDAT]|a[fter_IDAT] "keyword" "text" - - Uncompressed iTXt chunk to insert (see -text). - - -l zlib_compression_level [0-9] - - zlib compression level to use with method specified - with the preceding '-m method' or '-brute_force' - argument. - - -loco ("loco crush" truecolor PNGs) - - Make the file more compressible by performing a - lossless reversible color transformation. - The resulting file is a MNG, not a PNG, and should - be given the ".mng" file extension. The - "loco" option has no effect on grayscale or - indexed-color PNG files. - - -m method [0 through 200] - - pngcrush method to try (0 means try all of 1-10). - Can be repeated as in '-m 1 -m 4 -m 7'. - This can be useful if pngcrush runs out of memory - when it tries methods 2, 3, 5, 6, 8, 9, or 10 which - use filtering and are memory intensive. Methods - 1, 4, and 7 use no filtering; methods 11 and up use - specified filter, compression level, and strategy. - - -max maximum_IDAT_size [default 8192] - - -nofilecheck (do not check for infile.png == outfile.png) - - To avoid false hits from MSVC-compiled code. Note - that if you use this option, you are responsible for - ensuring that the input file is not the output file. - - -n (no save; does not do compression or write output PNG) - - Useful in conjunction with -v option to get info. - - -plte_len n (truncate PLTE) - - Truncates the PLTE. Be sure not to truncate it to - less than the greatest index present in IDAT. - - -q (quiet) - - -reduce (do lossless color type or bit depth reduction) - - (if possible) - - -rem chunkname (or "alla" or "allb") - - Name of an ancillary chunk or optional PLTE to be - removed. Be careful with this. Please don't use - this feature to remove transparency, gamma, copyright, - or other valuable information. To remove several - different chunks, repeat: -rem tEXt -rem pHYs. - Known chunks (those in the PNG 1.1 spec or extensions - document) can be named with all lower-case letters, - so "-rem bkgd" is equivalent to "-rem bKGD". But - note: "-rem text" removes all forms of text chunks; - Exact case is required to remove unknown chunks. - To do surgery with a chain-saw, "-rem alla" removes - all known ancillary chunks except for tRNS, and - "-rem allb" removes all but tRNS and gAMA. - --replace_gamma gamma (float or fixed*100000) even if gAMA is present. - - -res dpi - - Write a pHYs chunk with the given resolution. - - -save (keep all copy-unsafe chunks) - - Save otherwise unknown ancillary chunks that would - be considered copy-unsafe. This option makes - chunks 'known' to pngcrush, so they can be copied. - - -srgb [0, 1, 2, or 3] - - Value of 'rendering intent' for sRGB chunk. - - -text b[efore_IDAT]|a[fter_IDAT] "keyword" "text" - - tEXt chunk to insert. keyword < 80 chars, - - text < 2048 chars. For now, you can only add ten - tEXt, iTXt, or zTXt chunks per pngcrush run. - - -trns_array n trns[0] trns[1] .. trns[n-1] - - Insert a tRNS chunk, if no tRNS chunk found in file. - Values are for the tRNS array in indexed-color PNG. - - -trns index red green blue gray - - Insert a tRNS chunk, if no tRNS chunk found in file. - You must give all five parameters regardless of the - color type, scaled to the output bit depth. - - -v (display more detailed information) - - Repeat the option (use "-v -v") for even more. - - -version (display the pngcrush version) - - Look for the most recent version of pngcrush at - http://pmt.sf.net - - -w compression_window_size [32, 16, 8, 4, 2, 1, 512] - - Size of the sliding compression window, in kbytes - (or bytes, in case of 512). It's best to - use the default (32) unless you run out of memory. - The program will use a smaller window anyway when - the uncompressed file is smaller than 16k. - - -z zlib_strategy [0, 1, or 2] - - zlib compression strategy to use with the preceding - '-m method' argument. - - -zmem zlib_compression_mem_level [1-9, default 9] - - -zitxt b[efore_IDAT]|a[fter_IDAT] "keyword" "text" - - Compressed iTXt chunk to insert (see -text). - - -ztxt b[efore_IDAT]|a[fter_IDAT] "keyword" "text" - - zTXt chunk to insert (see -text). - - -h (help and legal notices) - - Display this information. - - -p (pause) - - Wait for [enter] key before continuing display. - e.g., type 'pngcrush -pause -help', if the help - screen scrolls out of sight. - diff --git a/adler32.c b/adler32.c index 16cf9a703..007ba2627 100644 --- a/adler32.c +++ b/adler32.c @@ -1,48 +1,149 @@ /* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ +#define ZLIB_INTERNAL #include "zlib.h" -#define BASE 65521L /* largest prime smaller than 65536 */ +#define BASE 65521UL /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ -#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + /* ========================================================================= */ uLong ZEXPORT adler32(adler, buf, len) uLong adler; const Bytef *buf; uInt len; { - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; + unsigned long sum2; + unsigned n; - if (buf == Z_NULL) return 1L; + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - buf += 16; - k -= 16; - } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - s1 %= BASE; - s2 %= BASE; + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); } - return (s2 << 16) | s1; + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); } diff --git a/cexcept.h b/cexcept.h index 532b23dae..dbea51ebe 100644 --- a/cexcept.h +++ b/cexcept.h @@ -1,17 +1,20 @@ /*=== -cexcept.h 1.0.0 (2000-Jun-21-Wed) +cexcept.h 2.0.0 (2001-Jul-12-Thu) Adam M. Costello -An interface for exception-handling in ANSI C, developed jointly with -Cosmin Truta . +An interface for exception-handling in ANSI C (C89 and subsequent ISO +standards), developed jointly with Cosmin Truta . - Copyright (c) 2000 Adam M. Costello and Cosmin Truta. Everyone + Copyright (c) 2001 Adam M. Costello and Cosmin Truta. Everyone is hereby granted permission to do whatever they like with this file, provided that if they modify it they take reasonable steps to avoid confusing or misleading people about the authors, version, and terms of use of the derived file. The copyright holders make - no guarantees about the correctness of this file, and are not - responsible for any damage resulting from its use. + no guarantees regarding this file, and are not responsible for any + damage resulting from its use. + +Only user-defined exceptions are supported, not "real" exceptions like +division by zero or memory segmentation violations. If this interface is used by multiple .c files, they shouldn't include this header file directly. Instead, create a wrapper header file that @@ -37,6 +40,10 @@ define_exception_type(type_name); struct exception { int code; const char *msg; }; define_exception_type(struct exception); + Because throwing an exception causes the object to be copied (not + just once, but twice), programmers may wish to consider size when + choosing the exception type. + struct exception_context; @@ -62,7 +69,7 @@ struct exception_context *the_exception_context; application may declare a variable of this name anywhere it likes (inside a function, in a parameter list, or externally), and may use whatever storage class specifiers (static, extern, etc) or type - qualifiers (const, volatile) it likes. Examples: + qualifiers (const, volatile, etc) it likes. Examples: static struct exception_context * const the_exception_context = &foo; @@ -107,15 +114,15 @@ Catch (expression) statement confusion with the C++ keywords, which have subtly different semantics. - A Try/Catch statement has a syntax similar to an if/else - statement, except that the parenthesized expression goes after - the second keyword rather than the first. As with if/else, - there are two clauses, each of which may be a simple statement - ending with a semicolon or a brace-enclosed compound statement. - But whereas the else clause is optional, the Catch clause is - required. The expression must be a modifiable lvalue (something - capable of being assigned to) of the exact same type passed to - define_exception_type(). + A Try/Catch statement has a syntax similar to an if/else statement, + except that the parenthesized expression goes after the second + keyword rather than the first. As with if/else, there are two + clauses, each of which may be a simple statement ending with a + semicolon or a brace-enclosed compound statement. But whereas + the else clause is optional, the Catch clause is required. The + expression must be a modifiable lvalue (something capable of being + assigned to) of the same type (disregarding type qualifiers) that + was passed to define_exception_type(). If a Throw that uses the same exception context as the Try/Catch is executed within the Try clause (typically within a function called @@ -125,9 +132,8 @@ Catch (expression) statement such Throw is executed, then the assignment is not performed, and the Catch clause is not executed. - Regardless of whether an exception is caught, the expression is - always evaluated exactly once, which is significant if it has side - effects, for example: + The expression is not evaluated unless and until the exception is + caught, which is significant if it has side effects, for example: Try foo(); Catch (p[++i].e) { ... } @@ -183,62 +189,55 @@ is subject to change. #include #define define_exception_type(etype) \ -struct exception__state { \ - etype *exception; \ - jmp_buf env; \ +struct exception_context { \ + jmp_buf *penv; \ + int caught; \ + volatile struct { etype etmp; } v; \ } -struct exception_context { \ - struct exception__state *last; \ - int caught; \ -}; +/* etmp must be volatile because the application might use automatic */ +/* storage for the_exception_context, and etmp is modified between */ +/* the calls to setjmp() and longjmp(). A wrapper struct is used to */ +/* avoid warnings about a duplicate volatile qualifier in case etype */ +/* already includes it. */ -#define init_exception_context(ec) ((void)((ec)->last = 0)) - -#define Catch(e) exception__catch(&(e)) -#define Catch_anonymous exception__catch(0) +#define init_exception_context(ec) ((void)((ec)->penv = 0)) #define Try \ { \ - struct exception__state *exception__p, exception__s; \ - int exception__i; \ - exception__p = the_exception_context->last; \ - the_exception_context->last = &exception__s; \ - for (exception__i = 0; ; exception__i = 1) \ - if (exception__i) { \ - if (setjmp(exception__s.env) == 0) { \ - if (&exception__s) + jmp_buf *exception__prev, exception__env; \ + exception__prev = the_exception_context->penv; \ + the_exception_context->penv = &exception__env; \ + if (setjmp(exception__env) == 0) { \ + if (&exception__prev) -#define exception__catch(e_addr) \ - else { } \ - the_exception_context->caught = 0; \ - } \ - else the_exception_context->caught = 1; \ - the_exception_context->last = exception__p; \ - break; \ - } \ - else exception__s.exception = e_addr; \ +#define exception__catch(action) \ + else { } \ + the_exception_context->caught = 0; \ + } \ + else { \ + the_exception_context->caught = 1; \ + } \ + the_exception_context->penv = exception__prev; \ } \ - if (!the_exception_context->caught) { } \ + if (!the_exception_context->caught || action) { } \ else +#define Catch(e) exception__catch(((e) = the_exception_context->v.etmp, 0)) +#define Catch_anonymous exception__catch(0) + /* Try ends with if(), and Catch begins and ends with else. This */ /* ensures that the Try/Catch syntax is really the same as the */ /* if/else syntax. */ /* */ -/* We use &exception__s instead of 1 to appease compilers that */ +/* We use &exception__prev instead of 1 to appease compilers that */ /* warn about constant expressions inside if(). Most compilers */ -/* should still recognize that &exception__s is never zero and avoid */ -/* generating test code. */ -/* */ -/* We use the variable exception__i to start the loop at the bottom, */ -/* rather than jump into the loop using a switch statement, to */ -/* appease compilers that warn about jumping into loops. */ +/* should still recognize that &exception__prev is never zero and */ +/* avoid generating test code. */ #define Throw \ - for (;; longjmp(the_exception_context->last->env, 1)) \ - if (the_exception_context->last->exception) \ - *the_exception_context->last->exception = + for (;; longjmp(*the_exception_context->penv, 1)) \ + the_exception_context->v.etmp = #endif /* CEXCEPT_H */ diff --git a/compress.c b/compress.c index 1cee47091..df04f0148 100644 --- a/compress.c +++ b/compress.c @@ -1,10 +1,11 @@ /* compress.c -- compress a memory buffer - * Copyright (C) 1995-1998 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ +#define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== @@ -66,3 +67,13 @@ int ZEXPORT compress (dest, destLen, source, sourceLen) { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/crc32.c b/crc32.c index a91101a81..f658a9ef5 100644 --- a/crc32.c +++ b/crc32.c @@ -1,22 +1,84 @@ /* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ -#include "zlib.h" +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ #define local static +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + #ifdef DYNAMIC_CRC_TABLE -local int crc_table_empty = 1; -local uLongf crc_table[256]; +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); - +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ /* - Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, @@ -35,128 +97,327 @@ local void make_crc_table OF((void)); out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. - The table is simply the CRC of all possible eight bit values. This is all - the information needed to generate CRC's on data a byte at a time for all - combinations of CRC register values and incoming bytes. + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. */ local void make_crc_table() { - uLong c; - int n, k; - uLong poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - /* make exclusive-or pattern from polynomial (0xedb88320L) */ - poly = 0L; - for (n = 0; n < sizeof(p)/sizeof(Byte); n++) - poly |= 1L << (31 - p[n]); - - for (n = 0; n < 256; n++) - { - c = (uLong)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[n] = c; - } - crc_table_empty = 0; + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ } -#else + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== - * Table of CRC-32's of all single-byte values (made by make_crc_table) + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). */ -local const uLongf crc_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; -#endif +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= * This function can be used by asm versions of crc32() */ -const uLongf * ZEXPORT get_crc_table() +const unsigned long FAR * ZEXPORT get_crc_table() { -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) make_crc_table(); -#endif - return (const uLongf *)crc_table; -} - -/* ========================================================================= */ -#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); -#define DO2(buf) DO1(buf); DO1(buf); -#define DO4(buf) DO2(buf); DO2(buf); -#define DO8(buf) DO4(buf); DO4(buf); - -/* ========================================================================= */ -uLong ZEXPORT crc32(crc, buf, len) - uLong crc; - const Bytef *buf; - uInt len; -{ - if (buf == Z_NULL) return 0L; #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) - make_crc_table(); -#endif - crc = crc ^ 0xffffffffL; - while (len >= 8) - { - DO8(buf); - len -= 8; + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; } if (len) do { - DO1(buf); + DO1; } while (--len); - return crc ^ 0xffffffffL; + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; } diff --git a/crc32.h b/crc32.h new file mode 100644 index 000000000..8053b6117 --- /dev/null +++ b/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/deflate.c b/deflate.c index 97ea74460..0e946cc42 100644 --- a/deflate.c +++ b/deflate.c @@ -1,6 +1,6 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-1998 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h */ /* @@ -37,7 +37,7 @@ * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in ftp://ds.internic.net/rfc/rfc1951.txt + * Available in http://www.ietf.org/rfc/rfc1951.txt * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.1.3pc Copyright 1995-1998 Jean-loup Gailly "; + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -76,17 +76,22 @@ typedef block_state (*compress_func) OF((deflate_state *s, int flush)); local void fill_window OF((deflate_state *s)); local block_state deflate_stored OF((deflate_state *s, int flush)); local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST #ifdef ASMV void match_init OF((void)); /* asm code initialization */ uInt longest_match OF((deflate_state *s, IPos cur_match)); #else local uInt longest_match OF((deflate_state *s, IPos cur_match)); #endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); #ifdef DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, @@ -123,10 +128,16 @@ typedef struct config_s { compress_func func; } config; +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, @@ -135,7 +146,8 @@ local const config configuration_table[10] = { /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different @@ -145,7 +157,9 @@ local const config configuration_table[10] = { #define EQUAL 0 /* result of memcmp for equal strings */ +#ifndef NO_DUMMY_DECL struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif /* =========================================================================== * Update a hash value with the given input byte @@ -174,7 +188,7 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ #else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #endif @@ -194,13 +208,13 @@ int ZEXPORT deflateInit_(strm, level, version, stream_size) int stream_size; { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); + Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) + version, stream_size) z_streamp strm; int level; int method; @@ -211,8 +225,8 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, int stream_size; { deflate_state *s; - int noheader = 0; - static const char* my_version = ZLIB_VERSION; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; ushf *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average @@ -221,38 +235,46 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; + return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; - if (strm->zalloc == Z_NULL) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; } - if (strm->zfree == Z_NULL) strm->zfree = zcfree; + if (strm->zfree == (free_func)0) strm->zfree = zcfree; #ifdef FASTEST - level = 1; + if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif - if (windowBits < 0) { /* undocumented feature: suppress zlib header */ - noheader = 1; + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; windowBits = -windowBits; } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; - s->noheader = noheader; + s->wrap = wrap; + s->gzhead = Z_NULL; s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; @@ -262,10 +284,8 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - s->window = (Bytef *) ZALLOC(strm, (windowBits == 8 ? 264 : s->w_size), - 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, (windowBits == 8 ? 264 : s->w_size), - sizeof(Pos)); + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ @@ -276,6 +296,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; @@ -302,17 +323,18 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) IPos hash_head = 0; if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || - strm->state->status != INIT_STATE) return Z_STREAM_ERROR; + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; s = strm->state; - strm->adler = adler32(strm->adler, dictionary, dictLength); + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); if (length < MIN_MATCH) return Z_OK; if (length > MAX_DIST(s)) { - length = MAX_DIST(s); -#ifndef USE_DICT_HEAD - dictionary += dictLength - length; /* use the tail of the dictionary */ -#endif + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ } zmemcpy(s->window, dictionary, length); s->strstart = length; @@ -325,7 +347,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) s->ins_h = s->window[0]; UPDATE_HASH(s, s->ins_h, s->window[1]); for (n = 0; n <= length - MIN_MATCH; n++) { - INSERT_STRING(s, n, hash_head); + INSERT_STRING(s, n, hash_head); } if (hash_head) hash_head = 0; /* to make compiler happy */ return Z_OK; @@ -336,9 +358,11 @@ int ZEXPORT deflateReset (strm) z_streamp strm; { deflate_state *s; - + if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ @@ -348,11 +372,15 @@ int ZEXPORT deflateReset (strm) s->pending = 0; s->pending_out = s->pending_buf; - if (s->noheader < 0) { - s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } - s->status = s->noheader ? BUSY_STATE : INIT_STATE; - strm->adler = 1; + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); s->last_flush = Z_NO_FLUSH; _tr_init(s); @@ -361,6 +389,29 @@ int ZEXPORT deflateReset (strm) return Z_OK; } +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + /* ========================================================================= */ int ZEXPORT deflateParams(strm, level, strategy) z_streamp strm; @@ -374,29 +425,91 @@ int ZEXPORT deflateParams(strm, level, strategy) if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; - if (level == Z_DEFAULT_COMPRESSION) { - level = 6; - } - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { - return Z_STREAM_ERROR; +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; } func = configuration_table[s->level].func; if (func != configuration_table[level].func && strm->total_in != 0) { - /* Flush the last buffer: */ - err = deflate(strm, Z_PARTIAL_FLUSH); + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); } if (s->level != level) { - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return err; } +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in @@ -408,7 +521,7 @@ local void putShortMSB (s, b) { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); -} +} /* ========================================================================= * Flush as much pending output as possible. All deflate() output goes @@ -444,14 +557,14 @@ int ZEXPORT deflate (strm, flush) deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_FINISH || flush < 0) { + flush > Z_FINISH || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { + (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); @@ -460,48 +573,206 @@ int ZEXPORT deflate (strm, flush) old_flush = s->last_flush; s->last_flush = flush; - /* Write the zlib header */ + /* Write the header */ if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags = (s->level-1) >> 1; + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); - if (level_flags > 3) level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); + s->status = BUSY_STATE; + putShortMSB(s, header); - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = 1L; + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: */ - s->last_flush = -1; - return Z_OK; - } + s->last_flush = -1; + return Z_OK; + } /* Make sure there is something to do and avoid duplicate consecutive * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUFF_ERROR. + * returning Z_STREAM_END instead of Z_BUF_ERROR. */ } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { + flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } @@ -516,24 +787,24 @@ int ZEXPORT deflate (strm, flush) (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; - bstate = (*(configuration_table[s->level].func))(s, flush); + bstate = (*(configuration_table[s->level].func))(s, flush); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; } if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); @@ -547,25 +818,40 @@ int ZEXPORT deflate (strm, flush) } } flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } } } Assert(strm->avail_out > 0, "bug2"); if (flush != Z_FINISH) return Z_OK; - if (s->noheader) return Z_STREAM_END; + if (s->wrap <= 0) return Z_STREAM_END; - /* Write the zlib trailer (adler32) */ - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ - s->noheader = -1; /* write the trailer only once! */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } @@ -578,8 +864,13 @@ int ZEXPORT deflateEnd (strm) if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; status = strm->state->status; - if (status != INIT_STATE && status != BUSY_STATE && - status != FINISH_STATE) { + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { return Z_STREAM_ERROR; } @@ -618,12 +909,12 @@ int ZEXPORT deflateCopy (dest, source) ss = source->state; - *dest = *source; + zmemcpy(dest, source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; - *ds = *ss; + zmemcpy(ds, ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); @@ -652,7 +943,7 @@ int ZEXPORT deflateCopy (dest, source) ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; -#endif +#endif /* MAXSEG_64K */ } /* =========================================================================== @@ -674,9 +965,14 @@ local int read_buf(strm, buf, size) strm->avail_in -= len; - if (!strm->state->noheader) { + if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, strm->next_in, len); } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif zmemcpy(buf, strm->next_in, len); strm->next_in += len; strm->total_in += len; @@ -707,11 +1003,14 @@ local void lm_init (s) s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; +#ifndef FASTEST #ifdef ASMV match_init(); /* initialize the asm code */ #endif +#endif } +#ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, @@ -725,7 +1024,6 @@ local void lm_init (s) /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ -#ifndef FASTEST local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ @@ -778,7 +1076,12 @@ local uInt longest_match(s, cur_match) match = s->window + cur_match; /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use @@ -863,12 +1166,13 @@ local uInt longest_match(s, cur_match) if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } +#endif /* ASMV */ +#endif /* FASTEST */ -#else /* FASTEST */ /* --------------------------------------------------------------------------- - * Optimized version for level == 1 only + * Optimized version for level == 1 or strategy == Z_RLE only */ -local uInt longest_match(s, cur_match) +local uInt longest_match_fast(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { @@ -906,10 +1210,10 @@ local uInt longest_match(s, cur_match) */ do { } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); @@ -918,10 +1222,8 @@ local uInt longest_match(s, cur_match) if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; - return len <= s->lookahead ? len : s->lookahead; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } -#endif /* FASTEST */ -#endif /* ASMV */ #ifdef DEBUG /* =========================================================================== @@ -936,10 +1238,10 @@ local void check_match(s, start, match, length) if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); + start, match, length); do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); z_error("invalid match"); } if (z_verbose > 1) { @@ -949,7 +1251,7 @@ local void check_match(s, start, match, length) } #else # define check_match(s, start, match, length) -#endif +#endif /* DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. @@ -973,19 +1275,22 @@ local void fill_window(s) more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if strstart == 0 - * and lookahead == 1 (input done one byte at time) - */ - more--; + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ - } else if (s->strstart >= wsize+MAX_DIST(s)) { + if (s->strstart >= wsize+MAX_DIST(s)) { zmemcpy(s->window, s->window+wsize, (unsigned)wsize); s->match_start -= wsize; @@ -998,23 +1303,24 @@ local void fill_window(s) later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); - n = wsize; + n = wsize; #ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); #endif more += wsize; } @@ -1059,8 +1365,8 @@ local void fill_window(s) _tr_flush_block(s, (s->block_start >= 0L ? \ (charf *)&s->window[(unsigned)s->block_start] : \ (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ Tracev((stderr,"[FLUSH]")); \ @@ -1101,32 +1407,32 @@ local block_state deflate_stored(s, flush) if (s->lookahead <= 1) { Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); + s->block_start >= (long)s->w_size, "slide too late"); fill_window(s); if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; if (s->lookahead == 0) break; /* flush the current block */ } - Assert(s->block_start >= 0L, "block gone"); + Assert(s->block_start >= 0L, "block gone"); - s->strstart += s->lookahead; - s->lookahead = 0; + s->strstart += s->lookahead; + s->lookahead = 0; - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become + } + /* Flush if we may have to slide, otherwise block_start may become * negative and the data will be gone: */ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { FLUSH_BLOCK(s, 0); - } + } } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; @@ -1155,8 +1461,8 @@ local block_state deflate_fast(s, flush) if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } + return need_more; + } if (s->lookahead == 0) break; /* flush the current block */ } @@ -1175,10 +1481,19 @@ local block_state deflate_fast(s, flush) * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ - if (s->strategy != Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); } - /* longest_match() sets match_start */ +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ } if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); @@ -1194,7 +1509,7 @@ local block_state deflate_fast(s, flush) #ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in hash table */ + s->match_length--; /* string at strstart already in table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); @@ -1202,10 +1517,10 @@ local block_state deflate_fast(s, flush) * always MIN_MATCH bytes ahead. */ } while (--s->match_length != 0); - s->strstart++; + s->strstart++; } else #endif - { + { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; @@ -1222,7 +1537,7 @@ local block_state deflate_fast(s, flush) Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; - s->strstart++; + s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } @@ -1230,6 +1545,7 @@ local block_state deflate_fast(s, flush) return flush == Z_FINISH ? finish_done : block_done; } +#ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is @@ -1252,8 +1568,8 @@ local block_state deflate_slow(s, flush) if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } + return need_more; + } if (s->lookahead == 0) break; /* flush the current block */ } @@ -1275,17 +1591,19 @@ local block_state deflate_slow(s, flush) * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ - if (s->strategy != Z_HUFFMAN_ONLY) { + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); } - /* longest_match() sets match_start */ + /* longest_match() or longest_match_fast() sets match_start */ if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if (TOO_FAR > 0 && TOO_FAR < 32767) - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) #endif - )) { + )) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. @@ -1303,7 +1621,7 @@ local block_state deflate_slow(s, flush) check_match(s, s->strstart-1, s->prev_match, s->prev_length); _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); + s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. If there is not @@ -1329,8 +1647,8 @@ local block_state deflate_slow(s, flush) * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; @@ -1354,3 +1672,65 @@ local block_state deflate_slow(s, flush) FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/deflate.h b/deflate.h index 962676da8..05a5ab3a2 100644 --- a/deflate.h +++ b/deflate.h @@ -1,6 +1,6 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-1998 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is @@ -10,11 +10,19 @@ /* @(#) $Id$ */ -#ifndef _DEFLATE_H -#define _DEFLATE_H +#ifndef DEFLATE_H +#define DEFLATE_H #include "zutil.h" +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + /* =========================================================================== * Internal compression state. */ @@ -41,6 +49,10 @@ /* All codes must not exceed MAX_BITS bits */ #define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 #define BUSY_STATE 113 #define FINISH_STATE 666 /* Stream status */ @@ -85,9 +97,10 @@ typedef struct internal_state { Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ - int pending; /* nb of bytes in the pending buffer */ - int noheader; /* suppress zlib header and adler32 */ - Byte data_type; /* UNKNOWN, BINARY or ASCII */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ Byte method; /* STORED (for zip only) or DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ @@ -269,7 +282,7 @@ typedef struct internal_state { void _tr_init OF((deflate_state *s)); int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); + int eof)); void _tr_align OF((deflate_state *s)); void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int eof)); @@ -312,7 +325,7 @@ void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) + flush = _tr_tally(s, distance, length) #endif -#endif +#endif /* DEFLATE_H */ diff --git a/example.c b/example.c new file mode 100644 index 000000000..6c8a0ee76 --- /dev/null +++ b/example.c @@ -0,0 +1,565 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2004 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include +#include "zlib.h" + +#ifdef STDC +# include +# include +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/gzio.c b/gzio.c index f7c336a55..7e90f4928 100644 --- a/gzio.c +++ b/gzio.c @@ -1,8 +1,8 @@ /* gzio.c -- IO on .gz files - * Copyright (C) 1995-1998 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h * - * Compile this file with -DNO_DEFLATE to avoid the compression code. + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. */ /* @(#) $Id$ */ @@ -11,7 +11,13 @@ #include "zutil.h" +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL struct internal_state {int dummy;}; /* for buggy compilers */ +#endif #ifndef Z_BUFSIZE # ifdef MAXSEG_64K @@ -24,10 +30,20 @@ struct internal_state {int dummy;}; /* for buggy compilers */ # define Z_PRINTF_BUFSIZE 4096 #endif +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + #define ALLOC(size) malloc(size) #define TRYFREE(p) {if (p) free(p);} -static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ @@ -49,7 +65,11 @@ typedef struct gz_stream { char *path; /* path name for debugging only */ int transparent; /* 1 if input file is not a .gz file */ char mode; /* 'w' or 'r' */ - long startpos; /* start of compressed data in file (header skipped) */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ } gz_stream; @@ -65,7 +85,7 @@ local uLong getLong OF((gz_stream *s)); Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb"). The file is given either by file descriptor or path name (if fd == -1). - gz_open return NULL if the file could not be opened or if there was + gz_open returns NULL if the file could not be opened or if there was insufficient memory to allocate the (de)compression state; errno can be checked to distinguish the two cases (if errno is zero, the zlib error is Z_MEM_ERROR). @@ -97,6 +117,9 @@ local gzFile gz_open (path, mode, fd) s->file = NULL; s->z_err = Z_OK; s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; s->crc = crc32(0L, Z_NULL, 0); s->msg = NULL; s->transparent = 0; @@ -112,19 +135,21 @@ local gzFile gz_open (path, mode, fd) if (*p == 'r') s->mode = 'r'; if (*p == 'w' || *p == 'a') s->mode = 'w'; if (*p >= '0' && *p <= '9') { - level = *p - '0'; - } else if (*p == 'f') { - strategy = Z_FILTERED; - } else if (*p == 'h') { - strategy = Z_HUFFMAN_ONLY; - } else { - *m++ = *p; /* copy the mode */ - } + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } } while (*p++ && m != fmode + sizeof(fmode)); if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; - + if (s->mode == 'w') { -#ifdef NO_DEFLATE +#ifdef NO_GZCOMPRESS err = Z_STREAM_ERROR; #else err = deflateInit2(&(s->stream), level, @@ -163,17 +188,17 @@ local gzFile gz_open (path, mode, fd) */ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); - s->startpos = 10L; - /* We use 10L instead of ftell(s->file) to because ftell causes an + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an * fflush on some systems. This version of the library doesn't use - * startpos anyway in write mode, so this initialization is not + * start anyway in write mode, so this initialization is not * necessary. */ } else { - check_header(s); /* skip the .gz header */ - s->startpos = (ftell(s->file) - s->stream.avail_in); + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; } - + return (gzFile)s; } @@ -195,7 +220,7 @@ gzFile ZEXPORT gzdopen (fd, mode) int fd; const char *mode; { - char name[20]; + char name[46]; /* allow for up to 128-bit integers */ if (fd < 0) return (gzFile)Z_NULL; sprintf(name, "", fd); /* for debugging */ @@ -218,11 +243,11 @@ int ZEXPORT gzsetparams (file, level, strategy) /* Make room to allow flushing */ if (s->stream.avail_out == 0) { - s->stream.next_out = s->outbuf; - if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { - s->z_err = Z_ERRNO; - } - s->stream.avail_out = Z_BUFSIZE; + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; } return deflateParams (&(s->stream), level, strategy); @@ -238,14 +263,14 @@ local int get_byte(s) { if (s->z_eof) return EOF; if (s->stream.avail_in == 0) { - errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); - if (s->stream.avail_in == 0) { - s->z_eof = 1; - if (ferror(s->file)) s->z_err = Z_ERRNO; - return EOF; - } - s->stream.next_in = s->inbuf; + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; } s->stream.avail_in--; return *(s->stream.next_in)++; @@ -268,43 +293,57 @@ local void check_header(s) uInt len; int c; - /* Check the gzip magic header */ - for (len = 0; len < 2; len++) { - c = get_byte(s); - if (c != gz_magic[len]) { - if (len != 0) s->stream.avail_in++, s->stream.next_in--; - if (c != EOF) { - s->stream.avail_in++, s->stream.next_in--; - s->transparent = 1; - } - s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; - return; - } + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ method = get_byte(s); flags = get_byte(s); if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - s->z_err = Z_DATA_ERROR; - return; + s->z_err = Z_DATA_ERROR; + return; } /* Discard time, xflags and OS code: */ for (len = 0; len < 6; len++) (void)get_byte(s); if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ - len = (uInt)get_byte(s); - len += ((uInt)get_byte(s))<<8; - /* len is garbage if EOF but the loop below will quit anyway */ - while (len-- != 0 && get_byte(s) != EOF) ; + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; } if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ - while ((c = get_byte(s)) != 0 && c != EOF) ; + while ((c = get_byte(s)) != 0 && c != EOF) ; } if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ - while ((c = get_byte(s)) != 0 && c != EOF) ; + while ((c = get_byte(s)) != 0 && c != EOF) ; } if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ - for (len = 0; len < 2; len++) (void)get_byte(s); + for (len = 0; len < 2; len++) (void)get_byte(s); } s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; } @@ -323,21 +362,21 @@ local int destroy (s) TRYFREE(s->msg); if (s->stream.state != NULL) { - if (s->mode == 'w') { -#ifdef NO_DEFLATE - err = Z_STREAM_ERROR; + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; #else - err = deflateEnd(&(s->stream)); + err = deflateEnd(&(s->stream)); #endif - } else if (s->mode == 'r') { - err = inflateEnd(&(s->stream)); - } + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } } if (s->file != NULL && fclose(s->file)) { #ifdef ESPIPE - if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ #endif - err = Z_ERRNO; + err = Z_ERRNO; } if (s->z_err < 0) err = s->z_err; @@ -370,74 +409,89 @@ int ZEXPORT gzread (file, buf, len) s->stream.next_out = (Bytef*)buf; s->stream.avail_out = len; + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + while (s->stream.avail_out != 0) { - if (s->transparent) { - /* Copy first the lookahead bytes: */ - uInt n = s->stream.avail_in; - if (n > s->stream.avail_out) n = s->stream.avail_out; - if (n > 0) { - zmemcpy(s->stream.next_out, s->stream.next_in, n); - next_out += n; - s->stream.next_out = next_out; - s->stream.next_in += n; - s->stream.avail_out -= n; - s->stream.avail_in -= n; - } - if (s->stream.avail_out > 0) { - s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, - s->file); - } - len -= s->stream.avail_out; - s->stream.total_in += (uLong)len; - s->stream.total_out += (uLong)len; + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; if (len == 0) s->z_eof = 1; - return (int)len; - } + return (int)len; + } if (s->stream.avail_in == 0 && !s->z_eof) { errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); if (s->stream.avail_in == 0) { s->z_eof = 1; - if (ferror(s->file)) { - s->z_err = Z_ERRNO; - break; - } + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } } s->stream.next_in = s->inbuf; } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; - if (s->z_err == Z_STREAM_END) { - /* Check CRC and original size */ - s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); - start = s->stream.next_out; + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; - if (getLong(s) != s->crc) { - s->z_err = Z_DATA_ERROR; - } else { - (void)getLong(s); - /* The uncompressed length returned by above getlong() may - * be different from s->stream.total_out) in case of - * concatenated .gz files. Check for such files: - */ - check_header(s); - if (s->z_err == Z_OK) { - uLong total_in = s->stream.total_in; - uLong total_out = s->stream.total_out; - - inflateReset(&(s->stream)); - s->stream.total_in = total_in; - s->stream.total_out = total_out; - s->crc = crc32(0L, Z_NULL, 0); - } - } - } - if (s->z_err != Z_OK || s->z_eof) break; + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; } s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; return (int)(len - s->stream.avail_out); } @@ -455,6 +509,25 @@ int ZEXPORT gzgetc(file) } +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + /* =========================================================================== Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an @@ -478,14 +551,14 @@ char * ZEXPORT gzgets(file, buf, len) } -#ifndef NO_DEFLATE +#ifndef NO_GZCOMPRESS /* =========================================================================== Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of bytes actually written (0 in case of error). */ int ZEXPORT gzwrite (file, buf, len) gzFile file; - const voidp buf; + voidpc buf; unsigned len; { gz_stream *s = (gz_stream*)file; @@ -506,7 +579,11 @@ int ZEXPORT gzwrite (file, buf, len) } s->stream.avail_out = Z_BUFSIZE; } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; if (s->z_err != Z_OK) break; } s->crc = crc32(s->crc, (const Bytef *)buf, len); @@ -514,6 +591,7 @@ int ZEXPORT gzwrite (file, buf, len) return (int)(len - s->stream.avail_in); } + /* =========================================================================== Converts, formats, and writes the args to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of @@ -528,40 +606,67 @@ int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) va_list va; int len; + buf[sizeof(buf) - 1] = 0; va_start(va, format); -#ifdef HAS_vsnprintf - (void)vsnprintf(buf, sizeof(buf), format, va); -#else +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void (void)vsprintf(buf, format, va); -#endif va_end(va); - len = strlen(buf); /* some *sprintf don't return the nb of bytes written */ - if (len <= 0) return 0; - + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; return gzwrite(file, buf, (unsigned)len); } #else /* not ANSI C */ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) gzFile file; const char *format; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; { char buf[Z_PRINTF_BUFSIZE]; int len; -#ifdef HAS_snprintf - snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -#else + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif #endif - len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */ - if (len <= 0) return 0; - + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; return gzwrite(file, buf, len); } #endif @@ -621,16 +726,18 @@ local int do_flush (file, flush) s->stream.avail_out = Z_BUFSIZE; } if (done) break; + s->out += s->stream.avail_out; s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; - /* Ignore the second of two consecutive flushes: */ - if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; /* deflate has finished flushing only when it hasn't used up - * all the available space in the output buffer: + * all the available space in the output buffer: */ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); - + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; } return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; @@ -647,7 +754,7 @@ int ZEXPORT gzflush (file, flush) fflush(s->file); return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; } -#endif /* NO_DEFLATE */ +#endif /* NO_GZCOMPRESS */ /* =========================================================================== Sets the starting position for the next gzread or gzwrite on the given @@ -665,99 +772,105 @@ z_off_t ZEXPORT gzseek (file, offset, whence) gz_stream *s = (gz_stream*)file; if (s == NULL || whence == SEEK_END || - s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { - return -1L; + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; } - + if (s->mode == 'w') { -#ifdef NO_DEFLATE - return -1L; +#ifdef NO_GZCOMPRESS + return -1L; #else - if (whence == SEEK_SET) { - offset -= s->stream.total_in; - } - if (offset < 0) return -1L; + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; - /* At this point, offset is the number of zero bytes to write. */ - if (s->inbuf == Z_NULL) { - s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ - zmemzero(s->inbuf, Z_BUFSIZE); - } - while (offset > 0) { - uInt size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (uInt)offset; + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; - size = gzwrite(file, s->inbuf, size); - if (size == 0) return -1L; + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; - offset -= size; - } - return (z_off_t)s->stream.total_in; + offset -= size; + } + return s->in; #endif } /* Rest of function is for reading only */ /* compute absolute position */ if (whence == SEEK_CUR) { - offset += s->stream.total_out; + offset += s->out; } if (offset < 0) return -1L; if (s->transparent) { - /* map to fseek */ - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; - s->stream.total_in = s->stream.total_out = (uLong)offset; - return offset; + s->in = s->out = offset; + return offset; } /* For a negative seek, rewind and use positive seek */ - if ((uLong)offset >= s->stream.total_out) { - offset -= s->stream.total_out; + if (offset >= s->out) { + offset -= s->out; } else if (gzrewind(file) < 0) { - return -1L; + return -1L; } /* offset is now the number of bytes to skip. */ if (offset != 0 && s->outbuf == Z_NULL) { - s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; } while (offset > 0) { - int size = Z_BUFSIZE; - if (offset < Z_BUFSIZE) size = (int)offset; + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; - size = gzread(file, s->outbuf, (uInt)size); - if (size <= 0) return -1L; - offset -= size; + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; } - return (z_off_t)s->stream.total_out; + return s->out; } /* =========================================================================== - Rewinds input file. + Rewinds input file. */ int ZEXPORT gzrewind (file) gzFile file; { gz_stream *s = (gz_stream*)file; - + if (s == NULL || s->mode != 'r') return -1; s->z_err = Z_OK; s->z_eof = 0; + s->back = EOF; s->stream.avail_in = 0; s->stream.next_in = s->inbuf; s->crc = crc32(0L, Z_NULL, 0); - - if (s->startpos == 0) { /* not a compressed file */ - rewind(s->file); - return 0; - } - - (void) inflateReset(&s->stream); - return fseek(s->file, s->startpos, SEEK_SET); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); } /* =========================================================================== @@ -779,8 +892,26 @@ int ZEXPORT gzeof (file) gzFile file; { gz_stream *s = (gz_stream*)file; - - return (s == NULL || s->mode != 'r') ? 0 : s->z_eof; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; } /* =========================================================================== @@ -822,33 +953,38 @@ local uLong getLong (s) int ZEXPORT gzclose (file) gzFile file; { - int err; gz_stream *s = (gz_stream*)file; if (s == NULL) return Z_STREAM_ERROR; if (s->mode == 'w') { -#ifdef NO_DEFLATE - return Z_STREAM_ERROR; +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; #else - err = do_flush (file, Z_FINISH); - if (err != Z_OK) return destroy((gz_stream*)file); + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); putLong (s->file, s->crc); - putLong (s->file, s->stream.total_in); + putLong (s->file, (uLong)(s->in & 0xffffffff)); #endif } return destroy((gz_stream*)file); } +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + /* =========================================================================== - Returns the error message for the last error which occured on the + Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an - error occured in the file system and not in the compression library, + error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. */ -const char* ZEXPORT gzerror (file, errnum) +const char * ZEXPORT gzerror (file, errnum) gzFile file; int *errnum; { @@ -862,14 +998,29 @@ const char* ZEXPORT gzerror (file, errnum) *errnum = s->z_err; if (*errnum == Z_OK) return (const char*)""; - m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); TRYFREE(s->msg); s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); strcpy(s->msg, s->path); strcat(s->msg, ": "); strcat(s->msg, m); return (const char*)s->msg; } + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/infback.c b/infback.c new file mode 100644 index 000000000..455dbc9ee --- /dev/null +++ b/infback.c @@ -0,0 +1,623 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/infblock.c b/infblock.c deleted file mode 100644 index f4920faa5..000000000 --- a/infblock.c +++ /dev/null @@ -1,398 +0,0 @@ -/* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "infblock.h" -#include "inftrees.h" -#include "infcodes.h" -#include "infutil.h" - -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* Table for deflate from PKZIP's appnote.txt. */ -local const uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -void inflate_blocks_reset(s, z, c) -inflate_blocks_statef *s; -z_streamp z; -uLongf *c; -{ - if (c != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens); - if (s->mode == CODES) - inflate_codes_free(s->sub.decode.codes, z); - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); - Tracev((stderr, "inflate: blocks reset\n")); -} - - -inflate_blocks_statef *inflate_blocks_new(z, c, w) -z_streamp z; -check_func c; -uInt w; -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->hufts = - (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) - { - ZFREE(z, s); - return Z_NULL; - } - if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s->hufts); - ZFREE(z, s); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Tracev((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, Z_NULL); - return s; -} - - -int inflate_blocks(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - Tracev((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Tracev((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td, z); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BAD; - z->msg = (char*)"invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) - { - s->mode = BAD; - z->msg = (char*)"invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = BAD; - z->msg = (char*)"too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, s->hufts, z); - if (t != Z_OK) - { - ZFREE(z, s->sub.trees.blens); - r = t; - if (r == Z_DATA_ERROR) - s->mode = BAD; - LEAVE - } - s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->bits; - c = h->base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - ZFREE(z, s->sub.trees.blens); - s->mode = BAD; - z->msg = (char*)"invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, - s->hufts, z); - ZFREE(z, s->sub.trees.blens); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - s->mode = BAD; - r = t; - LEAVE - } - Tracev((stderr, "inflate: trees ok\n")); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.codes = c; - } - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONE; - case DONE: - r = Z_STREAM_END; - LEAVE - case BAD: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -int inflate_blocks_free(s, z) -inflate_blocks_statef *s; -z_streamp z; -{ - inflate_blocks_reset(s, z, Z_NULL); - ZFREE(z, s->window); - ZFREE(z, s->hufts); - ZFREE(z, s); - Tracev((stderr, "inflate: blocks freed\n")); - return Z_OK; -} - - -void inflate_set_dictionary(s, d, n) -inflate_blocks_statef *s; -const Bytef *d; -uInt n; -{ - zmemcpy(s->window, d, n); - s->read = s->write = s->window + n; -} - - -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. - * IN assertion: s != Z_NULL - */ -int inflate_blocks_sync_point(s) -inflate_blocks_statef *s; -{ - return s->mode == LENS; -} diff --git a/infblock.h b/infblock.h deleted file mode 100644 index bd25c8075..000000000 --- a/infblock.h +++ /dev/null @@ -1,39 +0,0 @@ -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_blocks_state; -typedef struct inflate_blocks_state FAR inflate_blocks_statef; - -extern inflate_blocks_statef * inflate_blocks_new OF(( - z_streamp z, - check_func c, /* check function */ - uInt w)); /* window size */ - -extern int inflate_blocks OF(( - inflate_blocks_statef *, - z_streamp , - int)); /* initial return code */ - -extern void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_streamp , - uLongf *)); /* check value on output */ - -extern int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_streamp)); - -extern void inflate_set_dictionary OF(( - inflate_blocks_statef *s, - const Bytef *d, /* dictionary */ - uInt n)); /* dictionary length */ - -extern int inflate_blocks_sync_point OF(( - inflate_blocks_statef *s)); diff --git a/infcodes.c b/infcodes.c deleted file mode 100644 index d4e5ee9a5..000000000 --- a/infcodes.c +++ /dev/null @@ -1,257 +0,0 @@ -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "infblock.h" -#include "infcodes.h" -#include "infutil.h" -#include "inffast.h" - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ -inflate_codes_mode; - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - inflate_codes_mode mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; - - -inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) -uInt bl, bd; -inflate_huft *tl; -inflate_huft *td; /* need separate declaration for Borland C++ */ -z_streamp z; -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); - } - return c; -} - - -int inflate_codes(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Bytef *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - if (e & 32) /* end of block */ - { - Tracevv((stderr, "inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else - f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); -#endif - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ -#endif -} - - -void inflate_codes_free(c, z) -inflate_codes_statef *c; -z_streamp z; -{ - ZFREE(z, c); - Tracev((stderr, "inflate: codes free\n")); -} diff --git a/infcodes.h b/infcodes.h deleted file mode 100644 index 6c750d896..000000000 --- a/infcodes.h +++ /dev/null @@ -1,27 +0,0 @@ -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_codes_state; -typedef struct inflate_codes_state FAR inflate_codes_statef; - -extern inflate_codes_statef *inflate_codes_new OF(( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_streamp )); - -extern int inflate_codes OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -extern void inflate_codes_free OF(( - inflate_codes_statef *, - z_streamp )); - diff --git a/inffast.c b/inffast.c index 61a78ee93..bbee92ed1 100644 --- a/inffast.c +++ b/inffast.c @@ -1,170 +1,318 @@ -/* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" -#include "infblock.h" -#include "infcodes.h" -#include "infutil.h" +#include "inflate.h" #include "inffast.h" -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ +#ifndef ASMINF -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ + Entry assumptions: -int inflate_fast(bl, bd, tl, td, s, z) -uInt bl, bd; -inflate_huft *tl; -inflate_huft *td; /* need separate declaration for Borland C++ */ -inflate_blocks_statef *s; -z_streamp z; + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ { - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Bytef *r; /* copy source pointer */ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ - /* load input, output, bit values */ - LOAD + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; - /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ - { - e = d - (uInt)(q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ - { - c -= e; /* copy to end of window */ - do { - *q++ = *r++; - } while (--e); - r = s->window; /* copy rest from start of window */ - } - } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); - break; - } - else if ((e & 64) == 0) - { - t += t->base; - e = (t += ((uInt)b & inflate_mask[e]))->exop; - } - else - { - z->msg = (char*)"invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - t += t->base; - if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; } - } - else if (e & 32) - { - Tracevv((stderr, "inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = (char*)"invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; } + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/inffast.h b/inffast.h index 8facec553..1e88d2d97 100644 --- a/inffast.h +++ b/inffast.h @@ -1,6 +1,6 @@ /* inffast.h -- header to use inffast.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is @@ -8,10 +8,4 @@ subject to change. Applications should only use zlib.h. */ -extern int inflate_fast OF(( - uInt, - uInt, - inflate_huft *, - inflate_huft *, - inflate_blocks_statef *, - z_streamp )); +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/inffixed.h b/inffixed.h index 77f7e7631..75ed4b597 100644 --- a/inffixed.h +++ b/inffixed.h @@ -1,151 +1,94 @@ -/* inffixed.h -- table for decoding fixed codes - * Generated automatically by the maketree.c program - */ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ -local uInt fixed_bl = 9; -local uInt fixed_bd = 5; -local inflate_huft fixed_tl[] = { - {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, - {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, - {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, - {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, - {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, - {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, - {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, - {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, - {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, - {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, - {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, - {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, - {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, - {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, - {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, - {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, - {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, - {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, - {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, - {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, - {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, - {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, - {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, - {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, - {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, - {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, - {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, - {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, - {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, - {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, - {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, - {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, - {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, - {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, - {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, - {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, - {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, - {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, - {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, - {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, - {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, - {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, - {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, - {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, - {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, - {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, - {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, - {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, - {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, - {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, - {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, - {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, - {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, - {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, - {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, - {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, - {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, - {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, - {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, - {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, - {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, - {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, - {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, - {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, - {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, - {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, - {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, - {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, - {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, - {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, - {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, - {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, - {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, - {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, - {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, - {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, - {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, - {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, - {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, - {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, - {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, - {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, - {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, - {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, - {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, - {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, - {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, - {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, - {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, - {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, - {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, - {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, - {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, - {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, - {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, - {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, - {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, - {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, - {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, - {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, - {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, - {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, - {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, - {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, - {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, - {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, - {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, - {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, - {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, - {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, - {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, - {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, - {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, - {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, - {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, - {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, - {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, - {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, - {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, - {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, - {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, - {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, - {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, - {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, - {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} - }; -local inflate_huft fixed_td[] = { - {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, - {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, - {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, - {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, - {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, - {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, - {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, - {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} - }; + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/inflate.c b/inflate.c index bbefae46e..792fdee8e 100644 --- a/inflate.c +++ b/inflate.c @@ -1,365 +1,1368 @@ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "zutil.h" -#include "infblock.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" -struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ - -typedef enum { - METHOD, /* waiting for method byte */ - FLAG, /* waiting for flag byte */ - DICT4, /* four dictionary check bytes to go */ - DICT3, /* three dictionary check bytes to go */ - DICT2, /* two dictionary check bytes to go */ - DICT1, /* one dictionary check byte to go */ - DICT0, /* waiting for inflateSetDictionary */ - BLOCKS, /* decompressing blocks */ - CHECK4, /* four check bytes to go */ - CHECK3, /* three check bytes to go */ - CHECK2, /* two check bytes to go */ - CHECK1, /* one check byte to go */ - DONE, /* finished check, done */ - BAD} /* got an error--stay here */ -inflate_mode; - -/* inflate private state */ -struct internal_state { - - /* mode */ - inflate_mode mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - - -int ZEXPORT inflateReset(z) -z_streamp z; -{ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, Z_NULL); - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - - -int ZEXPORT inflateEnd(z) -z_streamp z; -{ - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z); - ZFREE(z, z->state); - z->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - - -int ZEXPORT inflateInit2_(z, w, version, stream_size) -z_streamp z; -int w; -const char *version; -int stream_size; -{ - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != sizeof(z_stream)) - return Z_VERSION_ERROR; - - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; - z->msg = Z_NULL; - if (z->zalloc == Z_NULL) - { - z->zalloc = zcalloc; - z->opaque = (voidpf)0; - } - if (z->zfree == Z_NULL) z->zfree = zcfree; - if ((z->state = (struct internal_state FAR *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Tracev((stderr, "inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; -} - - -int ZEXPORT inflateInit_(z, version, stream_size) -z_streamp z; -const char *version; -int stream_size; -{ - return inflateInit2_(z, DEF_WBITS, version, stream_size); -} - - -#define NEEDBYTE {if(z->avail_in==0)return r;r=f;} -#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int ZEXPORT inflate(z, f) -z_streamp z; -int f; -{ - int r; - uInt b; - - if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) - return Z_STREAM_ERROR; - f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (r == Z_DATA_ERROR) - { - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r == Z_OK) - r = f; - if (r != Z_STREAM_END) - return r; - r = f; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = DONE; - break; - } - z->state->mode = CHECK4; - case CHECK4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = CHECK3; - case CHECK3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = CHECK2; - case CHECK2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = CHECK1; - case CHECK1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = BAD; - z->msg = (char*)"incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Tracev((stderr, "inflate: zlib check ok\n")); - z->state->mode = DONE; - case DONE: - return Z_STREAM_END; - case METHOD: - NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) - { - z->state->mode = BAD; - z->msg = (char*)"unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = BAD; - z->msg = (char*)"invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = FLAG; - case FLAG: - NEEDBYTE - b = NEXTBYTE; - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = BAD; - z->msg = (char*)"incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Tracev((stderr, "inflate: zlib header ok\n")); - if (!(b & PRESET_DICT)) - { - z->state->mode = BLOCKS; - break; - } - z->state->mode = DICT4; - case DICT4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = DICT3; - case DICT3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = DICT2; - case DICT2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = DICT1; - case DICT1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - z->adler = z->state->sub.check.need; - z->state->mode = DICT0; - return Z_NEED_DICT; - case DICT0: - z->state->mode = BAD; - z->msg = (char*)"need dictionary"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_STREAM_ERROR; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif #endif -} +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); -int ZEXPORT inflateSetDictionary(z, dictionary, dictLength) -z_streamp z; -const Bytef *dictionary; -uInt dictLength; +int ZEXPORT inflateReset(strm) +z_streamp strm; { - uInt length = dictLength; + struct inflate_state FAR *state; - if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) - return Z_STREAM_ERROR; - - if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; - z->adler = 1L; - - if (length >= ((uInt)1<state->wbits)) - { - length = (1<state->wbits)-1; - dictionary += dictLength - length; - } - inflate_set_dictionary(z->state->blocks, dictionary, length); - z->state->mode = BLOCKS; - return Z_OK; + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; } - -int ZEXPORT inflateSync(z) -z_streamp z; +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; { - uInt n; /* number of bytes to look at */ - Bytef *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ + struct inflate_state FAR *state; - /* set up */ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != BAD) - { - z->state->mode = BAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - static const Byte mark[4] = {0, 0, 0xff, 0xff}; - if (*p == mark[m]) - m++; - else if (*p) - m = 0; - else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += p - z->next_in; - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) - return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; - return Z_OK; + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; } +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH - * but removes the length bytes of the resulting empty stored block. When - * decompressing, PPP checks that at the end of input packet, inflate is - * waiting for these length bytes. + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. */ -int ZEXPORT inflateSyncPoint(z) -z_streamp z; +local void fixedtables(state) +struct inflate_state FAR *state; { - if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) - return Z_STREAM_ERROR; - return inflate_blocks_sync_point(z->state->blocks); +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; } diff --git a/inflate.h b/inflate.h new file mode 100644 index 000000000..07bd3e78a --- /dev/null +++ b/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/inftrees.c b/inftrees.c index ef1e0b6b8..8a9c13ff0 100644 --- a/inftrees.c +++ b/inftrees.c @@ -1,455 +1,329 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" -#if !defined(BUILDFIXED) && !defined(STDC) -# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */ -#endif +#define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ -struct internal_state {int dummy;}; /* for buggy compilers */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - - -local int huft_build OF(( - uIntf *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - const uIntf *, /* list of base values for non-simple codes */ - const uIntf *, /* list of extra bits for non-simple codes */ - inflate_huft * FAR*,/* result: starting table */ - uIntf *, /* maximum lookup bits (returns actual) */ - inflate_huft *, /* space for trees */ - uInt *, /* hufts used in space */ - uIntf * )); /* space for values */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* see note #13 above about 258 */ -local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ -local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -local const uInt cpdext[30] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; /* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ - -local int huft_build(b, n, s, d, e, t, m, hp, hn, v) -uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ -uInt n; /* number of codes (assumed <= 288) */ -uInt s; /* number of simple-valued codes (0..s-1) */ -const uIntf *d; /* list of base values for non-simple codes */ -const uIntf *e; /* list of extra bits for non-simple codes */ -inflate_huft * FAR *t; /* result: starting table */ -uIntf *m; /* maximum lookup bits, returns actual */ -inflate_huft *hp; /* space for trees */ -uInt *hn; /* hufts used in space */ -uIntf *v; /* working area: values in order of bit length */ -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - lengths), or Z_MEM_ERROR if not enough memory. */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; { + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ - register uIntf *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uIntf *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - n = x[g]; /* set n to length of v */ + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ - z = 0; /* ditto */ + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ - /* compute minimum size table less than or equal to l bits */ - z = g - w; - z = z > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; } - z = 1 << j; /* table entries for j-bit table */ - /* allocate new table */ - if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ - return Z_MEM_ERROR; /* not enough memory */ - u[h] = q = hp + *hn; - *hn += z; + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - j = i >> (w - l); - r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ - u[h-1][j] = r; /* connect to last table */ + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; } else - *t = q; /* first table is returned result */ - } + huff = 0; - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; + /* increment past last table */ + next += min; /* here min is 1 << curr */ - /* backup over finished tables */ - mask = (1 << w) - 1; /* needed on HP, cc -O bug */ - while ((i & mask) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - mask = (1 << w) - 1; - } + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } } - } + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -int inflate_trees_bits(c, bb, tb, hp, z) -uIntf *c; /* 19 code lengths */ -uIntf *bb; /* bits tree desired/actual depth */ -inflate_huft * FAR *tb; /* bits tree result */ -inflate_huft *hp; /* space for trees */ -z_streamp z; /* for messages */ -{ - int r; - uInt hn = 0; /* hufts used in space */ - uIntf *v; /* work area for huft_build */ - - if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, - tb, bb, hp, &hn, v); - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR || *bb == 0) - { - z->msg = (char*)"incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; -} - - -int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) -uInt nl; /* number of literal/length codes */ -uInt nd; /* number of distance codes */ -uIntf *c; /* that many (total) code lengths */ -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -inflate_huft *hp; /* space for trees */ -z_streamp z; /* for messages */ -{ - int r; - uInt hn = 0; /* hufts used in space */ - uIntf *v; /* work area for huft_build */ - - /* allocate work area */ - if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - - /* build literal/length tree */ - r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); - if (r != Z_OK || *bl == 0) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed literal/length tree"; - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; - } - - /* build distance tree */ - r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); - if (r != Z_OK || (*bd == 0 && nl > 257)) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed distance tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - z->msg = (char*)"incomplete distance tree"; - r = Z_DATA_ERROR; - } - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"empty distance tree with lengths"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; -#endif - } - - /* done */ - ZFREE(z, v); - return Z_OK; -} - - -/* build fixed tables only once--keep them here */ -#ifdef BUILDFIXED -local int fixed_built = 0; -#define FIXEDH 544 /* number of hufts used by fixed tables */ -local inflate_huft fixed_mem[FIXEDH]; -local uInt fixed_bl; -local uInt fixed_bd; -local inflate_huft *fixed_tl; -local inflate_huft *fixed_td; -#else -#include "inffixed.h" -#endif - - -int inflate_trees_fixed(bl, bd, tl, td, z) -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -z_streamp z; /* for memory allocation */ -{ -#ifdef BUILDFIXED - /* build fixed tables if not already */ - if (!fixed_built) - { - int k; /* temporary variable */ - uInt f = 0; /* number of hufts used in fixed_mem */ - uIntf *c; /* length list for huft_build */ - uIntf *v; /* work area for huft_build */ - - /* allocate memory */ - if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - { - ZFREE(z, c); - return Z_MEM_ERROR; - } - - /* literal table */ - for (k = 0; k < 144; k++) - c[k] = 8; - for (; k < 256; k++) - c[k] = 9; - for (; k < 280; k++) - c[k] = 7; - for (; k < 288; k++) - c[k] = 8; - fixed_bl = 9; - huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, - fixed_mem, &f, v); - - /* distance table */ - for (k = 0; k < 30; k++) - c[k] = 5; - fixed_bd = 5; - huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, - fixed_mem, &f, v); - - /* done */ - ZFREE(z, v); - ZFREE(z, c); - fixed_built = 1; - } -#endif - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; } diff --git a/inftrees.h b/inftrees.h index 85853e097..b1104c87e 100644 --- a/inftrees.h +++ b/inftrees.h @@ -1,6 +1,6 @@ /* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is @@ -8,51 +8,48 @@ subject to change. Applications should only use zlib.h. */ -/* Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). */ +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; -typedef struct inflate_huft_s FAR inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; /* number of extra bits or operation */ - Byte Bits; /* number of bits in this code or subcode */ - } what; - uInt pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit int's) */ - uInt base; /* literal, length base, distance base, - or table offset */ -}; +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ /* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1004 huft structures (850 for length/literals - and 154 for distances, the latter actually the result of an - exhaustive search). The actual maximum is not known, but the - value below is more than safe. */ -#define MANY 1440 + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 -extern int inflate_trees_bits OF(( - uIntf *, /* 19 code lengths */ - uIntf *, /* bits tree desired/actual depth */ - inflate_huft * FAR *, /* bits tree result */ - inflate_huft *, /* space for trees */ - z_streamp)); /* for messages */ +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; -extern int inflate_trees_dynamic OF(( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uIntf *, /* that many (total) code lengths */ - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - inflate_huft *, /* space for trees */ - z_streamp)); /* for messages */ - -extern int inflate_trees_fixed OF(( - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - z_streamp)); /* for memory allocation */ +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/infutil.c b/infutil.c deleted file mode 100644 index 824dab571..000000000 --- a/infutil.c +++ /dev/null @@ -1,87 +0,0 @@ -/* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "infblock.h" -#include "inftrees.h" -#include "infcodes.h" -#include "infutil.h" - -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ - -/* And'ing with mask[n] masks the lower n bits */ -uInt inflate_mask[17] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - - -/* copy as much as possible from the sliding window to the output area */ -int inflate_flush(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt n; - Bytef *p; - Bytef *q; - - /* local copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as far as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy as far as end of window */ - zmemcpy(p, q, n); - p += n; - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - zmemcpy(p, q, n); - p += n; - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} diff --git a/infutil.h b/infutil.h deleted file mode 100644 index 99d1135d0..000000000 --- a/infutil.h +++ /dev/null @@ -1,98 +0,0 @@ -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -#ifndef _INFUTIL_H -#define _INFUTIL_H - -typedef enum { - TYPE, /* get type bits (3, including end bit) */ - LENS, /* get lengths for stored */ - STORED, /* processing stored block */ - TABLE, /* get table lengths */ - BTREE, /* get bit lengths tree for a dynamic block */ - DTREE, /* get length, distance trees for a dynamic block */ - CODES, /* processing fixed or dynamic block */ - DRY, /* output remaining window bytes */ - DONE, /* finished last block, done */ - BAD} /* got a data error--stuck here */ -inflate_block_mode; - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - inflate_block_mode mode; /* current inflate_block mode */ - - /* mode dependent information */ - union { - uInt left; /* if STORED, bytes left to copy */ - struct { - uInt table; /* table lengths (14 bits) */ - uInt index; /* index into blens (or border) */ - uIntf *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_codes_statef - *codes; - } decode; /* if CODES, current state */ - } sub; /* submode */ - uInt last; /* true if this block is the last block */ - - /* mode independent information */ - uInt bitk; /* bits in bit buffer */ - uLong bitb; /* bit buffer */ - inflate_huft *hufts; /* single malloc for tree space */ - Bytef *window; /* sliding window */ - Bytef *end; /* one byte after sliding window */ - Bytef *read; /* window read pointer */ - Bytef *write; /* window write pointer */ - check_func checkfn; /* check function */ - uLong check; /* check on output */ - -}; - - -/* defines for inflate input/output */ -/* update pointers and return */ -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} -/* get bytes and bits */ -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} -#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -/* load local pointers */ -#define LOAD {LOADIN LOADOUT} - -/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ -extern uInt inflate_mask[17]; - -/* copy as much as possible from the sliding window to the output area */ -extern int inflate_flush OF(( - inflate_blocks_statef *, - z_streamp , - int)); - -struct internal_state {int dummy;}; /* for buggy compilers */ - -#endif diff --git a/minigzip.c b/minigzip.c new file mode 100644 index 000000000..4524b96a1 --- /dev/null +++ b/minigzip.c @@ -0,0 +1,322 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* @(#) $Id$ */ + +#include +#include "zlib.h" + +#ifdef STDC +# include +# include +#endif + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fileno */ +#endif + +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + uInt len = (uInt)strlen(file); + + strcpy(buf, file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + strcat(infile, GZ_SUFFIX); + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-d] [-f] [-h] [-r] [-1 to -9] [files...] + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -r : compress with Z_RLE + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int uncompr = 0; + gzFile file; + char outmode[20]; + + strcpy(outmode, "wb6 "); + + prog = argv[0]; + argc--, argv++; + + while (argc > 0) { + if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if (strcmp(*argv, "-r") == 0) + outmode[3] = 'R'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (outmode[3] == ' ') + outmode[3] = 0; + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + do { + if (uncompr) { + file_uncompress(*argv); + } else { + file_compress(*argv, outmode); + } + } while (argv++, --argc); + } + return 0; +} diff --git a/png.c b/png.c index 380c19c8c..608ea2ce7 100644 --- a/png.c +++ b/png.c @@ -1,11 +1,11 @@ /* png.c - location for general purpose libpng functions * - * libpng version 1.2.4 - July 8, 2002 - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * libpng version 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * */ #define PNG_INTERNAL @@ -13,14 +13,14 @@ #include "png.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef version_1_2_4 Your_png_h_is_not_version_1_2_4; +typedef version_1_2_8 Your_png_h_is_not_version_1_2_8; /* Version information for C files. This had better match the version * string defined in png.h. */ #ifdef PNG_USE_GLOBAL_ARRAYS /* png_libpng_ver was changed to a function in version 1.0.5c */ -const char png_libpng_ver[18] = "1.2.4"; +const char png_libpng_ver[18] = PNG_LIBPNG_VER_STRING; /* png_sig was changed to a function in version 1.0.5c */ /* Place to hold the signature string for a PNG file. */ @@ -80,7 +80,7 @@ const int FARDATA png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; const int FARDATA png_pass_dsp_mask[] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; -#endif +#endif /* PNG_USE_GLOBAL_ARRAYS */ /* Tells libpng that we have already handled the first "num_bytes" bytes * of the PNG file signature. If the PNG data is embedded into another @@ -136,22 +136,29 @@ png_check_sig(png_bytep sig, int num) /* Function to allocate memory for zlib and clear it to 0. */ #ifdef PNG_1_0_X -void PNGAPI +voidpf PNGAPI #else voidpf /* private */ #endif png_zalloc(voidpf png_ptr, uInt items, uInt size) { - png_uint_32 num_bytes = (png_uint_32)items * size; png_voidp ptr; png_structp p=png_ptr; png_uint_32 save_flags=p->flags; + png_uint_32 num_bytes; + + if (items > PNG_UINT_32_MAX/size) + { + png_warning (png_ptr, "Potential overflow in png_zalloc()"); + return (NULL); + } + num_bytes = (png_uint_32)items * size; p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes); p->flags=save_flags; -#ifndef PNG_NO_ZALLOC_ZERO +#if defined(PNG_1_0_X) && !defined(PNG_NO_ZALLOC_ZERO) if (ptr == NULL) return ((voidpf)ptr); @@ -217,7 +224,7 @@ png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length) /* Allocate the memory for an info_struct for the application. We don't * really need the png_ptr, but it could potentially be useful in the - * future. This should be used in favour of malloc(sizeof(png_info)) + * future. This should be used in favour of malloc(png_sizeof(png_info)) * and png_info_init() so that applications that want to use a shared * libpng don't have to be recompiled if png_info changes size. */ @@ -235,7 +242,7 @@ png_create_info_struct(png_structp png_ptr) info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); #endif if (info_ptr != NULL) - png_info_init_3(&info_ptr, sizeof(png_info)); + png_info_init_3(&info_ptr, png_sizeof(png_info)); return (info_ptr); } @@ -272,6 +279,7 @@ png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr) * and applications using it are urged to use png_create_info_struct() * instead. */ +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) #undef png_info_init void PNGAPI png_info_init(png_infop info_ptr) @@ -279,6 +287,7 @@ png_info_init(png_infop info_ptr) /* We only come here via pre-1.0.12-compiled applications */ png_info_init_3(&info_ptr, 0); } +#endif void PNGAPI png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) @@ -287,7 +296,7 @@ png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) png_debug(1, "in png_info_init_3\n"); - if(sizeof(png_info) > png_info_struct_size) + if(png_sizeof(png_info) > png_info_struct_size) { png_destroy_struct(info_ptr); info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); @@ -295,7 +304,7 @@ png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) } /* set everything to 0 */ - png_memset(info_ptr, 0, sizeof (png_info)); + png_memset(info_ptr, 0, png_sizeof (png_info)); } #ifdef PNG_FREE_ME_SUPPORTED @@ -581,7 +590,7 @@ png_info_destroy(png_structp png_ptr, png_infop info_ptr) } #endif - png_info_init_3(&info_ptr, sizeof(png_info)); + png_info_init_3(&info_ptr, png_sizeof(png_info)); } /* This function returns a pointer to the io_ptr associated with the user @@ -623,7 +632,7 @@ png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime) if (png_ptr->time_buffer == NULL) { png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29* - sizeof(char))); + png_sizeof(char))); } #if defined(_WIN32_WCE) @@ -645,7 +654,7 @@ png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime) ptime->year, ptime->hour % 24, ptime->minute % 60, ptime->second % 61); png_memcpy(png_ptr->time_buffer, near_time_buf, - 29*sizeof(char)); + 29*png_sizeof(char)); } #else sprintf(png_ptr->time_buffer, "%d %s %d %02d:%02d:%02d +0000", @@ -670,45 +679,47 @@ png_sig_bytes(void) png_charp PNGAPI png_get_copyright(png_structp png_ptr) { - if (png_ptr != NULL || png_ptr == NULL) /* silence compiler warning */ - return ((png_charp) "\n libpng version 1.2.4 - July 8, 2002\n\ - Copyright (c) 1998-2002 Glenn Randers-Pehrson\n\ + if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return ((png_charp) "\n libpng version 1.2.8 - December 3, 2004\n\ + Copyright (c) 1998-2004 Glenn Randers-Pehrson\n\ Copyright (c) 1996-1997 Andreas Dilger\n\ Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n"); return ((png_charp) ""); } /* The following return the library version as a short string in the - * format 1.0.0 through 99.99.99zz. To get the version of *.h files used - * with your application, print out PNG_LIBPNG_VER_STRING, which is defined - * in png.h. + * format 1.0.0 through 99.99.99zz. To get the version of *.h files + * used with your application, print out PNG_LIBPNG_VER_STRING, which + * is defined in png.h. + * Note: now there is no difference between png_get_libpng_ver() and + * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, + * it is guaranteed that png.c uses the correct version of png.h. */ - png_charp PNGAPI png_get_libpng_ver(png_structp png_ptr) { /* Version of *.c files used when building libpng */ - if(png_ptr != NULL) /* silence compiler warning about unused png_ptr */ - return((png_charp) "1.2.4"); - return((png_charp) "1.2.4"); + if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return ((png_charp) PNG_LIBPNG_VER_STRING); + return ((png_charp) ""); } png_charp PNGAPI png_get_header_ver(png_structp png_ptr) { /* Version of *.h files used when building libpng */ - if(png_ptr != NULL) /* silence compiler warning about unused png_ptr */ - return((png_charp) PNG_LIBPNG_VER_STRING); - return((png_charp) PNG_LIBPNG_VER_STRING); + if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return ((png_charp) PNG_LIBPNG_VER_STRING); + return ((png_charp) ""); } png_charp PNGAPI png_get_header_version(png_structp png_ptr) { /* Returns longer string containing both version and date */ - if(png_ptr != NULL) /* silence compiler warning about unused png_ptr */ - return((png_charp) PNG_HEADER_VERSION_STRING); - return((png_charp) PNG_HEADER_VERSION_STRING); + if (&png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return ((png_charp) PNG_HEADER_VERSION_STRING); + return ((png_charp) ""); } #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED @@ -740,7 +751,7 @@ png_uint_32 PNGAPI png_access_version_number(void) { /* Version of *.c files used when building libpng */ - return((png_uint_32) 10204L); + return((png_uint_32) PNG_LIBPNG_VER); } @@ -758,7 +769,7 @@ png_init_mmx_flags (png_structp png_ptr) png_ptr->asm_flags |= PNG_ASM_FLAG_MMX_SUPPORT_COMPILED; - if (png_mmx_support()) { + if (png_mmx_support() > 0) { png_ptr->asm_flags |= PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU # ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW | PNG_ASM_FLAG_MMX_READ_COMBINE_ROW @@ -803,3 +814,15 @@ png_mmx_support(void) } #endif #endif /* PNG_1_0_X */ + +#ifdef PNG_SIZE_T +/* Added at libpng version 1.2.6 */ + PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); +png_size_t PNGAPI +png_convert_size(size_t size) +{ + if (size > (png_size_t)-1) + PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */ + return ((png_size_t)size); +} +#endif /* PNG_SIZE_T */ diff --git a/png.h b/png.h index 365c80b39..e87a3011c 100644 --- a/png.h +++ b/png.h @@ -1,14 +1,14 @@ /* png.h - header file for PNG reference library * - * libpng version 1.2.4 - July 8, 2002 - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * libpng version 1.2.8 - December 3, 2004 + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.2.4 - July 8, 2002: Glenn + * libpng versions 0.97, January 1998, through 1.2.8 - December 3, 2004: Glenn * See also "Contributing Authors", below. * * Note about libpng version numbers: @@ -93,6 +93,24 @@ * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 * 1.0.14 10 10014 10.so.0.1.0.14 * 1.2.4 13 10204 12.so.0.1.2.4 + * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 + * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 + * 1.0.15 10 10015 10.so.0.1.0.15 + * 1.2.5 13 10205 12.so.0.1.2.5 + * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 + * 1.0.16 10 10016 10.so.0.1.0.16 + * 1.2.6 13 10206 12.so.0.1.2.6 + * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 + * 1.0.17rc1 10 10017 12.so.0.1.0.17rc1 + * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 + * 1.0.17 10 10017 12.so.0.1.0.17 + * 1.2.7 13 10207 12.so.0.1.2.7 + * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 + * 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5 + * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 + * 1.0.18 10 10018 12.so.0.1.0.18 + * 1.2.8 13 10208 12.so.0.1.2.8 * * Henceforth the source version will match the shared-library major * and minor numbers; the shared-library major version number will be @@ -112,8 +130,8 @@ * in binary compatibility (e.g., when a new feature is added). * * See libpng.txt or libpng.3 for more information. The PNG specification - * is available as RFC 2083 - * and as a W3C Recommendation + * is available as a W3C Recommendation and as an ISO Specification, + * = 8 ? \ + ((width) * (((png_uint_32)(pixel_bits)) >> 3)) : \ + (( ((width) * ((png_uint_32)(pixel_bits))) + 7) >> 3) ) + +/* PNG_OUT_OF_RANGE returns true if value is outside the range + ideal-delta..ideal+delta. Each argument is evaluated twice. + "ideal" and "delta" should be constants, normally simple + integers, "value" a variable. Added to libpng-1.2.6 JB */ +#define PNG_OUT_OF_RANGE(value, ideal, delta) \ + ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) + /* variables declared in png.c - only it needs to define PNG_NO_EXTERN */ #if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) /* place to hold the signature string for a PNG file. */ @@ -2650,6 +2784,8 @@ PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf)); PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf)); PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf)); #endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */ +PNG_EXTERN png_uint_32 png_get_uint_31 PNGARG((png_structp png_ptr, + png_bytep buf)); /* Initialize png_ptr struct for reading, and allocate any other memory. * (old interface - DEPRECATED - use png_create_read_struct instead). @@ -2657,7 +2793,7 @@ PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf)); extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr)); #undef png_read_init #define png_read_init(png_ptr) png_read_init_3(&png_ptr, \ - PNG_LIBPNG_VER_STRING, sizeof(png_struct)); + PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr, png_const_charp user_png_ver, png_size_t png_struct_size)); extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr, @@ -2670,7 +2806,7 @@ extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr, extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr)); #undef png_write_init #define png_write_init(png_ptr) png_write_init_3(&png_ptr, \ - PNG_LIBPNG_VER_STRING, sizeof(png_struct)); + PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr, png_const_charp user_png_ver, png_size_t png_struct_size)); extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr, @@ -2699,6 +2835,11 @@ PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size)); /* Function to free memory for zlib */ PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); +#ifdef PNG_SIZE_T +/* Function to convert a sizeof an item to png_sizeof item */ + PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); +#endif + /* Next four functions are used internally as callbacks. PNGAPI is required * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. */ diff --git a/pngconf.h b/pngconf.h index a0ca483ce..d33fbf6fa 100644 --- a/pngconf.h +++ b/pngconf.h @@ -1,8 +1,9 @@ + /* pngconf.h - machine configurable file for libpng * - * libpng 1.2.4 - July 8, 2002 + * libpng version 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) */ @@ -16,7 +17,55 @@ #ifndef PNGCONF_H #define PNGCONF_H -#include "pngcrush.h" /* except for this line, this is libpng's pngconf.h */ +#include "pngcrush.h" + +#define PNG_1_2_X + +/* + * PNG_USER_CONFIG has to be defined on the compiler command line. This + * includes the resource compiler for Windows DLL configurations. + */ +#ifdef PNG_USER_CONFIG +#include "pngusr.h" +#endif + +/* + * Added at libpng-1.2.8 + * + * If you create a private DLL you need to define in "pngusr.h" the followings: + * #define PNG_USER_PRIVATEBUILD + * e.g. #define PNG_USER_PRIVATEBUILD "Build by MyCompany for xyz reasons." + * #define PNG_USER_DLLFNAME_POSTFIX + * e.g. // private DLL "libpng13gx.dll" + * #define PNG_USER_DLLFNAME_POSTFIX "gx" + * + * The following macros are also at your disposal if you want to complete the + * DLL VERSIONINFO structure. + * - PNG_USER_VERSIONINFO_COMMENTS + * - PNG_USER_VERSIONINFO_COMPANYNAME + * - PNG_USER_VERSIONINFO_LEGALTRADEMARKS + */ + +#ifdef __STDC__ +#ifdef SPECIALBUILD +# pragma message("PNG_LIBPNG_SPECIALBUILD (and deprecated SPECIALBUILD)\ + are now LIBPNG reserved macros. Use PNG_USER_PRIVATEBUILD instead.") +#endif + +#ifdef PRIVATEBUILD +# pragma message("PRIVATEBUILD is deprecated. Use\ + PNG_USER_PRIVATEBUILD instead.") +# define PNG_USER_PRIVATEBUILD PRIVATEBUILD +#endif +#endif /* __STDC__ */ + +#ifndef PNG_VERSION_INFO_ONLY + +/* End of material added to libpng-1.2.8 */ /* This is the size of the compression buffer, and thus the size of * an IDAT chunk. Make this whatever size you feel is best for your @@ -254,8 +303,11 @@ # undef _BSD_SOURCE # endif # ifdef _SETJMP_H - __png.h__ already includes setjmp.h; - __dont__ include it again.; + /* If you encounter a compiler error here, see the explanation + * near the end of INSTALL. + */ + __png.h__ already includes setjmp.h; + __dont__ include it again.; # endif # endif /* __linux__ */ @@ -319,15 +371,13 @@ # define PNG_ALWAYS_EXTERN #endif -/* For some reason, Borland C++ defines memcmp, etc. in mem.h, not - * stdlib.h like it should (I think). Or perhaps this is a C++ - * "feature"? - */ -#ifdef __TURBOC__ +/* This provides the non-ANSI (far) memory allocation routines. */ +#if defined(__TURBOC__) && defined(__MSDOS__) # include -# include "alloc.h" +# include #endif +/* I have no idea why is this necessary... */ #if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \ defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__)) # include @@ -585,13 +635,6 @@ # endif #endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -# ifndef PNG_NO_USER_TRANSFORM_PTR -# define PNG_USER_TRANSFORM_PTR_SUPPORTED -# endif -#endif - #define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant encoders, but can cause trouble if left undefined */ @@ -601,12 +644,6 @@ # define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED #endif -#ifndef PNG_1_0_X -#ifndef PNG_NO_ERROR_NUMBERS -#define PNG_ERROR_NUMBERS_SUPPORTED -#endif -#endif /* PNG_1_0_X */ - #ifndef PNG_NO_WRITE_FLUSH # define PNG_WRITE_FLUSH_SUPPORTED #endif @@ -618,6 +655,19 @@ #endif /* PNG_WRITE_SUPPORTED */ +#ifndef PNG_1_0_X +# ifndef PNG_NO_ERROR_NUMBERS +# define PNG_ERROR_NUMBERS_SUPPORTED +# endif +#endif /* PNG_1_0_X */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +# ifndef PNG_NO_USER_TRANSFORM_PTR +# define PNG_USER_TRANSFORM_PTR_SUPPORTED +# endif +#endif + #ifndef PNG_NO_STDIO # define PNG_TIME_RFC1123_SUPPORTED #endif @@ -665,6 +715,25 @@ #endif #endif /* PNG_1_0_X */ +/* Added at libpng-1.2.6 */ +#if !defined(PNG_1_0_X) +#ifndef PNG_SET_USER_LIMITS_SUPPORTED +#if !defined(PNG_NO_SET_USER_LIMITS) && !defined(PNG_SET_USER_LIMITS_SUPPORTED) +# define PNG_SET_USER_LIMITS_SUPPORTED +#endif +#endif +#endif /* PNG_1_0_X */ + +/* Added at libpng-1.0.16 and 1.2.6. To accept all valid PNGS no matter + * how large, set these limits to 0x7fffffffL + */ +#ifndef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000L +#endif +#ifndef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000L +#endif + /* These are currently experimental features, define them if you want */ /* very little testing */ @@ -679,10 +748,8 @@ /* This is only for PowerPC big-endian and 680x0 systems */ /* some testing */ /* -#ifdef PNG_READ_SUPPORTED -# ifndef PNG_PNG_READ_BIG_ENDIAN_SUPPORTED -# define PNG_READ_BIG_ENDIAN_SUPPORTED -# endif +#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED +# define PNG_READ_BIG_ENDIAN_SUPPORTED #endif */ @@ -990,7 +1057,13 @@ typedef unsigned char png_byte; /* This is usually size_t. It is typedef'ed just in case you need it to change (I'm not sure if you will or not, so I thought I'd be safe) */ -typedef size_t png_size_t; +#ifdef PNG_SIZE_T + typedef PNG_SIZE_T png_size_t; +# define png_sizeof(x) png_convert_size(sizeof (x)) +#else + typedef size_t png_size_t; +# define png_sizeof(x) sizeof (x) +#endif /* The following is needed for medium model support. It cannot be in the * PNG_INTERNAL section. Needs modification for other compilers besides @@ -1094,6 +1167,9 @@ typedef double FAR * FAR * png_doublepp; /* Pointers to pointers to pointers; i.e., pointer to array */ typedef char FAR * FAR * FAR * png_charppp; +#if defined(PNG_1_0_X) || defined(PNG_1_2_X) +/* SPC - Is this stuff deprecated? */ +/* It'll be removed as of libpng-1.3.0 - GR-P */ /* libpng typedefs for types in zlib. If zlib changes * or another compression library is used, then change these. * Eliminates need to change all the source files. @@ -1101,6 +1177,7 @@ typedef char FAR * FAR * FAR * png_charppp; typedef charf * png_zcharp; typedef charf * FAR * png_zcharpp; typedef z_stream FAR * png_zstreamp; +#endif /* (PNG_1_0_X) || defined(PNG_1_2_X) */ /* * Define PNG_BUILD_DLL if the module being built is a Windows @@ -1173,8 +1250,6 @@ typedef z_stream FAR * png_zstreamp; * zlib and your applications the same way you build libpng. */ -#ifndef PNGAPI - #if defined(__MINGW32__) && !defined(PNG_MODULEDEF) # ifndef PNG_NO_MODULEDEF # define PNG_NO_MODULEDEF @@ -1189,10 +1264,12 @@ typedef z_stream FAR * png_zstreamp; (( defined(_Windows) || defined(_WINDOWS) || \ defined(WIN32) || defined(_WIN32) || defined(__WIN32__) )) -# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) -# define PNGAPI __cdecl -# else -# define PNGAPI _cdecl +# ifndef PNGAPI +# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) +# define PNGAPI __cdecl +# else +# define PNGAPI _cdecl +# endif # endif # if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \ @@ -1230,17 +1307,14 @@ typedef z_stream FAR * png_zstreamp; # endif # endif /* PNG_IMPEXP */ #else /* !(DLL || non-cygwin WINDOWS) */ -# if (defined(__IBMC__) || defined(IBMCPP__)) && defined(__OS2__) -# define PNGAPI _System -# define PNG_IMPEXP -# else -# if 0 /* ... other platforms, with other meanings */ -# else -# define PNGAPI -# define PNG_IMPEXP +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# ifndef PNGAPI +# define PNGAPI _System # endif -# endif -#endif +# else +# if 0 /* ... other platforms, with other meanings */ +# endif +# endif #endif #ifndef PNGAPI @@ -1250,6 +1324,17 @@ typedef z_stream FAR * png_zstreamp; # define PNG_IMPEXP #endif +#ifdef PNG_BUILDSYMS +# ifndef PNG_EXPORT +# define PNG_EXPORT(type,symbol) PNG_FUNCTION_EXPORT symbol END +# endif +# ifdef PNG_USE_GLOBAL_ARRAYS +# ifndef PNG_EXPORT_VAR +# define PNG_EXPORT_VAR(type) PNG_DATA_EXPORT +# endif +# endif +#endif + #ifndef PNG_EXPORT # define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol #endif @@ -1281,28 +1366,30 @@ typedef z_stream FAR * png_zstreamp; # define NOCHECK 0 # define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) # define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) -# define png_strcpy _fstrcpy -# define png_strlen _fstrlen -# define png_memcmp _fmemcmp /* SJT: added */ -# define png_memcpy _fmemcpy -# define png_memset _fmemset +# define png_strcpy _fstrcpy +# define png_strncpy _fstrncpy /* Added to v 1.2.6 */ +# define png_strlen _fstrlen +# define png_memcmp _fmemcmp /* SJT: added */ +# define png_memcpy _fmemcpy +# define png_memset _fmemset #else /* use the usual functions */ # define CVT_PTR(ptr) (ptr) # define CVT_PTR_NOCHECK(ptr) (ptr) -# define png_strcpy strcpy -# define png_strlen strlen -# define png_memcmp memcmp /* SJT: added */ -# define png_memcpy memcpy -# define png_memset memset +# define png_strcpy strcpy +# define png_strncpy strncpy /* Added to v 1.2.6 */ +# define png_strlen strlen +# define png_memcmp memcmp /* SJT: added */ +# define png_memcpy memcpy +# define png_memset memset #endif /* End of memory model independent support */ /* Just a little check that someone hasn't tried to define something * contradictory. */ -#if (PNG_ZBUF_SIZE > 65536) && defined(PNG_MAX_MALLOC_64K) +#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) # undef PNG_ZBUF_SIZE -# define PNG_ZBUF_SIZE 65536 +# define PNG_ZBUF_SIZE 65536L #endif #ifdef PNG_READ_SUPPORTED @@ -1346,5 +1433,7 @@ typedef z_stream FAR * png_zstreamp; #endif /* PNG_INTERNAL */ #endif /* PNG_READ_SUPPORTED */ -#endif /* PNGCONF_H */ +/* Added at libpng-1.2.8 */ +#endif /* PNG_VERSION_INFO_ONLY */ +#endif /* PNGCONF_H */ diff --git a/pngcrush.c b/pngcrush.c index c4ec2d1f9..a8f02a5ef 100644 --- a/pngcrush.c +++ b/pngcrush.c @@ -1,5 +1,6 @@ /* pngcrush.c - recompresses png files - * Copyright (C) 1998-2002 Glenn Randers-Pehrson (randeg@alum.rpi.edu) + * Copyright (C) 1998-2002,2006 Glenn Randers-Pehrson (glennrp@users.sf.net) + * Copyright (C) 2005 Greg Roelofs * * The most recent version of pngcrush can be found at SourceForge in * http://pmt.sf.net/pngcrush/ @@ -13,7 +14,7 @@ * Optionally, it can remove unwanted chunks or add gAMA, sRGB, bKGD, * tEXt/zTXt, and tRNS chunks. It will remove some chunks such as gAMA, * cHRM, pHYs, and oFFs when their data fields contain all zero, which is a - * mistake. + * mistake. * * Uses libpng and zlib. This program was based upon libpng's pngtest.c. * @@ -25,7 +26,7 @@ * */ -#define PNGCRUSH_VERSION "1.5.10" +#define PNGCRUSH_VERSION "1.6.2" /* #define PNGCRUSH_COUNT_COLORS @@ -37,7 +38,8 @@ * If you have modified this source, you may insert additional notices * immediately after this sentence. * - * Copyright (C) 1998-2002 Glenn Randers-Pehrson (randeg@alum.rpi.edu) + * Copyright (C) 1998-2002,2006 Glenn Randers-Pehrson (glennrp@users.sf.net) + * Copyright (C) 2005 Greg Roelofs * * The pngcrush computer program is supplied "AS IS". The Author disclaims all * warranties, expressed or implied, including, without limitation, the @@ -66,318 +68,6 @@ * or altered from any source or altered source distribution. */ -/* Change log: - * - * Version 1.5.10 (built with libpng-1.2.4 and zlib-1.1.4pc) - * - * Fixed bug, introduced in 1.5.9, that caused defaults for method 0 to - * be used instead of copying the original image, when the original was - * already smallest. - * - * Version 1.5.9 (built with libpng-1.2.4beta3 and zlib-1.1.4pc) - * - * Work around CPU timer wraparound at 2G microseconds. - * - * Upgraded zlib from 1.1.3 to 1.1.4. Pngcrush is believed not to - * be vulnerable to the zlib-1.1.3 buffer-overflow bug. - * - * Choose the first instance of smallest IDAT instead of the last, - * for faster final recompression, suggested by TSamuel. - * - * Version 1.5.8 (built with libpng-1.2.1) - * - * Added -trns_a option for entering a tRNS array. - * - * Version 1.5.7 (built with libpng-1.2.0) - * - * Added setargv.obj to Makefile.msc to expand wildcards, e.g., *.png - * - * Use constant string "pngcrush" instead of argv[0] when appropriate. - * - * Only check stats for infile==outfile once per input file, or not at all - * if "-nofilecheck" option is present or if a directory was created. - * - * Fixed bugs with changing bit_depth of grayscale images. - * - * Version 1.5.6 (built with libpng-1.0.12) - * - * Eliminated extra "Removed the cHNK chunk" messages generated by version - * 1.5.5 when "-rem alla" or "-rem allb" is used. - * - * All unknown chunks including safe-to-copy chunks are now removed in - * response to the "-rem alla" or "-rem allb" options. - * - * Issue a warning if the user tries "-cc" option when it is not supported. - * - * Version 1.5.5 (built with libpng-1.0.12) - * - * Reset reduce_to_gray and it_is_opaque flags prior to processing each - * image. - * - * Enable removal of safe-to-copy chunks that are being handled as unknown - * e.g., "-rem time". - * - * Version 1.5.4 (built with libpng-1.0.11) - * - * Added 262 to the length of uncompressed data when calculating - * required_window_size, to account for zlib/deflate implementation. - * - * Added "-bit_depth n" to the help screen. - * - * Call png_set_packing() when increasing bit_depth to 2 or 4. - * - * Added warning about not overwriting an existing tRNS chunk. - * - * Reduced the memory usage - * - * Write 500K IDAT chunks even when system libpng is being used. - * - * Ignore all-zero cHRM chunks, with a warning. - * - * Version 1.5.3 (built with libpng-1.0.9beta5) - * - * Added "-loco" option (writes MNG files with filter_method 64) - * - * "-dir" and "-ext" options are no longer mutually exclusive, e.g.: - * pngcrush -loco -dir Crushed -ext .mng *.png - * - * Version 1.5.2 (built with libpng-1.0.9beta1) - * - * Added "-iccp" option. - * - * Increased the zlib memory level, which improves compression (typically - * about 1.3 percent for photos) at the expense of increased memory usage. - * - * Enabled the "-max max_idat_size" option, even when max_idat_size - * exceeds the default 1/2 megabyte size. - * - * Added missing "png_ptr" argument to png_error() call - * - * Added "-loco" option, to enable the LOCO color transformation - * (R->R-G, G, B->B-G) while writing a MNG with filter_method 64. Undo - * the transformation and write the regular PNG filter_method (0) if the - * MNG filter_method 64 is detected. - * - * Revised the "-help" output slightly and improved the "-version" output. - * - * The "-already[_crushed]" option is now ignored if the "-force" option - * is present or if chunks are being added, deleted, or modified. - * - * Improved "things_have_changed" behavior (now, when set in a particular - * file, it is not set for all remaining files) - * - * Version 1.5.1 (built with libpng-1.0.8) - * - * Disabled color counting by default and made it controllable with new - * -cc and -no_cc commandline arguments. - * - * Added some #ifdef PNGCRUSH_COUNT_COLORS around code that needs it. - * - * Revised count_colors() attempting to avoid stack corruption that has - * been observed on RedHat 6.2 - * - * Added the word "irrevocably" to the license and changed "without fee" - * to "without payment of any fee". - * - * Version 1.5.0 (built with libpng-1.0.8) - * - * After encountering an image with a bad Photoshop iCCP chunk, pngcrush - * 1.4.5 through 1.4.8 write sRGB and gAMA=45455 chunks in all - * remaining PNG files on the command line. This has been fixed so the - * correction is only applied to the particular bad input file. - * - * Version 1.4.8 (built with libpng-1.0.8rc1) - * - * Detect and remove all-opaque alpha channel. - * Detect and reduce all-gray truecolor images to grayscale. - * - * Version 1.4.7 (built with libpng-1.0.8rc1) - * - * Restored the "-ext" option that was inadvertently overridden with - * a new "-exit" option in version 1.4.6 ("-exit" is used to force an - * "exit" instead of a "return" from the main program). - * - * Version 1.4.6 (built with libpng-1.0.8rc1) - * - * Fixed bug in color-counting of noninterlaced images. - * - * Added capability of processing multiple rows at a time (disabled by - * default because it turns out to be no faster). - * - * Replaced "return" statements in main() with "exit" statements. - * Force exit instead of return with "-exit" argument. - * - * Added the UCITA disclaimers to the help output. - * - * Version 1.4.5 (built with libpng-1.0.7rc2 and cexcept-1.0.0) - * - * Added color-counting and palette-building capability (enable by - * defining PNGCRUSH_COUNT_COLORS). In a future version, this will - * give pngcrush the ability to reduce RGBA images to indexed-color - * or grayscale when fewer than 257 RGBA combinations are present, - * and no color is present that requires 16-bit precision. For now, - * it only reports the frequencies. - * - * Added "-fix" option, for fixing bad CRC's and other correctable - * conditions. - * - * Write sBIT.alpha=1 when adding an opaque alpha channel and sBIT - * is present. - * - * Identify the erroneous 2615-byte sRGB monitor profile being written - * by Photoshop 5.5, which causes many apps to crash, and replace it with - * an sRGB chunk. - * - * Added a check for input and output on different devices before rejecting - * the output file as being the same as the input file based on inode. - * - * Added some UCITA language to the disclaimer. - * - * Version 1.4.4 (built with libpng-1.0.6i and cexcept-0.6.3) - * - * Can be built on RISC OS platforms, thanks to Darren Salt. - * - * Version 1.4.3 (built with libpng-1.0.6h and cexcept-0.6.3) - * - * Reduced scope of Try/Catch blocks to avoid nesting them, and - * removed returns from within the Try blocks, where they are not - * allowed. - * - * Removed direct access to the png structure when possible, and isolated - * the remaining direct accesses to the png structure into new - * png_get_compression_buffer_size(), png_set_compression_buffer_size(), - * and png_set_unknown_chunk_location() functions that were installed - * in libpng version 1.0.6g. - * - * Version 1.4.2 (built with libpng-1.0.6f and cexcept-0.6.0) - * - * Removes extra IDAT chunks (such as found in some POV-ray PNGs) with - * a warning instead of bailing out (this feature requires libpng-1.0.6f - * or later, compiled with "#define PNG_ABORT()"). - * - * Removed old setjmp interface entirely. - * - * Version 1.4.1 (built with libpng-1.0.6e and cexcept-0.6.0) - * - * Uses cexcept.h for error handling instead of libpng's built-in - * setjmp/longjmp mechanism. See http://cexcept.sf.net/ - * - * Pngcrush.c will now run when compiled with old versions of libpng back - * to version 0.96, although some features will not be available. - * - * Version 1.4.0 (built with libpng-1.0.6 + libpng-1.0.6-patch-a) - * - * Version 1.3.6 (built with libpng-1.0.5v) - * - * RGB to Grayscale conversion is more accurate (15-bit instead of 8-bit) - * and now uses only integer arithmetic. - * - * #ifdef'ed out PNG_READ_DITHER - * - * Changed "Compressed" to "Uncompressed" in help for -itxt. - * - * Stifled some compiler warnings - * - * Version 1.3.5 (built with libpng-1.0.5s) - * - * Add test on stat_buf.st_size to verify fpin==fpout, because stat in - * MSVC++6.0 standard version returns stat_buf.st_ino=0 for all files. - * - * Revised pngcrush.h to make it easier to control PNG_ZBUF_SIZE and - * PNG_NO_FLOATING_POINT_SUPPORTED from a makefile. - * - * Restored ability to enter "replace_gamma" value as a float even when - * floating point arithmetic is not enabled. - * - * Enabled removing tEXt, zTXt, or iTXt chunks by chunk type, i.e., - * "-rem tEXt" only removes tEXt chunks, while "-rem text" removes all - * three types of text chunk. - * - * Removed definition of TOO_FAR from pngcrush.h - * - * Uses new libpng error handler; if a file has errors, pngcrush now will - * continue on and compress the remaining files instead of bailing out. - * - * Version 1.3.4 (built with libpng-1.0.5m) - * - * Do not allow pngcrush to overwrite the input file. - * - * Version 1.3.3 (built with libpng-1.0.5m) - * - * Restored ability to enter gamma as a float even when floating point - * arithmetic is not enabled. - * - * Version 1.3.2 (built with libpng-1.0.5k) - * - * Renamed "dirname" to "directory_name" to avoid conflict with "dirname" - * that appears in string.h on some platforms. - * - * Fixed "PNG_NO_FLOAING_POINT" typo in pngcrush.h - * - * #ifdef'ed out parts of the help screen for options that are unsupported. - * - * Version 1.3.1 (built with libpng-1.0.5k): Eliminated some spurious warnings - * that were being issued by libpng-1.0.5j. Added -itxt, -ztxt, and - * -zitxt descriptions to the help screen. - * - * Dropped explicit support for pCAL, hIST, sCAL, sPLT, iCCP, tIME, and - * cHRM chunks and handle them as unknown but safe-to-copy instead, using - * new png_handle_as_unknown function available in libpng-1.0.5k. - * - * Version 1.3.0 (built with libpng-1.0.5j): Added support for handling - * unknown chunks. - * - * pngcrush is now fixed-point only, unless PNG_NO_FLOATING_POINT_SUPPORTED - * is undefined in pngcrush.h. - * - * Added support for the iCCP, iTXt, sCAL, and sPLT chunks, which - * are now supported by libpng (since libpng-1.0.5j). None of these have - * been adequately tested. - * - * #ifdef'ed out more unused code (weighted filters and progressive read; - * this saves about 15k in the size of the executable). - * - * Moved the special definitions from pngconf.h into a new pngcrush.h - * - * Disallow 256-byte compression window size when writing, to work around - * an apparent zlib bug. Either deflate was producing incorrect results in a - * 21x21 4-bit image or inflate was decoding it incorrectly; the uncompressed - * stream is 252 bytes, which is uncomfortably close to the resulting - * 256-byte compression window. This workaround can be removed when zlib - * is fixed. - * - * The "-m method" can be used any of the 124 methods, without having to - * specify the filter, level, and strategy, instead of just the first 10. - * - * Version 1.2.1 (built with libpng-1.0.5f): Fixed -srgb parameter so it - * really does take an argument, and so it continues to use "0" if an - * integer does not follow the -srgb. - * - * Added "-plte_len n" argument for truncating the PLTE. Be sure not to - * truncate it to less than the greatest index actually appearing in IDAT. - * - * Version 1.2.0: Removed registration requirement. Added open source - * license. Redefined TOO_FAR=32k in deflate.c. - * - * Changes prior to going "open source": - * - * Version 1.1.8: built with libpng-1.0.5a. Runs OK with pngvcrd.c. - * - * Version 1.1.7: added ability to add tEXt/zTXt chunks. Fixed bug with - * closing a file that wasn't opened when using "pngcrush -n". Fixed - * bug with tEXt/zTXt chunks after IDAT not being copied. - * Added alpha to the displayed palette table. Rebuilt with libpng-1.0.5. - * - * Version 1.1.6: fixed bug with one file left open after each image is - * processed - * - * Version 1.1.5: Shorten or remove tRNS chunks that are all opaque or have - * opaque entries at the end. Added timing report. - * - * Version 1.1.4: added ability to restrict brute_force to one or more filter - * types, compression levels, or compression strategies. - */ - /* To do: * * Reset CINFO to reflect decoder's required window size (instead of @@ -398,159 +88,136 @@ * * Finish pplt (partial palette) feature. * - * Use an alternate write function for the trial passes, that - * simply counts bytes rather than actually writing to a file, to save wear - * and tear on disk drives. + * add "-time" directive * * Allow in-place file replacement or as a filter, as in * "pngcrush -overwrite file.png" * "pngcreator | pngcrush > output.png" * + * Use an alternate write function for the trial passes, that + * simply counts bytes rather than actually writing to a file, to save wear + * and tear on disk drives. + * * Remove text-handling and color-handling features and put * those in a separate program or programs, to avoid unnecessary * recompressing. * * Move the Photoshop-fixing stuff into a separate program. * - * add "-time" directive + * GRR: More generally (superset of previous 3 items): split into separate + * "edit" and "crush" programs (or functions). Former is fully libpng- + * aware, much like current pngcrush; latter makes little or no use of + * libpng (maybe IDAT-compression parts only?), instead handling virtually + * all chunks as opaque binary blocks that are copied to output file _once_, + * with IDATs alone replaced (either by best in-memory result or by original + * _data_ resplit into bigger IDATs, if pngcrush can't match/beat). "edit" + * version should be similar to current code but more efficient: make + * _one_ pass through args list, creating table of PNG_UINTs for removal; + * then make initial pass through PNG image, creating (in-order) table of + * all chunks (and byte offsets?) and marking each as "keep" or "remove" + * according to args table. Can start with static table of ~20-30 slots, + * then double size & copy if run out of room: still O(n) algorithm. */ #define PNG_INTERNAL #include "png.h" -/* we don't need the some of the extra libpng transformations - * so they are ifdef'ed out in a special version of pngconf.h, which - * includes pngcrush.h and is included by png.h */ +/* we don't need some of the extra libpng transformations + * so they are ifdef'ed out in pngcrush.h, which is included by + * libpng's pngconf.h which is included by png.h */ /* defined so I can write to a file on gui/windowing platforms */ /* #define STDERR stderr */ -#define STDERR stdout /* for DOS */ - +#define STDERR stdout /* for DOS */ #ifndef PNGCRUSH_LIBPNG_VER # define PNGCRUSH_LIBPNG_VER PNG_LIBPNG_VER #endif -#if PNGCRUSH_LIBPNG_VER != PNG_LIBPNG_VER -int -main() -{ - printf("Version numbers in pngcrush.h (%d) and png.h (%d) do not match\n", - PNGCRUSH_LIBPNG_VER, PNG_LIBPNG_VER); -} - -#else -#if PNG_LIBPNG_VER < 96 -int -main() -{ - printf("Sorry, but pngcrush needs libpng version 0.96 or later\n"); - printf("You have built pngcrush with libpng version %s\n", - PNG_LIBPNG_VER_STRING); -} - -#else - #ifdef PNG_MNG_FEATURES_SUPPORTED # define PNGCRUSH_LOCO #endif +/* These macros were renamed in libpng-1.2.6 */ +#ifndef PNG_HANDLE_CHUNK_ALWAYS +#define PNG_HANDLE_CHUNK_ALWAYS HANDLE_CHUNK_ALWAYS +#define PNG_HANDLE_CHUNK_NEVER HANDLE_CHUNK_NEVER +#define PNG_HANDLE_CHUNK_IF_SAFE HANDLE_CHUNK_IF_SAFE +#endif + #if defined(__DJGPP__) # if ((__DJGPP__ == 2) && (__DJGPP_MINOR__ == 0)) -# include /* for _USE_LFN, djgpp 2.0 only */ +# include /* for _USE_LFN, djgpp 2.0 only */ # endif # define SLASH "\\" # define DOT "." #else -# ifdef __riscos -# define SLASH "." -# define DOT "/" -# else -# define SLASH "/" -# define DOT "." -# endif +# ifdef __riscos +# define SLASH "." +# define DOT "/" +# else +# define SLASH "/" +# define DOT "." +# endif #endif + +#ifndef GAS_VERSION +# define GAS_VERSION "2.9.5(?)" /* used only in help/usage screen */ +#endif + #if !defined(__TURBOC__) && !defined(_MSC_VER) && !defined(_MBCS) && \ !defined(__riscos) # include #endif + #ifndef __riscos # include # include +# include #endif + #include #include #include #include + #if defined(_MBCS) || defined(WIN32) || defined(__WIN32__) # include #endif -#define DEFAULT_MODE 0 -#define DIRECTORY_MODE 1 -#define EXTENSION_MODE 2 -#define DIREX_MODE 3 +#define DEFAULT_MODE 0 +#define DIRECTORY_MODE 1 +#define EXTENSION_MODE 2 +#define DIREX_MODE 3 #define FOPEN(file, how) fopen(file, how) -#define FCLOSE(file) {fclose(file); file=NULL;--number_of_open_files;}; +#define FCLOSE(file) {fclose(file); file=NULL;--number_of_open_files;}; + #define P0 if(first_trial && verbose > 0)printf #define P1 if(verbose > 1)printf #define P2 if(verbose > 2)printf -#if (PNG_LIBPNG_VER > 95) +#define STRNGIFY_STAGE1(x) #x +#define STRNGIFY(x) STRNGIFY_STAGE1(x) -/* so we can load pngcrush with pre-1.0.6 versions of libpng */ +#define STR_BUF_SIZE 256 +#define MAX_IDAT_SIZE 524288L +#define MAX_METHODS 200 +#define MAX_METHODSP1 (MAX_METHODS+1) +#define DEFAULT_METHODS 10 +#define FAKE_PAUSE_STRING "P" -/* for version 1.0.2 and earlier */ -#ifndef PNG_MAX_UINT -#define PNG_MAX_UINT 2147483647L -#endif - -/* for version 0.89c and earlier */ -#ifndef PNG_TEXT_COMPRESSION_NONE -#define PNG_TEXT_COMPRESSION_NONE -1 -#define PNG_TEXT_COMPRESSION_zTXt 0 -#endif -#ifndef png_debug -#define png_debug(l, m) -#endif -#ifndef png_debug1 -#define png_debug1(l, m, p1) -#endif -#ifndef png_debug2 -#define png_debug2(l, m, p1, p2) -#endif - -#if (PNG_LIBPNG_VER < 10006) -/* These shorter macros weren't defined until version 1.0.6 */ -#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_WRITE_gAMA_SUPPORTED) -#define PNG_gAMA_SUPPORTED -#endif -#if defined(PNG_READ_pHYs_SUPPORTED) || defined(PNG_WRITE_pHYs_SUPPORTED) -#define PNG_pHYs_SUPPORTED -#endif -#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED) -#define PNG_sRGB_SUPPORTED -#endif -#if defined(PNG_READ_cHRM_SUPPORTED) || defined(PNG_WRITE_cHRM_SUPPORTED) -#define PNG_cHRM_SUPPORTED -#endif -#if defined(PNG_READ_hIST_SUPPORTED) || defined(PNG_WRITE_hIST_SUPPORTED) -#define PNG_hIST_SUPPORTED -#endif -#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) -#define PNG_pCAL_SUPPORTED -#endif -#if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED) -#define PNG_tIME_SUPPORTED -#endif -#if defined(PNG_READ_tRNS_SUPPORTED) || defined(PNG_WRITE_tRNS_SUPPORTED) -#define PNG_tRNS_SUPPORTED -#endif -#endif +#ifdef Z_RLE +# define NUM_STRATEGIES 4 +#else +# define NUM_STRATEGIES 3 #endif #ifdef __TURBOC__ -#include +# include +#endif + +#ifndef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 1000 #endif #if CLOCKS_PER_SEC <= 100 @@ -559,62 +226,62 @@ main() # define TIME_T float #endif +struct options_help { + int verbosity; /* if verbose >= this value, then print line */ + const char *textline; /* static string with newline chopped off */ +}; + /* input and output filenames */ -static PNG_CONST char *progname = "pngtest" DOT "exe"; +static PNG_CONST char *progname; static PNG_CONST char *inname = "pngtest" DOT "png"; static PNG_CONST char *outname = "pngout" DOT "png"; static PNG_CONST char *directory_name = "pngcrush" DOT "bak"; static PNG_CONST char *extension = "_C" DOT "png"; - static png_uint_32 width, height; static png_uint_32 measured_idat_length; -static int pngcrush_must_exit=0; -static int all_chunks_are_safe=0; +static int pngcrush_must_exit = 0; +static int all_chunks_are_safe = 0; static int number_of_open_files; static int do_pplt = 0; #ifdef PNGCRUSH_MULTIPLE_ROWS -static png_uint_32 max_rows_at_a_time=1; +static png_uint_32 max_rows_at_a_time = 1; static png_uint_32 rows_at_a_time; #endif char pplt_string[1024]; char *ip, *op, *dot; -char in_string[256]; -char prog_string[256]; -char out_string[256]; -char in_extension[256]; -static int text_inputs=0; -int text_where[10]; /* 0: no text; 1: before PLTE; 2: after PLTE */ -int text_compression[10]; /* -1: uncompressed tEXt; 0: compressed zTXt - 1: uncompressed iTXt; 2: compressed iTXt */ -char text_text[20480]; /* It would be nice to png_malloc this, but we don't - * have a png_ptr yet when we need it. */ +char in_string[STR_BUF_SIZE]; +char prog_string[STR_BUF_SIZE]; +char out_string[STR_BUF_SIZE]; +char in_extension[STR_BUF_SIZE]; +static int text_inputs = 0; +int text_where[10]; /* 0: no text; 1: before PLTE; 2: after PLTE */ +int text_compression[10]; /* -1: uncompressed tEXt; 0: compressed zTXt + 1: uncompressed iTXt; 2: compressed iTXt */ +char text_text[20480]; /* It would be nice to png_malloc this, but we + * don't have a png_ptr yet when we need it. */ char text_keyword[800]; -#ifdef PNG_iTXt_SUPPORTED + +/* PNG_iTXt_SUPPORTED */ char text_lang[800]; char text_lang_key[800]; -#endif -#ifdef PNG_iCCP_SUPPORTED + +/* PNG_iCCP_SUPPORTED */ int iccp_length = 0; char *iccp_text; char *iccp_file; char iccp_name[80]; -#endif + int best; char buffer[256]; -char *str_return; /* Set up the "cexcept" Try/Throw/Catch exception handler. */ #include "cexcept.h" define_exception_type(const char *); extern struct exception_context the_exception_context[1]; struct exception_context the_exception_context[1]; -#if (PNG_LIBPNG_VER > 96) png_const_charp msg; -#else -const char *msg; -#endif static png_uint_32 total_input_length = 0; static png_uint_32 total_output_length = 0; @@ -623,69 +290,72 @@ static int resolution = 0; static int remove_chunks = 0; static int output_color_type; static int output_bit_depth; -static int force_output_color_type=8; -static int force_output_bit_depth=0; +static int force_output_color_type = 8; +static int force_output_bit_depth = 0; static int input_color_type; static int input_bit_depth; static int trial; -static int first_trial=0; -static int verbose=1; -static int help=0; -static int fix=0; -static int things_have_changed=0; -static int global_things_have_changed=0; -static int default_compression_window=15; -static int force_compression_window=0; -static int compression_mem_level=9; -static int final_method=0; -static int brute_force=0; -static int brute_force_level=0; -static int brute_force_filter=0; -static int brute_force_strategy=0; -static int brute_force_levels[10]={1,1,1,1,1,1,1,1,1,1}; -static int brute_force_filters[6]={1,1,1,1,1,1}; -static int brute_force_strategies[3]={1,1,1}; -static int method=10; -static int pauses=0; -static int nosave=0; -static int nofilecheck=0; +static int first_trial = 0; +static int verbose = 1; +static int fix = 0; +static int things_have_changed = 0; +static int global_things_have_changed = 0; +static int default_compression_window = 15; +static int force_compression_window = 0; +static int compression_mem_level = 9; +static int final_method = 0; +static int brute_force = 0; +static int brute_force_level = 0; +static int brute_force_filter = 0; +static int brute_force_strategy = 0; +static int brute_force_levels[10] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; +static int brute_force_filters[6] = { 1, 1, 1, 1, 1, 1 }; +#ifdef Z_RLE +static int brute_force_strategies[NUM_STRATEGIES] = { 1, 1, 1, 1 }; +#else +static int brute_force_strategies[NUM_STRATEGIES] = { 1, 1, 1 }; +#endif +static int method = 10; +static int pauses = 0; +static int nosave = 0; +static int nofilecheck = 0; static png_bytep row_buf; #ifdef PNGCRUSH_MULTIPLE_ROWS static png_bytepp row_pointers; #endif static int z_strategy; static int best_of_three; -static int methods_specified=0; -static int intent=-1; -static int plte_len=-1; -#ifdef PNG_gAMA_SUPPORTED -# ifdef PNG_FIXED_POINT_SUPPORTED -static int specified_gamma=0; -static int image_specified_gamma=0; -static int force_specified_gamma=0; -# else -static double specified_gamma=0.0; -static double image_specified_gamma=0; -static double force_specified_gamma=0.0; -# endif -static int double_gamma=0; +static int methods_specified = 0; +static int intent = -1; +static int plte_len = -1; +#ifdef PNG_FIXED_POINT_SUPPORTED +static int specified_gamma = 0; +static int image_specified_gamma = 0; +static int force_specified_gamma = 0; +#else +static double specified_gamma = 0.0; +static double image_specified_gamma = 0; +static double force_specified_gamma = 0.0; #endif +static int double_gamma = 0; + static int names; -#ifdef PNG_tRNS_SUPPORTED -static int have_trns=0; -static png_uint_16 trns_index=0; -static png_uint_16 trns_red=0; -static png_uint_16 trns_green=0; -static png_uint_16 trns_blue=0; -static png_uint_16 trns_gray=0; -#endif + +static int have_trns = 0; +static png_uint_16 trns_index = 0; +static png_uint_16 trns_red = 0; +static png_uint_16 trns_green = 0; +static png_uint_16 trns_blue = 0; +static png_uint_16 trns_gray = 0; + static png_byte trns_array[256]; static png_byte trans_in[256]; static png_uint_16 num_trans_in; -static int have_bkgd=0; -static png_uint_16 bkgd_red=0; -static png_uint_16 bkgd_green=0; -static png_uint_16 bkgd_blue=0; + +static int have_bkgd = 0; +static png_uint_16 bkgd_red = 0; +static png_uint_16 bkgd_green = 0; +static png_uint_16 bkgd_blue = 0; static png_colorp palette; static int num_palette; @@ -699,113 +369,545 @@ static png_infop read_info_ptr, write_info_ptr; static png_infop end_info_ptr; static png_infop write_end_info_ptr; static FILE *fpin, *fpout; -png_uint_32 measure_idats(FILE *fpin); +png_uint_32 measure_idats(FILE * fpin); #ifdef PNGCRUSH_LOCO -static int do_loco=0; -static int input_format=0; /* 0: PNG 1: MNG */ -static int output_format=0; +static int do_loco = 0; +static int input_format = 0; /* 0: PNG 1: MNG */ +static int output_format = 0; #endif static int do_color_count; -static int reduction_ok=0; +static int reduction_ok = 0; #ifdef PNGCRUSH_COUNT_COLORS -int count_colors(FILE *fpin); +int count_colors(FILE * fpin); static int num_rgba, reduce_to_gray, it_is_opaque; #endif png_uint_32 png_measure_idat(png_structp png_ptr); -# define MAX_METHODS 200 -# define MAX_METHODSP1 201 -# define DEFAULT_METHODS 10 + static png_uint_32 idat_length[MAX_METHODSP1]; static int filter_type, zlib_level; -static png_bytep png_row_filters=NULL; +static png_bytep png_row_filters = NULL; static float t_start, t_stop, t_decode, t_encode, t_misc; -static png_uint_32 max_idat_size = 524288L; /* increases the IDAT size */ +static png_uint_32 max_idat_size = MAX_IDAT_SIZE; /* increases the IDAT size */ static png_uint_32 crushed_idat_size = 0x3ffffffL; static int already_crushed = 0; int ia; -/********* Functions to make direct access to the png_ptr. *************** - * - * Making direct access to the png_ptr or info_ptr is frowned upon because - * it incurs a risk of binary incompatibility with otherwise compatible - * versions of libpng, so all such accesses are collected here. These - * functions all exist in later versions of libpng. - */ -#if (PNG_LIBPNG_VER < 95) -png_uint_32 -png_get_rowbytes(png_structp png_ptr, png_infop info_ptr) -{ - return ((png_ptr && info_ptr) ? info_ptr->rowbytes : 0); -} -#endif /* (PNG_LIBPNG_VER < 95) */ +/* prototypes */ +static void png_cexcept_error(png_structp png_ptr, png_const_charp msg); -#if (PNG_LIBPNG_VER < 10007) -/* This is binary incompatible with versions earlier than 0.99h because of the - * introduction of png_user_transform stuff ahead of the zbuf_size member - * of png_ptr in libpng version 0.99h. Not needed after libpng-1.0.6g - * because the functions became available in libpng. - */ -static png_uint_32 -png_get_compression_buffer_size(png_structp png_ptr) -{ - if(png_ptr->zbuf_size != PNG_ZBUF_SIZE) - { - fprintf(STDERR, " png_ptr->zbuf_size = %d but PNG_ZBUF_SIZE is %d\n", - png_ptr->zbuf_size, PNG_ZBUF_SIZE); - fprintf(STDERR, " You may be using pngcrush with an incompatible version"); - fprintf(STDERR, " of libpng. pngcrush was compiled with version %s\n", - PNG_LIBPNG_VER_STRING); - } - return(png_ptr->zbuf_size); -} -static void -png_set_compression_buffer_size(png_structp png_ptr, png_uint_32 size) -{ - if(png_ptr->zbuf) - png_free(png_ptr, png_ptr->zbuf); png_ptr->zbuf=NULL; - png_ptr->zbuf_size = (png_size_t)size; - png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size); - if(!png_ptr->zbuf) - png_error(png_ptr,"Unable to malloc zbuf"); -} - -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) -static void -png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr, - int chunk, int location) -{ - if(png_ptr && info_ptr && chunk >= 0 && chunk < info_ptr->unknown_chunks_num) - info_ptr->unknown_chunks[chunk].location = (png_byte)location; -} +#ifdef PNG_USER_MEM_SUPPORTED +png_voidp png_debug_malloc(png_structp png_ptr, png_uint_32 size); +void png_debug_free(png_structp png_ptr, png_voidp ptr); #endif -#endif /* (PNG_LIBPNG_VER < 10007) */ -/************* end of direct access functions *****************************/ +void png_crush_pause(void); -/* cexcept interface */ +#ifdef __riscos +static int fileexists(const char *name) +static int filesize(const char *name) +static int mkdir(const char *name, int ignored) +static void setfiletype(const char *name) +#endif -static void -png_cexcept_error(png_structp png_ptr, png_const_charp msg) +int keep_unknown_chunk(png_const_charp name, char *argv[]); +int keep_chunk(png_const_charp name, char *argv[]); +void show_result(void); +png_uint_32 measure_idats(FILE * fpin); +png_uint_32 png_measure_idat(png_structp png_ptr); + +#ifdef PNGCRUSH_COUNT_COLORS +int count_colors(FILE * fpin); +#endif +void print_version_info(void); +void print_usage(int retval); + + +#if (!defined(PNGCRUSH_H)) +/* ============================================================ + * We aren't using the bundled libpng functions, so we must + * reproduce the libpng routines that aren't exported by libpng + * ============================================================ + */ + +#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED +/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ +png_uint_32 /* PRIVATE */ +png_get_uint_32(png_bytep buf) { - if(png_ptr) - ; -#if (PNG_LIBPNG_VER > 10006 && defined(PNGCRUSH_H)) - if (!strcmp(msg, "Too many IDAT's found")) - { -#ifndef PNG_NO_CONSOLE_IO - fprintf(stderr, "\nIn %s, correcting ",inname); + png_uint_32 i = ((png_uint_32)(*buf) << 24) + + ((png_uint_32)(*(buf + 1)) << 16) + + ((png_uint_32)(*(buf + 2)) << 8) + + (png_uint_32)(*(buf + 3)); + + return (i); +} #else - png_warning(png_ptr, msg); +# define png_get_uint_32(buf) ( *((png_uint_32p) (buf))) +#endif +png_uint_32 /* PRIVATE */ +png_get_uint_31(png_structp png_ptr, png_bytep buf) +{ + png_uint_32 i = png_get_uint_32(buf); + if (i > PNG_UINT_31_MAX) + png_error(png_ptr, "PNG unsigned integer out of range.\n"); + return (i); +} + +/* Reset the CRC variable to 32 bits of 1's. Care must be taken + * in case CRC is > 32 bits to leave the top bits 0. + */ +void /* PRIVATE */ +png_reset_crc(png_structp png_ptr) +{ + png_ptr->crc = crc32(0, Z_NULL, 0); +} +/* Calculate the CRC over a section of data. We can only pass as + * much data to this routine as the largest single buffer size. We + * also check that this data will actually be used before going to the + * trouble of calculating it. + */ +void /* PRIVATE */ +png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length) +{ + int need_crc = 1; + + if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + + if (need_crc) + png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length); +} + +/* Read data, and (optionally) run it through the CRC. */ +void /* PRIVATE */ +png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) +{ + png_read_data(png_ptr, buf, length); + png_calculate_crc(png_ptr, buf, length); +} + +/* Compare the CRC stored in the PNG file with that calculated by libpng from + the data it has read thus far. */ +int /* PRIVATE */ +png_crc_error(png_structp png_ptr) +{ + png_byte crc_bytes[4]; + png_uint_32 crc; + int need_crc = 1; + + if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + + png_read_data(png_ptr, crc_bytes, 4); + + if (need_crc) + { + crc = png_get_uint_32(crc_bytes); + return ((int)(crc != png_ptr->crc)); + } + else + return (0); +} + +/* Optionally skip data and then check the CRC. Depending on whether we + are reading a ancillary or critical chunk, and how the program has set + things up, we may calculate the CRC on the data and print a message. + Returns '1' if there was a CRC error, '0' otherwise. */ +int /* PRIVATE */ +png_crc_finish(png_structp png_ptr, png_uint_32 skip) +{ + png_size_t i; + png_size_t istop = png_ptr->zbuf_size; + + for (i = (png_size_t)skip; i > istop; i -= istop) + { + png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + } + if (i) + { + png_crc_read(png_ptr, png_ptr->zbuf, i); + } + + if (png_crc_error(png_ptr)) + { + if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */ + !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) || + (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */ + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))) + { + png_chunk_warning(png_ptr, "CRC error"); + } + else + { + png_chunk_error(png_ptr, "CRC error"); + } + return (1); + } + + return (0); +} + +/* Modify the info structure to reflect the transformations. The + * info should be updated so a PNG file could be written with it, + * assuming the transformations result in valid PNG data. + */ +void /* PRIVATE */ +png_read_transform_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_transform_info\n"); +#if defined(PNG_READ_EXPAND_SUPPORTED) + if (png_ptr->transformations & PNG_EXPAND) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans) + info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + else + info_ptr->color_type = PNG_COLOR_TYPE_RGB; + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + else + { + if (png_ptr->num_trans) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + if (info_ptr->bit_depth < 8) + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + } +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->transformations & PNG_BACKGROUND) + { + info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; + info_ptr->num_trans = 0; + info_ptr->background = png_ptr->background; + } +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (png_ptr->transformations & PNG_GAMMA) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->gamma = png_ptr->gamma; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = png_ptr->int_gamma; +#endif + } +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) + if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16)) + info_ptr->bit_depth = 8; +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) + if (png_ptr->transformations & PNG_DITHER) + { + if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && + png_ptr->palette_lookup && info_ptr->bit_depth == 8) + { + info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; + } + } +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) + if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) + info_ptr->bit_depth = 8; +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + info_ptr->color_type |= PNG_COLOR_MASK_COLOR; +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR; +#endif + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + else + info_ptr->channels = 1; + +#ifndef PNG_FLAG_ADD_ALPHA +#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */ +#endif +#ifndef PNG_FLAG_STRIP_ALPHA +#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */ +#endif +#ifndef PNG_ADD_ALPHA +#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ +#endif + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) + if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) + info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; +#endif + + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + +#if defined(PNG_READ_FILLER_SUPPORTED) + /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ + if ((png_ptr->transformations & PNG_FILLER) && + ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) + { + info_ptr->channels++; + /* if adding a true alpha channel not just filler */ +#if !defined(PNG_1_0_X) + if (png_ptr->transformations & PNG_ADD_ALPHA) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; +#endif + } +#endif + +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ +defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + if(png_ptr->transformations & PNG_USER_TRANSFORM) + { + if(info_ptr->bit_depth < png_ptr->user_transform_depth) + info_ptr->bit_depth = png_ptr->user_transform_depth; + if(info_ptr->channels < png_ptr->user_transform_channels) + info_ptr->channels = png_ptr->user_transform_channels; + } +#endif + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * + info_ptr->bit_depth); + +#ifndef PNG_ROWBYTES +/* Added to libpng-1.2.6 JB */ +#define PNG_ROWBYTES(pixel_bits, width) \ + ((pixel_bits) >= 8 ? \ + ((width) * (((png_uint_32)(pixel_bits)) >> 3)) : \ + (( ((width) * ((png_uint_32)(pixel_bits))) + 7) >> 3) ) +#endif + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,info_ptr->width); + +#if !defined(PNG_READ_EXPAND_SUPPORTED) + if(png_ptr) + return; +#endif +} + +#if !defined(PNG_NO_STDIO) +/* This is the function that does the actual reading of data. If you are + not reading from a standard C stream, you should create a replacement + read_data function and use it at run time with png_set_read_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +void PNGAPI +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ +#if defined(_WIN32_WCE) + if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = (png_size_t)fread(data, (png_size_t)1, length, + (png_FILE_p)png_ptr->io_ptr); +#endif + + if (check != length) + png_error(png_ptr, "Read Error"); +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void /* PRIVATE */ +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + int check; + png_byte *n_data; + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + n_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)n_data == data) + { +#if defined(_WIN32_WCE) + if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = fread(n_data, 1, length, io_ptr); #endif } else -#endif { - Throw msg; + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); +#if defined(_WIN32_WCE) + if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) ) + err = 0; +#else + err = fread(buf, (png_size_t)1, read, io_ptr); +#endif + png_memcpy(data, buf, read); /* copy far buffer to near buffer */ + if(err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); } + if ((png_uint_32)check != (png_uint_32)length) + png_error(png_ptr, "read Error"); } +#endif +#endif +#if !defined(PNG_NO_STDIO) +/* This is the function that does the actual writing of data. If you are + not writing to a standard C stream, you should create a replacement + write_data function and use it at run time with png_set_write_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +void PNGAPI +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + +#if defined(_WIN32_WCE) + if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); +#endif + if (check != length) + png_error(png_ptr, "Write Error"); +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +void PNGAPI +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + near_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)near_data == data) + { +#if defined(_WIN32_WCE) + if ( !WriteFile(io_ptr, near_data, length, &check, NULL) ) + check = 0; +#else + check = fwrite(near_data, 1, length, io_ptr); +#endif + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* copy far buffer to near buffer */ +#if defined(_WIN32_WCE) + if ( !WriteFile(io_ptr, buf, written, &err, NULL) ) + err = 0; +#else + err = fwrite(buf, 1, written, io_ptr); +#endif + if (err != written) + break; + else + check += err; + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + png_error(png_ptr, "Write Error"); +} + +#endif +#endif + +#endif /* !defined(PNGCRUSH_H) */ + + + +/* cexcept interface */ + +static void png_cexcept_error(png_structp png_ptr, png_const_charp msg) +{ + if (png_ptr); +#if (defined(PNGCRUSH_H)) + if (!strcmp(msg, "Too many IDAT's found")) { +#ifndef PNG_NO_CONSOLE_IO + fprintf(stderr, "\nIn %s, correcting ", inname); +#else + png_warning(png_ptr, msg); +#endif + } else +#endif /* defined(PNGCRUSH_H) */ + { + Throw msg; + } +} + + + /* START of code to validate memory allocation and deallocation */ #ifdef PNG_USER_MEM_SUPPORTED @@ -819,9 +921,9 @@ png_cexcept_error(png_structp png_ptr, png_const_charp msg) This piece of code can be compiled to validate max 64K allocations by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */ typedef struct memory_information { - png_uint_32 size; - png_voidp pointer; - struct memory_information FAR *next; + png_uint_32 size; + png_voidp pointer; + struct memory_information FAR *next; } memory_information; typedef memory_information FAR *memory_infop; @@ -829,136 +931,150 @@ static memory_infop pinformation = NULL; static int current_allocation = 0; static int maximum_allocation = 0; -extern PNG_EXPORT(png_voidp,png_debug_malloc) PNGARG((png_structp png_ptr, - png_uint_32 size)); -extern PNG_EXPORT(void,png_debug_free) PNGARG((png_structp png_ptr, - png_voidp ptr)); -png_voidp -png_debug_malloc(png_structp png_ptr, png_uint_32 size) { - /* png_malloc has already tested for NULL; png_create_struct calls - png_debug_malloc directly (with png_ptr == NULL prior to libpng-1.2.0 - which is OK since we are not using a user mem_ptr) */ - if (size == 0) - return (png_voidp)(NULL); +png_voidp png_debug_malloc(png_structp png_ptr, png_uint_32 size) +{ - /* This calls the library allocator twice, once to get the requested - buffer and once to get a new free list entry. */ - { - memory_infop pinfo = png_malloc_default(png_ptr, sizeof *pinfo); - pinfo->size = size; - current_allocation += size; - if (current_allocation > maximum_allocation) - maximum_allocation = current_allocation; - pinfo->pointer = png_malloc_default(png_ptr, size); - pinfo->next = pinformation; - pinformation = pinfo; - /* Make sure the caller isn't assuming zeroed memory. */ - png_memset(pinfo->pointer, 0xdd, pinfo->size); - if(verbose > 2) - fprintf(STDERR, "Pointer %x allocated %lu bytes\n", - (int)pinfo->pointer, size); - return (png_voidp)(pinfo->pointer); - } + /* png_malloc has already tested for NULL; png_create_struct calls + png_debug_malloc directly (with png_ptr == NULL prior to libpng-1.2.0 + which is OK since we are not using a user mem_ptr) */ + + if (size == 0) + return (png_voidp) (NULL); + + /* This calls the library allocator twice, once to get the requested + buffer and once to get a new free list entry. */ + { + memory_infop pinfo = png_malloc_default(png_ptr, sizeof *pinfo); + pinfo->size = size; + current_allocation += size; + if (current_allocation > maximum_allocation) + maximum_allocation = current_allocation; + pinfo->pointer = png_malloc_default(png_ptr, size); + pinfo->next = pinformation; + pinformation = pinfo; + /* Make sure the caller isn't assuming zeroed memory. */ + png_memset(pinfo->pointer, 0xdd, pinfo->size); + if (verbose > 2) + fprintf(STDERR, "Pointer %x allocated %lu bytes\n", + (int) pinfo->pointer, size); + return (png_voidp) (pinfo->pointer); + } } + + + /* Free a pointer. It is removed from the list at the same time. */ -void -png_debug_free(png_structp png_ptr, png_voidp ptr) +void png_debug_free(png_structp png_ptr, png_voidp ptr) { - if (png_ptr == NULL) - fprintf(STDERR, "NULL pointer to png_debug_free.\n"); - if (ptr == 0) { + if (png_ptr == NULL) + fprintf(STDERR, "NULL pointer to png_debug_free.\n"); + if (ptr == 0) { #if 0 /* This happens all the time. */ - fprintf(STDERR, "WARNING: freeing NULL pointer\n"); + fprintf(STDERR, "WARNING: freeing NULL pointer\n"); #endif - return; - } + return; + } - /* Unlink the element from the list. */ - { - memory_infop FAR *ppinfo = &pinformation; - for (;;) { - memory_infop pinfo = *ppinfo; - if (pinfo->pointer == ptr) { - *ppinfo = pinfo->next; - current_allocation -= pinfo->size; - if (current_allocation < 0) - fprintf(STDERR, "Duplicate free of memory\n"); - /* We must free the list element too, but first kill - the memory that is to be freed. */ - memset(ptr, 0x55, pinfo->size); - if(verbose > 2) - fprintf(STDERR, "Pointer %x freed %lu bytes\n", (int)ptr, - pinfo->size); - png_free_default(png_ptr, pinfo); - break; - } - if (pinfo->next == NULL) { - fprintf(STDERR, "Pointer %x not found\n", (int)ptr); - break; - } - ppinfo = &pinfo->next; - } - } + /* Unlink the element from the list. */ + { + memory_infop FAR *ppinfo = &pinformation; + for (;;) { + memory_infop pinfo = *ppinfo; + if (pinfo->pointer == ptr) { + *ppinfo = pinfo->next; + current_allocation -= pinfo->size; + if (current_allocation < 0) + fprintf(STDERR, "Duplicate free of memory\n"); + /* We must free the list element too, but first kill + the memory that is to be freed. */ + memset(ptr, 0x55, pinfo->size); + if (verbose > 2) + fprintf(STDERR, "Pointer %x freed %lu bytes\n", + (int) ptr, pinfo->size); + png_free_default(png_ptr, pinfo); + break; + } + if (pinfo->next == NULL) { + fprintf(STDERR, "Pointer %x not found\n", (int) ptr); + break; + } + ppinfo = &pinfo->next; + } + } - /* Finally free the data. */ - png_free_default(png_ptr, ptr); + /* Finally free the data. */ + png_free_default(png_ptr, ptr); } + #endif /* PNG_USER_MEM_SUPPORTED */ /* END of code to test memory allocation/deallocation */ -void png_crush_pause(void); + + + void png_crush_pause(void) { - if(pauses > 0) - { - char keystroke; - fprintf(STDERR, "Press [ENTER] key to continue.\n"); - keystroke=(char)getc(stdin); - keystroke = keystroke; /* stifle compiler warning */ - } + if (pauses > 0) { + char keystroke; + fprintf(STDERR, "Press [ENTER] key to continue.\n"); + keystroke = (char) getc(stdin); + keystroke = keystroke; /* stifle compiler warning */ + } } -#ifdef __riscos + + + +#ifndef __riscos +# define setfiletype(x) + +#else /* defined(__riscos) */ +# include + /* The riscos/acorn support was contributed by Darren Salt. */ -#include static int fileexists(const char *name) { # ifdef __acorn - int ret; - return _swix (8, 3 | 1<<31, 17, name, &ret) ? 0 : ret; + int ret; + return _swix(8, 3 | 1 << 31, 17, name, &ret) ? 0 : ret; # else - _kernel_swi_regs r; - r.r[0] = 17; r.r[1] = (int) name; - return _kernel_swi(8, &r, &r) ? 0 : r.r[0]; + _kernel_swi_regs r; + r.r[0] = 17; + r.r[1] = (int) name; + return _kernel_swi(8, &r, &r) ? 0 : r.r[0]; # endif } + static int filesize(const char *name) { # ifdef __acorn - int ret; - return _swix (8, 3 | 1<<27, 17, name, &ret) ? 0 : ret; + int ret; + return _swix(8, 3 | 1 << 27, 17, name, &ret) ? 0 : ret; # else - _kernel_swi_regs r; - r.r[0] = 17; r.r[1] = (int) name; - return _kernel_swi(8, &r, &r) ? 0 : r.r[4]; + _kernel_swi_regs r; + r.r[0] = 17; + r.r[1] = (int) name; + return _kernel_swi(8, &r, &r) ? 0 : r.r[4]; # endif } + static int mkdir(const char *name, int ignored) { # ifdef __acorn - _swi (8, 0x13, 8, name, 0); - return 0; + _swi(8, 0x13, 8, name, 0); + return 0; # else - _kernel_swi_regs r; - r.r[0] = 8; r.r[1] = (int) name; - r.r[4] = r.r[3] = r.r[2] = 0; - return (int)_kernel_swi(8 | 1<<31, &r, &r); + _kernel_swi_regs r; + r.r[0] = 8; + r.r[1] = (int) name; + r.r[4] = r.r[3] = r.r[2] = 0; + return (int) _kernel_swi(8 | 1 << 31, &r, &r); # endif } @@ -966,4138 +1082,4270 @@ static int mkdir(const char *name, int ignored) static void setfiletype(const char *name) { # ifdef __acorn - _swi (8, 7, 18, name, 0xB60); + _swi(8, 7, 18, name, 0xB60); # else - _kernel_swi_regs r; - r.r[0] = 18; r.r[1] = (int) name; r.r[2] = 0xB60; - _kernel_swi(8 | 1<<31, &r, &r); + _kernel_swi_regs r; + r.r[0] = 18; + r.r[1] = (int) name; + r.r[2] = 0xB60; + _kernel_swi(8 | 1 << 31, &r, &r); # endif } -#else /* !defined(__riscos) */ -# define setfiletype(x) -#endif -int keep_unknown_chunk(png_const_charp name, char *argv[]); +#endif /* ?defined(__riscos) */ + + + +/* GRR: basically boolean; first arg is chunk name-string (e.g., "tIME" or + * "alla"); second is always full argv[] command line + * - remove_chunks is argv index of *last* -rem arg on command line + * (would be more efficient to build table at time of cmdline processing!) + * (i.e., build removal_list with names or unique IDs or whatever--skip + * excessive string-processing on every single one) + * - reprocesses command line _every_ time called, looking for -rem opts... + * - just like keep_chunk() except that latter sets things_have_changed + * variable and debug stmts say "Removed chunk" (but caller actually does + * so, by choosing not to copy chunk to new file) + * - for any given chunk name, "name" must either match exact command-line + * arg (e.g., -rem fOOb), OR it must match one of the official PNG chunk + * names explicitly listed below AND command-line arg either used all- + * lowercase form or one of "all[ab]" options + */ int keep_unknown_chunk(png_const_charp name, char *argv[]) { int i; - if(remove_chunks == 0) return 1; - for (i=1; i<=remove_chunks; i++) - { - if(!strncmp(argv[i],"-rem",4)) - { - int alla = 0; - int allb = 0; - i++; - if(!strncmp(argv[i],"alla",4)) alla++; /* all ancillaries */ - if(!strncmp(argv[i],"all",3)) allb++; /* all but gamma */ - if(!strncmp(argv[i],name,4) || - (!strncmp(name,"cHRM",4) && (!strncmp(argv[i],"chrm",4) || allb)) || - (!strncmp(name,"gIFg",4) && (!strncmp(argv[i],"gifg",4) || allb)) || - (!strncmp(name,"gIFt",4) && (!strncmp(argv[i],"gift",4) || allb)) || - (!strncmp(name,"gIFx",4) && (!strncmp(argv[i],"gifx",4) || allb)) || - (!strncmp(name,"hIST",4) && (!strncmp(argv[i],"hist",4) || allb)) || - (!strncmp(name,"iCCP",4) && (!strncmp(argv[i],"iccp",4) || allb)) || - (!strncmp(name,"pCAL",4) && (!strncmp(argv[i],"pcal",4) || allb)) || - (!strncmp(name,"sCAL",4) && (!strncmp(argv[i],"scal",4) || allb)) || - (!strncmp(name,"sPLT",4) && (!strncmp(argv[i],"splt",4) || allb)) || - (!strncmp(name,"tIME",4) && (!strncmp(argv[i],"time",4) || allb))) - { - return 0; - } - } + if (remove_chunks == 0) + return 1; /* no -rem options, so always keeping */ + for (i = 1; i <= remove_chunks; i++) { + if (!strncmp(argv[i], "-rem", 4)) { + int allb = 0; + i++; + if (!strncmp(argv[i], "all", 3)) { + allb++; /* all but gamma, but not doing gamma here */ + } + if (!strncmp(argv[i], name, 4) /* exact chunk-name match in args */ + /* ...or exact match for one of known set, plus args included + * either "alla", "allb", or all-lowercase form of "name" */ + || (!strncmp(name, "cHRM", 4) + && (!strncmp(argv[i], "chrm", 4) || allb)) + || (!strncmp(name, "gIFg", 4) + && (!strncmp(argv[i], "gifg", 4) || allb)) + || (!strncmp(name, "gIFt", 4) + && (!strncmp(argv[i], "gift", 4) || allb)) + || (!strncmp(name, "gIFx", 4) + && (!strncmp(argv[i], "gifx", 4) || allb)) + || (!strncmp(name, "hIST", 4) + && (!strncmp(argv[i], "hist", 4) || allb)) + || (!strncmp(name, "iCCP", 4) + && (!strncmp(argv[i], "iccp", 4) || allb)) + || (!strncmp(name, "pCAL", 4) + && (!strncmp(argv[i], "pcal", 4) || allb)) + || (!strncmp(name, "sCAL", 4) + && (!strncmp(argv[i], "scal", 4) || allb)) + || (!strncmp(name, "sPLT", 4) + && (!strncmp(argv[i], "splt", 4) || allb)) + || (!strncmp(name, "tIME", 4) + && (!strncmp(argv[i], "time", 4) || allb))) + { + return 0; + } + } } return 1; } -int keep_chunk(png_const_charp name, char *argv[]); + + int keep_chunk(png_const_charp name, char *argv[]) { int i; - if(verbose > 2 && first_trial) - fprintf(STDERR, " Read the %s chunk.\n", name); - if(remove_chunks == 0) return 1; - if(verbose > 1 && first_trial) - fprintf(STDERR, " Check for removal of the %s chunk.\n", name); - for (i=1; i<=remove_chunks; i++) - { - if(!strncmp(argv[i],"-rem",4)) - { - int alla = 0; - int allb = 0; - i++; - if(!strncmp(argv[i],"alla",4)) alla++; /* all ancillaries */ - if(!strncmp(argv[i],"all",3)) allb++; /* all but gamma */ - if(!strncmp(argv[i],name,4) || - (!strncmp(name,"PLTE",4) && (!strncmp(argv[i],"plte",4))) || - (!strncmp(name,"bKGD",4) && (!strncmp(argv[i],"bkgd",4) || allb)) || - (!strncmp(name,"cHRM",4) && (!strncmp(argv[i],"chrm",4) || allb)) || - (!strncmp(name,"gAMA",4) && (!strncmp(argv[i],"gama",4) || alla)) || - (!strncmp(name,"gIFg",4) && (!strncmp(argv[i],"gifg",4) || allb)) || - (!strncmp(name,"gIFt",4) && (!strncmp(argv[i],"gift",4) || allb)) || - (!strncmp(name,"gIFx",4) && (!strncmp(argv[i],"gifx",4) || allb)) || - (!strncmp(name,"hIST",4) && (!strncmp(argv[i],"hist",4) || allb)) || - (!strncmp(name,"iCCP",4) && (!strncmp(argv[i],"iccp",4) || allb)) || - (!strncmp(name,"iTXt",4) && (!strncmp(argv[i],"itxt",4) || allb)) || - (!strncmp(name,"iTXt",4) && (!strncmp(argv[i],"text",4) )) || - (!strncmp(name,"oFFs",4) && (!strncmp(argv[i],"offs",4) || allb)) || - (!strncmp(name,"pHYs",4) && (!strncmp(argv[i],"phys",4) || allb)) || - (!strncmp(name,"pCAL",4) && (!strncmp(argv[i],"pcal",4) || allb)) || - (!strncmp(name,"sBIT",4) && (!strncmp(argv[i],"sbit",4) || allb)) || - (!strncmp(name,"sCAL",4) && (!strncmp(argv[i],"scal",4) || allb)) || - (!strncmp(name,"sRGB",4) && (!strncmp(argv[i],"srgb",4) || allb)) || - (!strncmp(name,"sPLT",4) && (!strncmp(argv[i],"splt",4) || allb)) || - (!strncmp(name,"tEXt",4) && (!strncmp(argv[i],"text",4) || allb)) || - (!strncmp(name,"tIME",4) && (!strncmp(argv[i],"time",4) || allb)) || - (!strncmp(name,"tRNS",4) && (!strncmp(argv[i],"trns",4) )) || - (!strncmp(name,"zTXt",4) && (!strncmp(argv[i],"ztxt",4) || allb)) || - (!strncmp(name,"zTXt",4) && (!strncmp(argv[i],"text",4) ))) - { - things_have_changed=1; - if(verbose > 0 && first_trial) - fprintf(STDERR, " Removed the %s chunk.\n", name); - return 0; - } - } + if (verbose > 2 && first_trial) + fprintf(STDERR, " Read the %s chunk.\n", name); + if (remove_chunks == 0) + return 1; + if (verbose > 1 && first_trial) + fprintf(STDERR, " Check for removal of the %s chunk.\n", name); + for (i = 1; i <= remove_chunks; i++) { + if (!strncmp(argv[i], "-rem", 4)) { + int alla = 0; + int allb = 0; + int allt = 0; + i++; + if (!strncmp(argv[i], "all", 3)) { + allt++; /* all forms of text chunk are ancillary */ + allb++; /* all ancillaries but gamma... */ + if (!strncmp(argv[i], "alla", 4)) + alla++; /* ...no, all ancillaries, period */ + } else if (!strncmp(argv[i], "text", 4)) + allt++; /* all forms of text chunk */ + if (!strncmp(argv[i], name, 4) /* exact chunk-name match in args + * ...or exact match for one of known set, plus args included + * either "alla", "allb", or all-lowercase form of "name": */ + || (!strncmp(name, "PLTE", 4) + && (!strncmp(argv[i], "plte", 4) )) + || (!strncmp(name, "bKGD", 4) + && (!strncmp(argv[i], "bkgd", 4) || allb)) + || (!strncmp(name, "cHRM", 4) + && (!strncmp(argv[i], "chrm", 4) || allb)) + || (!strncmp(name, "gAMA", 4) + && (!strncmp(argv[i], "gama", 4) || alla)) + || (!strncmp(name, "gIFg", 4) + && (!strncmp(argv[i], "gifg", 4) || allb)) + || (!strncmp(name, "gIFt", 4) + && (!strncmp(argv[i], "gift", 4) || allb)) + || (!strncmp(name, "gIFx", 4) + && (!strncmp(argv[i], "gifx", 4) || allb)) + || (!strncmp(name, "hIST", 4) + && (!strncmp(argv[i], "hist", 4) || allb)) + || (!strncmp(name, "iCCP", 4) + && (!strncmp(argv[i], "iccp", 4) || allb)) + || (!strncmp(name, "iTXt", 4) + && (!strncmp(argv[i], "itxt", 4) || allt)) + || (!strncmp(name, "oFFs", 4) + && (!strncmp(argv[i], "offs", 4) || allb)) + || (!strncmp(name, "pHYs", 4) + && (!strncmp(argv[i], "phys", 4) || allb)) + || (!strncmp(name, "pCAL", 4) + && (!strncmp(argv[i], "pcal", 4) || allb)) + || (!strncmp(name, "sBIT", 4) + && (!strncmp(argv[i], "sbit", 4) || allb)) + || (!strncmp(name, "sCAL", 4) + && (!strncmp(argv[i], "scal", 4) || allb)) + || (!strncmp(name, "sRGB", 4) + && (!strncmp(argv[i], "srgb", 4) || allb)) + || (!strncmp(name, "sPLT", 4) + && (!strncmp(argv[i], "splt", 4) || allb)) + || (!strncmp(name, "tEXt", 4) + && ( allt)) + || (!strncmp(name, "tIME", 4) + && (!strncmp(argv[i], "time", 4) || allb)) + || (!strncmp(name, "tRNS", 4) + && (!strncmp(argv[i], "trns", 4) )) + || (!strncmp(name, "zTXt", 4) + && (!strncmp(argv[i], "ztxt", 4) || allt)) ) + { + things_have_changed = 1; + /* (caller actually does the removal--by failing to create + * copy) */ + if (verbose > 0 && first_trial) + fprintf(STDERR, " Removed the %s chunk.\n", name); + return 0; + } + } } - if(verbose > 1 && first_trial) - fprintf(STDERR, " Preserving the %s chunk.\n", name); + if (verbose > 1 && first_trial) + fprintf(STDERR, " Preserving the %s chunk.\n", name); return 1; } -void -show_result(void) + + + +void show_result(void) { - if(total_output_length) - { - if(total_input_length == total_output_length) - fprintf(STDERR, - " Overall result: no change\n"); - else if(total_input_length > total_output_length) - fprintf(STDERR, - " Overall result: %4.2f%% reduction, %ld bytes\n", - (100.0 - (100.0*total_output_length)/total_input_length), - total_input_length - total_output_length); - else - fprintf(STDERR, - " Overall result: %4.2f%% increase, %ld bytes\n", - -(100.0 - (100.0*total_output_length)/total_input_length), - total_output_length - total_input_length); - } - t_stop = (TIME_T)clock(); - t_misc += (t_stop - t_start); - if (t_stop < t_start) - { - t_misc+= PNG_MAX_UINT; - if (t_stop < 0) - t_misc+= PNG_MAX_UINT; - } - t_start = t_stop; - fprintf(STDERR," CPU time used = %.3f seconds", - (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); - fprintf(STDERR," (decoding %.3f,\n", - t_decode/(float)CLOCKS_PER_SEC); - fprintf(STDERR," encoding %.3f,", - t_encode/(float)CLOCKS_PER_SEC); - fprintf(STDERR," other %.3f seconds)\n\n", - t_misc/(float)CLOCKS_PER_SEC); + if (total_output_length) { + if (total_input_length == total_output_length) + fprintf(STDERR, " Overall result: no change\n"); + else if (total_input_length > total_output_length) + fprintf(STDERR, + " Overall result: %4.2f%% reduction, %ld bytes\n", + (100.0 - + (100.0 * total_output_length) / total_input_length), + total_input_length - total_output_length); + else + fprintf(STDERR, + " Overall result: %4.2f%% increase, %ld bytes\n", + -(100.0 - + (100.0 * total_output_length) / total_input_length), + total_output_length - total_input_length); + } + t_stop = (TIME_T) clock(); + t_misc += (t_stop - t_start); + if (t_stop < t_start) { + t_misc += PNG_MAX_UINT; + if (t_stop < 0) + t_misc += PNG_MAX_UINT; + } + t_start = t_stop; + fprintf(STDERR, " CPU time used = %.3f seconds", + (t_misc + t_decode + t_encode) / (float) CLOCKS_PER_SEC); + fprintf(STDERR, " (decoding %.3f,\n", + t_decode / (float) CLOCKS_PER_SEC); + fprintf(STDERR, " encoding %.3f,", + t_encode / (float) CLOCKS_PER_SEC); + fprintf(STDERR, " other %.3f seconds)\n\n", + t_misc / (float) CLOCKS_PER_SEC); #ifdef PNG_USER_MEM_SUPPORTED - if (current_allocation) { - memory_infop pinfo = pinformation; - fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", - current_allocation); - while (pinfo != NULL) { - fprintf(STDERR, " %8lu bytes at %x\n", pinfo->size, - (int)pinfo->pointer); - free(pinfo->pointer); - pinfo = pinfo->next; - } - } + if (current_allocation) { + memory_infop pinfo = pinformation; + fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", + current_allocation); + while (pinfo != NULL) { + fprintf(STDERR, " %8lu bytes at %x\n", pinfo->size, + (int) pinfo->pointer); + free(pinfo->pointer); + pinfo = pinfo->next; + } + } #endif } -int -main(int argc, char *argv[]) + + + +int main(int argc, char *argv[]) { - png_uint_32 y; - int bit_depth, color_type; - int num_pass, pass; - int try_method[MAX_METHODSP1]; - int fm[MAX_METHODSP1]; - int lv[MAX_METHODSP1]; - int zs[MAX_METHODSP1]; - int ntrial; - int lev, strat, filt; + png_uint_32 y; + int bit_depth, color_type; + int num_pass, pass; + int num_methods; + int try_method[MAX_METHODSP1]; + int fm[MAX_METHODSP1]; + int lv[MAX_METHODSP1]; + int zs[MAX_METHODSP1]; + int lev, strat, filt; #ifdef PNG_gAMA_SUPPORTED #ifdef PNG_FIXED_POINT_SUPPORTED - png_fixed_point file_gamma=0; + png_fixed_point file_gamma = 0; #else - double file_gamma=0.; + double file_gamma = 0.; #endif #endif - char *cp; - int i; - row_buf = (png_bytep)NULL; - number_of_open_files=0; + char *cp; + int i; + row_buf = (png_bytep) NULL; + number_of_open_files = 0; #ifdef PNGCRUSH_COUNT_COLORS - reduce_to_gray=0; - it_is_opaque=0; + reduce_to_gray = 0; + it_is_opaque = 0; #else - do_color_count = 0; - do_color_count = do_color_count; /* silence compiler warning */ + do_color_count = 0; + do_color_count = do_color_count; /* silence compiler warning */ #endif - if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) - { - fprintf(STDERR, - "Warning: versions are different between png.h and png.c\n"); - fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); - fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); - } + if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) { + fprintf(STDERR, + "Warning: versions are different between png.h and png.c\n"); + fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); + } - t_start = (TIME_T)clock(); + t_start = (TIME_T) clock(); - prog_string[0] = '\0'; - str_return = strcat(prog_string,argv[0]); - progname = prog_string; - for(i=0, cp=prog_string; *cp!='\0'; i++, cp++) - { + strncpy(prog_string, argv[0], STR_BUF_SIZE); + prog_string[STR_BUF_SIZE-1] = '\0'; + progname = prog_string; + for (i = 0, cp = prog_string; *cp != '\0'; i++, cp++) { #ifdef __riscos - if(*cp == '.' || *cp == ':') progname = ++cp; + if (*cp == '.' || *cp == ':') + progname = ++cp; #else - if(*cp == '\\' || *cp == '/') progname = ++cp; - if(*cp == '.') *cp='\0'; + if (*cp == '\\' || *cp == '/') + progname = ++cp; + if (*cp == '.') + *cp = '\0'; #endif - } + } - for(i=0; i= argc) {printf("insufficient parameters\n");exit(1);} - names=1; - for (i=1; i 5 || specified_filter < 0) - specified_filter = 5; - names++; - if(brute_force == 0) - fm[method]=specified_filter; - else - { - for (filt=0; filt<6; filt++) - brute_force_filters[filt]=1; - brute_force_filters[specified_filter]=0; - method=11; - for(filt=0; filt<6; filt++) - { - try_method[method]= brute_force_filters[filt] | - brute_force_strategies[2]; - method++; + } + + else if (!strncmp(argv[i], "-already", 8)) { + names++; + BUMP_I; + crushed_idat_size = (png_uint_32) atoi(argv[i]); + } + + else if (!strncmp(argv[i], "-bkgd", 5) || + !strncmp(argv[i], "-bKGD", 5)) + { + names += 3; + have_bkgd = 1; + bkgd_red = (png_uint_16) atoi(argv[++i]); + bkgd_green = (png_uint_16) atoi(argv[++i]); + bkgd_blue = (png_uint_16) atoi(argv[++i]); + } + + else if (!strncmp(argv[i], "-brute", 6)) + /* brute force: try everything */ + { + int lev, strat, filt; + methods_specified = 1; + brute_force++; + for (method = 11; method < num_methods; method++) + try_method[method] = 0; + if (brute_force_filter == 0) + for (filt = 0; filt < 6; filt++) + brute_force_filters[filt] = 0; + if (brute_force_level == 0) + for (lev = 0; lev < 10; lev++) + brute_force_levels[lev] = 0; + if (brute_force_strategy == 0) + for (strat = 0; strat < NUM_STRATEGIES; strat++) + brute_force_strategies[strat] = 0; + } else if (!strncmp(argv[i], "-bit_depth", 10)) { + names++; + BUMP_I; + force_output_bit_depth = atoi(argv[i]); + } else if (!strncmp(argv[i], "-cc", 3)) { + do_color_count = 1; + } else if (!strncmp(argv[i], "-no_cc", 6)) { + do_color_count = 0; + } else if (!strncmp(argv[i], "-c", 2)) { + names++; + BUMP_I; + force_output_color_type = atoi(argv[i]); + } +#ifdef PNG_gAMA_SUPPORTED + else if (!strncmp(argv[i], "-dou", 4)) { + double_gamma++; + global_things_have_changed = 1; + } +#endif + else if (!strncmp(argv[i], "-d", 2)) { + BUMP_I; + if (pngcrush_mode == EXTENSION_MODE) + pngcrush_mode = DIREX_MODE; + else + pngcrush_mode = DIRECTORY_MODE; + directory_name = argv[names++]; + } else if (!strncmp(argv[i], "-exit", 5)) { + pngcrush_must_exit = 1; + } else if (!strncmp(argv[i], "-e", 2)) { + BUMP_I; + if (pngcrush_mode == DIRECTORY_MODE) + pngcrush_mode = DIREX_MODE; + else + pngcrush_mode = EXTENSION_MODE; + extension = argv[names++]; + } else if (!strncmp(argv[i], "-force", 6)) { + global_things_have_changed = 1; + } else if (!strncmp(argv[i], "-fix", 4)) { + fix++; + } else if (!strncmp(argv[i], "-f", 2)) { + int specified_filter = atoi(argv[++i]); + int lev, strat, filt; + if (specified_filter > 5 || specified_filter < 0) + specified_filter = 5; + names++; + if (brute_force == 0) + fm[method] = specified_filter; + else { + for (filt = 0; filt < 6; filt++) + brute_force_filters[filt] = 1; + brute_force_filters[specified_filter] = 0; + method = 11; + for (filt = 0; filt < 6; filt++) { + try_method[method] = brute_force_filters[filt] | + brute_force_strategies[2]; + method++; + } + for (lev = 1; lev < 10; lev++) { + for (strat = 0; strat < 2; strat++) { + for (filt = 0; filt < 6; filt++) { + try_method[method] = brute_force_levels[lev] | + brute_force_filters[filt] | + brute_force_strategies[strat]; + method++; + } + } + } + brute_force_filter++; } - for(lev=1; lev<10; lev++) - { - for(strat=0; strat<2; strat++) - { - for(filt=0; filt<6; filt++) - { - try_method[method]=brute_force_levels[lev] | - brute_force_filters[filt] | - brute_force_strategies[strat]; - method++; - } - } - } - brute_force_filter++; - } - } - else if(!strncmp(argv[i],"-loco",5)) - { + } else if (!strncmp(argv[i], "-loco", 5)) { #ifdef PNGCRUSH_LOCO - do_loco=1; + do_loco = 1; #else - printf( - "Cannot do -loco because libpng was compiled without MNG features"); + printf + ("Cannot do -loco because libpng was compiled without MNG features"); #endif - } - else if(!strncmp(argv[i],"-l",2)) - { - int lev, strat, filt; - int specified_level=atoi(argv[++i]); - if(specified_level > 9 || specified_level < 0) - specified_level = 9; - names++; - if(brute_force == 0) - lv[method]=specified_level; - else - { - if(brute_force_level == 0) - for (lev=0; lev<10; lev++) - brute_force_levels[lev]=1; - brute_force_levels[specified_level]=0; - method=11; - for(filt=0; filt<6; filt++) - { - lv[method]=specified_level; - method++; - } - for(lev=1; lev<10; lev++) - { - for(strat=0; strat<2; strat++) - { - for(filt=0; filt<6; filt++) - { - try_method[method]=brute_force_levels[lev] | - brute_force_filters[filt] | - brute_force_strategies[strat]; - method++; - } - } - } - brute_force_level++; - } - } -#ifdef PNG_gAMA_SUPPORTED - else if(!strncmp(argv[i],"-g",2)) - { - names++; - BUMP_I; - if (intent < 0) - { -#ifdef PNG_FIXED_POINT_SUPPORTED - int c; - char number[16]; - char *n=number; - int nzeroes=-1; - int length=strlen(argv[i]); - for (c=0; c 9 || specified_level < 0) + specified_level = 9; + names++; + if (brute_force == 0) + lv[method] = specified_level; + else { + if (brute_force_level == 0) + for (lev = 0; lev < 10; lev++) + brute_force_levels[lev] = 1; + brute_force_levels[specified_level] = 0; + method = 11; + for (filt = 0; filt < 6; filt++) { + lv[method] = specified_level; + method++; + } + for (lev = 1; lev < 10; lev++) { + for (strat = 0; strat < 2; strat++) { + for (filt = 0; filt < 6; filt++) { + try_method[method] = brute_force_levels[lev] | + brute_force_filters[filt] | + brute_force_strategies[strat]; + method++; } - else if (nzeroes) - { - *n++=*(argv[i]+c); - nzeroes--; - } - } - for (c=0; c PNG_MAX_UINT) - max_idat_size=PNG_ZBUF_SIZE; - } - else if(!strncmp(argv[i],"-m",2)) - { - names++; - BUMP_I; - method=atoi(argv[i]); - methods_specified=1; - brute_force=0; - try_method[method]=0; - } - else if(!strncmp(argv[i],"-nofilecheck",5)) - nofilecheck++; - else if(!strncmp(argv[i],"-nosave",2)) - { - /* no save; I just use this for testing decode speed */ - nosave++; - pngcrush_mode=EXTENSION_MODE; - } - else if(!strncmp(argv[i],"-plte_len",9)) - { - names++; - BUMP_I; - plte_len=atoi(argv[i]); - } - else if(!strncmp(argv[i],"-pplt",3)) - { - names++; - do_pplt++; - BUMP_I; - strcpy(pplt_string,argv[i]); - global_things_have_changed=1; - } - else if(!strncmp(argv[i],"-p",2)) - { - pauses++; - } - else if(!strncmp(argv[i],"-q",2)) - verbose=0; - else if(!strncmp(argv[i],"-reduce",7)) - { - reduction_ok++; - do_color_count=1; - } + } #ifdef PNG_gAMA_SUPPORTED - else if(!strncmp(argv[i],"-rep",4)) - { - names++; - BUMP_I; - { + else if (!strncmp(argv[i], "-g", 2)) { + names++; + BUMP_I; + if (intent < 0) { #ifdef PNG_FIXED_POINT_SUPPORTED - int c; - char number[16]; - char *n=number; - int nzeroes=-1; - int length=strlen(argv[i]); - for (c=0; c PNG_MAX_UINT) + max_idat_size = PNG_ZBUF_SIZE; + } else if (!strncmp(argv[i], "-m", 2)) { + names++; + BUMP_I; + method = atoi(argv[i]); + methods_specified = 1; + brute_force = 0; + try_method[method] = 0; + } else if (!strncmp(argv[i], "-nofilecheck", 5)) { + nofilecheck++; + } else if (!strncmp(argv[i], "-nosave", 2)) { + /* no save; I just use this for testing decode speed */ + nosave++; + pngcrush_mode = EXTENSION_MODE; + } else if (!strncmp(argv[i], "-plte_len", 9)) { + names++; + BUMP_I; + plte_len = atoi(argv[i]); + } else if (!strncmp(argv[i], "-pplt", 3)) { + names++; + do_pplt++; + BUMP_I; + strcpy(pplt_string, argv[i]); + global_things_have_changed = 1; + } else if (!strncmp(argv[i], "-p", 2)) { + pauses++; + } else if (!strncmp(argv[i], "-q", 2)) { + verbose = 0; + } else if (!strncmp(argv[i], "-reduce", 7)) { + reduction_ok++; + do_color_count = 1; + } +#ifdef PNG_gAMA_SUPPORTED + else if (!strncmp(argv[i], "-rep", 4)) { + names++; + BUMP_I; + { +#ifdef PNG_FIXED_POINT_SUPPORTED + int c; + char number[16]; + char *n = number; + int nzeroes = -1; + int length = strlen(argv[i]); + for (c = 0; c < length; c++) { + if (*(argv[i] + c) == '.') { + nzeroes = 5; + } else if (nzeroes) { + *n++ = *(argv[i] + c); + nzeroes--; + } + } + for (c = 0; c < nzeroes; c++) + *n++ = '0'; + *n = '\0'; + force_specified_gamma = atoi(number); +#else + force_specified_gamma = atof(argv[i]); +#endif + } + global_things_have_changed = 1; + } #endif #ifdef PNG_pHYs_SUPPORTED - else if(!strncmp(argv[i],"-res",4)) - { - names++; - BUMP_I; - resolution=atoi(argv[i]); - global_things_have_changed=1; - } + else if (!strncmp(argv[i], "-res", 4)) { + names++; + BUMP_I; + resolution = atoi(argv[i]); + global_things_have_changed = 1; + } #endif #ifdef PNGCRUSH_MULTIPLE_ROWS - else if(!strncmp(argv[i],"-rows",5)) - { - names++; - BUMP_I; - max_rows_at_a_time=atoi(argv[i]); - } + else if (!strncmp(argv[i], "-rows", 5)) { + names++; + BUMP_I; + max_rows_at_a_time = atoi(argv[i]); + } #endif - else if(!strncmp(argv[i],"-r",2)) - { - remove_chunks=i; - names++; - BUMP_I; - } - else if( !strncmp(argv[i],"-save",5)) - all_chunks_are_safe++; - else if( !strncmp(argv[i],"-srgb",5) || - !strncmp(argv[i],"-sRGB",5)) - { + else if (!strncmp(argv[i], "-r", 2)) { + remove_chunks = i; + names++; + BUMP_I; + } else if (!strncmp(argv[i], "-save", 5)) { + all_chunks_are_safe++; + } else if (!strncmp(argv[i], "-srgb", 5) || + !strncmp(argv[i], "-sRGB", 5)) { #ifdef PNG_gAMA_SUPPORTED #ifdef PNG_FIXED_POINT_SUPPORTED - specified_gamma=45455L; + specified_gamma = 45455L; #else - specified_gamma=0.45455; + specified_gamma = 0.45455; #endif #endif - intent=0; - BUMP_I; - if(!strncmp(argv[i],"0",1) || - !strncmp(argv[i],"1",1) || - !strncmp(argv[i],"2",1) || - !strncmp(argv[i],"3",1)) - { - names++; - intent=(int)atoi(argv[i]); - } - else - i--; - } - else if(!strncmp(argv[i],"-s",2)) - verbose=0; - else if( !strncmp(argv[i],"-text",5) || !strncmp(argv[i],"-tEXt",5) || + intent = 0; + BUMP_I; + if (!strncmp(argv[i], "0", 1) || + !strncmp(argv[i], "1", 1) || + !strncmp(argv[i], "2", 1) || !strncmp(argv[i], "3", 1)) { + names++; + intent = (int) atoi(argv[i]); + } else + i--; + } else if (!strncmp(argv[i], "-s", 2)) { + verbose = 0; + } else if (!strncmp(argv[i], "-text", 5) + || !strncmp(argv[i], "-tEXt", 5) || #ifdef PNG_iTXt_SUPPORTED - !strncmp(argv[i],"-itxt",5) || !strncmp(argv[i],"-iTXt",5) || - !strncmp(argv[i],"-zitxt",6) || !strncmp(argv[i],"-ziTXt",6) || + !strncmp(argv[i], "-itxt", 5) + || !strncmp(argv[i], "-iTXt", 5) + || !strncmp(argv[i], "-zitxt", 6) + || !strncmp(argv[i], "-ziTXt", 6) || #endif - !strncmp(argv[i],"-ztxt",5) || !strncmp(argv[i],"-zTXt",5)) - { - i+=2; BUMP_I; i-=3; - if(strlen(argv[i+2]) < 80 && strlen(argv[i+3]) < 2048 && - text_inputs < 10) - { + !strncmp(argv[i], "-ztxt", 5) + || !strncmp(argv[i], "-zTXt", 5)) + { + i += 2; + BUMP_I; + i -= 3; + if (strlen(argv[i + 2]) < 80 && strlen(argv[i + 3]) < 2048 && + text_inputs < 10) { #ifdef PNG_iTXt_SUPPORTED - if( !strncmp(argv[i],"-zi",3)) - { - text_compression[text_inputs] = PNG_ITXT_COMPRESSION_zTXt; - names+=2; - } - else + if (!strncmp(argv[i], "-zi", 3)) { + text_compression[text_inputs] = + PNG_ITXT_COMPRESSION_zTXt; + names += 2; + } else #endif - if( !strncmp(argv[i],"-z",2)) - text_compression[text_inputs] = PNG_TEXT_COMPRESSION_zTXt; - else if( !strncmp(argv[i],"-t",2)) - text_compression[text_inputs] = PNG_TEXT_COMPRESSION_NONE; + if (!strncmp(argv[i], "-z", 2)) + text_compression[text_inputs] = + PNG_TEXT_COMPRESSION_zTXt; + else if (!strncmp(argv[i], "-t", 2)) + text_compression[text_inputs] = + PNG_TEXT_COMPRESSION_NONE; #ifdef PNG_iTXt_SUPPORTED - else - { - text_compression[text_inputs] = PNG_ITXT_COMPRESSION_NONE; - names+=2; - } + else { + text_compression[text_inputs] = + PNG_ITXT_COMPRESSION_NONE; + names += 2; + } #endif - names+=3; - if( !strncmp(argv[++i],"b",1)) - text_where[text_inputs]=1; - if( !strncmp(argv[i],"a",1)) - text_where[text_inputs]=2; - strcpy(&text_keyword[text_inputs*80],argv[++i]); + names += 3; + if (!strncmp(argv[++i], "b", 1)) + text_where[text_inputs] = 1; + if (!strncmp(argv[i], "a", 1)) + text_where[text_inputs] = 2; + strcpy(&text_keyword[text_inputs * 80], argv[++i]); #ifdef PNG_iTXt_SUPPORTED - if(text_compression[text_inputs] <= 0) - { - text_lang[text_inputs*80] = '\0'; - text_lang_key[text_inputs*80] = '\0'; - } - else - { - strcpy(&text_lang[text_inputs*80],argv[++i]); - /* libpng-1.0.5j and later */ - strcpy(&text_lang_key[text_inputs*80],argv[++i]); - } + if (text_compression[text_inputs] <= 0) { + text_lang[text_inputs * 80] = '\0'; + text_lang_key[text_inputs * 80] = '\0'; + } else { + strcpy(&text_lang[text_inputs * 80], argv[++i]); + /* libpng-1.0.5j and later */ + strcpy(&text_lang_key[text_inputs * 80], argv[++i]); + } #endif - strcpy(&text_text[text_inputs*2048],argv[++i]); - text_inputs++; - } - else - { - if(text_inputs > 9) - fprintf(STDERR, - "too many text/zTXt inputs; only 10 allowed\n"); - else - fprintf(STDERR, - "keyword exceeds 79 characters or text exceeds 2047 characters\n"); - i+=3; - names+=3; + strcpy(&text_text[text_inputs * 2048], argv[++i]); + text_inputs++; + } else { + if (text_inputs > 9) + fprintf(STDERR, + "too many text/zTXt inputs; only 10 allowed\n"); + else + fprintf(STDERR, + "keyword exceeds 79 characters or text exceeds 2047 characters\n"); + i += 3; + names += 3; #ifdef PNG_iTXt_SUPPORTED - if( !strncmp(argv[i],"-i",2) || !strncmp(argv[i],"-zi",3)) - { - i++; - BUMP_I; - names+=2; + if (!strncmp(argv[i], "-i", 2) + || !strncmp(argv[i], "-zi", 3)) { + i++; + BUMP_I; + names += 2; + } +#endif } -#endif - } - } + } #ifdef PNG_tRNS_SUPPORTED - else if( !strncmp(argv[i],"-trns_a",7) || - !strncmp(argv[i],"-tRNS_a",7)) - { - num_trans_in=(png_uint_16)atoi(argv[++i]); - have_trns=1; - for (ia=0; ia 2 || specified_strategy < 0) - specified_strategy = 0; - names++; - if(brute_force == 0) - zs[method]=specified_strategy; - else - { - if(brute_force_strategy == 0) - for (strat=0; strat<2; strat++) - brute_force_strategies[strat]=1; - brute_force_strategies[specified_strategy]=0; - method=11; - for(filt=0; filt<6; filt++) - { - if(specified_strategy != 2) - try_method[method]=1; - method++; + else if (!strncmp(argv[i], "-version", 8)) { + fprintf(STDERR, " pngcrush "); + fprintf(STDERR, PNGCRUSH_VERSION); + fprintf(STDERR, ", uses libpng "); + fprintf(STDERR, PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " and zlib "); + fprintf(STDERR, ZLIB_VERSION); + fprintf(STDERR, "\n Check http://pmt.sf.net/\n"); + fprintf(STDERR, " for the most recent version.\n"); + verbose = 0; + } else if (!strncmp(argv[i], "-v", 2)) { + verbose++; + } else if (!strncmp(argv[i], "-w", 2)) { + default_compression_window = atoi(argv[++i]); + force_compression_window++; + names++; + } else if (!strncmp(argv[i], "-zm", 3)) { + compression_mem_level = atoi(argv[++i]); + names++; + } else if (!strncmp(argv[i], "-z", 2)) { + int lev, strat, filt; + int specified_strategy = atoi(argv[++i]); + if (specified_strategy > 2 || specified_strategy < 0) + specified_strategy = 0; + names++; + if (brute_force == 0) + zs[method] = specified_strategy; + else { + if (brute_force_strategy == 0) + for (strat = 0; strat < 2; strat++) + brute_force_strategies[strat] = 1; + brute_force_strategies[specified_strategy] = 0; + method = 11; + for (filt = 0; filt < 6; filt++) { + if (specified_strategy != 2) + try_method[method] = 1; + method++; + } + for (lev = 1; lev < 10; lev++) { + for (strat = 0; strat < 2; strat++) { + for (filt = 0; filt < 6; filt++) { + try_method[method] = brute_force_levels[lev] | + brute_force_filters[filt] | + brute_force_strategies[strat]; + method++; + } + } + } } - for(lev=1; lev<10; lev++) - { - for(strat=0; strat<2; strat++) - { - for(filt=0; filt<6; filt++) - { - try_method[method]=brute_force_levels[lev] | - brute_force_filters[filt] | - brute_force_strategies[strat]; - method++; - } - } + brute_force_strategy++; + } /* GRR: end of giant if-else block */ + } /* end of loop over args ============================================ */ + + + if (verbose > 0) + print_version_info(); + + if (default_compression_window == 32) + default_compression_window = 15; + else if (default_compression_window == 16) + default_compression_window = 14; + else if (default_compression_window == 8) + default_compression_window = 13; + else if (default_compression_window == 4) + default_compression_window = 12; + else if (default_compression_window == 2) + default_compression_window = 11; + else if (default_compression_window == 1) + default_compression_window = 10; + else if (default_compression_window == 512) + default_compression_window = 9; + /* Use of compression window size 256 is not recommended. */ + else if (default_compression_window == 256) + default_compression_window = 8; + else if (default_compression_window != 15) { + fprintf(STDERR, "Invalid window size (%d); using window size=4\n", + default_compression_window); + default_compression_window = 12; + } + + if (pngcrush_mode == DEFAULT_MODE) { + if (argc - names == 2) { + inname = argv[names]; + outname = argv[names + 1]; + } else { + if ((argc - names == 1 || nosave)) { + inname = argv[names]; } - } - brute_force_strategy++; - } - } - - if(verbose > 0) - { - /* If you have modified this source, you may insert additional notices - * immediately after this sentence. */ - fprintf(STDERR, - "\n | pngcrush %s, Copyright (C) 1998-2002 Glenn Randers-Pehrson\n", - PNGCRUSH_VERSION); - fprintf(STDERR, - " | This is a free, open-source program. Permission is irrevocably\n"); - fprintf(STDERR, - " | granted to everyone to use this version of pngcrush without\n"); - fprintf(STDERR, - " | payment of any fee.\n"); - fprintf(STDERR, - " | Executable name is %s\n",progname); - fprintf(STDERR, - " | It was built with libpng version %s, and is\n", - PNG_LIBPNG_VER_STRING); -#if PNG_LIBPNG_VER > 10001 - fprintf(STDERR, - " | running with %s", png_get_header_version(NULL)); -#endif -#if PNG_LIBPNG_VER > 96 - fprintf(STDERR, - " | Copyright (C) 1998-2002 Glenn Randers-Pehrson,\n"); -#endif -#if PNG_LIBPNG_VER > 89 - fprintf(STDERR, - " | Copyright (C) 1996, 1997 Andreas Dilger,\n"); -#endif - fprintf(STDERR, - " | Copyright (C) 1995, Guy Eric Schalnat, Group 42 Inc.,\n"); - fprintf(STDERR, - " | and zlib version %s, Copyright (C) 1998,\n", - ZLIB_VERSION); - fprintf(STDERR, - " | Jean-loup Gailly and Mark Adler.\n"); -#if defined(__DJGPP__) - fprintf(STDERR, - " | It was compiled with gcc version %s", __VERSION__); -# if defined(PNG_USE_PNGGCCRD) - /* is there a macro for "as" versions? */ - fprintf(STDERR, "\n | and as version %s", "2.9.5"); -# endif - fprintf(STDERR, - "\n | under DJGPP %d.%d, Copyright (C) 1995, D. J. Delorie\n", - __DJGPP__,__DJGPP_MINOR__); - fprintf(STDERR, - " | and loaded with PMODE/DJ, by Thomas Pytel and Matthias Grimrath\n"); - fprintf(STDERR, - " | Copyright (C) 1996, Matthias Grimrath.\n"); -#endif - fprintf(STDERR,"\n"); - } - - if (default_compression_window == 32) default_compression_window=15; - else if(default_compression_window == 16) default_compression_window=14; - else if(default_compression_window == 8) default_compression_window=13; - else if(default_compression_window == 4) default_compression_window=12; - else if(default_compression_window == 2) default_compression_window=11; - else if(default_compression_window == 1) default_compression_window=10; - else if(default_compression_window == 512) default_compression_window= 9; - /* Use of compression window size 256 is not recommended. */ - else if(default_compression_window == 256) default_compression_window= 8; - else if(default_compression_window != 15) - { - fprintf(STDERR,"Invalid window size (%d); using window size=4\n", - default_compression_window); - default_compression_window=12; - } - - if(pngcrush_mode == DEFAULT_MODE && argc - names == 2) - { - inname= argv[names]; - outname=argv[names+1]; - } - - if(pngcrush_mode == DEFAULT_MODE && (argc - names == 1 || nosave)) - { - inname= argv[names]; - } - - if((verbose && nosave == 0 && pngcrush_mode == DEFAULT_MODE - && argc - names != 2) || help > 0) - { - fprintf(STDERR, - "\nusage: %s [options] infile.png outfile.png\n",progname); - fprintf(STDERR, - " %s -e ext [other options] files.png ...\n",progname); - fprintf(STDERR, - " %s -d dir [other options] files.png ...\n",progname); - if(verbose > 1) - { - png_crush_pause(); - fprintf(STDERR, - "\noptions (Note: any option can be spelled out for clarity, e.g.,\n"); - fprintf(STDERR, - " \"pngcrush -dir New -method 7 -remove bkgd *.png\"\n"); - fprintf(STDERR, - " is the same as \"pngcrush -d New -m 7 -rem bkgd *.png\"):\n\n"); - } - else - fprintf(STDERR, "options:\n"); - fprintf(STDERR, - " -already already_crushed_size [e.g., 8192]\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n If file has an IDAT greater than this size, it\n"); - fprintf(STDERR, - " will be considered to be already crushed and will\n"); - fprintf(STDERR, - " not be processed, unless you are making other changes\n"); - fprintf(STDERR, - " or the \"-force\" option is present.\n\n"); - } - - fprintf(STDERR, - " -bit_depth depth (bit_depth to use in output file)\n"); - if(verbose > 1) - fprintf(STDERR, - "\n Default output depth is same as input depth.\n\n"); - - fprintf(STDERR, - " -brute (Use brute-force, try 114 different methods [11-124])\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Very time-consuming and generally not worthwhile.\n"); - fprintf(STDERR, - " You can restrict this option to certain filter types,\n"); - fprintf(STDERR, - " compression levels, or strategies by following it with\n"); - fprintf(STDERR, - " \"-f filter\", \"-l level\", or \"-z strategy\".\n\n"); - } - fprintf(STDERR, - " -c color_type of output file [0, 2, 4, or 6]\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Color type for the output file. Future versions\n"); - fprintf(STDERR, - " will also allow color_type 3, if there are 256 or\n"); - fprintf(STDERR, - " fewer colors present in the input file. Color types\n"); - fprintf(STDERR, - " 4 and 6 are padded with an opaque alpha channel if\n"); - fprintf(STDERR, - " the input file does not have alpha information.\n"); - fprintf(STDERR, - " You can use 0 or 4 to convert color to grayscale.\n"); - fprintf(STDERR, - " Use 0 or 2 to delete an unwanted alpha channel.\n"); - fprintf(STDERR, - " Default is to use same color type as the input file.\n\n"); - } -#ifdef PNGCRUSH_COUNT_COLORS - fprintf(STDERR, - " -cc (do color counting)\n"); - if(verbose > 1) - fprintf(STDERR,"\n"); -#endif - fprintf(STDERR, - " -d directory_name (where output files will go)\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n If a directory name is given, then the output\n"); - fprintf(STDERR, - " files are placed in it, with the same filenames as\n"); - fprintf(STDERR, - " those of the original files. For example,\n"); - fprintf(STDERR, - " you would type 'pngcrush -directory CRUSHED *.png'\n"); - fprintf(STDERR, - " to get *.png => CRUSHED/*.png\n\n"); - } - png_crush_pause(); - fprintf(STDERR, - " -double_gamma (used for fixing gamma in PhotoShop 5.0/5.02 files)\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n It has been claimed that the PS5 bug is actually\n"); - fprintf(STDERR, - " more complex than that, in some unspecified way.\n\n"); - } - fprintf(STDERR, - " -e extension (used for creating output filename)\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n e.g., -ext .new means *.png => *.new\n"); - fprintf(STDERR, - " and -e _C.png means *.png => *_C.png\n\n"); - } - fprintf(STDERR, - " -f user_filter [0-5]\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n filter to use with the method specified in the\n"); - fprintf(STDERR, - " preceding '-m method' or '-brute_force' argument.\n"); - fprintf(STDERR, - " 0: none; 1-4: use specified filter; 5: adaptive.\n\n"); - } - fprintf(STDERR, - " -fix (fix otherwise fatal conditions such as bad CRCs)\n"); - if(verbose > 1) - fprintf(STDERR, "\n"); - fprintf(STDERR, - " -force (Write a new output file even if larger than input)\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Otherwise the input file will be copied to output\n"); - fprintf(STDERR, - " if it is smaller than any generated file and no chunk\n"); - fprintf(STDERR, - " additions, removals, or changes were requested.\n\n"); - } - fprintf(STDERR, -#ifdef PNG_FIXED_POINT_SUPPORTED - " -g gamma (float or fixed*100000, e.g., 0.45455 or 45455)\n"); -#else - " -g gamma (float, e.g., 0.45455)\n"); -#endif - if(verbose > 1) - fprintf(STDERR, - "\n Value to insert in gAMA chunk, only if the input\n"); - if(verbose > 1) - fprintf(STDERR, - " file has no gAMA chunk. To replace an existing\n"); - if(verbose > 1) - fprintf(STDERR, - " gAMA chunk, use the '-replace_gamma' option.\n\n"); - png_crush_pause(); -#ifdef PNG_iCCP_SUPPORTED - fprintf(STDERR, - " -iccp length \"Profile Name\" iccp_file\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n file with ICC profile to insert in an iCCP chunk."); - fprintf(STDERR, "\n\n"); - } -#endif -#ifdef PNG_iTXt_SUPPORTED - fprintf(STDERR, - " -itxt b[efore_IDAT]|a[fter_IDAT] \"keyword\" \"text\"\n"); - if(verbose > 1) - fprintf(STDERR, - "\n Uncompressed iTXt chunk to insert (see -text).\n\n"); -#endif - fprintf(STDERR, - " -l zlib_compression_level [0-9]\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n zlib compression level to use with method specified\n"); - fprintf(STDERR, - " with the preceding '-m method' or '-brute_force'\n"); - fprintf(STDERR, - " argument.\n\n"); - } -#ifdef PNGCRUSH_LOCO - fprintf(STDERR, - " -loco (\"loco crush\" truecolor PNGs)\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Make the file more compressible by performing a\n"); - fprintf(STDERR, - " lossless reversible color transformation.\n"); - fprintf(STDERR, - " The resulting file is a MNG, not a PNG, and should\n"); - fprintf(STDERR, - " be given the \".mng\" file extension. The\n"); - fprintf(STDERR, - " \"loco\" option has no effect on grayscale or\n"); - fprintf(STDERR, - " indexed-color PNG files.\n\n"); - } -#endif - fprintf(STDERR, - " -m method [0 through %d]\n",MAX_METHODS); - if(verbose > 1) - { - fprintf(STDERR, - "\n pngcrush method to try (0 means try all of 1-10).\n"); - fprintf(STDERR, - " Can be repeated as in '-m 1 -m 4 -m 7'.\n"); - fprintf(STDERR, - " This can be useful if pngcrush runs out of memory\n"); - fprintf(STDERR, - " when it tries methods 2, 3, 5, 6, 8, 9, or 10 which\n"); - fprintf(STDERR, - " use filtering and are memory intensive. Methods\n"); - fprintf(STDERR, - " 1, 4, and 7 use no filtering; methods 11 and up use \n"); - fprintf(STDERR, - " specified filter, compression level, and strategy.\n\n"); - png_crush_pause(); - } - - fprintf(STDERR, - " -max maximum_IDAT_size [default %d]\n",PNG_ZBUF_SIZE); - if(verbose > 1) - fprintf(STDERR,"\n"); -#ifdef PNGCRUSH_COUNT_COLORS - fprintf(STDERR, - " -no_cc (no color counting)\n"); - if(verbose > 1) - fprintf(STDERR,"\n"); -#endif - fprintf(STDERR, - " -nofilecheck (do not check for infile.png == outfile.png)\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n To avoid false hits from MSVC-compiled code. Note\n"); - fprintf(STDERR, - " that if you use this option, you are responsible for\n"); - fprintf(STDERR, - " ensuring that the input file is not the output file.\n\n"); - } - fprintf(STDERR, - " -n (no save; does not do compression or write output PNG)\n"); - if(verbose > 1) - fprintf(STDERR, - "\n Useful in conjunction with -v option to get info.\n\n"); - - fprintf(STDERR, - " -plte_len n (truncate PLTE)\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Truncates the PLTE. Be sure not to truncate it to\n"); - fprintf(STDERR, - " less than the greatest index present in IDAT.\n\n"); - - } - fprintf(STDERR, - " -q (quiet)\n"); - if(verbose > 1) - fprintf(STDERR,"\n"); - fprintf(STDERR, - " -reduce (do lossless color type or bit depth reduction)\n"); - if(verbose > 1) - fprintf(STDERR, - "\n (if possible)\n\n"); - fprintf(STDERR, - " -rem chunkname (or \"alla\" or \"allb\")\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Name of an ancillary chunk or optional PLTE to be\n"); - fprintf(STDERR, - " removed. Be careful with this. Please don't use \n"); - fprintf(STDERR, - " this feature to remove transparency, gamma, copyright,\n"); - fprintf(STDERR, - " or other valuable information. To remove several\n"); - fprintf(STDERR, - " different chunks, repeat: -rem tEXt -rem pHYs.\n"); - fprintf(STDERR, - " Known chunks (those in the PNG 1.1 spec or extensions\n"); - fprintf(STDERR, - " document) can be named with all lower-case letters,\n"); - fprintf(STDERR, - " so \"-rem bkgd\" is equivalent to \"-rem bKGD\". But\n"); - fprintf(STDERR, - " note: \"-rem text\" removes all forms of text chunks;\n"); - fprintf(STDERR, - " Exact case is required to remove unknown chunks.\n"); - fprintf(STDERR, - " To do surgery with a chain-saw, \"-rem alla\" removes\n"); - fprintf(STDERR, - " all known ancillary chunks except for tRNS, and\n"); - fprintf(STDERR, - " \"-rem allb\" removes all but tRNS and gAMA.\n\n"); - } - png_crush_pause(); - fprintf(STDERR, -#ifdef PNG_FIXED_POINT_SUPPORTED - "-replace_gamma gamma (float or fixed*100000) even if gAMA is present.\n"); -#else - "-replace_gamma gamma (float, e.g. 0.45455) even if gAMA is present.\n"); -#endif - if(verbose > 1) - fprintf(STDERR,"\n"); - fprintf(STDERR, - " -res dpi\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Write a pHYs chunk with the given resolution.\n\n"); - } - fprintf(STDERR, - " -save (keep all copy-unsafe chunks)\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Save otherwise unknown ancillary chunks that would\n"); - fprintf(STDERR, - " be considered copy-unsafe. This option makes\n"); - fprintf(STDERR, - " chunks 'known' to pngcrush, so they can be copied.\n\n"); - } - png_crush_pause(); - - fprintf(STDERR, - " -srgb [0, 1, 2, or 3]\n"); - if(verbose > 1) - fprintf(STDERR, - "\n Value of 'rendering intent' for sRGB chunk.\n\n"); - fprintf(STDERR, - " -text b[efore_IDAT]|a[fter_IDAT] \"keyword\" \"text\"\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n tEXt chunk to insert. keyword < 80 chars,\n"); - fprintf(STDERR, - "\n text < 2048 chars. For now, you can only add ten\n"); - fprintf(STDERR, - " tEXt, iTXt, or zTXt chunks per pngcrush run.\n\n"); - } -#ifdef PNG_tRNS_SUPPORTED - fprintf(STDERR, - " -trns_array n trns[0] trns[1] .. trns[n-1]\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Insert a tRNS chunk, if no tRNS chunk found in file.\n"); - fprintf(STDERR, - " Values are for the tRNS array in indexed-color PNG.\n\n"); - } - fprintf(STDERR, - " -trns index red green blue gray\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Insert a tRNS chunk, if no tRNS chunk found in file.\n"); - fprintf(STDERR, - " You must give all five parameters regardless of the\n"); - fprintf(STDERR, - " color type, scaled to the output bit depth.\n\n"); - } -#endif - fprintf(STDERR, - " -v (display more detailed information)\n"); - if(verbose > 1) - fprintf(STDERR, - "\n Repeat the option (use \"-v -v\") for even more.\n\n"); - fprintf(STDERR, - " -version (display the pngcrush version)\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Look for the most recent version of pngcrush at\n"); - fprintf(STDERR, - " http://pmt.sf.net\n\n"); - } - fprintf(STDERR, - " -w compression_window_size [32, 16, 8, 4, 2, 1, 512]\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Size of the sliding compression window, in kbytes\n"); - fprintf(STDERR, - " (or bytes, in case of 512). It's best to\n"); - fprintf(STDERR, - " use the default (32) unless you run out of memory.\n"); - fprintf(STDERR, - " The program will use a smaller window anyway when\n"); - fprintf(STDERR, - " the uncompressed file is smaller than 16k.\n\n"); - } - fprintf(STDERR, - " -z zlib_strategy [0, 1, or 2]\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n zlib compression strategy to use with the preceding\n"); - fprintf(STDERR, - " '-m method' argument.\n\n"); - } - fprintf(STDERR, - " -zmem zlib_compression_mem_level [1-9, default 9]\n"); - if(verbose > 1) - fprintf(STDERR,"\n"); -#ifdef PNG_iTXt_SUPPORTED - fprintf(STDERR, - " -zitxt b[efore_IDAT]|a[fter_IDAT] \"keyword\" \"text\"\n"); - if(verbose > 1) - fprintf(STDERR, - "\n Compressed iTXt chunk to insert (see -text).\n\n"); -#endif - fprintf(STDERR, - " -ztxt b[efore_IDAT]|a[fter_IDAT] \"keyword\" \"text\"\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n zTXt chunk to insert (see -text).\n\n"); - png_crush_pause(); - } - fprintf(STDERR, - " -h (help and legal notices)\n"); - if(verbose > 1) - fprintf(STDERR, - "\n Display this information.\n\n"); - fprintf(STDERR, - " -p (pause)\n"); - if(verbose > 1) - { - fprintf(STDERR, - "\n Wait for [enter] key before continuing display.\n"); - fprintf(STDERR, - " e.g., type '%s -pause -help', if the help\n",progname); - fprintf(STDERR, - " screen scrolls out of sight.\n\n"); - } - /* If you have modified this source, you may insert additional notices - * immediately after this sentence. */ - fprintf (STDERR, - "\nCopyright (C) 1998-2002 Glenn Randers-Pehrson (randeg@alum.rpi.edu)\n\n"); - fprintf(STDERR, - "\nDISCLAIMER: The pngcrush computer program is supplied \"AS IS\".\n"); - fprintf(STDERR, - "The Author disclaims all warranties, expressed or implied, including,\n"); - fprintf(STDERR, - "without limitation, the warranties of merchantability and of fitness\n"); - fprintf(STDERR, - "for any purpose. The Author assumes no liability for direct, indirect,\n"); - fprintf(STDERR, - "incidental, special, exemplary, or consequential damages, which may\n"); - fprintf(STDERR, - "result from the use of the computer program, even if advised of the\n"); - fprintf(STDERR, - "possibility of such damage. There is no warranty against interference\n"); - fprintf(STDERR, - "with your enjoyment of the computer program or against infringement.\n"); - fprintf(STDERR, - "There is no warranty that my efforts or the computer program will\n"); - fprintf(STDERR, - "fulfill any of your particular purposes or needs. This computer\n"); - fprintf(STDERR, - "program is provided with all faults, and the entire risk of satisfactory\n"); - fprintf(STDERR, - "quality, performance, accuracy, and effort is with the user.\n"); - fprintf(STDERR, - - "\nLICENSE: Permission is hereby irrevocably granted to everyone to use,\n"); - fprintf(STDERR, - "copy, modify, and distribute this computer program, or portions hereof,\n"); - fprintf(STDERR, - "purpose, without payment of any fee, subject to the following\n"); - fprintf(STDERR, - "restrictions:\n\n"); - fprintf(STDERR, - "1. The origin of this binary or source code must not be misrepresented.\n\n"); - fprintf(STDERR, - "2. Altered versions must be plainly marked as such and must not be\n"); - fprintf(STDERR, - "misrepresented as being the original binary or source.\n\n"); - fprintf(STDERR, - "3. The Copyright notice, disclaimer, and license may not be removed\n"); - fprintf(STDERR, - "or altered from any source, binary, or altered source distribution.\n"); - - if(pngcrush_mode == DEFAULT_MODE && argc - names != 2 && nosave == 0) - exit(1); - } - - for (ia=0; ia<256; ia++) - trans_in[ia]=trns_array[ia]=255; - - for(;;) /* loop on input files */ - - { - first_trial = 1; - - things_have_changed=global_things_have_changed; - - if(png_row_filters != NULL) - { - free(png_row_filters); png_row_filters=NULL; - } - - image_specified_gamma=0; - - inname=argv[names++]; - - if(inname == NULL) - { - if(verbose > 0) show_result(); - exit(0); - } - - if(pngcrush_mode == DIRECTORY_MODE || pngcrush_mode == DIREX_MODE) - { -#ifdef __riscos - if(fileexists(directory_name) & 2) -#else - struct stat stat_buf; - if(stat(directory_name, &stat_buf)) -#endif - { -#if defined(_MBCS) || defined(WIN32) || defined(__WIN32__) - if(_mkdir(directory_name)) -#else - if(mkdir(directory_name, 0x1ed)) -#endif - { - fprintf(STDERR,"could not create directory %s\n",directory_name); - exit(1); - } - nofilecheck=1; - } - out_string[0] = '\0'; - str_return = strcat(out_string,directory_name); - str_return = strcat(out_string,SLASH); - - in_string[0] = '\0'; - str_return = strcat(in_string,inname); - ip = op = in_string; -#ifdef __riscos - op = strrchr(in_string, '.'); - if (!op) op = in_string; else op++; -#else - while(*ip != '\0') - { - if(*ip == '\\' || *ip == '/')op=ip+1; - ip++; - } -#endif - - str_return = strcat(out_string,op); - outname=out_string; - } - - if(pngcrush_mode == EXTENSION_MODE || pngcrush_mode == DIREX_MODE) - { - ip=in_string; - in_string[0]='\0'; - if(pngcrush_mode == EXTENSION_MODE) - str_return = strcat(in_string,inname); - else - str_return = strcat(in_string,outname); - ip = in_string; - op = dot = out_string; - while(*ip != '\0') - { - *op++ = *ip++; -#ifdef __riscos - if(*ip == '/')dot=op; -#else - if(*ip == '.')dot=op; -#endif - } - *op = '\0'; - - if(dot != out_string) - *dot = '\0'; - - in_extension[0]='\0'; - if(dot != out_string) - { - str_return = strcat(in_extension,++dot); - } - - str_return = strcat(out_string,extension); - outname=out_string; - } - - - if(nosave < 2) - { - png_debug1(0, "Opening file %s for length measurement\n",inname); - - if ((fpin = FOPEN(inname, "rb")) == NULL) - { - fprintf(STDERR, "Could not find file: %s\n", inname); - continue; - } - number_of_open_files++; - - already_crushed = 0; - - idat_length[0]=measure_idats(fpin); - - FCLOSE(fpin); - - if(already_crushed) - { - fprintf(STDERR, "File has already been crushed: %s\n", inname); - if(!things_have_changed) continue; - } - - if(verbose > 0) - { - fprintf(STDERR," Recompressing %s\n",inname); - fprintf(STDERR, - " Total length of data found in IDAT chunks = %8lu\n", - idat_length[0]); - fflush(STDERR); - } - - if(idat_length[0] == 0) continue; - - } - else - idat_length[0]=1; - -#ifdef PNGCRUSH_COUNT_COLORS - reduce_to_gray=0; - it_is_opaque=0; - output_color_type = input_color_type; - if (do_color_count) - { - if (force_output_color_type == 8 && (input_color_type == 2 || - (input_color_type == 3) || - input_color_type == 4 || input_color_type == 6)) - /* check for unused alpha channel or single transparent color */ - { - int alpha_status; - png_debug1(0, "Opening file %s for alpha check\n",inname); - - if ((fpin = FOPEN(inname, "rb")) == NULL) - { - fprintf(STDERR, "Could not find file: %s\n", inname); - continue; - } - number_of_open_files++; - - alpha_status=count_colors(fpin); - if(num_rgba < 257) - { - P1 ("Finished counting colors. num_rgba=%d\n", num_rgba); - } - else - { - P1 ("Finished counting colors. num_rgba is more than 256\n"); - } - alpha_status = alpha_status; /* silence compiler warning. */ - - FCLOSE(fpin); - - if (it_is_opaque) - { - if (output_color_type == 4) - output_color_type=0; - else if (output_color_type == 6) - output_color_type=2; - } - if (reduce_to_gray) - { - if (output_color_type == 2) - output_color_type=0; - else if (output_color_type == 6) - output_color_type=4; - } - } - -#if 0 /* TO DO */ - if (output_color_type == 0) - /* see if bit depth can be reduced */ - { - } - - if (input_color_type == 2) - /* check for 256 or fewer colors */ - { - /* TO DO */ - } - - if (input_color_type == 3) - /* check for unused palette entries */ - { - /* TO DO */ - } -#endif - if(force_output_color_type == 8 && input_color_type != output_color_type) - { - P1 ("setting output color type to %d\n",output_color_type); - force_output_color_type = output_color_type; - } - } -#else - if (do_color_count) - printf(" color counting (-cc option) is disabled.\n"); -#endif /* PNGCRUSH_COUNT_COLORS */ - - output_color_type=force_output_color_type; - output_bit_depth=force_output_bit_depth; - - if(!methods_specified || try_method[0] == 0) - { - for (i=1; i<=DEFAULT_METHODS; i++) try_method[i]=0; - try_method[6]=try_method[0]; - } - - best_of_three=1; - - for(trial=1; trial<=MAX_METHODS; trial++) - { - idat_length[trial]=(png_uint_32)0xffffffff; - if(trial == MAX_METHODS) - { - png_uint_32 best_length; - /* check lengths */ - best=0; - best_length=(png_uint_32)0xffffffff; - for (ntrial=things_have_changed; ntrial 2 && trial < 5 && idat_length[trial-1] - < idat_length[best_of_three])best_of_three = trial-1; - if(try_method[trial])continue; - if(!methods_specified && try_method[0]) - { - if((trial == 4 || trial == 7) && best_of_three != 1) continue; - if((trial == 5 || trial == 8) && best_of_three != 2) continue; - if((trial == 6 || trial == 9 || trial == 10) && best_of_three != 3) - continue; - } - filter_type=fm[trial]; - zlib_level=lv[trial]; - if(zs[trial] == 0)z_strategy=Z_DEFAULT_STRATEGY; - if(zs[trial] == 1)z_strategy=Z_FILTERED; - if(zs[trial] == 2)z_strategy=Z_HUFFMAN_ONLY; - final_method=trial; - if(nosave == 0) - P2(" Begin trial %d, filter %d, strategy %d, level %d\n", - trial, filter_type, z_strategy, zlib_level); - } - - P2("prepare to open files.\n"); - png_crush_pause(); - - if ((fpin = FOPEN(inname, "rb")) == NULL) - { - fprintf(STDERR, "Could not find input file %s\n", inname); - continue; - } - number_of_open_files++; - if(nosave == 0) - { -#ifndef __riscos - /* Can't sensibly check this on RISC OS without opening a file for - update or output - */ - struct stat stat_in, stat_out; - if (first_trial && !nofilecheck && (stat(inname, &stat_in) == 0) && - (stat(outname, &stat_out) == 0) && -#if defined(_MSC_VER) || defined(__MINGW32__) /* maybe others? */ - /* MSVC++6.0 will erroneously return 0 for both files, so we - simply check the size instead. It is possible that we will - erroneously reject the attempt when inputsize and outputsize - are equal, for different files - */ - (stat_in.st_size == stat_out.st_size) && -#else - (stat_in.st_ino == stat_out.st_ino) && -#endif - (stat_in.st_dev == stat_out.st_dev)) - { - fprintf(STDERR, "\n Cannot overwrite input file %s\n", outname); - P1(" st_ino=%d, st_size=%d\n\n", (int)stat_in.st_ino, - (int)stat_in.st_size); - FCLOSE(fpin); - exit(1); - } -#endif - if ((fpout = FOPEN(outname, "wb")) == NULL) - { - fprintf(STDERR, "Could not open output file %s\n", outname); - FCLOSE(fpin); - exit(1); - } - - number_of_open_files++; + if (png_row_filters != NULL) { + free(png_row_filters); + png_row_filters = NULL; } - P2("files are opened.\n"); + image_specified_gamma = 0; + + inname = argv[names++]; + + if (inname == NULL) { + if (verbose > 0) + show_result(); + break; + } + + if (pngcrush_mode == DIRECTORY_MODE || pngcrush_mode == DIREX_MODE) { + int inlen, outlen; +#ifndef __riscos + struct stat stat_buf; + if (stat(directory_name, &stat_buf)) +#else + if (fileexists(directory_name) & 2) +#endif + { +#if defined(_MBCS) || defined(WIN32) || defined(__WIN32__) + if (_mkdir(directory_name)) +#else + if (mkdir(directory_name, 0755)) +#endif + { + fprintf(STDERR, "could not create directory %s\n", + directory_name); + exit(1); + } + nofilecheck = 1; + } + outlen = strlen(directory_name); + if (outlen >= STR_BUF_SIZE-1) { + fprintf(STDERR, "directory %s is too long for buffer\n", + directory_name); + exit(1); + } + strcpy(out_string, directory_name); + /*strcpy(out_string+outlen, SLASH); */ + out_string[outlen++] = SLASH[0]; /* (assuming SLASH is 1 byte) */ + out_string[outlen] = '\0'; + + inlen = strlen(inname); + if (inlen >= STR_BUF_SIZE) { + fprintf(STDERR, "filename %s is too long for buffer\n", inname); + exit(1); + } + strcpy(in_string, inname); + in_string[inlen] = '\0'; +#ifdef __riscos + op = strrchr(in_string, '.'); + if (!op) + op = in_string; + else + op++; +#else + op = in_string; + ip = in_string + inlen - 1; /* start at last char in string */ + while (ip > in_string) { + if (*ip == '\\' || *ip == '/') { + op = ip + 1; + break; + } + --ip; + } +#endif + + if (outlen + (inlen - (op - in_string)) >= STR_BUF_SIZE) { + fprintf(STDERR, "full path is too long for buffer\n"); + exit(1); + } + strcpy(out_string+outlen, op); + /*outlen += inlen - (op - in_string); */ + outname = out_string; + } + + /* FIXME: need same input-validation fixes (as above) here, too + * FIXME: what was the point of setting in_string and out_string in + * DIREX_MODE above if going to do all over again here? */ + if (pngcrush_mode == EXTENSION_MODE || pngcrush_mode == DIREX_MODE) { + ip = in_string; + in_string[0] = '\0'; + if (pngcrush_mode == EXTENSION_MODE) + strcat(in_string, inname); + else + strcat(in_string, outname); + ip = in_string; + op = dot = out_string; + while (*ip != '\0') { + *op++ = *ip++; +#ifdef __riscos + if (*ip == '/') + dot = op; +#else + if (*ip == '.') + dot = op; +#endif + } + *op = '\0'; + + if (dot != out_string) + *dot = '\0'; + + in_extension[0] = '\0'; + if (dot != out_string) { + strcat(in_extension, ++dot); + } + + strcat(out_string, extension); + outname = out_string; + } + + + if (nosave < 2) { + P1( "Opening file %s for length measurement\n", + inname); + + if ((fpin = FOPEN(inname, "rb")) == NULL) { + fprintf(STDERR, "Could not find file: %s\n", inname); + continue; + } + number_of_open_files++; + + already_crushed = 0; + + idat_length[0] = measure_idats(fpin); + + FCLOSE(fpin); + + if (already_crushed) { + fprintf(STDERR, "File has already been crushed: %s\n", inname); + if (!things_have_changed) + continue; + } + + if (verbose > 0) { + fprintf(STDERR, " Recompressing %s\n", inname); + fprintf(STDERR, + " Total length of data found in IDAT chunks = %8lu\n", + idat_length[0]); + fflush(STDERR); + } + + if (idat_length[0] == 0) + continue; + + } else + idat_length[0] = 1; + +#ifdef PNGCRUSH_COUNT_COLORS + reduce_to_gray = 0; + it_is_opaque = 0; + output_color_type = input_color_type; + if (do_color_count) { + if (force_output_color_type == 8 && (input_color_type == 2 || + (input_color_type == 3) || + input_color_type == 4 + || input_color_type == 6)) + /* check for unused alpha channel or single transparent color */ + { + int alpha_status; + P1( "Opening file %s for alpha check\n", inname); + + if ((fpin = FOPEN(inname, "rb")) == NULL) { + fprintf(STDERR, "Could not find file: %s\n", inname); + continue; + } + number_of_open_files++; + + alpha_status = count_colors(fpin); + if (num_rgba < 257) { + P1("Finished counting colors. num_rgba=%d\n", + num_rgba); + } else { + P1("Finished counting colors. num_rgba is more than 256\n"); + } + alpha_status = alpha_status; /* silence compiler warning. */ + + FCLOSE(fpin); + + if (it_is_opaque) { + if (output_color_type == 4) + output_color_type = 0; + else if (output_color_type == 6) + output_color_type = 2; + } + if (reduce_to_gray) { + if (output_color_type == 2) + output_color_type = 0; + else if (output_color_type == 6) + output_color_type = 4; + } + } +#if 0 /* TO DO */ + if (output_color_type == 0) + /* see if bit depth can be reduced */ + { + } + + if (input_color_type == 2) + /* check for 256 or fewer colors */ + { + /* TO DO */ + } + + if (input_color_type == 3) + /* check for unused palette entries */ + { + /* TO DO */ + } +#endif + if (force_output_color_type == 8 + && input_color_type != output_color_type) { + P1("setting output color type to %d\n", output_color_type); + force_output_color_type = output_color_type; + } + } +#else + if (do_color_count) + printf(" color counting (-cc option) is disabled.\n"); +#endif /* PNGCRUSH_COUNT_COLORS */ + + output_color_type = force_output_color_type; + output_bit_depth = force_output_bit_depth; + + if (!methods_specified || try_method[0] == 0) { + for (i = 1; i <= DEFAULT_METHODS; i++) + try_method[i] = 0; + try_method[6] = try_method[0]; + } + + best_of_three = 1; + + /* //////////////////////////////////////////////////////////////////// + //////////////// //////////////////// + //////////////// START OF MAIN LOOP OVER METHODS //////////////////// + //////////////// //////////////////// + //////////////////////////////////////////////////////////////////// */ + + /* MAX_METHODS is 200 */ + P1("\n\nENTERING MAIN LOOP OVER %d METHODS\n", MAX_METHODS); + for (trial = 1; trial <= MAX_METHODS; trial++) { + idat_length[trial] = (png_uint_32) 0xffffffff; + + /* this part of if-block is for final write-the-best-file + iteration */ + if (trial == MAX_METHODS) { + png_uint_32 best_length; + int j; + + /* check lengths */ + best = 0; /* i.e., input file */ + best_length = (png_uint_32) 0xffffffff; + for (j = things_have_changed; j < MAX_METHODS; j++) { + if (best_length > idat_length[j]) { + best_length = idat_length[j]; + best = j; + } + } + + if (idat_length[best] == idat_length[0] + && things_have_changed == 0 + && idat_length[best] != idat_length[final_method] + && nosave == 0) + { + /* just copy input to output */ + + P2("prepare to copy input to output\n"); + png_crush_pause(); + + if ((fpin = FOPEN(inname, "rb")) == NULL) { + fprintf(STDERR, "Could not find input file %s\n", + inname); + continue; + } + + number_of_open_files++; + if ((fpout = FOPEN(outname, "wb")) == NULL) { + fprintf(STDERR, "Could not open output file %s\n", + outname); + FCLOSE(fpin); + exit(1); + } + + number_of_open_files++; + P2("copying input to output... tc=%d ...", + things_have_changed); + + for (;;) { + png_size_t num_in; + + num_in = fread(buffer, 1, 1, fpin); + if (!num_in) + break; + fwrite(buffer, 1, 1, fpout); + } + P2("copy complete.\n"); + png_crush_pause(); + FCLOSE(fpin); + FCLOSE(fpout); + setfiletype(outname); + break; + } + + if (idat_length[best] == idat_length[final_method]) { + break; + } else { + filter_type = fm[best]; + zlib_level = lv[best]; + if (zs[best] == 1) + z_strategy = Z_FILTERED; + else if (zs[best] == 2) + z_strategy = Z_HUFFMAN_ONLY; +#ifdef Z_RLE + else if (zs[best] == 3) + z_strategy = Z_RLE; +#endif + else /* if (zs[best] == 0) */ + z_strategy = Z_DEFAULT_STRATEGY; + } + } else { + if (trial > 2 && trial < 5 && idat_length[trial - 1] + < idat_length[best_of_three]) + best_of_three = trial - 1; + if (try_method[trial]) { + P2("skipping \"late\" trial %d\n", trial); + continue; + } + if (!methods_specified && try_method[0]) { + if ((trial == 4 || trial == 7) && best_of_three != 1) { + P2("skipping \"early\" trial %d\n", trial); + continue; + } + if ((trial == 5 || trial == 8) && best_of_three != 2) { + P2("skipping \"early\" trial %d\n", trial); + continue; + } + if ((trial == 6 || trial == 9 || trial == 10) + && best_of_three != 3) { + P2("skipping \"early\" trial %d\n", trial); + continue; + } + } + filter_type = fm[trial]; + zlib_level = lv[trial]; + if (zs[trial] == 1) + z_strategy = Z_FILTERED; + else if (zs[trial] == 2) + z_strategy = Z_HUFFMAN_ONLY; +#ifdef Z_RLE + else if (zs[trial] == 3) + z_strategy = Z_RLE; +#endif + else /* if (zs[trial] == 0) */ + z_strategy = Z_DEFAULT_STRATEGY; + final_method = trial; + if (!nosave) { + P2("\n\n------------------------------------------------\n" + "Begin trial %d, filter %d, strategy %d, level %d\n", + trial, filter_type, z_strategy, zlib_level); + } + } + + P2("prepare to open files.\n"); png_crush_pause(); - Try - { - png_uint_32 row_length; - png_debug(0, "Allocating read and write structures\n"); -#ifdef PNG_USER_MEM_SUPPORTED - read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, - (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL, (png_voidp)NULL, - (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); + if ((fpin = FOPEN(inname, "rb")) == NULL) { + fprintf(STDERR, "Could not find input file %s\n", inname); + continue; + } + number_of_open_files++; + if (nosave == 0) { +#ifndef __riscos + /* Can't sensibly check this on RISC OS without opening a file + for update or output + */ + struct stat stat_in, stat_out; + if (first_trial && !nofilecheck + && (stat(inname, &stat_in) == 0) + && (stat(outname, &stat_out) == 0) && +#if defined(_MSC_VER) || defined(__MINGW32__) /* maybe others? */ + /* MSVC++6.0 will erroneously return 0 for both files, so + we simply check the size instead. It is possible that + we will erroneously reject the attempt when inputsize + and outputsize are equal, for different files + */ + (stat_in.st_size == stat_out.st_size) && #else - read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, - (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL); + (stat_in.st_ino == stat_out.st_ino) && #endif - if (read_ptr == NULL) - Throw "pngcrush could not create read_ptr"; - - if(nosave == 0) - { -#ifdef PNG_USER_MEM_SUPPORTED - write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, - (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL, (png_voidp)NULL, - (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); -#else - write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, - (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL); + (stat_in.st_dev == stat_out.st_dev)) { + fprintf(STDERR, + "\n Cannot overwrite input file %s\n", + outname); + P1(" st_ino=%d, st_size=%d\n\n", + (int) stat_in.st_ino, (int) stat_in.st_size); + FCLOSE(fpin); + exit(1); + } #endif - if (write_ptr == NULL) - Throw "pngcrush could not create write_ptr"; + if ((fpout = FOPEN(outname, "wb")) == NULL) { + fprintf(STDERR, "Could not open output file %s\n", + outname); + FCLOSE(fpin); + exit(1); + } - } - png_debug(0, "Allocating read_info, write_info and end_info structures\n"); - read_info_ptr = png_create_info_struct(read_ptr); - if (read_info_ptr == NULL) - Throw "pngcrush could not create read_info_ptr"; - end_info_ptr = png_create_info_struct(read_ptr); - if (end_info_ptr == NULL) - Throw "pngcrush could not create end_info_ptr"; - if(nosave == 0) - { - write_info_ptr = png_create_info_struct(write_ptr); - if (write_info_ptr == NULL) - Throw "pngcrush could not create write_info_ptr"; - write_end_info_ptr = png_create_info_struct(write_ptr); - if (write_end_info_ptr == NULL) - Throw "pngcrush could not create write_end_info_ptr"; - } + number_of_open_files++; + } - P2("structures created.\n"); + P2("files are opened.\n"); png_crush_pause(); - png_debug(0, "Initializing input and output streams\n"); + Try { + png_uint_32 row_length; + P1( "Allocating read and write structures\n"); +#ifdef PNG_USER_MEM_SUPPORTED + read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, + (png_voidp) NULL, (png_error_ptr) png_cexcept_error, + (png_error_ptr) NULL, (png_voidp) NULL, + (png_malloc_ptr) png_debug_malloc, + (png_free_ptr) png_debug_free); +#else + read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + (png_voidp) NULL, (png_error_ptr) png_cexcept_error, + (png_error_ptr) NULL); +#endif + if (read_ptr == NULL) + Throw "pngcrush could not create read_ptr"; + + if (nosave == 0) { +#ifdef PNG_USER_MEM_SUPPORTED + write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, + (png_voidp) NULL, (png_error_ptr) png_cexcept_error, + (png_error_ptr) NULL, (png_voidp) NULL, + (png_malloc_ptr) png_debug_malloc, + (png_free_ptr) png_debug_free); +#else + write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + (png_voidp) NULL, (png_error_ptr) png_cexcept_error, + (png_error_ptr) NULL); +#endif + if (write_ptr == NULL) + Throw "pngcrush could not create write_ptr"; + + } + P1("Allocating read_info, write_info, end_info structures\n"); + read_info_ptr = png_create_info_struct(read_ptr); + if (read_info_ptr == NULL) + Throw "pngcrush could not create read_info_ptr"; + end_info_ptr = png_create_info_struct(read_ptr); + if (end_info_ptr == NULL) + Throw "pngcrush could not create end_info_ptr"; + if (nosave == 0) { + write_info_ptr = png_create_info_struct(write_ptr); + if (write_info_ptr == NULL) + Throw "pngcrush could not create write_info_ptr"; + write_end_info_ptr = png_create_info_struct(write_ptr); + if (write_end_info_ptr == NULL) + Throw + "pngcrush could not create write_end_info_ptr"; + } + + P2("structures created.\n"); + png_crush_pause(); + + P1( "Initializing input and output streams\n"); #if !defined(PNG_NO_STDIO) - png_init_io(read_ptr, fpin); - if(nosave == 0) - png_init_io(write_ptr, fpout); + png_init_io(read_ptr, fpin); + if (nosave == 0) + png_init_io(write_ptr, fpout); #else - png_set_read_fn(read_ptr, (png_voidp)fpin, (png_rw_ptr)NULL); - if(nosave == 0) - png_set_write_fn(write_ptr, (png_voidp)fpout, (png_rw_ptr)NULL, + png_set_read_fn(read_ptr, (png_voidp) fpin, + (png_rw_ptr) NULL); + if (nosave == 0) + png_set_write_fn(write_ptr, (png_voidp) fpout, + (png_rw_ptr) NULL, #if defined(PNG_WRITE_FLUSH_SUPPORTED) - png_default_flush); + png_default_flush); #else - NULL); + NULL); #endif #endif - P2("io has been initialized.\n"); - png_crush_pause(); + P2("io has been initialized.\n"); + png_crush_pause(); - /* We don't need to check CRC's because they were already checked - in the png_measure_idat function */ + /* We don't need to check CRC's because they were already + checked in the png_measure_idat function */ #ifdef PNG_CRC_QUIET_USE - png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); + png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE, + PNG_CRC_QUIET_USE); #endif #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - png_set_keep_unknown_chunks(read_ptr, HANDLE_CHUNK_ALWAYS, - (png_bytep)NULL, 0); + png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, + (png_bytep) NULL, 0); #endif #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) - if(nosave == 0) - { - if(all_chunks_are_safe) - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - (png_bytep)NULL, 0); - else - { -#ifndef PNG_UINT_IHDR -/* We are using libpng-1.0.6 or earlier */ -#ifdef PNG_USE_LOCAL_ARRAYS -#if !defined(PNG_cHRM_SUPPORTED) - PNG_cHRM; -#endif -#if !defined(PNG_hIST_SUPPORTED) - PNG_hIST; -#endif -#if !defined(PNG_iCCP_SUPPORTED) - PNG_iCCP; -#endif -#if !defined(PNG_pCAL_SUPPORTED) - PNG_pCAL; -#endif -#if !defined(PNG_sCAL_SUPPORTED) - PNG_sCAL; -#endif -#if !defined(PNG_sPLT_SUPPORTED) - PNG_sPLT; -#endif -#if !defined(PNG_tIME_SUPPORTED) - PNG_tIME; -#endif -#endif /* PNG_USE_LOCAL_ARRAYS */ - - if(keep_unknown_chunk("alla",argv) && - keep_unknown_chunk("allb",argv)) - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_IF_SAFE, - (png_bytep)NULL, 0); - else - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_NEVER, - (png_bytep)NULL, 0); - -/* Process the following chunks as if safe-to-copy since it is known that - recompressing the IDAT chunks has no effect on them */ -#if !defined(PNG_cHRM_SUPPORTED) - if(keep_unknown_chunk("cHRM",argv)) - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - (png_bytep)png_cHRM, 1); -#endif -#if !defined(PNG_hIST_SUPPORTED) - if(keep_unknown_chunk("hIST",argv)) - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - (png_bytep)png_hIST, 1); -#endif -#if !defined(PNG_iCCP_SUPPORTED) - if(keep_unknown_chunk("iCCP",argv)) - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - (png_bytep)png_iCCP, 1); -#endif -#if !defined(PNG_sCAL_SUPPORTED) - if(keep_unknown_chunk("sCAL",argv)) - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - (png_bytep)png_sCAL, 1); -#endif -#if !defined(PNG_pCAL_SUPPORTED) - if(keep_unknown_chunk("pCAL",argv)) - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - (png_bytep)png_pCAL, 1); -#endif -#if !defined(PNG_sPLT_SUPPORTED) - if(keep_unknown_chunk("sPLT",argv)) - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - (png_bytep)png_sPLT, 1); -#endif -#if !defined(PNG_tIME_SUPPORTED) - if(keep_unknown_chunk("tIME",argv)) - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - (png_bytep)png_tIME, 1); -#endif -#else /* PNG_UINT_IHDR is defined; we are using libpng newer than 1.0.6 */ - + if (nosave == 0) { + if (all_chunks_are_safe) + png_set_keep_unknown_chunks(write_ptr, + PNG_HANDLE_CHUNK_ALWAYS, + (png_bytep) NULL, 0); + else { #if !defined(PNG_cHRM_SUPPORTED) || !defined(PNG_hIST_SUPPORTED) || \ !defined(PNG_iCCP_SUPPORTED) || !defined(PNG_sCAL_SUPPORTED) || \ !defined(PNG_pCAL_SUPPORTED) || !defined(PNG_sPLT_SUPPORTED) || \ !defined(PNG_tIME_SUPPORTED) - png_byte chunk_name[5]; - chunk_name[4]='\0'; + png_byte chunk_name[5]; + chunk_name[4] = '\0'; #endif - if(keep_unknown_chunk("alla",argv) && - keep_unknown_chunk("allb",argv)) - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_IF_SAFE, - (png_bytep)NULL, 0); - else - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_NEVER, - (png_bytep)NULL, 0); + if (keep_unknown_chunk("alla", argv) && + keep_unknown_chunk("allb", argv)) + png_set_keep_unknown_chunks(write_ptr, + PNG_HANDLE_CHUNK_IF_SAFE, + (png_bytep) NULL, + 0); + else + png_set_keep_unknown_chunks(write_ptr, + PNG_HANDLE_CHUNK_NEVER, + (png_bytep) NULL, + 0); #if !defined(PNG_cHRM_SUPPORTED) - if(keep_unknown_chunk("cHRM",argv)) - { - png_save_uint_32(chunk_name, PNG_UINT_cHRM); - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - chunk_name, 1); - } + if (keep_unknown_chunk("cHRM", argv)) { + png_save_uint_32(chunk_name, PNG_UINT_cHRM); + png_set_keep_unknown_chunks(write_ptr, + PNG_HANDLE_CHUNK_ALWAYS, + chunk_name, 1); + } #endif #if !defined(PNG_hIST_SUPPORTED) - if(keep_unknown_chunk("hIST",argv)) - { - png_save_uint_32(chunk_name, PNG_UINT_hIST); - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - chunk_name, 1); - } + if (keep_unknown_chunk("hIST", argv)) { + png_save_uint_32(chunk_name, PNG_UINT_hIST); + png_set_keep_unknown_chunks(write_ptr, + PNG_HANDLE_CHUNK_ALWAYS, + chunk_name, 1); + } #endif #if !defined(PNG_iCCP_SUPPORTED) - if(keep_unknown_chunk("iCCP",argv)) - { - png_save_uint_32(chunk_name, PNG_UINT_iCCP); - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - chunk_name, 1); - } + if (keep_unknown_chunk("iCCP", argv)) { + png_save_uint_32(chunk_name, PNG_UINT_iCCP); + png_set_keep_unknown_chunks(write_ptr, + PNG_HANDLE_CHUNK_ALWAYS, + chunk_name, 1); + } #endif #if !defined(PNG_sCAL_SUPPORTED) - if(keep_unknown_chunk("sCAL",argv)) - { - png_save_uint_32(chunk_name, PNG_UINT_sCAL); - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - chunk_name, 1); - } + if (keep_unknown_chunk("sCAL", argv)) { + png_save_uint_32(chunk_name, PNG_UINT_sCAL); + png_set_keep_unknown_chunks(write_ptr, + PNG_HANDLE_CHUNK_ALWAYS, + chunk_name, 1); + } #endif #if !defined(PNG_pCAL_SUPPORTED) - if(keep_unknown_chunk("pCAL",argv)) - { - png_save_uint_32(chunk_name, PNG_UINT_pCAL); - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - chunk_name, 1); - } + if (keep_unknown_chunk("pCAL", argv)) { + png_save_uint_32(chunk_name, PNG_UINT_pCAL); + png_set_keep_unknown_chunks(write_ptr, + PNG_HANDLE_CHUNK_ALWAYS, + chunk_name, 1); + } #endif #if !defined(PNG_sPLT_SUPPORTED) - if(keep_unknown_chunk("sPLT",argv)) - { - png_save_uint_32(chunk_name, PNG_UINT_sPLT); - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - chunk_name, 1); - } + if (keep_unknown_chunk("sPLT", argv)) { + png_save_uint_32(chunk_name, PNG_UINT_sPLT); + png_set_keep_unknown_chunks(write_ptr, + PNG_HANDLE_CHUNK_ALWAYS, + chunk_name, 1); + } #endif #if !defined(PNG_tIME_SUPPORTED) - if(keep_unknown_chunk("tIME",argv)) - { - png_save_uint_32(chunk_name, PNG_UINT_tIME); - png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_ALWAYS, - chunk_name, 1); - } + if (keep_unknown_chunk("tIME", argv)) { + png_save_uint_32(chunk_name, PNG_UINT_tIME); + png_set_keep_unknown_chunks(write_ptr, + PNG_HANDLE_CHUNK_ALWAYS, + chunk_name, 1); + } #endif -#endif /* PNG_UINT_IHDR */ - } - } -#endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ + } + } +#endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ - png_debug(0, "Reading info struct\n"); - { + P1( "Reading info struct\n"); + { #if defined(PNGCRUSH_LOCO) - png_byte mng_signature[8] = {138, 77, 78, 71, 13, 10, 26, 10}; + png_byte mng_signature[8] = + { 138, 77, 78, 71, 13, 10, 26, 10 }; #endif - png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + png_byte png_signature[8] = + { 137, 80, 78, 71, 13, 10, 26, 10 }; - png_read_data(read_ptr, png_signature, 8); - png_set_sig_bytes(read_ptr, 8); + png_default_read_data(read_ptr, png_signature, 8); + png_set_sig_bytes(read_ptr, 8); #if defined(PNGCRUSH_LOCO) - if (!(int)(png_memcmp(mng_signature, png_signature, 8))) - { - png_byte buffer[40]; - /* Skip the MHDR */ - png_permit_mng_features (read_ptr, PNG_FLAG_MNG_FILTER_64); - png_read_data(read_ptr, buffer, 40); - input_format=1; - } - else + if (!(int) + (png_memcmp(mng_signature, png_signature, 8))) { + png_byte buffer[40]; + /* Skip the MHDR */ + png_permit_mng_features(read_ptr, + PNG_FLAG_MNG_FILTER_64); + png_default_read_data(read_ptr, buffer, 40); + input_format = 1; + } else #endif - if (png_sig_cmp(png_signature, 0, 8)) - { - if (png_sig_cmp(png_signature, 0, 4)) - png_error(read_ptr, "Not a PNG file!"); - else - png_error(read_ptr, "PNG file corrupted by ASCII conversion"); - } - } - png_read_info(read_ptr, read_info_ptr); + if (png_sig_cmp(png_signature, 0, 8)) { + if (png_sig_cmp(png_signature, 0, 4)) + png_error(read_ptr, "Not a PNG file!"); + else + png_error(read_ptr, + "PNG file corrupted by ASCII conversion"); + } + } -#if (PNG_LIBPNG_VER > 90) - { - int interlace_method, compression_method, filter_method; + png_read_info(read_ptr, read_info_ptr); - png_debug(0, "Transferring info struct\n"); + { /* GRR added for quick %-navigation (1) */ - if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, - &color_type, &interlace_method, &compression_method, &filter_method)) - { - int need_expand = 0; - input_color_type=color_type; - input_bit_depth=bit_depth; + /* Start of chunk-copying/removal code, in order: + * - IHDR + * - bKGD + * - cHRM + * - gAMA + * - sRGB + * - iCCP + * - oFFs + * - pCAL + * - pHYs + * - hIST + * - tRNS + * - PLTE + * - sBIT + * - sCAL + * - sPLT + * - tEXt/zTXt/iTXt + * - tIME + * - unknown chunks + */ + { + int interlace_method, compression_method, + filter_method; - if(output_color_type > 7) - { - output_color_type=input_color_type; - } + P1( "Transferring info struct\n"); - if(verbose > 1 && first_trial) - { - fprintf(STDERR, " IHDR chunk data:\n"); - fprintf(STDERR, " Width=%ld, height=%ld\n", width, height); - fprintf(STDERR, " Bit depth =%d\n", bit_depth); - fprintf(STDERR, " Color type=%d\n", color_type); - if (output_color_type != color_type) - fprintf(STDERR, " Output color type=%d\n", - output_color_type); - fprintf(STDERR, " Interlace =%d\n", interlace_method); - } + if (png_get_IHDR + (read_ptr, read_info_ptr, &width, &height, + &bit_depth, &color_type, &interlace_method, + &compression_method, &filter_method)) { + int need_expand = 0; + input_color_type = color_type; + input_bit_depth = bit_depth; + if (output_color_type > 7) { + output_color_type = input_color_type; + } + + if (verbose > 1 && first_trial) { + fprintf(STDERR, " IHDR chunk data:\n"); + fprintf(STDERR, + " Width=%ld, height=%ld\n", width, + height); + fprintf(STDERR, " Bit depth =%d\n", + bit_depth); + fprintf(STDERR, " Color type=%d\n", + color_type); + if (output_color_type != color_type) + fprintf(STDERR, + " Output color type=%d\n", + output_color_type); + fprintf(STDERR, " Interlace =%d\n", + interlace_method); + } #ifndef PNG_WRITE_PACK_SUPPORTED - if(output_bit_depth == 0) + if (output_bit_depth == 0) #else - if(force_output_bit_depth == 0) + if (force_output_bit_depth == 0) #endif - { - output_bit_depth=input_bit_depth; - } - if((output_color_type != 3 || output_bit_depth > 8) && - output_bit_depth >= 8 && output_bit_depth != input_bit_depth) - need_expand = 1; + { + output_bit_depth = input_bit_depth; + } + if ((output_color_type != 3 + || output_bit_depth > 8) + && output_bit_depth >= 8 + && output_bit_depth != input_bit_depth) + need_expand = 1; #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if((color_type == 2 || color_type == 6 || color_type == 3) && - (output_color_type == 0 || output_color_type == 4)) - { - if(verbose > 0 && first_trial) - { + if ((color_type == 2 || color_type == 6 + || color_type == 3) && + (output_color_type == 0 || output_color_type == 4)) + { + if (verbose > 0 && first_trial) { #ifdef PNGCRUSH_COUNT_COLORS - if(reduce_to_gray) - fprintf(STDERR, - " Reducing all-gray truecolor image to grayscale.\n"); - else + if (reduce_to_gray) + fprintf(STDERR, " Reducing all-gray " + "truecolor image to grayscale.\n"); + else #endif - fprintf(STDERR, - " Reducing truecolor image to grayscale.\n"); - } + fprintf(STDERR, " Reducing truecolor " + "image to grayscale.\n"); + } #ifdef PNG_FIXED_POINT_SUPPORTED - png_set_rgb_to_gray_fixed(read_ptr, 1, -1, -1); + png_set_rgb_to_gray_fixed(read_ptr, 1, -1, -1); #else - png_set_rgb_to_gray(read_ptr, 1, 0., 0.); + png_set_rgb_to_gray(read_ptr, 1, 0., 0.); #endif - if(output_bit_depth < 8)output_bit_depth=8; - if(color_type == 3) need_expand = 1; - } + if (output_bit_depth < 8) + output_bit_depth = 8; + if (color_type == 3) + need_expand = 1; + } #endif - - if(color_type != 3 && output_color_type == 3) - { - printf(" Cannot change to indexed color (color_type 3)\n"); - output_color_type=input_color_type; - } - if((color_type == 0 || color_type == 4) && - (output_color_type == 2 || output_color_type == 6)) - { - png_set_gray_to_rgb(read_ptr); - } + if (color_type != 3 && output_color_type == 3) { + printf(" Cannot change to indexed color " + "(color_type 3)\n"); + output_color_type = input_color_type; + } - if((color_type == 4 || color_type == 6) && - (output_color_type != 4 && output_color_type != 6)) - { - if(verbose > 0 && first_trial) - { + if ((color_type == 0 || color_type == 4) && + (output_color_type == 2 + || output_color_type == 6)) { + png_set_gray_to_rgb(read_ptr); + } + + if ((color_type == 4 || color_type == 6) && + (output_color_type != 4 + && output_color_type != 6)) { + if (verbose > 0 && first_trial) { #ifdef PNGCRUSH_COUNT_COLORS - if(it_is_opaque) - fprintf(STDERR, " Stripping opaque alpha channel.\n"); - else + if (it_is_opaque) + fprintf(STDERR, + " Stripping opaque alpha channel.\n"); + else #endif - fprintf(STDERR, " Stripping existing alpha channel.\n"); - } + fprintf(STDERR, + " Stripping existing alpha channel.\n"); + } #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - png_set_strip_alpha(read_ptr); + png_set_strip_alpha(read_ptr); #endif - } + } - if((output_color_type == 4 || output_color_type == 6) && - (color_type != 4 && color_type != 6)) - { - if(verbose > 0 && first_trial) - fprintf(STDERR, " Adding an opaque alpha channel.\n"); + if ((output_color_type == 4 + || output_color_type == 6) && (color_type != 4 + && color_type + != 6)) { + if (verbose > 0 && first_trial) + fprintf(STDERR, + " Adding an opaque alpha channel.\n"); #ifdef PNG_READ_FILLER_SUPPORTED - png_set_filler(read_ptr, (png_uint_32)65535L, PNG_FILLER_AFTER); + png_set_filler(read_ptr, (png_uint_32) 65535L, + PNG_FILLER_AFTER); #endif - need_expand = 1; - } + need_expand = 1; + } - if(output_color_type && output_color_type != 3 && - output_bit_depth < 8) output_bit_depth = 8; - - if((output_color_type == 2 || output_color_type == 6) && - color_type == 3) - { - if(verbose > 0 && first_trial) - fprintf(STDERR, " Expanding indexed color file.\n"); - need_expand = 1; - } + if (output_color_type && output_color_type != 3 && + output_bit_depth < 8) + output_bit_depth = 8; + if ((output_color_type == 2 + || output_color_type == 6) + && color_type == 3) { + if (verbose > 0 && first_trial) + fprintf(STDERR, + " Expanding indexed color file.\n"); + need_expand = 1; + } #ifdef PNG_READ_EXPAND_SUPPORTED - if (need_expand == 1) - png_set_expand(read_ptr); + if (need_expand == 1) + png_set_expand(read_ptr); #endif #ifdef PNG_READ_PACK_SUPPORTED - if(input_bit_depth < 8) - { - png_set_packing(read_ptr); - } - if(output_color_type == 0 && output_bit_depth < 8) - { - png_color_8 true_bits; - true_bits.gray = (png_byte)(output_bit_depth); - png_set_shift(read_ptr, &true_bits); - } + if (input_bit_depth < 8) { + png_set_packing(read_ptr); + } + if (output_color_type == 0 && output_bit_depth < 8) { + png_color_8 true_bits; + true_bits.gray = (png_byte) (output_bit_depth); + png_set_shift(read_ptr, &true_bits); + } #endif - if(verbose > 1) - fprintf(STDERR, " Setting IHDR\n"); + if (verbose > 1) + fprintf(STDERR, " Setting IHDR\n"); #if defined(PNGCRUSH_LOCO) - output_format=0; - if(do_loco) - { - if(output_color_type == 2 || output_color_type == 6) - { - output_format=1; - filter_method = 64; - png_permit_mng_features (write_ptr, PNG_FLAG_MNG_FILTER_64); + output_format = 0; + if (do_loco) { + if (output_color_type == 2 + || output_color_type == 6) { + output_format = 1; + filter_method = 64; + png_permit_mng_features(write_ptr, + PNG_FLAG_MNG_FILTER_64); + } + } else + filter_method = 0; + if (input_format != output_format) + things_have_changed = 1; +#endif + + png_set_IHDR(write_ptr, write_info_ptr, width, + height, output_bit_depth, + output_color_type, interlace_method, + compression_method, filter_method); + + if (output_color_type != input_color_type) + things_have_changed = 1; + + } } - } - else - filter_method=0; - if(input_format != output_format) - things_have_changed = 1; -#endif - png_set_IHDR(write_ptr, write_info_ptr, width, height, - output_bit_depth, output_color_type, interlace_method, - compression_method, filter_method); - - if(output_color_type != input_color_type) things_have_changed=1; - - } - } #if defined(PNG_READ_bKGD_SUPPORTED) && defined(PNG_WRITE_bKGD_SUPPORTED) - { - png_color_16p background; + { + png_color_16p background; + + if (!have_bkgd + && png_get_bKGD(read_ptr, read_info_ptr, + &background)) { + if (keep_chunk("bKGD", argv)) { + if ((input_color_type == 2 + || input_color_type == 6) + && (output_color_type == 0 + || output_color_type == 4)) + background->gray = background->green; + png_set_bKGD(write_ptr, write_info_ptr, + background); + } + } + if (have_bkgd) { + /* If we are reducing an RGB image to grayscale, but + the background color isn't gray, the green channel + is written. That's not spec-compliant. We should + really check for a non-gray bKGD and refuse to do + the reduction if one is present. */ + png_color_16 backgd; + png_color_16p background = &backgd; + background->red = bkgd_red; + background->green = bkgd_green; + background->blue = bkgd_blue; + background->gray = background->green; + png_set_bKGD(write_ptr, write_info_ptr, + background); + } + } +#endif /* defined(PNG_READ_bKGD_SUPPORTED)&&defined(PNG_WRITE_bKGD_SUPPORTED) */ - if (!have_bkgd && png_get_bKGD(read_ptr, read_info_ptr, &background)) - { - if(keep_chunk("bKGD",argv)) - { - if((input_color_type == 2 || input_color_type == 6 ) && - (output_color_type == 0 || output_color_type == 4)) - background->gray = background->green; - png_set_bKGD(write_ptr, write_info_ptr, background); - } - } - if (have_bkgd) - { - /* If we are reducing an RGB image to grayscale, but the - background color isn't gray, the green channel is written. - That's not spec-compliant. We should really check for - a non-gray bKGD and refuse to do the reduction if one is - present. */ - png_color_16 backgd; - png_color_16p background = &backgd; - background->red=bkgd_red; - background->green=bkgd_green; - background->blue=bkgd_blue; - background->gray = background->green; - png_set_bKGD(write_ptr, write_info_ptr, background); - } - } -#endif #if defined(PNG_READ_cHRM_SUPPORTED) && defined(PNG_WRITE_cHRM_SUPPORTED) #ifdef PNG_FIXED_POINT_SUPPORTED - { - png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, - blue_x, blue_y; + { + png_fixed_point white_x, white_y, red_x, red_y, + green_x, green_y, blue_x, blue_y; - if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, - &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) - { - if(keep_chunk("cHRM",argv)) - { - if (white_x == 0 && white_y == 0 && red_x == 0 && red_y == 0 && - green_x == 0 && green_y == 0 && blue_x == 0 && blue_y == 0) - png_warning (write_ptr, "Deleting all-zero cHRM chunk"); - else - png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, - red_x, red_y, green_x, green_y, blue_x, blue_y); - } - } - } + if (png_get_cHRM_fixed + (read_ptr, read_info_ptr, &white_x, &white_y, + &red_x, &red_y, &green_x, &green_y, &blue_x, + &blue_y)) { + if (keep_chunk("cHRM", argv)) { + if (white_x == 0 && white_y == 0 && red_x == 0 + && red_y == 0 && green_x == 0 + && green_y == 0 && blue_x == 0 + && blue_y == 0) + png_warning(write_ptr, + "Deleting all-zero cHRM chunk"); + else + png_set_cHRM_fixed(write_ptr, + write_info_ptr, white_x, + white_y, red_x, red_y, + green_x, green_y, + blue_x, blue_y); + } + } + } #else - { - double white_x, white_y, red_x, red_y, green_x, green_y, - blue_x, blue_y; + { + double white_x, white_y, red_x, red_y, green_x, + green_y, blue_x, blue_y; - if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, - &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) - { - if(keep_chunk("cHRM",argv)) - { - if (white_x == 0 && white_y == 0 && red_x == 0 && red_y == 0 && - green_x == 0 && green_y == 0 && blue_x == 0 && blue_y == 0) - png_warning (write_ptr, "Deleting all-zero cHRM chunk"); - else - png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, - red_x, red_y, green_x, green_y, blue_x, blue_y); - } - } - } -#endif -#endif + if (png_get_cHRM + (read_ptr, read_info_ptr, &white_x, &white_y, + &red_x, &red_y, &green_x, &green_y, &blue_x, + &blue_y)) { + if (keep_chunk("cHRM", argv)) { + if (white_x == 0 && white_y == 0 && red_x == 0 + && red_y == 0 && green_x == 0 + && green_y == 0 && blue_x == 0 + && blue_y == 0) + png_warning(write_ptr, + "Deleting all-zero cHRM chunk"); + else + png_set_cHRM(write_ptr, write_info_ptr, + white_x, white_y, red_x, + red_y, green_x, green_y, + blue_x, blue_y); + } + } + } +#endif /* ?PNG_FIXED_POINT_SUPPORTED */ +#endif /* defined(PNG_READ_cHRM_SUPPORTED)&&defined(PNG_WRITE_cHRM_SUPPORTED) */ #if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_WRITE_gAMA_SUPPORTED) - { - if(force_specified_gamma) - { - if(first_trial) - { - things_have_changed=1; - if(verbose > 0) - fprintf(STDERR, + { + if (force_specified_gamma) { + if (first_trial) { + things_have_changed = 1; + if (verbose > 0) + fprintf(STDERR, " Inserting gAMA chunk with " #ifdef PNG_FIXED_POINT_SUPPORTED - " Inserting gAMA chunk with gamma=(%d/100000)\n", + "gamma=(%d/100000)\n", #else - " Inserting gAMA chunk with gamma=%f\n", + "gamma=%f\n", #endif - force_specified_gamma); - } + force_specified_gamma); + } #ifdef PNG_FIXED_POINT_SUPPORTED - png_set_gAMA_fixed(write_ptr, write_info_ptr, - (png_fixed_point)force_specified_gamma); - file_gamma=(png_fixed_point)force_specified_gamma; + png_set_gAMA_fixed(write_ptr, write_info_ptr, + (png_fixed_point) + force_specified_gamma); + file_gamma = + (png_fixed_point) force_specified_gamma; #else - png_set_gAMA(write_ptr, write_info_ptr, - force_specified_gamma); - file_gamma=force_specified_gamma; + png_set_gAMA(write_ptr, write_info_ptr, + force_specified_gamma); + file_gamma = force_specified_gamma; #endif - } + } #ifdef PNG_FIXED_POINT_SUPPORTED - else if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &file_gamma)) + else if (png_get_gAMA_fixed + (read_ptr, read_info_ptr, &file_gamma)) #else - else if (png_get_gAMA(read_ptr, read_info_ptr, &file_gamma)) + else if (png_get_gAMA + (read_ptr, read_info_ptr, &file_gamma)) #endif - { - if(keep_chunk("gAMA",argv)) - { - if(image_specified_gamma) - file_gamma=image_specified_gamma; - if(verbose > 1 && first_trial) + { + if (keep_chunk("gAMA", argv)) { + if (image_specified_gamma) + file_gamma = image_specified_gamma; + if (verbose > 1 && first_trial) #ifdef PNG_FIXED_POINT_SUPPORTED - fprintf(STDERR, " gamma=(%d/100000)\n", (int)file_gamma); - if(double_gamma) - file_gamma+=file_gamma; - png_set_gAMA_fixed(write_ptr, write_info_ptr, file_gamma); + fprintf(STDERR, " gamma=(%d/100000)\n", + (int) file_gamma); + if (double_gamma) + file_gamma += file_gamma; + png_set_gAMA_fixed(write_ptr, write_info_ptr, + file_gamma); #else - fprintf(STDERR, " gamma=%f\n", file_gamma); - if(double_gamma) - file_gamma+=file_gamma; - png_set_gAMA(write_ptr, write_info_ptr, file_gamma); + fprintf(STDERR, " gamma=%f\n", + file_gamma); + if (double_gamma) + file_gamma += file_gamma; + png_set_gAMA(write_ptr, write_info_ptr, + file_gamma); #endif - } - } - else if(specified_gamma) - { - if(first_trial) - { - things_have_changed=1; - if(verbose > 0) - fprintf(STDERR, + } + } else if (specified_gamma) { + if (first_trial) { + things_have_changed = 1; + if (verbose > 0) + fprintf(STDERR, " Inserting gAMA chunk with " #ifdef PNG_FIXED_POINT_SUPPORTED - " Inserting gAMA chunk with gamma=(%d/100000)\n", + "gamma=(%d/100000)\n", #else - " Inserting gAMA chunk with gamma=%f\n", + "gamma=%f\n", #endif - specified_gamma); - } + specified_gamma); + } #ifdef PNG_FIXED_POINT_SUPPORTED - png_set_gAMA_fixed(write_ptr, write_info_ptr, specified_gamma); - file_gamma=(png_fixed_point)specified_gamma; + png_set_gAMA_fixed(write_ptr, write_info_ptr, + specified_gamma); + file_gamma = (png_fixed_point) specified_gamma; #else - png_set_gAMA(write_ptr, write_info_ptr, specified_gamma); - file_gamma=specified_gamma; -#endif - } - } + png_set_gAMA(write_ptr, write_info_ptr, + specified_gamma); + file_gamma = specified_gamma; #endif + } + } +#endif /* defined(PNG_READ_gAMA_SUPPORTED)&&defined(PNG_WRITE_gAMA_SUPPORTED) */ #if defined(PNG_READ_sRGB_SUPPORTED) && defined(PNG_WRITE_sRGB_SUPPORTED) - { - int file_intent; + { + int file_intent; - if (png_get_sRGB(read_ptr, read_info_ptr, &file_intent)) - { - if(keep_chunk("sRGB",argv)) - { - png_set_sRGB(write_ptr, write_info_ptr, file_intent); - intent=file_intent; - } - } - else if(intent >= 0) - { + if (png_get_sRGB + (read_ptr, read_info_ptr, &file_intent)) { + if (keep_chunk("sRGB", argv)) { + png_set_sRGB(write_ptr, write_info_ptr, + file_intent); + intent = file_intent; + } + } else if (intent >= 0) { #ifdef PNG_gAMA_SUPPORTED #ifdef PNG_FIXED_POINT_SUPPORTED - if(file_gamma >= 45000L && file_gamma <= 46000L) + if (file_gamma >= 45000L && file_gamma <= 46000L) #else - if(file_gamma >= 0.45000 && file_gamma <= 0.46000) + if (file_gamma >= 0.45000 && file_gamma <= 0.46000) #endif - { - things_have_changed=1; - if(first_trial) - fprintf(STDERR, " Inserting sRGB chunk with intent=%d\n",intent); - png_set_sRGB(write_ptr, write_info_ptr, intent); - } - else if(file_gamma == 0) - { - things_have_changed=1; - png_set_sRGB_gAMA_and_cHRM(write_ptr, write_info_ptr, intent); - } - else - { - if(first_trial) - { - fprintf(STDERR, + { + things_have_changed = 1; + if (first_trial) + fprintf(STDERR, + " Inserting sRGB chunk with intent=%d\n", + intent); + png_set_sRGB(write_ptr, write_info_ptr, + intent); + } else if (file_gamma == 0) { + things_have_changed = 1; + png_set_sRGB_gAMA_and_cHRM(write_ptr, + write_info_ptr, + intent); + } else { + if (first_trial) { + fprintf(STDERR, " Ignoring sRGB request; " #ifdef PNG_FIXED_POINT_SUPPORTED - " Ignoring sRGB request; gamma=(%lu/100000) is not approx. 0.455\n", + "gamma=(%lu/100000)" #else - " Ignoring sRGB request; gamma=%f is not approx. 0.455\n", -#endif - file_gamma); - } - } -#endif - } - } + "gamma=%f" #endif + " is not approx. 0.455\n", file_gamma); + } + } +#endif /* PNG_gAMA_SUPPORTED */ + } + } +#endif /* defined(PNG_READ_sRGB_SUPPORTED)&&defined(PNG_WRITE_sRGB_SUPPORTED) */ + #if defined(PNG_READ_iCCP_SUPPORTED) && defined(PNG_WRITE_iCCP_SUPPORTED) - if(intent < 0) /* ignore iCCP if sRGB is being written */ - { - png_charp name; - png_charp profile; - png_uint_32 proflen; - int compression_method; + if (intent < 0) { /* ignore iCCP if sRGB is being written */ + png_charp name; + png_charp profile; + png_uint_32 proflen; + int compression_method; - if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_method, - &profile, &proflen)) - { - P1 ("Got iccp chunk, proflen=%lu\n",proflen); - if(iccp_length) - P0 ("Will not replace existing iccp chunk.\n"); - if(keep_chunk("iCCP",argv)) - png_set_iCCP(write_ptr, write_info_ptr, name, compression_method, - profile, proflen); - - } + if (png_get_iCCP + (read_ptr, read_info_ptr, &name, + &compression_method, &profile, &proflen)) { + P1("Got iccp chunk, proflen=%lu\n", proflen); + if (iccp_length) + P0("Will not replace existing iccp chunk.\n"); + if (keep_chunk("iCCP", argv)) + png_set_iCCP(write_ptr, write_info_ptr, name, + compression_method, profile, + proflen); + + } #ifdef PNG_iCCP_SUPPORTED - else if (iccp_length) - { - png_set_iCCP(write_ptr, write_info_ptr, iccp_name, 0, - iccp_text, iccp_length); - P1 ("Wrote iccp chunk, proflen=%d\n",iccp_length); - } + else if (iccp_length) { + png_set_iCCP(write_ptr, write_info_ptr, iccp_name, + 0, iccp_text, iccp_length); + P1("Wrote iccp chunk, proflen=%d\n", iccp_length); + } #endif - } -#endif + } +#endif /* defined(PNG_READ_iCCP_SUPPORTED)&&defined(PNG_WRITE_iCCP_SUPPORTED) */ + #if defined(PNG_READ_oFFs_SUPPORTED) && defined(PNG_WRITE_oFFs_SUPPORTED) - { -#if PNG_LIBPNG_VER < 10006 - png_uint_32 offset_x, offset_y; -#else - png_int_32 offset_x, offset_y; -#endif - int unit_type; + { + png_int_32 offset_x, offset_y; + int unit_type; - if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type)) - { - if(offset_x == 0 && offset_y == 0) - { - if(verbose > 0 && first_trial) - fprintf(STDERR, " Deleting useless oFFs 0 0 chunk\n"); - } - else - { - if(keep_chunk("oFFs",argv)) - png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, - unit_type); - } - } - } + if (png_get_oFFs + (read_ptr, read_info_ptr, &offset_x, &offset_y, + &unit_type)) { + if (offset_x == 0 && offset_y == 0) { + if (verbose > 0 && first_trial) + fprintf(STDERR, + " Deleting useless oFFs 0 0 chunk\n"); + } else { + if (keep_chunk("oFFs", argv)) + png_set_oFFs(write_ptr, write_info_ptr, + offset_x, offset_y, + unit_type); + } + } + } #endif + #if defined(PNG_READ_pCAL_SUPPORTED) && defined(PNG_WRITE_pCAL_SUPPORTED) - { - png_charp purpose, units; - png_charpp params; - png_int_32 X0, X1; - int type, nparams; + { + png_charp purpose, units; + png_charpp params; + png_int_32 X0, X1; + int type, nparams; - if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, - &nparams, &units, ¶ms)) - { - if(keep_chunk("pCAL",argv)) - png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, - nparams, units, params); - } - } + if (png_get_pCAL + (read_ptr, read_info_ptr, &purpose, &X0, &X1, + &type, &nparams, &units, ¶ms)) { + if (keep_chunk("pCAL", argv)) + png_set_pCAL(write_ptr, write_info_ptr, + purpose, X0, X1, type, nparams, + units, params); + } + } #endif -#if defined(PNG_READ_pHYs_SUPPORTED) && defined(PNG_WRITE_pHYs_SUPPORTED) - { - png_uint_32 res_x, res_y; - int unit_type; - if(resolution == 0) - { - if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, - &unit_type)) - { - if(res_x == 0 && res_y == 0) - { - if(verbose > 0 && first_trial) - fprintf(STDERR, " Deleting useless pHYs 0 0 chunk\n"); - } - else - { - if(keep_chunk("pHYs",argv)) - png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); - } - } - } - else - { - unit_type=1; - res_x = res_y = (png_uint_32)((resolution/.0254 + 0.5)); - png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); - if(verbose > 0 && first_trial) - fprintf(STDERR, " Added pHYs %lu %lu 1 chunk\n",res_x,res_y); - } - } +#if defined(PNG_READ_pHYs_SUPPORTED) && defined(PNG_WRITE_pHYs_SUPPORTED) + { + png_uint_32 res_x, res_y; + int unit_type; + + if (resolution == 0) { + if (png_get_pHYs + (read_ptr, read_info_ptr, &res_x, &res_y, + &unit_type)) { + if (res_x == 0 && res_y == 0) { + if (verbose > 0 && first_trial) + fprintf(STDERR, + " Deleting useless pHYs 0 0 chunk\n"); + } else { + if (keep_chunk("pHYs", argv)) + png_set_pHYs(write_ptr, write_info_ptr, + res_x, res_y, unit_type); + } + } + } else { + unit_type = 1; + res_x = res_y = + (png_uint_32) ((resolution / .0254 + 0.5)); + png_set_pHYs(write_ptr, write_info_ptr, res_x, + res_y, unit_type); + if (verbose > 0 && first_trial) + fprintf(STDERR, " Added pHYs %lu %lu 1 chunk\n", + res_x, res_y); + } + } #endif #if defined(PNG_READ_hIST_SUPPORTED) && defined(PNG_WRITE_hIST_SUPPORTED) - { - png_uint_16p hist; + { + png_uint_16p hist; - if (png_get_hIST(read_ptr, read_info_ptr, &hist)) - { - if(keep_chunk("hIST",argv)) - png_set_hIST(write_ptr, write_info_ptr, hist); - } - } -#endif -#if defined(PNG_READ_tRNS_SUPPORTED) && defined(PNG_WRITE_tRNS_SUPPORTED) - { - png_bytep trans; - int num_trans; - png_color_16p trans_values; - - if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans, - &trans_values)) - { - if(verbose > 1) - fprintf(STDERR," Found tRNS chunk in input file.\n"); - if (have_trns == 1) - P0 (" Will not overwrite existing tRNS chunk.\n"); - if(keep_chunk("tRNS",argv)) - { - int last_nonmax = -1; - trns_red = trans_values->red; - trns_green = trans_values->green; - trns_blue = trans_values->blue; - trns_gray = trans_values->gray; - if(output_color_type == 3) - { - for (ia=0;ia 0) - { - if(last_nonmax < 0) - fprintf(STDERR," Deleting all-opaque tRNS chunk.\n"); - else if(last_nonmax+1 < num_trans) - fprintf(STDERR, - " Truncating trailing opaque entries from tRNS chunk.\n"); + if (png_get_hIST(read_ptr, read_info_ptr, &hist)) { + if (keep_chunk("hIST", argv)) + png_set_hIST(write_ptr, write_info_ptr, hist); } - num_trans = last_nonmax+1; - } - if(verbose > 1) - fprintf(STDERR," png_set_tRNS, num_trans=%d\n",num_trans); - if (output_color_type != 3 || num_trans) - png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans, - trans_values); - } - } - else if (have_trns == 1) /* will not overwrite existing trns data */ - { - png_color_16 trans_data; - png_byte index_data = (png_byte)trns_index; - num_trans = index_data+1; - if(verbose > 1) - fprintf(STDERR,"Have_tRNS, num_trans=%d\n",num_trans); - if (output_color_type == 3) - { - trans_values=NULL; - for (ia=0;ia 1 && first_trial) - { - int last=-1; - for (i=0 ; ia= 0) - { - fprintf(STDERR, " Transparency:\n"); - if(output_color_type == 3) - for (i=0 ; ia 0) - num_palette=plte_len; - if (do_pplt) - { - printf("PPLT: %s\n",pplt_string); - printf("Sorry, PPLT is not implemented yet.\n"); - } - if(output_color_type == 3) - png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); - else if(keep_chunk("PLTE",argv)) - png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); - if(verbose > 1 && first_trial) - { - int i; - png_colorp p = palette; - fprintf(STDERR, " Palette:\n"); - fprintf(STDERR, " I R G B ( color ) A\n"); - for (i=0; ired, p->green, p->blue, - p->red, p->green, p->blue, - trns_array[i]); - p++; - } - } - } +#if defined(PNG_READ_tRNS_SUPPORTED) && defined(PNG_WRITE_tRNS_SUPPORTED) + { + png_bytep trans; + int num_trans; + png_color_16p trans_values; + if (png_get_tRNS + (read_ptr, read_info_ptr, &trans, &num_trans, + &trans_values)) { + if (verbose > 1) + fprintf(STDERR, + " Found tRNS chunk in input file.\n"); + if (have_trns == 1) { + P0(" Will not overwrite existing tRNS chunk.\n"); + } + if (keep_chunk("tRNS", argv)) { + int last_nonmax = -1; + trns_red = trans_values->red; + trns_green = trans_values->green; + trns_blue = trans_values->blue; + trns_gray = trans_values->gray; + if (output_color_type == 3) { + for (ia = 0; ia < num_trans; ia++) + trns_array[ia] = trans[ia]; + for (; ia < 256; ia++) + trns_array[ia] = 255; + for (ia = 0; ia < 256; ia++) { + if (trns_array[ia] != 255) + last_nonmax = ia; + } + if (first_trial && verbose > 0) { + if (last_nonmax < 0) + fprintf(STDERR, " Deleting " + "all-opaque tRNS chunk.\n"); + else if (last_nonmax + 1 < num_trans) + fprintf(STDERR, + " Truncating trailing opaque " + "entries from tRNS chunk.\n"); + } + num_trans = last_nonmax + 1; + } + if (verbose > 1) + fprintf(STDERR, + " png_set_tRNS, num_trans=%d\n", + num_trans); + if (output_color_type != 3 || num_trans) + png_set_tRNS(write_ptr, write_info_ptr, + trans, num_trans, + trans_values); + } + } else if (have_trns == 1) { /* will not overwrite existing trns data */ + png_color_16 trans_data; + png_byte index_data = (png_byte) trns_index; + num_trans = index_data + 1; + if (verbose > 1) + fprintf(STDERR, "Have_tRNS, num_trans=%d\n", + num_trans); + if (output_color_type == 3) { + trans_values = NULL; + for (ia = 0; ia < num_trans; ia++) + trns_array[ia] = trans_in[ia]; + for (; ia < 256; ia++) + trns_array[ia] = 255; + } else { + for (ia = 0; ia < 256; ia++) + trns_array[ia] = 255; + trns_array[index_data] = 0; + + trans_data.index = index_data; + trans_data.red = trns_red; + trans_data.green = trns_green; + trans_data.blue = trns_blue; + trans_data.gray = trns_gray; + trans_values = &trans_data; + } + + P0(" Adding a tRNS chunk\n"); + png_set_tRNS(write_ptr, write_info_ptr, trns_array, + num_trans, trans_values); + + things_have_changed = 1; + } else { + for (ia = 0; ia < 256; ia++) + trns_array[ia] = 255; + } + if (verbose > 1 && first_trial) { + int last = -1; + for (i = 0; ia < num_palette; ia++) + if (trns_array[ia] != 255) + last = ia; + if (last >= 0) { + fprintf(STDERR, " Transparency:\n"); + if (output_color_type == 3) + for (i = 0; ia < num_palette; ia++) + fprintf(STDERR, " %4d %4d\n", ia, + trns_array[ia]); + else if (output_color_type == 0) + fprintf(STDERR, " %d\n", trns_gray); + else if (output_color_type == 2) + fprintf(STDERR, " %d %d %d\n", + trns_red, trns_green, trns_blue); + } + } + } +#endif /* defined(PNG_READ_tRNS_SUPPORTED)&&defined(PNG_WRITE_tRNS_SUPPORTED) */ + + if (png_get_PLTE + (read_ptr, read_info_ptr, &palette, &num_palette)) + { + if (plte_len > 0) + num_palette = plte_len; + if (do_pplt) { + printf("PPLT: %s\n", pplt_string); + printf("Sorry, PPLT is not implemented yet.\n"); + } + if (output_color_type == 3) + png_set_PLTE(write_ptr, write_info_ptr, palette, + num_palette); + else if (keep_chunk("PLTE", argv)) + png_set_PLTE(write_ptr, write_info_ptr, palette, + num_palette); + if (verbose > 1 && first_trial) { + int i; + png_colorp p = palette; + fprintf(STDERR, " Palette:\n"); + fprintf(STDERR, + " I R G B ( color ) A\n"); + for (i = 0; i < num_palette; i++) { + fprintf(STDERR, + " %4d %4d %4d %4d (#%2.2x%2.2x%2.2x) %4d\n", + i, p->red, p->green, p->blue, p->red, + p->green, p->blue, trns_array[i]); + p++; + } + } + } #if defined(PNG_READ_sBIT_SUPPORTED) && defined(PNG_WRITE_sBIT_SUPPORTED) - { - png_color_8p sig_bit; + { + png_color_8p sig_bit; - /* If we are reducing a truecolor PNG to grayscale, and the - RGB sBIT values aren't identical, we'll lose sBIT info. */ + /* If we are reducing a truecolor PNG to grayscale, and the + * RGB sBIT values aren't identical, we'll lose sBIT info. + */ + if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) { + if (keep_chunk("sBIT", argv)) { + if ((input_color_type == 0 + || input_color_type == 4) + && (output_color_type == 2 + || output_color_type == 6 + || output_color_type == 3)) + sig_bit->red = sig_bit->green = + sig_bit->blue = sig_bit->gray; + if ((input_color_type == 2 + || input_color_type == 6 + || output_color_type == 3) + && (output_color_type == 0 + || output_color_type == 4)) + sig_bit->gray = sig_bit->green; - if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) - { - if(keep_chunk("sBIT",argv)) - { - if((input_color_type == 0 || input_color_type == 4) && - (output_color_type == 2 || output_color_type == 6 || - output_color_type == 3)) - sig_bit->red = sig_bit->green = sig_bit->blue - = sig_bit->gray; - if((input_color_type == 2 || input_color_type == 6 || - output_color_type == 3) && - (output_color_type == 0 || output_color_type == 4)) - sig_bit->gray = sig_bit->green; + if ((input_color_type == 0 + || input_color_type == 2) + && (output_color_type == 4 + || output_color_type == 6)) + sig_bit->alpha = 1; - if((input_color_type == 0 || input_color_type == 2) && - (output_color_type == 4 || output_color_type == 6)) - sig_bit->alpha=1; + png_set_sBIT(write_ptr, write_info_ptr, + sig_bit); + } + } + } +#endif /* defined(PNG_READ_sBIT_SUPPORTED)&&defined(PNG_WRITE_sBIT_SUPPORTED) */ - png_set_sBIT(write_ptr, write_info_ptr, sig_bit); - } - } - } -#endif #if defined(PNG_sCAL_SUPPORTED) #ifdef PNG_FLOATING_POINT_SUPPORTED - { - int unit; - double scal_width, scal_height; + { + int unit; + double scal_width, scal_height; - if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, &scal_height)) - { - png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); - } - } + if (png_get_sCAL + (read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) { + png_set_sCAL(write_ptr, write_info_ptr, unit, + scal_width, scal_height); + } + } #else #ifdef PNG_FIXED_POINT_SUPPORTED - { - int unit; - png_charp scal_width, scal_height; + { + int unit; + png_charp scal_width, scal_height; - if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, &scal_height)) - { - if(keep_chunk("sCAL",argv)) - png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height); - } - } -#endif -#endif + if (png_get_sCAL_s + (read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) { + if (keep_chunk("sCAL", argv)) + png_set_sCAL_s(write_ptr, write_info_ptr, unit, + scal_width, scal_height); + } + } #endif +#endif /* PNG_FLOATING_POINT_SUPPORTED */ +#endif /* ?PNG_sCAL_SUPPORTED */ #if defined(PNG_sPLT_SUPPORTED) - { - png_sPLT_tp entries; - int num_entries; + { + png_sPLT_tp entries; + int num_entries; - num_entries = (int)png_get_sPLT(read_ptr, read_info_ptr, &entries); - if (num_entries) - { - if(keep_chunk("sPLT",argv)) - png_set_sPLT(write_ptr, write_info_ptr, entries, num_entries); - png_free_data(read_ptr, read_info_ptr, PNG_FREE_SPLT, num_entries); - } - } + num_entries = + (int) png_get_sPLT(read_ptr, read_info_ptr, + &entries); + if (num_entries) { + if (keep_chunk("sPLT", argv)) + png_set_sPLT(write_ptr, write_info_ptr, + entries, num_entries); + png_free_data(read_ptr, read_info_ptr, + PNG_FREE_SPLT, num_entries); + } + } #endif #if defined(PNG_TEXT_SUPPORTED) - { - png_textp text_ptr; - int num_text=0; + { + png_textp text_ptr; + int num_text = 0; - if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0 || - text_inputs) - { - int ntext; - png_debug1(0, "Handling %d tEXt/zTXt chunks\n", num_text); + if (png_get_text + (read_ptr, read_info_ptr, &text_ptr, &num_text) > 0 + || text_inputs) { + int ntext; + P1( "Handling %d tEXt/zTXt chunks\n", + num_text); - if (verbose > 1 && first_trial && num_text > 0) - { - for (ntext = 0; ntext < num_text; ntext++) - { - fprintf(STDERR,"%d %s",ntext,text_ptr[ntext].key); - if(text_ptr[ntext].text_length) - fprintf(STDERR,": %s\n",text_ptr[ntext].text); + if (verbose > 1 && first_trial && num_text > 0) { + for (ntext = 0; ntext < num_text; ntext++) { + fprintf(STDERR, "%d %s", ntext, + text_ptr[ntext].key); + if (text_ptr[ntext].text_length) + fprintf(STDERR, ": %s\n", + text_ptr[ntext].text); #ifdef PNG_iTXt_SUPPORTED - else if (text_ptr[ntext].itxt_length) - { - fprintf(STDERR," (%s: %s): \n", - text_ptr[ntext].lang, - text_ptr[ntext].lang_key); - fprintf(STDERR,"%s\n",text_ptr[ntext].text); - } + else if (text_ptr[ntext].itxt_length) { + fprintf(STDERR, " (%s: %s): \n", + text_ptr[ntext].lang, + text_ptr[ntext].lang_key); + fprintf(STDERR, "%s\n", + text_ptr[ntext].text); + } #endif - else - fprintf(STDERR,"\n"); - } - } + else + fprintf(STDERR, "\n"); + } + } - if(num_text > 0) - { - if(keep_chunk("text",argv)) - { - int num_to_write=num_text; - for (ntext = 0; ntext < num_text; ntext++) - { - if (first_trial) - P2("Text chunk before IDAT, compression=%d\n", - text_ptr[ntext].compression); - if(text_ptr[ntext].compression==PNG_TEXT_COMPRESSION_NONE) - { - if(!keep_chunk("tEXt",argv)) - { - text_ptr[ntext].key[0]='\0'; - num_to_write--; - } - } - if(text_ptr[ntext].compression==PNG_TEXT_COMPRESSION_zTXt) - { - if(!keep_chunk("zTXt",argv)) - { - text_ptr[ntext].key[0]='\0'; - num_to_write--; - } - } + if (num_text > 0) { + if (keep_chunk("text", argv)) { + int num_to_write = num_text; + for (ntext = 0; ntext < num_text; ntext++) { + if (first_trial) + P2("Text chunk before IDAT, " + "compression=%d\n", + text_ptr[ntext].compression); + if (text_ptr[ntext].compression == + PNG_TEXT_COMPRESSION_NONE) { + if (!keep_chunk("tEXt", argv)) { + text_ptr[ntext].key[0] = '\0'; + num_to_write--; + } + } + if (text_ptr[ntext].compression == + PNG_TEXT_COMPRESSION_zTXt) { + if (!keep_chunk("zTXt", argv)) { + text_ptr[ntext].key[0] = '\0'; + num_to_write--; + } + } #ifdef PNG_iTXt_SUPPORTED - if(text_ptr[ntext].compression==PNG_ITXT_COMPRESSION_NONE - ||text_ptr[ntext].compression==PNG_ITXT_COMPRESSION_zTXt) - { - if(!keep_chunk("iTXt",argv)) - { - text_ptr[ntext].key[0]='\0'; - num_to_write--; - } - } + if (text_ptr[ntext].compression == + PNG_ITXT_COMPRESSION_NONE + || text_ptr[ntext].compression == + PNG_ITXT_COMPRESSION_zTXt) { + if (!keep_chunk("iTXt", argv)) { + text_ptr[ntext].key[0] = '\0'; + num_to_write--; + } + } #endif - } - if (num_to_write > 0) - png_set_text(write_ptr, write_info_ptr, text_ptr, - num_text); - } - } - for (ntext=0; ntext 0) + png_set_text(write_ptr, write_info_ptr, + text_ptr, num_text); + } + } + for (ntext = 0; ntext < text_inputs; ntext++) { + if (text_where[ntext] == 1) { + png_textp added_text; + added_text = (png_textp) png_malloc(write_ptr, + (png_uint_32) sizeof(png_text)); + added_text[0].key = &text_keyword[ntext * 80]; #ifdef PNG_iTXt_SUPPORTED - added_text[0].lang = &text_lang[ntext*80]; - added_text[0].lang_key = &text_lang_key[ntext*80]; + added_text[0].lang = &text_lang[ntext * 80]; + added_text[0].lang_key = + &text_lang_key[ntext * 80]; #endif - added_text[0].text = &text_text[ntext*2048]; - added_text[0].compression = text_compression[ntext]; - png_set_text(write_ptr, write_info_ptr, added_text, 1); - if(added_text[0].compression < 0) - printf(" Added a tEXt chunk.\n"); - else if(added_text[0].compression == 0) - printf(" Added a zTXt chunk.\n"); + added_text[0].text = &text_text[ntext * 2048]; + added_text[0].compression = + text_compression[ntext]; + png_set_text(write_ptr, write_info_ptr, + added_text, 1); + if (added_text[0].compression < 0) + printf(" Added a tEXt chunk.\n"); + else if (added_text[0].compression == 0) + printf(" Added a zTXt chunk.\n"); #ifdef PNG_iTXt_SUPPORTED - else if(added_text[0].compression == 1) - printf(" Added an uncompressed iTXt chunk.\n"); - else - printf(" Added a compressed iTXt chunk.\n"); -#endif - png_free(write_ptr,added_text); added_text=(png_textp)NULL; - } - } - } - } + else + printf(" Added a%scompressed iTXt chunk" + ".\n", (added_text[0].compression == 1)? + "n un" : " "); #endif + png_free(write_ptr, added_text); + added_text = (png_textp) NULL; + } + } + } + } +#endif /* defined(PNG_TEXT_SUPPORTED) */ #if defined(PNG_READ_tIME_SUPPORTED) && defined(PNG_WRITE_tIME_SUPPORTED) - { - png_timep mod_time; + { + png_timep mod_time; - if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) - { - if(keep_chunk("tIME",argv)) - png_set_tIME(write_ptr, write_info_ptr, mod_time); - } - } + if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) { + if (keep_chunk("tIME", argv)) + png_set_tIME(write_ptr, write_info_ptr, mod_time); + } + } #endif -#endif /* PNG_LIBPNG_VER > 90 */ - png_read_transform_info(read_ptr, read_info_ptr); +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + /* This section handles pCAL and tIME (at least, in default + * build), gIFx/gIFg/gIFt, private Fireworks chunks, etc. */ + { + png_unknown_chunkp unknowns; /* allocated by libpng */ + int num_unknowns; + + num_unknowns = (int)png_get_unknown_chunks(read_ptr, + read_info_ptr, &unknowns); + P1("Found %d unknown chunks\n", num_unknowns); + + if (num_unknowns) { + png_unknown_chunkp unknowns_keep; /* allocated by us */ + int num_unknowns_keep; + int i; + + unknowns_keep = png_malloc(write_ptr, + (png_uint_32) num_unknowns*sizeof(png_unknown_chunk)); + num_unknowns_keep = 0; + + /* make an array of only those chunks we want to keep */ + for (i = 0; i < num_unknowns; i++) { + /* not EBCDIC-safe, but neither is keep_chunks(): */ + P2(" unknown[%d] = %s (%lu bytes, location %d)\n", + i, unknowns[i].name, + (png_uint_32)unknowns[i].size, + unknowns[i].location); + if (keep_chunk((char *)unknowns[i].name, argv)) { + memcpy(&unknowns_keep[num_unknowns_keep], + &unknowns[i], sizeof(png_unknown_chunk)); + ++num_unknowns_keep; + } + } + + P1("Keeping %d unknown chunks\n", num_unknowns_keep); + png_set_unknown_chunks(write_ptr, write_info_ptr, + unknowns_keep, num_unknowns_keep); + + /* relevant location bits: + * (1) !PNG_HAVE_PLTE && !PNG_HAVE_IDAT (before PLTE) + * (2) PNG_HAVE_PLTE && !PNG_HAVE_IDAT (between) + * (3) PNG_AFTER_IDAT (after IDAT) + * PNG_HAVE_PLTE = 0x02 + * PNG_HAVE_IDAT = 0x04 + * PNG_AFTER_IDAT = 0x08 + */ + for (i = 0; i < num_unknowns_keep; i++) { + png_set_unknown_chunk_location(write_ptr, + write_info_ptr, i, + (int)unknowns_keep[i].location); + } + + /* png_set_unknown_chunks() makes own copy, so nuke + * ours */ + png_free(write_ptr, unknowns_keep); + } + } +#endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ + } /* GRR added for quick %-navigation (1) */ - if(nosave == 0) - { - - if (filter_type == 0)png_set_filter(write_ptr,0,PNG_FILTER_NONE); - else if(filter_type == 1)png_set_filter(write_ptr,0,PNG_FILTER_SUB); - else if(filter_type == 2)png_set_filter(write_ptr,0,PNG_FILTER_UP); - else if(filter_type == 3)png_set_filter(write_ptr,0,PNG_FILTER_AVG); - else if(filter_type == 4)png_set_filter(write_ptr,0,PNG_FILTER_PAETH); - else if(filter_type == 5)png_set_filter(write_ptr,0,PNG_ALL_FILTERS); - else png_set_filter(write_ptr,0,PNG_FILTER_NONE); + png_read_transform_info(read_ptr, read_info_ptr); -#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) - { - png_unknown_chunkp unknowns; - int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, - &unknowns); - if (num_unknowns) - { - int i; - png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, - num_unknowns); - for (i = 0; i < num_unknowns; i++) - png_set_unknown_chunk_location(write_ptr, write_info_ptr, - i, (int)unknowns[i].location); - } - } -#endif + /* this is the default case (nosave == 1 -> perf-testing + only) */ + if (nosave == 0) { + + if (filter_type == 0) + png_set_filter(write_ptr, 0, PNG_FILTER_NONE); + else if (filter_type == 1) + png_set_filter(write_ptr, 0, PNG_FILTER_SUB); + else if (filter_type == 2) + png_set_filter(write_ptr, 0, PNG_FILTER_UP); + else if (filter_type == 3) + png_set_filter(write_ptr, 0, PNG_FILTER_AVG); + else if (filter_type == 4) + png_set_filter(write_ptr, 0, PNG_FILTER_PAETH); + else if (filter_type == 5) + png_set_filter(write_ptr, 0, PNG_ALL_FILTERS); + else + png_set_filter(write_ptr, 0, PNG_FILTER_NONE); + + +/* GRR 20050220: not clear why unknowns treated differently from other chunks */ +/* (i.e., inside nosave==0 block)... Moved up 50 lines now. */ +#if 0 /* #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ + { + png_unknown_chunkp unknowns; + int num_unknowns = (int) png_get_unknown_chunks( + read_ptr, read_info_ptr, &unknowns); + + P1("Keeping %d unknown chunks\n", num_unknowns); + if (num_unknowns) { + int i; + + png_set_unknown_chunks(write_ptr, write_info_ptr, + unknowns, num_unknowns); + for (i = 0; i < num_unknowns; i++) { + P2(" unknown[%d] = %s\n", i, unknowns[i].name); + png_set_unknown_chunk_location(write_ptr, + write_info_ptr, i, (int)unknowns[i].location); + } + } + } +#endif /* 0, was PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ #ifdef PNGCRUSH_LOCO - if(do_loco) - { - png_byte buffer[30]; - const png_byte png_MHDR[5] = { 77, 72, 68, 82, '\0'}; - png_byte mng_signature[8] = {138, 77, 78, 71, 13, 10, 26, 10}; - /* write the MNG 8 byte signature */ - if(outname[strlen(outname)-3] == 'p') - png_warning(read_ptr, " Writing a MNG file with a .png extension"); - png_write_data(write_ptr, &mng_signature[0], (png_size_t)8); - png_set_sig_bytes(write_ptr, 8); + if (do_loco) { + png_byte buffer[30]; + const png_byte png_MHDR[5] = + { 77, 72, 68, 82, '\0' }; + png_byte mng_signature[8] = + { 138, 77, 78, 71, 13, 10, 26, 10 }; + /* write the MNG 8-byte signature */ + if (outname[strlen(outname) - 3] == 'p') + png_warning(read_ptr, + " Writing a MNG file with a .png extension"); + png_default_write_data(write_ptr, &mng_signature[0], + (png_size_t) 8); + png_set_sig_bytes(write_ptr, 8); - /* Write a MHDR chunk */ + /* Write a MHDR chunk */ - buffer[0]=(png_byte)((width>>24) & 0xff); - buffer[1]=(png_byte)((width>>16) & 0xff); - buffer[2]=(png_byte)((width>> 8) & 0xff); - buffer[3]=(png_byte)((width ) & 0xff); - buffer[4]=(png_byte)((height>>24) & 0xff); - buffer[5]=(png_byte)((height>>16) & 0xff); - buffer[6]=(png_byte)((height>> 8) & 0xff); - buffer[7]=(png_byte)((height ) & 0xff); - for (i=8; i<27; i++) - buffer[i]=0x00; - buffer[15]=2; /* layer count */ - buffer[19]=1; /* frame count */ - if(output_color_type == 6) - buffer[27]=0x09; /* simplicity profile: MNG-VLC with transparency */ - else - buffer[27]=0x01; /* simplicity profile: MNG-VLC */ - png_write_chunk(write_ptr, (png_bytep)png_MHDR, buffer, (png_size_t)28); - } -#endif + buffer[0] = (png_byte) ((width >> 24) & 0xff); + buffer[1] = (png_byte) ((width >> 16) & 0xff); + buffer[2] = (png_byte) ((width >> 8) & 0xff); + buffer[3] = (png_byte) ((width) & 0xff); + buffer[4] = (png_byte) ((height >> 24) & 0xff); + buffer[5] = (png_byte) ((height >> 16) & 0xff); + buffer[6] = (png_byte) ((height >> 8) & 0xff); + buffer[7] = (png_byte) ((height) & 0xff); + for (i = 8; i < 27; i++) + buffer[i] = 0x00; + buffer[15] = 2; /* layer count */ + buffer[19] = 1; /* frame count */ + if (output_color_type == 6) + buffer[27] = 0x09; /* profile: MNG-VLC with trans. */ + else + buffer[27] = 0x01; /* profile: MNG-VLC */ + png_write_chunk(write_ptr, (png_bytep) png_MHDR, + buffer, (png_size_t) 28); + } +#endif /* PNGCRUSH_LOCO */ - P2("writing info structure.\n"); - png_crush_pause(); - png_debug(0, "\nWriting info struct\n"); + png_crush_pause(); + P1( "\nWriting info struct\n"); #if 0 /* doesn't work; compression level has to be the same as in IDAT */ - /* if zTXt other compressed chunk */ - png_set_compression_level(write_ptr, 9); - png_set_compression_window_bits(write_ptr, 15); + /* if zTXt other compressed chunk */ + png_set_compression_level(write_ptr, 9); + png_set_compression_window_bits(write_ptr, 15); #endif - png_crush_pause(); - { - int compression_window; -#if (PNG_LIBPNG_VER >= 10000) - png_uint_32 zbuf_size; -#endif - png_uint_32 required_window; - int channels=0; - png_set_compression_strategy(write_ptr, z_strategy); - png_set_compression_mem_level(write_ptr, compression_mem_level); + png_crush_pause(); + { + int compression_window; + png_uint_32 zbuf_size; + png_uint_32 required_window; + int channels = 0; + png_set_compression_strategy(write_ptr, + z_strategy); + png_set_compression_mem_level(write_ptr, + compression_mem_level); - if (output_color_type == 0)channels=1; - if (output_color_type == 2)channels=3; - if (output_color_type == 3)channels=1; - if (output_color_type == 4)channels=2; - if (output_color_type == 6)channels=4; + if (output_color_type == 0) + channels = 1; + if (output_color_type == 2) + channels = 3; + if (output_color_type == 3) + channels = 1; + if (output_color_type == 4) + channels = 2; + if (output_color_type == 6) + channels = 4; - required_window= - (png_uint_32)(height*((width*channels*bit_depth+15)>>3)+262); + required_window = + (png_uint_32) (height * + ((width * channels * bit_depth + + 15) >> 3) + 262); -#if (PNG_LIBPNG_VER >= 10000) - zbuf_size = png_get_compression_buffer_size(write_ptr); + zbuf_size = + png_get_compression_buffer_size(write_ptr); - /* reinitialize zbuf - compression buffer */ - if (zbuf_size != max_idat_size) - { - png_uint_32 max_possible_size=required_window; - if(max_possible_size > max_idat_size) - max_possible_size=max_idat_size; - P2("reinitializing write zbuf to %lu.\n",max_possible_size); - png_set_compression_buffer_size(write_ptr, max_possible_size); - } -#endif + /* reinitialize zbuf - compression buffer */ + if (zbuf_size != max_idat_size) { + png_uint_32 max_possible_size = + required_window; + if (max_possible_size > max_idat_size) + max_possible_size = max_idat_size; + P2("reinitializing write zbuf to %lu.\n", + max_possible_size); + png_set_compression_buffer_size(write_ptr, + max_possible_size); + } #ifdef WBITS_8_OK - if (required_window <= 256)compression_window = 8; - else if(required_window <= 512)compression_window = 9; + if (required_window <= 256) + compression_window = 8; + else if (required_window <= 512) + compression_window = 9; #else - if (required_window <= 512)compression_window = 9; + if (required_window <= 512) + compression_window = 9; #endif - else if(required_window <= 1024)compression_window = 10; - else if(required_window <= 2048)compression_window = 11; - else if(required_window <= 4096)compression_window = 12; - else if(required_window <= 8192)compression_window = 13; - else if(required_window <= 16384)compression_window = 14; - else compression_window = 15; - if(compression_window > default_compression_window || - force_compression_window) - compression_window = default_compression_window; + else if (required_window <= 1024) + compression_window = 10; + else if (required_window <= 2048) + compression_window = 11; + else if (required_window <= 4096) + compression_window = 12; + else if (required_window <= 8192) + compression_window = 13; + else if (required_window <= 16384) + compression_window = 14; + else + compression_window = 15; + if (compression_window > default_compression_window + || force_compression_window) + compression_window = + default_compression_window; - if(verbose > 1 && first_trial && (compression_window != 15 || - force_compression_window)) - fprintf(STDERR, " Compression window for output= %d\n", - 1 << compression_window); + if (verbose > 1 && first_trial + && (compression_window != 15 + || force_compression_window)) + fprintf(STDERR, + " Compression window for output= %d\n", + 1 << compression_window); - png_set_compression_window_bits(write_ptr, compression_window); - } + png_set_compression_window_bits(write_ptr, + compression_window); + } - png_set_compression_level(write_ptr, zlib_level); - png_write_info(write_ptr, write_info_ptr); - png_debug(0, "\nWrote info struct\n"); - P2("wrote info structure.\n"); + png_set_compression_level(write_ptr, zlib_level); + png_write_info(write_ptr, write_info_ptr); + P1( "\nWrote info struct\n"); #ifdef PNG_WRITE_PACK_SUPPORTED - if(output_bit_depth < 8) - { - if(output_color_type == 0) - { - png_color_8 true_bits; - true_bits.gray = (png_byte)(output_bit_depth); - png_set_shift(write_ptr, &true_bits); - } - png_set_packing(write_ptr); - } + if (output_bit_depth < 8) { + if (output_color_type == 0) { + png_color_8 true_bits; + true_bits.gray = (png_byte) (output_bit_depth); + png_set_shift(write_ptr, &true_bits); + } + png_set_packing(write_ptr); + } #endif - } /* no save */ - + } + /* no save */ #define LARGE_PNGCRUSH #ifdef PNGCRUSH_MULTIPLE_ROWS - rows_at_a_time=max_rows_at_a_time; - if(rows_at_a_time == 0 || rows_at_a_time < height) - rows_at_a_time=height; + rows_at_a_time = max_rows_at_a_time; + if (rows_at_a_time == 0 || rows_at_a_time < height) + rows_at_a_time = height; #endif #ifndef LARGE_PNGCRUSH - { - png_uint_32 rowbytes_s; - png_uint_32 rowbytes; + { + png_uint_32 rowbytes_s; + png_uint_32 rowbytes; - rowbytes = png_get_rowbytes(read_ptr, read_info_ptr); + rowbytes = png_get_rowbytes(read_ptr, read_info_ptr); - rowbytes_s = (png_size_t)rowbytes; - if(rowbytes == (png_uint_32)rowbytes_s) + rowbytes_s = (png_size_t) rowbytes; + if (rowbytes == (png_uint_32) rowbytes_s) #ifdef PNGCRUSH_MULTIPLE_ROWS - row_buf = png_malloc(read_ptr, rows_at_a_time*rowbytes+16); + row_buf = + png_malloc(read_ptr, + rows_at_a_time * rowbytes + 16); #else - row_buf = png_malloc(read_ptr, rowbytes+16); + row_buf = png_malloc(read_ptr, rowbytes + 16); #endif - else - row_buf = NULL; - } + else + row_buf = NULL; + } #else - { - png_uint_32 read_row_length, write_row_length; - read_row_length= - (png_uint_32)(png_get_rowbytes(read_ptr, read_info_ptr)); - write_row_length= - (png_uint_32)(png_get_rowbytes(write_ptr, write_info_ptr)); - row_length = read_row_length > write_row_length ? - read_row_length : write_row_length; + { + png_uint_32 read_row_length, write_row_length; + read_row_length = + (png_uint_32) (png_get_rowbytes + (read_ptr, read_info_ptr)); + write_row_length = + (png_uint_32) (png_get_rowbytes + (write_ptr, write_info_ptr)); + row_length = + read_row_length > + write_row_length ? read_row_length : + write_row_length; #ifdef PNGCRUSH_MULTIPLE_ROWS - row_buf = (png_bytep)png_malloc(read_ptr,rows_at_a_time*row_length+16); + row_buf = + (png_bytep) png_malloc(read_ptr, + rows_at_a_time * + row_length + 16); #else - row_buf = (png_bytep)png_malloc(read_ptr,row_length+16); + row_buf = + (png_bytep) png_malloc(read_ptr, row_length + 16); #endif - } + } #endif - if (row_buf == NULL) - png_error(read_ptr, "Insufficient memory to allocate row buffer"); + if (row_buf == NULL) + png_error(read_ptr, + "Insufficient memory to allocate row buffer"); - { - /* check for sufficient memory: we need 2*zlib_window - and, if filter_type == 5, 4*rowbytes in separate allocations. - If it's not enough we can drop the "average" filter and - we can reduce the zlib_window for writing. We can't change - the input zlib_window because the input file might have - used the full 32K sliding window. - */ - } + { + /* check for sufficient memory: we need 2*zlib_window and, + if filter_type == 5, 4*rowbytes in separate allocations. + If it's not enough we can drop the "average" filter and + we can reduce the zlib_window for writing. We can't + change the input zlib_window because the input file + might have used the full 32K sliding window. + */ + } #ifdef PNGCRUSH_MULTIPLE_ROWS - row_pointers = (png_bytepp)png_malloc(read_ptr, - rows_at_a_time*sizeof(png_bytepp)); - for (i=0; i height) num_rows=height-y; - png_read_rows(read_ptr, row_pointers, (png_bytepp)NULL, num_rows); + if (y + num_rows > height) + num_rows = height - y; + png_read_rows(read_ptr, row_pointers, + (png_bytepp) NULL, num_rows); #else - png_read_row(read_ptr, row_buf, (png_bytep)NULL); + png_read_row(read_ptr, row_buf, (png_bytep) NULL); #endif - if(nosave == 0) - { - t_stop = (TIME_T)clock(); - t_decode += (t_stop - t_start); - if (t_stop < t_start) - { - t_decode+= PNG_MAX_UINT; - if (t_stop < 0) - t_decode+= PNG_MAX_UINT; - } - t_start = t_stop; + if (nosave == 0) { + t_stop = (TIME_T) clock(); + t_decode += (t_stop - t_start); + if (t_stop < t_start) { + t_decode += PNG_MAX_UINT; + if (t_stop < 0) + t_decode += PNG_MAX_UINT; + } + t_start = t_stop; #ifdef PNGCRUSH_MULTIPLE_ROWS - png_write_rows(write_ptr, row_pointers, num_rows); + png_write_rows(write_ptr, row_pointers, + num_rows); #else - png_write_row(write_ptr, row_buf); + png_write_row(write_ptr, row_buf); #endif - t_stop = (TIME_T)clock(); - t_encode += (t_stop - t_start); - if (t_stop < t_start) - { - t_encode+= PNG_MAX_UINT; - if (t_stop < 0) - t_encode+= PNG_MAX_UINT; - } - t_start = t_stop; - } - } - png_debug(0, "\nEnd Pass\n"); - } - if(nosave) - { - t_stop = (TIME_T)clock(); - t_decode += (t_stop - t_start); - if (t_stop < t_start) - { - t_decode+= PNG_MAX_UINT; - if (t_stop < 0) - t_decode+= PNG_MAX_UINT; - } - t_start = t_stop; - } + t_stop = (TIME_T) clock(); + t_encode += (t_stop - t_start); + if (t_stop < t_start) { + t_encode += PNG_MAX_UINT; + if (t_stop < 0) + t_encode += PNG_MAX_UINT; + } + t_start = t_stop; + } + } + P2( "End interlace pass %d\n\n", pass); + } + if (nosave) { + t_stop = (TIME_T) clock(); + t_decode += (t_stop - t_start); + if (t_stop < t_start) { + t_decode += PNG_MAX_UINT; + if (t_stop < 0) + t_decode += PNG_MAX_UINT; + } + t_start = t_stop; + } - #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) && \ defined(PNG_FLOATING_POINT_SUPPORTED) - if((color_type == 2 || color_type == 6 || color_type == 3) && - (output_color_type == 0 || output_color_type == 4)) - { - png_byte rgb_error = png_get_rgb_to_gray_status(read_ptr); - if((first_trial) && rgb_error) - printf(" **** Converted non-gray image to gray. **** \n"); - } + if ((color_type == 2 || color_type == 6 || color_type == 3) + && (output_color_type == 0 || output_color_type == 4)) + { + png_byte rgb_error = + png_get_rgb_to_gray_status(read_ptr); + if ((first_trial) && rgb_error) + printf( + " **** Converted non-gray image to gray. **** \n"); + } #endif #ifdef PNG_FREE_UNKN # if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); + png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); # endif # if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) - png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); + png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); # endif #else # if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - png_free_unknown_chunks(read_ptr, read_info_ptr, -1); + png_free_unknown_chunks(read_ptr, read_info_ptr, -1); # endif # if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) - png_free_unknown_chunks(write_ptr, write_info_ptr, -1); + png_free_unknown_chunks(write_ptr, write_info_ptr, -1); # endif #endif - png_debug(0, "Reading and writing end_info data\n"); - png_read_end(read_ptr, end_info_ptr); + P1( "Reading and writing end_info data\n"); + png_read_end(read_ptr, end_info_ptr); -#if (PNG_LIBPNG_VER > 90) -#if (defined(PNG_READ_tEXt_SUPPORTED) && defined(PNG_WRITE_tEXt_SUPPORTED)) || \ - (defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED)) - { - png_textp text_ptr; - int num_text=0; + { /* GRR: added for %-navigation (2) */ - if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0 || - text_inputs) - { - int ntext; - png_debug1(0, "Handling %d tEXt/zTXt chunks\n", num_text); +#if (defined(PNG_READ_tEXt_SUPPORTED) && defined(PNG_WRITE_tEXt_SUPPORTED)) \ + || (defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED)) + { + png_textp text_ptr; + int num_text = 0; - if (verbose > 1 && first_trial && num_text > 0) - { - for (ntext = 0; ntext < num_text; ntext++) - { - fprintf(STDERR,"%d %s",ntext,text_ptr[ntext].key); - if(text_ptr[ntext].text_length) - fprintf(STDERR,": %s\n",text_ptr[ntext].text); -#ifdef PNG_iTXt_SUPPORTED - else if (text_ptr[ntext].itxt_length) - { - fprintf(STDERR," (%s: %s): \n", - text_ptr[ntext].lang, - text_ptr[ntext].lang_key); - fprintf(STDERR,"%s\n",text_ptr[ntext].text); - } -#endif - else - fprintf(STDERR,"\n"); - } - } + if (png_get_text + (read_ptr, end_info_ptr, &text_ptr, &num_text) > 0 + || text_inputs) { + int ntext; + P1( "Handling %d tEXt/zTXt chunks\n", + num_text); - if(num_text > 0) - { - if(keep_chunk("text",argv)) - { - int num_to_write=num_text; - for (ntext = 0; ntext < num_text; ntext++) - { - if (first_trial) - P2("Text chunk after IDAT, compression=%d\n", - text_ptr[ntext].compression); - if(text_ptr[ntext].compression==PNG_TEXT_COMPRESSION_NONE) - { - if(!keep_chunk("tEXt",argv)) - { - text_ptr[ntext].key[0]='\0'; - num_to_write--; - } - } - if(text_ptr[ntext].compression==PNG_TEXT_COMPRESSION_zTXt) - { - if(!keep_chunk("zTXt",argv)) - { - text_ptr[ntext].key[0]='\0'; - num_to_write--; - } - } + if (verbose > 1 && first_trial && num_text > 0) { + for (ntext = 0; ntext < num_text; ntext++) { + fprintf(STDERR, "%d %s", ntext, + text_ptr[ntext].key); + if (text_ptr[ntext].text_length) + fprintf(STDERR, ": %s\n", + text_ptr[ntext].text); #ifdef PNG_iTXt_SUPPORTED - if(text_ptr[ntext].compression==PNG_ITXT_COMPRESSION_NONE - ||text_ptr[ntext].compression==PNG_ITXT_COMPRESSION_zTXt) - { - if(!keep_chunk("iTXt",argv)) - { - text_ptr[ntext].key[0]='\0'; - num_to_write--; - } - } + else if (text_ptr[ntext].itxt_length) { + fprintf(STDERR, " (%s: %s): \n", + text_ptr[ntext].lang, + text_ptr[ntext].lang_key); + fprintf(STDERR, "%s\n", + text_ptr[ntext].text); + } #endif - } - if (num_to_write > 0) - png_set_text(write_ptr, write_end_info_ptr, text_ptr, - num_text); - } - } - for (ntext=0; ntext 0) { + if (keep_chunk("text", argv)) { + int num_to_write = num_text; + for (ntext = 0; ntext < num_text; ntext++) { + if (first_trial) + P2("Text chunk after IDAT, " + "compression=%d\n", + text_ptr[ntext].compression); + if (text_ptr[ntext].compression == + PNG_TEXT_COMPRESSION_NONE) { + if (!keep_chunk("tEXt", argv)) { + text_ptr[ntext].key[0] = '\0'; + num_to_write--; + } + } + if (text_ptr[ntext].compression == + PNG_TEXT_COMPRESSION_zTXt) { + if (!keep_chunk("zTXt", argv)) { + text_ptr[ntext].key[0] = '\0'; + num_to_write--; + } + } #ifdef PNG_iTXt_SUPPORTED - added_text[0].lang = &text_lang[ntext*80]; - added_text[0].lang_key = &text_lang_key[ntext*80]; + if (text_ptr[ntext].compression == + PNG_ITXT_COMPRESSION_NONE + || text_ptr[ntext].compression == + PNG_ITXT_COMPRESSION_zTXt) { + if (!keep_chunk("iTXt", argv)) { + text_ptr[ntext].key[0] = '\0'; + num_to_write--; + } + } #endif - added_text[0].text = &text_text[ntext*2048]; - added_text[0].compression = text_compression[ntext]; - png_set_text(write_ptr, write_end_info_ptr, added_text, 1); - if(added_text[0].compression < 0) - printf(" Added a tEXt chunk.\n"); - else if(added_text[0].compression == 0) - printf(" Added a zTXt chunk.\n"); + } + if (num_to_write > 0) + png_set_text(write_ptr, + write_end_info_ptr, + text_ptr, num_text); + } + } + for (ntext = 0; ntext < text_inputs; ntext++) { + if (text_where[ntext] == 2) { + png_textp added_text; + added_text = (png_textp) + png_malloc(write_ptr, + (png_uint_32) + sizeof(png_text)); + added_text[0].key = + &text_keyword[ntext * 80]; #ifdef PNG_iTXt_SUPPORTED - else if(added_text[0].compression == 1) - printf(" Added an uncompressed iTXt chunk.\n"); - else - printf(" Added a compressed iTXt chunk.\n"); + added_text[0].lang = + &text_lang[ntext * 80]; + added_text[0].lang_key = + &text_lang_key[ntext * 80]; #endif - png_free(write_ptr,added_text); added_text=(png_textp)NULL; - } - } - } - } + added_text[0].text = + &text_text[ntext * 2048]; + added_text[0].compression = + text_compression[ntext]; + png_set_text(write_ptr, write_end_info_ptr, + added_text, 1); + if (added_text[0].compression < 0) + printf(" Added a tEXt chunk.\n"); + else if (added_text[0].compression == 0) + printf(" Added a zTXt chunk.\n"); +#ifdef PNG_iTXt_SUPPORTED + else if (added_text[0].compression == 1) + printf(" Added an uncompressed iTXt " + "chunk.\n"); + else + printf(" Added a compressed iTXt " + "chunk.\n"); #endif + png_free(write_ptr, added_text); + added_text = (png_textp) NULL; + } + } + } + } +#endif /* (PNG_READ_tEXt_SUPPORTED and PNG_WRITE_tEXt_SUPPORTED) or */ + /* (PNG_READ_zTXt_SUPPORTED and PNG_WRITE_zTXt_SUPPORTED) */ #if defined(PNG_READ_tIME_SUPPORTED) && defined(PNG_WRITE_tIME_SUPPORTED) - { - png_timep mod_time; + { + png_timep mod_time; - if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) - { - if(keep_chunk("tIME",argv)) - png_set_tIME(write_ptr, write_end_info_ptr, mod_time); - } - } + if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) { + if (keep_chunk("tIME", argv)) + png_set_tIME(write_ptr, write_end_info_ptr, + mod_time); + } + } #endif #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) - { - png_unknown_chunkp unknowns; - int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, - &unknowns); - if (num_unknowns && nosave == 0) - { - int i; - printf("setting %d unknown chunks after IDAT\n",num_unknowns); - png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, - num_unknowns); - for (i = 0; i < num_unknowns; i++) - png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, - i, (int)unknowns[i].location); - } - } + /* GRR FIXME? this block may need same fix as above */ + { + png_unknown_chunkp unknowns; + int num_unknowns = + (int) png_get_unknown_chunks(read_ptr, + read_info_ptr, + &unknowns); + if (num_unknowns && nosave == 0) { + int i; + printf("setting %d unknown chunks after IDAT\n", + num_unknowns); + png_set_unknown_chunks(write_ptr, + write_end_info_ptr, + unknowns, num_unknowns); + for (i = 0; i < num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, + write_end_info_ptr, + i, + (int) + unknowns[i]. + location); + } + } #endif -#endif /* PNG_LIBPNG_VER > 90 */ + } /* GRR: added for %-navigation (2) */ - if(nosave == 0) - { + if (nosave == 0) { #if 0 /* doesn't work; compression level has to be the same as in IDAT */ - /* if zTXt other compressed chunk */ - png_set_compression_level(write_ptr, 9); - png_set_compression_window_bits(write_ptr, 15); - png_set_compression_buffer_size(write_ptr, PNG_ZBUF_SIZE); - png_set_compression_strategy(write_ptr, 0); + /* if zTXt other compressed chunk */ + png_set_compression_level(write_ptr, 9); + png_set_compression_window_bits(write_ptr, 15); + png_set_compression_buffer_size(write_ptr, + PNG_ZBUF_SIZE); + png_set_compression_strategy(write_ptr, 0); #endif - png_write_end(write_ptr, write_end_info_ptr); - } + png_write_end(write_ptr, write_end_info_ptr); + } - png_debug(0, "Destroying data structs\n"); - if(row_buf != (png_bytep)NULL) - { - png_free(read_ptr, row_buf); row_buf = (png_bytep)NULL; - } + P1( "Destroying data structs\n"); + if (row_buf != (png_bytep) NULL) { + png_free(read_ptr, row_buf); + row_buf = (png_bytep) NULL; + } #ifdef PNGCRUSH_MULTIPLE_ROWS - if(row_pointers != (png_bytepp)NULL) - { - png_free(read_ptr, row_pointers); row_pointers = (png_bytepp)NULL; - } + if (row_pointers != (png_bytepp) NULL) { + png_free(read_ptr, row_pointers); + row_pointers = (png_bytepp) NULL; + } #endif - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); - if(nosave == 0) - { + png_destroy_read_struct(&read_ptr, &read_info_ptr, + &end_info_ptr); + if (nosave == 0) { #ifdef PNGCRUSH_LOCO - if(do_loco) - { - const png_byte png_MEND[5] = { 77, 69, 78, 68, '\0'}; - /* write the MNG MEND chunk */ - png_write_chunk(write_ptr, (png_bytep)png_MEND, NULL, (png_size_t)0); - } + if (do_loco) { + const png_byte png_MEND[5] = + { 77, 69, 78, 68, '\0' }; + /* write the MNG MEND chunk */ + png_write_chunk(write_ptr, (png_bytep) png_MEND, + NULL, (png_size_t) 0); + } #endif - png_destroy_info_struct(write_ptr, &write_end_info_ptr); - png_destroy_write_struct(&write_ptr, &write_info_ptr); - } - } - Catch (msg) - { - if(nosave == 0) - fprintf(stderr, "While converting %s to %s:\n", inname, outname); - else - fprintf(stderr, "While reading %s:\n", inname); - fprintf(stderr, " pngcrush caught libpng error:\n %s\n\n",msg); - if(row_buf) - { - png_free(read_ptr, row_buf); row_buf = (png_bytep)NULL; - } -#ifdef PNGCRUSH_MULTIPLE_ROWS - if(row_pointers != (png_bytepp)NULL) - { - png_free(read_ptr, row_pointers); row_pointers = (png_bytepp)NULL; - } -#endif - if(nosave == 0) - { - png_destroy_info_struct(write_ptr, &write_end_info_ptr); - png_destroy_write_struct(&write_ptr, &write_info_ptr); - FCLOSE(fpout); - setfiletype(outname); - } - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); - FCLOSE(fpin); - if(verbose > 1) - fprintf(stderr, "returning after cleanup\n"); - trial = MAX_METHODS+1; - } - - read_ptr=NULL; - write_ptr=NULL; - FCLOSE(fpin); - if(nosave == 0) - { - FCLOSE(fpout); - setfiletype(outname); - } - - if(nosave) - break; - - first_trial=0; - - if (nosave == 0) - { - png_debug(0, "Opening file for length measurement\n"); - if ((fpin = FOPEN(outname, "rb")) == NULL) - { - fprintf(STDERR, "Could not find file %s\n", outname); - if(png_row_filters != NULL) - { - free(png_row_filters); png_row_filters=NULL; + png_destroy_info_struct(write_ptr, + &write_end_info_ptr); + png_destroy_write_struct(&write_ptr, &write_info_ptr); + } + } + Catch(msg) { + if (nosave == 0) + fprintf(stderr, "While converting %s to %s:\n", inname, + outname); + else + fprintf(stderr, "While reading %s:\n", inname); + fprintf(stderr, + " pngcrush caught libpng error:\n %s\n\n", msg); + if (row_buf) { + png_free(read_ptr, row_buf); + row_buf = (png_bytep) NULL; + } +#ifdef PNGCRUSH_MULTIPLE_ROWS + if (row_pointers != (png_bytepp) NULL) { + png_free(read_ptr, row_pointers); + row_pointers = (png_bytepp) NULL; + } +#endif + if (nosave == 0) { + png_destroy_info_struct(write_ptr, + &write_end_info_ptr); + png_destroy_write_struct(&write_ptr, &write_info_ptr); + FCLOSE(fpout); + setfiletype(outname); + } + png_destroy_read_struct(&read_ptr, &read_info_ptr, + &end_info_ptr); + FCLOSE(fpin); + if (verbose > 1) + fprintf(stderr, "returning after cleanup\n"); + trial = MAX_METHODS + 1; } - exit(1); - } - number_of_open_files++; - idat_length[trial]=measure_idats(fpin); + read_ptr = NULL; + write_ptr = NULL; + FCLOSE(fpin); + if (nosave == 0) { + FCLOSE(fpout); + setfiletype(outname); + } - FCLOSE(fpin); - } + if (nosave) + break; - if(verbose > 0 && trial != MAX_METHODS) - { - fprintf(STDERR, - " IDAT length with method %3d (fm %d zl %d zs %d)= %8lu\n", - trial,filter_type,zlib_level,z_strategy,idat_length[trial]); - fflush(STDERR); - } + first_trial = 0; - } /* end of trial-loop */ + if (nosave == 0) { + P1( "Opening file for length measurement\n"); + if ((fpin = FOPEN(outname, "rb")) == NULL) { + fprintf(STDERR, "Could not find file %s\n", outname); + if (png_row_filters != NULL) { + free(png_row_filters); + png_row_filters = NULL; + } + exit(1); + } + number_of_open_files++; - if (fpin) - { - FCLOSE(fpin); - } - if (nosave == 0 && fpout) - { - FCLOSE(fpout); - setfiletype(outname); - } + idat_length[trial] = measure_idats(fpin); - if(verbose > 0 && nosave == 0) - { - png_uint_32 input_length, output_length; + FCLOSE(fpin); + } -#ifdef __riscos - input_length = (unsigned long)filesize(inname); - output_length = (unsigned long)filesize(outname); + if (verbose > 0 && trial != MAX_METHODS) { + fprintf(STDERR, + " IDAT length with method %3d (fm %d zl %d zs %d) = %8lu\n", + trial, filter_type, zlib_level, z_strategy, + idat_length[trial]); + fflush(STDERR); + } + + } /* end of trial-loop */ + P1("\n\nFINISHED MAIN LOOP OVER %d METHODS\n\n\n", MAX_METHODS); + + /* //////////////////////////////////////////////////////////////////// + ////////////////// //////////////////// + ////////////////// END OF MAIN LOOP OVER METHODS //////////////////// + ////////////////// //////////////////// + //////////////////////////////////////////////////////////////////// */ + + if (fpin) { + FCLOSE(fpin); + } + if (nosave == 0 && fpout) { + FCLOSE(fpout); + setfiletype(outname); + } + + if (verbose > 0 && nosave == 0) { + png_uint_32 input_length, output_length; +#ifndef __riscos + struct stat stat_buf; + struct utimbuf utim; + + stat(inname, &stat_buf); + input_length = (unsigned long) stat_buf.st_size; + utim.actime = stat_buf.st_atime; + utim.modtime = stat_buf.st_mtime; + stat(outname, &stat_buf); + output_length = (unsigned long) stat_buf.st_size; + utime(outname, &utim); /* set timestamp (no big deal if fails) */ #else - struct stat stat_buf; - - stat(inname, &stat_buf); - input_length = (unsigned long)stat_buf.st_size; - stat(outname, &stat_buf); - output_length = (unsigned long)stat_buf.st_size; + input_length = (unsigned long) filesize(inname); + output_length = (unsigned long) filesize(outname); #endif - total_input_length += input_length + output_length; - if(input_length == output_length) - fprintf(STDERR, - " Best pngcrush method = %d for %s (no change)\n\n", - best, outname); - else if(input_length > output_length) - fprintf(STDERR, - " Best pngcrush method = %d for %s (%4.2f%% reduction)\n\n", - best, outname, - (100.0 - (100.0*output_length)/input_length)); - else - fprintf(STDERR, - " Best pngcrush method = %d for %s (%4.2f%% increase)\n\n", - best, outname, - -(100.0 - (100.0*output_length)/input_length)); - if(verbose > 2) - fprintf(STDERR, " Number of open files=%d\n",number_of_open_files); + total_input_length += input_length + output_length; - } - if(pngcrush_mode == DEFAULT_MODE) - { - if(png_row_filters != NULL) - { - free(png_row_filters); png_row_filters=NULL; - } - if(verbose > 0) show_result(); + fprintf(STDERR, " Best pngcrush method = %d (fm %d zl %d zs %d) " + "for %s\n", best, fm[best], lv[best], zs[best], outname); + if (idat_length[0] == idat_length[best]) + fprintf(STDERR, " (no IDAT change)\n"); + else if (idat_length[0] > idat_length[best]) + fprintf(STDERR, " (%4.2f%% IDAT reduction)\n", + (100.0 - (100.0 * idat_length[best]) / idat_length[0])); + else + fprintf(STDERR, " (%4.2f%% IDAT increase)\n", + -(100.0 - (100.0 * idat_length[best]) / idat_length[0])); + if (input_length == output_length) + fprintf(STDERR, " (no filesize change)\n\n"); + else if (input_length > output_length) + fprintf(STDERR, " (%4.2f%% filesize reduction)\n\n", + (100.0 - (100.0 * output_length) / input_length)); + else + fprintf(STDERR, " (%4.2f%% filesize increase)\n\n", + -(100.0 - (100.0 * output_length) / input_length)); + + if (verbose > 2) + fprintf(STDERR, " Number of open files=%d\n", + number_of_open_files); + + } + + if (pngcrush_mode == DEFAULT_MODE) { + if (png_row_filters != NULL) { + free(png_row_filters); + png_row_filters = NULL; + } + if (verbose > 0) + show_result(); #ifdef PNG_iCCP_SUPPORTED - if(iccp_length) - free(iccp_text); + if (iccp_length) + free(iccp_text); #endif - if(pngcrush_must_exit) - exit(0); - return(0); - } - } /* end of loop on input files */ -} + if (pngcrush_must_exit) + exit(0); + return 0; + } + } /* end of loop on input files */ -png_uint_32 -measure_idats(FILE *fpin) + return 0; /* just in case */ + +} /* end of main() */ + + + + +png_uint_32 measure_idats(FILE * fpin) { - /* Copyright (C) 1999-2002 Glenn Randers-Pehrson (randeg@alum.rpi.edu) - See notice in pngcrush.c for conditions of use and distribution */ - P2("measure_idats:\n"); - png_debug(0, "Allocating read structure\n"); - Try - { - read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, - (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL); - png_debug(0, "Allocating read_info, end_info structures\n"); - read_info_ptr = png_create_info_struct(read_ptr); - end_info_ptr = png_create_info_struct(read_ptr); + /* Copyright (C) 1999-2002,2006 Glenn Randers-Pehrson (glennrp@users.sf.net) + See notice in pngcrush.c for conditions of use and distribution */ + P2("\nmeasure_idats:\n"); + P1( "Allocating read structure\n"); + Try { + read_ptr = + png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, + (png_error_ptr) png_cexcept_error, + (png_error_ptr) NULL); + P1( "Allocating read_info, end_info structures\n"); + read_info_ptr = png_create_info_struct(read_ptr); + end_info_ptr = png_create_info_struct(read_ptr); #if !defined(PNG_NO_STDIO) - png_init_io(read_ptr, fpin); + png_init_io(read_ptr, fpin); #else - png_set_read_fn(read_ptr, (png_voidp)fpin, (png_rw_ptr)NULL); + png_set_read_fn(read_ptr, (png_voidp) fpin, (png_rw_ptr) NULL); #endif - png_set_sig_bytes(read_ptr, 0); - measured_idat_length=png_measure_idat(read_ptr); - P2("measure_idats: IDAT length=%lu\n",measured_idat_length); - png_debug(0, "Destroying data structs\n"); - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); - } - Catch (msg) - { - fprintf(STDERR, "\nWhile reading %s ", inname); - fprintf(STDERR,"pngcrush caught libpng error:\n %s\n\n",msg); - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); - png_debug(0, "Destroyed data structs\n"); - measured_idat_length=0; - } - return measured_idat_length; + png_set_sig_bytes(read_ptr, 0); + measured_idat_length = png_measure_idat(read_ptr); + P2("measure_idats: IDAT length=%lu\n", measured_idat_length); + P1( "Destroying data structs\n"); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); + } + Catch(msg) { + fprintf(STDERR, "\nWhile reading %s ", inname); + fprintf(STDERR, "pngcrush caught libpng error:\n %s\n\n", msg); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); + P1( "Destroyed data structs\n"); + measured_idat_length = 0; + } + return measured_idat_length; } -png_uint_32 -png_measure_idat(png_structp png_ptr) + + + +png_uint_32 png_measure_idat(png_structp png_ptr) { - /* Copyright (C) 1999-2002 Glenn Randers-Pehrson (randeg@alum.rpi.edu) - See notice in pngcrush.c for conditions of use and distribution */ - png_uint_32 sum_idat_length=0; + /* Copyright (C) 1999-2002,2006 Glenn Randers-Pehrson (glennrp@users.sf.net) + See notice in pngcrush.c for conditions of use and distribution */ + png_uint_32 sum_idat_length = 0; - { - png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + { + png_byte png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; #if defined(PNGCRUSH_LOCO) - png_byte mng_signature[8] = {138, 77, 78, 71, 13, 10, 26, 10}; + png_byte mng_signature[8] = { 138, 77, 78, 71, 13, 10, 26, 10 }; #endif - png_read_data(png_ptr, png_signature, 8); - png_set_sig_bytes(png_ptr, 8); + png_default_read_data(png_ptr, png_signature, 8); + png_set_sig_bytes(png_ptr, 8); #if defined(PNGCRUSH_LOCO) - if (!(int)(png_memcmp(mng_signature, png_signature, 8))) - { - png_byte buffer[40]; - /* skip the MHDR */ - png_read_data(read_ptr, buffer, 40); - input_format=1; - } - else + if (!(int) (png_memcmp(mng_signature, png_signature, 8))) { + png_byte buffer[40]; + /* skip the MHDR */ + png_default_read_data(read_ptr, buffer, 40); + input_format = 1; + } else #endif - if (png_sig_cmp(png_signature, 0, 8)) - { - if (png_sig_cmp(png_signature, 0, 4)) - png_error(png_ptr, "Not a PNG file.."); - else - png_error(png_ptr, "PNG file corrupted by ASCII conversion"); - } - } + if (png_sig_cmp(png_signature, 0, 8)) { + if (png_sig_cmp(png_signature, 0, 4)) + png_error(png_ptr, "Not a PNG file.."); + else + png_error(png_ptr, + "PNG file corrupted by ASCII conversion"); + } + } #ifdef PNG_CRC_WARN_USE - if(fix) - png_set_crc_action(png_ptr, PNG_CRC_WARN_USE, PNG_CRC_WARN_USE); + if (fix) + png_set_crc_action(png_ptr, PNG_CRC_WARN_USE, PNG_CRC_WARN_USE); #endif - for(;;) - { + for (;;) { #ifndef PNG_UINT_IDAT #ifdef PNG_USE_LOCAL_ARRAYS - PNG_IDAT; - PNG_IEND; - PNG_IHDR; + PNG_IDAT; + PNG_IEND; + PNG_IHDR; #ifdef PNG_iCCP_SUPPORTED - PNG_iCCP; + PNG_iCCP; #else - const png_byte png_iCCP[5]={105, 67, 67, 80, '\0'}; + const png_byte png_iCCP[5] = { 105, 67, 67, 80, '\0' }; #endif #endif #endif - png_byte chunk_name[5]; - png_byte chunk_length[4]; - png_byte buffer[32]; - png_uint_32 length; + png_byte chunk_name[5]; + png_byte chunk_length[4]; + png_byte buffer[32]; + png_uint_32 length; - png_read_data(png_ptr, chunk_length, 4); - length = png_get_uint_32(chunk_length); + png_default_read_data(png_ptr, chunk_length, 4); + length = png_get_uint_31(png_ptr,chunk_length); - png_reset_crc(png_ptr); - png_crc_read(png_ptr, chunk_name, 4); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, chunk_name, 4); #ifdef PNG_UINT_IDAT - if (png_get_uint_32(chunk_name) == PNG_UINT_IDAT) + if (png_get_uint_32(chunk_name) == PNG_UINT_IDAT) #else - if (!png_memcmp(chunk_name, png_IDAT, 4)) + if (!png_memcmp(chunk_name, png_IDAT, 4)) #endif - { - sum_idat_length += length; - if(length > crushed_idat_size) - already_crushed++; - } + { + sum_idat_length += length; + if (length > crushed_idat_size) + already_crushed++; + } - if(verbose > 1) - { - chunk_name[4]='\0'; - printf( "Reading %s chunk, length = %ld.\n", chunk_name, length); - } - -#ifdef PNG_UINT_IDAT - if (png_get_uint_32(chunk_name) == PNG_UINT_IHDR) + if (verbose > 1) { + chunk_name[4] = '\0'; + printf("Reading %s chunk, length = %ld.\n", chunk_name, + length); + } +#ifdef PNG_UINT_IHDR + if (png_get_uint_32(chunk_name) == PNG_UINT_IHDR) #else - if (!png_memcmp(chunk_name, png_IHDR, 4)) + if (!png_memcmp(chunk_name, png_IHDR, 4)) #endif - { - /* get the color type */ - png_crc_read(png_ptr, buffer, 13); - length-=13; - input_color_type=buffer[9]; - } - + { + /* get the color type */ + png_crc_read(png_ptr, buffer, 13); + length -= 13; + input_color_type = buffer[9]; + } #ifdef PNG_iCCP_SUPPORTED - /* check for bad photoshop iccp chunk */ -#ifdef PNG_UINT_IDAT - if (png_get_uint_32(chunk_name) == PNG_UINT_iCCP) + /* check for bad Photoshop iCCP chunk */ +#ifdef PNG_UINT_iCCP + if (png_get_uint_32(chunk_name) == PNG_UINT_iCCP) #else - if (!png_memcmp(chunk_name, png_iCCP, 4)) + if (!png_memcmp(chunk_name, png_iCCP, 4)) #endif - { - /* Check for bad Photoshop iCCP chunk. Libpng will reject the - * bad chunk because the Adler-32 bytes are missing, but we check - * here to see if it's really the sRGB profile, and if so, set the - * "intent" flag and gamma so pngcrush will write an sRGB chunk - * and a gamma chunk. - */ - if (length == 2615) - { - png_crc_read(png_ptr, buffer, 22); - length-=22; - buffer[23]=0; - if(!strncmp((png_const_charp)buffer, "Photoshop ICC profile",21)) - { - printf( - " Replacing bad Photoshop ICCP chunk with an sRGB chunk\n"); + { + /* Check for bad Photoshop iCCP chunk. Libpng will reject the + * bad chunk because the Adler-32 bytes are missing, but we check + * here to see if it's really the sRGB profile, and if so, set the + * "intent" flag and gamma so pngcrush will write an sRGB chunk + * and a gamma chunk. + */ + if (length == 2615) { + png_crc_read(png_ptr, buffer, 22); + length -= 22; + buffer[23] = 0; + if (!strncmp((png_const_charp) buffer, "Photoshop ICC profile", + 21)) + { + printf(" Replacing bad Photoshop ICCP chunk with an " + "sRGB chunk\n"); #ifdef PNG_gAMA_SUPPORTED #ifdef PNG_FIXED_POINT_SUPPORTED - image_specified_gamma=45455L; + image_specified_gamma = 45455L; #else - image_specified_gamma=0.45455; + image_specified_gamma = 0.45455; #endif #endif - intent=0; - } - } - } + intent = 0; + } + } + } #endif - png_crc_finish(png_ptr, length); + png_crc_finish(png_ptr, length); #ifdef PNG_UINT_IEND - if (png_get_uint_32(chunk_name) == PNG_UINT_IEND) + if (png_get_uint_32(chunk_name) == PNG_UINT_IEND) #else - if (!png_memcmp(chunk_name, png_IEND, 4)) + if (!png_memcmp(chunk_name, png_IEND, 4)) #endif - return sum_idat_length; - } + return sum_idat_length; + } } + + + + #ifdef PNGCRUSH_COUNT_COLORS #define USE_HASHCODE -int -count_colors(FILE *fpin) +int count_colors(FILE * fpin) { - /* Copyright (C) 2000-2002 Glenn Randers-Pehrson (randeg@alum.rpi.edu) - See notice in pngcrush.c for conditions of use and distribution */ - int bit_depth, color_type, interlace_method, filter_method, compression_method; - png_uint_32 rowbytes; - volatile png_uint_32 channels; + /* Copyright (C) 2000-2002,2006 Glenn Randers-Pehrson (glennrp@users.sf.net) + See notice in pngcrush.c for conditions of use and distribution */ + int bit_depth, color_type, interlace_method, filter_method, + compression_method; + png_uint_32 rowbytes; + volatile png_uint_32 channels; - int i; - int pass, num_pass; - int ret; - volatile int result, hashmiss, hashinserts; + int i; + int pass, num_pass; + int ret; + volatile int result, hashmiss, hashinserts; - png_uint_32 rgba_frequency[257]; + png_uint_32 rgba_frequency[257]; - png_uint_32 rgba_hi[257]; /* Actually contains ARGB not RGBA */ + png_uint_32 rgba_hi[257]; /* Actually contains ARGB not RGBA */ #if 0 - png_uint_32 rgba_lo[257]; /* Low bytes of ARGB in 16-bit PNGs */ + png_uint_32 rgba_lo[257]; /* Low bytes of ARGB in 16-bit PNGs */ #endif - /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - /* start of interlace block */ - int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + /* start of interlace block */ + int png_pass_start[] = { 0, 4, 0, 2, 0, 1, 0 }; - /* offset to next interlace block */ - int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + /* offset to next interlace block */ + int png_pass_inc[] = { 8, 8, 4, 4, 2, 2, 1 }; - /* start of interlace block in the y direction */ - int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + /* start of interlace block in the y direction */ + int png_pass_ystart[] = { 0, 0, 4, 0, 2, 0, 1 }; - /* offset to next interlace block in the y direction */ - int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + /* offset to next interlace block in the y direction */ + int png_pass_yinc[] = { 8, 8, 8, 4, 4, 2, 2 }; - result=0; - reduce_to_gray=1; - it_is_opaque=1; - hashmiss=0; - hashinserts=0; - row_buf = (png_bytep)NULL; + result = 0; + reduce_to_gray = 1; + it_is_opaque = 1; + hashmiss = 0; + hashinserts = 0; + row_buf = (png_bytep) NULL; - num_rgba=0; - for (i=0; i<257; i++) - { - rgba_frequency[i]=0; - } + num_rgba = 0; + for (i = 0; i < 257; i++) { + rgba_frequency[i] = 0; + } - P2("Checking alphas:\n"); - png_debug(0, "Allocating read structure\n"); - Try - { - read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, - (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL); - if (read_ptr) - { - png_debug(0, "Allocating read_info structure\n"); - read_info_ptr = png_create_info_struct(read_ptr); - if (read_info_ptr == NULL) - png_destroy_read_struct(&read_ptr, (png_infopp)NULL, (png_infopp)NULL); - } - else - read_info_ptr = NULL; - if(read_info_ptr) - { + P2("Checking alphas:\n"); + P1( "Allocating read structure\n"); + Try { + read_ptr = + png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, + (png_error_ptr) png_cexcept_error, + (png_error_ptr) NULL); + if (read_ptr) { + P1( "Allocating read_info structure\n"); + read_info_ptr = png_create_info_struct(read_ptr); + if (read_info_ptr == NULL) + png_destroy_read_struct(&read_ptr, (png_infopp) NULL, + (png_infopp) NULL); + } else + read_info_ptr = NULL; + if (read_info_ptr) { #ifdef USE_HASHCODE - int hash[16385]; + int hash[16385]; #endif #ifdef USE_HASHCODE - for (i=0; i<16385; i++) - hash[i]=-1; + for (i = 0; i < 16385; i++) + hash[i] = -1; #endif - end_info_ptr = NULL; + end_info_ptr = NULL; #if !defined(PNG_NO_STDIO) - png_init_io(read_ptr, fpin); + png_init_io(read_ptr, fpin); #else - png_set_read_fn(read_ptr, (png_voidp)fpin, (png_rw_ptr)NULL); + png_set_read_fn(read_ptr, (png_voidp) fpin, (png_rw_ptr) NULL); #endif - { + { #if defined(PNGCRUSH_LOCO) - png_byte mng_signature[8] = {138, 77, 78, 71, 13, 10, 26, 10}; + png_byte mng_signature[8] = + { 138, 77, 78, 71, 13, 10, 26, 10 }; #endif - png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + png_byte png_signature[8] = + { 137, 80, 78, 71, 13, 10, 26, 10 }; - png_read_data(read_ptr, png_signature, 8); - png_set_sig_bytes(read_ptr, 8); + png_default_read_data(read_ptr, png_signature, 8); + png_set_sig_bytes(read_ptr, 8); #if defined(PNGCRUSH_LOCO) - if (!(int)(png_memcmp(mng_signature, png_signature, 8))) - { - png_byte buffer[40]; - /* skip the MHDR */ - png_read_data(read_ptr, buffer, 40); - png_permit_mng_features (read_ptr, PNG_FLAG_MNG_FILTER_64); - input_format=1; - } - else + if (!(int) (png_memcmp(mng_signature, png_signature, 8))) { + png_byte buffer[40]; + /* skip the MHDR */ + png_default_read_data(read_ptr, buffer, 40); + png_permit_mng_features(read_ptr, + PNG_FLAG_MNG_FILTER_64); + input_format = 1; + } else #endif - if (png_sig_cmp(png_signature, 0, 8)) - { - if (png_sig_cmp(png_signature, 0, 4)) - png_error(read_ptr, "Not a PNG file."); - else - png_error(read_ptr, "PNG file corrupted by ASCII conversion"); - } - } - png_read_info(read_ptr, read_info_ptr); + if (png_sig_cmp(png_signature, 0, 8)) { + if (png_sig_cmp(png_signature, 0, 4)) + png_error(read_ptr, "Not a PNG file."); + else + png_error(read_ptr, + "PNG file corrupted by ASCII conversion"); + } + } + png_read_info(read_ptr, read_info_ptr); #ifdef PNG_CRC_QUIET_USE - png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); + png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE, + PNG_CRC_QUIET_USE); #endif - png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, - &color_type, &interlace_method, &compression_method, &filter_method); + png_get_IHDR(read_ptr, read_info_ptr, &width, &height, + &bit_depth, &color_type, &interlace_method, + &compression_method, &filter_method); - if (color_type == 2) - channels = 3; - else if (color_type == 4) - channels = 2; - else if (color_type == 6) - channels = 4; - else - channels=1; + if (color_type == 2) + channels = 3; + else if (color_type == 4) + channels = 2; + else if (color_type == 6) + channels = 4; + else + channels = 1; - if(color_type == 0 || color_type == 3 || color_type == 4) - reduce_to_gray = 1; + if (color_type == 0 || color_type == 3 || color_type == 4) + reduce_to_gray = 1; - if(bit_depth == 8) - { - if(interlace_method) - num_pass=7; - else - num_pass = 1; + if (bit_depth == 8) { + if (interlace_method) + num_pass = 7; + else + num_pass = 1; - rowbytes = png_get_rowbytes(read_ptr, read_info_ptr); + rowbytes = png_get_rowbytes(read_ptr, read_info_ptr); - row_buf = png_malloc(read_ptr, rowbytes+16); + row_buf = png_malloc(read_ptr, rowbytes + 16); - for (pass = 0; pass < num_pass; pass++) - { - - png_byte *rp; - png_uint_32 pass_height, pass_width, y; - png_debug(0, "\nBegin Pass\n"); + for (pass = 0; pass < num_pass; pass++) { + png_byte *rp; + png_uint_32 pass_height, pass_width, y; + P2( "\nBegin count_colors() interlace pass %d\n", pass); - if (interlace_method) - { - pass_height = (height - png_pass_ystart[pass] - + png_pass_yinc[pass] - 1) / png_pass_yinc[pass]; - pass_width = (width - png_pass_start[pass] - + png_pass_inc[pass] - 1) / png_pass_inc[pass]; - } - else - { - pass_height=height; - pass_width=width; - } + if (interlace_method) { + pass_height = (height - png_pass_ystart[pass] + + png_pass_yinc[pass] - + 1) / png_pass_yinc[pass]; + pass_width = (width - png_pass_start[pass] + + png_pass_inc[pass] - + 1) / png_pass_inc[pass]; + } else { + pass_height = height; + pass_width = width; + } - for (y = 0; y < pass_height; y++) - { - png_uint_32 x; - png_read_row(read_ptr, row_buf, (png_bytep)NULL); - if(result < 2 || it_is_opaque || - reduce_to_gray) - { - if(color_type==2) - { - for (rp=row_buf, x = 0; x < pass_width; x++, rp+=channels) - { + for (y = 0; y < pass_height; y++) { + png_uint_32 x; + png_read_row(read_ptr, row_buf, (png_bytep) NULL); + if (result < 2 || it_is_opaque || reduce_to_gray) { + if (color_type == 2) { + for (rp = row_buf, x = 0; x < pass_width; + x++, rp += channels) { #ifdef USE_HASHCODE - int hashcode; + int hashcode; #endif - png_uint_32 rgba_high = (255<<24)|(*(rp)<<16)|(*(rp+1)<<8)| - *(rp+2); - assert(num_rgba < 258); - rgba_hi[num_rgba]=rgba_high; + png_uint_32 rgba_high = + (255 << 24) | (*(rp) << 16) | + (*(rp + 1) << 8) | *(rp + 2); + assert(num_rgba < 258); + rgba_hi[num_rgba] = rgba_high; - if(reduce_to_gray && - ((*(rp)) != (*(rp+1)) || (*(rp)) != (*(rp+2)))) - reduce_to_gray=0; + if (reduce_to_gray && + ((*(rp)) != (*(rp + 1)) + || (*(rp)) != (*(rp + 2)))) + reduce_to_gray = 0; - if (result > 1 || !it_is_opaque) - continue; + if (result > 1 || !it_is_opaque) + continue; #ifdef USE_HASHCODE - /* - * R G B mask - * 11,111 0,0000, 0000 0x3e00 - * 00,000 1,1111, 0000 0x01f0 - * 00,000 0,0000, 1111 0x000f - * - */ + /* + * R G B mask + * 11,111 0,0000, 0000 0x3e00 + * 00,000 1,1111, 0000 0x01f0 + * 00,000 0,0000, 1111 0x000f + * + */ - hashcode=(int)(((rgba_high>>10)&0x3e00)| - ((rgba_high>> 7)&0x01f0)| - ((rgba_high>> 4)&0x000f)); - assert(hashcode < 16385); - if (hash[hashcode] < 0) - { - hash[hashcode] = i = num_rgba; - if (i > 256) - result=2; - else - num_rgba++; - } - else - { - int start=hash[hashcode]; - for(i=start; i<=num_rgba; i++) - if(rgba_high == rgba_hi[i]) - break; - hashmiss += (i-start); - if(i == num_rgba) - { - int j; - if (i > 256) - result=2; - else - { - for(j=num_rgba; j>start+1; j--) - { - rgba_hi[j]=rgba_hi[j-1]; - rgba_frequency[j]=rgba_frequency[j-1]; - } - assert(start+1 < 258); - rgba_hi[start+1]=rgba_high; - rgba_frequency[start+1]=0; - for(j=0; j<16384; j++) - if(hash[j]>start) - hash[j]++; - i=start+1; - hashinserts++; - num_rgba++; - } - } - } + hashcode = + (int) (((rgba_high >> 10) & 0x3e00) + | ((rgba_high >> 7) & + 0x01f0) | ((rgba_high >> + 4) & + 0x000f)); + assert(hashcode < 16385); + if (hash[hashcode] < 0) { + hash[hashcode] = i = num_rgba; + if (i > 256) + result = 2; + else + num_rgba++; + } else { + int start = hash[hashcode]; + for (i = start; i <= num_rgba; i++) + if (rgba_high == rgba_hi[i]) + break; + hashmiss += (i - start); + if (i == num_rgba) { + int j; + if (i > 256) + result = 2; + else { + for (j = num_rgba; + j > start + 1; j--) { + rgba_hi[j] = + rgba_hi[j - 1]; + rgba_frequency[j] = + rgba_frequency[j - + 1]; + } + assert(start + 1 < 258); + rgba_hi[start + 1] = + rgba_high; + rgba_frequency[start + 1] = + 0; + for (j = 0; j < 16384; j++) + if (hash[j] > start) + hash[j]++; + i = start + 1; + hashinserts++; + num_rgba++; + } + } + } #else - for(i=0; i<=num_rgba; i++) - if(rgba_high == rgba_hi[i]) - break; - hashmiss += i; - if (i > 256) - result=2; - else if(i == num_rgba) - num_rgba++; + for (i = 0; i <= num_rgba; i++) + if (rgba_high == rgba_hi[i]) + break; + hashmiss += i; + if (i > 256) + result = 2; + else if (i == num_rgba) + num_rgba++; #endif - assert(i < 258); - ++rgba_frequency[i]; - } - } - else if(color_type==6) - { - for (rp=row_buf, x = 0; x < pass_width; x++, rp+=channels) - { + assert(i < 258); + ++rgba_frequency[i]; + } + } else if (color_type == 6) { + for (rp = row_buf, x = 0; x < pass_width; + x++, rp += channels) { #ifdef USE_HASHCODE - int hashcode; + int hashcode; #endif - png_uint_32 rgba_high = (*(rp+3)<<24)|(*(rp)<<16)| - (*(rp+1)<<8)|*(rp+2); - assert(rp-row_buf+3 < rowbytes); - rgba_hi[num_rgba]=rgba_high; - if(reduce_to_gray && - ((*(rp)) != (*(rp+1)) || (*(rp)) != (*(rp+2)))) - reduce_to_gray=0; - if(it_is_opaque && (*(rp+3)) != 255) - it_is_opaque=0; - if (result > 1) - continue; + png_uint_32 rgba_high = + (*(rp + 3) << 24) | (*(rp) << 16) | + (*(rp + 1) << 8) | *(rp + 2); + assert(rp - row_buf + 3 < rowbytes); + rgba_hi[num_rgba] = rgba_high; + if (reduce_to_gray && + ((*(rp)) != (*(rp + 1)) + || (*(rp)) != (*(rp + 2)))) + reduce_to_gray = 0; + if (it_is_opaque && (*(rp + 3)) != 255) + it_is_opaque = 0; + if (result > 1) + continue; #ifdef USE_HASHCODE - /* - * A R G B mask - * 11,1 000,0 000,0 000 0x3800 - * 00,0 111,1 000,0 000 0x0780 - * 00,0 000,0 111,1 000 0x0078 - * 00,0 000,0 000,0 111 0x0007 - * - */ + /* + * A R G B mask + * 11,1 000,0 000,0 000 0x3800 + * 00,0 111,1 000,0 000 0x0780 + * 00,0 000,0 111,1 000 0x0078 + * 00,0 000,0 000,0 111 0x0007 + * + */ - hashcode=(int)(((rgba_high>>18)&0x3800)| - ((rgba_high>>12)&0x0780)| - ((rgba_high>> 8)&0x0078)| - ((rgba_high>> 4)&0x0007)); - assert(hashcode < 16385); - if (hash[hashcode] < 0) - { - hash[hashcode] = i = num_rgba; - if (i > 256) - result=2; - else - num_rgba++; - } - else - { - int start=hash[hashcode]; - for(i=start; i<=num_rgba; i++) - if(rgba_high == rgba_hi[i]) - break; - hashmiss += (i-start); - if(i == num_rgba) - { - if (i > 256) - result=2; - else - { - int j; - for(j=num_rgba; j>start+1; j--) - { - rgba_hi[j]=rgba_hi[j-1]; - rgba_frequency[j]=rgba_frequency[j-1]; - } - rgba_hi[start+1]=rgba_high; - rgba_frequency[start+1]=0; - for(j=0; j<16384; j++) - if(hash[j]>start) - hash[j]++; - i=start+1; - hashinserts++; - num_rgba++; - } - } - } + hashcode = + (int) (((rgba_high >> 18) & 0x3800) + | ((rgba_high >> 12) & + 0x0780) | ((rgba_high >> + 8) & 0x0078) + | ((rgba_high >> 4) & + 0x0007)); + assert(hashcode < 16385); + if (hash[hashcode] < 0) { + hash[hashcode] = i = num_rgba; + if (i > 256) + result = 2; + else + num_rgba++; + } else { + int start = hash[hashcode]; + for (i = start; i <= num_rgba; i++) + if (rgba_high == rgba_hi[i]) + break; + hashmiss += (i - start); + if (i == num_rgba) { + if (i > 256) + result = 2; + else { + int j; + for (j = num_rgba; + j > start + 1; j--) { + rgba_hi[j] = + rgba_hi[j - 1]; + rgba_frequency[j] = + rgba_frequency[j - + 1]; + } + rgba_hi[start + 1] = + rgba_high; + rgba_frequency[start + 1] = + 0; + for (j = 0; j < 16384; j++) + if (hash[j] > start) + hash[j]++; + i = start + 1; + hashinserts++; + num_rgba++; + } + } + } #else - for(i=0; i<=num_rgba; i++) - if(rgba_high == rgba_hi[i]) - break; - hashmiss += i; - if (i > 256) - result=2; - else if(i == num_rgba) - num_rgba++; + for (i = 0; i <= num_rgba; i++) + if (rgba_high == rgba_hi[i]) + break; + hashmiss += i; + if (i > 256) + result = 2; + else if (i == num_rgba) + num_rgba++; #endif - ++rgba_frequency[i]; - } - } - else if(color_type==4) - { - for (rp=row_buf, x = 0; x < pass_width; x++, rp+=channels) - { + ++rgba_frequency[i]; + } + } else if (color_type == 4) { + for (rp = row_buf, x = 0; x < pass_width; + x++, rp += channels) { #ifdef USE_HASHCODE - int hashcode; + int hashcode; #endif - png_uint_32 rgba_high = (*(rp+1)<<24)|(*(rp)<<16)| - (*(rp)<<8)|(*rp); - assert(rp-row_buf+1 < rowbytes); - rgba_hi[num_rgba]=rgba_high; - if(it_is_opaque && (*(rp+1)) != 255) - it_is_opaque=0; + png_uint_32 rgba_high = + (*(rp + 1) << 24) | (*(rp) << 16) | + (*(rp) << 8) | (*rp); + assert(rp - row_buf + 1 < rowbytes); + rgba_hi[num_rgba] = rgba_high; + if (it_is_opaque && (*(rp + 1)) != 255) + it_is_opaque = 0; #ifdef USE_HASHCODE - /* - * A G mask - * 11,1111, 0000,0000 0x3f00 - * 00,0000, 1111,1111 0x00ff - * - */ + /* + * A G mask + * 11,1111, 0000,0000 0x3f00 + * 00,0000, 1111,1111 0x00ff + * + */ - hashcode=(int)(((rgba_high>>18)&0x3f00)| - ((rgba_high>> 4)&0x00ff)); - if (hash[hashcode] < 0) - { - hash[hashcode] = i = num_rgba; - if (i > 256) - result=2; - else - num_rgba++; - } - else - { - int start=hash[hashcode]; - for(i=start; i<=num_rgba; i++) - if(rgba_high == rgba_hi[i]) - break; - hashmiss += (i-start); - if(i == num_rgba) - { - if (i > 256) - result=2; - else - { - int j; - for(j=num_rgba; j>start+1; j--) - { - rgba_hi[j]=rgba_hi[j-1]; - rgba_frequency[j]=rgba_frequency[j-1]; - } - rgba_hi[start+1]=rgba_high; - rgba_frequency[start+1]=0; - for(j=0; j<16384; j++) - if(hash[j]>start) - hash[j]++; - i=start+1; - hashinserts++; - num_rgba++; - } - } - } + hashcode = + (int) (((rgba_high >> 18) & 0x3f00) + | ((rgba_high >> 4) & + 0x00ff)); + if (hash[hashcode] < 0) { + hash[hashcode] = i = num_rgba; + if (i > 256) + result = 2; + else + num_rgba++; + } else { + int start = hash[hashcode]; + for (i = start; i <= num_rgba; i++) + if (rgba_high == rgba_hi[i]) + break; + hashmiss += (i - start); + if (i == num_rgba) { + if (i > 256) + result = 2; + else { + int j; + for (j = num_rgba; + j > start + 1; j--) { + rgba_hi[j] = + rgba_hi[j - 1]; + rgba_frequency[j] = + rgba_frequency[j - + 1]; + } + rgba_hi[start + 1] = + rgba_high; + rgba_frequency[start + 1] = + 0; + for (j = 0; j < 16384; j++) + if (hash[j] > start) + hash[j]++; + i = start + 1; + hashinserts++; + num_rgba++; + } + } + } #else - for(i=0; i<=num_rgba; i++) - if(rgba_high == rgba_hi[i]) - break; - hashmiss += i; - if (i > 256) - result=2; - else if(i == num_rgba) - num_rgba++; + for (i = 0; i <= num_rgba; i++) + if (rgba_high == rgba_hi[i]) + break; + hashmiss += i; + if (i > 256) + result = 2; + else if (i == num_rgba) + num_rgba++; #endif - ++rgba_frequency[i]; + ++rgba_frequency[i]; + } + } else { /* other color type */ + + result = 2; + } + } + } + P2( "End count_colors() interlace pass %d\n\n", pass); } - } - else /* other color type */ - { - result=2; - } + + } else /* (bit_depth != 8) */ { + + /* TO DO: 16-bit support */ + reduce_to_gray = 0; + it_is_opaque = 0; + result = 0; } - } - png_debug(0, "\nEnd Pass\n"); - } - } - else - { - /* TO DO: 16-bit support */ - reduce_to_gray=0; - it_is_opaque=0; - result=0; - } - png_free (read_ptr, row_buf); row_buf = (png_bytep)NULL; - png_debug(0, "Destroying data structs\n"); - png_destroy_read_struct(&read_ptr, &read_info_ptr, (png_infopp)NULL); - } - else - result=2; - } - Catch (msg) - { - fprintf(STDERR, "\nWhile checking alphas in %s ", inname); - fprintf(STDERR,"pngcrush caught libpng error:\n %s\n\n",msg); - png_free (read_ptr, row_buf); row_buf = (png_bytep)NULL; - png_destroy_read_struct(&read_ptr, &read_info_ptr, (png_infopp)NULL); - png_debug(0, "Destroyed data structs\n"); - result=2; - } - if(verbose > 1) - { - int total=0; - if(num_rgba && num_rgba < 257) - { - for(i=0; i>16) & 0xff, - (int)(rgba_hi[i]>>8) & 0xff, - (int)(rgba_hi[i]) & 0xff, - (int)(rgba_hi[i]>>24) & 0xff, - (int)rgba_frequency[i]); - total+=rgba_frequency[i]; + png_free(read_ptr, row_buf); + row_buf = (png_bytep) NULL; + P1( "Destroying data structs\n"); + png_destroy_read_struct(&read_ptr, &read_info_ptr, + (png_infopp) NULL); + } else + result = 2; + } + Catch(msg) { + fprintf(STDERR, "\nWhile checking alphas in %s ", inname); + fprintf(STDERR, "pngcrush caught libpng error:\n %s\n\n", msg); + png_free(read_ptr, row_buf); + row_buf = (png_bytep) NULL; + png_destroy_read_struct(&read_ptr, &read_info_ptr, + (png_infopp) NULL); + P1( "Destroyed data structs\n"); + result = 2; + } + if (verbose > 1) { + int total = 0; + if (num_rgba && num_rgba < 257) { + for (i = 0; i < num_rgba; i++) { + printf("RGBA=(%3.3d,%3.3d,%3.3d,%3.3d), frequency=%d\n", + (int) (rgba_hi[i] >> 16) & 0xff, + (int) (rgba_hi[i] >> 8) & 0xff, + (int) (rgba_hi[i]) & 0xff, + (int) (rgba_hi[i] >> 24) & 0xff, + (int) rgba_frequency[i]); + total += rgba_frequency[i]; + } + P2("num_rgba=%d, total pixels=%d\n", num_rgba, total); + P2("hashcode misses=%d, inserts=%d\n", hashmiss, hashinserts); } - P2 ("num_rgba=%d, total pixels=%d\n",num_rgba, total); - P2 ("hashcode misses=%d, inserts=%d\n",hashmiss, - hashinserts); - } - if(color_type == 0 || color_type == 2) - it_is_opaque=0; - if(reduction_ok) - { - if(reduce_to_gray) - P1 ("The truecolor image is all gray and will be reduced.\n"); - if(it_is_opaque) - P1 ("The image is opaque and the alpha channel will be removed.\n"); - } - else - { - if(reduce_to_gray) - P1 ("The truecolor image is all gray and could be reduced.\n"); - if(it_is_opaque) - P1 ("The image is opaque and the alpha channel could be removed.\n"); - if (reduce_to_gray || it_is_opaque) - P1 ("Rerun pngcrush with the \"-reduce\" option to do so.\n"); - reduce_to_gray = 0; - it_is_opaque = 0; - - } - P2 ("Finished checking alphas, result=%d\n",result); - } - ret=result; - return (ret); + if (color_type == 0 || color_type == 2) + it_is_opaque = 0; + if (reduction_ok) { + if (reduce_to_gray) + P1("The truecolor image is all gray and will be reduced.\n"); + if (it_is_opaque) + P1("The image is opaque and the alpha channel will be " + "removed.\n"); + } else { + if (reduce_to_gray) + P1("The truecolor image is all gray and could be reduced.\n"); + if (it_is_opaque) + P1("The image is opaque and the alpha channel could be " + "removed.\n"); + if (reduce_to_gray || it_is_opaque) + P1("Rerun pngcrush with the \"-reduce\" option to do so.\n"); + reduce_to_gray = 0; + it_is_opaque = 0; + } + P2("Finished checking alphas, result=%d\n", result); + } + ret = result; + return (ret); } #endif /* PNGCRUSH_COUNT_COLORS */ -#endif /* PNG_LIBPNG_VER < 96 */ -#endif /* PNGCRUSH_LIBPNG_VER != PNG_LIBPNG_VER */ + + + + + +void print_version_info(void) +{ + fprintf(STDERR, + "\n" + " | pngcrush %s\n" + /* If you have modified this source, you may insert additional notices + * immediately after this sentence: */ + " | Copyright (C) 1998-2002,2006 Glenn Randers-Pehrson\n" + " | Copyright (C) 2005 Greg Roelofs\n" + " | This is a free, open-source program. Permission is irrevocably\n" + " | granted to everyone to use this version of pngcrush without\n" + " | payment of any fee.\n" + " | Executable name is %s\n" + " | It was built with libpng version %s, and is\n" + " | running with %s" + " | Copyright (C) 1998-2004,2006 Glenn Randers-Pehrson,\n" + " | Copyright (C) 1996, 1997 Andreas Dilger,\n" + " | Copyright (C) 1995, Guy Eric Schalnat, Group 42 Inc.,\n" + " | and zlib version %s, Copyright (C) 1998-2002 (or later),\n" + " | Jean-loup Gailly and Mark Adler.\n", + PNGCRUSH_VERSION, progname, PNG_LIBPNG_VER_STRING, + png_get_header_version(NULL), ZLIB_VERSION); + +#if defined(__GNUC__) + fprintf(STDERR, + " | It was compiled with gcc version %s", __VERSION__); +# if defined(PNG_USE_PNGGCCRD) + fprintf(STDERR, + " and gas version %s", GAS_VERSION); +# endif +# if defined(__DJGPP__) + fprintf(STDERR, + "\n" + " | under DJGPP %d.%d, Copyright (C) 1995, D. J. Delorie\n" + " | and loaded with PMODE/DJ, by Thomas Pytel and Matthias Grimrath\n" + " | Copyright (C) 1996, Matthias Grimrath.\n", + __DJGPP__, __DJGPP_MINOR__); +# else + fprintf(STDERR, ".\n"); +# endif +#endif + + fprintf(STDERR, "\n"); +} + + + + + +static const char *pngcrush_legal[] = { + "", + /* If you have modified this source, you may insert additional notices + * immediately after this sentence: */ + "Copyright (C) 1998-2002,2006 Glenn Randers-Pehrson (glennrp@users.sf.net)", + "Copyright (C) 2005 Greg Roelofs", + "", + "DISCLAIMER: The pngcrush computer program is supplied \"AS IS\".", + "The Author disclaims all warranties, expressed or implied, including,", + "without limitation, the warranties of merchantability and of fitness", + "for any purpose. The Author assumes no liability for direct, indirect,", + "incidental, special, exemplary, or consequential damages, which may", + "result from the use of the computer program, even if advised of the", + "possibility of such damage. There is no warranty against interference", + "with your enjoyment of the computer program or against infringement.", + "There is no warranty that my efforts or the computer program will", + "fulfill any of your particular purposes or needs. This computer", + "program is provided with all faults, and the entire risk of satisfactory", + "quality, performance, accuracy, and effort is with the user.", + "", + "LICENSE: Permission is hereby irrevocably granted to everyone to use,", + "copy, modify, and distribute this computer program, or portions hereof,", + "purpose, without payment of any fee, subject to the following", + "restrictions:", + "", + "1. The origin of this binary or source code must not be misrepresented.", + "", + "2. Altered versions must be plainly marked as such and must not be", + "misrepresented as being the original binary or source.", + "", + "3. The Copyright notice, disclaimer, and license may not be removed", + "or altered from any source, binary, or altered source distribution.", + "" +}; + +static const char *pngcrush_usage[] = { + "\nusage: %s [options] infile.png outfile.png\n", + " %s -e ext [other options] files.png ...\n", + " %s -d dir [other options] files.png ...\n" +}; + +struct options_help pngcrush_options[] = { + {0, " -already already_crushed_size [e.g., 8192]"}, + {2, ""}, /* blank */ + {2, " If file has an IDAT greater than this size, it"}, + {2, " will be considered to be already crushed and will"}, + {2, " not be processed, unless you are making other changes"}, + {2, " or the \"-force\" option is present."}, + {2, ""}, + + {0, " -bit_depth depth (bit_depth to use in output file)"}, + {2, ""}, + {2, " Default output depth is same as input depth."}, + {2, ""}, + +#ifdef Z_RLE + {0, " -brute (use brute-force: try 126 different methods [11-136])"}, +#else + {0, " -brute (use brute-force: try 114 different methods [11-124])"}, +#endif + {2, ""}, + {2, " Very time-consuming and generally not worthwhile."}, + {2, " You can restrict this option to certain filter types,"}, + {2, " compression levels, or strategies by following it"}, + {2, " with \"-f filter\", \"-l level\", or \"-z strategy\"."}, + {2, ""}, + + {0, " -c color_type of output file [0, 2, 4, or 6]"}, + {2, ""}, + {2, " Color type for the output file. Future versions"}, + {2, " will also allow color_type 3, if there are 256 or"}, + {2, " fewer colors present in the input file. Color types"}, + {2, " 4 and 6 are padded with an opaque alpha channel if"}, + {2, " the input file does not have alpha information."}, + {2, " You can use 0 or 4 to convert color to grayscale."}, + {2, " Use 0 or 2 to delete an unwanted alpha channel."}, + {2, " Default is to use same color type as the input file."}, + {2, ""}, + +#ifdef PNGCRUSH_COUNT_COLORS + {0, " -cc (do color counting)"}, + {2, ""}, +#endif + + {0, " -d directory_name (where output files will go)"}, + {2, ""}, + {2, " If a directory name is given, then the output"}, + {2, " files are placed in it, with the same filenames as"}, + {2, " those of the original files. For example,"}, + {2, " you would type 'pngcrush -directory CRUSHED *.png'"}, + {2, " to get *.png => CRUSHED/*.png"}, + {2, ""}, + + {0, FAKE_PAUSE_STRING}, + + {0, " -double_gamma (used for fixing gamma in PhotoShop 5.0/5.02 files)"}, + {2, ""}, + {2, " It has been claimed that the PS5 bug is actually"}, + {2, " more complex than that, in some unspecified way."}, + {2, ""}, + + {0, " -e extension (used for creating output filename)"}, + {2, ""}, + {2, " e.g., -ext .new means *.png => *.new"}, + {2, " and -e _C.png means *.png => *_C.png"}, + {2, ""}, + + {0, " -f user_filter [0-5]"}, + {2, ""}, + {2, " filter to use with the method specified in the"}, + {2, " preceding '-m method' or '-brute_force' argument."}, + {2, " 0: none; 1-4: use specified filter; 5: adaptive."}, + {2, ""}, + + {0, " -fix (fix otherwise fatal conditions such as bad CRCs)"}, + {2, ""}, + + {0, " -force (write a new output file even if larger than input)"}, + {2, ""}, + {2, " Otherwise the input file will be copied to output"}, + {2, " if it is smaller than any generated file and no chunk"}, + {2, " additions, removals, or changes were requested."}, + {2, ""}, + +#ifdef PNG_FIXED_POINT_SUPPORTED + {0, " -g gamma (float or fixed*100000, e.g., 0.45455 or 45455)"}, +#else + {0, " -g gamma (float, e.g., 0.45455)"}, +#endif + {2, ""}, + {2, " Value to insert in gAMA chunk, only if the input"}, + {2, " file has no gAMA chunk. To replace an existing"}, + {2, " gAMA chunk, use the '-replace_gamma' option."}, + {2, ""}, + + {0, FAKE_PAUSE_STRING}, + + {0, " -huffman (use only zlib strategy 2, Huffman-only)"}, + {2, ""}, + {2, " Fast, but almost never very effective except for"}, + {2, " certain rare image types."}, + {2, ""}, + +#ifdef PNG_iCCP_SUPPORTED + {0, " -iccp length \"Profile Name\" iccp_file"}, + {2, ""}, + {2, " file with ICC profile to insert in an iCCP chunk."}, + {2, ""}, +#endif + +#ifdef PNG_iTXt_SUPPORTED + {0, " -itxt b[efore_IDAT]|a[fter_IDAT] \"keyword\" \"text\""}, + {2, ""}, + {2, " Uncompressed iTXt chunk to insert (see -text)."}, + {2, ""}, +#endif + + {0, " -l zlib_compression_level [0-9]"}, + {2, ""}, + {2, " zlib compression level to use with method specified"}, + {2, " with the preceding '-m method' or '-brute_force'"}, + {2, " argument."}, + {2, ""}, + +#ifdef PNGCRUSH_LOCO + {0, " -loco (\"loco crush\" truecolor PNGs)"}, + {2, ""}, + {2, " Make the file more compressible by performing a"}, + {2, " lossless, reversible, color transformation."}, + {2, " The resulting file is a MNG, not a PNG, and should"}, + {2, " be given the \".mng\" file extension. The"}, + {2, " \"loco\" option has no effect on grayscale or"}, + {2, " indexed-color PNG files."}, + {2, ""}, +#endif + + {0, " -m method [0 through " STRNGIFY(MAX_METHODS) "]"}, + {2, ""}, + {2, " pngcrush method to try (0 means try all of 1-10)."}, + {2, " Can be repeated as in '-m 1 -m 4 -m 7'."}, + {2, " This can be useful if pngcrush runs out of memory"}, + {2, " when it tries methods 2, 3, 5, 6, 8, 9, or 10 which"}, + {2, " use filtering and are memory-intensive. Methods"}, + {2, " 1, 4, and 7 use no filtering; methods 11 and up use"}, + {2, " specified filter, compression level, and strategy."}, + {2, ""}, + {2, FAKE_PAUSE_STRING}, + + {0, " -max maximum_IDAT_size [default "STRNGIFY(PNG_ZBUF_SIZE)"]"}, + {2, ""}, + +#ifdef PNGCRUSH_COUNT_COLORS + {0, " -no_cc (no color counting)"}, + {2, ""}, +#endif + + {0, " -nofilecheck (do not check for infile.png == outfile.png)"}, + {2, ""}, + {2, " To avoid false hits from MSVC-compiled code. Note"}, + {2, " that if you use this option, you are responsible for"}, + {2, " ensuring that the input file is not the output file."}, + {2, ""}, + + {0, " -n (no save; does not do compression or write output PNG)"}, + {2, ""}, + {2, " Useful in conjunction with -v option to get info."}, + {2, ""}, + + + {0, " -plte_len n (truncate PLTE)"}, + {2, ""}, + {2, " Truncates the PLTE. Be sure not to truncate it to"}, + {2, " less than the greatest index present in IDAT."}, + {2, ""}, + + {0, " -q (quiet)"}, + {2, ""}, + + {0, " -reduce (do lossless color-type or bit-depth reduction)"}, + {2, ""}, + {2, " (if possible)"}, + {2, ""}, + + {0, " -rem chunkname (or \"alla\" or \"allb\")"}, + {2, ""}, + {2, " Name of an ancillary chunk or optional PLTE to be"}, + {2, " removed. Be careful with this. Please don't use "}, + {2, " this feature to remove transparency, gamma, copyright,"}, + {2, " or other valuable information. To remove several"}, + {2, " different chunks, repeat: -rem tEXt -rem pHYs."}, + {2, " Known chunks (those in the PNG 1.1 spec or extensions"}, + {2, " document) can be named with all lower-case letters,"}, + {2, " so \"-rem bkgd\" is equivalent to \"-rem bKGD\". But"}, + {2, " note: \"-rem text\" removes all forms of text chunks;"}, + {2, " Exact case is required to remove unknown chunks."}, + {2, " To do surgery with a chain-saw, \"-rem alla\" removes"}, + {2, " all known ancillary chunks except for tRNS, and"}, + {2, " \"-rem allb\" removes all but tRNS and gAMA."}, + {2, ""}, + + {0, FAKE_PAUSE_STRING}, + +#ifdef PNG_FIXED_POINT_SUPPORTED + {0, "-replace_gamma gamma (float or fixed*100000) even if gAMA is present."}, +#else + {0, "-replace_gamma gamma (float, e.g. 0.45455) even if gAMA is present."}, +#endif + {2, ""}, + + {0, " -res dpi"}, + {2, ""}, + {2, " Write a pHYs chunk with the given resolution."}, + {2, ""}, + +#ifdef Z_RLE + {0, " -rle (use only zlib strategy 3, RLE-only)"}, + {2, ""}, + {2, " A relatively fast subset of the \"-brute\" methods,"}, + {2, " generally more effective than \"-huffman\" on PNG images"}, + {2, " (and quite effective on black-and-white images),"}, + {2, " but not necessarily worth the bother otherwise."}, + {2, ""}, +#endif + + {0, " -save (keep all copy-unsafe chunks)"}, + {2, ""}, + {2, " Save otherwise unknown ancillary chunks that would"}, + {2, " be considered copy-unsafe. This option makes"}, + {2, " chunks 'known' to pngcrush, so they can be copied."}, + {2, ""}, + + {0, FAKE_PAUSE_STRING}, + + {0, " -srgb [0, 1, 2, or 3]"}, + {2, ""}, + {2, " Value of 'rendering intent' for sRGB chunk."}, + {2, ""}, + + {0, " -text b[efore_IDAT]|a[fter_IDAT] \"keyword\" \"text\""}, + {2, ""}, + {2, " tEXt chunk to insert. keyword < 80 chars,"}, + {2, " text < 2048 chars. For now, you can add no more than"}, + {2, " ten tEXt, iTXt, or zTXt chunks per pngcrush run."}, + {2, ""}, + +#ifdef PNG_tRNS_SUPPORTED + {0, " -trns_array n trns[0] trns[1] .. trns[n-1]"}, + {2, ""}, + {2, " Insert a tRNS chunk, if no tRNS chunk found in file."}, + {2, " Values are for the tRNS array in indexed-color PNG."}, + {2, ""}, + + {0, " -trns index red green blue gray"}, + {2, ""}, + {2, " Insert a tRNS chunk, if no tRNS chunk found in file."}, + {2, " You must give all five parameters regardless of the"}, + {2, " color type, scaled to the output bit depth."}, + {2, ""}, +#endif + + {0, " -v (display more detailed information)"}, + {2, ""}, + {2, " Repeat the option (use \"-v -v\") for even more."}, + {2, ""}, + + {0, " -version (display the pngcrush version)"}, + {2, ""}, + {2, " Look for the most recent version of pngcrush at"}, + {2, " http://pmt.sf.net"}, + {2, ""}, + + {0, " -w compression_window_size [32, 16, 8, 4, 2, 1, 512]"}, + {2, ""}, + {2, " Size of the sliding compression window, in kbytes"}, + {2, " (or bytes, in case of 512). It's best to"}, + {2, " use the default (32) unless you run out of memory."}, + {2, " The program will use a smaller window anyway when"}, + {2, " the uncompressed file is smaller than 16k."}, + {2, ""}, + +#ifdef Z_RLE + {0, " -z zlib_strategy [0, 1, 2, or 3]"}, +#else + {0, " -z zlib_strategy [0, 1, or 2]"}, +#endif + {2, ""}, + {2, " zlib compression strategy to use with the preceding"}, + {2, " '-m method' argument."}, + {2, ""}, + + {0, " -zmem zlib_compression_mem_level [1-9, default 9]"}, + {2, ""}, + +#ifdef PNG_iTXt_SUPPORTED + {0, " -zitxt b[efore_IDAT]|a[fter_IDAT] \"keyword\" \"text\""}, + {2, ""}, + {2, " Compressed iTXt chunk to insert (see -text)."}, + {2, ""}, +#endif + + {0, " -ztxt b[efore_IDAT]|a[fter_IDAT] \"keyword\" \"text\""}, + {2, ""}, + {2, " zTXt chunk to insert (see -text)."}, + {2, ""}, + {2, FAKE_PAUSE_STRING}, + + {0, " -h (help and legal notices)"}, + {2, ""}, + {2, " Display this information."}, + {2, ""}, + + {0, " -p (pause)"} +}; + + + + + +void print_usage(int retval) +{ + int j, jmax; + + if (verbose) { + jmax = sizeof(pngcrush_legal) / sizeof(char *); + for (j = 0; j < jmax; ++j) + fprintf(STDERR, "%s\n", pngcrush_legal[j]); + + jmax = sizeof(pngcrush_usage) / sizeof(char *); + for (j = 0; j < jmax; ++j) + fprintf(STDERR, pngcrush_usage[j], progname); /* special case */ + } + + /* this block is also handled specially due to the "else" clause... */ + if (verbose > 1) { + png_crush_pause(); + fprintf(STDERR, + "\n" + "options (Note: any option can be spelled out for clarity, e.g.,\n" + " \"pngcrush -dir New -method 7 -remove bkgd *.png\"\n" + " is the same as \"pngcrush -d New -m 7 -rem bkgd *.png\"):" + "\n\n"); + } else + fprintf(STDERR, "options:\n"); + + /* this is the main part of the help screen; it is more complex than the + * other blocks due to the mix of verbose and non-verbose lines */ + jmax = sizeof(pngcrush_options) / sizeof(struct options_help); + for (j = 0; j < jmax; ++j) { + if (verbose >= pngcrush_options[j].verbosity) { + if (pngcrush_options[j].textline[0] == FAKE_PAUSE_STRING[0]) + png_crush_pause(); + else + fprintf(STDERR, "%s\n", pngcrush_options[j].textline); + } + } + + /* due to progname, the verbose part of the -p option is handled explicitly + * (fortunately, it's the very last option anyway) */ + if (verbose > 1) { + fprintf(STDERR, "\n" + " Wait for [enter] key before continuing display.\n" + " e.g., type '%s -pause -help', if the help\n" + " screen scrolls out of sight.\n\n", progname); + } + + exit(retval); +} diff --git a/pngcrush.h b/pngcrush.h index 1c9f6af67..fa543e844 100644 --- a/pngcrush.h +++ b/pngcrush.h @@ -113,4 +113,152 @@ an error. */ #define PNG_ABORT() +/* GRR 20050220: added these, which apparently aren't defined anywhere else */ +#ifndef PNG_UINT_IHDR +# define PNG_UINT_IHDR (((png_uint_32) 73<<24) | \ + ((png_uint_32) 72<<16) | \ + ((png_uint_32) 68<< 8) | \ + ((png_uint_32) 82 )) #endif + +#ifndef PNG_UINT_IDAT +# define PNG_UINT_IDAT (((png_uint_32) 73<<24) | \ + ((png_uint_32) 68<<16) | \ + ((png_uint_32) 65<< 8) | \ + ((png_uint_32) 84 )) +#endif + +#ifndef PNG_UINT_IEND +# define PNG_UINT_IEND (((png_uint_32) 73<<24) | \ + ((png_uint_32) 69<<16) | \ + ((png_uint_32) 78<< 8) | \ + ((png_uint_32) 68 )) +#endif + +#ifndef PNG_UINT_PLTE +# define PNG_UINT_PLTE (((png_uint_32) 80<<24) | \ + ((png_uint_32) 76<<16) | \ + ((png_uint_32) 84<< 8) | \ + ((png_uint_32) 69 )) +#endif + +#ifndef PNG_UINT_bKGD +# define PNG_UINT_bKGD (((png_uint_32) 98<<24) | \ + ((png_uint_32) 75<<16) | \ + ((png_uint_32) 71<< 8) | \ + ((png_uint_32) 68 )) +#endif + +#ifndef PNG_UINT_cHRM +# define PNG_UINT_cHRM (((png_uint_32) 99<<24) | \ + ((png_uint_32) 72<<16) | \ + ((png_uint_32) 82<< 8) | \ + ((png_uint_32) 77 )) +#endif + +#ifndef PNG_UINT_gAMA +# define PNG_UINT_gAMA (((png_uint_32) 103<<24) | \ + ((png_uint_32) 65<<16) | \ + ((png_uint_32) 77<< 8) | \ + ((png_uint_32) 65 )) +#endif + +#ifndef PNG_UINT_hIST +# define PNG_UINT_hIST (((png_uint_32) 104<<24) | \ + ((png_uint_32) 73<<16) | \ + ((png_uint_32) 83<< 8) | \ + ((png_uint_32) 84 )) +#endif + +#ifndef PNG_UINT_iCCP +# define PNG_UINT_iCCP (((png_uint_32) 105<<24) | \ + ((png_uint_32) 67<<16) | \ + ((png_uint_32) 67<< 8) | \ + ((png_uint_32) 80 )) +#endif + +#ifndef PNG_UINT_iTXt +# define PNG_UINT_iTXt (((png_uint_32) 105<<24) | \ + ((png_uint_32) 84<<16) | \ + ((png_uint_32) 88<< 8) | \ + ((png_uint_32) 116 )) +#endif + +#ifndef PNG_UINT_oFFs +# define PNG_UINT_oFFs (((png_uint_32) 111<<24) | \ + ((png_uint_32) 70<<16) | \ + ((png_uint_32) 70<< 8) | \ + ((png_uint_32) 115 )) +#endif + +#ifndef PNG_UINT_pCAL +# define PNG_UINT_pCAL (((png_uint_32) 112<<24) | \ + ((png_uint_32) 67<<16) | \ + ((png_uint_32) 65<< 8) | \ + ((png_uint_32) 76 )) +#endif + +#ifndef PNG_UINT_sCAL +# define PNG_UINT_sCAL (((png_uint_32) 115<<24) | \ + ((png_uint_32) 67<<16) | \ + ((png_uint_32) 65<< 8) | \ + ((png_uint_32) 76 )) +#endif + +#ifndef PNG_UINT_pHYs +# define PNG_UINT_pHYs (((png_uint_32) 112<<24) | \ + ((png_uint_32) 72<<16) | \ + ((png_uint_32) 89<< 8) | \ + ((png_uint_32) 115 )) +#endif + +#ifndef PNG_UINT_sBIT +# define PNG_UINT_sBIT (((png_uint_32) 115<<24) | \ + ((png_uint_32) 66<<16) | \ + ((png_uint_32) 73<< 8) | \ + ((png_uint_32) 84 )) +#endif + +#ifndef PNG_UINT_sPLT +# define PNG_UINT_sPLT (((png_uint_32) 115<<24) | \ + ((png_uint_32) 80<<16) | \ + ((png_uint_32) 76<< 8) | \ + ((png_uint_32) 84 )) +#endif + +#ifndef PNG_UINT_sRGB +# define PNG_UINT_sRGB (((png_uint_32) 115<<24) | \ + ((png_uint_32) 82<<16) | \ + ((png_uint_32) 71<< 8) | \ + ((png_uint_32) 66 )) +#endif + +#ifndef PNG_UINT_tEXt +# define PNG_UINT_tEXt (((png_uint_32) 116<<24) | \ + ((png_uint_32) 69<<16) | \ + ((png_uint_32) 88<< 8) | \ + ((png_uint_32) 116 )) +#endif + +#ifndef PNG_UINT_tIME +# define PNG_UINT_tIME (((png_uint_32) 116<<24) | \ + ((png_uint_32) 73<<16) | \ + ((png_uint_32) 77<< 8) | \ + ((png_uint_32) 69 )) +#endif + +#ifndef PNG_UINT_tRNS +# define PNG_UINT_tRNS (((png_uint_32) 116<<24) | \ + ((png_uint_32) 82<<16) | \ + ((png_uint_32) 78<< 8) | \ + ((png_uint_32) 83 )) +#endif + +#ifndef PNG_UINT_zTXt +# define PNG_UINT_zTXt (((png_uint_32) 122<<24) | \ + ((png_uint_32) 84<<16) | \ + ((png_uint_32) 88<< 8) | \ + ((png_uint_32) 116 )) +#endif + +#endif /* !PNGCRUSH_H */ diff --git a/pngerror.c b/pngerror.c index e6c197357..6fa401237 100644 --- a/pngerror.c +++ b/pngerror.c @@ -1,9 +1,9 @@ /* pngerror.c - stub functions for i/o and memory allocation * - * libpng 1.2.4 - July 8, 2002 + * libpng version 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -35,9 +35,9 @@ png_error(png_structp png_ptr, png_const_charp error_message) char msg[16]; if (png_ptr->flags&(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) { - int offset = 0; if (*error_message == '#') { + int offset; for (offset=1; offset<15; offset++) if (*(error_message+offset) == ' ') break; @@ -63,11 +63,11 @@ png_error(png_structp png_ptr, png_const_charp error_message) } } #endif - if (png_ptr->error_fn != NULL) + if (png_ptr != NULL && png_ptr->error_fn != NULL) (*(png_ptr->error_fn))(png_ptr, error_message); - /* if the following returns or doesn't exist, use the default function, - which will not return */ + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ png_default_error(png_ptr, error_message); } @@ -79,7 +79,7 @@ png_error(png_structp png_ptr, png_const_charp error_message) void PNGAPI png_warning(png_structp png_ptr, png_const_charp warning_message) { - int offset = 0; + int offset = 0; #ifdef PNG_ERROR_NUMBERS_SUPPORTED if (png_ptr->flags&(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) #endif @@ -91,11 +91,10 @@ png_warning(png_structp png_ptr, png_const_charp warning_message) break; } } - if (png_ptr->warning_fn != NULL) - (*(png_ptr->warning_fn))(png_ptr, - (png_const_charp)(warning_message+offset)); + if (png_ptr != NULL && png_ptr->warning_fn != NULL) + (*(png_ptr->warning_fn))(png_ptr, warning_message+offset); else - png_default_warning(png_ptr, (png_const_charp)(warning_message+offset)); + png_default_warning(png_ptr, warning_message+offset); } /* These utilities are used internally to build an error message that relates @@ -104,10 +103,11 @@ png_warning(png_structp png_ptr, png_const_charp warning_message) * to 63 bytes, the name characters are output as hex digits wrapped in [] * if the character is invalid. */ -#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97)) +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) static PNG_CONST char png_digit[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', - 'F' }; + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; static void /* PRIVATE */ png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp @@ -137,7 +137,7 @@ png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp { buffer[iout++] = ':'; buffer[iout++] = ' '; - png_memcpy(buffer+iout, error_message, 64); + png_strncpy(buffer+iout, error_message, 63); buffer[iout+63] = 0; } } @@ -190,26 +190,28 @@ png_default_error(png_structp png_ptr, png_const_charp error_message) else #endif fprintf(stderr, "libpng error: %s\n", error_message); -#else - if (error_message) - /* make compiler happy */ ; #endif #ifdef PNG_SETJMP_SUPPORTED # ifdef USE_FAR_KEYWORD { jmp_buf jmpbuf; - png_memcpy(jmpbuf,png_ptr->jmpbuf,sizeof(jmp_buf)); + png_memcpy(jmpbuf,png_ptr->jmpbuf,png_sizeof(jmp_buf)); longjmp(jmpbuf, 1); } # else longjmp(png_ptr->jmpbuf, 1); # endif #else + /* make compiler happy */ ; if (png_ptr) - /* make compiler happy */ ; PNG_ABORT(); #endif +#ifdef PNG_NO_CONSOLE_IO + /* make compiler happy */ ; + if (&error_message != NULL) + return; +#endif } /* This function is called when there is a warning, but the library thinks @@ -245,9 +247,11 @@ png_default_warning(png_structp png_ptr, png_const_charp warning_message) # endif fprintf(stderr, "libpng warning: %s\n", warning_message); #else + /* make compiler happy */ ; if (warning_message) - /* appease compiler */ ; + return; #endif + /* make compiler happy */ ; if (png_ptr) return; } diff --git a/pnggccrd.c b/pnggccrd.c index 2d1d1d3b3..248e1b3bb 100644 --- a/pnggccrd.c +++ b/pnggccrd.c @@ -6,9 +6,9 @@ * and http://www.intel.com/drg/pentiumII/appnotes/923/923.htm * for Intel's performance analysis of the MMX vs. non-MMX code. * - * libpng version 1.2.4 - July 8, 2002 + * libpng version 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * Copyright (c) 1998, Intel Corporation * * Based on MSVC code contributed by Nirav Chhatrapati, Intel Corp., 1998. @@ -223,6 +223,10 @@ * 20020304: * - eliminated incorrect use of width_mmx in pixel_bytes == 8 case * + * 20040724: + * - more tinkering with clobber list at lines 4529 and 5033, to get + * it to compile on gcc-3.4. + * * STILL TO DO: * - test png_do_read_interlace() 64-bit case (pixel_bytes == 8) * - write MMX code for 48-bit case (pixel_bytes == 6) @@ -412,8 +416,10 @@ png_combine_row(png_structp png_ptr, png_bytep row, int mask) #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) if (_mmx_supported == 2) { +#if !defined(PNG_1_0_X) /* this should have happened in png_init_mmx_flags() already */ png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif png_mmx_support(); } #endif @@ -422,7 +428,7 @@ png_combine_row(png_structp png_ptr, png_bytep row, int mask) { png_debug(2,"mask == 0xff: doing single png_memcpy()\n"); png_memcpy(row, png_ptr->row_buf + 1, - (png_size_t)((png_ptr->width * png_ptr->row_info.pixel_depth + 7) >> 3)); + (png_size_t)PNG_ROWBYTES(png_ptr->row_info.pixel_depth,png_ptr->width)); } else /* (png_combine_row() is never called with mask == 0) */ { @@ -1767,8 +1773,8 @@ png_do_read_interlace(png_structp png_ptr) : "1" (sptr), // esi // input regs "2" (dp), // edi - "0" (width) // ecx -// doesn't work "i" (0x0000000000FFFFFFLL) // %1 (a.k.a. _const4) + "0" (width), // ecx + "rim" (_const4) // %1(?) (0x0000000000FFFFFFLL) #if 0 /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */ : "%mm0", "%mm1", "%mm2" // clobber list @@ -1811,7 +1817,8 @@ png_do_read_interlace(png_structp png_ptr) : "1" (sptr), // esi // input regs "2" (dp), // edi - "0" (width) // ecx + "0" (width), // ecx + "rim" (_const4) // (0x0000000000FFFFFFLL) #if 0 /* %mm0, ..., %mm2 not supported by gcc 2.7.2.3 or egcs 1.1 */ : "%mm0", "%mm1", "%mm2" // clobber list @@ -1865,7 +1872,9 @@ png_do_read_interlace(png_structp png_ptr) : "1" (sptr), // esi // input regs "2" (dp), // edi - "0" (width_mmx) // ecx + "0" (width_mmx), // ecx + "rim" (_const4), // 0x0000000000FFFFFFLL + "rim" (_const6) // 0x00000000000000FFLL #if 0 /* %mm0, ..., %mm3 not supported by gcc 2.7.2.3 or egcs 1.1 */ : "%mm0", "%mm1" // clobber list @@ -2727,8 +2736,8 @@ png_do_read_interlace(png_structp png_ptr) } /* end switch (row_info->pixel_depth) */ row_info->width = final_width; - row_info->rowbytes = ((final_width * - (png_uint_32)row_info->pixel_depth + 7) >> 3); + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width); } } /* end png_do_read_interlace() */ @@ -4529,8 +4538,7 @@ png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row) : "0" (bpp), // eax // input regs "1" (row) // edi - : "%ebx", "%ecx", "%edx" // clobber list - , "%esi" + : "%esi", "%ecx", "%edx" // clobber list #if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ , "%mm0", "%mm1", "%mm2", "%mm3" @@ -4990,7 +4998,7 @@ png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row, "jz up_end \n\t" "cmpl $8, %%edx \n\t" // test for less than 8 bytes - "jb up_lt8 \n\t" // [added by lcreeve@netins.net] + "jb up_lt8 \n\t" // [added by lcreeve at netins.net] "addl %%edx, %%ecx \n\t" "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8 @@ -5034,7 +5042,10 @@ png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row, "1" (prev_row), // esi "2" (row) // edi - : "%eax", "%ebx", "%ecx" // clobber list (no input regs!) + : "%eax", "%ecx" // clobber list (no input regs!) +#ifndef __PIC__ + , "%ebx" +#endif #if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ , "%mm0", "%mm1", "%mm2", "%mm3" @@ -5075,7 +5086,9 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep if (_mmx_supported == 2) { /* this should have happened in png_init_mmx_flags() already */ +#if !defined(PNG_1_0_X) png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif png_mmx_support(); } #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ @@ -5345,13 +5358,13 @@ png_mmx_support(void) "pushl %%ecx \n\t" // save original Eflag to stack "popfl \n\t" // restore original Eflag "xorl %%ecx, %%eax \n\t" // compare new Eflag with original Eflag - "jz .NOT_SUPPORTED \n\t" // if same, CPUID instr. is not supported + "jz 0f \n\t" // if same, CPUID instr. is not supported "xorl %%eax, %%eax \n\t" // set eax to zero // ".byte 0x0f, 0xa2 \n\t" // CPUID instruction (two-byte opcode) "cpuid \n\t" // get the CPU identification info "cmpl $1, %%eax \n\t" // make sure eax return non-zero value - "jl .NOT_SUPPORTED \n\t" // if eax is zero, MMX is not supported + "jl 0f \n\t" // if eax is zero, MMX is not supported "xorl %%eax, %%eax \n\t" // set eax to zero and... "incl %%eax \n\t" // ...increment eax to 1. This pair is @@ -5359,14 +5372,14 @@ png_mmx_support(void) "cpuid \n\t" // get the CPU identification info again "andl $0x800000, %%edx \n\t" // mask out all bits but MMX bit (23) "cmpl $0, %%edx \n\t" // 0 = MMX not supported - "jz .NOT_SUPPORTED \n\t" // non-zero = yes, MMX IS supported + "jz 0f \n\t" // non-zero = yes, MMX IS supported "movl $1, %%eax \n\t" // set return value to 1 - "jmp .RETURN \n\t" // DONE: have MMX support + "jmp 1f \n\t" // DONE: have MMX support - ".NOT_SUPPORTED: \n\t" // target label for jump instructions + "0: \n\t" // .NOT_SUPPORTED: target label for jump instructions "movl $0, %%eax \n\t" // set return value to 0 - ".RETURN: \n\t" // target label for jump instructions + "1: \n\t" // .RETURN: target label for jump instructions "movl %%eax, _mmx_supported \n\t" // save in global static variable, too "popl %%edx \n\t" // restore edx "popl %%ecx \n\t" // restore ecx diff --git a/pngget.c b/pngget.c index d3805a6e0..8eefa7779 100644 --- a/pngget.c +++ b/pngget.c @@ -1,9 +1,9 @@ /* pngget.c - retrieval of values from info struct * - * libpng 1.2.4 - July 8, 2002 + * libpng 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) */ @@ -540,9 +540,6 @@ png_get_IHDR(png_structp png_ptr, png_infop info_ptr, if (png_ptr != NULL && info_ptr != NULL && width != NULL && height != NULL && bit_depth != NULL && color_type != NULL) { - int pixel_depth, channels; - png_uint_32 rowbytes_per_pixel; - png_debug1(1, "in %s retrieval function\n", "IHDR"); *width = info_ptr->width; *height = info_ptr->height; @@ -560,23 +557,18 @@ png_get_IHDR(png_structp png_ptr, png_infop info_ptr, *interlace_type = info_ptr->interlace_type; /* check for potential overflow of rowbytes */ - if (*color_type == PNG_COLOR_TYPE_PALETTE) - channels = 1; - else if (*color_type & PNG_COLOR_MASK_COLOR) - channels = 3; - else - channels = 1; - if (*color_type & PNG_COLOR_MASK_ALPHA) - channels++; - pixel_depth = *bit_depth * channels; - rowbytes_per_pixel = (pixel_depth + 7) >> 3; - if (width == 0 || *width > PNG_MAX_UINT) + if (*width == 0 || *width > PNG_UINT_31_MAX) png_error(png_ptr, "Invalid image width"); - if (height == 0 || *height > PNG_MAX_UINT) + if (*height == 0 || *height > PNG_UINT_31_MAX) png_error(png_ptr, "Invalid image height"); - if (*width > PNG_MAX_UINT/rowbytes_per_pixel - 64) + if (info_ptr->width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 64 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ { - png_error(png_ptr, + png_warning(png_ptr, "Width too large for libpng to process image data."); } return (1); @@ -827,13 +819,13 @@ png_get_user_chunk_ptr(png_structp png_ptr) } #endif - +#ifdef PNG_WRITE_SUPPORTED png_uint_32 PNGAPI png_get_compression_buffer_size(png_structp png_ptr) { return (png_uint_32)(png_ptr? png_ptr->zbuf_size : 0L); } - +#endif #ifndef PNG_1_0_X #ifdef PNG_ASSEMBLER_CODE_SUPPORTED @@ -923,5 +915,20 @@ png_get_mmx_rowbytes_threshold (png_structp png_ptr) { return (png_uint_32)(png_ptr? png_ptr->mmx_rowbytes_threshold : 0L); } -#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ -#endif /* PNG_1_0_X */ +#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* these functions were added to libpng 1.2.6 */ +png_uint_32 PNGAPI +png_get_user_width_max (png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_width_max : 0); +} +png_uint_32 PNGAPI +png_get_user_height_max (png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_height_max : 0); +} +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + +#endif /* ?PNG_1_0_X */ diff --git a/pngmem.c b/pngmem.c index feb8a5dfc..f1cb69395 100644 --- a/pngmem.c +++ b/pngmem.c @@ -1,9 +1,9 @@ /* pngmem.c - stub functions for memory allocation * - * libpng 1.2.4 - July 8, 2002 + * libpng version 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -39,11 +39,11 @@ png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) png_voidp struct_ptr; if (type == PNG_STRUCT_INFO) - size = sizeof(png_info); + size = png_sizeof(png_info); else if (type == PNG_STRUCT_PNG) - size = sizeof(png_struct); + size = png_sizeof(png_struct); else - return (png_get_copyright()); + return (png_get_copyright(NULL)); #ifdef PNG_USER_MEM_SUPPORTED if(malloc_fn != NULL) @@ -55,7 +55,7 @@ png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) } else #endif /* PNG_USER_MEM_SUPPORTED */ - struct_ptr = (png_voidp)farmalloc(size)); + struct_ptr = (png_voidp)farmalloc(size); if (struct_ptr != NULL) png_memset(struct_ptr, 0, size); return (struct_ptr); @@ -121,14 +121,12 @@ png_malloc(png_structp png_ptr, png_uint_32 size) #ifdef PNG_USER_MEM_SUPPORTED if(png_ptr->malloc_fn != NULL) - { ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of memory!"); - return (ret); - } else - return png_malloc_default(png_ptr, size); + ret = (png_malloc_default(png_ptr, size)); + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of memory!"); + return (ret); } png_voidp PNGAPI @@ -139,10 +137,16 @@ png_malloc_default(png_structp png_ptr, png_uint_32 size) #ifdef PNG_MAX_MALLOC_64K if (size > (png_uint_32)65536L) - png_error(png_ptr, "Cannot Allocate > 64K"); + { + png_warning(png_ptr, "Cannot Allocate > 64K"); + ret = NULL; + } + else #endif - if (size == (png_uint_32)65536L) + if (size != (size_t)size) + ret = NULL; + else if (size == (png_uint_32)65536L) { if (png_ptr->offset_table == NULL) { @@ -177,34 +181,40 @@ png_malloc_default(png_structp png_ptr, png_uint_32 size) if (table == NULL) { - if (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) png_error(png_ptr, "Out Of Memory."); /* Note "O" and "M" */ else png_warning(png_ptr, "Out Of Memory."); +#endif return (NULL); } if ((png_size_t)table & 0xfff0) { - if (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) png_error(png_ptr, "Farmalloc didn't return normalized pointer"); else png_warning(png_ptr, "Farmalloc didn't return normalized pointer"); +#endif return (NULL); } png_ptr->offset_table = table; png_ptr->offset_table_ptr = farmalloc(num_blocks * - sizeof (png_bytep)); + png_sizeof (png_bytep)); if (png_ptr->offset_table_ptr == NULL) { - if (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) png_error(png_ptr, "Out Of memory."); /* Note "O" and "M" */ else png_warning(png_ptr, "Out Of memory."); +#endif return (NULL); } @@ -228,10 +238,12 @@ png_malloc_default(png_structp png_ptr, png_uint_32 size) if (png_ptr->offset_table_count >= png_ptr->offset_table_number) { - if (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) +#ifndef PNG_USER_MEM_SUPPORTED + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) png_error(png_ptr, "Out of Memory."); /* Note "o" and "M" */ else png_warning(png_ptr, "Out of Memory."); +#endif return (NULL); } @@ -240,13 +252,15 @@ png_malloc_default(png_structp png_ptr, png_uint_32 size) else ret = farmalloc(size); +#ifndef PNG_USER_MEM_SUPPORTED if (ret == NULL) { - if (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */ else png_warning(png_ptr, "Out of memory."); /* Note "o" and "m" */ } +#endif return (ret); } @@ -325,9 +339,9 @@ png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) png_voidp struct_ptr; if (type == PNG_STRUCT_INFO) - size = sizeof(png_info); + size = png_sizeof(png_info); else if (type == PNG_STRUCT_PNG) - size = sizeof(png_struct); + size = png_sizeof(png_struct); else return (NULL); @@ -345,17 +359,16 @@ png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) #endif /* PNG_USER_MEM_SUPPORTED */ #if defined(__TURBOC__) && !defined(__FLAT__) - if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL) + struct_ptr = (png_voidp)farmalloc(size); #else # if defined(_MSC_VER) && defined(MAXSEG_64K) - if ((struct_ptr = (png_voidp)halloc(size,1)) != NULL) + struct_ptr = (png_voidp)halloc(size,1); # else - if ((struct_ptr = (png_voidp)malloc(size)) != NULL) + struct_ptr = (png_voidp)malloc(size); # endif #endif - { + if (struct_ptr != NULL) png_memset(struct_ptr, 0, size); - } return (struct_ptr); } @@ -410,19 +423,17 @@ png_malloc(png_structp png_ptr, png_uint_32 size) { png_voidp ret; +#ifdef PNG_USER_MEM_SUPPORTED if (png_ptr == NULL || size == 0) return (NULL); -#ifdef PNG_USER_MEM_SUPPORTED if(png_ptr->malloc_fn != NULL) - { ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory!"); - return (ret); - } else - return (png_malloc_default(png_ptr, size)); + ret = (png_malloc_default(png_ptr, size)); + if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) + png_error(png_ptr, "Out of Memory!"); + return (ret); } png_voidp PNGAPI @@ -431,28 +442,45 @@ png_malloc_default(png_structp png_ptr, png_uint_32 size) png_voidp ret; #endif /* PNG_USER_MEM_SUPPORTED */ + if (png_ptr == NULL || size == 0) + return (NULL); + #ifdef PNG_MAX_MALLOC_64K if (size > (png_uint_32)65536L) { +#ifndef PNG_USER_MEM_SUPPORTED if(png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) png_error(png_ptr, "Cannot Allocate > 64K"); else +#endif return NULL; } #endif + /* Check for overflow */ #if defined(__TURBOC__) && !defined(__FLAT__) + if (size != (unsigned long)size) + ret = NULL; + else ret = farmalloc(size); #else # if defined(_MSC_VER) && defined(MAXSEG_64K) + if (size != (unsigned long)size) + ret = NULL; + else ret = halloc(size, 1); # else + if (size != (size_t)size) + ret = NULL; + else ret = malloc((size_t)size); # endif #endif +#ifndef PNG_USER_MEM_SUPPORTED if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) png_error(png_ptr, "Out of Memory"); +#endif return (ret); } @@ -498,8 +526,9 @@ png_free_default(png_structp png_ptr, png_voidp ptr) # define png_malloc_warn png_malloc #else /* This function was added at libpng version 1.2.3. The png_malloc_warn() - * function will issue a png_warning and return NULL instead of issuing a - * png_error, if it fails to allocate the requested memory. + * function will set up png_malloc() to issue a png_warning and return NULL + * instead of issuing a png_error, if it fails to allocate the requested + * memory. */ png_voidp PNGAPI png_malloc_warn(png_structp png_ptr, png_uint_32 size) diff --git a/pngpread.c b/pngpread.c index 9a5b54dfb..8c35faae4 100644 --- a/pngpread.c +++ b/pngpread.c @@ -1,9 +1,9 @@ /* pngpread.c - read a png file in push mode * - * libpng 1.2.4 - July 8, 2002 + * libpng version 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) */ @@ -208,7 +208,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) } png_push_fill_buffer(png_ptr, chunk_length, 4); - png_ptr->push_length = png_get_uint_32(chunk_length); + png_ptr->push_length = png_get_uint_31(png_ptr,chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, png_ptr->chunk_name, 4); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; @@ -223,6 +223,41 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) } png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); } + else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); + + png_ptr->process_mode = PNG_READ_DONE_MODE; + png_push_have_end(png_ptr, info_ptr); + } +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_ptr->mode |= PNG_HAVE_IDAT; + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + } + } +#endif else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) @@ -261,18 +296,6 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) png_ptr->zstream.next_out = png_ptr->row_buf; return; } - else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); - - png_ptr->process_mode = PNG_READ_DONE_MODE; - png_push_have_end(png_ptr, info_ptr); - } #if defined(PNG_READ_gAMA_SUPPORTED) else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) { @@ -591,6 +614,11 @@ png_push_save_buffer(png_structp png_ptr) png_size_t new_max; png_bytep old_buffer; + if (png_ptr->save_buffer_size > PNG_SIZE_MAX - + (png_ptr->current_buffer_size + 256)) + { + png_error(png_ptr, "Potential overflow of save_buffer"); + } new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; old_buffer = png_ptr->save_buffer; png_ptr->save_buffer = (png_bytep)png_malloc(png_ptr, @@ -637,8 +665,7 @@ png_push_read_IDAT(png_structp png_ptr) } png_push_fill_buffer(png_ptr, chunk_length, 4); - png_ptr->push_length = png_get_uint_32(chunk_length); - + png_ptr->push_length = png_get_uint_31(png_ptr,chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, png_ptr->chunk_name, 4); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; @@ -668,8 +695,8 @@ png_push_read_IDAT(png_structp png_ptr) save_size = png_ptr->save_buffer_size; png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); - png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); - + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); png_ptr->idat_size -= save_size; png_ptr->buffer_size -= save_size; png_ptr->save_buffer_size -= save_size; @@ -690,7 +717,8 @@ png_push_read_IDAT(png_structp png_ptr) save_size = png_ptr->current_buffer_size; png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); - png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); png_ptr->idat_size -= save_size; png_ptr->buffer_size -= save_size; @@ -707,6 +735,7 @@ png_push_read_IDAT(png_structp png_ptr) png_crc_finish(png_ptr, 0); png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; + png_ptr->mode |= PNG_AFTER_IDAT; } } @@ -751,8 +780,13 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, png_ptr->interlaced && png_ptr->pass > 6) || (!png_ptr->interlaced && #endif - png_ptr->row_number == png_ptr->num_rows-1)) - png_error(png_ptr, "Too much data in IDAT chunks"); + png_ptr->row_number == png_ptr->num_rows)) + { + if (png_ptr->zstream.avail_in) + png_warning(png_ptr, "Too much data in IDAT chunks"); + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } png_push_process_row(png_ptr); png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; png_ptr->zstream.next_out = png_ptr->row_buf; @@ -771,8 +805,8 @@ png_push_process_row(png_structp png_ptr) png_ptr->row_info.bit_depth = png_ptr->bit_depth; png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; - png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * - (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); png_read_filter_row(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr->prev_row + 1, @@ -781,7 +815,7 @@ png_push_process_row(png_structp png_ptr) png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1); - if (png_ptr->transformations) + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) png_do_read_transformations(png_ptr); #if defined(PNG_READ_INTERLACING_SUPPORTED) @@ -987,6 +1021,8 @@ png_read_push_finish_row(png_structp png_ptr) (png_ptr->pass == 5 && png_ptr->width < 2)) png_ptr->pass++; + if (png_ptr->pass > 7) + png_ptr->pass--; if (png_ptr->pass >= 7) break; @@ -995,8 +1031,8 @@ png_read_push_finish_row(png_structp png_ptr) png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; - png_ptr->irowbytes = ((png_ptr->iwidth * - png_ptr->pixel_depth + 7) >> 3) + 1; + png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; if (png_ptr->transformations & PNG_INTERLACE) break; @@ -1085,7 +1121,8 @@ png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr) if (text != key + png_ptr->current_text_size) text++; - text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr = (png_textp)png_malloc(png_ptr, + (png_uint_32)png_sizeof(png_text)); text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; text_ptr->key = key; #ifdef PNG_iTXt_SUPPORTED @@ -1278,7 +1315,8 @@ png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr) key = text; text += key_size; - text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr = (png_textp)png_malloc(png_ptr, + (png_uint_32)png_sizeof(png_text)); text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt; text_ptr->key = key; #ifdef PNG_iTXt_SUPPORTED @@ -1390,7 +1428,8 @@ png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr) if (text != key + png_ptr->current_text_size) text++; - text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr = (png_textp)png_malloc(png_ptr, + (png_uint_32)png_sizeof(png_text)); text_ptr->compression = comp_flag + 2; text_ptr->key = key; text_ptr->lang = lang; @@ -1425,7 +1464,7 @@ png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 { #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - HANDLE_CHUNK_ALWAYS + PNG_HANDLE_CHUNK_ALWAYS #if defined(PNG_READ_USER_CHUNKS_SUPPORTED) && png_ptr->read_user_chunk_fn == NULL #endif @@ -1464,7 +1503,7 @@ png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 { if (!(png_ptr->chunk_name[0] & 0x20)) if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - HANDLE_CHUNK_ALWAYS) + PNG_HANDLE_CHUNK_ALWAYS) png_chunk_error(png_ptr, "unknown critical chunk"); } png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); diff --git a/pngread.c b/pngread.c index 24ddeb5c7..5924333df 100644 --- a/pngread.c +++ b/pngread.c @@ -1,9 +1,9 @@ /* pngread.c - read a PNG file * - * libpng 1.2.4 - July 8, 2002 + * libpng 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -59,6 +59,12 @@ png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, #endif #endif /* PNG_1_0_X */ + /* added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max=PNG_USER_WIDTH_MAX; + png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; +#endif + #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) @@ -77,7 +83,7 @@ png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, return (NULL); } #ifdef USE_FAR_KEYWORD - png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf)); + png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf)); #endif #endif @@ -154,7 +160,7 @@ png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) PNG_ABORT(); - png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf)); + png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf)); #else if (setjmp(png_ptr->jmpbuf)) PNG_ABORT(); @@ -166,6 +172,7 @@ png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, /* Initialize PNG structure for reading, and allocate any memory needed. This interface is deprecated in favour of the png_create_read_struct(), and it will eventually disappear. */ +#if defined(PNG_1_0_X) || defined (PNG_1_2_X) #undef png_read_init void PNGAPI png_read_init(png_structp png_ptr) @@ -173,6 +180,7 @@ png_read_init(png_structp png_ptr) /* We only come here via pre-1.0.7-compiled applications */ png_read_init_2(png_ptr, "1.0.6 or earlier", 0, 0); } +#endif void PNGAPI png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver, @@ -180,7 +188,8 @@ png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver, { /* We only come here via pre-1.0.12-compiled applications */ #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) - if(sizeof(png_struct) > png_struct_size || sizeof(png_info) > png_info_size) + if(png_sizeof(png_struct) > png_struct_size || + png_sizeof(png_info) > png_info_size) { char msg[80]; png_ptr->warning_fn=NULL; @@ -195,7 +204,7 @@ png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver, png_warning(png_ptr, msg); } #endif - if(sizeof(png_struct) > png_struct_size) + if(png_sizeof(png_struct) > png_struct_size) { png_ptr->error_fn=NULL; #ifdef PNG_ERROR_NUMBERS_SUPPORTED @@ -204,7 +213,7 @@ png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver, png_error(png_ptr, "The png struct allocated by the application for reading is too small."); } - if(sizeof(png_info) > png_info_size) + if(png_sizeof(png_info) > png_info_size) { png_ptr->error_fn=NULL; #ifdef PNG_ERROR_NUMBERS_SUPPORTED @@ -247,10 +256,10 @@ png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, #ifdef PNG_SETJMP_SUPPORTED /* save jump buffer and error functions */ - png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf)); #endif - if(sizeof(png_struct) > png_struct_size) + if(png_sizeof(png_struct) > png_struct_size) { png_destroy_struct(png_ptr); *ptr_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); @@ -258,11 +267,17 @@ png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, } /* reset all variables to 0 */ - png_memset(png_ptr, 0, sizeof (png_struct)); + png_memset(png_ptr, 0, png_sizeof (png_struct)); #ifdef PNG_SETJMP_SUPPORTED /* restore jump buffer */ - png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf)); +#endif + + /* added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max=PNG_USER_WIDTH_MAX; + png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; #endif /* initialize zbuf - compression buffer */ @@ -288,6 +303,7 @@ png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); } +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED /* Read the information before the actual image data. This has been * changed in v0.90 to allow reading a file that already has the magic * bytes read from the stream. You can tell libpng how many bytes have @@ -379,12 +395,12 @@ png_read_info(png_structp png_ptr, png_infop info_ptr) #if defined(PNG_READ_zTXt_SUPPORTED) PNG_zTXt; #endif -#endif /* PNG_GLOBAL_ARRAYS */ +#endif /* PNG_USE_LOCAL_ARRAYS */ png_byte chunk_length[4]; png_uint_32 length; png_read_data(png_ptr, chunk_length, 4); - length = png_get_uint_32(chunk_length); + length = png_get_uint_31(png_ptr,chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, png_ptr->chunk_name, 4); @@ -392,9 +408,6 @@ png_read_info(png_structp png_ptr, png_infop info_ptr) png_debug2(0, "Reading %s chunk, length=%lu.\n", png_ptr->chunk_name, length); - if (length > PNG_MAX_UINT) - png_error(png_ptr, "Invalid chunk length."); - /* This should be a binary subdivision search or a hash for * matching the chunk name rather than a linear search. */ @@ -507,6 +520,7 @@ png_read_info(png_structp png_ptr, png_infop info_ptr) png_handle_unknown(png_ptr, info_ptr, length); } } +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ /* optional call to update the users info_ptr structure */ void PNGAPI @@ -521,6 +535,7 @@ png_read_update_info(png_structp png_ptr, png_infop info_ptr) png_read_transform_info(png_ptr, info_ptr); } +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED /* Initialize palette, background, etc, after transformations * are set, but before any reading takes place. This allows * the user to obtain a gamma-corrected palette, for example. @@ -533,7 +548,9 @@ png_start_read_image(png_structp png_ptr) if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) png_read_start_row(png_ptr); } +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED void PNGAPI png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) { @@ -673,10 +690,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) png_crc_finish(png_ptr, 0); png_read_data(png_ptr, chunk_length, 4); - png_ptr->idat_size = png_get_uint_32(chunk_length); - - if (png_ptr->idat_size > PNG_MAX_UINT) - png_error(png_ptr, "Invalid chunk length."); + png_ptr->idat_size = png_get_uint_31(png_ptr,chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, png_ptr->chunk_name, 4); @@ -712,8 +726,8 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) png_ptr->row_info.channels = png_ptr->channels; png_ptr->row_info.bit_depth = png_ptr->bit_depth; png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; - png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * - (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); if(png_ptr->row_buf[0]) png_read_filter_row(png_ptr, &(png_ptr->row_info), @@ -732,7 +746,8 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) } #endif - if (png_ptr->transformations) + + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) png_do_read_transformations(png_ptr); #if defined(PNG_READ_INTERLACING_SUPPORTED) @@ -767,7 +782,9 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) if (png_ptr->read_row_fn != NULL) (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); } +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED /* Read one or more rows of image data. If the image is interlaced, * and png_set_interlace_handling() has been called, the rows need to * contain the contents of the rows from the previous pass. If the @@ -789,7 +806,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) * not called png_set_interlace_handling(), the display_row buffer will * be ignored, so pass NULL to it. * - * [*] png_handle_alpha() does not exist yet, as of libpng version 1.2.4 + * [*] png_handle_alpha() does not exist yet, as of libpng version 1.2.8 */ void PNGAPI @@ -826,7 +843,9 @@ png_read_rows(png_structp png_ptr, png_bytepp row, dp++; } } +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED /* Read the entire image. If the image has an alpha channel or a tRNS * chunk, and you have called png_handle_alpha()[*], you will need to * initialize the image to the current image that PNG will be overlaying. @@ -837,7 +856,7 @@ png_read_rows(png_structp png_ptr, png_bytepp row, * only call this function once. If you desire to have an image for * each pass of a interlaced image, use png_read_rows() instead. * - * [*] png_handle_alpha() does not exist yet, as of libpng version 1.2.4 + * [*] png_handle_alpha() does not exist yet, as of libpng version 1.2.8 */ void PNGAPI png_read_image(png_structp png_ptr, png_bytepp image) @@ -871,7 +890,9 @@ png_read_image(png_structp png_ptr, png_bytepp image) } } } +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED /* Read the end of the PNG file. Will not read past the end of the * file, will verify the end is accurate, and will read any comments * or time information at the end of the file, if info is not NULL. @@ -943,19 +964,16 @@ png_read_end(png_structp png_ptr, png_infop info_ptr) #if defined(PNG_READ_zTXt_SUPPORTED) PNG_zTXt; #endif -#endif /* PNG_GLOBAL_ARRAYS */ +#endif /* PNG_USE_LOCAL_ARRAYS */ png_read_data(png_ptr, chunk_length, 4); - length = png_get_uint_32(chunk_length); + length = png_get_uint_31(png_ptr,chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, png_ptr->chunk_name, 4); png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name); - if (length > PNG_MAX_UINT) - png_error(png_ptr, "Invalid chunk length."); - if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) png_handle_IHDR(png_ptr, info_ptr, length); else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) @@ -1058,6 +1076,7 @@ png_read_end(png_structp png_ptr, png_infop info_ptr) png_handle_unknown(png_ptr, info_ptr, length); } while (!(png_ptr->mode & PNG_HAVE_IEND)); } +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ /* free all memory used by the read */ void PNGAPI @@ -1067,8 +1086,8 @@ png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_structp png_ptr = NULL; png_infop info_ptr = NULL, end_info_ptr = NULL; #ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn = NULL; - png_voidp mem_ptr = NULL; + png_free_ptr free_fn; + png_voidp mem_ptr; #endif png_debug(1, "in png_destroy_read_struct\n"); @@ -1249,7 +1268,7 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr * being used again. */ #ifdef PNG_SETJMP_SUPPORTED - png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf)); #endif error_fn = png_ptr->error_fn; @@ -1259,7 +1278,7 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr free_fn = png_ptr->free_fn; #endif - png_memset(png_ptr, 0, sizeof (png_struct)); + png_memset(png_ptr, 0, png_sizeof (png_struct)); png_ptr->error_fn = error_fn; png_ptr->warning_fn = warning_fn; @@ -1269,7 +1288,7 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr #endif #ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf)); #endif } @@ -1280,6 +1299,8 @@ png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) png_ptr->read_row_fn = read_row_fn; } + +#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED #if defined(PNG_INFO_IMAGE_SUPPORTED) void PNGAPI png_read_png(png_structp png_ptr, png_infop info_ptr, @@ -1289,34 +1310,38 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, int row; #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) - /* invert the alpha channel from opacity to transparency */ + /* invert the alpha channel from opacity to transparency + */ if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); #endif - /* The call to png_read_info() gives us all of the information from the + /* png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); + if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) + png_error(png_ptr,"Image is too high to process with png_read_png()"); /* -------------- image transformations start here ------------------- */ #if defined(PNG_READ_16_TO_8_SUPPORTED) - /* tell libpng to strip 16 bit/color files down to 8 bits/color */ + /* tell libpng to strip 16 bit/color files down to 8 bits per color + */ if (transforms & PNG_TRANSFORM_STRIP_16) png_set_strip_16(png_ptr); #endif #if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) - /* Strip alpha bytes from the input data without combining with the - * background (not recommended). + /* Strip alpha bytes from the input data without combining with + * the background (not recommended). */ if (transforms & PNG_TRANSFORM_STRIP_ALPHA) png_set_strip_alpha(png_ptr); #endif #if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) - /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single + /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ if (transforms & PNG_TRANSFORM_PACKING) @@ -1325,7 +1350,8 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, #if defined(PNG_READ_PACKSWAP_SUPPORTED) /* Change the order of packed pixels to least significant bit first - * (not useful if you are using png_set_packing). */ + * (not useful if you are using png_set_packing). + */ if (transforms & PNG_TRANSFORM_PACKSWAP) png_set_packswap(png_ptr); #endif @@ -1343,10 +1369,12 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, png_set_expand(png_ptr); #endif - /* We don't handle background color or gamma transformation or dithering. */ + /* We don't handle background color or gamma transformation or dithering. + */ #if defined(PNG_READ_INVERT_SUPPORTED) - /* invert monochrome files to have 0 as white and 1 as black */ + /* invert monochrome files to have 0 as white and 1 as black + */ if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); #endif @@ -1367,19 +1395,22 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, #endif #if defined(PNG_READ_BGR_SUPPORTED) - /* flip the RGB pixels to BGR (or RGBA to BGRA) */ + /* flip the RGB pixels to BGR (or RGBA to BGRA) + */ if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) - /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) + */ if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); #endif #if defined(PNG_READ_SWAP_SUPPORTED) - /* swap bytes of 16 bit files to least significant byte first */ + /* swap bytes of 16 bit files to least significant byte first + */ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); #endif @@ -1400,7 +1431,7 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, if(info_ptr->row_pointers == NULL) { info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, - info_ptr->height * sizeof(png_bytep)); + info_ptr->height * png_sizeof(png_bytep)); #ifdef PNG_FREE_ME_SUPPORTED info_ptr->free_me |= PNG_FREE_ROWS; #endif @@ -1422,3 +1453,4 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, } #endif +#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ diff --git a/pngrio.c b/pngrio.c index bb4197d2b..cae501a5c 100644 --- a/pngrio.c +++ b/pngrio.c @@ -1,9 +1,9 @@ /* pngrio.c - functions for data input * - * libpng 1.2.4 - July 8, 2002 + * libpng 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * diff --git a/pngrtran.c b/pngrtran.c index f8142ebfc..e1d6e3ce3 100644 --- a/pngrtran.c +++ b/pngrtran.c @@ -1,9 +1,9 @@ /* pngrtran.c - transforms the data in a row for PNG readers * - * libpng 1.2.4 - July 8, 2002 + * libpng version 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -85,7 +85,8 @@ png_set_background(png_structp png_ptr, } png_ptr->transformations |= PNG_BACKGROUND; - png_memcpy(&(png_ptr->background), background_color, sizeof(png_color_16)); + png_memcpy(&(png_ptr->background), background_color, + png_sizeof(png_color_16)); png_ptr->background_gamma = (float)background_gamma; png_ptr->background_gamma_type = (png_byte)(background_gamma_code); png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); @@ -118,7 +119,7 @@ void PNGAPI png_set_strip_alpha(png_structp png_ptr) { png_debug(1, "in png_set_strip_alpha\n"); - png_ptr->transformations |= PNG_STRIP_ALPHA; + png_ptr->flags |= PNG_FLAG_STRIP_ALPHA; } #endif @@ -154,7 +155,7 @@ png_set_dither(png_structp png_ptr, png_colorp palette, int i; png_ptr->dither_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * sizeof (png_byte))); + (png_uint_32)(num_palette * png_sizeof (png_byte))); for (i = 0; i < num_palette; i++) png_ptr->dither_index[i] = (png_byte)i; } @@ -170,7 +171,7 @@ png_set_dither(png_structp png_ptr, png_colorp palette, /* initialize an array to sort colors */ png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * sizeof (png_byte))); + (png_uint_32)(num_palette * png_sizeof (png_byte))); /* initialize the dither_sort array */ for (i = 0; i < num_palette; i++) @@ -299,9 +300,9 @@ png_set_dither(png_structp png_ptr, png_colorp palette, /* initialize palette index arrays */ png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * sizeof (png_byte))); + (png_uint_32)(num_palette * png_sizeof (png_byte))); png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * sizeof (png_byte))); + (png_uint_32)(num_palette * png_sizeof (png_byte))); /* initialize the sort array */ for (i = 0; i < num_palette; i++) @@ -311,10 +312,10 @@ png_set_dither(png_structp png_ptr, png_colorp palette, } hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 * - sizeof (png_dsortp))); + png_sizeof (png_dsortp))); for (i = 0; i < 769; i++) hash[i] = NULL; -/* png_memset(hash, 0, 769 * sizeof (png_dsortp)); */ +/* png_memset(hash, 0, 769 * png_sizeof (png_dsortp)); */ num_new_palette = num_palette; @@ -344,7 +345,7 @@ png_set_dither(png_structp png_ptr, png_colorp palette, { t = (png_dsortp)png_malloc_warn(png_ptr, - (png_uint_32)(sizeof(png_dsort))); + (png_uint_32)(png_sizeof(png_dsort))); if (t == NULL) break; t->next = hash[d]; @@ -462,14 +463,15 @@ png_set_dither(png_structp png_ptr, png_colorp palette, png_size_t num_entries = ((png_size_t)1 << total_bits); png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr, - (png_uint_32)(num_entries * sizeof (png_byte))); + (png_uint_32)(num_entries * png_sizeof (png_byte))); - png_memset(png_ptr->palette_lookup, 0, num_entries * sizeof (png_byte)); + png_memset(png_ptr->palette_lookup, 0, num_entries * + png_sizeof (png_byte)); distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * - sizeof(png_byte))); + png_sizeof(png_byte))); - png_memset(distance, 0xff, num_entries * sizeof(png_byte)); + png_memset(distance, 0xff, num_entries * png_sizeof(png_byte)); for (i = 0; i < num_palette; i++) { @@ -480,12 +482,14 @@ png_set_dither(png_structp png_ptr, png_colorp palette, for (ir = 0; ir < num_red; ir++) { - int dr = abs(ir - r); + /* int dr = abs(ir - r); */ + int dr = ((ir > r) ? ir - r : r - ir); int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS)); for (ig = 0; ig < num_green; ig++) { - int dg = abs(ig - g); + /* int dg = abs(ig - g); */ + int dg = ((ig > g) ? ig - g : g - ig); int dt = dr + dg; int dm = ((dr > dg) ? dr : dg); int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS); @@ -493,7 +497,8 @@ png_set_dither(png_structp png_ptr, png_colorp palette, for (ib = 0; ib < num_blue; ib++) { int d_index = index_g | ib; - int db = abs(ib - b); + /* int db = abs(ib - b); */ + int db = ((ib > b) ? ib - b : b - ib); int dmax = ((dm > db) ? dm : db); int d = dmax + dt + db; @@ -1116,7 +1121,7 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) info_ptr->channels = 1; #if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) - if (png_ptr->transformations & PNG_STRIP_ALPHA) + if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; #endif @@ -1130,8 +1135,10 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) { info_ptr->channels++; -#if 0 /* if adding a true alpha channel not just filler */ - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + /* if adding a true alpha channel not just filler */ +#if !defined(PNG_1_0_X) + if (png_ptr->transformations & PNG_ADD_ALPHA) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; #endif } #endif @@ -1149,7 +1156,8 @@ defined(PNG_READ_USER_TRANSFORM_SUPPORTED) info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); - info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3); + + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,info_ptr->width); #if !defined(PNG_READ_EXPAND_SUPPORTED) if(png_ptr) @@ -1201,9 +1209,9 @@ png_do_read_transformations(png_structp png_ptr) #endif #if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) - if (png_ptr->transformations & PNG_STRIP_ALPHA) + if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, - PNG_FLAG_FILLER_AFTER); + PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)); #endif #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) @@ -1380,8 +1388,8 @@ From Andreas Dilger e-mail to png-implement, 26 March 1998: #endif png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * png_ptr->row_info.channels); - png_ptr->row_info.rowbytes = (png_ptr->row_info.width * - png_ptr->row_info.pixel_depth+7)>>3; + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); } #endif @@ -1889,8 +1897,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, /* This changes the data from GG to GGXX */ if (flags & PNG_FLAG_FILLER_AFTER) { - png_bytep sp = row + (png_size_t)row_width; - png_bytep dp = sp + (png_size_t)row_width; + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { *(--dp) = hi_filler; @@ -1907,8 +1915,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, /* This changes the data from GG to XXGG */ else { - png_bytep sp = row + (png_size_t)row_width; - png_bytep dp = sp + (png_size_t)row_width; + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); @@ -1965,8 +1973,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, /* This changes the data from RRGGBB to RRGGBBXX */ if (flags & PNG_FLAG_FILLER_AFTER) { - png_bytep sp = row + (png_size_t)row_width * 3; - png_bytep dp = sp + (png_size_t)row_width; + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { *(--dp) = hi_filler; @@ -1987,8 +1995,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, /* This changes the data from RRGGBB to XXRRGGBB */ else { - png_bytep sp = row + (png_size_t)row_width * 3; - png_bytep dp = sp + (png_size_t)row_width; + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); @@ -2087,8 +2095,7 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) row_info->color_type |= PNG_COLOR_MASK_COLOR; row_info->pixel_depth = (png_byte)(row_info->channels * row_info->bit_depth); - row_info->rowbytes = ((row_width * - row_info->pixel_depth + 7) >> 3); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); } } #endif @@ -2097,7 +2104,7 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) /* reduce RGB files to grayscale, with or without alpha * using the equation given in Poynton's ColorFAQ at * - * Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net + * Copyright (c) 1998-01-04 Charles Poynton poynton at inforamp.net * * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B * @@ -2271,7 +2278,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) png_byte blue = *(sp++); if(red != green || red != blue) rgb_error |= 1; - *(dp++) = (png_byte)((gc*red + gc*green + bc*blue)>>8); + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); *(dp++) = *(sp++); /* alpha */ } } @@ -2341,8 +2348,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) row_info->color_type &= ~PNG_COLOR_MASK_COLOR; row_info->pixel_depth = (png_byte)(row_info->channels * row_info->bit_depth); - row_info->rowbytes = ((row_width * - row_info->pixel_depth + 7) >> 3); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); } return rgb_error; } @@ -3260,8 +3266,7 @@ png_do_background(png_row_infop row_info, png_bytep row, row_info->channels--; row_info->pixel_depth = (png_byte)(row_info->channels * row_info->bit_depth); - row_info->rowbytes = ((row_width * - row_info->pixel_depth + 7) >> 3); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); } } } @@ -3735,8 +3740,8 @@ png_do_expand(png_row_infop row_info, png_bytep row, row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; row_info->channels = 2; row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); - row_info->rowbytes = - ((row_width * row_info->pixel_depth) >> 3); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_width); } } else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value) @@ -3790,8 +3795,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; row_info->channels = 4; row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); - row_info->rowbytes = - ((row_width * row_info->pixel_depth) >> 3); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); } } } @@ -3844,8 +3848,7 @@ png_do_dither(png_row_infop row_info, png_bytep row, row_info->color_type = PNG_COLOR_TYPE_PALETTE; row_info->channels = 1; row_info->pixel_depth = row_info->bit_depth; - row_info->rowbytes = - ((row_width * row_info->pixel_depth + 7) >> 3); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); } else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && palette_lookup != NULL && row_info->bit_depth == 8) @@ -3874,8 +3877,7 @@ png_do_dither(png_row_infop row_info, png_bytep row, row_info->color_type = PNG_COLOR_TYPE_PALETTE; row_info->channels = 1; row_info->pixel_depth = row_info->bit_depth; - row_info->rowbytes = - ((row_width * row_info->pixel_depth + 7) >> 3); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width); } else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && dither_lookup && row_info->bit_depth == 8) @@ -4005,7 +4007,7 @@ png_build_gamma_table(png_structp png_ptr) g = 1.0; png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr, - (png_uint_32)(num * sizeof (png_uint_16p))); + (png_uint_32)(num * png_sizeof (png_uint_16p))); if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND)) { @@ -4015,7 +4017,7 @@ png_build_gamma_table(png_structp png_ptr) for (i = 0; i < num; i++) { png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * sizeof (png_uint_16))); + (png_uint_32)(256 * png_sizeof (png_uint_16))); } g = 1.0 / g; @@ -4045,7 +4047,7 @@ png_build_gamma_table(png_structp png_ptr) for (i = 0; i < num; i++) { png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * sizeof (png_uint_16))); + (png_uint_32)(256 * png_sizeof (png_uint_16))); ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4); for (j = 0; j < 256; j++) @@ -4065,12 +4067,12 @@ png_build_gamma_table(png_structp png_ptr) g = 1.0 / (png_ptr->gamma); png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr, - (png_uint_32)(num * sizeof (png_uint_16p ))); + (png_uint_32)(num * png_sizeof (png_uint_16p ))); for (i = 0; i < num; i++) { png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * sizeof (png_uint_16))); + (png_uint_32)(256 * png_sizeof (png_uint_16))); ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4); @@ -4088,12 +4090,12 @@ png_build_gamma_table(png_structp png_ptr) g = png_ptr->gamma; /* probably doing rgb_to_gray */ png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr, - (png_uint_32)(num * sizeof (png_uint_16p))); + (png_uint_32)(num * png_sizeof (png_uint_16p))); for (i = 0; i < num; i++) { png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * sizeof (png_uint_16))); + (png_uint_32)(256 * png_sizeof (png_uint_16))); ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4); @@ -4159,15 +4161,15 @@ png_do_read_intrapixel(png_row_infop row_info, png_bytep row) for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) { - png_uint_32 s0=*(rp )<<8 | *(rp+1); - png_uint_32 s1=*(rp+2)<<8 | *(rp+3); - png_uint_32 s2=*(rp+4)<<8 | *(rp+5); - png_uint_32 red=(65536+s0+s1)&0xffff; - png_uint_32 blue=(65536+s2+s1)&0xffff; - *(rp ) = (png_byte)((red>>8)&0xff); - *(rp+1) = (png_byte)(red&0xff); - *(rp+4) = (png_byte)((blue>>8)&0xff); - *(rp+5) = (png_byte)(blue&0xff); + png_uint_32 s0 = (*(rp ) << 8) | *(rp+1); + png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3); + png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5); + png_uint_32 red = (png_uint_32)((s0+s1+65536L) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2+s1+65536L) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp+1) = (png_byte)(red & 0xff); + *(rp+4) = (png_byte)((blue >> 8) & 0xff); + *(rp+5) = (png_byte)(blue & 0xff); } } } diff --git a/pngrutil.c b/pngrutil.c index 974006311..99e466f18 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -1,9 +1,8 @@ - /* pngrutil.c - utilities to read a PNG file * - * libpng 1.2.4 - July 8, 2002 + * libpng version 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -38,6 +37,14 @@ __inline double strtod(const char *nptr, char **endptr) # endif #endif +png_uint_32 /* PRIVATE */ +png_get_uint_31(png_structp png_ptr, png_bytep buf) +{ + png_uint_32 i = png_get_uint_32(buf); + if (i > PNG_UINT_31_MAX) + png_error(png_ptr, "PNG unsigned integer out of range.\n"); + return (i); +} #ifndef PNG_READ_BIG_ENDIAN_SUPPORTED /* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ png_uint_32 /* PRIVATE */ @@ -171,7 +178,7 @@ png_decompress_chunk(png_structp png_ptr, int comp_type, png_size_t prefix_size, png_size_t *newlength) { static char msg[] = "Error decoding compressed text"; - png_charp text = NULL; + png_charp text; png_size_t text_size; if (comp_type == PNG_COMPRESSION_TYPE_BASE) @@ -199,7 +206,7 @@ png_decompress_chunk(png_structp png_ptr, int comp_type, if (text == NULL) { - text_size = prefix_size + sizeof(msg) + 1; + text_size = prefix_size + png_sizeof(msg) + 1; text = (png_charp)png_malloc_warn(png_ptr, text_size); if (text == NULL) { @@ -213,7 +220,8 @@ png_decompress_chunk(png_structp png_ptr, int comp_type, /* Copy what we can of the error message into the text chunk */ text_size = (png_size_t)(chunklength - (text - chunkdata) - 1); - text_size = sizeof(msg) > text_size ? text_size : sizeof(msg); + text_size = png_sizeof(msg) > text_size ? text_size : + png_sizeof(msg); png_memcpy(text + prefix_size, msg, text_size + 1); break; } @@ -346,15 +354,14 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_crc_read(png_ptr, buf, 13); png_crc_finish(png_ptr, 0); - width = png_get_uint_32(buf); - height = png_get_uint_32(buf + 4); + width = png_get_uint_31(png_ptr, buf); + height = png_get_uint_31(png_ptr, buf + 4); bit_depth = buf[8]; color_type = buf[9]; compression_type = buf[10]; filter_type = buf[11]; interlace_type = buf[12]; - /* set internal variables */ png_ptr->width = width; png_ptr->height = height; @@ -364,6 +371,7 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #if defined(PNG_MNG_FEATURES_SUPPORTED) png_ptr->filter_type = (png_byte)filter_type; #endif + png_ptr->compression_type = (png_byte)compression_type; /* find number of channels */ switch (png_ptr->color_type) @@ -386,8 +394,7 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* set up other useful info */ png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); - png_ptr->rowbytes = ((png_ptr->width * - (png_uint_32)png_ptr->pixel_depth + 7) >> 3); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width); png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth); png_debug1(3,"channels = %d\n", png_ptr->channels); png_debug1(3,"rowbytes = %lu\n", png_ptr->rowbytes); @@ -542,8 +549,6 @@ png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) { png_error(png_ptr, "No image in file"); - - info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */ } png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); @@ -553,6 +558,9 @@ png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_warning(png_ptr, "Incorrect IEND chunk length"); } png_crc_finish(png_ptr, length); + + if (&info_ptr == NULL) /* quiet compiler warnings about unused info_ptr */ + return; } #if defined(PNG_READ_gAMA_SUPPORTED) @@ -579,7 +587,7 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Should be an error, but we can cope with it */ png_warning(png_ptr, "Out of place gAMA chunk"); - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) #if defined(PNG_READ_sRGB_SUPPORTED) && !(info_ptr->valid & PNG_INFO_sRGB) #endif @@ -612,7 +620,7 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #if defined(PNG_READ_sRGB_SUPPORTED) if (info_ptr->valid & PNG_INFO_sRGB) - if(igamma < 45000L || igamma > 46000L) + if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) { png_warning(png_ptr, "Ignoring incorrect gAMA value when sRGB is also present"); @@ -660,7 +668,7 @@ png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Should be an error, but we can cope with it */ png_warning(png_ptr, "Out of place sBIT chunk"); } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) { png_warning(png_ptr, "Duplicate sBIT chunk"); png_crc_finish(png_ptr, length); @@ -672,7 +680,7 @@ png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) else truelen = (png_size_t)png_ptr->channels; - if (length != truelen) + if (length != truelen || length > 4) { png_warning(png_ptr, "Incorrect sBIT chunk length"); png_crc_finish(png_ptr, length); @@ -729,7 +737,7 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Should be an error, but we can cope with it */ png_warning(png_ptr, "Missing PLTE before cHRM"); - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) #if defined(PNG_READ_sRGB_SUPPORTED) && !(info_ptr->valid & PNG_INFO_sRGB) #endif @@ -825,14 +833,14 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #if defined(PNG_READ_sRGB_SUPPORTED) if (info_ptr->valid & PNG_INFO_sRGB) { - if (abs(int_x_white - 31270L) > 1000 || - abs(int_y_white - 32900L) > 1000 || - abs(int_x_red - 64000L) > 1000 || - abs(int_y_red - 33000L) > 1000 || - abs(int_x_green - 30000L) > 1000 || - abs(int_y_green - 60000L) > 1000 || - abs(int_x_blue - 15000L) > 1000 || - abs(int_y_blue - 6000L) > 1000) + if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) || + PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) || + PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) || + PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) || + PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) || + PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) || + PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) || + PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000)) { png_warning(png_ptr, @@ -891,7 +899,7 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Should be an error, but we can cope with it */ png_warning(png_ptr, "Out of place sRGB chunk"); - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) { png_warning(png_ptr, "Duplicate sRGB chunk"); png_crc_finish(png_ptr, length); @@ -920,15 +928,15 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) if ((info_ptr->valid & PNG_INFO_gAMA)) { - int igamma; + png_fixed_point igamma; #ifdef PNG_FIXED_POINT_SUPPORTED - igamma=(int)info_ptr->int_gamma; + igamma=info_ptr->int_gamma; #else # ifdef PNG_FLOATING_POINT_SUPPORTED - igamma=(int)(info_ptr->gamma * 100000.); + igamma=(png_fixed_point)(info_ptr->gamma * 100000.); # endif #endif - if(igamma < 45000L || igamma > 46000L) + if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) { png_warning(png_ptr, "Ignoring incorrect gAMA value when sRGB is also present"); @@ -948,14 +956,14 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_cHRM_SUPPORTED #ifdef PNG_FIXED_POINT_SUPPORTED if (info_ptr->valid & PNG_INFO_cHRM) - if (abs(info_ptr->int_x_white - 31270L) > 1000 || - abs(info_ptr->int_y_white - 32900L) > 1000 || - abs(info_ptr->int_x_red - 64000L) > 1000 || - abs(info_ptr->int_y_red - 33000L) > 1000 || - abs(info_ptr->int_x_green - 30000L) > 1000 || - abs(info_ptr->int_y_green - 60000L) > 1000 || - abs(info_ptr->int_x_blue - 15000L) > 1000 || - abs(info_ptr->int_y_blue - 6000L) > 1000) + if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) || + PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000)) { png_warning(png_ptr, "Ignoring incorrect cHRM value when sRGB is also present"); @@ -977,8 +985,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_bytep pC; png_charp profile; png_uint_32 skip = 0; - png_uint_32 profile_size = 0; - png_uint_32 profile_length = 0; + png_uint_32 profile_size, profile_length; png_size_t slength, prefix_length, data_length; png_debug(1, "in png_handle_iCCP\n"); @@ -995,7 +1002,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Should be an error, but we can cope with it */ png_warning(png_ptr, "Out of place iCCP chunk"); - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)) + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)) { png_warning(png_ptr, "Duplicate iCCP chunk"); png_crc_finish(png_ptr, length); @@ -1153,9 +1160,20 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } - new_palette.nentries = data_length / entry_size; - new_palette.entries = (png_sPLT_entryp)png_malloc( - png_ptr, new_palette.nentries * sizeof(png_sPLT_entry)); + new_palette.nentries = (png_uint_32) (data_length / entry_size); + if ((png_uint_32) new_palette.nentries > (png_uint_32) (PNG_SIZE_MAX / + png_sizeof(png_sPLT_entry))) + { + png_warning(png_ptr, "sPLT chunk too long"); + return; + } + new_palette.entries = (png_sPLT_entryp)png_malloc_warn( + png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry)); + if (new_palette.entries == NULL) + { + png_warning(png_ptr, "sPLT chunk requires too much memory"); + return; + } #ifndef PNG_NO_POINTER_INDEXING for (i = 0; i < new_palette.nentries; i++) @@ -1234,49 +1252,9 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) { - if (!(png_ptr->mode & PNG_HAVE_PLTE)) - { - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Missing PLTE before tRNS"); - } - else if (length > (png_uint_32)png_ptr->num_palette) - { - png_warning(png_ptr, "Incorrect tRNS chunk length"); - png_crc_finish(png_ptr, length); - return; - } - if (length == 0) - { - png_warning(png_ptr, "Zero length tRNS chunk"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, readbuf, (png_size_t)length); - png_ptr->num_trans = (png_uint_16)length; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - png_byte buf[6]; - - if (length != 6) - { - png_warning(png_ptr, "Incorrect tRNS chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, (png_size_t)length); - png_ptr->num_trans = 1; - png_ptr->trans_values.red = png_get_uint_16(buf); - png_ptr->trans_values.green = png_get_uint_16(buf + 2); - png_ptr->trans_values.blue = png_get_uint_16(buf + 4); - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) - { - png_byte buf[6]; + png_byte buf[2]; if (length != 2) { @@ -1289,6 +1267,45 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_ptr->num_trans = 1; png_ptr->trans_values.gray = png_get_uint_16(buf); } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_byte buf[6]; + + if (length != 6) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + png_crc_read(png_ptr, buf, (png_size_t)length); + png_ptr->num_trans = 1; + png_ptr->trans_values.red = png_get_uint_16(buf); + png_ptr->trans_values.green = png_get_uint_16(buf + 2); + png_ptr->trans_values.blue = png_get_uint_16(buf + 4); + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + /* Should be an error, but we can cope with it. */ + png_warning(png_ptr, "Missing PLTE before tRNS"); + } + if (length > (png_uint_32)png_ptr->num_palette || + length > PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + if (length == 0) + { + png_warning(png_ptr, "Zero length tRNS chunk"); + png_crc_finish(png_ptr, length); + return; + } + png_crc_read(png_ptr, readbuf, (png_size_t)length); + png_ptr->num_trans = (png_uint_16)length; + } else { png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); @@ -1397,7 +1414,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) void /* PRIVATE */ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { - int num, i; + unsigned int num, i; png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; png_debug(1, "in png_handle_hIST\n"); @@ -1423,8 +1440,9 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } - num = (int)length / 2 ; - if (num != png_ptr->num_palette) + num = length / 2 ; + if (num != (unsigned int) png_ptr->num_palette || num > + (unsigned int) PNG_MAX_PALETTE_LENGTH) { png_warning(png_ptr, "Incorrect hIST chunk length"); png_crc_finish(png_ptr, length); @@ -1625,7 +1643,7 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(3, "Allocating pCAL parameters array\n"); params = (png_charpp)png_malloc_warn(png_ptr, (png_uint_32)(nparams - *sizeof(png_charp))) ; + *png_sizeof(png_charp))) ; if (params == NULL) { png_free(png_ptr, purpose); @@ -1883,7 +1901,8 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (text != key + slength) text++; - text_ptr = (png_textp)png_malloc_warn(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)png_sizeof(png_text)); if (text_ptr == NULL) { png_warning(png_ptr, "Not enough memory to process text chunk."); @@ -1979,7 +1998,8 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata, (png_size_t)length, prefix_len, &data_len); - text_ptr = (png_textp)png_malloc_warn(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)png_sizeof(png_text)); if (text_ptr == NULL) { png_warning(png_ptr,"Not enough memory to process zTXt chunk."); @@ -2088,7 +2108,8 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) (size_t)length, prefix_len, &data_len); else data_len=png_strlen(chunkdata + prefix_len); - text_ptr = (png_textp)png_malloc_warn(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr = (png_textp)png_malloc_warn(png_ptr, + (png_uint_32)png_sizeof(png_text)); if (text_ptr == NULL) { png_warning(png_ptr,"Not enough memory to process iTXt chunk."); @@ -2139,7 +2160,7 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - HANDLE_CHUNK_ALWAYS + PNG_HANDLE_CHUNK_ALWAYS #if defined(PNG_READ_USER_CHUNKS_SUPPORTED) && png_ptr->read_user_chunk_fn == NULL #endif @@ -2173,7 +2194,7 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { if (!(png_ptr->chunk_name[0] & 0x20)) if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - HANDLE_CHUNK_ALWAYS) + PNG_HANDLE_CHUNK_ALWAYS) { png_free(png_ptr, chunk.data); png_chunk_error(png_ptr, "unknown critical chunk"); @@ -2193,7 +2214,8 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_crc_finish(png_ptr, skip); #if !defined(PNG_READ_USER_CHUNKS_SUPPORTED) - info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */ + if (&info_ptr == NULL) /* quiet compiler warnings about unused info_ptr */ + return; #endif } @@ -2203,7 +2225,7 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) functions to handle unknown critical chunks after we check that the chunk name itself is valid. */ -#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97)) +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) void /* PRIVATE */ png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name) @@ -2234,8 +2256,7 @@ png_combine_row(png_structp png_ptr, png_bytep row, int mask) if (mask == 0xff) { png_memcpy(row, png_ptr->row_buf + 1, - (png_size_t)((png_ptr->width * - png_ptr->row_info.pixel_depth + 7) >> 3)); + PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width)); } else { @@ -2650,11 +2671,11 @@ png_do_read_interlace(png_structp png_ptr) } } row_info->width = final_width; - row_info->rowbytes = ((final_width * - (png_uint_32)row_info->pixel_depth + 7) >> 3); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width); } #if !defined(PNG_READ_PACKSWAP_SUPPORTED) - transformations = transformations; /* silence compiler warning */ + if (&transformations == NULL) /* silence compiler warning */ + return; #endif } #endif /* !PNG_HAVE_ASSEMBLER_READ_INTERLACE */ @@ -2822,8 +2843,9 @@ png_read_finish_row(png_structp png_ptr) png_pass_inc[png_ptr->pass] - 1 - png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; - png_ptr->irowbytes = ((png_ptr->iwidth * - (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1; + + png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; if (!(png_ptr->transformations & PNG_INTERLACE)) { @@ -2863,8 +2885,7 @@ png_read_finish_row(png_structp png_ptr) png_crc_finish(png_ptr, 0); png_read_data(png_ptr, chunk_length, 4); - png_ptr->idat_size = png_get_uint_32(chunk_length); - + png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, png_ptr->chunk_name, 4); if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4)) @@ -2883,7 +2904,7 @@ png_read_finish_row(png_structp png_ptr) { if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || png_ptr->idat_size) - png_error(png_ptr, "Extra compressed data"); + png_warning(png_ptr, "Extra compressed data"); png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; break; @@ -2893,14 +2914,19 @@ png_read_finish_row(png_structp png_ptr) "Decompression Error"); if (!(png_ptr->zstream.avail_out)) - png_error(png_ptr, "Extra compressed data"); + { + png_warning(png_ptr, "Extra compressed data."); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } } png_ptr->zstream.avail_out = 0; } if (png_ptr->idat_size || png_ptr->zstream.avail_in) - png_error(png_ptr, "Extra compression data"); + png_warning(png_ptr, "Extra compression data"); inflateReset(&png_ptr->zstream); @@ -2945,8 +2971,8 @@ png_read_start_row(png_structp png_ptr) png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; - row_bytes = ((png_ptr->iwidth * - (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1; + row_bytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->iwidth) + 1; + png_ptr->irowbytes = (png_size_t)row_bytes; if((png_uint_32)png_ptr->irowbytes != row_bytes) png_error(png_ptr, "Rowbytes overflow in png_read_start_row"); @@ -3064,7 +3090,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); /* calculate the maximum bytes needed, adding a byte and a pixel for safety's sake */ - row_bytes = ((row_bytes * (png_uint_32)max_pixel_depth + 7) >> 3) + + row_bytes = PNG_ROWBYTES(max_pixel_depth,row_bytes) + 1 + ((max_pixel_depth + 7) >> 3); #ifdef PNG_MAX_MALLOC_64K if (row_bytes > (png_uint_32)65536L) @@ -3080,6 +3106,8 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L) png_error(png_ptr, "This image requires a row greater than 64KB"); #endif + if ((png_uint_32)png_ptr->rowbytes > PNG_SIZE_MAX - 1) + png_error(png_ptr, "Row has too many bytes to allocate in memory."); png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)( png_ptr->rowbytes + 1)); diff --git a/pngset.c b/pngset.c index c691f9e60..5922cad0c 100644 --- a/pngset.c +++ b/pngset.c @@ -1,9 +1,9 @@ /* pngset.c - storage of image information into info struct * - * libpng 1.2.4 - July 8, 2002 + * libpng 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -24,7 +24,7 @@ png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background) if (png_ptr == NULL || info_ptr == NULL) return; - png_memcpy(&(info_ptr->background), background, sizeof(png_color_16)); + png_memcpy(&(info_ptr->background), background, png_sizeof(png_color_16)); info_ptr->valid |= PNG_INFO_bKGD; } #endif @@ -100,10 +100,14 @@ png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, "Ignoring attempt to set negative chromaticity value"); return; } - if (white_x > (double) PNG_MAX_UINT || white_y > (double) PNG_MAX_UINT || - red_x > (double) PNG_MAX_UINT || red_y > (double) PNG_MAX_UINT || - green_x > (double) PNG_MAX_UINT || green_y > (double) PNG_MAX_UINT || - blue_x > (double) PNG_MAX_UINT || blue_y > (double) PNG_MAX_UINT) + if (white_x > (double) PNG_UINT_31_MAX || + white_y > (double) PNG_UINT_31_MAX || + red_x > (double) PNG_UINT_31_MAX || + red_y > (double) PNG_UINT_31_MAX || + green_x > (double) PNG_UINT_31_MAX || + green_y > (double) PNG_UINT_31_MAX || + blue_x > (double) PNG_UINT_31_MAX || + blue_y > (double) PNG_UINT_31_MAX) { png_warning(png_ptr, "Ignoring attempt to set chromaticity value exceeding 21474.83"); @@ -169,10 +173,10 @@ png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point if (png_ptr == NULL || info_ptr == NULL) return; - if (int_gamma > (png_fixed_point) PNG_MAX_UINT) + if (int_gamma > (png_fixed_point) PNG_UINT_31_MAX) { png_warning(png_ptr, "Limiting gamma to 21474.83"); - gamma=PNG_MAX_UINT; + gamma=PNG_UINT_31_MAX; } else { @@ -217,7 +221,7 @@ png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist) #endif /* Changed from info->num_palette to 256 in version 1.2.1 */ png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr, - (png_uint_32)(256 * sizeof (png_uint_16))); + (png_uint_32)(256 * png_sizeof (png_uint_16))); if (png_ptr->hist == NULL) { png_warning(png_ptr, "Insufficient memory for hIST chunk data."); @@ -243,7 +247,6 @@ png_set_IHDR(png_structp png_ptr, png_infop info_ptr, int color_type, int interlace_type, int compression_type, int filter_type) { - int rowbytes_per_pixel; png_debug1(1, "in %s storage function\n", "IHDR"); if (png_ptr == NULL || info_ptr == NULL) return; @@ -251,8 +254,22 @@ png_set_IHDR(png_structp png_ptr, png_infop info_ptr, /* check for width and height valid values */ if (width == 0 || height == 0) png_error(png_ptr, "Image width or height is zero in IHDR"); - if (width > PNG_MAX_UINT || height > PNG_MAX_UINT) +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (width > png_ptr->user_width_max || height > png_ptr->user_height_max) + png_error(png_ptr, "image size exceeds user limits in IHDR"); +#else + if (width > PNG_USER_WIDTH_MAX || height > PNG_USER_HEIGHT_MAX) + png_error(png_ptr, "image size exceeds user limits in IHDR"); +#endif + if (width > PNG_UINT_31_MAX || height > PNG_UINT_31_MAX) png_error(png_ptr, "Invalid image size in IHDR"); + if ( width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 64 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ + png_warning(png_ptr, "Width is too large for libpng to process pixels"); /* check other values */ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && @@ -320,16 +337,16 @@ png_set_IHDR(png_structp png_ptr, png_infop info_ptr, info_ptr->channels++; info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); - /* check for overflow */ - rowbytes_per_pixel = (info_ptr->pixel_depth + 7) >> 3; - if ( width > PNG_MAX_UINT/rowbytes_per_pixel - 64) - { - png_warning(png_ptr, - "Width too large to process image data; rowbytes will overflow."); + /* check for potential overflow */ + if ( width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 64 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ info_ptr->rowbytes = (png_size_t)0; - } else - info_ptr->rowbytes = (info_ptr->width * info_ptr->pixel_depth + 7) >> 3; + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,width); } #if defined(PNG_oFFs_SUPPORTED) @@ -388,7 +405,7 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr, png_memcpy(info_ptr->pcal_units, units, (png_size_t)length); info_ptr->pcal_params = (png_charpp)png_malloc_warn(png_ptr, - (png_uint_32)((nparams + 1) * sizeof(png_charp))); + (png_uint_32)((nparams + 1) * png_sizeof(png_charp))); if (info_ptr->pcal_params == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL params."); @@ -449,12 +466,21 @@ png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, length = png_strlen(swidth) + 1; png_debug1(3, "allocating unit for info (%d bytes)\n", length); - info_ptr->scal_s_width = (png_charp)png_malloc(png_ptr, length); + info_ptr->scal_s_width = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->scal_s_width == NULL) + { + png_warning(png_ptr, "Memory allocation failed while processing sCAL."); + } png_memcpy(info_ptr->scal_s_width, swidth, (png_size_t)length); length = png_strlen(sheight) + 1; png_debug1(3, "allocating unit for info (%d bytes)\n", length); - info_ptr->scal_s_height = (png_charp)png_malloc(png_ptr, length); + info_ptr->scal_s_height = (png_charp)png_malloc_warn(png_ptr, length); + if (info_ptr->scal_s_height == NULL) + { + png_free (png_ptr, info_ptr->scal_s_width); + png_warning(png_ptr, "Memory allocation failed while processing sCAL."); + } png_memcpy(info_ptr->scal_s_height, sheight, (png_size_t)length); info_ptr->valid |= PNG_INFO_sCAL; @@ -499,13 +525,13 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr, #ifdef PNG_FREE_ME_SUPPORTED png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); #endif + /* Changed in libpng-1.2.1 to allocate 256 instead of num_palette entries, in case of an invalid PNG file that has too-large sample values. */ - png_ptr->palette = (png_colorp)png_zalloc(png_ptr, (uInt)256, - sizeof (png_color)); - if (png_ptr->palette == NULL) - png_error(png_ptr, "Unable to malloc palette"); - png_memcpy(png_ptr->palette, palette, num_palette * sizeof (png_color)); + png_ptr->palette = (png_colorp)png_malloc(png_ptr, + 256 * png_sizeof(png_color)); + png_memset(png_ptr->palette, 0, 256 * png_sizeof(png_color)); + png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof (png_color)); info_ptr->palette = png_ptr->palette; info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; @@ -527,7 +553,7 @@ png_set_sBIT(png_structp png_ptr, png_infop info_ptr, if (png_ptr == NULL || info_ptr == NULL) return; - png_memcpy(&(info_ptr->sig_bit), sig_bit, sizeof (png_color_8)); + png_memcpy(&(info_ptr->sig_bit), sig_bit, png_sizeof (png_color_8)); info_ptr->valid |= PNG_INFO_sBIT; } #endif @@ -628,9 +654,20 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr, if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) return; - new_iccp_name = (png_charp)png_malloc(png_ptr, png_strlen(name)+1); + new_iccp_name = (png_charp)png_malloc_warn(png_ptr, png_strlen(name)+1); + if (new_iccp_name == NULL) + { + png_warning(png_ptr, "Insufficient memory to process iCCP chunk."); + return; + } png_strcpy(new_iccp_name, name); - new_iccp_profile = (png_charp)png_malloc(png_ptr, proflen); + new_iccp_profile = (png_charp)png_malloc_warn(png_ptr, proflen); + if (new_iccp_profile == NULL) + { + png_free (png_ptr, new_iccp_name); + png_warning(png_ptr, "Insufficient memory to process iCCP profile."); + return; + } png_memcpy(new_iccp_profile, profile, (png_size_t)proflen); png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); @@ -685,14 +722,14 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, info_ptr->max_text = info_ptr->num_text + num_text + 8; old_text = info_ptr->text; info_ptr->text = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)(info_ptr->max_text * sizeof (png_text))); + (png_uint_32)(info_ptr->max_text * png_sizeof (png_text))); if (info_ptr->text == NULL) { png_free(png_ptr, old_text); return(1); } png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max * - sizeof(png_text))); + png_sizeof(png_text))); png_free(png_ptr, old_text); } else @@ -700,7 +737,7 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, info_ptr->max_text = num_text + 8; info_ptr->num_text = 0; info_ptr->text = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)(info_ptr->max_text * sizeof (png_text))); + (png_uint_32)(info_ptr->max_text * png_sizeof (png_text))); if (info_ptr->text == NULL) return(1); #ifdef PNG_FREE_ME_SUPPORTED @@ -829,7 +866,7 @@ png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time) (png_ptr->mode & PNG_WROTE_tIME)) return; - png_memcpy(&(info_ptr->mod_time), mod_time, sizeof (png_time)); + png_memcpy(&(info_ptr->mod_time), mod_time, png_sizeof (png_time)); info_ptr->valid |= PNG_INFO_tIME; } #endif @@ -867,7 +904,7 @@ png_set_tRNS(png_structp png_ptr, png_infop info_ptr, if (trans_values != NULL) { png_memcpy(&(info_ptr->trans_values), trans_values, - sizeof(png_color_16)); + png_sizeof(png_color_16)); if (num_trans == 0) num_trans = 1; } @@ -885,7 +922,7 @@ png_set_sPLT(png_structp png_ptr, int i; np = (png_sPLT_tp)png_malloc_warn(png_ptr, - (info_ptr->splt_palettes_num + nentries) * sizeof(png_sPLT_t)); + (info_ptr->splt_palettes_num + nentries) * png_sizeof(png_sPLT_t)); if (np == NULL) { png_warning(png_ptr, "No memory for sPLT palettes."); @@ -893,7 +930,7 @@ png_set_sPLT(png_structp png_ptr, } png_memcpy(np, info_ptr->splt_palettes, - info_ptr->splt_palettes_num * sizeof(png_sPLT_t)); + info_ptr->splt_palettes_num * png_sizeof(png_sPLT_t)); png_free(png_ptr, info_ptr->splt_palettes); info_ptr->splt_palettes=NULL; @@ -904,11 +941,13 @@ png_set_sPLT(png_structp png_ptr, to->name = (png_charp)png_malloc(png_ptr, png_strlen(from->name) + 1); + /* TODO: use png_malloc_warn */ png_strcpy(to->name, from->name); to->entries = (png_sPLT_entryp)png_malloc(png_ptr, - from->nentries * sizeof(png_sPLT_t)); + from->nentries * png_sizeof(png_sPLT_t)); + /* TODO: use png_malloc_warn */ png_memcpy(to->entries, from->entries, - from->nentries * sizeof(png_sPLT_t)); + from->nentries * png_sizeof(png_sPLT_t)); to->nentries = from->nentries; to->depth = from->depth; } @@ -935,7 +974,7 @@ png_set_unknown_chunks(png_structp png_ptr, np = (png_unknown_chunkp)png_malloc_warn(png_ptr, (info_ptr->unknown_chunks_num + num_unknowns) * - sizeof(png_unknown_chunk)); + png_sizeof(png_unknown_chunk)); if (np == NULL) { png_warning(png_ptr, "Out of memory while processing unknown chunk."); @@ -943,7 +982,7 @@ png_set_unknown_chunks(png_structp png_ptr, } png_memcpy(np, info_ptr->unknown_chunks, - info_ptr->unknown_chunks_num * sizeof(png_unknown_chunk)); + info_ptr->unknown_chunks_num * png_sizeof(png_unknown_chunk)); png_free(png_ptr, info_ptr->unknown_chunks); info_ptr->unknown_chunks=NULL; @@ -952,17 +991,19 @@ png_set_unknown_chunks(png_structp png_ptr, png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i; png_unknown_chunkp from = unknowns + i; - png_strcpy((png_charp)to->name, (png_charp)from->name); - to->data = (png_bytep)png_malloc(png_ptr, from->size); + png_strncpy((png_charp)to->name, (png_charp)from->name, 5); + to->data = (png_bytep)png_malloc_warn(png_ptr, from->size); if (to->data == NULL) - png_warning(png_ptr, "Out of memory while processing unknown chunk."); + { + png_warning(png_ptr, "Out of memory processing unknown chunk."); + } else { - png_memcpy(to->data, from->data, from->size); - to->size = from->size; + png_memcpy(to->data, from->data, from->size); + to->size = from->size; - /* note our location in the read or write sequence */ - to->location = (png_byte)(png_ptr->mode & 0xff); + /* note our location in the read or write sequence */ + to->location = (png_byte)(png_ptr->mode & 0xff); } } @@ -1020,12 +1061,12 @@ png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep int i, old_num_chunks; if (num_chunks == 0) { - if(keep == HANDLE_CHUNK_ALWAYS || keep == HANDLE_CHUNK_IF_SAFE) + if(keep == PNG_HANDLE_CHUNK_ALWAYS || keep == PNG_HANDLE_CHUNK_IF_SAFE) png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; else png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS; - if(keep == HANDLE_CHUNK_ALWAYS) + if(keep == PNG_HANDLE_CHUNK_ALWAYS) png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS; else png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS; @@ -1083,6 +1124,7 @@ png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers) } #endif +#ifdef PNG_WRITE_SUPPORTED void PNGAPI png_set_compression_buffer_size(png_structp png_ptr, png_uint_32 size) { @@ -1093,6 +1135,7 @@ png_set_compression_buffer_size(png_structp png_ptr, png_uint_32 size) png_ptr->zstream.next_out = png_ptr->zbuf; png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; } +#endif void PNGAPI png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask) @@ -1157,4 +1200,20 @@ png_set_mmx_thresholds (png_structp png_ptr, png_ptr->mmx_rowbytes_threshold = mmx_rowbytes_threshold; } #endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* this function was added to libpng 1.2.6 */ +void PNGAPI +png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, + png_uint_32 user_height_max) +{ + /* Images with dimensions larger than these limits will be + * rejected by png_set_IHDR(). To accept any PNG datastream + * regardless of dimensions, set both limits to 0x7ffffffL. + */ + png_ptr->user_width_max = user_width_max; + png_ptr->user_height_max = user_height_max; +} +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + #endif /* ?PNG_1_0_X */ diff --git a/pngtest.c b/pngtest.c new file mode 100644 index 000000000..f2085e1e5 --- /dev/null +++ b/pngtest.c @@ -0,0 +1,1554 @@ + +/* pngtest.c - a simple test program to test libpng + * + * libpng 1.2.8 - December 3, 2004 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2004 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This program reads in a PNG image, writes it out again, and then + * compares the two files. If the files are identical, this shows that + * the basic chunk handling, filtering, and (de)compression code is working + * properly. It does not currently test all of the transforms, although + * it probably should. + * + * The program will report "FAIL" in certain legitimate cases: + * 1) when the compression level or filter selection method is changed. + * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192. + * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks + * exist in the input file. + * 4) others not listed here... + * In these cases, it is best to check with another tool such as "pngcheck" + * to see what the differences between the two files are. + * + * If a filename is given on the command-line, then this file is used + * for the input, rather than the default "pngtest.png". This allows + * testing a wide variety of files easily. You can also test a number + * of files at once by typing "pngtest -m file1.png file2.png ..." + */ + +#include "png.h" + +#if defined(_WIN32_WCE) +# if _WIN32_WCE < 211 + __error__ (f|w)printf functions are not supported on old WindowsCE.; +# endif +# include +# include +# define READFILE(file, data, length, check) \ + if (ReadFile(file, data, length, &check,NULL)) check = 0 +# define WRITEFILE(file, data, length, check)) \ + if (WriteFile(file, data, length, &check, NULL)) check = 0 +# define FCLOSE(file) CloseHandle(file) +#else +# include +# include +# include +# define READFILE(file, data, length, check) \ + check=(png_size_t)fread(data,(png_size_t)1,length,file) +# define WRITEFILE(file, data, length, check) \ + check=(png_size_t)fwrite(data,(png_size_t)1, length, file) +# define FCLOSE(file) fclose(file) +#endif + +#if defined(PNG_NO_STDIO) +# if defined(_WIN32_WCE) + typedef HANDLE png_FILE_p; +# else + typedef FILE * png_FILE_p; +# endif +#endif + +/* Makes pngtest verbose so we can find problems (needs to be before png.h) */ +#ifndef PNG_DEBUG +# define PNG_DEBUG 0 +#endif + +#if !PNG_DEBUG +# define SINGLE_ROWBUF_ALLOC /* makes buffer overruns easier to nail */ +#endif + +/* Turn on CPU timing +#define PNGTEST_TIMING +*/ + +#ifdef PNG_NO_FLOATING_POINT_SUPPORTED +#undef PNGTEST_TIMING +#endif + +#ifdef PNGTEST_TIMING +static float t_start, t_stop, t_decode, t_encode, t_misc; +#include +#endif + +/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) png_ptr->jmpbuf +#endif + +#ifdef PNGTEST_TIMING +static float t_start, t_stop, t_decode, t_encode, t_misc; +#if !defined(PNG_tIME_SUPPORTED) +#include +#endif +#endif + +#if defined(PNG_TIME_RFC1123_SUPPORTED) +static int tIME_chunk_present=0; +static char tIME_string[30] = "no tIME chunk present in file"; +#endif + +static int verbose = 0; + +int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname)); + +#ifdef __TURBOC__ +#include +#endif + +/* defined so I can write to a file on gui/windowing platforms */ +/* #define STDERR stderr */ +#define STDERR stdout /* for DOS */ + +/* example of using row callbacks to make a simple progress meter */ +static int status_pass=1; +static int status_dots_requested=0; +static int status_dots=1; + +void +#ifdef PNG_1_0_X +PNGAPI +#endif +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if(png_ptr == NULL || row_number > PNG_UINT_31_MAX) return; + if(status_pass != pass) + { + fprintf(stdout,"\n Pass %d: ",pass); + status_pass = pass; + status_dots = 31; + } + status_dots--; + if(status_dots == 0) + { + fprintf(stdout, "\n "); + status_dots=30; + } + fprintf(stdout, "r"); +} + +void +#ifdef PNG_1_0_X +PNGAPI +#endif +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if(png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) return; + fprintf(stdout, "w"); +} + + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) +/* Example of using user transform callback (we don't transform anything, + but merely examine the row filters. We set this to 256 rather than + 5 in case illegal filter values are present.) */ +static png_uint_32 filters_used[256]; +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + if(png_ptr != NULL && row_info != NULL) + ++filters_used[*(data-1)]; +} +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +/* example of using user transform callback (we don't transform anything, + but merely count the zero samples) */ + +static png_uint_32 zero_samples; + +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data); +void +#ifdef PNG_1_0_X +PNGAPI +#endif +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + png_bytep dp = data; + if(png_ptr == NULL)return; + + /* contents of row_info: + * png_uint_32 width width of row + * png_uint_32 rowbytes number of bytes in row + * png_byte color_type color type of pixels + * png_byte bit_depth bit depth of samples + * png_byte channels number of channels (1-4) + * png_byte pixel_depth bits per pixel (depth*channels) + */ + + + /* counts the number of zero samples (or zero pixels if color_type is 3 */ + + if(row_info->color_type == 0 || row_info->color_type == 3) + { + int pos=0; + png_uint_32 n, nstop; + for (n=0, nstop=row_info->width; nbit_depth == 1) + { + if(((*dp << pos++ ) & 0x80) == 0) zero_samples++; + if(pos == 8) + { + pos = 0; + dp++; + } + } + if(row_info->bit_depth == 2) + { + if(((*dp << (pos+=2)) & 0xc0) == 0) zero_samples++; + if(pos == 8) + { + pos = 0; + dp++; + } + } + if(row_info->bit_depth == 4) + { + if(((*dp << (pos+=4)) & 0xf0) == 0) zero_samples++; + if(pos == 8) + { + pos = 0; + dp++; + } + } + if(row_info->bit_depth == 8) + if(*dp++ == 0) zero_samples++; + if(row_info->bit_depth == 16) + { + if((*dp | *(dp+1)) == 0) zero_samples++; + dp+=2; + } + } + } + else /* other color types */ + { + png_uint_32 n, nstop; + int channel; + int color_channels = row_info->channels; + if(row_info->color_type > 3)color_channels--; + + for (n=0, nstop=row_info->width; nbit_depth == 8) + if(*dp++ == 0) zero_samples++; + if(row_info->bit_depth == 16) + { + if((*dp | *(dp+1)) == 0) zero_samples++; + dp+=2; + } + } + if(row_info->color_type > 3) + { + dp++; + if(row_info->bit_depth == 16)dp++; + } + } + } +} +#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */ + +static int wrote_question = 0; + +#if defined(PNG_NO_STDIO) +/* START of code to validate stdio-free compilation */ +/* These copies of the default read/write functions come from pngrio.c and */ +/* pngwio.c. They allow "don't include stdio" testing of the library. */ +/* This is the function that does the actual reading of data. If you are + not reading from a standard C stream, you should create a replacement + read_data function and use it at run time with png_set_read_fn(), rather + than changing the library. */ + +#ifndef USE_FAR_KEYWORD +static void +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + READFILE((png_FILE_p)png_ptr->io_ptr, data, length, check); + + if (check != length) + { + png_error(png_ptr, "Read Error!"); + } +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + int check; + png_byte *n_data; + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + n_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)n_data == data) + { + READFILE(io_ptr, n_data, length, check); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); + READFILE(io_ptr, buf, 1, err); + png_memcpy(data, buf, read); /* copy far buffer to near buffer */ + if(err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); + } + if (check != length) + { + png_error(png_ptr, "read Error"); + } +} +#endif /* USE_FAR_KEYWORD */ + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +static void +pngtest_flush(png_structp png_ptr) +{ +#if !defined(_WIN32_WCE) + png_FILE_p io_ptr; + io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); + if (io_ptr != NULL) + fflush(io_ptr); +#endif +} +#endif + +/* This is the function that does the actual writing of data. If you are + not writing to a standard C stream, you should create a replacement + write_data function and use it at run time with png_set_write_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +static void +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + + WRITEFILE((png_FILE_p)png_ptr->io_ptr, data, length, check); + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + near_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)near_data == data) + { + WRITEFILE(io_ptr, near_data, length, check); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* copy far buffer to near buffer */ + WRITEFILE(io_ptr, buf, written, err); + if (err != written) + break; + else + check += err; + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} + +#endif /* USE_FAR_KEYWORD */ + +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void +pngtest_warning(png_structp png_ptr, png_const_charp message) +{ + PNG_CONST char *name = "UNKNOWN (ERROR!)"; + if (png_ptr != NULL && png_ptr->error_ptr != NULL) + name = png_ptr->error_ptr; + fprintf(STDERR, "%s: libpng warning: %s\n", name, message); +} + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static void +pngtest_error(png_structp png_ptr, png_const_charp message) +{ + pngtest_warning(png_ptr, message); + /* We can return because png_error calls the default handler, which is + * actually OK in this case. */ +} +#endif /* PNG_NO_STDIO */ +/* END of code to validate stdio-free compilation */ + +/* START of code to validate memory allocation and deallocation */ +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + +/* Allocate memory. For reasonable files, size should never exceed + 64K. However, zlib may allocate more then 64K if you don't tell + it not to. See zconf.h and png.h for more information. zlib does + need to allocate exactly 64K, so whatever you call here must + have the ability to do that. + + This piece of code can be compiled to validate max 64K allocations + by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */ +typedef struct memory_information +{ + png_uint_32 size; + png_voidp pointer; + struct memory_information FAR *next; +} memory_information; +typedef memory_information FAR *memory_infop; + +static memory_infop pinformation = NULL; +static int current_allocation = 0; +static int maximum_allocation = 0; +static int total_allocation = 0; +static int num_allocations = 0; + +png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size)); +void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); + +png_voidp +png_debug_malloc(png_structp png_ptr, png_uint_32 size) +{ + + /* png_malloc has already tested for NULL; png_create_struct calls + png_debug_malloc directly, with png_ptr == NULL which is OK */ + + if (size == 0) + return (NULL); + + /* This calls the library allocator twice, once to get the requested + buffer and once to get a new free list entry. */ + { + /* Disable malloc_fn and free_fn */ + memory_infop pinfo; + png_set_mem_fn(png_ptr, NULL, NULL, NULL); + pinfo = (memory_infop)png_malloc(png_ptr, + (png_uint_32)png_sizeof (*pinfo)); + pinfo->size = size; + current_allocation += size; + total_allocation += size; + num_allocations ++; + if (current_allocation > maximum_allocation) + maximum_allocation = current_allocation; + pinfo->pointer = (png_voidp)png_malloc(png_ptr, size); + /* Restore malloc_fn and free_fn */ + png_set_mem_fn(png_ptr, png_voidp_NULL, (png_malloc_ptr)png_debug_malloc, + (png_free_ptr)png_debug_free); + if (size != 0 && pinfo->pointer == NULL) + { + current_allocation -= size; + total_allocation -= size; + png_error(png_ptr, + "out of memory in pngtest->png_debug_malloc."); + } + pinfo->next = pinformation; + pinformation = pinfo; + /* Make sure the caller isn't assuming zeroed memory. */ + png_memset(pinfo->pointer, 0xdd, pinfo->size); + if(verbose) + printf("png_malloc %lu bytes at %x\n",size,pinfo->pointer); + assert(pinfo->size != 12345678); + return (png_voidp)(pinfo->pointer); + } +} + +/* Free a pointer. It is removed from the list at the same time. */ +void +png_debug_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL) + fprintf(STDERR, "NULL pointer to png_debug_free.\n"); + if (ptr == 0) + { +#if 0 /* This happens all the time. */ + fprintf(STDERR, "WARNING: freeing NULL pointer\n"); +#endif + return; + } + + /* Unlink the element from the list. */ + { + memory_infop FAR *ppinfo = &pinformation; + for (;;) + { + memory_infop pinfo = *ppinfo; + if (pinfo->pointer == ptr) + { + *ppinfo = pinfo->next; + current_allocation -= pinfo->size; + if (current_allocation < 0) + fprintf(STDERR, "Duplicate free of memory\n"); + /* We must free the list element too, but first kill + the memory that is to be freed. */ + png_memset(ptr, 0x55, pinfo->size); + png_free_default(png_ptr, pinfo); + pinfo=NULL; + break; + } + if (pinfo->next == NULL) + { + fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr); + break; + } + ppinfo = &pinfo->next; + } + } + + /* Finally free the data. */ + if(verbose) + printf("Freeing %x\n",ptr); + png_free_default(png_ptr, ptr); + ptr=NULL; +} +#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ +/* END of code to test memory allocation/deallocation */ + +/* Test one file */ +int +test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) +{ + static png_FILE_p fpin; + static png_FILE_p fpout; /* "static" prevents setjmp corruption */ + png_structp read_ptr; + png_infop read_info_ptr, end_info_ptr; +#ifdef PNG_WRITE_SUPPORTED + png_structp write_ptr; + png_infop write_info_ptr; + png_infop write_end_info_ptr; +#else + png_structp write_ptr = NULL; + png_infop write_info_ptr = NULL; + png_infop write_end_info_ptr = NULL; +#endif + png_bytep row_buf; + png_uint_32 y; + png_uint_32 width, height; + int num_pass, pass; + int bit_depth, color_type; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + +#if defined(_WIN32_WCE) + TCHAR path[MAX_PATH]; +#endif + char inbuf[256], outbuf[256]; + + row_buf = NULL; + +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); + if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpin = fopen(inname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find input file %s\n", inname); + return (1); + } + +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); + if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpout = fopen(outname, "wb")) == NULL) +#endif + { + fprintf(STDERR, "Could not open output file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + png_debug(0, "Allocating read and write structures\n"); +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, + (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); +#else + read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL); +#endif +#if defined(PNG_NO_STDIO) + png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, + pngtest_warning); +#endif +#ifdef PNG_WRITE_SUPPORTED +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, + (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); +#else + write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, + png_error_ptr_NULL, png_error_ptr_NULL); +#endif +#if defined(PNG_NO_STDIO) + png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, + pngtest_warning); +#endif +#endif + png_debug(0, "Allocating read_info, write_info and end_info structures\n"); + read_info_ptr = png_create_info_struct(read_ptr); + end_info_ptr = png_create_info_struct(read_ptr); +#ifdef PNG_WRITE_SUPPORTED + write_info_ptr = png_create_info_struct(write_ptr); + write_end_info_ptr = png_create_info_struct(write_ptr); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_debug(0, "Setting jmpbuf for read struct\n"); +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(read_ptr))) +#endif + { + fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); + if (row_buf) + png_free(read_ptr, row_buf); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(read_ptr),jmpbuf,png_sizeof(jmp_buf)); +#endif + +#ifdef PNG_WRITE_SUPPORTED + png_debug(0, "Setting jmpbuf for write struct\n"); +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(write_ptr))) +#endif + { + fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(write_ptr),jmpbuf,png_sizeof(jmp_buf)); +#endif +#endif +#endif + + png_debug(0, "Initializing input and output streams\n"); +#if !defined(PNG_NO_STDIO) + png_init_io(read_ptr, fpin); +# ifdef PNG_WRITE_SUPPORTED + png_init_io(write_ptr, fpout); +# endif +#else + png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); +# ifdef PNG_WRITE_SUPPORTED + png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, +# if defined(PNG_WRITE_FLUSH_SUPPORTED) + pngtest_flush); +# else + NULL); +# endif +# endif +#endif + if(status_dots_requested == 1) + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, write_row_callback); +#endif + png_set_read_status_fn(read_ptr, read_row_callback); + } + else + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL); +#endif + png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL); + } + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + { + int i; + for(i=0; i<256; i++) + filters_used[i]=0; + png_set_read_user_transform_fn(read_ptr, count_filters); + } +#endif +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + zero_samples=0; + png_set_write_user_transform_fn(write_ptr, count_zero_samples); +#endif + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) +# ifndef PNG_HANDLE_CHUNK_ALWAYS +# define PNG_HANDLE_CHUNK_ALWAYS 3 +# endif + png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, + png_bytep_NULL, 0); +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) +# ifndef PNG_HANDLE_CHUNK_IF_SAFE +# define PNG_HANDLE_CHUNK_IF_SAFE 2 +# endif + png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, + png_bytep_NULL, 0); +#endif + + png_debug(0, "Reading info struct\n"); + png_read_info(read_ptr, read_info_ptr); + + png_debug(0, "Transferring info struct\n"); + { + int interlace_type, compression_type, filter_type; + + if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, + &color_type, &interlace_type, &compression_type, &filter_type)) + { + png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + color_type, interlace_type, compression_type, filter_type); +#else + color_type, PNG_INTERLACE_NONE, compression_type, filter_type); +#endif + } + } +#if defined(PNG_FIXED_POINT_SUPPORTED) +#if defined(PNG_cHRM_SUPPORTED) + { + png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y)) + { + png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#if defined(PNG_gAMA_SUPPORTED) + { + png_fixed_point gamma; + + if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) + { + png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); + } + } +#endif +#else /* Use floating point versions */ +#if defined(PNG_FLOATING_POINT_SUPPORTED) +#if defined(PNG_cHRM_SUPPORTED) + { + double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y)) + { + png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#if defined(PNG_gAMA_SUPPORTED) + { + double gamma; + + if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) + { + png_set_gAMA(write_ptr, write_info_ptr, gamma); + } + } +#endif +#endif /* floating point */ +#endif /* fixed point */ +#if defined(PNG_iCCP_SUPPORTED) + { + png_charp name; + png_charp profile; + png_uint_32 proflen; + int compression_type; + + if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, + &profile, &proflen)) + { + png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, + profile, proflen); + } + } +#endif +#if defined(PNG_sRGB_SUPPORTED) + { + int intent; + + if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) + { + png_set_sRGB(write_ptr, write_info_ptr, intent); + } + } +#endif + { + png_colorp palette; + int num_palette; + + if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) + { + png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); + } + } +#if defined(PNG_bKGD_SUPPORTED) + { + png_color_16p background; + + if (png_get_bKGD(read_ptr, read_info_ptr, &background)) + { + png_set_bKGD(write_ptr, write_info_ptr, background); + } + } +#endif +#if defined(PNG_hIST_SUPPORTED) + { + png_uint_16p hist; + + if (png_get_hIST(read_ptr, read_info_ptr, &hist)) + { + png_set_hIST(write_ptr, write_info_ptr, hist); + } + } +#endif +#if defined(PNG_oFFs_SUPPORTED) + { + png_int_32 offset_x, offset_y; + int unit_type; + + if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type)) + { + png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); + } + } +#endif +#if defined(PNG_pCAL_SUPPORTED) + { + png_charp purpose, units; + png_charpp params; + png_int_32 X0, X1; + int type, nparams; + + if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, + &nparams, &units, ¶ms)) + { + png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, + nparams, units, params); + } + } +#endif +#if defined(PNG_pHYs_SUPPORTED) + { + png_uint_32 res_x, res_y; + int unit_type; + + if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) + { + png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); + } + } +#endif +#if defined(PNG_sBIT_SUPPORTED) + { + png_color_8p sig_bit; + + if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) + { + png_set_sBIT(write_ptr, write_info_ptr, sig_bit); + } + } +#endif +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + { + int unit; + double scal_width, scal_height; + + if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) + { + png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); + } + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + { + int unit; + png_charp scal_width, scal_height; + + if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) + { + png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height); + } + } +#endif +#endif +#endif +#if defined(PNG_TEXT_SUPPORTED) + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) + { + png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text); + png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); + } + } +#endif +#if defined(PNG_tIME_SUPPORTED) + { + png_timep mod_time; + + if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) + { + png_set_tIME(write_ptr, write_info_ptr, mod_time); +#if defined(PNG_TIME_RFC1123_SUPPORTED) + /* we have to use png_strcpy instead of "=" because the string + pointed to by png_convert_to_rfc1123() gets free'ed before + we use it */ + png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time)); + tIME_chunk_present++; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } +#endif +#if defined(PNG_tRNS_SUPPORTED) + { + png_bytep trans; + int num_trans; + png_color_16p trans_values; + + if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans, + &trans_values)) + { + png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans, + trans_values); + } + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + { + png_unknown_chunkp unknowns; + int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, + num_unknowns); + /* copy the locations from the read_info_ptr. The automatically + generated locations in write_info_ptr are wrong because we + haven't written anything yet */ + for (i = 0; i < (png_size_t)num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_info_ptr, i, + unknowns[i].location); + } + } +#endif + +#ifdef PNG_WRITE_SUPPORTED + png_debug(0, "\nWriting info struct\n"); + +/* If we wanted, we could write info in two steps: + png_write_info_before_PLTE(write_ptr, write_info_ptr); + */ + png_write_info(write_ptr, write_info_ptr); +#endif + +#ifdef SINGLE_ROWBUF_ALLOC + png_debug(0, "\nAllocating row buffer..."); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + png_debug1(0, "0x%08lx\n\n", (unsigned long)row_buf); +#endif /* SINGLE_ROWBUF_ALLOC */ + png_debug(0, "Writing row data\n"); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) + num_pass = png_set_interlace_handling(read_ptr); +# ifdef PNG_WRITE_SUPPORTED + png_set_interlace_handling(write_ptr); +# endif +#else + num_pass=1; +#endif + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; +#endif + for (pass = 0; pass < num_pass; pass++) + { + png_debug1(0, "Writing row data for pass %d\n",pass); + for (y = 0; y < height; y++) + { +#ifndef SINGLE_ROWBUF_ALLOC + png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass,y); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + png_debug2(0, "0x%08lx (%ld bytes)\n", (unsigned long)row_buf, + png_get_rowbytes(read_ptr, read_info_ptr)); +#endif /* !SINGLE_ROWBUF_ALLOC */ + png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1); + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_decode += (t_stop - t_start); + t_start = t_stop; +#endif + png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_encode += (t_stop - t_start); + t_start = t_stop; +#endif +#endif /* PNG_WRITE_SUPPORTED */ + +#ifndef SINGLE_ROWBUF_ALLOC + png_debug2(0, "Freeing row buffer (pass %d, y = %ld)\n\n", pass, y); + png_free(read_ptr, row_buf); +#endif /* !SINGLE_ROWBUF_ALLOC */ + } + } + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); +#endif + + png_debug(0, "Reading and writing end_info data\n"); + + png_read_end(read_ptr, end_info_ptr); +#if defined(PNG_TEXT_SUPPORTED) + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0) + { + png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text); + png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); + } + } +#endif +#if defined(PNG_tIME_SUPPORTED) + { + png_timep mod_time; + + if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) + { + png_set_tIME(write_ptr, write_end_info_ptr, mod_time); +#if defined(PNG_TIME_RFC1123_SUPPORTED) + /* we have to use png_strcpy instead of "=" because the string + pointed to by png_convert_to_rfc1123() gets free'ed before + we use it */ + png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time)); + tIME_chunk_present++; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + { + png_unknown_chunkp unknowns; + int num_unknowns; + num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, + num_unknowns); + /* copy the locations from the read_info_ptr. The automatically + generated locations in write_end_info_ptr are wrong because we + haven't written the end_info yet */ + for (i = 0; i < (png_size_t)num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i, + unknowns[i].location); + } + } +#endif +#ifdef PNG_WRITE_SUPPORTED + png_write_end(write_ptr, write_end_info_ptr); +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED + if(verbose) + { + png_uint_32 iwidth, iheight; + iwidth = png_get_image_width(write_ptr, write_info_ptr); + iheight = png_get_image_height(write_ptr, write_info_ptr); + fprintf(STDERR, "Image width = %lu, height = %lu\n", + iwidth, iheight); + } +#endif + + png_debug(0, "Destroying data structs\n"); +#ifdef SINGLE_ROWBUF_ALLOC + png_debug(1, "destroying row_buf for read_ptr\n"); + png_free(read_ptr, row_buf); + row_buf=NULL; +#endif /* SINGLE_ROWBUF_ALLOC */ + png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr\n"); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_debug(1, "destroying write_end_info_ptr\n"); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_debug(1, "destroying write_ptr, write_info_ptr\n"); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + png_debug(0, "Destruction complete.\n"); + + FCLOSE(fpin); + FCLOSE(fpout); + + png_debug(0, "Opening files for comparison\n"); +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); + if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpin = fopen(inname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find file %s\n", inname); + return (1); + } + +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); + if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpout = fopen(outname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + for(;;) + { + png_size_t num_in, num_out; + + READFILE(fpin, inbuf, 1, num_in); + READFILE(fpout, outbuf, 1, num_out); + + if (num_in != num_out) + { + fprintf(STDERR, "\nFiles %s and %s are of a different size\n", + inname, outname); + if(wrote_question == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname,PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question=1; + } + FCLOSE(fpin); + FCLOSE(fpout); + return (0); + } + + if (!num_in) + break; + + if (png_memcmp(inbuf, outbuf, num_in)) + { + fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); + if(wrote_question == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname,PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question=1; + } + FCLOSE(fpin); + FCLOSE(fpout); + return (0); + } + } + + FCLOSE(fpin); + FCLOSE(fpout); + + return (0); +} + +/* input and output filenames */ +#ifdef RISCOS +static PNG_CONST char *inname = "pngtest/png"; +static PNG_CONST char *outname = "pngout/png"; +#else +static PNG_CONST char *inname = "pngtest.png"; +static PNG_CONST char *outname = "pngout.png"; +#endif + +int +main(int argc, char *argv[]) +{ + int multiple = 0; + int ierror = 0; + + fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); + fprintf(STDERR,"%s",png_get_copyright(NULL)); + /* Show the version of libpng used in building the library */ + fprintf(STDERR," library (%lu):%s", png_access_version_number(), + png_get_header_version(NULL)); + /* Show the version of libpng used in building the application */ + fprintf(STDERR," pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, + PNG_HEADER_VERSION_STRING); + fprintf(STDERR," png_sizeof(png_struct)=%ld, png_sizeof(png_info)=%ld\n", + (long)png_sizeof(png_struct), (long)png_sizeof(png_info)); + + /* Do some consistency checking on the memory allocation settings, I'm + not sure this matters, but it is nice to know, the first of these + tests should be impossible because of the way the macros are set + in pngconf.h */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n"); +#endif + /* I think the following can happen. */ +#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); +#endif + + if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) + { + fprintf(STDERR, + "Warning: versions are different between png.h and png.c\n"); + fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); + ++ierror; + } + + if (argc > 1) + { + if (strcmp(argv[1], "-m") == 0) + { + multiple = 1; + status_dots_requested = 0; + } + else if (strcmp(argv[1], "-mv") == 0 || + strcmp(argv[1], "-vm") == 0 ) + { + multiple = 1; + verbose = 1; + status_dots_requested = 1; + } + else if (strcmp(argv[1], "-v") == 0) + { + verbose = 1; + status_dots_requested = 1; + inname = argv[2]; + } + else + { + inname = argv[1]; + status_dots_requested = 0; + } + } + + if (!multiple && argc == 3+verbose) + outname = argv[2+verbose]; + + if ((!multiple && argc > 3+verbose) || (multiple && argc < 2)) + { + fprintf(STDERR, + "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", + argv[0], argv[0]); + fprintf(STDERR, + " reads/writes one PNG file (without -m) or multiple files (-m)\n"); + fprintf(STDERR, + " with -m %s is used as a temporary file\n", outname); + exit(1); + } + + if (multiple) + { + int i; +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + int allocation_now = current_allocation; +#endif + for (i=2; isize, + (unsigned int) pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + else + { + int i; + for (i=0; i<3; ++i) + { + int kerror; +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + int allocation_now = current_allocation; +#endif + if (i == 1) status_dots_requested = 1; + else if(verbose == 0)status_dots_requested = 0; + if (i == 0 || verbose == 1 || ierror != 0) + fprintf(STDERR, "Testing %s:",inname); + kerror = test_one_file(inname, outname); + if(kerror == 0) + { + if(verbose == 1 || i == 2) + { +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + int k; +#endif +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples); +#else + fprintf(STDERR, " PASS\n"); +#endif +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + for (k=0; k<256; k++) + if(filters_used[k]) + fprintf(STDERR, " Filter %d was used %lu times\n", + k,filters_used[k]); +#endif +#if defined(PNG_TIME_RFC1123_SUPPORTED) + if(tIME_chunk_present != 0) + fprintf(STDERR, " tIME = %s\n",tIME_string); +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } + else + { + if(verbose == 0 && i != 2) + fprintf(STDERR, "Testing %s:",inname); + fprintf(STDERR, " FAIL\n"); + ierror += kerror; + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + if (allocation_now != current_allocation) + fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", + current_allocation-allocation_now); + if (current_allocation != 0) + { + memory_infop pinfo = pinformation; + + fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", + current_allocation); + while (pinfo != NULL) + { + fprintf(STDERR," %lu bytes at %x\n", + pinfo->size, (unsigned int)pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; + fprintf(STDERR," CPU time used = %.3f seconds", + (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); + fprintf(STDERR," (decoding %.3f,\n", + t_decode/(float)CLOCKS_PER_SEC); + fprintf(STDERR," encoding %.3f ,", + t_encode/(float)CLOCKS_PER_SEC); + fprintf(STDERR," other %.3f seconds)\n\n", + t_misc/(float)CLOCKS_PER_SEC); +#endif + + if (ierror == 0) + fprintf(STDERR, "libpng passes test\n"); + else + fprintf(STDERR, "libpng FAILS test\n"); + return (int)(ierror != 0); +} + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef version_1_2_8 your_png_h_is_not_version_1_2_8; diff --git a/pngtrans.c b/pngtrans.c index d850ee7ac..9003a2109 100644 --- a/pngtrans.c +++ b/pngtrans.c @@ -1,9 +1,9 @@ /* pngtrans.c - transforms the data in a row (used by both readers and writers) * - * libpng 1.2.4 - July 8, 2002 + * libpng 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) */ @@ -100,7 +100,7 @@ png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc) else png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; - /* This should probably go in the "do_filler" routine. + /* This should probably go in the "do_read_filler" routine. * I attempted to do that in libpng-1.0.1a but that caused problems * so I restored it in libpng-1.0.2a */ @@ -118,6 +118,18 @@ png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc) png_ptr->usr_channels = 2; } } + +#if !defined(PNG_1_0_X) +/* Added to libpng-1.2.7 */ +void PNGAPI +png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_add_alpha\n"); + png_set_filler(png_ptr, filler, filler_loc); + png_ptr->transformations |= PNG_ADD_ALPHA; +} +#endif + #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ @@ -375,16 +387,15 @@ png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags) if (row != NULL && row_info != NULL) #endif { -/* - if (row_info->color_type == PNG_COLOR_TYPE_RGB || - row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) -*/ png_bytep sp=row; png_bytep dp=row; png_uint_32 row_width=row_info->width; png_uint_32 i; - if (row_info->channels == 4) + if ((row_info->color_type == PNG_COLOR_TYPE_RGB || + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + (flags & PNG_FLAG_STRIP_ALPHA))) && + row_info->channels == 4) { if (row_info->bit_depth == 8) { @@ -461,13 +472,11 @@ png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags) row_info->rowbytes = row_width * 6; } row_info->channels = 3; - row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; } -/* - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY || - row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) -*/ - else if (row_info->channels == 2) + else if ((row_info->color_type == PNG_COLOR_TYPE_GRAY || + (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + (flags & PNG_FLAG_STRIP_ALPHA))) && + row_info->channels == 2) { if (row_info->bit_depth == 8) { @@ -519,8 +528,9 @@ png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags) row_info->rowbytes = row_width * 2; } row_info->channels = 1; - row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; } + if (flags & PNG_FLAG_STRIP_ALPHA) + row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; } } #endif diff --git a/pngvcrd.c b/pngvcrd.c index 72c441213..940a7fc0f 100644 --- a/pngvcrd.c +++ b/pngvcrd.c @@ -2,9 +2,9 @@ * * For Intel x86 CPU and Microsoft Visual C++ compiler * - * libpng version 1.2.4 - July 8, 2002 + * libpng version 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * Copyright (c) 1998, Intel Corporation * * Contributed by Nirav Chhatrapati, Intel Corporation, 1998 @@ -115,15 +115,18 @@ png_combine_row(png_structp png_ptr, png_bytep row, int mask) png_debug(1,"in png_combine_row_asm\n"); if (mmx_supported == 2) { +#if !defined(PNG_1_0_X) /* this should have happened in png_init_mmx_flags() already */ png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif png_mmx_support(); } if (mask == 0xff) { png_memcpy(row, png_ptr->row_buf + 1, - (png_size_t)((png_ptr->width * png_ptr->row_info.pixel_depth + 7) >> 3)); + (png_size_t)PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->width)); } /* GRR: add "else if (mask == 0)" case? * or does png_combine_row() not even get called in that case? */ @@ -307,8 +310,12 @@ png_combine_row(png_structp png_ptr, png_bytep row, int mask) __int64 mask0=0x0102040810204080; +#if !defined(PNG_1_0_X) if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif { srcptr = png_ptr->row_buf + 1; dstptr = row; @@ -408,8 +415,12 @@ end8: __int64 mask1=0x0101020204040808, mask0=0x1010202040408080; +#if !defined(PNG_1_0_X) if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif { srcptr = png_ptr->row_buf + 1; dstptr = row; @@ -529,8 +540,12 @@ end16: len = (png_ptr->width)&~7; diff = (png_ptr->width)&7; +#if !defined(PNG_1_0_X) if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif { _asm { @@ -661,8 +676,12 @@ end24: len = (png_ptr->width)&~7; diff = (png_ptr->width)&7; +#if !defined(PNG_1_0_X) if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif { _asm { @@ -796,8 +815,12 @@ end32: mask1=0x2020202040404040, mask0=0x4040808080808080; +#if !defined(PNG_1_0_X) if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif { srcptr = png_ptr->row_buf + 1; dstptr = row; @@ -987,8 +1010,10 @@ png_do_read_interlace(png_structp png_ptr) png_debug(1,"in png_do_read_interlace\n"); if (mmx_supported == 2) { +#if !defined(PNG_1_0_X) /* this should have happened in png_init_mmx_flags() already */ png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif png_mmx_support(); } @@ -1189,8 +1214,12 @@ png_do_read_interlace(png_structp png_ptr) // NOTE: there is NO MMX code for 48-bit and 64-bit images // use MMX routine if machine supports it +#if !defined(PNG_1_0_X) if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE) /* && mmx_supported */ ) +#else + if (mmx_supported) +#endif { if (pixel_bytes == 3) { @@ -1874,8 +1903,8 @@ loop4_pass4: } /* end switch (row_info->pixel_depth) */ row_info->width = final_width; - row_info->rowbytes = ((final_width * - (png_uint_32)row_info->pixel_depth + 7) >> 3); + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width); } } @@ -3603,7 +3632,7 @@ duploop: jz dupend - // 2 lines added by lcreeve@netins.net + // 2 lines added by lcreeve at netins.net // (mail 11 Jul 98 in png-implement list) cmp edx, 8 //test for less than 8 bytes jb duplt8 @@ -3652,8 +3681,10 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep #endif if (mmx_supported == 2) { +#if !defined(PNG_1_0_X) /* this should have happened in png_init_mmx_flags() already */ png_warning(png_ptr, "asm_flags may not have been initialized"); +#endif png_mmx_support(); } @@ -3663,6 +3694,7 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep { case 0: sprintf(filnm, "none"); break; +#if !defined(PNG_1_0_X) case 1: sprintf(filnm, "sub-%s", (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "MMX" : "x86"); break; @@ -3675,6 +3707,16 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep case 4: sprintf(filnm, "Paeth-%s", (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "MMX":"x86"); break; +#else + case 1: sprintf(filnm, "sub"); + break; + case 2: sprintf(filnm, "up"); + break; + case 3: sprintf(filnm, "avg"); + break; + case 4: sprintf(filnm, "Paeth"); + break; +#endif default: sprintf(filnm, "unknw"); break; } @@ -3691,9 +3733,13 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep case PNG_FILTER_VALUE_SUB: { +#if !defined(PNG_1_0_X) if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) && (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (mmx_supported) +#endif { png_read_filter_row_mmx_sub(row_info, row); } @@ -3716,9 +3762,13 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep case PNG_FILTER_VALUE_UP: { +#if !defined(PNG_1_0_X) if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) && (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (mmx_supported) +#endif { png_read_filter_row_mmx_up(row_info, row, prev_row); } @@ -3740,9 +3790,13 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep case PNG_FILTER_VALUE_AVG: { +#if !defined(PNG_1_0_X) if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) && (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (mmx_supported) +#endif { png_read_filter_row_mmx_avg(row_info, row, prev_row); } @@ -3774,9 +3828,13 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep case PNG_FILTER_VALUE_PAETH: { +#if !defined(PNG_1_0_X) if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) && (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) && (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold)) +#else + if (mmx_supported) +#endif { png_read_filter_row_mmx_paeth(row_info, row, prev_row); } diff --git a/pngwio.c b/pngwio.c index f356b7d4a..d5d61f49e 100644 --- a/pngwio.c +++ b/pngwio.c @@ -1,9 +1,9 @@ /* pngwio.c - functions for data output * - * libpng 1.2.4 - July 8, 2002 + * libpng 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * diff --git a/pngwrite.c b/pngwrite.c index ff62395cf..3246fdaaf 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -1,9 +1,9 @@ /* pngwrite.c - general routines to write a PNG file * - * libpng 1.2.4 - July 8, 2002 + * libpng 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) */ @@ -104,9 +104,10 @@ png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) up++) { int keep=png_handle_as_unknown(png_ptr, up->name); - if (keep != HANDLE_CHUNK_NEVER && - up->location && (!(up->location & PNG_HAVE_PLTE)) && - ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS || + if (keep != PNG_HANDLE_CHUNK_NEVER && + up->location && !(up->location & PNG_HAVE_PLTE) && + !(up->location & PNG_HAVE_IDAT) && + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) { png_write_chunk(png_ptr, up->name, up->data, up->size); @@ -267,10 +268,10 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) up++) { int keep=png_handle_as_unknown(png_ptr, up->name); - if (keep != HANDLE_CHUNK_NEVER && + if (keep != PNG_HANDLE_CHUNK_NEVER && up->location && (up->location & PNG_HAVE_PLTE) && !(up->location & PNG_HAVE_IDAT) && - ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS || + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) { png_write_chunk(png_ptr, up->name, up->data, up->size); @@ -367,9 +368,9 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) up++) { int keep=png_handle_as_unknown(png_ptr, up->name); - if (keep != HANDLE_CHUNK_NEVER && + if (keep != PNG_HANDLE_CHUNK_NEVER && up->location && (up->location & PNG_AFTER_IDAT) && - ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS || + ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) { png_write_chunk(png_ptr, up->name, up->data, up->size); @@ -457,6 +458,12 @@ png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, #endif #endif /* PNG_1_0_X */ + /* added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max=PNG_USER_WIDTH_MAX; + png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; +#endif + #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) @@ -470,7 +477,7 @@ png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, return (NULL); } #ifdef USE_FAR_KEYWORD - png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf)); + png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf)); #endif #endif @@ -537,7 +544,7 @@ png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, #ifdef USE_FAR_KEYWORD if (setjmp(jmpbuf)) PNG_ABORT(); - png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf)); + png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf)); #else if (setjmp(png_ptr->jmpbuf)) PNG_ABORT(); @@ -561,7 +568,8 @@ png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver, { /* We only come here via pre-1.0.12-compiled applications */ #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) - if(sizeof(png_struct) > png_struct_size || sizeof(png_info) > png_info_size) + if(png_sizeof(png_struct) > png_struct_size || + png_sizeof(png_info) > png_info_size) { char msg[80]; png_ptr->warning_fn=NULL; @@ -576,7 +584,7 @@ png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver, png_warning(png_ptr, msg); } #endif - if(sizeof(png_struct) > png_struct_size) + if(png_sizeof(png_struct) > png_struct_size) { png_ptr->error_fn=NULL; #ifdef PNG_ERROR_NUMBERS_SUPPORTED @@ -585,7 +593,7 @@ png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver, png_error(png_ptr, "The png struct allocated by the application for writing is too small."); } - if(sizeof(png_info) > png_info_size) + if(png_sizeof(png_info) > png_info_size) { png_ptr->error_fn=NULL; #ifdef PNG_ERROR_NUMBERS_SUPPORTED @@ -626,10 +634,10 @@ png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, #ifdef PNG_SETJMP_SUPPORTED /* save jump buffer and error functions */ - png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf)); #endif - if (sizeof(png_struct) > png_struct_size) + if (png_sizeof(png_struct) > png_struct_size) { png_destroy_struct(png_ptr); png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); @@ -637,7 +645,13 @@ png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, } /* reset all variables to 0 */ - png_memset(png_ptr, 0, sizeof (png_struct)); + png_memset(png_ptr, 0, png_sizeof (png_struct)); + + /* added at libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_ptr->user_width_max=PNG_USER_WIDTH_MAX; + png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; +#endif #if !defined(PNG_1_0_X) #ifdef PNG_ASSEMBLER_CODE_SUPPORTED @@ -647,7 +661,7 @@ png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, #ifdef PNG_SETJMP_SUPPORTED /* restore jump buffer */ - png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf)); #endif png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, @@ -827,8 +841,8 @@ png_write_row(png_structp png_ptr, png_bytep row) png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * png_ptr->row_info.channels); - png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * - (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); + png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, + png_ptr->row_info.width); png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type); png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width); @@ -1049,7 +1063,7 @@ png_write_destroy(png_structp png_ptr) #ifdef PNG_SETJMP_SUPPORTED /* reset structure */ - png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); + png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf)); #endif error_fn = png_ptr->error_fn; @@ -1059,7 +1073,7 @@ png_write_destroy(png_structp png_ptr) free_fn = png_ptr->free_fn; #endif - png_memset(png_ptr, 0, sizeof (png_struct)); + png_memset(png_ptr, 0, png_sizeof (png_struct)); png_ptr->error_fn = error_fn; png_ptr->warning_fn = warning_fn; @@ -1069,7 +1083,7 @@ png_write_destroy(png_structp png_ptr) #endif #ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); + png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf)); #endif } @@ -1211,7 +1225,7 @@ png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, if (png_ptr->prev_filters == NULL) { png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(sizeof(png_byte) * num_weights)); + (png_uint_32)(png_sizeof(png_byte) * num_weights)); /* To make sure that the weighting starts out fairly */ for (i = 0; i < num_weights; i++) @@ -1223,10 +1237,10 @@ png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, if (png_ptr->filter_weights == NULL) { png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(sizeof(png_uint_16) * num_weights)); + (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(sizeof(png_uint_16) * num_weights)); + (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); for (i = 0; i < num_weights; i++) { png_ptr->inv_filter_weights[i] = @@ -1257,10 +1271,10 @@ png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, if (png_ptr->filter_costs == NULL) { png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) { diff --git a/pngwtran.c b/pngwtran.c index d15c0c55c..f1c8b3e62 100644 --- a/pngwtran.c +++ b/pngwtran.c @@ -1,9 +1,9 @@ /* pngwtran.c - transforms the data in a row for PNG writers * - * libpng 1.2.4 - July 8, 2002 + * libpng version 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) */ @@ -195,8 +195,8 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) } row_info->bit_depth = (png_byte)bit_depth; row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); - row_info->rowbytes = - ((row_info->width * row_info->pixel_depth + 7) >> 3); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); } } #endif @@ -546,15 +546,15 @@ png_do_write_intrapixel(png_row_infop row_info, png_bytep row) for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) { - png_uint_32 s0=*(rp )<<8 | *(rp+1); - png_uint_32 s1=*(rp+2)<<8 | *(rp+3); - png_uint_32 s2=*(rp+4)<<8 | *(rp+5); - png_uint_32 red=(s0-s1)&0xffff; - png_uint_32 blue=(s2-s1)&0xffff; - *(rp ) = (png_byte)((red>>8)&0xff); - *(rp+1) = (png_byte)(red&0xff); - *(rp+4) = (png_byte)((blue>>8)&0xff); - *(rp+5) = (png_byte)(blue&0xff); + png_uint_32 s0 = (*(rp ) << 8) | *(rp+1); + png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3); + png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5); + png_uint_32 red = (png_uint_32)((s0-s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2-s1) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp+1) = (png_byte)(red & 0xff); + *(rp+4) = (png_byte)((blue >> 8) & 0xff); + *(rp+5) = (png_byte)(blue & 0xff); } } } diff --git a/pngwutil.c b/pngwutil.c index 22155e93f..dd7b150b7 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -1,9 +1,9 @@ /* pngwutil.c - utilities to write a PNG file * - * libpng 1.2.4 - July 8, 2002 + * libpng version 1.2.8 - December 3, 2004 * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * Copyright (c) 1998-2004 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) */ @@ -219,7 +219,7 @@ png_text_compress(png_structp png_ptr, png_error(png_ptr, "zlib error"); } /* check to see if we need more room */ - if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in) + if (!(png_ptr->zstream.avail_out)) { /* make sure the output array has room */ if (comp->num_output_ptr >= comp->max_output_ptr) @@ -234,14 +234,16 @@ png_text_compress(png_structp png_ptr, old_ptr = comp->output_ptr; comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp))); + (png_uint_32)(comp->max_output_ptr * + png_sizeof (png_charpp))); png_memcpy(comp->output_ptr, old_ptr, old_max - * sizeof (png_charp)); + * png_sizeof (png_charp)); png_free(png_ptr, old_ptr); } else comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_uint_32)(comp->max_output_ptr * sizeof (png_charp))); + (png_uint_32)(comp->max_output_ptr * + png_sizeof (png_charp))); } /* save the data */ @@ -283,14 +285,16 @@ png_text_compress(png_structp png_ptr, old_ptr = comp->output_ptr; /* This could be optimized to realloc() */ comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp))); + (png_uint_32)(comp->max_output_ptr * + png_sizeof (png_charpp))); png_memcpy(comp->output_ptr, old_ptr, - old_max * sizeof (png_charp)); + old_max * png_sizeof (png_charp)); png_free(png_ptr, old_ptr); } else comp->output_ptr = (png_charpp)png_malloc(png_ptr, - (png_uint_32)(comp->max_output_ptr * sizeof (png_charp))); + (png_uint_32)(comp->max_output_ptr * + png_sizeof (png_charp))); } /* save off the data */ @@ -353,9 +357,9 @@ png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) png_write_chunk_data(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - png_ptr->zstream.avail_out); - /* reset zlib for another zTXt/iTXt or the image data */ + /* reset zlib for another zTXt/iTXt or image data */ deflateReset(&png_ptr->zstream); - + png_ptr->zstream.data_type = Z_BINARY; } #endif @@ -464,11 +468,12 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, #if defined(PNG_MNG_FEATURES_SUPPORTED) png_ptr->filter_type = (png_byte)filter_type; #endif + png_ptr->compression_type = (png_byte)compression_type; png_ptr->width = width; png_ptr->height = height; png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); - png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); /* set the usr info, so any transformations can modify it */ png_ptr->usr_width = png_ptr->width; png_ptr->usr_bit_depth = png_ptr->bit_depth; @@ -518,6 +523,9 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, png_ptr->zlib_mem_level, png_ptr->zlib_strategy); png_ptr->zstream.next_out = png_ptr->zbuf; png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + /* libpng is not interested in zstream.data_type */ + /* set it to a predefined value, to avoid its evaluation inside zlib */ + png_ptr->zstream.data_type = Z_BINARY; png_ptr->mode = PNG_HAVE_IHDR; } @@ -596,6 +604,46 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) PNG_IDAT; #endif png_debug(1, "in png_write_IDAT\n"); + + /* Optimize the CMF field in the zlib stream. */ + /* This hack of the zlib stream is compliant to the stream specification. */ + if (!(png_ptr->mode & PNG_HAVE_IDAT) && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + { + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + { + /* Avoid memory underflows and multiplication overflows. */ + /* The conditions below are practically always satisfied; + however, they still must be checked. */ + if (length >= 2 && + png_ptr->height < 16384 && png_ptr->width < 16384) + { + png_uint_32 uncompressed_idat_size = png_ptr->height * + ((png_ptr->width * + png_ptr->channels * png_ptr->bit_depth + 15) >> 3); + unsigned int z_cinfo = z_cmf >> 4; + unsigned int half_z_window_size = 1 << (z_cinfo + 7); + while (uncompressed_idat_size <= half_z_window_size && + half_z_window_size >= 256) + { + z_cinfo--; + half_z_window_size >>= 1; + } + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + if (data[0] != (png_byte)z_cmf) + { + data[0] = (png_byte)z_cmf; + data[1] &= 0xe0; + data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f); + } + } + } + else + png_error(png_ptr, + "Invalid zlib compression method or flags in IDAT"); + } + png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length); png_ptr->mode |= PNG_HAVE_IDAT; } @@ -1141,7 +1189,12 @@ png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key) png_debug1(2, "Keyword to be checked is '%s'\n", key); - *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 2)); + *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); + if (*new_key == NULL) + { + png_warning(png_ptr, "Out of memory while procesing keyword"); + return ((png_size_t)0); + } /* Replace non-printing characters with a blank and print a warning */ for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++) @@ -1353,7 +1406,7 @@ png_write_iTXt(png_structp png_ptr, int compression, png_charp key, { png_warning(png_ptr, "Empty language field in iTXt chunk"); new_lang = NULL; - lang_len = 0; + lang_len = 0; } if (lang_key == NULL) @@ -1461,7 +1514,7 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, total_len = purpose_len + units_len + 10; params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams - *sizeof(png_uint_32))); + *png_sizeof(png_uint_32))); /* Find the length of each parameter, making sure we don't count the null terminator for the last parameter. */ @@ -1506,6 +1559,7 @@ png_write_sCAL(png_structp png_ptr, int unit, double width,double height) #endif png_size_t total_len; char wbuf[32], hbuf[32]; + png_byte bunit = unit; png_debug(1, "in png_write_sCAL\n"); @@ -1526,7 +1580,7 @@ png_write_sCAL(png_structp png_ptr, int unit, double width,double height) png_debug1(3, "sCAL total length = %d\n", (int)total_len); png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len); - png_write_chunk_data(png_ptr, (png_bytep)&unit, 1); + png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1); png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1); png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf)); @@ -1543,6 +1597,7 @@ png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, #endif png_size_t total_len; char wbuf[32], hbuf[32]; + png_byte bunit = unit; png_debug(1, "in png_write_sCAL_s\n"); @@ -1552,7 +1607,7 @@ png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, png_debug1(3, "sCAL total length = %d\n", total_len); png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len); - png_write_chunk_data(png_ptr, (png_bytep)&unit, 1); + png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1); png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1); png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf)); @@ -1641,8 +1696,8 @@ png_write_start_row(png_structp png_ptr) png_size_t buf_size; png_debug(1, "in png_write_start_row\n"); - buf_size = (png_size_t)(((png_ptr->width * png_ptr->usr_channels * - png_ptr->usr_bit_depth + 7) >> 3) + 1); + buf_size = (png_size_t)(PNG_ROWBYTES( + png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1); /* set up row buffer */ png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size); @@ -1778,9 +1833,8 @@ png_write_finish_row(png_structp png_ptr) { if (png_ptr->prev_row != NULL) png_memset(png_ptr->prev_row, 0, - (png_size_t) (((png_uint_32)png_ptr->usr_channels * - (png_uint_32)png_ptr->usr_bit_depth * - png_ptr->width + 7) >> 3) + 1); + (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* + png_ptr->usr_bit_depth,png_ptr->width))+1); return; } } @@ -1820,6 +1874,7 @@ png_write_finish_row(png_structp png_ptr) } deflateReset(&png_ptr->zstream); + png_ptr->zstream.data_type = Z_BINARY; } #if defined(PNG_WRITE_INTERLACING_SUPPORTED) @@ -1987,8 +2042,8 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) png_pass_inc[pass] - 1 - png_pass_start[pass]) / png_pass_inc[pass]; - row_info->rowbytes = ((row_info->width * - row_info->pixel_depth + 7) >> 3); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); } } #endif @@ -1997,7 +2052,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) * been specified by the application, and then writes the row out with the * chosen filter. */ -#define PNG_MAXSUM (~((png_uint_32)0) >> 1) +#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) #define PNG_HISHIFT 10 #define PNG_LOMASK ((png_uint_32)0xffffL) #define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) @@ -2014,7 +2069,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) png_debug(1, "in png_write_find_filter\n"); /* find out how many bytes offset each pixel is */ - bpp = (row_info->pixel_depth + 7) / 8; + bpp = (row_info->pixel_depth + 7) >> 3; prev_row = png_ptr->prev_row; best_row = row_buf = png_ptr->row_buf; @@ -2165,7 +2220,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) sum += (v < 128) ? v : 256 - v; } - for (lp = row_buf + 1; i < row_info->rowbytes; + for (lp = row_buf + 1; i < row_bytes; i++, rp++, lp++, dp++) { v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); diff --git a/trees.c b/trees.c index f01fb30d8..395e4e168 100644 --- a/trees.c +++ b/trees.c @@ -1,6 +1,6 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-1998 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h */ /* @@ -230,7 +230,6 @@ local void send_bits(s, value, length) #endif /* DEBUG */ -#define MAX(a,b) (a >= b ? a : b) /* the arguments must not have side effects */ /* =========================================================================== @@ -335,42 +334,42 @@ void gen_trees_header() Assert (header != NULL, "Can't open trees.h"); fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); + "/* header created automatically with -DGEN_TREES_H */\n\n"); fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); } fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); } fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); } fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); } fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); } fprintf(header, "local const int base_dist[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); } fclose(header); @@ -556,7 +555,7 @@ local void gen_bitlen(s, desc) while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; - if (tree[m].Len != (unsigned) bits) { + if ((unsigned) tree[m].Len != (unsigned) bits) { Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((long)bits - (long)tree[m].Len) *(long)tree[m].Freq; @@ -675,7 +674,8 @@ local void build_tree(s, desc) /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { @@ -930,39 +930,40 @@ void _tr_flush_block(s, buf, stored_len, eof) /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { - /* Check if the file is ascii or binary */ - if (s->data_type == Z_UNKNOWN) set_data_type(s); + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); - /* Determine the best encoding. Compute first the block length in bytes*/ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED @@ -982,7 +983,7 @@ void _tr_flush_block(s, buf, stored_len, eof) #ifdef FORCE_STATIC } else if (static_lenb >= 0) { /* force static trees */ #else - } else if (static_lenb == opt_lenb) { + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+eof, 3); compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); @@ -1107,7 +1108,8 @@ local void compress_block(s, ltree, dtree) } /* literal or match pair ? */ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); } while (lx < s->last_lit); @@ -1116,21 +1118,24 @@ local void compress_block(s, ltree, dtree) } /* =========================================================================== - * Set the data type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. */ local void set_data_type(s) deflate_state *s; { - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; - while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; - while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; - s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; } /* =========================================================================== @@ -1199,7 +1204,7 @@ local void copy_block(s, buf, len, header) s->last_eob_len = 8; /* enough lookahead for inflate */ if (header) { - put_short(s, (ush)len); + put_short(s, (ush)len); put_short(s, (ush)~len); #ifdef DEBUG s->bits_sent += 2*16; diff --git a/uncompr.c b/uncompr.c index d10332137..b59e3d0de 100644 --- a/uncompr.c +++ b/uncompr.c @@ -1,10 +1,11 @@ /* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-1998 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ +#define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== @@ -49,7 +50,9 @@ int ZEXPORT uncompress (dest, destLen, source, sourceLen) err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; } *destLen = stream.total_out; diff --git a/zconf.h b/zconf.h index 6d450fc79..03a9431c8 100644 --- a/zconf.h +++ b/zconf.h @@ -1,102 +1,135 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ -#ifndef _ZCONF_H -#define _ZCONF_H +#ifndef ZCONF_H +#define ZCONF_H /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. */ #ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateReset z_inflateReset -# define compress z_compress -# define compress2 z_compress2 -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp #endif -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) -# define WIN32 -#endif -#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) -# ifndef __32BIT__ -# define __32BIT__ -# endif -#endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif /* * Compile with -DMAXSEG_64K if the alloc function cannot allocate more * than 64k bytes at a time (needed on systems with 16-bit int). */ -#if defined(MSDOS) && !defined(__32BIT__) +#ifdef SYS16BIT # define MAXSEG_64K #endif #ifdef MSDOS # define UNALIGNED_OK #endif -#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) -# define STDC -#endif -#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) +#ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC #endif #ifndef STDC # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const +# define const /* note: need a more gentle solution here */ # endif #endif /* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) # define NO_DUMMY_DECL #endif -/* Old Borland C incorrectly complains about missing returns: */ -#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) -# define NEED_DUMMY_RETURN -#endif - - /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K @@ -144,73 +177,87 @@ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ -#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -#endif -#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) -# ifndef __32BIT__ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ # define SMALL_MEDIUM -# define FAR _far +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif # endif #endif -/* Compile with -DZLIB_DLL for Windows DLL support */ -#if defined(ZLIB_DLL) -# if defined(_WINDOWS) || defined(WINDOWS) +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # include -# define ZEXPORT WINAPI + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI # ifdef WIN32 -# define ZEXPORTVA WINAPIV +# define ZEXPORTVA WINAPIV # else -# define ZEXPORTVA FAR _cdecl _export -# endif -# endif -# if defined (__BORLANDC__) -# if (__BORLANDC__ >= 0x0500) && defined (WIN32) -# include -# define ZEXPORT __declspec(dllexport) WINAPI -# define ZEXPORTRVA __declspec(dllexport) WINAPIV -# else -# if defined (_Windows) && defined (__DLL__) -# define ZEXPORT _export -# define ZEXPORTVA _export -# endif +# define ZEXPORTVA FAR CDECL # endif # endif #endif #if defined (__BEOS__) -# if defined (ZLIB_DLL) -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif # endif #endif +#ifndef ZEXTERN +# define ZEXTERN extern +#endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif -#ifndef ZEXTERN -# define ZEXTERN extern -#endif #ifndef FAR -# define FAR +# define FAR #endif -#if !defined(MACOS) && !defined(TARGET_OS_MAC) +#if !defined(__MACTYPES__) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ @@ -228,17 +275,22 @@ typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC - typedef void FAR *voidpf; - typedef void *voidp; + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; #else - typedef Byte FAR *voidpf; - typedef Byte *voidp; + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; #endif -#ifdef HAVE_UNISTD_H +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ # include /* for off_t */ # include /* for SEEK_* and off_t */ -# define z_off_t off_t +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t #endif #ifndef SEEK_SET # define SEEK_SET 0 /* Seek from beginning of file. */ @@ -246,7 +298,18 @@ typedef uLong FAR uLongf; # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif #ifndef z_off_t -# define z_off_t long +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif #endif /* MVS linker does not support external names larger than 8 bytes */ @@ -254,26 +317,16 @@ typedef uLong FAR uLongf; # pragma map(deflateInit_,"DEIN") # pragma map(deflateInit2_,"DEIN2") # pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") # pragma map(inflateInit_,"ININ") # pragma map(inflateInit2_,"ININ2") # pragma map(inflateEnd,"INEND") # pragma map(inflateSync,"INSY") # pragma map(inflateSetDictionary,"INSEDI") -# pragma map(inflate_blocks,"INBL") -# pragma map(inflate_blocks_new,"INBLNE") -# pragma map(inflate_blocks_free,"INBLFR") -# pragma map(inflate_blocks_reset,"INBLRE") -# pragma map(inflate_codes_free,"INCOFR") -# pragma map(inflate_codes,"INCO") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") # pragma map(inflate_fast,"INFA") -# pragma map(inflate_flush,"INFLU") -# pragma map(inflate_mask,"INMA") -# pragma map(inflate_set_dictionary,"INSEDI2") # pragma map(inflate_copyright,"INCOPY") -# pragma map(inflate_trees_bits,"INTRBI") -# pragma map(inflate_trees_dynamic,"INTRDY") -# pragma map(inflate_trees_fixed,"INTRFI") -# pragma map(inflate_trees_free,"INTRFR") #endif -#endif /* _ZCONF_H */ +#endif /* ZCONF_H */ diff --git a/zconf.in.h b/zconf.in.h new file mode 100644 index 000000000..03a9431c8 --- /dev/null +++ b/zconf.in.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/zlib.h b/zlib.h index 00456bc52..022817927 100644 --- a/zlib.h +++ b/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.1.4pc, March 2002 + version 1.2.3, July 18th, 2005 - Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -24,26 +24,12 @@ The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). */ -/* Changes from version 1.1.4 to version 1.1.4pc - * - * The default value of TOO_FAR has been changed to 32767 in deflate.c - * Glenn Randers-Pehrson, February 2000. - * - * The switch statement in inflate.c was rearranged so that case BLOCKS is - * checked first. Glenn Randers-Pehrson, April 2001. - * - * Added tests for Windows platforms at line 136 in zutil.h, since some - * emulators will use MSC compiler on other platforms. Glenn Randers-Pehrson, - * May 2001. Suggested by Emmanuel Blot. - * - */ - -#ifndef _ZLIB_H -#define _ZLIB_H +#ifndef ZLIB_H +#define ZLIB_H #include "zconf.h" @@ -51,9 +37,10 @@ extern "C" { #endif -#define ZLIB_VERSION "1.1.4pc" +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 -/* +/* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method @@ -66,8 +53,21 @@ extern "C" { application must provide more input and/or consume the output (providing more output space) before each call. + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio. + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never @@ -95,13 +95,36 @@ typedef struct z_stream_s { free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ - int data_type; /* best guess about the data type: ascii or binary */ + int data_type; /* best guess about the data type: binary or text */ uLong adler; /* adler32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out @@ -141,7 +164,8 @@ typedef z_stream FAR *z_streamp; #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 -/* Allowed flush values; see deflate() below for details */ +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 @@ -164,13 +188,16 @@ typedef z_stream FAR *z_streamp; #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 -#define Z_ASCII 1 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 -/* Possible values of the data_type field */ +/* Possible values of the data_type field (though see inflate()) */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ @@ -189,7 +216,7 @@ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); This check is automatically made by deflateInit and inflateInit. */ -/* +/* ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields @@ -242,6 +269,10 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular @@ -253,12 +284,14 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - the compression. + compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero - avail_out). + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there @@ -267,17 +300,17 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. - + Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least - 0.1% larger than avail_in plus 12 bytes. If deflate does not return + the value returned by deflateBound (see below). If deflate does not return Z_STREAM_END, then it must be called again as described above. deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. @@ -286,7 +319,9 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. */ @@ -304,7 +339,7 @@ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); */ -/* +/* ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields @@ -328,9 +363,9 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may some - introduce some output latency (reading input without producing any output) - except when forced to flush. + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: @@ -354,11 +389,26 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); must be called again after making room in the output buffer because there might be more output pending. - If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much - output as possible to the output buffer. The flushing behavior of inflate is - not specified for values of the flush parameter other than Z_SYNC_FLUSH - and Z_FINISH, but the current implementation actually flushes as much output - as possible anyway. + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step @@ -368,29 +418,44 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); uncompressed data. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The next operation on this stream must be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster routine + is never required, but can be used to inform inflate that a faster approach may be used for the single inflate() call. - If a preset dictionary is needed at this point (see inflateSetDictionary - below), inflate sets strm-adler to the adler32 checksum of the - dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise - it sets strm->adler to the adler32 checksum of all output produced - so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or - an error code as described below. At the end of the stream, inflate() - checks that its computed adler32 checksum is equal to that saved by the - compressor and returns Z_STREAM_END only if the checksum is correct. + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect - adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent - (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if no progress is possible or if there was not - enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR - case, the application may then call inflateSync to look for a good - compression block. + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. */ @@ -411,7 +476,7 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); The following functions are needed only in some special applications. */ -/* +/* ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, int level, int method, @@ -427,11 +492,22 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, this version of the library. The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this + (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory @@ -440,21 +516,25 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match). Filtered data consists mostly of small values with a - somewhat random distribution. In this case, the compression algorithm is - tuned to compress them better. The effect of Z_FILTERED is to force more - Huffman coding and less string matching; it is somewhat intermediate - between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects - the compression ratio but not the correctness of the compressed output even - if it is not set appropriately. + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid method). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ - + ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); @@ -476,13 +556,16 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size in deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. - Upon return of this function, strm->adler is set to the Adler32 value + Upon return of this function, strm->adler is set to the adler32 value of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The Adler32 value + which dictionary has been used by the compressor. (The adler32 value applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is @@ -521,8 +604,8 @@ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); */ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); + int level, + int strategy)); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2. This can be @@ -541,7 +624,73 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, if strm->avail_out was zero. */ -/* +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); @@ -552,16 +701,36 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used - instead. If a compressed stream with a larger window size is given as - input, inflate() will return with the error code Z_DATA_ERROR instead of - trying to allocate a larger window. + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative - memLevel). msg is set to null if there is no error message. inflateInit2 - does not perform any decompression apart from reading the zlib header if - present: this will be done by inflate(). (So next_in and avail_in may be - modified, but next_out and avail_out are unchanged.) + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, @@ -569,22 +738,25 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate - if this call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the Adler32 value returned by this call of - inflate. The compressor and decompressor must use exactly the same - dictionary (see deflateSetDictionary). + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect Adler32 value). inflateSetDictionary does not + expected one (incorrect adler32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* +/* Skips invalid compressed data until a full flush point (see above the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. @@ -598,6 +770,22 @@ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); until success or end of the input data. */ +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, @@ -608,6 +796,205 @@ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); stream state was inconsistent (such as zalloc or state being NULL). */ +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + /* utility functions */ @@ -624,8 +1011,8 @@ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least 0.1% larger than - sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. This function can be used to compress a whole file at once if the input file is mmap'ed. @@ -641,14 +1028,22 @@ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* @@ -664,7 +1059,7 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. */ @@ -675,8 +1070,9 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h". (See the description - of deflateInit2 for more information about the strategy parameter.) + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. @@ -715,8 +1111,8 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); gzread returns the number of uncompressed bytes actually read (0 for end of file, -1 for error). */ -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - const voidp buf, unsigned len)); +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes actually written @@ -727,7 +1123,13 @@ ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); /* Converts, formats, and writes the args to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); @@ -758,6 +1160,16 @@ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); or -1 in case of end of file or error. */ +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); /* Flushes all pending output into the compressed file. The parameter @@ -769,8 +1181,8 @@ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); */ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* + z_off_t offset, int whence)); +/* Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); @@ -808,6 +1220,12 @@ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); input stream, otherwise zero. */ +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file @@ -824,6 +1242,13 @@ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); to get the exact error code. */ +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + /* checksum functions */ /* @@ -833,7 +1258,6 @@ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); - /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is NULL, this function returns @@ -849,12 +1273,21 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); if (adler != original_adler) error(); */ +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* - Update a running crc with the bytes buf[0..len-1] and return the updated - crc. If buf is NULL, this function returns the required initial value - for the crc. Pre- and post-conditioning (one's complement) is performed - within this function so it shouldn't be done by the application. + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); @@ -865,6 +1298,16 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); if (crc != original_crc) error(); */ +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + /* various hacks, don't look :) */ @@ -881,6 +1324,10 @@ ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); #define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) #define inflateInit(strm) \ @@ -890,13 +1337,16 @@ ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, (strategy), ZLIB_VERSION, sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) -#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; /* hack for buggy compilers */ #endif -ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); @@ -904,4 +1354,4 @@ ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); } #endif -#endif /* _ZLIB_H */ +#endif /* ZLIB_H */ diff --git a/zutil.c b/zutil.c index d0a9da58f..d55f5948a 100644 --- a/zutil.c +++ b/zutil.c @@ -1,19 +1,17 @@ /* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" +#ifndef NO_DUMMY_DECL struct internal_state {int dummy;}; /* for buggy compilers */ - -#ifndef STDC -extern void exit OF((int)); #endif -const char *z_errmsg[10] = { +const char * const z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ "", /* Z_OK 0 */ @@ -31,6 +29,89 @@ const char * ZEXPORT zlibVersion() return ZLIB_VERSION; } +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + #ifdef DEBUG # ifndef verbose @@ -55,6 +136,13 @@ const char * ZEXPORT zError(err) return ERR_MSG(err); } +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif #ifndef HAVE_MEMCPY @@ -93,11 +181,12 @@ void zmemzero(dest, len) } #endif + +#ifdef SYS16BIT + #ifdef __TURBOC__ -#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) -/* Small and medium model in Turbo C are for now limited to near allocation - * with reduced MAX_WBITS and MAX_MEM_LEVEL - */ +/* Turbo C in 16-bit mode */ + # define MY_ZCALLOC /* Turbo C malloc() does not allow dynamic allocation of 64K bytes @@ -169,11 +258,11 @@ void zcfree (voidpf opaque, voidpf ptr) ptr = opaque; /* just to make some compilers happy */ Assert(0, "zcfree: ptr not found"); } -#endif + #endif /* __TURBOC__ */ -#if defined(M_I86) && !defined(__32BIT__) +#ifdef M_I86 /* Microsoft C in 16-bit mode */ # define MY_ZCALLOC @@ -195,14 +284,16 @@ void zcfree (voidpf opaque, voidpf ptr) _hfree(ptr); } -#endif /* MSC */ +#endif /* M_I86 */ + +#endif /* SYS16BIT */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC +extern voidp malloc OF((uInt size)); extern voidp calloc OF((uInt items, uInt size)); -extern voidp malloc OF((uInt items)); extern void free OF((voidpf ptr)); #endif @@ -212,17 +303,8 @@ voidpf zcalloc (opaque, items, size) unsigned size; { if (opaque) items += size - size; /* make compiler happy */ - return (voidpf)calloc(items, size); -} - -/* added to version 1.1.3pc -- glennrp */ -voidpf zmalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - if (opaque) items += size - size; /* make compiler happy */ - return (voidpf)malloc(items * size); + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); } void zcfree (opaque, ptr) diff --git a/zutil.h b/zutil.h index fe7583314..b7d5eff81 100644 --- a/zutil.h +++ b/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -8,24 +8,35 @@ subject to change. Applications should only use zlib.h. */ -/* Added tests for Windows platforms at line 136. glennrp, May 2001 */ - /* @(#) $Id$ */ -#ifndef _Z_UTIL_H -#define _Z_UTIL_H +#ifndef ZUTIL_H +#define ZUTIL_H +#define ZLIB_INTERNAL #include "zlib.h" #ifdef STDC -# include +# ifndef _WIN32_WCE +# include +# endif # include # include #endif #ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif extern int errno; #else -# include +# ifndef _WIN32_WCE +# include +# endif #endif #ifndef local @@ -39,7 +50,7 @@ typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; -extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] @@ -75,7 +86,7 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ /* target dependencies */ -#ifdef MSDOS +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00 # if defined(__TURBOC__) || defined(__BORLANDC__) # if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) @@ -83,19 +94,15 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ void _Cdecl farfree( void *block ); void *_Cdecl farmalloc( unsigned long nbytes ); # else -# include +# include # endif # else /* MSC or DJGPP */ # include # endif #endif -#ifdef OS2 -# define OS_CODE 0x06 -#endif - -#ifdef WIN32 /* Window 95 & Windows NT */ -# define OS_CODE 0x0b +#ifdef AMIGA +# define OS_CODE 0x01 #endif #if defined(VAXC) || defined(VMS) @@ -104,14 +111,17 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif -#ifdef AMIGA -# define OS_CODE 0x01 -#endif - #if defined(ATARI) || defined(atarist) # define OS_CODE 0x05 #endif +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 0x07 # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os @@ -123,26 +133,37 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ # endif #endif -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0F -#endif - #ifdef TOPS20 # define OS_CODE 0x0a #endif +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + #if defined(_BEOS_) || defined(RISCOS) # define fdopen(fd,mode) NULL /* No fdopen() */ #endif -#if (defined(_MSC_VER) && (_MSC_VER > 600)) && (defined(WIN32) || \ - defined(_Windows) || defined(_WINDOWS) || defined(_WIN32) || \ - defined(__WIN32__)) -# define fdopen(fd,type) _fdopen(fd,type) +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif #endif - - /* Common defaults */ + /* common defaults */ #ifndef OS_CODE # define OS_CODE 0x03 /* assume Unix */ @@ -154,11 +175,37 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ /* functions */ -#ifdef HAVE_STRERROR - extern char *strerror OF((int)); -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf #endif #if defined(pyr) @@ -211,8 +258,6 @@ extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ #endif -typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, - uInt len)); voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); void zcfree OF((voidpf opaque, voidpf ptr)); @@ -221,4 +266,4 @@ void zcfree OF((voidpf opaque, voidpf ptr)); #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} -#endif /* _Z_UTIL_H */ +#endif /* ZUTIL_H */