diff --git a/configure b/configure index 39c599e9d6c..c9ee7235938 100755 --- a/configure +++ b/configure @@ -705,6 +705,8 @@ XMKMF PTHREAD_LIBS ZLIB_PE_LIBS ZLIB_PE_CFLAGS +TIFF_PE_LIBS +TIFF_PE_CFLAGS PNG_PE_LIBS PNG_PE_CFLAGS JPEG_PE_LIBS @@ -1789,6 +1791,7 @@ enable_jpeg enable_mfuuid enable_png enable_strmiids +enable_tiff enable_uuid enable_wbemuuid enable_wine @@ -1928,6 +1931,8 @@ JPEG_PE_CFLAGS JPEG_PE_LIBS PNG_PE_CFLAGS PNG_PE_LIBS +TIFF_PE_CFLAGS +TIFF_PE_LIBS ZLIB_PE_CFLAGS ZLIB_PE_LIBS XMKMF @@ -2718,6 +2723,10 @@ Some influential environment variables: PNG_PE_CFLAGS C compiler flags for the PE png, overriding the bundled version PNG_PE_LIBS Linker flags for the PE png, overriding the bundled version + TIFF_PE_CFLAGS + C compiler flags for the PE tiff, overriding the bundled version + TIFF_PE_LIBS + Linker flags for the PE tiff, overriding the bundled version ZLIB_PE_CFLAGS C compiler flags for the PE zlib, overriding the bundled version ZLIB_PE_LIBS @@ -10738,6 +10747,19 @@ fi $as_echo "$as_me:${as_lineno-$LINENO}: png cflags: $PNG_PE_CFLAGS" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: png libs: $PNG_PE_LIBS" >&5 +if ${TIFF_PE_CFLAGS:+false} :; then : + TIFF_PE_CFLAGS="-I\$(top_srcdir)/libs/tiff/libtiff" +else + enable_tiff=no +fi +if ${TIFF_PE_LIBS:+false} :; then : + TIFF_PE_LIBS=tiff +else + enable_tiff=no +fi +$as_echo "$as_me:${as_lineno-$LINENO}: tiff cflags: $TIFF_PE_CFLAGS" >&5 +$as_echo "$as_me:${as_lineno-$LINENO}: tiff libs: $TIFF_PE_LIBS" >&5 + if ${ZLIB_PE_CFLAGS:+false} :; then : ZLIB_PE_CFLAGS="-I\$(top_srcdir)/libs/zlib -DFAR= -DZ_SOLO" else @@ -19583,6 +19605,8 @@ JPEG_PE_CFLAGS = $JPEG_PE_CFLAGS JPEG_PE_LIBS = $JPEG_PE_LIBS PNG_PE_CFLAGS = $PNG_PE_CFLAGS PNG_PE_LIBS = $PNG_PE_LIBS +TIFF_PE_CFLAGS = $TIFF_PE_CFLAGS +TIFF_PE_LIBS = $TIFF_PE_LIBS ZLIB_PE_CFLAGS = $ZLIB_PE_CFLAGS ZLIB_PE_LIBS = $ZLIB_PE_LIBS PTHREAD_LIBS = $PTHREAD_LIBS @@ -20879,6 +20903,7 @@ wine_fn_config_makefile libs/jpeg enable_jpeg wine_fn_config_makefile libs/mfuuid enable_mfuuid wine_fn_config_makefile libs/png enable_png wine_fn_config_makefile libs/strmiids enable_strmiids +wine_fn_config_makefile libs/tiff enable_tiff wine_fn_config_makefile libs/uuid enable_uuid wine_fn_config_makefile libs/wbemuuid enable_wbemuuid wine_fn_config_makefile libs/wine enable_wine diff --git a/configure.ac b/configure.ac index 79e6d1963e0..b6d0404ed3e 100644 --- a/configure.ac +++ b/configure.ac @@ -1064,6 +1064,7 @@ dnl **** External libraries **** WINE_EXTLIB_FLAGS(JPEG, jpeg, jpeg, "-I\$(top_srcdir)/libs/jpeg") WINE_EXTLIB_FLAGS(PNG, png, "png \$(ZLIB_PE_LIBS)", "-I\$(top_srcdir)/libs/png") +WINE_EXTLIB_FLAGS(TIFF, tiff, tiff, "-I\$(top_srcdir)/libs/tiff/libtiff") WINE_EXTLIB_FLAGS(ZLIB, zlib, z, "-I\$(top_srcdir)/libs/zlib -DFAR= -DZ_SOLO") dnl **** Check for pthread **** @@ -3797,6 +3798,7 @@ WINE_CONFIG_MAKEFILE(libs/jpeg) WINE_CONFIG_MAKEFILE(libs/mfuuid) WINE_CONFIG_MAKEFILE(libs/png) WINE_CONFIG_MAKEFILE(libs/strmiids) +WINE_CONFIG_MAKEFILE(libs/tiff) WINE_CONFIG_MAKEFILE(libs/uuid) WINE_CONFIG_MAKEFILE(libs/wbemuuid) WINE_CONFIG_MAKEFILE(libs/wine) diff --git a/libs/tiff/COPYRIGHT b/libs/tiff/COPYRIGHT new file mode 100644 index 00000000000..8282186151e --- /dev/null +++ b/libs/tiff/COPYRIGHT @@ -0,0 +1,21 @@ +Copyright (c) 1988-1997 Sam Leffler +Copyright (c) 1991-1997 Silicon Graphics, Inc. + +Permission to use, copy, modify, distribute, and sell this software and +its documentation for any purpose is hereby granted without fee, provided +that (i) the above copyright notices and this permission notice appear in +all copies of the software and related documentation, and (ii) the names of +Sam Leffler and Silicon Graphics may not be used in any advertising or +publicity relating to the software without the specific, prior written +permission of Sam Leffler and Silicon Graphics. + +THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR +ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF +LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +OF THIS SOFTWARE. diff --git a/libs/tiff/Makefile.in b/libs/tiff/Makefile.in new file mode 100644 index 00000000000..f8ceb5006d4 --- /dev/null +++ b/libs/tiff/Makefile.in @@ -0,0 +1,34 @@ +EXTLIB = libtiff.a +EXTRAINCL = -I$(srcdir)/libtiff $(JPEG_PE_CFLAGS) $(ZLIB_PE_CFLAGS) + +C_SRCS = \ + libtiff/tif_aux.c \ + libtiff/tif_close.c \ + libtiff/tif_codec.c \ + libtiff/tif_compress.c \ + libtiff/tif_dir.c \ + libtiff/tif_dirinfo.c \ + libtiff/tif_dirread.c \ + libtiff/tif_dirwrite.c \ + libtiff/tif_dumpmode.c \ + libtiff/tif_error.c \ + libtiff/tif_fax3.c \ + libtiff/tif_fax3sm.c \ + libtiff/tif_flush.c \ + libtiff/tif_jpeg.c \ + libtiff/tif_luv.c \ + libtiff/tif_lzw.c \ + libtiff/tif_next.c \ + libtiff/tif_open.c \ + libtiff/tif_packbits.c \ + libtiff/tif_pixarlog.c \ + libtiff/tif_predict.c \ + libtiff/tif_read.c \ + libtiff/tif_strip.c \ + libtiff/tif_swab.c \ + libtiff/tif_thunder.c \ + libtiff/tif_tile.c \ + libtiff/tif_warning.c \ + libtiff/tif_win32.c \ + libtiff/tif_write.c \ + libtiff/tif_zip.c diff --git a/libs/tiff/libtiff/t4.h b/libs/tiff/libtiff/t4.h new file mode 100644 index 00000000000..fb0951a16f7 --- /dev/null +++ b/libs/tiff/libtiff/t4.h @@ -0,0 +1,290 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _T4_ +#define _T4_ +/* + * CCITT T.4 1D Huffman runlength codes and + * related definitions. Given the small sizes + * of these tables it does not seem + * worthwhile to make code & length 8 bits. + */ +typedef struct tableentry { + unsigned short length; /* bit length of g3 code */ + unsigned short code; /* g3 code */ + short runlen; /* run length in bits */ +} tableentry; + +#define EOL 0x001 /* EOL code value - 0000 0000 0000 1 */ + +/* status values returned instead of a run length */ +#define G3CODE_EOL -1 /* NB: ACT_EOL - ACT_WRUNT */ +#define G3CODE_INVALID -2 /* NB: ACT_INVALID - ACT_WRUNT */ +#define G3CODE_EOF -3 /* end of input data */ +#define G3CODE_INCOMP -4 /* incomplete run code */ + +/* + * Note that these tables are ordered such that the + * index into the table is known to be either the + * run length, or (run length / 64) + a fixed offset. + * + * NB: The G3CODE_INVALID entries are only used + * during state generation (see mkg3states.c). + */ +#ifdef G3CODES +const tableentry TIFFFaxWhiteCodes[] = { + { 8, 0x35, 0 }, /* 0011 0101 */ + { 6, 0x7, 1 }, /* 0001 11 */ + { 4, 0x7, 2 }, /* 0111 */ + { 4, 0x8, 3 }, /* 1000 */ + { 4, 0xB, 4 }, /* 1011 */ + { 4, 0xC, 5 }, /* 1100 */ + { 4, 0xE, 6 }, /* 1110 */ + { 4, 0xF, 7 }, /* 1111 */ + { 5, 0x13, 8 }, /* 1001 1 */ + { 5, 0x14, 9 }, /* 1010 0 */ + { 5, 0x7, 10 }, /* 0011 1 */ + { 5, 0x8, 11 }, /* 0100 0 */ + { 6, 0x8, 12 }, /* 0010 00 */ + { 6, 0x3, 13 }, /* 0000 11 */ + { 6, 0x34, 14 }, /* 1101 00 */ + { 6, 0x35, 15 }, /* 1101 01 */ + { 6, 0x2A, 16 }, /* 1010 10 */ + { 6, 0x2B, 17 }, /* 1010 11 */ + { 7, 0x27, 18 }, /* 0100 111 */ + { 7, 0xC, 19 }, /* 0001 100 */ + { 7, 0x8, 20 }, /* 0001 000 */ + { 7, 0x17, 21 }, /* 0010 111 */ + { 7, 0x3, 22 }, /* 0000 011 */ + { 7, 0x4, 23 }, /* 0000 100 */ + { 7, 0x28, 24 }, /* 0101 000 */ + { 7, 0x2B, 25 }, /* 0101 011 */ + { 7, 0x13, 26 }, /* 0010 011 */ + { 7, 0x24, 27 }, /* 0100 100 */ + { 7, 0x18, 28 }, /* 0011 000 */ + { 8, 0x2, 29 }, /* 0000 0010 */ + { 8, 0x3, 30 }, /* 0000 0011 */ + { 8, 0x1A, 31 }, /* 0001 1010 */ + { 8, 0x1B, 32 }, /* 0001 1011 */ + { 8, 0x12, 33 }, /* 0001 0010 */ + { 8, 0x13, 34 }, /* 0001 0011 */ + { 8, 0x14, 35 }, /* 0001 0100 */ + { 8, 0x15, 36 }, /* 0001 0101 */ + { 8, 0x16, 37 }, /* 0001 0110 */ + { 8, 0x17, 38 }, /* 0001 0111 */ + { 8, 0x28, 39 }, /* 0010 1000 */ + { 8, 0x29, 40 }, /* 0010 1001 */ + { 8, 0x2A, 41 }, /* 0010 1010 */ + { 8, 0x2B, 42 }, /* 0010 1011 */ + { 8, 0x2C, 43 }, /* 0010 1100 */ + { 8, 0x2D, 44 }, /* 0010 1101 */ + { 8, 0x4, 45 }, /* 0000 0100 */ + { 8, 0x5, 46 }, /* 0000 0101 */ + { 8, 0xA, 47 }, /* 0000 1010 */ + { 8, 0xB, 48 }, /* 0000 1011 */ + { 8, 0x52, 49 }, /* 0101 0010 */ + { 8, 0x53, 50 }, /* 0101 0011 */ + { 8, 0x54, 51 }, /* 0101 0100 */ + { 8, 0x55, 52 }, /* 0101 0101 */ + { 8, 0x24, 53 }, /* 0010 0100 */ + { 8, 0x25, 54 }, /* 0010 0101 */ + { 8, 0x58, 55 }, /* 0101 1000 */ + { 8, 0x59, 56 }, /* 0101 1001 */ + { 8, 0x5A, 57 }, /* 0101 1010 */ + { 8, 0x5B, 58 }, /* 0101 1011 */ + { 8, 0x4A, 59 }, /* 0100 1010 */ + { 8, 0x4B, 60 }, /* 0100 1011 */ + { 8, 0x32, 61 }, /* 0011 0010 */ + { 8, 0x33, 62 }, /* 0011 0011 */ + { 8, 0x34, 63 }, /* 0011 0100 */ + { 5, 0x1B, 64 }, /* 1101 1 */ + { 5, 0x12, 128 }, /* 1001 0 */ + { 6, 0x17, 192 }, /* 0101 11 */ + { 7, 0x37, 256 }, /* 0110 111 */ + { 8, 0x36, 320 }, /* 0011 0110 */ + { 8, 0x37, 384 }, /* 0011 0111 */ + { 8, 0x64, 448 }, /* 0110 0100 */ + { 8, 0x65, 512 }, /* 0110 0101 */ + { 8, 0x68, 576 }, /* 0110 1000 */ + { 8, 0x67, 640 }, /* 0110 0111 */ + { 9, 0xCC, 704 }, /* 0110 0110 0 */ + { 9, 0xCD, 768 }, /* 0110 0110 1 */ + { 9, 0xD2, 832 }, /* 0110 1001 0 */ + { 9, 0xD3, 896 }, /* 0110 1001 1 */ + { 9, 0xD4, 960 }, /* 0110 1010 0 */ + { 9, 0xD5, 1024 }, /* 0110 1010 1 */ + { 9, 0xD6, 1088 }, /* 0110 1011 0 */ + { 9, 0xD7, 1152 }, /* 0110 1011 1 */ + { 9, 0xD8, 1216 }, /* 0110 1100 0 */ + { 9, 0xD9, 1280 }, /* 0110 1100 1 */ + { 9, 0xDA, 1344 }, /* 0110 1101 0 */ + { 9, 0xDB, 1408 }, /* 0110 1101 1 */ + { 9, 0x98, 1472 }, /* 0100 1100 0 */ + { 9, 0x99, 1536 }, /* 0100 1100 1 */ + { 9, 0x9A, 1600 }, /* 0100 1101 0 */ + { 6, 0x18, 1664 }, /* 0110 00 */ + { 9, 0x9B, 1728 }, /* 0100 1101 1 */ + { 11, 0x8, 1792 }, /* 0000 0001 000 */ + { 11, 0xC, 1856 }, /* 0000 0001 100 */ + { 11, 0xD, 1920 }, /* 0000 0001 101 */ + { 12, 0x12, 1984 }, /* 0000 0001 0010 */ + { 12, 0x13, 2048 }, /* 0000 0001 0011 */ + { 12, 0x14, 2112 }, /* 0000 0001 0100 */ + { 12, 0x15, 2176 }, /* 0000 0001 0101 */ + { 12, 0x16, 2240 }, /* 0000 0001 0110 */ + { 12, 0x17, 2304 }, /* 0000 0001 0111 */ + { 12, 0x1C, 2368 }, /* 0000 0001 1100 */ + { 12, 0x1D, 2432 }, /* 0000 0001 1101 */ + { 12, 0x1E, 2496 }, /* 0000 0001 1110 */ + { 12, 0x1F, 2560 }, /* 0000 0001 1111 */ + { 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */ + { 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */ + { 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */ + { 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */ + { 12, 0x0, G3CODE_INVALID }, /* 0000 0000 0000 */ +}; + +const tableentry TIFFFaxBlackCodes[] = { + { 10, 0x37, 0 }, /* 0000 1101 11 */ + { 3, 0x2, 1 }, /* 010 */ + { 2, 0x3, 2 }, /* 11 */ + { 2, 0x2, 3 }, /* 10 */ + { 3, 0x3, 4 }, /* 011 */ + { 4, 0x3, 5 }, /* 0011 */ + { 4, 0x2, 6 }, /* 0010 */ + { 5, 0x3, 7 }, /* 0001 1 */ + { 6, 0x5, 8 }, /* 0001 01 */ + { 6, 0x4, 9 }, /* 0001 00 */ + { 7, 0x4, 10 }, /* 0000 100 */ + { 7, 0x5, 11 }, /* 0000 101 */ + { 7, 0x7, 12 }, /* 0000 111 */ + { 8, 0x4, 13 }, /* 0000 0100 */ + { 8, 0x7, 14 }, /* 0000 0111 */ + { 9, 0x18, 15 }, /* 0000 1100 0 */ + { 10, 0x17, 16 }, /* 0000 0101 11 */ + { 10, 0x18, 17 }, /* 0000 0110 00 */ + { 10, 0x8, 18 }, /* 0000 0010 00 */ + { 11, 0x67, 19 }, /* 0000 1100 111 */ + { 11, 0x68, 20 }, /* 0000 1101 000 */ + { 11, 0x6C, 21 }, /* 0000 1101 100 */ + { 11, 0x37, 22 }, /* 0000 0110 111 */ + { 11, 0x28, 23 }, /* 0000 0101 000 */ + { 11, 0x17, 24 }, /* 0000 0010 111 */ + { 11, 0x18, 25 }, /* 0000 0011 000 */ + { 12, 0xCA, 26 }, /* 0000 1100 1010 */ + { 12, 0xCB, 27 }, /* 0000 1100 1011 */ + { 12, 0xCC, 28 }, /* 0000 1100 1100 */ + { 12, 0xCD, 29 }, /* 0000 1100 1101 */ + { 12, 0x68, 30 }, /* 0000 0110 1000 */ + { 12, 0x69, 31 }, /* 0000 0110 1001 */ + { 12, 0x6A, 32 }, /* 0000 0110 1010 */ + { 12, 0x6B, 33 }, /* 0000 0110 1011 */ + { 12, 0xD2, 34 }, /* 0000 1101 0010 */ + { 12, 0xD3, 35 }, /* 0000 1101 0011 */ + { 12, 0xD4, 36 }, /* 0000 1101 0100 */ + { 12, 0xD5, 37 }, /* 0000 1101 0101 */ + { 12, 0xD6, 38 }, /* 0000 1101 0110 */ + { 12, 0xD7, 39 }, /* 0000 1101 0111 */ + { 12, 0x6C, 40 }, /* 0000 0110 1100 */ + { 12, 0x6D, 41 }, /* 0000 0110 1101 */ + { 12, 0xDA, 42 }, /* 0000 1101 1010 */ + { 12, 0xDB, 43 }, /* 0000 1101 1011 */ + { 12, 0x54, 44 }, /* 0000 0101 0100 */ + { 12, 0x55, 45 }, /* 0000 0101 0101 */ + { 12, 0x56, 46 }, /* 0000 0101 0110 */ + { 12, 0x57, 47 }, /* 0000 0101 0111 */ + { 12, 0x64, 48 }, /* 0000 0110 0100 */ + { 12, 0x65, 49 }, /* 0000 0110 0101 */ + { 12, 0x52, 50 }, /* 0000 0101 0010 */ + { 12, 0x53, 51 }, /* 0000 0101 0011 */ + { 12, 0x24, 52 }, /* 0000 0010 0100 */ + { 12, 0x37, 53 }, /* 0000 0011 0111 */ + { 12, 0x38, 54 }, /* 0000 0011 1000 */ + { 12, 0x27, 55 }, /* 0000 0010 0111 */ + { 12, 0x28, 56 }, /* 0000 0010 1000 */ + { 12, 0x58, 57 }, /* 0000 0101 1000 */ + { 12, 0x59, 58 }, /* 0000 0101 1001 */ + { 12, 0x2B, 59 }, /* 0000 0010 1011 */ + { 12, 0x2C, 60 }, /* 0000 0010 1100 */ + { 12, 0x5A, 61 }, /* 0000 0101 1010 */ + { 12, 0x66, 62 }, /* 0000 0110 0110 */ + { 12, 0x67, 63 }, /* 0000 0110 0111 */ + { 10, 0xF, 64 }, /* 0000 0011 11 */ + { 12, 0xC8, 128 }, /* 0000 1100 1000 */ + { 12, 0xC9, 192 }, /* 0000 1100 1001 */ + { 12, 0x5B, 256 }, /* 0000 0101 1011 */ + { 12, 0x33, 320 }, /* 0000 0011 0011 */ + { 12, 0x34, 384 }, /* 0000 0011 0100 */ + { 12, 0x35, 448 }, /* 0000 0011 0101 */ + { 13, 0x6C, 512 }, /* 0000 0011 0110 0 */ + { 13, 0x6D, 576 }, /* 0000 0011 0110 1 */ + { 13, 0x4A, 640 }, /* 0000 0010 0101 0 */ + { 13, 0x4B, 704 }, /* 0000 0010 0101 1 */ + { 13, 0x4C, 768 }, /* 0000 0010 0110 0 */ + { 13, 0x4D, 832 }, /* 0000 0010 0110 1 */ + { 13, 0x72, 896 }, /* 0000 0011 1001 0 */ + { 13, 0x73, 960 }, /* 0000 0011 1001 1 */ + { 13, 0x74, 1024 }, /* 0000 0011 1010 0 */ + { 13, 0x75, 1088 }, /* 0000 0011 1010 1 */ + { 13, 0x76, 1152 }, /* 0000 0011 1011 0 */ + { 13, 0x77, 1216 }, /* 0000 0011 1011 1 */ + { 13, 0x52, 1280 }, /* 0000 0010 1001 0 */ + { 13, 0x53, 1344 }, /* 0000 0010 1001 1 */ + { 13, 0x54, 1408 }, /* 0000 0010 1010 0 */ + { 13, 0x55, 1472 }, /* 0000 0010 1010 1 */ + { 13, 0x5A, 1536 }, /* 0000 0010 1101 0 */ + { 13, 0x5B, 1600 }, /* 0000 0010 1101 1 */ + { 13, 0x64, 1664 }, /* 0000 0011 0010 0 */ + { 13, 0x65, 1728 }, /* 0000 0011 0010 1 */ + { 11, 0x8, 1792 }, /* 0000 0001 000 */ + { 11, 0xC, 1856 }, /* 0000 0001 100 */ + { 11, 0xD, 1920 }, /* 0000 0001 101 */ + { 12, 0x12, 1984 }, /* 0000 0001 0010 */ + { 12, 0x13, 2048 }, /* 0000 0001 0011 */ + { 12, 0x14, 2112 }, /* 0000 0001 0100 */ + { 12, 0x15, 2176 }, /* 0000 0001 0101 */ + { 12, 0x16, 2240 }, /* 0000 0001 0110 */ + { 12, 0x17, 2304 }, /* 0000 0001 0111 */ + { 12, 0x1C, 2368 }, /* 0000 0001 1100 */ + { 12, 0x1D, 2432 }, /* 0000 0001 1101 */ + { 12, 0x1E, 2496 }, /* 0000 0001 1110 */ + { 12, 0x1F, 2560 }, /* 0000 0001 1111 */ + { 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */ + { 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */ + { 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */ + { 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */ + { 12, 0x0, G3CODE_INVALID }, /* 0000 0000 0000 */ +}; +#else +extern const tableentry TIFFFaxWhiteCodes[]; +extern const tableentry TIFFFaxBlackCodes[]; +#endif +#endif /* _T4_ */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_aux.c b/libs/tiff/libtiff/tif_aux.c new file mode 100644 index 00000000000..ca033f64f2d --- /dev/null +++ b/libs/tiff/libtiff/tif_aux.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Auxiliary Support Routines. + */ +#include "tiffiop.h" +#include "tif_predict.h" +#include +#include + +uint32_t +_TIFFMultiply32(TIFF* tif, uint32_t first, uint32_t second, const char* where) +{ + if (second && first > UINT32_MAX / second) { + TIFFErrorExt(tif->tif_clientdata, where, "Integer overflow in %s", where); + return 0; + } + + return first * second; +} + +uint64_t +_TIFFMultiply64(TIFF* tif, uint64_t first, uint64_t second, const char* where) +{ + if (second && first > UINT64_MAX / second) { + TIFFErrorExt(tif->tif_clientdata, where, "Integer overflow in %s", where); + return 0; + } + + return first * second; +} + +tmsize_t +_TIFFMultiplySSize(TIFF* tif, tmsize_t first, tmsize_t second, const char* where) +{ + if( first <= 0 || second <= 0 ) + { + if( tif != NULL && where != NULL ) + { + TIFFErrorExt(tif->tif_clientdata, where, + "Invalid argument to _TIFFMultiplySSize() in %s", where); + } + return 0; + } + + if( first > TIFF_TMSIZE_T_MAX / second ) + { + if( tif != NULL && where != NULL ) + { + TIFFErrorExt(tif->tif_clientdata, where, + "Integer overflow in %s", where); + } + return 0; + } + return first * second; +} + +tmsize_t _TIFFCastUInt64ToSSize(TIFF* tif, uint64_t val, const char* module) +{ + if( val > (uint64_t)TIFF_TMSIZE_T_MAX ) + { + if( tif != NULL && module != NULL ) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + } + return 0; + } + return (tmsize_t)val; +} + +void* +_TIFFCheckRealloc(TIFF* tif, void* buffer, + tmsize_t nmemb, tmsize_t elem_size, const char* what) +{ + void* cp = NULL; + tmsize_t count = _TIFFMultiplySSize(tif, nmemb, elem_size, NULL); + /* + * Check for integer overflow. + */ + if (count != 0) + { + cp = _TIFFrealloc(buffer, count); + } + + if (cp == NULL) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Failed to allocate memory for %s " + "(%"TIFF_SSIZE_FORMAT" elements of %"TIFF_SSIZE_FORMAT" bytes each)", + what, nmemb, elem_size); + } + + return cp; +} + +void* +_TIFFCheckMalloc(TIFF* tif, tmsize_t nmemb, tmsize_t elem_size, const char* what) +{ + return _TIFFCheckRealloc(tif, NULL, nmemb, elem_size, what); +} + +static int +TIFFDefaultTransferFunction(TIFFDirectory* td) +{ + uint16_t **tf = td->td_transferfunction; + tmsize_t i, n, nbytes; + + tf[0] = tf[1] = tf[2] = 0; + if (td->td_bitspersample >= sizeof(tmsize_t) * 8 - 2) + return 0; + + n = ((tmsize_t)1)<td_bitspersample; + nbytes = n * sizeof (uint16_t); + tf[0] = (uint16_t *)_TIFFmalloc(nbytes); + if (tf[0] == NULL) + return 0; + tf[0][0] = 0; + for (i = 1; i < n; i++) { + double t = (double)i/((double) n-1.); + tf[0][i] = (uint16_t)floor(65535. * pow(t, 2.2) + .5); + } + + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + tf[1] = (uint16_t *)_TIFFmalloc(nbytes); + if(tf[1] == NULL) + goto bad; + _TIFFmemcpy(tf[1], tf[0], nbytes); + tf[2] = (uint16_t *)_TIFFmalloc(nbytes); + if (tf[2] == NULL) + goto bad; + _TIFFmemcpy(tf[2], tf[0], nbytes); + } + return 1; + +bad: + if (tf[0]) + _TIFFfree(tf[0]); + if (tf[1]) + _TIFFfree(tf[1]); + if (tf[2]) + _TIFFfree(tf[2]); + tf[0] = tf[1] = tf[2] = 0; + return 0; +} + +static int +TIFFDefaultRefBlackWhite(TIFFDirectory* td) +{ + int i; + + td->td_refblackwhite = (float *)_TIFFmalloc(6*sizeof (float)); + if (td->td_refblackwhite == NULL) + return 0; + if (td->td_photometric == PHOTOMETRIC_YCBCR) { + /* + * YCbCr (Class Y) images must have the ReferenceBlackWhite + * tag set. Fix the broken images, which lacks that tag. + */ + td->td_refblackwhite[0] = 0.0F; + td->td_refblackwhite[1] = td->td_refblackwhite[3] = + td->td_refblackwhite[5] = 255.0F; + td->td_refblackwhite[2] = td->td_refblackwhite[4] = 128.0F; + } else { + /* + * Assume RGB (Class R) + */ + for (i = 0; i < 3; i++) { + td->td_refblackwhite[2*i+0] = 0; + td->td_refblackwhite[2*i+1] = + (float)((1L<td_bitspersample)-1L); + } + } + return 1; +} + +/* + * Like TIFFGetField, but return any default + * value if the tag is not present in the directory. + * + * NB: We use the value in the directory, rather than + * explicit values so that defaults exist only one + * place in the library -- in TIFFDefaultDirectory. + */ +int +TIFFVGetFieldDefaulted(TIFF* tif, uint32_t tag, va_list ap) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (TIFFVGetField(tif, tag, ap)) + return (1); + switch (tag) { + case TIFFTAG_SUBFILETYPE: + *va_arg(ap, uint32_t *) = td->td_subfiletype; + return (1); + case TIFFTAG_BITSPERSAMPLE: + *va_arg(ap, uint16_t *) = td->td_bitspersample; + return (1); + case TIFFTAG_THRESHHOLDING: + *va_arg(ap, uint16_t *) = td->td_threshholding; + return (1); + case TIFFTAG_FILLORDER: + *va_arg(ap, uint16_t *) = td->td_fillorder; + return (1); + case TIFFTAG_ORIENTATION: + *va_arg(ap, uint16_t *) = td->td_orientation; + return (1); + case TIFFTAG_SAMPLESPERPIXEL: + *va_arg(ap, uint16_t *) = td->td_samplesperpixel; + return (1); + case TIFFTAG_ROWSPERSTRIP: + *va_arg(ap, uint32_t *) = td->td_rowsperstrip; + return (1); + case TIFFTAG_MINSAMPLEVALUE: + *va_arg(ap, uint16_t *) = td->td_minsamplevalue; + return (1); + case TIFFTAG_MAXSAMPLEVALUE: + *va_arg(ap, uint16_t *) = td->td_maxsamplevalue; + return (1); + case TIFFTAG_PLANARCONFIG: + *va_arg(ap, uint16_t *) = td->td_planarconfig; + return (1); + case TIFFTAG_RESOLUTIONUNIT: + *va_arg(ap, uint16_t *) = td->td_resolutionunit; + return (1); + case TIFFTAG_PREDICTOR: + { + TIFFPredictorState* sp = (TIFFPredictorState*) tif->tif_data; + if( sp == NULL ) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Cannot get \"Predictor\" tag as plugin is not configured"); + *va_arg(ap, uint16_t*) = 0; + return 0; + } + *va_arg(ap, uint16_t*) = (uint16_t) sp->predictor; + return 1; + } + case TIFFTAG_DOTRANGE: + *va_arg(ap, uint16_t *) = 0; + *va_arg(ap, uint16_t *) = (1 << td->td_bitspersample) - 1; + return (1); + case TIFFTAG_INKSET: + *va_arg(ap, uint16_t *) = INKSET_CMYK; + return 1; + case TIFFTAG_NUMBEROFINKS: + *va_arg(ap, uint16_t *) = 4; + return (1); + case TIFFTAG_EXTRASAMPLES: + *va_arg(ap, uint16_t *) = td->td_extrasamples; + *va_arg(ap, const uint16_t **) = td->td_sampleinfo; + return (1); + case TIFFTAG_MATTEING: + *va_arg(ap, uint16_t *) = + (td->td_extrasamples == 1 && + td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA); + return (1); + case TIFFTAG_TILEDEPTH: + *va_arg(ap, uint32_t *) = td->td_tiledepth; + return (1); + case TIFFTAG_DATATYPE: + *va_arg(ap, uint16_t *) = td->td_sampleformat - 1; + return (1); + case TIFFTAG_SAMPLEFORMAT: + *va_arg(ap, uint16_t *) = td->td_sampleformat; + return(1); + case TIFFTAG_IMAGEDEPTH: + *va_arg(ap, uint32_t *) = td->td_imagedepth; + return (1); + case TIFFTAG_YCBCRCOEFFICIENTS: + { + /* defaults are from CCIR Recommendation 601-1 */ + static const float ycbcrcoeffs[] = { 0.299f, 0.587f, 0.114f }; + *va_arg(ap, const float **) = ycbcrcoeffs; + return 1; + } + case TIFFTAG_YCBCRSUBSAMPLING: + *va_arg(ap, uint16_t *) = td->td_ycbcrsubsampling[0]; + *va_arg(ap, uint16_t *) = td->td_ycbcrsubsampling[1]; + return (1); + case TIFFTAG_YCBCRPOSITIONING: + *va_arg(ap, uint16_t *) = td->td_ycbcrpositioning; + return (1); + case TIFFTAG_WHITEPOINT: + { + /* TIFF 6.0 specification tells that it is no default + value for the WhitePoint, but AdobePhotoshop TIFF + Technical Note tells that it should be CIE D50. */ + static const float whitepoint[] = { + D50_X0 / (D50_X0 + D50_Y0 + D50_Z0), + D50_Y0 / (D50_X0 + D50_Y0 + D50_Z0) + }; + *va_arg(ap, const float **) = whitepoint; + return 1; + } + case TIFFTAG_TRANSFERFUNCTION: + if (!td->td_transferfunction[0] && + !TIFFDefaultTransferFunction(td)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "No space for \"TransferFunction\" tag"); + return (0); + } + *va_arg(ap, const uint16_t **) = td->td_transferfunction[0]; + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + *va_arg(ap, const uint16_t **) = td->td_transferfunction[1]; + *va_arg(ap, const uint16_t **) = td->td_transferfunction[2]; + } + return (1); + case TIFFTAG_REFERENCEBLACKWHITE: + if (!td->td_refblackwhite && !TIFFDefaultRefBlackWhite(td)) + return (0); + *va_arg(ap, const float **) = td->td_refblackwhite; + return (1); + } + return 0; +} + +/* + * Like TIFFGetField, but return any default + * value if the tag is not present in the directory. + */ +int WINAPIV +TIFFGetFieldDefaulted(TIFF* tif, uint32_t tag, ...) +{ + int ok; + va_list ap; + + va_start(ap, tag); + ok = TIFFVGetFieldDefaulted(tif, tag, ap); + va_end(ap); + return (ok); +} + +struct _Int64Parts { + int32_t low, high; +}; + +typedef union { + struct _Int64Parts part; + int64_t value; +} _Int64; + +float +_TIFFUInt64ToFloat(uint64_t ui64) +{ + _Int64 i; + + i.value = ui64; + if (i.part.high >= 0) { + return (float)i.value; + } else { + long double df; + df = (long double)i.value; + df += 18446744073709551616.0; /* adding 2**64 */ + return (float)df; + } +} + +double +_TIFFUInt64ToDouble(uint64_t ui64) +{ + _Int64 i; + + i.value = ui64; + if (i.part.high >= 0) { + return (double)i.value; + } else { + long double df; + df = (long double)i.value; + df += 18446744073709551616.0; /* adding 2**64 */ + return (double)df; + } +} + +float _TIFFClampDoubleToFloat( double val ) +{ + if( val > FLT_MAX ) + return FLT_MAX; + if( val < -FLT_MAX ) + return -FLT_MAX; + return (float)val; +} + +int _TIFFSeekOK(TIFF* tif, toff_t off) +{ + /* Huge offsets, especially -1 / UINT64_MAX, can cause issues */ + /* See http://bugzilla.maptools.org/show_bug.cgi?id=2726 */ + return off <= (~(uint64_t)0) / 2 && TIFFSeekFile(tif, off, SEEK_SET) == off; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_close.c b/libs/tiff/libtiff/tif_close.c new file mode 100644 index 00000000000..674518a1888 --- /dev/null +++ b/libs/tiff/libtiff/tif_close.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" +#include + +/************************************************************************/ +/* TIFFCleanup() */ +/************************************************************************/ + +/** + * Auxiliary function to free the TIFF structure. Given structure will be + * completely freed, so you should save opened file handle and pointer + * to the close procedure in external variables before calling + * _TIFFCleanup(), if you will need these ones to close the file. + * + * @param tif A TIFF pointer. + */ + +void +TIFFCleanup(TIFF* tif) +{ + /* + * Flush buffered data and directory (if dirty). + */ + if (tif->tif_mode != O_RDONLY) + TIFFFlush(tif); + (*tif->tif_cleanup)(tif); + TIFFFreeDirectory(tif); + + if (tif->tif_dirlist) + _TIFFfree(tif->tif_dirlist); + + /* + * Clean up client info links. + */ + while( tif->tif_clientinfo ) + { + TIFFClientInfoLink *psLink = tif->tif_clientinfo; + + tif->tif_clientinfo = psLink->next; + _TIFFfree( psLink->name ); + _TIFFfree( psLink ); + } + + if (tif->tif_rawdata && (tif->tif_flags&TIFF_MYBUFFER)) + _TIFFfree(tif->tif_rawdata); + if (isMapped(tif)) + TIFFUnmapFileContents(tif, tif->tif_base, (toff_t)tif->tif_size); + + /* + * Clean up custom fields. + */ + if (tif->tif_fields && tif->tif_nfields > 0) { + uint32_t i; + + for (i = 0; i < tif->tif_nfields; i++) { + TIFFField *fld = tif->tif_fields[i]; + if (fld->field_bit == FIELD_CUSTOM && + strncmp("Tag ", fld->field_name, 4) == 0) { + _TIFFfree(fld->field_name); + _TIFFfree(fld); + } + } + + _TIFFfree(tif->tif_fields); + } + + if (tif->tif_nfieldscompat > 0) { + uint32_t i; + + for (i = 0; i < tif->tif_nfieldscompat; i++) { + if (tif->tif_fieldscompat[i].allocated_size) + _TIFFfree(tif->tif_fieldscompat[i].fields); + } + _TIFFfree(tif->tif_fieldscompat); + } + + _TIFFfree(tif); +} + +/************************************************************************/ +/* TIFFClose() */ +/************************************************************************/ + +/** + * Close a previously opened TIFF file. + * + * TIFFClose closes a file that was previously opened with TIFFOpen(). + * Any buffered data are flushed to the file, including the contents of + * the current directory (if modified); and all resources are reclaimed. + * + * @param tif A TIFF pointer. + */ + +void +TIFFClose(TIFF* tif) +{ + TIFFCloseProc closeproc = tif->tif_closeproc; + thandle_t fd = tif->tif_clientdata; + + TIFFCleanup(tif); + (void) (*closeproc)(fd); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_codec.c b/libs/tiff/libtiff/tif_codec.c new file mode 100644 index 00000000000..931eb093fa4 --- /dev/null +++ b/libs/tiff/libtiff/tif_codec.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Builtin Compression Scheme Configuration Support. + */ +#include "tiffiop.h" + +static int NotConfigured(TIFF*, int); + +#ifndef LZW_SUPPORT +#define TIFFInitLZW NotConfigured +#endif +#ifndef PACKBITS_SUPPORT +#define TIFFInitPackBits NotConfigured +#endif +#ifndef THUNDER_SUPPORT +#define TIFFInitThunderScan NotConfigured +#endif +#ifndef NEXT_SUPPORT +#define TIFFInitNeXT NotConfigured +#endif +#ifndef JPEG_SUPPORT +#define TIFFInitJPEG NotConfigured +#endif +#ifndef OJPEG_SUPPORT +#define TIFFInitOJPEG NotConfigured +#endif +#ifndef CCITT_SUPPORT +#define TIFFInitCCITTRLE NotConfigured +#define TIFFInitCCITTRLEW NotConfigured +#define TIFFInitCCITTFax3 NotConfigured +#define TIFFInitCCITTFax4 NotConfigured +#endif +#ifndef JBIG_SUPPORT +#define TIFFInitJBIG NotConfigured +#endif +#ifndef ZIP_SUPPORT +#define TIFFInitZIP NotConfigured +#endif +#ifndef PIXARLOG_SUPPORT +#define TIFFInitPixarLog NotConfigured +#endif +#ifndef LOGLUV_SUPPORT +#define TIFFInitSGILog NotConfigured +#endif +#ifndef LERC_SUPPORT +#define TIFFInitLERC NotConfigured +#endif +#ifndef LZMA_SUPPORT +#define TIFFInitLZMA NotConfigured +#endif +#ifndef ZSTD_SUPPORT +#define TIFFInitZSTD NotConfigured +#endif +#ifndef WEBP_SUPPORT +#define TIFFInitWebP NotConfigured +#endif + +/* + * Compression schemes statically built into the library. + */ +const TIFFCodec _TIFFBuiltinCODECS[] = { + { "None", COMPRESSION_NONE, TIFFInitDumpMode }, + { "LZW", COMPRESSION_LZW, TIFFInitLZW }, + { "PackBits", COMPRESSION_PACKBITS, TIFFInitPackBits }, + { "ThunderScan", COMPRESSION_THUNDERSCAN,TIFFInitThunderScan }, + { "NeXT", COMPRESSION_NEXT, TIFFInitNeXT }, + { "JPEG", COMPRESSION_JPEG, TIFFInitJPEG }, + { "Old-style JPEG", COMPRESSION_OJPEG, TIFFInitOJPEG }, + { "CCITT RLE", COMPRESSION_CCITTRLE, TIFFInitCCITTRLE }, + { "CCITT RLE/W", COMPRESSION_CCITTRLEW, TIFFInitCCITTRLEW }, + { "CCITT Group 3", COMPRESSION_CCITTFAX3, TIFFInitCCITTFax3 }, + { "CCITT Group 4", COMPRESSION_CCITTFAX4, TIFFInitCCITTFax4 }, + { "ISO JBIG", COMPRESSION_JBIG, TIFFInitJBIG }, + { "Deflate", COMPRESSION_DEFLATE, TIFFInitZIP }, + { "AdobeDeflate", COMPRESSION_ADOBE_DEFLATE , TIFFInitZIP }, + { "PixarLog", COMPRESSION_PIXARLOG, TIFFInitPixarLog }, + { "SGILog", COMPRESSION_SGILOG, TIFFInitSGILog }, + { "SGILog24", COMPRESSION_SGILOG24, TIFFInitSGILog }, + { "LZMA", COMPRESSION_LZMA, TIFFInitLZMA }, + { "ZSTD", COMPRESSION_ZSTD, TIFFInitZSTD }, + { "WEBP", COMPRESSION_WEBP, TIFFInitWebP }, + { "LERC", COMPRESSION_LERC, TIFFInitLERC }, + { NULL, 0, NULL } +}; + +static int +_notConfigured(TIFF* tif) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + char compression_code[20]; + + sprintf(compression_code, "%"PRIu16, tif->tif_dir.td_compression ); + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%s compression support is not configured", + c ? c->name : compression_code ); + return (0); +} + +static int +NotConfigured(TIFF* tif, int scheme) +{ + (void) scheme; + + tif->tif_fixuptags = _notConfigured; + tif->tif_decodestatus = FALSE; + tif->tif_setupdecode = _notConfigured; + tif->tif_encodestatus = FALSE; + tif->tif_setupencode = _notConfigured; + return (1); +} + +/************************************************************************/ +/* TIFFIsCODECConfigured() */ +/************************************************************************/ + +/** + * Check whether we have working codec for the specific coding scheme. + * + * @return returns 1 if the codec is configured and working. Otherwise + * 0 will be returned. + */ + +int +TIFFIsCODECConfigured(uint16_t scheme) +{ + const TIFFCodec* codec = TIFFFindCODEC(scheme); + + if(codec == NULL) { + return 0; + } + if(codec->init == NULL) { + return 0; + } + if(codec->init != NotConfigured){ + return 1; + } + return 0; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_compress.c b/libs/tiff/libtiff/tif_compress.c new file mode 100644 index 00000000000..8fcedf45439 --- /dev/null +++ b/libs/tiff/libtiff/tif_compress.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Compression Scheme Configuration Support. + */ +#include "tiffiop.h" + +static int +TIFFNoEncode(TIFF* tif, const char* method) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + + if (c) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%s %s encoding is not implemented", + c->name, method); + } else { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression scheme %"PRIu16" %s encoding is not implemented", + tif->tif_dir.td_compression, method); + } + return (-1); +} + +int +_TIFFNoRowEncode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "scanline")); +} + +int +_TIFFNoStripEncode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "strip")); +} + +int +_TIFFNoTileEncode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "tile")); +} + +static int +TIFFNoDecode(TIFF* tif, const char* method) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + + if (c) + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%s %s decoding is not implemented", + c->name, method); + else + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression scheme %"PRIu16" %s decoding is not implemented", + tif->tif_dir.td_compression, method); + return (0); +} + +static int +_TIFFNoFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +int +_TIFFNoRowDecode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "scanline")); +} + +int +_TIFFNoStripDecode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "strip")); +} + +int +_TIFFNoTileDecode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "tile")); +} + +int +_TIFFNoSeek(TIFF* tif, uint32_t off) +{ + (void) off; + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Compression algorithm does not support random access"); + return (0); +} + +int +_TIFFNoPreCode(TIFF* tif, uint16_t s) +{ + (void) tif; (void) s; + return (1); +} + +static int _TIFFtrue(TIFF* tif) { (void) tif; return (1); } +static void _TIFFvoid(TIFF* tif) { (void) tif; } + +void +_TIFFSetDefaultCompressionState(TIFF* tif) +{ + tif->tif_fixuptags = _TIFFNoFixupTags; + tif->tif_decodestatus = TRUE; + tif->tif_setupdecode = _TIFFtrue; + tif->tif_predecode = _TIFFNoPreCode; + tif->tif_decoderow = _TIFFNoRowDecode; + tif->tif_decodestrip = _TIFFNoStripDecode; + tif->tif_decodetile = _TIFFNoTileDecode; + tif->tif_encodestatus = TRUE; + tif->tif_setupencode = _TIFFtrue; + tif->tif_preencode = _TIFFNoPreCode; + tif->tif_postencode = _TIFFtrue; + tif->tif_encoderow = _TIFFNoRowEncode; + tif->tif_encodestrip = _TIFFNoStripEncode; + tif->tif_encodetile = _TIFFNoTileEncode; + tif->tif_close = _TIFFvoid; + tif->tif_seek = _TIFFNoSeek; + tif->tif_cleanup = _TIFFvoid; + tif->tif_defstripsize = _TIFFDefaultStripSize; + tif->tif_deftilesize = _TIFFDefaultTileSize; + tif->tif_flags &= ~(TIFF_NOBITREV|TIFF_NOREADRAW); +} + +int +TIFFSetCompressionScheme(TIFF* tif, int scheme) +{ + const TIFFCodec *c = TIFFFindCODEC((uint16_t) scheme); + + _TIFFSetDefaultCompressionState(tif); + /* + * Don't treat an unknown compression scheme as an error. + * This permits applications to open files with data that + * the library does not have builtin support for, but which + * may still be meaningful. + */ + return (c ? (*c->init)(tif, scheme) : 1); +} + +/* + * Other compression schemes may be registered. Registered + * schemes can also override the builtin versions provided + * by this library. + */ +typedef struct _codec { + struct _codec* next; + TIFFCodec* info; +} codec_t; +static codec_t* registeredCODECS = NULL; + +const TIFFCodec* +TIFFFindCODEC(uint16_t scheme) +{ + const TIFFCodec* c; + codec_t* cd; + + for (cd = registeredCODECS; cd; cd = cd->next) + if (cd->info->scheme == scheme) + return ((const TIFFCodec*) cd->info); + for (c = _TIFFBuiltinCODECS; c->name; c++) + if (c->scheme == scheme) + return (c); + return ((const TIFFCodec*) 0); +} + +TIFFCodec* +TIFFRegisterCODEC(uint16_t scheme, const char* name, TIFFInitMethod init) +{ + codec_t* cd = (codec_t*) + _TIFFmalloc((tmsize_t)(sizeof (codec_t) + sizeof (TIFFCodec) + strlen(name)+1)); + + if (cd != NULL) { + cd->info = (TIFFCodec*) ((uint8_t*) cd + sizeof (codec_t)); + cd->info->name = (char*) + ((uint8_t*) cd->info + sizeof (TIFFCodec)); + strcpy(cd->info->name, name); + cd->info->scheme = scheme; + cd->info->init = init; + cd->next = registeredCODECS; + registeredCODECS = cd; + } else { + TIFFErrorExt(0, "TIFFRegisterCODEC", + "No space to register compression scheme %s", name); + return NULL; + } + return (cd->info); +} + +void +TIFFUnRegisterCODEC(TIFFCodec* c) +{ + codec_t* cd; + codec_t** pcd; + + for (pcd = ®isteredCODECS; (cd = *pcd) != NULL; pcd = &cd->next) + if (cd->info == c) { + *pcd = cd->next; + _TIFFfree(cd); + return; + } + TIFFErrorExt(0, "TIFFUnRegisterCODEC", + "Cannot remove compression scheme %s; not registered", c->name); +} + +/************************************************************************/ +/* TIFFGetConfisuredCODECs() */ +/************************************************************************/ + +/** + * Get list of configured codecs, both built-in and registered by user. + * Caller is responsible to free this structure. + * + * @return returns array of TIFFCodec records (the last record should be NULL) + * or NULL if function failed. + */ + +TIFFCodec* +TIFFGetConfiguredCODECs() +{ + int i = 1; + codec_t *cd; + const TIFFCodec* c; + TIFFCodec* codecs = NULL; + TIFFCodec* new_codecs; + + for (cd = registeredCODECS; cd; cd = cd->next) { + new_codecs = (TIFFCodec *) + _TIFFrealloc(codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) { + _TIFFfree (codecs); + return NULL; + } + codecs = new_codecs; + _TIFFmemcpy(codecs + i - 1, cd->info, sizeof(TIFFCodec)); + i++; + } + for (c = _TIFFBuiltinCODECS; c->name; c++) { + if (TIFFIsCODECConfigured(c->scheme)) { + new_codecs = (TIFFCodec *) + _TIFFrealloc(codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) { + _TIFFfree (codecs); + return NULL; + } + codecs = new_codecs; + _TIFFmemcpy(codecs + i - 1, (const void*)c, sizeof(TIFFCodec)); + i++; + } + } + + new_codecs = (TIFFCodec *) _TIFFrealloc(codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) { + _TIFFfree (codecs); + return NULL; + } + codecs = new_codecs; + _TIFFmemset(codecs + i - 1, 0, sizeof(TIFFCodec)); + + return codecs; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_config.h b/libs/tiff/libtiff/tif_config.h new file mode 100644 index 00000000000..c4629bd7c34 --- /dev/null +++ b/libs/tiff/libtiff/tif_config.h @@ -0,0 +1,163 @@ +/* libtiff/tif_config.h. Generated from tif_config.h.in by configure. */ +/* libtiff/tif_config.h.in. Not generated, but originated from autoheader. */ + +#include "tiffconf.h" + +/* Support CCITT Group 3 & 4 algorithms */ +#define CCITT_SUPPORT 1 + +/* Pick up YCbCr subsampling info from the JPEG data stream to support files + lacking the tag (default enabled). */ +#define CHECK_JPEG_YCBCR_SUBSAMPLING 1 + +/* enable partial strip reading for large strips (experimental) */ +/* #undef CHUNKY_STRIP_READ_SUPPORT */ + +/* Support C++ stream API (requires C++ compiler) */ +/* #undef CXX_SUPPORT */ + +/* enable deferred strip/tile offset/size loading */ +/* #undef DEFER_STRILE_LOAD */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't. + */ +/* #undef HAVE_DECL_OPTARG */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `getopt' function. */ +/* #undef HAVE_GETOPT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_GLUT_GLUT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_GL_GLUT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_GL_GLU_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_GL_GL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IO_H 1 + +/* Define to 1 if you have the `jbg_newlen' function. */ +/* #undef HAVE_JBG_NEWLEN */ + +/* Define to 1 if you have the `mmap' function. */ +/* #undef HAVE_MMAP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_OPENGL_GLU_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_OPENGL_GL_H */ + +/* Define to 1 if you have the `setmode' function. */ +#define HAVE_SETMODE 1 + +/* Define to 1 if you have the `snprintf' function. */ +/* #undef HAVE_SNPRINTF */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* 8/12 bit libjpeg dual mode enabled */ +/* #undef JPEG_DUAL_MODE_8_12 */ + +/* Support LERC compression */ +/* #undef LERC_SUPPORT */ + +/* 12bit libjpeg primary include file with path */ +/* #undef LIBJPEG_12_PATH */ + +/* Support LZMA2 compression */ +/* #undef LZMA_SUPPORT */ + +/* Name of package */ +#define PACKAGE "tiff" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "tiff@lists.maptools.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "LibTIFF Software" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "LibTIFF Software 4.3.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "tiff" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "4.3.0" + +/* The size of `size_t', as computed by sizeof. */ +/* #undef SIZEOF_SIZE_T */ + +/* Default size of the strip in bytes (when strip chopping enabled) */ +#define STRIP_SIZE_DEFAULT 8192 + +/* define to use win32 IO system */ +#define USE_WIN32_FILEIO 1 + +/* Version number of package */ +#define VERSION "4.3.0" + +/* Support webp compression */ +/* #undef WEBP_SUPPORT */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Support zstd compression */ +/* #undef ZSTD_SUPPORT */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +/* #undef _LARGEFILE_SOURCE */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +#if !defined(__MINGW32__) +# define TIFF_SIZE_FORMAT "zu" +# define TIFF_SSIZE_FORMAT "zd" +#else +# define TIFF_SIZE_FORMAT "Iu" +# define TIFF_SSIZE_FORMAT "Id" +#endif diff --git a/libs/tiff/libtiff/tif_dir.c b/libs/tiff/libtiff/tif_dir.c new file mode 100644 index 00000000000..0bd43a62e74 --- /dev/null +++ b/libs/tiff/libtiff/tif_dir.c @@ -0,0 +1,1835 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Tag Get & Set Routines. + * (and also some miscellaneous stuff) + */ +#include "tiffiop.h" +#include /*--: for Rational2Double */ + +/* + * These are used in the backwards compatibility code... + */ +#define DATATYPE_VOID 0 /* !untyped data */ +#define DATATYPE_INT 1 /* !signed integer data */ +#define DATATYPE_UINT 2 /* !unsigned integer data */ +#define DATATYPE_IEEEFP 3 /* !IEEE floating point data */ + +static void +setByteArray(void** vpp, void* vp, size_t nmemb, size_t elem_size) +{ + if (*vpp) { + _TIFFfree(*vpp); + *vpp = 0; + } + if (vp) { + tmsize_t bytes = _TIFFMultiplySSize(NULL, nmemb, elem_size, NULL); + if (bytes) + *vpp = (void*) _TIFFmalloc(bytes); + if (*vpp) + _TIFFmemcpy(*vpp, vp, bytes); + } +} +void _TIFFsetByteArray(void** vpp, void* vp, uint32_t n) + { setByteArray(vpp, vp, n, 1); } +void _TIFFsetString(char** cpp, char* cp) + { setByteArray((void**) cpp, (void*) cp, strlen(cp)+1, 1); } +static void _TIFFsetNString(char** cpp, char* cp, uint32_t n) + { setByteArray((void**) cpp, (void*) cp, n, 1); } +void _TIFFsetShortArray(uint16_t** wpp, uint16_t* wp, uint32_t n) + { setByteArray((void**) wpp, (void*) wp, n, sizeof (uint16_t)); } +void _TIFFsetLongArray(uint32_t** lpp, uint32_t* lp, uint32_t n) + { setByteArray((void**) lpp, (void*) lp, n, sizeof (uint32_t)); } +static void _TIFFsetLong8Array(uint64_t** lpp, uint64_t* lp, uint32_t n) + { setByteArray((void**) lpp, (void*) lp, n, sizeof (uint64_t)); } +void _TIFFsetFloatArray(float** fpp, float* fp, uint32_t n) + { setByteArray((void**) fpp, (void*) fp, n, sizeof (float)); } +void _TIFFsetDoubleArray(double** dpp, double* dp, uint32_t n) + { setByteArray((void**) dpp, (void*) dp, n, sizeof (double)); } + +static void +setDoubleArrayOneValue(double** vpp, double value, size_t nmemb) +{ + if (*vpp) + _TIFFfree(*vpp); + *vpp = _TIFFmalloc(nmemb*sizeof(double)); + if (*vpp) + { + while (nmemb--) + ((double*)*vpp)[nmemb] = value; + } +} + +/* + * Install extra samples information. + */ +static int +setExtraSamples(TIFF* tif, va_list ap, uint32_t* v) +{ +/* XXX: Unassociated alpha data == 999 is a known Corel Draw bug, see below */ +#define EXTRASAMPLE_COREL_UNASSALPHA 999 + + uint16_t* va; + uint32_t i; + TIFFDirectory* td = &tif->tif_dir; + static const char module[] = "setExtraSamples"; + + *v = (uint16_t) va_arg(ap, uint16_vap); + if ((uint16_t) *v > td->td_samplesperpixel) + return 0; + va = va_arg(ap, uint16_t*); + if (*v > 0 && va == NULL) /* typically missing param */ + return 0; + for (i = 0; i < *v; i++) { + if (va[i] > EXTRASAMPLE_UNASSALPHA) { + /* + * XXX: Corel Draw is known to produce incorrect + * ExtraSamples tags which must be patched here if we + * want to be able to open some of the damaged TIFF + * files: + */ + if (va[i] == EXTRASAMPLE_COREL_UNASSALPHA) + va[i] = EXTRASAMPLE_UNASSALPHA; + else + return 0; + } + } + + if ( td->td_transferfunction[0] != NULL && (td->td_samplesperpixel - *v > 1) && + !(td->td_samplesperpixel - td->td_extrasamples > 1)) + { + TIFFWarningExt(tif->tif_clientdata,module, + "ExtraSamples tag value is changing, " + "but TransferFunction was read with a different value. Canceling it"); + TIFFClrFieldBit(tif,FIELD_TRANSFERFUNCTION); + _TIFFfree(td->td_transferfunction[0]); + td->td_transferfunction[0] = NULL; + } + + td->td_extrasamples = (uint16_t) *v; + _TIFFsetShortArray(&td->td_sampleinfo, va, td->td_extrasamples); + return 1; + +#undef EXTRASAMPLE_COREL_UNASSALPHA +} + +/* + * Confirm we have "samplesperpixel" ink names separated by \0. Returns + * zero if the ink names are not as expected. + */ +static uint32_t +checkInkNamesString(TIFF* tif, uint32_t slen, const char* s) +{ + TIFFDirectory* td = &tif->tif_dir; + uint16_t i = td->td_samplesperpixel; + + if (slen > 0) { + const char* ep = s+slen; + const char* cp = s; + for (; i > 0; i--) { + for (; cp < ep && *cp != '\0'; cp++) {} + if (cp >= ep) + goto bad; + cp++; /* skip \0 */ + } + return ((uint32_t)(cp - s)); + } +bad: + TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", + "%s: Invalid InkNames value; expecting %"PRIu16" names, found %"PRIu16, + tif->tif_name, + td->td_samplesperpixel, + (uint16_t)(td->td_samplesperpixel-i)); + return (0); +} + +static int +_TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap) +{ + static const char module[] = "_TIFFVSetField"; + + TIFFDirectory* td = &tif->tif_dir; + int status = 1; + uint32_t v32, i, v; + double dblval; + char* s; + const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY); + uint32_t standard_tag = tag; + if( fip == NULL ) /* cannot happen since OkToChangeTag() already checks it */ + return 0; + /* + * We want to force the custom code to be used for custom + * fields even if the tag happens to match a well known + * one - important for reinterpreted handling of standard + * tag values in custom directories (i.e. EXIF) + */ + if (fip->field_bit == FIELD_CUSTOM) { + standard_tag = 0; + } + + switch (standard_tag) { + case TIFFTAG_SUBFILETYPE: + td->td_subfiletype = (uint32_t) va_arg(ap, uint32_t); + break; + case TIFFTAG_IMAGEWIDTH: + td->td_imagewidth = (uint32_t) va_arg(ap, uint32_t); + break; + case TIFFTAG_IMAGELENGTH: + td->td_imagelength = (uint32_t) va_arg(ap, uint32_t); + break; + case TIFFTAG_BITSPERSAMPLE: + td->td_bitspersample = (uint16_t) va_arg(ap, uint16_vap); + /* + * If the data require post-decoding processing to byte-swap + * samples, set it up here. Note that since tags are required + * to be ordered, compression code can override this behavior + * in the setup method if it wants to roll the post decoding + * work in with its normal work. + */ + if (tif->tif_flags & TIFF_SWAB) { + if (td->td_bitspersample == 8) + tif->tif_postdecode = _TIFFNoPostDecode; + else if (td->td_bitspersample == 16) + tif->tif_postdecode = _TIFFSwab16BitData; + else if (td->td_bitspersample == 24) + tif->tif_postdecode = _TIFFSwab24BitData; + else if (td->td_bitspersample == 32) + tif->tif_postdecode = _TIFFSwab32BitData; + else if (td->td_bitspersample == 64) + tif->tif_postdecode = _TIFFSwab64BitData; + else if (td->td_bitspersample == 128) /* two 64's */ + tif->tif_postdecode = _TIFFSwab64BitData; + } + break; + case TIFFTAG_COMPRESSION: + v = (uint16_t) va_arg(ap, uint16_vap); + /* + * If we're changing the compression scheme, the notify the + * previous module so that it can cleanup any state it's + * setup. + */ + if (TIFFFieldSet(tif, FIELD_COMPRESSION)) { + if ((uint32_t)td->td_compression == v) + break; + (*tif->tif_cleanup)(tif); + tif->tif_flags &= ~TIFF_CODERSETUP; + } + /* + * Setup new compression routine state. + */ + if( (status = TIFFSetCompressionScheme(tif, v)) != 0 ) + td->td_compression = (uint16_t) v; + else + status = 0; + break; + case TIFFTAG_PHOTOMETRIC: + td->td_photometric = (uint16_t) va_arg(ap, uint16_vap); + break; + case TIFFTAG_THRESHHOLDING: + td->td_threshholding = (uint16_t) va_arg(ap, uint16_vap); + break; + case TIFFTAG_FILLORDER: + v = (uint16_t) va_arg(ap, uint16_vap); + if (v != FILLORDER_LSB2MSB && v != FILLORDER_MSB2LSB) + goto badvalue; + td->td_fillorder = (uint16_t) v; + break; + case TIFFTAG_ORIENTATION: + v = (uint16_t) va_arg(ap, uint16_vap); + if (v < ORIENTATION_TOPLEFT || ORIENTATION_LEFTBOT < v) + goto badvalue; + else + td->td_orientation = (uint16_t) v; + break; + case TIFFTAG_SAMPLESPERPIXEL: + v = (uint16_t) va_arg(ap, uint16_vap); + if (v == 0) + goto badvalue; + if( v != td->td_samplesperpixel ) + { + /* See http://bugzilla.maptools.org/show_bug.cgi?id=2500 */ + if( td->td_sminsamplevalue != NULL ) + { + TIFFWarningExt(tif->tif_clientdata,module, + "SamplesPerPixel tag value is changing, " + "but SMinSampleValue tag was read with a different value. Canceling it"); + TIFFClrFieldBit(tif,FIELD_SMINSAMPLEVALUE); + _TIFFfree(td->td_sminsamplevalue); + td->td_sminsamplevalue = NULL; + } + if( td->td_smaxsamplevalue != NULL ) + { + TIFFWarningExt(tif->tif_clientdata,module, + "SamplesPerPixel tag value is changing, " + "but SMaxSampleValue tag was read with a different value. Canceling it"); + TIFFClrFieldBit(tif,FIELD_SMAXSAMPLEVALUE); + _TIFFfree(td->td_smaxsamplevalue); + td->td_smaxsamplevalue = NULL; + } + /* Test if 3 transfer functions instead of just one are now needed + See http://bugzilla.maptools.org/show_bug.cgi?id=2820 */ + if( td->td_transferfunction[0] != NULL && (v - td->td_extrasamples > 1) && + !(td->td_samplesperpixel - td->td_extrasamples > 1)) + { + TIFFWarningExt(tif->tif_clientdata,module, + "SamplesPerPixel tag value is changing, " + "but TransferFunction was read with a different value. Canceling it"); + TIFFClrFieldBit(tif,FIELD_TRANSFERFUNCTION); + _TIFFfree(td->td_transferfunction[0]); + td->td_transferfunction[0] = NULL; + } + } + td->td_samplesperpixel = (uint16_t) v; + break; + case TIFFTAG_ROWSPERSTRIP: + v32 = (uint32_t) va_arg(ap, uint32_t); + if (v32 == 0) + goto badvalue32; + td->td_rowsperstrip = v32; + if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { + td->td_tilelength = v32; + td->td_tilewidth = td->td_imagewidth; + } + break; + case TIFFTAG_MINSAMPLEVALUE: + td->td_minsamplevalue = (uint16_t) va_arg(ap, uint16_vap); + break; + case TIFFTAG_MAXSAMPLEVALUE: + td->td_maxsamplevalue = (uint16_t) va_arg(ap, uint16_vap); + break; + case TIFFTAG_SMINSAMPLEVALUE: + if (tif->tif_flags & TIFF_PERSAMPLE) + _TIFFsetDoubleArray(&td->td_sminsamplevalue, va_arg(ap, double*), td->td_samplesperpixel); + else + setDoubleArrayOneValue(&td->td_sminsamplevalue, va_arg(ap, double), td->td_samplesperpixel); + break; + case TIFFTAG_SMAXSAMPLEVALUE: + if (tif->tif_flags & TIFF_PERSAMPLE) + _TIFFsetDoubleArray(&td->td_smaxsamplevalue, va_arg(ap, double*), td->td_samplesperpixel); + else + setDoubleArrayOneValue(&td->td_smaxsamplevalue, va_arg(ap, double), td->td_samplesperpixel); + break; + case TIFFTAG_XRESOLUTION: + dblval = va_arg(ap, double); + if( dblval < 0 ) + goto badvaluedouble; + td->td_xresolution = _TIFFClampDoubleToFloat( dblval ); + break; + case TIFFTAG_YRESOLUTION: + dblval = va_arg(ap, double); + if( dblval < 0 ) + goto badvaluedouble; + td->td_yresolution = _TIFFClampDoubleToFloat( dblval ); + break; + case TIFFTAG_PLANARCONFIG: + v = (uint16_t) va_arg(ap, uint16_vap); + if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE) + goto badvalue; + td->td_planarconfig = (uint16_t) v; + break; + case TIFFTAG_XPOSITION: + td->td_xposition = _TIFFClampDoubleToFloat( va_arg(ap, double) ); + break; + case TIFFTAG_YPOSITION: + td->td_yposition = _TIFFClampDoubleToFloat( va_arg(ap, double) ); + break; + case TIFFTAG_RESOLUTIONUNIT: + v = (uint16_t) va_arg(ap, uint16_vap); + if (v < RESUNIT_NONE || RESUNIT_CENTIMETER < v) + goto badvalue; + td->td_resolutionunit = (uint16_t) v; + break; + case TIFFTAG_PAGENUMBER: + td->td_pagenumber[0] = (uint16_t) va_arg(ap, uint16_vap); + td->td_pagenumber[1] = (uint16_t) va_arg(ap, uint16_vap); + break; + case TIFFTAG_HALFTONEHINTS: + td->td_halftonehints[0] = (uint16_t) va_arg(ap, uint16_vap); + td->td_halftonehints[1] = (uint16_t) va_arg(ap, uint16_vap); + break; + case TIFFTAG_COLORMAP: + v32 = (uint32_t)(1L << td->td_bitspersample); + _TIFFsetShortArray(&td->td_colormap[0], va_arg(ap, uint16_t*), v32); + _TIFFsetShortArray(&td->td_colormap[1], va_arg(ap, uint16_t*), v32); + _TIFFsetShortArray(&td->td_colormap[2], va_arg(ap, uint16_t*), v32); + break; + case TIFFTAG_EXTRASAMPLES: + if (!setExtraSamples(tif, ap, &v)) + goto badvalue; + break; + case TIFFTAG_MATTEING: + td->td_extrasamples = (((uint16_t) va_arg(ap, uint16_vap)) != 0); + if (td->td_extrasamples) { + uint16_t sv = EXTRASAMPLE_ASSOCALPHA; + _TIFFsetShortArray(&td->td_sampleinfo, &sv, 1); + } + break; + case TIFFTAG_TILEWIDTH: + v32 = (uint32_t) va_arg(ap, uint32_t); + if (v32 % 16) { + if (tif->tif_mode != O_RDONLY) + goto badvalue32; + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "Nonstandard tile width %"PRIu32", convert file", v32); + } + td->td_tilewidth = v32; + tif->tif_flags |= TIFF_ISTILED; + break; + case TIFFTAG_TILELENGTH: + v32 = (uint32_t) va_arg(ap, uint32_t); + if (v32 % 16) { + if (tif->tif_mode != O_RDONLY) + goto badvalue32; + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "Nonstandard tile length %"PRIu32", convert file", v32); + } + td->td_tilelength = v32; + tif->tif_flags |= TIFF_ISTILED; + break; + case TIFFTAG_TILEDEPTH: + v32 = (uint32_t) va_arg(ap, uint32_t); + if (v32 == 0) + goto badvalue32; + td->td_tiledepth = v32; + break; + case TIFFTAG_DATATYPE: + v = (uint16_t) va_arg(ap, uint16_vap); + switch (v) { + case DATATYPE_VOID: v = SAMPLEFORMAT_VOID; break; + case DATATYPE_INT: v = SAMPLEFORMAT_INT; break; + case DATATYPE_UINT: v = SAMPLEFORMAT_UINT; break; + case DATATYPE_IEEEFP: v = SAMPLEFORMAT_IEEEFP;break; + default: goto badvalue; + } + td->td_sampleformat = (uint16_t) v; + break; + case TIFFTAG_SAMPLEFORMAT: + v = (uint16_t) va_arg(ap, uint16_vap); + if (v < SAMPLEFORMAT_UINT || SAMPLEFORMAT_COMPLEXIEEEFP < v) + goto badvalue; + td->td_sampleformat = (uint16_t) v; + + /* Try to fix up the SWAB function for complex data. */ + if( td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT + && td->td_bitspersample == 32 + && tif->tif_postdecode == _TIFFSwab32BitData ) + tif->tif_postdecode = _TIFFSwab16BitData; + else if( (td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT + || td->td_sampleformat == SAMPLEFORMAT_COMPLEXIEEEFP) + && td->td_bitspersample == 64 + && tif->tif_postdecode == _TIFFSwab64BitData ) + tif->tif_postdecode = _TIFFSwab32BitData; + break; + case TIFFTAG_IMAGEDEPTH: + td->td_imagedepth = (uint32_t) va_arg(ap, uint32_t); + break; + case TIFFTAG_SUBIFD: + if ((tif->tif_flags & TIFF_INSUBIFD) == 0) { + td->td_nsubifd = (uint16_t) va_arg(ap, uint16_vap); + _TIFFsetLong8Array(&td->td_subifd, (uint64_t*) va_arg(ap, uint64_t*), + (uint32_t) td->td_nsubifd); + } else { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Sorry, cannot nest SubIFDs", + tif->tif_name); + status = 0; + } + break; + case TIFFTAG_YCBCRPOSITIONING: + td->td_ycbcrpositioning = (uint16_t) va_arg(ap, uint16_vap); + break; + case TIFFTAG_YCBCRSUBSAMPLING: + td->td_ycbcrsubsampling[0] = (uint16_t) va_arg(ap, uint16_vap); + td->td_ycbcrsubsampling[1] = (uint16_t) va_arg(ap, uint16_vap); + break; + case TIFFTAG_TRANSFERFUNCTION: + v = (td->td_samplesperpixel - td->td_extrasamples) > 1 ? 3 : 1; + for (i = 0; i < v; i++) + _TIFFsetShortArray(&td->td_transferfunction[i], + va_arg(ap, uint16_t*), 1U << td->td_bitspersample); + break; + case TIFFTAG_REFERENCEBLACKWHITE: + /* XXX should check for null range */ + _TIFFsetFloatArray(&td->td_refblackwhite, va_arg(ap, float*), 6); + break; + case TIFFTAG_INKNAMES: + v = (uint16_t) va_arg(ap, uint16_vap); + s = va_arg(ap, char*); + v = checkInkNamesString(tif, v, s); + status = v > 0; + if( v > 0 ) { + _TIFFsetNString(&td->td_inknames, s, v); + td->td_inknameslen = v; + } + break; + case TIFFTAG_PERSAMPLE: + v = (uint16_t) va_arg(ap, uint16_vap); + if( v == PERSAMPLE_MULTI ) + tif->tif_flags |= TIFF_PERSAMPLE; + else + tif->tif_flags &= ~TIFF_PERSAMPLE; + break; + default: { + TIFFTagValue *tv; + int tv_size, iCustom; + + /* + * This can happen if multiple images are open with different + * codecs which have private tags. The global tag information + * table may then have tags that are valid for one file but not + * the other. If the client tries to set a tag that is not valid + * for the image's codec then we'll arrive here. This + * happens, for example, when tiffcp is used to convert between + * compression schemes and codec-specific tags are blindly copied. + */ + if(fip->field_bit != FIELD_CUSTOM) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Invalid %stag \"%s\" (not supported by codec)", + tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", + fip->field_name); + status = 0; + break; + } + + /* + * Find the existing entry for this custom value. + */ + tv = NULL; + for (iCustom = 0; iCustom < td->td_customValueCount; iCustom++) { + if (td->td_customValues[iCustom].info->field_tag == tag) { + tv = td->td_customValues + iCustom; + if (tv->value != NULL) { + _TIFFfree(tv->value); + tv->value = NULL; + } + break; + } + } + + /* + * Grow the custom list if the entry was not found. + */ + if(tv == NULL) { + TIFFTagValue *new_customValues; + + td->td_customValueCount++; + new_customValues = (TIFFTagValue *) + _TIFFrealloc(td->td_customValues, + sizeof(TIFFTagValue) * td->td_customValueCount); + if (!new_customValues) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Failed to allocate space for list of custom values", + tif->tif_name); + status = 0; + goto end; + } + + td->td_customValues = new_customValues; + + tv = td->td_customValues + (td->td_customValueCount - 1); + tv->info = fip; + tv->value = NULL; + tv->count = 0; + } + + /* + * Set custom value ... save a copy of the custom tag value. + */ + tv_size = _TIFFDataSize(fip->field_type); + /*--: Rational2Double: For Rationals evaluate "set_field_type" to determine internal storage size. */ + if (fip->field_type == TIFF_RATIONAL || fip->field_type == TIFF_SRATIONAL) { + tv_size = _TIFFSetGetFieldSize(fip->set_field_type); + } + if (tv_size == 0) { + status = 0; + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad field type %d for \"%s\"", + tif->tif_name, fip->field_type, + fip->field_name); + goto end; + } + + if (fip->field_type == TIFF_ASCII) + { + uint32_t ma; + char* mb; + if (fip->field_passcount) + { + assert(fip->field_writecount==TIFF_VARIABLE2); + ma=(uint32_t)va_arg(ap, uint32_t); + mb=(char*)va_arg(ap,char*); + } + else + { + mb=(char*)va_arg(ap,char*); + ma=(uint32_t)(strlen(mb) + 1); + } + tv->count=ma; + setByteArray(&tv->value,mb,ma,1); + } + else + { + if (fip->field_passcount) { + if (fip->field_writecount == TIFF_VARIABLE2) + tv->count = (uint32_t) va_arg(ap, uint32_t); + else + tv->count = (int) va_arg(ap, int); + } else if (fip->field_writecount == TIFF_VARIABLE + || fip->field_writecount == TIFF_VARIABLE2) + tv->count = 1; + else if (fip->field_writecount == TIFF_SPP) + tv->count = td->td_samplesperpixel; + else + tv->count = fip->field_writecount; + + if (tv->count == 0) { + status = 0; + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Null count for \"%s\" (type " + "%d, writecount %d, passcount %d)", + tif->tif_name, + fip->field_name, + fip->field_type, + fip->field_writecount, + fip->field_passcount); + goto end; + } + + tv->value = _TIFFCheckMalloc(tif, tv->count, tv_size, + "custom tag binary object"); + if (!tv->value) { + status = 0; + goto end; + } + + if (fip->field_tag == TIFFTAG_DOTRANGE + && strcmp(fip->field_name,"DotRange") == 0) { + /* TODO: This is an evil exception and should not have been + handled this way ... likely best if we move it into + the directory structure with an explicit field in + libtiff 4.1 and assign it a FIELD_ value */ + uint16_t v2[2]; + v2[0] = (uint16_t)va_arg(ap, int); + v2[1] = (uint16_t)va_arg(ap, int); + _TIFFmemcpy(tv->value, &v2, 4); + } + + else if (fip->field_passcount + || fip->field_writecount == TIFF_VARIABLE + || fip->field_writecount == TIFF_VARIABLE2 + || fip->field_writecount == TIFF_SPP + || tv->count > 1) { + /*--: Rational2Double: For Rationals tv_size is set above to 4 or 8 according to fip->set_field_type! */ + _TIFFmemcpy(tv->value, va_arg(ap, void *), + tv->count * tv_size); + } else { + char *val = (char *)tv->value; + assert( tv->count == 1 ); + + switch (fip->field_type) { + case TIFF_BYTE: + case TIFF_UNDEFINED: + { + uint8_t v2 = (uint8_t)va_arg(ap, int); + _TIFFmemcpy(val, &v2, tv_size); + } + break; + case TIFF_SBYTE: + { + int8_t v2 = (int8_t)va_arg(ap, int); + _TIFFmemcpy(val, &v2, tv_size); + } + break; + case TIFF_SHORT: + { + uint16_t v2 = (uint16_t)va_arg(ap, int); + _TIFFmemcpy(val, &v2, tv_size); + } + break; + case TIFF_SSHORT: + { + int16_t v2 = (int16_t)va_arg(ap, int); + _TIFFmemcpy(val, &v2, tv_size); + } + break; + case TIFF_LONG: + case TIFF_IFD: + { + uint32_t v2 = va_arg(ap, uint32_t); + _TIFFmemcpy(val, &v2, tv_size); + } + break; + case TIFF_SLONG: + { + int32_t v2 = va_arg(ap, int32_t); + _TIFFmemcpy(val, &v2, tv_size); + } + break; + case TIFF_LONG8: + case TIFF_IFD8: + { + uint64_t v2 = va_arg(ap, uint64_t); + _TIFFmemcpy(val, &v2, tv_size); + } + break; + case TIFF_SLONG8: + { + int64_t v2 = va_arg(ap, int64_t); + _TIFFmemcpy(val, &v2, tv_size); + } + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + /*-- Rational2Double: For Rationals tv_size is set above to 4 or 8 according to fip->set_field_type! */ + { + if (tv_size == 8) { + double v2 = va_arg(ap, double); + _TIFFmemcpy(val, &v2, tv_size); + } else { + /*-- default should be tv_size == 4 */ + float v3 = (float)va_arg(ap, double); + _TIFFmemcpy(val, &v3, tv_size); + /*-- ToDo: After Testing, this should be removed and tv_size==4 should be set as default. */ + if (tv_size != 4) { + TIFFErrorExt(0,"TIFFLib: _TIFFVSetField()", "Rational2Double: .set_field_type in not 4 but %d", tv_size); + } + } + } + break; + case TIFF_FLOAT: + { + float v2 = _TIFFClampDoubleToFloat(va_arg(ap, double)); + _TIFFmemcpy(val, &v2, tv_size); + } + break; + case TIFF_DOUBLE: + { + double v2 = va_arg(ap, double); + _TIFFmemcpy(val, &v2, tv_size); + } + break; + default: + _TIFFmemset(val, 0, tv_size); + status = 0; + break; + } + } + } + } + } + if (status) { + const TIFFField* fip2=TIFFFieldWithTag(tif,tag); + if (fip2) + TIFFSetFieldBit(tif, fip2->field_bit); + tif->tif_flags |= TIFF_DIRTYDIRECT; + } + +end: + va_end(ap); + return (status); +badvalue: + { + const TIFFField* fip2=TIFFFieldWithTag(tif,tag); + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad value %"PRIu32" for \"%s\" tag", + tif->tif_name, v, + fip2 ? fip2->field_name : "Unknown"); + va_end(ap); + } + return (0); +badvalue32: + { + const TIFFField* fip2=TIFFFieldWithTag(tif,tag); + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad value %"PRIu32" for \"%s\" tag", + tif->tif_name, v32, + fip2 ? fip2->field_name : "Unknown"); + va_end(ap); + } + return (0); +badvaluedouble: + { + const TIFFField* fip2=TIFFFieldWithTag(tif,tag); + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Bad value %f for \"%s\" tag", + tif->tif_name, dblval, + fip2 ? fip2->field_name : "Unknown"); + va_end(ap); + } + return (0); +} + +/* + * Return 1/0 according to whether or not + * it is permissible to set the tag's value. + * Note that we allow ImageLength to be changed + * so that we can append and extend to images. + * Any other tag may not be altered once writing + * has commenced, unless its value has no effect + * on the format of the data that is written. + */ +static int +OkToChangeTag(TIFF* tif, uint32_t tag) +{ + const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); + if (!fip) { /* unknown tag */ + TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", "%s: Unknown %stag %"PRIu32, + tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", tag); + return (0); + } + if (tag != TIFFTAG_IMAGELENGTH && (tif->tif_flags & TIFF_BEENWRITING) && + !fip->field_oktochange) { + /* + * Consult info table to see if tag can be changed + * after we've started writing. We only allow changes + * to those tags that don't/shouldn't affect the + * compression and/or format of the data. + */ + TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", + "%s: Cannot modify tag \"%s\" while writing", + tif->tif_name, fip->field_name); + return (0); + } + return (1); +} + +/* + * Record the value of a field in the + * internal directory structure. The + * field will be written to the file + * when/if the directory structure is + * updated. + */ +int WINAPIV +TIFFSetField(TIFF* tif, uint32_t tag, ...) +{ + va_list ap; + int status; + + va_start(ap, tag); + status = TIFFVSetField(tif, tag, ap); + va_end(ap); + return (status); +} + +/* + * Clear the contents of the field in the internal structure. + */ +int +TIFFUnsetField(TIFF* tif, uint32_t tag) +{ + const TIFFField *fip = TIFFFieldWithTag(tif, tag); + TIFFDirectory* td = &tif->tif_dir; + + if( !fip ) + return 0; + + if( fip->field_bit != FIELD_CUSTOM ) + TIFFClrFieldBit(tif, fip->field_bit); + else + { + TIFFTagValue *tv = NULL; + int i; + + for (i = 0; i < td->td_customValueCount; i++) { + + tv = td->td_customValues + i; + if( tv->info->field_tag == tag ) + break; + } + + if( i < td->td_customValueCount ) + { + _TIFFfree(tv->value); + for( ; i < td->td_customValueCount-1; i++) { + td->td_customValues[i] = td->td_customValues[i+1]; + } + td->td_customValueCount--; + } + } + + tif->tif_flags |= TIFF_DIRTYDIRECT; + + return (1); +} + +/* + * Like TIFFSetField, but taking a varargs + * parameter list. This routine is useful + * for building higher-level interfaces on + * top of the library. + */ +int +TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap) +{ + return OkToChangeTag(tif, tag) ? + (*tif->tif_tagmethods.vsetfield)(tif, tag, ap) : 0; +} + +static int +_TIFFVGetField(TIFF* tif, uint32_t tag, va_list ap) +{ + TIFFDirectory* td = &tif->tif_dir; + int ret_val = 1; + uint32_t standard_tag = tag; + const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); + if( fip == NULL ) /* cannot happen since TIFFGetField() already checks it */ + return 0; + + /* + * We want to force the custom code to be used for custom + * fields even if the tag happens to match a well known + * one - important for reinterpreted handling of standard + * tag values in custom directories (i.e. EXIF) + */ + if (fip->field_bit == FIELD_CUSTOM) { + standard_tag = 0; + } + + if( standard_tag == TIFFTAG_NUMBEROFINKS ) + { + int i; + for (i = 0; i < td->td_customValueCount; i++) { + uint16_t val; + TIFFTagValue *tv = td->td_customValues + i; + if (tv->info->field_tag != standard_tag) + continue; + if( tv->value == NULL ) + return 0; + val = *(uint16_t *)tv->value; + /* Truncate to SamplesPerPixel, since the */ + /* setting code for INKNAMES assume that there are SamplesPerPixel */ + /* inknames. */ + /* Fixes http://bugzilla.maptools.org/show_bug.cgi?id=2599 */ + if( val > td->td_samplesperpixel ) + { + TIFFWarningExt(tif->tif_clientdata,"_TIFFVGetField", + "Truncating NumberOfInks from %u to %"PRIu16, + val, td->td_samplesperpixel); + val = td->td_samplesperpixel; + } + *va_arg(ap, uint16_t*) = val; + return 1; + } + return 0; + } + + switch (standard_tag) { + case TIFFTAG_SUBFILETYPE: + *va_arg(ap, uint32_t*) = td->td_subfiletype; + break; + case TIFFTAG_IMAGEWIDTH: + *va_arg(ap, uint32_t*) = td->td_imagewidth; + break; + case TIFFTAG_IMAGELENGTH: + *va_arg(ap, uint32_t*) = td->td_imagelength; + break; + case TIFFTAG_BITSPERSAMPLE: + *va_arg(ap, uint16_t*) = td->td_bitspersample; + break; + case TIFFTAG_COMPRESSION: + *va_arg(ap, uint16_t*) = td->td_compression; + break; + case TIFFTAG_PHOTOMETRIC: + *va_arg(ap, uint16_t*) = td->td_photometric; + break; + case TIFFTAG_THRESHHOLDING: + *va_arg(ap, uint16_t*) = td->td_threshholding; + break; + case TIFFTAG_FILLORDER: + *va_arg(ap, uint16_t*) = td->td_fillorder; + break; + case TIFFTAG_ORIENTATION: + *va_arg(ap, uint16_t*) = td->td_orientation; + break; + case TIFFTAG_SAMPLESPERPIXEL: + *va_arg(ap, uint16_t*) = td->td_samplesperpixel; + break; + case TIFFTAG_ROWSPERSTRIP: + *va_arg(ap, uint32_t*) = td->td_rowsperstrip; + break; + case TIFFTAG_MINSAMPLEVALUE: + *va_arg(ap, uint16_t*) = td->td_minsamplevalue; + break; + case TIFFTAG_MAXSAMPLEVALUE: + *va_arg(ap, uint16_t*) = td->td_maxsamplevalue; + break; + case TIFFTAG_SMINSAMPLEVALUE: + if (tif->tif_flags & TIFF_PERSAMPLE) + *va_arg(ap, double**) = td->td_sminsamplevalue; + else + { + /* libtiff historically treats this as a single value. */ + uint16_t i; + double v = td->td_sminsamplevalue[0]; + for (i=1; i < td->td_samplesperpixel; ++i) + if( td->td_sminsamplevalue[i] < v ) + v = td->td_sminsamplevalue[i]; + *va_arg(ap, double*) = v; + } + break; + case TIFFTAG_SMAXSAMPLEVALUE: + if (tif->tif_flags & TIFF_PERSAMPLE) + *va_arg(ap, double**) = td->td_smaxsamplevalue; + else + { + /* libtiff historically treats this as a single value. */ + uint16_t i; + double v = td->td_smaxsamplevalue[0]; + for (i=1; i < td->td_samplesperpixel; ++i) + if( td->td_smaxsamplevalue[i] > v ) + v = td->td_smaxsamplevalue[i]; + *va_arg(ap, double*) = v; + } + break; + case TIFFTAG_XRESOLUTION: + *va_arg(ap, float*) = td->td_xresolution; + break; + case TIFFTAG_YRESOLUTION: + *va_arg(ap, float*) = td->td_yresolution; + break; + case TIFFTAG_PLANARCONFIG: + *va_arg(ap, uint16_t*) = td->td_planarconfig; + break; + case TIFFTAG_XPOSITION: + *va_arg(ap, float*) = td->td_xposition; + break; + case TIFFTAG_YPOSITION: + *va_arg(ap, float*) = td->td_yposition; + break; + case TIFFTAG_RESOLUTIONUNIT: + *va_arg(ap, uint16_t*) = td->td_resolutionunit; + break; + case TIFFTAG_PAGENUMBER: + *va_arg(ap, uint16_t*) = td->td_pagenumber[0]; + *va_arg(ap, uint16_t*) = td->td_pagenumber[1]; + break; + case TIFFTAG_HALFTONEHINTS: + *va_arg(ap, uint16_t*) = td->td_halftonehints[0]; + *va_arg(ap, uint16_t*) = td->td_halftonehints[1]; + break; + case TIFFTAG_COLORMAP: + *va_arg(ap, const uint16_t**) = td->td_colormap[0]; + *va_arg(ap, const uint16_t**) = td->td_colormap[1]; + *va_arg(ap, const uint16_t**) = td->td_colormap[2]; + break; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_TILEOFFSETS: + _TIFFFillStriles( tif ); + *va_arg(ap, const uint64_t**) = td->td_stripoffset_p; + break; + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEBYTECOUNTS: + _TIFFFillStriles( tif ); + *va_arg(ap, const uint64_t**) = td->td_stripbytecount_p; + break; + case TIFFTAG_MATTEING: + *va_arg(ap, uint16_t*) = + (td->td_extrasamples == 1 && + td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA); + break; + case TIFFTAG_EXTRASAMPLES: + *va_arg(ap, uint16_t*) = td->td_extrasamples; + *va_arg(ap, const uint16_t**) = td->td_sampleinfo; + break; + case TIFFTAG_TILEWIDTH: + *va_arg(ap, uint32_t*) = td->td_tilewidth; + break; + case TIFFTAG_TILELENGTH: + *va_arg(ap, uint32_t*) = td->td_tilelength; + break; + case TIFFTAG_TILEDEPTH: + *va_arg(ap, uint32_t*) = td->td_tiledepth; + break; + case TIFFTAG_DATATYPE: + switch (td->td_sampleformat) { + case SAMPLEFORMAT_UINT: + *va_arg(ap, uint16_t*) = DATATYPE_UINT; + break; + case SAMPLEFORMAT_INT: + *va_arg(ap, uint16_t*) = DATATYPE_INT; + break; + case SAMPLEFORMAT_IEEEFP: + *va_arg(ap, uint16_t*) = DATATYPE_IEEEFP; + break; + case SAMPLEFORMAT_VOID: + *va_arg(ap, uint16_t*) = DATATYPE_VOID; + break; + } + break; + case TIFFTAG_SAMPLEFORMAT: + *va_arg(ap, uint16_t*) = td->td_sampleformat; + break; + case TIFFTAG_IMAGEDEPTH: + *va_arg(ap, uint32_t*) = td->td_imagedepth; + break; + case TIFFTAG_SUBIFD: + *va_arg(ap, uint16_t*) = td->td_nsubifd; + *va_arg(ap, const uint64_t**) = td->td_subifd; + break; + case TIFFTAG_YCBCRPOSITIONING: + *va_arg(ap, uint16_t*) = td->td_ycbcrpositioning; + break; + case TIFFTAG_YCBCRSUBSAMPLING: + *va_arg(ap, uint16_t*) = td->td_ycbcrsubsampling[0]; + *va_arg(ap, uint16_t*) = td->td_ycbcrsubsampling[1]; + break; + case TIFFTAG_TRANSFERFUNCTION: + *va_arg(ap, const uint16_t**) = td->td_transferfunction[0]; + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + *va_arg(ap, const uint16_t**) = td->td_transferfunction[1]; + *va_arg(ap, const uint16_t**) = td->td_transferfunction[2]; + } else { + *va_arg(ap, const uint16_t**) = NULL; + *va_arg(ap, const uint16_t**) = NULL; + } + break; + case TIFFTAG_REFERENCEBLACKWHITE: + *va_arg(ap, const float**) = td->td_refblackwhite; + break; + case TIFFTAG_INKNAMES: + *va_arg(ap, const char**) = td->td_inknames; + break; + default: + { + int i; + + /* + * This can happen if multiple images are open + * with different codecs which have private + * tags. The global tag information table may + * then have tags that are valid for one file + * but not the other. If the client tries to + * get a tag that is not valid for the image's + * codec then we'll arrive here. + */ + if( fip->field_bit != FIELD_CUSTOM ) + { + TIFFErrorExt(tif->tif_clientdata, "_TIFFVGetField", + "%s: Invalid %stag \"%s\" " + "(not supported by codec)", + tif->tif_name, + isPseudoTag(tag) ? "pseudo-" : "", + fip->field_name); + ret_val = 0; + break; + } + + /* + * Do we have a custom value? + */ + ret_val = 0; + for (i = 0; i < td->td_customValueCount; i++) { + TIFFTagValue *tv = td->td_customValues + i; + + if (tv->info->field_tag != tag) + continue; + + if (fip->field_passcount) { + if (fip->field_readcount == TIFF_VARIABLE2) + *va_arg(ap, uint32_t*) = (uint32_t)tv->count; + else /* Assume TIFF_VARIABLE */ + *va_arg(ap, uint16_t*) = (uint16_t)tv->count; + *va_arg(ap, const void **) = tv->value; + ret_val = 1; + } else if (fip->field_tag == TIFFTAG_DOTRANGE + && strcmp(fip->field_name,"DotRange") == 0) { + /* TODO: This is an evil exception and should not have been + handled this way ... likely best if we move it into + the directory structure with an explicit field in + libtiff 4.1 and assign it a FIELD_ value */ + *va_arg(ap, uint16_t*) = ((uint16_t *)tv->value)[0]; + *va_arg(ap, uint16_t*) = ((uint16_t *)tv->value)[1]; + ret_val = 1; + } else { + if (fip->field_type == TIFF_ASCII + || fip->field_readcount == TIFF_VARIABLE + || fip->field_readcount == TIFF_VARIABLE2 + || fip->field_readcount == TIFF_SPP + || tv->count > 1) { + *va_arg(ap, void **) = tv->value; + ret_val = 1; + } else { + char *val = (char *)tv->value; + assert( tv->count == 1 ); + switch (fip->field_type) { + case TIFF_BYTE: + case TIFF_UNDEFINED: + *va_arg(ap, uint8_t*) = + *(uint8_t *)val; + ret_val = 1; + break; + case TIFF_SBYTE: + *va_arg(ap, int8_t*) = + *(int8_t *)val; + ret_val = 1; + break; + case TIFF_SHORT: + *va_arg(ap, uint16_t*) = + *(uint16_t *)val; + ret_val = 1; + break; + case TIFF_SSHORT: + *va_arg(ap, int16_t*) = + *(int16_t *)val; + ret_val = 1; + break; + case TIFF_LONG: + case TIFF_IFD: + *va_arg(ap, uint32_t*) = + *(uint32_t *)val; + ret_val = 1; + break; + case TIFF_SLONG: + *va_arg(ap, int32_t*) = + *(int32_t *)val; + ret_val = 1; + break; + case TIFF_LONG8: + case TIFF_IFD8: + *va_arg(ap, uint64_t*) = + *(uint64_t *)val; + ret_val = 1; + break; + case TIFF_SLONG8: + *va_arg(ap, int64_t*) = + *(int64_t *)val; + ret_val = 1; + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + { + /*-- Rational2Double: For Rationals evaluate "set_field_type" to determine internal storage size and return value size. */ + int tv_size = _TIFFSetGetFieldSize(fip->set_field_type); + if (tv_size == 8) { + *va_arg(ap, double*) = *(double *)val; + ret_val = 1; + } else { + /*-- default should be tv_size == 4 */ + *va_arg(ap, float*) = *(float *)val; + ret_val = 1; + /*-- ToDo: After Testing, this should be removed and tv_size==4 should be set as default. */ + if (tv_size != 4) { + TIFFErrorExt(0,"TIFFLib: _TIFFVGetField()", "Rational2Double: .set_field_type in not 4 but %d", tv_size); + } + } + } + break; + case TIFF_FLOAT: + *va_arg(ap, float*) = + *(float *)val; + ret_val = 1; + break; + case TIFF_DOUBLE: + *va_arg(ap, double*) = + *(double *)val; + ret_val = 1; + break; + default: + ret_val = 0; + break; + } + } + } + break; + } + } + } + return(ret_val); +} + +/* + * Return the value of a field in the + * internal directory structure. + */ +int WINAPIV +TIFFGetField(TIFF* tif, uint32_t tag, ...) +{ + int status; + va_list ap; + + va_start(ap, tag); + status = TIFFVGetField(tif, tag, ap); + va_end(ap); + return (status); +} + +/* + * Like TIFFGetField, but taking a varargs + * parameter list. This routine is useful + * for building higher-level interfaces on + * top of the library. + */ +int +TIFFVGetField(TIFF* tif, uint32_t tag, va_list ap) +{ + const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); + return (fip && (isPseudoTag(tag) || TIFFFieldSet(tif, fip->field_bit)) ? + (*tif->tif_tagmethods.vgetfield)(tif, tag, ap) : 0); +} + +#define CleanupField(member) { \ + if (td->member) { \ + _TIFFfree(td->member); \ + td->member = 0; \ + } \ +} + +/* + * Release storage associated with a directory. + */ +void +TIFFFreeDirectory(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + int i; + + _TIFFmemset(td->td_fieldsset, 0, FIELD_SETLONGS); + CleanupField(td_sminsamplevalue); + CleanupField(td_smaxsamplevalue); + CleanupField(td_colormap[0]); + CleanupField(td_colormap[1]); + CleanupField(td_colormap[2]); + CleanupField(td_sampleinfo); + CleanupField(td_subifd); + CleanupField(td_inknames); + CleanupField(td_refblackwhite); + CleanupField(td_transferfunction[0]); + CleanupField(td_transferfunction[1]); + CleanupField(td_transferfunction[2]); + CleanupField(td_stripoffset_p); + CleanupField(td_stripbytecount_p); + td->td_stripoffsetbyteallocsize = 0; + TIFFClrFieldBit(tif, FIELD_YCBCRSUBSAMPLING); + TIFFClrFieldBit(tif, FIELD_YCBCRPOSITIONING); + + /* Cleanup custom tag values */ + for( i = 0; i < td->td_customValueCount; i++ ) { + if (td->td_customValues[i].value) + _TIFFfree(td->td_customValues[i].value); + } + + td->td_customValueCount = 0; + CleanupField(td_customValues); + + _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); + _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); +} +#undef CleanupField + +/* + * Client Tag extension support (from Niles Ritter). + */ +static TIFFExtendProc _TIFFextender = (TIFFExtendProc) NULL; + +TIFFExtendProc +TIFFSetTagExtender(TIFFExtendProc extender) +{ + TIFFExtendProc prev = _TIFFextender; + _TIFFextender = extender; + return (prev); +} + +/* + * Setup for a new directory. Should we automatically call + * TIFFWriteDirectory() if the current one is dirty? + * + * The newly created directory will not exist on the file till + * TIFFWriteDirectory(), TIFFFlush() or TIFFClose() is called. + */ +int +TIFFCreateDirectory(TIFF* tif) +{ + TIFFDefaultDirectory(tif); + tif->tif_diroff = 0; + tif->tif_nextdiroff = 0; + tif->tif_curoff = 0; + tif->tif_row = (uint32_t) -1; + tif->tif_curstrip = (uint32_t) -1; + + return 0; +} + +int +TIFFCreateCustomDirectory(TIFF* tif, const TIFFFieldArray* infoarray) +{ + TIFFDefaultDirectory(tif); + + /* + * Reset the field definitions to match the application provided list. + * Hopefully TIFFDefaultDirectory() won't have done anything irreversible + * based on it's assumption this is an image directory. + */ + _TIFFSetupFields(tif, infoarray); + + tif->tif_diroff = 0; + tif->tif_nextdiroff = 0; + tif->tif_curoff = 0; + tif->tif_row = (uint32_t) -1; + tif->tif_curstrip = (uint32_t) -1; + + return 0; +} + +int +TIFFCreateEXIFDirectory(TIFF* tif) +{ + const TIFFFieldArray* exifFieldArray; + exifFieldArray = _TIFFGetExifFields(); + return TIFFCreateCustomDirectory(tif, exifFieldArray); +} + +/* + * Creates the EXIF GPS custom directory + */ +int +TIFFCreateGPSDirectory(TIFF* tif) +{ + const TIFFFieldArray* gpsFieldArray; + gpsFieldArray = _TIFFGetGpsFields(); + return TIFFCreateCustomDirectory(tif, gpsFieldArray); +} + +/* + * Setup a default directory structure. + */ +int +TIFFDefaultDirectory(TIFF* tif) +{ + register TIFFDirectory* td = &tif->tif_dir; + const TIFFFieldArray* tiffFieldArray; + + tiffFieldArray = _TIFFGetFields(); + _TIFFSetupFields(tif, tiffFieldArray); + + _TIFFmemset(td, 0, sizeof (*td)); + td->td_fillorder = FILLORDER_MSB2LSB; + td->td_bitspersample = 1; + td->td_threshholding = THRESHHOLD_BILEVEL; + td->td_orientation = ORIENTATION_TOPLEFT; + td->td_samplesperpixel = 1; + td->td_rowsperstrip = (uint32_t) -1; + td->td_tilewidth = 0; + td->td_tilelength = 0; + td->td_tiledepth = 1; +#ifdef STRIPBYTECOUNTSORTED_UNUSED + td->td_stripbytecountsorted = 1; /* Our own arrays always sorted. */ +#endif + td->td_resolutionunit = RESUNIT_INCH; + td->td_sampleformat = SAMPLEFORMAT_UINT; + td->td_imagedepth = 1; + td->td_ycbcrsubsampling[0] = 2; + td->td_ycbcrsubsampling[1] = 2; + td->td_ycbcrpositioning = YCBCRPOSITION_CENTERED; + tif->tif_postdecode = _TIFFNoPostDecode; + tif->tif_foundfield = NULL; + tif->tif_tagmethods.vsetfield = _TIFFVSetField; + tif->tif_tagmethods.vgetfield = _TIFFVGetField; + tif->tif_tagmethods.printdir = NULL; + /* + * Give client code a chance to install their own + * tag extensions & methods, prior to compression overloads, + * but do some prior cleanup first. (http://trac.osgeo.org/gdal/ticket/5054) + */ + if (tif->tif_nfieldscompat > 0) { + uint32_t i; + + for (i = 0; i < tif->tif_nfieldscompat; i++) { + if (tif->tif_fieldscompat[i].allocated_size) + _TIFFfree(tif->tif_fieldscompat[i].fields); + } + _TIFFfree(tif->tif_fieldscompat); + tif->tif_nfieldscompat = 0; + tif->tif_fieldscompat = NULL; + } + if (_TIFFextender) + (*_TIFFextender)(tif); + (void) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + /* + * NB: The directory is marked dirty as a result of setting + * up the default compression scheme. However, this really + * isn't correct -- we want TIFF_DIRTYDIRECT to be set only + * if the user does something. We could just do the setup + * by hand, but it seems better to use the normal mechanism + * (i.e. TIFFSetField). + */ + tif->tif_flags &= ~TIFF_DIRTYDIRECT; + + /* + * As per http://bugzilla.remotesensing.org/show_bug.cgi?id=19 + * we clear the ISTILED flag when setting up a new directory. + * Should we also be clearing stuff like INSUBIFD? + */ + tif->tif_flags &= ~TIFF_ISTILED; + + return (1); +} + +static int +TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off) +{ + static const char module[] = "TIFFAdvanceDirectory"; + if (isMapped(tif)) + { + uint64_t poff=*nextdir; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + tmsize_t poffa,poffb,poffc,poffd; + uint16_t dircount; + uint32_t nextdir32; + poffa=(tmsize_t)poff; + poffb=poffa+sizeof(uint16_t); + if (((uint64_t)poffa != poff) || (poffb < poffa) || (poffb < (tmsize_t)sizeof(uint16_t)) || (poffb > tif->tif_size)) + { + TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count"); + *nextdir=0; + return(0); + } + _TIFFmemcpy(&dircount,tif->tif_base+poffa,sizeof(uint16_t)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort(&dircount); + poffc=poffb+dircount*12; + poffd=poffc+sizeof(uint32_t); + if ((poffc tif->tif_size)) + { + TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory link"); + return(0); + } + if (off!=NULL) + *off=(uint64_t)poffc; + _TIFFmemcpy(&nextdir32,tif->tif_base+poffc,sizeof(uint32_t)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&nextdir32); + *nextdir=nextdir32; + } + else + { + tmsize_t poffa,poffb,poffc,poffd; + uint64_t dircount64; + uint16_t dircount16; + poffa=(tmsize_t)poff; + poffb=poffa+sizeof(uint64_t); + if (((uint64_t)poffa != poff) || (poffb < poffa) || (poffb < (tmsize_t)sizeof(uint64_t)) || (poffb > tif->tif_size)) + { + TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count"); + return(0); + } + _TIFFmemcpy(&dircount64,tif->tif_base+poffa,sizeof(uint64_t)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>0xFFFF) + { + TIFFErrorExt(tif->tif_clientdata,module,"Sanity check on directory count failed"); + return(0); + } + dircount16=(uint16_t)dircount64; + poffc=poffb+dircount16*20; + poffd=poffc+sizeof(uint64_t); + if ((poffc tif->tif_size)) + { + TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory link"); + return(0); + } + if (off!=NULL) + *off=(uint64_t)poffc; + _TIFFmemcpy(nextdir,tif->tif_base+poffc,sizeof(uint64_t)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(nextdir); + } + return(1); + } + else + { + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint16_t dircount; + uint32_t nextdir32; + if (!SeekOK(tif, *nextdir) || + !ReadOK(tif, &dircount, sizeof (uint16_t))) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + if (off != NULL) + *off = TIFFSeekFile(tif, + dircount*12, SEEK_CUR); + else + (void) TIFFSeekFile(tif, + dircount*12, SEEK_CUR); + if (!ReadOK(tif, &nextdir32, sizeof (uint32_t))) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdir32); + *nextdir=nextdir32; + } + else + { + uint64_t dircount64; + uint16_t dircount16; + if (!SeekOK(tif, *nextdir) || + !ReadOK(tif, &dircount64, sizeof (uint64_t))) { + TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>0xFFFF) + { + TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory count"); + return(0); + } + dircount16 = (uint16_t)dircount64; + if (off != NULL) + *off = TIFFSeekFile(tif, + dircount16*20, SEEK_CUR); + else + (void) TIFFSeekFile(tif, + dircount16*20, SEEK_CUR); + if (!ReadOK(tif, nextdir, sizeof (uint64_t))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Error fetching directory link", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(nextdir); + } + return (1); + } +} + +/* + * Count the number of directories in a file. + */ +uint16_t +TIFFNumberOfDirectories(TIFF* tif) +{ + static const char module[] = "TIFFNumberOfDirectories"; + uint64_t nextdir; + uint16_t n; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + nextdir = tif->tif_header.classic.tiff_diroff; + else + nextdir = tif->tif_header.big.tiff_diroff; + n = 0; + while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL)) + { + if (n != 65535) { + ++n; + } + else + { + TIFFErrorExt(tif->tif_clientdata, module, + "Directory count exceeded 65535 limit," + " giving up on counting."); + return (65535); + } + } + return (n); +} + +/* + * Set the n-th directory as the current directory. + * NB: Directories are numbered starting at 0. + */ +int +TIFFSetDirectory(TIFF* tif, uint16_t dirn) +{ + uint64_t nextdir; + uint16_t n; + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + nextdir = tif->tif_header.classic.tiff_diroff; + else + nextdir = tif->tif_header.big.tiff_diroff; + for (n = dirn; n > 0 && nextdir != 0; n--) + if (!TIFFAdvanceDirectory(tif, &nextdir, NULL)) + return (0); + tif->tif_nextdiroff = nextdir; + /* + * Set curdir to the actual directory index. The + * -1 is because TIFFReadDirectory will increment + * tif_curdir after successfully reading the directory. + */ + tif->tif_curdir = (dirn - n) - 1; + /* + * Reset tif_dirnumber counter and start new list of seen directories. + * We need this to prevent IFD loops. + */ + tif->tif_dirnumber = 0; + return (TIFFReadDirectory(tif)); +} + +/* + * Set the current directory to be the directory + * located at the specified file offset. This interface + * is used mainly to access directories linked with + * the SubIFD tag (e.g. thumbnail images). + */ +int +TIFFSetSubDirectory(TIFF* tif, uint64_t diroff) +{ + tif->tif_nextdiroff = diroff; + /* + * Reset tif_dirnumber counter and start new list of seen directories. + * We need this to prevent IFD loops. + */ + tif->tif_dirnumber = 0; + return (TIFFReadDirectory(tif)); +} + +/* + * Return file offset of the current directory. + */ +uint64_t +TIFFCurrentDirOffset(TIFF* tif) +{ + return (tif->tif_diroff); +} + +/* + * Return an indication of whether or not we are + * at the last directory in the file. + */ +int +TIFFLastDirectory(TIFF* tif) +{ + return (tif->tif_nextdiroff == 0); +} + +/* + * Unlink the specified directory from the directory chain. + */ +int +TIFFUnlinkDirectory(TIFF* tif, uint16_t dirn) +{ + static const char module[] = "TIFFUnlinkDirectory"; + uint64_t nextdir; + uint64_t off; + uint16_t n; + + if (tif->tif_mode == O_RDONLY) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not unlink directory in read-only file"); + return (0); + } + /* + * Go to the directory before the one we want + * to unlink and nab the offset of the link + * field we'll need to patch. + */ + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + nextdir = tif->tif_header.classic.tiff_diroff; + off = 4; + } + else + { + nextdir = tif->tif_header.big.tiff_diroff; + off = 8; + } + for (n = dirn-1; n > 0; n--) { + if (nextdir == 0) { + TIFFErrorExt(tif->tif_clientdata, module, "Directory %"PRIu16" does not exist", dirn); + return (0); + } + if (!TIFFAdvanceDirectory(tif, &nextdir, &off)) + return (0); + } + /* + * Advance to the directory to be unlinked and fetch + * the offset of the directory that follows. + */ + if (!TIFFAdvanceDirectory(tif, &nextdir, NULL)) + return (0); + /* + * Go back and patch the link field of the preceding + * directory to point to the offset of the directory + * that follows. + */ + (void) TIFFSeekFile(tif, off, SEEK_SET); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32_t nextdir32; + nextdir32=(uint32_t)nextdir; + assert((uint64_t)nextdir32 == nextdir); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdir32); + if (!WriteOK(tif, &nextdir32, sizeof (uint32_t))) { + TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link"); + return (0); + } + } + else + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&nextdir); + if (!WriteOK(tif, &nextdir, sizeof (uint64_t))) { + TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link"); + return (0); + } + } + /* + * Leave directory state setup safely. We don't have + * facilities for doing inserting and removing directories, + * so it's safest to just invalidate everything. This + * means that the caller can only append to the directory + * chain. + */ + (*tif->tif_cleanup)(tif); + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawcc = 0; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = 0; + } + tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP|TIFF_POSTENCODE|TIFF_BUF4WRITE); + TIFFFreeDirectory(tif); + TIFFDefaultDirectory(tif); + tif->tif_diroff = 0; /* force link on next write */ + tif->tif_nextdiroff = 0; /* next write must be at end */ + tif->tif_curoff = 0; + tif->tif_row = (uint32_t) -1; + tif->tif_curstrip = (uint32_t) -1; + return (1); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_dir.h b/libs/tiff/libtiff/tif_dir.h new file mode 100644 index 00000000000..1782b35d426 --- /dev/null +++ b/libs/tiff/libtiff/tif_dir.h @@ -0,0 +1,317 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFDIR_ +#define _TIFFDIR_ + +#include "tiff.h" +#include "tiffio.h" + +/* + * ``Library-private'' Directory-related Definitions. + */ + +typedef struct { + const TIFFField *info; + int count; + void *value; +} TIFFTagValue; + +/* + * TIFF Image File Directories are comprised of a table of field + * descriptors of the form shown below. The table is sorted in + * ascending order by tag. The values associated with each entry are + * disjoint and may appear anywhere in the file (so long as they are + * placed on a word boundary). + * + * If the value is 4 bytes or less, in ClassicTIFF, or 8 bytes or less in + * BigTIFF, then it is placed in the offset field to save space. If so, + * it is left-justified in the offset field. + */ +typedef struct { + uint16_t tdir_tag; /* see below */ + uint16_t tdir_type; /* data type; see below */ + uint64_t tdir_count; /* number of items; length in spec */ + union { + uint16_t toff_short; + uint32_t toff_long; + uint64_t toff_long8; + } tdir_offset; /* either offset or the data itself if fits */ + uint8_t tdir_ignore; /* flag status to ignore tag when parsing tags in tif_dirread.c */ +} TIFFDirEntry; + +/* + * Internal format of a TIFF directory entry. + */ +typedef struct { +#define FIELD_SETLONGS 4 + /* bit vector of fields that are set */ + unsigned long td_fieldsset[FIELD_SETLONGS]; + + uint32_t td_imagewidth, td_imagelength, td_imagedepth; + uint32_t td_tilewidth, td_tilelength, td_tiledepth; + uint32_t td_subfiletype; + uint16_t td_bitspersample; + uint16_t td_sampleformat; + uint16_t td_compression; + uint16_t td_photometric; + uint16_t td_threshholding; + uint16_t td_fillorder; + uint16_t td_orientation; + uint16_t td_samplesperpixel; + uint32_t td_rowsperstrip; + uint16_t td_minsamplevalue, td_maxsamplevalue; + double* td_sminsamplevalue; + double* td_smaxsamplevalue; + float td_xresolution, td_yresolution; + uint16_t td_resolutionunit; + uint16_t td_planarconfig; + float td_xposition, td_yposition; + uint16_t td_pagenumber[2]; + uint16_t* td_colormap[3]; + uint16_t td_halftonehints[2]; + uint16_t td_extrasamples; + uint16_t* td_sampleinfo; + /* even though the name is misleading, td_stripsperimage is the number + * of striles (=strips or tiles) per plane, and td_nstrips the total + * number of striles */ + uint32_t td_stripsperimage; + uint32_t td_nstrips; /* size of offset & bytecount arrays */ + uint64_t* td_stripoffset_p; /* should be accessed with TIFFGetStrileOffset */ + uint64_t* td_stripbytecount_p; /* should be accessed with TIFFGetStrileByteCount */ + uint32_t td_stripoffsetbyteallocsize; /* number of elements currently allocated for td_stripoffset/td_stripbytecount. Only used if TIFF_LAZYSTRILELOAD is set */ +#ifdef STRIPBYTECOUNTSORTED_UNUSED + int td_stripbytecountsorted; /* is the bytecount array sorted ascending? */ +#endif + TIFFDirEntry td_stripoffset_entry; /* for deferred loading */ + TIFFDirEntry td_stripbytecount_entry; /* for deferred loading */ + uint16_t td_nsubifd; + uint64_t* td_subifd; + /* YCbCr parameters */ + uint16_t td_ycbcrsubsampling[2]; + uint16_t td_ycbcrpositioning; + /* Colorimetry parameters */ + uint16_t* td_transferfunction[3]; + float* td_refblackwhite; + /* CMYK parameters */ + int td_inknameslen; + char* td_inknames; + + int td_customValueCount; + TIFFTagValue *td_customValues; + + unsigned char td_deferstrilearraywriting; /* see TIFFDeferStrileArrayWriting() */ +} TIFFDirectory; + +/* + * Field flags used to indicate fields that have been set in a directory, and + * to reference fields when manipulating a directory. + */ + +/* + * FIELD_IGNORE is used to signify tags that are to be processed but otherwise + * ignored. This permits antiquated tags to be quietly read and discarded. + * Note that a bit *is* allocated for ignored tags; this is understood by the + * directory reading logic which uses this fact to avoid special-case handling + */ +#define FIELD_IGNORE 0 + +/* multi-item fields */ +#define FIELD_IMAGEDIMENSIONS 1 +#define FIELD_TILEDIMENSIONS 2 +#define FIELD_RESOLUTION 3 +#define FIELD_POSITION 4 + +/* single-item fields */ +#define FIELD_SUBFILETYPE 5 +#define FIELD_BITSPERSAMPLE 6 +#define FIELD_COMPRESSION 7 +#define FIELD_PHOTOMETRIC 8 +#define FIELD_THRESHHOLDING 9 +#define FIELD_FILLORDER 10 +#define FIELD_ORIENTATION 15 +#define FIELD_SAMPLESPERPIXEL 16 +#define FIELD_ROWSPERSTRIP 17 +#define FIELD_MINSAMPLEVALUE 18 +#define FIELD_MAXSAMPLEVALUE 19 +#define FIELD_PLANARCONFIG 20 +#define FIELD_RESOLUTIONUNIT 22 +#define FIELD_PAGENUMBER 23 +#define FIELD_STRIPBYTECOUNTS 24 +#define FIELD_STRIPOFFSETS 25 +#define FIELD_COLORMAP 26 +#define FIELD_EXTRASAMPLES 31 +#define FIELD_SAMPLEFORMAT 32 +#define FIELD_SMINSAMPLEVALUE 33 +#define FIELD_SMAXSAMPLEVALUE 34 +#define FIELD_IMAGEDEPTH 35 +#define FIELD_TILEDEPTH 36 +#define FIELD_HALFTONEHINTS 37 +#define FIELD_YCBCRSUBSAMPLING 39 +#define FIELD_YCBCRPOSITIONING 40 +#define FIELD_REFBLACKWHITE 41 +#define FIELD_TRANSFERFUNCTION 44 +#define FIELD_INKNAMES 46 +#define FIELD_SUBIFD 49 +/* FIELD_CUSTOM (see tiffio.h) 65 */ +/* end of support for well-known tags; codec-private tags follow */ +#define FIELD_CODEC 66 /* base of codec-private tags */ + + +/* + * Pseudo-tags don't normally need field bits since they are not written to an + * output file (by definition). The library also has express logic to always + * query a codec for a pseudo-tag so allocating a field bit for one is a + * waste. If codec wants to promote the notion of a pseudo-tag being ``set'' + * or ``unset'' then it can do using internal state flags without polluting + * the field bit space defined for real tags. + */ +#define FIELD_PSEUDO 0 + +#define FIELD_LAST (32*FIELD_SETLONGS-1) + +#define BITn(n) (((unsigned long)1L)<<((n)&0x1f)) +#define BITFIELDn(tif, n) ((tif)->tif_dir.td_fieldsset[(n)/32]) +#define TIFFFieldSet(tif, field) (BITFIELDn(tif, field) & BITn(field)) +#define TIFFSetFieldBit(tif, field) (BITFIELDn(tif, field) |= BITn(field)) +#define TIFFClrFieldBit(tif, field) (BITFIELDn(tif, field) &= ~BITn(field)) + +#define FieldSet(fields, f) (fields[(f)/32] & BITn(f)) +#define ResetFieldBit(fields, f) (fields[(f)/32] &= ~BITn(f)) + +typedef enum { + TIFF_SETGET_UNDEFINED = 0, + TIFF_SETGET_ASCII = 1, + TIFF_SETGET_UINT8 = 2, + TIFF_SETGET_SINT8 = 3, + TIFF_SETGET_UINT16 = 4, + TIFF_SETGET_SINT16 = 5, + TIFF_SETGET_UINT32 = 6, + TIFF_SETGET_SINT32 = 7, + TIFF_SETGET_UINT64 = 8, + TIFF_SETGET_SINT64 = 9, + TIFF_SETGET_FLOAT = 10, + TIFF_SETGET_DOUBLE = 11, + TIFF_SETGET_IFD8 = 12, + TIFF_SETGET_INT = 13, + TIFF_SETGET_UINT16_PAIR = 14, + TIFF_SETGET_C0_ASCII = 15, + TIFF_SETGET_C0_UINT8 = 16, + TIFF_SETGET_C0_SINT8 = 17, + TIFF_SETGET_C0_UINT16 = 18, + TIFF_SETGET_C0_SINT16 = 19, + TIFF_SETGET_C0_UINT32 = 20, + TIFF_SETGET_C0_SINT32 = 21, + TIFF_SETGET_C0_UINT64 = 22, + TIFF_SETGET_C0_SINT64 = 23, + TIFF_SETGET_C0_FLOAT = 24, + TIFF_SETGET_C0_DOUBLE = 25, + TIFF_SETGET_C0_IFD8 = 26, + TIFF_SETGET_C16_ASCII = 27, + TIFF_SETGET_C16_UINT8 = 28, + TIFF_SETGET_C16_SINT8 = 29, + TIFF_SETGET_C16_UINT16 = 30, + TIFF_SETGET_C16_SINT16 = 31, + TIFF_SETGET_C16_UINT32 = 32, + TIFF_SETGET_C16_SINT32 = 33, + TIFF_SETGET_C16_UINT64 = 34, + TIFF_SETGET_C16_SINT64 = 35, + TIFF_SETGET_C16_FLOAT = 36, + TIFF_SETGET_C16_DOUBLE = 37, + TIFF_SETGET_C16_IFD8 = 38, + TIFF_SETGET_C32_ASCII = 39, + TIFF_SETGET_C32_UINT8 = 40, + TIFF_SETGET_C32_SINT8 = 41, + TIFF_SETGET_C32_UINT16 = 42, + TIFF_SETGET_C32_SINT16 = 43, + TIFF_SETGET_C32_UINT32 = 44, + TIFF_SETGET_C32_SINT32 = 45, + TIFF_SETGET_C32_UINT64 = 46, + TIFF_SETGET_C32_SINT64 = 47, + TIFF_SETGET_C32_FLOAT = 48, + TIFF_SETGET_C32_DOUBLE = 49, + TIFF_SETGET_C32_IFD8 = 50, + TIFF_SETGET_OTHER = 51 +} TIFFSetGetFieldType; + +#if defined(__cplusplus) +extern "C" { +#endif + +extern const TIFFFieldArray* _TIFFGetFields(void); +extern const TIFFFieldArray* _TIFFGetExifFields(void); +extern const TIFFFieldArray* _TIFFGetGpsFields(void); +extern void _TIFFSetupFields(TIFF* tif, const TIFFFieldArray* infoarray); +extern void _TIFFPrintFieldInfo(TIFF*, FILE*); + +extern int _TIFFFillStriles(TIFF*); + +typedef enum { + tfiatImage, + tfiatExif, + tfiatGps, /* EXIF-GPS fields array type */ + tfiatOther +} TIFFFieldArrayType; + +struct _TIFFFieldArray { + TIFFFieldArrayType type; /* array type, will be used to determine if IFD is image and such */ + uint32_t allocated_size; /* 0 if array is constant, other if modified by future definition extension support */ + uint32_t count; /* number of elements in fields array */ + TIFFField* fields; /* actual field info */ +}; + +struct _TIFFField { + uint32_t field_tag; /* field's tag */ + short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ + short field_writecount; /* write count/TIFF_VARIABLE */ + TIFFDataType field_type; /* type of associated data */ + uint32_t reserved; /* reserved for future extension */ + TIFFSetGetFieldType set_field_type; /* type to be passed to TIFFSetField */ + TIFFSetGetFieldType get_field_type; /* type to be passed to TIFFGetField */ + unsigned short field_bit; /* bit in fieldsset bit vector */ + unsigned char field_oktochange; /* if true, can change while writing */ + unsigned char field_passcount; /* if true, pass dir count on set */ + char* field_name; /* ASCII name */ + TIFFFieldArray* field_subfields; /* if field points to child ifds, child ifd field definition array */ +}; + +extern int _TIFFMergeFields(TIFF*, const TIFFField[], uint32_t); +extern const TIFFField* _TIFFFindOrRegisterField(TIFF *, uint32_t, TIFFDataType); +extern TIFFField* _TIFFCreateAnonField(TIFF *, uint32_t, TIFFDataType); +extern int _TIFFCheckFieldIsValidForCodec(TIFF *tif, ttag_t tag); + +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFDIR_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_dirinfo.c b/libs/tiff/libtiff/tif_dirinfo.c new file mode 100644 index 00000000000..5d3a33810b1 --- /dev/null +++ b/libs/tiff/libtiff/tif_dirinfo.c @@ -0,0 +1,1251 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Core Directory Tag Support. + */ +#include "tiffiop.h" +#include + +/* + * NOTE: THIS ARRAY IS ASSUMED TO BE SORTED BY TAG. + * + * NOTE: The second field (field_readcount) and third field (field_writecount) + * sometimes use the values TIFF_VARIABLE (-1), TIFF_VARIABLE2 (-3) + * and TIFF_SPP (-2). The macros should be used but would throw off + * the formatting of the code, so please interpret the -1, -2 and -3 + * values accordingly. + */ + +/* const object should be initialized */ +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4132 ) +#endif +static const TIFFFieldArray tiffFieldArray; +static const TIFFFieldArray exifFieldArray; +static const TIFFFieldArray gpsFieldArray; +#ifdef _MSC_VER +#pragma warning( pop ) +#endif +/*--: Rational2Double: -- + * The Rational2Double upgraded libtiff functionality allows the definition and achievement of true double-precision accuracy + * for TIFF tags of RATIONAL type and field_bit=FIELD_CUSTOM using the set_field_type = TIFF_SETGET_DOUBLE. + * Unfortunately, that changes the old implemented interface for TIFFGetField(). + * In order to keep the old TIFFGetField() interface behavior those tags have to be redefined with set_field_type = TIFF_SETGET_FLOAT! + * + * Rational custom arrays are already defined as _Cxx_FLOAT, thus can stay. + * + */ + +static const TIFFField +tiffFields[] = { + { TIFFTAG_SUBFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_SUBFILETYPE, 1, 0, "SubfileType", NULL }, + { TIFFTAG_OSUBFILETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_SUBFILETYPE, 1, 0, "OldSubfileType", NULL }, + { TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDIMENSIONS, 0, 0, "ImageWidth", NULL }, + { TIFFTAG_IMAGELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDIMENSIONS, 1, 0, "ImageLength", NULL }, + { TIFFTAG_BITSPERSAMPLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_BITSPERSAMPLE, 0, 0, "BitsPerSample", NULL }, + { TIFFTAG_COMPRESSION, -1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_COMPRESSION, 0, 0, "Compression", NULL }, + { TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_PHOTOMETRIC, 0, 0, "PhotometricInterpretation", NULL }, + { TIFFTAG_THRESHHOLDING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_THRESHHOLDING, 1, 0, "Threshholding", NULL }, + { TIFFTAG_CELLWIDTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "CellWidth", NULL }, + { TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "CellLength", NULL }, + { TIFFTAG_FILLORDER, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_FILLORDER, 0, 0, "FillOrder", NULL }, + { TIFFTAG_DOCUMENTNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DocumentName", NULL }, + { TIFFTAG_IMAGEDESCRIPTION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageDescription", NULL }, + { TIFFTAG_MAKE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Make", NULL }, + { TIFFTAG_MODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Model", NULL }, + { TIFFTAG_STRIPOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "StripOffsets", NULL }, + { TIFFTAG_ORIENTATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_ORIENTATION, 0, 0, "Orientation", NULL }, + { TIFFTAG_SAMPLESPERPIXEL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLESPERPIXEL, 0, 0, "SamplesPerPixel", NULL }, + { TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_ROWSPERSTRIP, 0, 0, "RowsPerStrip", NULL }, + { TIFFTAG_STRIPBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "StripByteCounts", NULL }, + { TIFFTAG_MINSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_MINSAMPLEVALUE, 1, 0, "MinSampleValue", NULL }, + { TIFFTAG_MAXSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_MAXSAMPLEVALUE, 1, 0, "MaxSampleValue", NULL }, + { TIFFTAG_XRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTION, 1, 0, "XResolution", NULL }, + { TIFFTAG_YRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTION, 1, 0, "YResolution", NULL }, + { TIFFTAG_PLANARCONFIG, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_PLANARCONFIG, 0, 0, "PlanarConfiguration", NULL }, + { TIFFTAG_PAGENAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PageName", NULL }, + { TIFFTAG_XPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_POSITION, 1, 0, "XPosition", NULL }, + { TIFFTAG_YPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_POSITION, 1, 0, "YPosition", NULL }, + { TIFFTAG_FREEOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 0, 0, "FreeOffsets", NULL }, + { TIFFTAG_FREEBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 0, 0, "FreeByteCounts", NULL }, + { TIFFTAG_GRAYRESPONSEUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "GrayResponseUnit", NULL }, + { TIFFTAG_GRAYRESPONSECURVE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "GrayResponseCurve", NULL }, + { TIFFTAG_RESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTIONUNIT, 1, 0, "ResolutionUnit", NULL }, + { TIFFTAG_PAGENUMBER, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_PAGENUMBER, 1, 0, "PageNumber", NULL }, + { TIFFTAG_COLORRESPONSEUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "ColorResponseUnit", NULL }, + { TIFFTAG_TRANSFERFUNCTION, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_TRANSFERFUNCTION, 1, 0, "TransferFunction", NULL }, + { TIFFTAG_SOFTWARE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Software", NULL }, + { TIFFTAG_DATETIME, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTime", NULL }, + { TIFFTAG_ARTIST, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Artist", NULL }, + { TIFFTAG_HOSTCOMPUTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "HostComputer", NULL }, + { TIFFTAG_WHITEPOINT, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "WhitePoint", NULL }, + { TIFFTAG_PRIMARYCHROMATICITIES, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PrimaryChromaticities", NULL }, + { TIFFTAG_COLORMAP, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_COLORMAP, 1, 0, "ColorMap", NULL }, + { TIFFTAG_HALFTONEHINTS, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_HALFTONEHINTS, 1, 0, "HalftoneHints", NULL }, + { TIFFTAG_TILEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDIMENSIONS, 0, 0, "TileWidth", NULL }, + { TIFFTAG_TILELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDIMENSIONS, 0, 0, "TileLength", NULL }, + { TIFFTAG_TILEOFFSETS, -1, 1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "TileOffsets", NULL }, + { TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "TileByteCounts", NULL }, + { TIFFTAG_SUBIFD, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, TIFF_SETGET_UNDEFINED, FIELD_SUBIFD, 1, 1, "SubIFD", (TIFFFieldArray*) &tiffFieldArray }, + { TIFFTAG_INKSET, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InkSet", NULL }, + { TIFFTAG_INKNAMES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_C16_ASCII, TIFF_SETGET_UNDEFINED, FIELD_INKNAMES, 1, 1, "InkNames", NULL }, + { TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NumberOfInks", NULL }, + { TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DotRange", NULL }, + { TIFFTAG_TARGETPRINTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TargetPrinter", NULL }, + { TIFFTAG_EXTRASAMPLES, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 1, "ExtraSamples", NULL }, + { TIFFTAG_SAMPLEFORMAT, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLEFORMAT, 0, 0, "SampleFormat", NULL }, + { TIFFTAG_SMINSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_SMINSAMPLEVALUE, 1, 0, "SMinSampleValue", NULL }, + { TIFFTAG_SMAXSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_SMAXSAMPLEVALUE, 1, 0, "SMaxSampleValue", NULL }, + { TIFFTAG_CLIPPATH, -1, -3, TIFF_BYTE, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ClipPath", NULL }, + { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SLONG, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL }, + { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SBYTE, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL }, + { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SLONG, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "YClipPathUnits", NULL }, + { TIFFTAG_YCBCRCOEFFICIENTS, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "YCbCrCoefficients", NULL }, + { TIFFTAG_YCBCRSUBSAMPLING, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_YCBCRSUBSAMPLING, 0, 0, "YCbCrSubsampling", NULL }, + { TIFFTAG_YCBCRPOSITIONING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_YCBCRPOSITIONING, 0, 0, "YCbCrPositioning", NULL }, + { TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_REFBLACKWHITE, 1, 0, "ReferenceBlackWhite", NULL }, + { TIFFTAG_XMLPACKET, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "XMLPacket", NULL }, + /* begin SGI tags */ + { TIFFTAG_MATTEING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 0, "Matteing", NULL }, + { TIFFTAG_DATATYPE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLEFORMAT, 0, 0, "DataType", NULL }, + { TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDEPTH, 0, 0, "ImageDepth", NULL }, + { TIFFTAG_TILEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDEPTH, 0, 0, "TileDepth", NULL }, + /* end SGI tags */ + /* begin Pixar tags */ + { TIFFTAG_PIXAR_IMAGEFULLWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageFullWidth", NULL }, + { TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageFullLength", NULL }, + { TIFFTAG_PIXAR_TEXTUREFORMAT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TextureFormat", NULL }, + { TIFFTAG_PIXAR_WRAPMODES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TextureWrapModes", NULL }, + { TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FieldOfViewCotangent", NULL }, + { TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToScreen", NULL }, + { TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToCamera", NULL }, + { TIFFTAG_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CFARepeatPatternDim", NULL }, + { TIFFTAG_CFAPATTERN, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CFAPattern" , NULL}, + { TIFFTAG_COPYRIGHT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Copyright", NULL }, + /* end Pixar tags */ + { TIFFTAG_RICHTIFFIPTC, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "RichTIFFIPTC", NULL }, + { TIFFTAG_PHOTOSHOP, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "Photoshop", NULL }, + /*--: EXIFIFD and GPSIFD specified as TIFF_LONG by Aware-Systems and not TIFF_IFD8 as in original LibTiff. + * However, for IFD-like tags, libtiff uses the data type TIFF_IFD8 in tiffFields[]-tag definition combined with + * a special handling procedure in order to write either a 32-bit value and the TIFF_IFD type-id into ClassicTIFF files + * or a 64-bit value and the TIFF_IFD8 type-id into BigTIFF files. */ + { TIFFTAG_EXIFIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EXIFIFDOffset", (TIFFFieldArray*) &exifFieldArray }, + { TIFFTAG_ICCPROFILE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ICC Profile", NULL }, + { TIFFTAG_GPSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "GPSIFDOffset", (TIFFFieldArray*) &gpsFieldArray }, + { TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvParams", NULL }, + { TIFFTAG_FAXSUBADDRESS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxSubAddress", NULL }, + { TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvTime", NULL }, + { TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxDcs", NULL }, + { TIFFTAG_STONITS, 1, 1, TIFF_DOUBLE, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "StoNits", NULL }, + { TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InteroperabilityIFDOffset", NULL }, + /* begin DNG tags */ + { TIFFTAG_DNGVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DNGVersion", NULL }, + { TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DNGBackwardVersion", NULL }, + { TIFFTAG_UNIQUECAMERAMODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "UniqueCameraModel", NULL }, + { TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "LocalizedCameraModel", NULL }, + { TIFFTAG_CFAPLANECOLOR, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CFAPlaneColor", NULL }, + { TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CFALayout", NULL }, + { TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "LinearizationTable", NULL }, + { TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BlackLevelRepeatDim", NULL }, + { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevel", NULL }, + { TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevelDeltaH", NULL }, + { TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevelDeltaV", NULL }, + { TIFFTAG_WHITELEVEL, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "WhiteLevel", NULL }, + { TIFFTAG_DEFAULTSCALE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultScale", NULL }, + { TIFFTAG_BESTQUALITYSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BestQualityScale", NULL }, + { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultCropOrigin", NULL }, + { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultCropSize", NULL }, + { TIFFTAG_COLORMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ColorMatrix1", NULL }, + { TIFFTAG_COLORMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ColorMatrix2", NULL }, + { TIFFTAG_CAMERACALIBRATION1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CameraCalibration1", NULL }, + { TIFFTAG_CAMERACALIBRATION2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CameraCalibration2", NULL }, + { TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ReductionMatrix1", NULL }, + { TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ReductionMatrix2", NULL }, + { TIFFTAG_ANALOGBALANCE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AnalogBalance", NULL }, + { TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotNeutral", NULL }, + { TIFFTAG_ASSHOTWHITEXY, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "AsShotWhiteXY", NULL }, + { TIFFTAG_BASELINEEXPOSURE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineExposure", NULL }, + { TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineNoise", NULL }, + { TIFFTAG_BASELINESHARPNESS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineSharpness", NULL }, + { TIFFTAG_BAYERGREENSPLIT, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BayerGreenSplit", NULL }, + { TIFFTAG_LINEARRESPONSELIMIT, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "LinearResponseLimit", NULL }, + { TIFFTAG_CAMERASERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CameraSerialNumber", NULL }, + { TIFFTAG_LENSINFO, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "LensInfo", NULL }, + { TIFFTAG_CHROMABLURRADIUS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ChromaBlurRadius", NULL }, + { TIFFTAG_ANTIALIASSTRENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "AntiAliasStrength", NULL }, + { TIFFTAG_SHADOWSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ShadowScale", NULL }, + { TIFFTAG_DNGPRIVATEDATA, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "DNGPrivateData", NULL }, + { TIFFTAG_MAKERNOTESAFETY, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "MakerNoteSafety", NULL }, + { TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CalibrationIlluminant1", NULL }, + { TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CalibrationIlluminant2", NULL }, + { TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "RawDataUniqueID", NULL }, + { TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OriginalRawFileName", NULL }, + { TIFFTAG_ORIGINALRAWFILEDATA, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "OriginalRawFileData", NULL }, + { TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ActiveArea", NULL }, + { TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "MaskedAreas", NULL }, + { TIFFTAG_ASSHOTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotICCProfile", NULL }, + { TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotPreProfileMatrix", NULL }, + { TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CurrentICCProfile", NULL }, + { TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CurrentPreProfileMatrix", NULL }, + { TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL}, + /* end DNG tags */ + /* begin TIFF/FX tags */ + { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "Indexed", NULL }, + { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "GlobalParametersIFD", NULL }, + { TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ProfileType", NULL }, + { TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "FaxProfile", NULL }, + { TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CodingMethods", NULL }, + { TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "VersionYear", NULL }, + { TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ModeNumber", NULL }, + { TIFFTAG_DECODE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "Decode", NULL }, + { TIFFTAG_IMAGEBASECOLOR, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ImageBaseColor", NULL }, + { TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "T82Options", NULL }, + { TIFFTAG_STRIPROWCOUNTS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "StripRowCounts", NULL }, + { TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ImageLayer", NULL }, + /* end TIFF/FX tags */ + /* begin pseudo tags */ +}; + +/* + * EXIF tags (Version 2.31, July 2016 plus version 2.32 May 2019) + */ +static const TIFFField +exifFields[] = { + { EXIFTAG_EXPOSURETIME, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureTime", NULL }, + { EXIFTAG_FNUMBER, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FNumber", NULL }, + { EXIFTAG_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureProgram", NULL }, + { EXIFTAG_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SpectralSensitivity", NULL }, + { EXIFTAG_ISOSPEEDRATINGS, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ISOSpeedRatings", NULL }, + { EXIFTAG_OECF, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OptoelectricConversionFactor", NULL }, + { EXIFTAG_SENSITIVITYTYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SensitivityType", NULL }, + { EXIFTAG_STANDARDOUTPUTSENSITIVITY, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "StandardOutputSensitivity", NULL }, + { EXIFTAG_RECOMMENDEDEXPOSUREINDEX, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RecommendedExposureIndex", NULL }, + { EXIFTAG_ISOSPEED, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ISOSpeed", NULL }, + { EXIFTAG_ISOSPEEDLATITUDEYYY, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ISOSpeedLatitudeyyy", NULL }, + { EXIFTAG_ISOSPEEDLATITUDEZZZ, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ISOSpeedLatitudezzz", NULL }, + { EXIFTAG_EXIFVERSION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExifVersion", NULL }, + { EXIFTAG_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTimeOriginal", NULL }, + { EXIFTAG_DATETIMEDIGITIZED, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DateTimeDigitized", NULL }, + { EXIFTAG_OFFSETTIME, 7, 7, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OffsetTime", NULL }, + { EXIFTAG_OFFSETTIMEORIGINAL, 7, 7, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OffsetTimeOriginal", NULL }, + { EXIFTAG_OFFSETTIMEDIGITIZED, 7, 7, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OffsetTimeDigitized", NULL }, + { EXIFTAG_COMPONENTSCONFIGURATION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ComponentsConfiguration", NULL }, + { EXIFTAG_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CompressedBitsPerPixel", NULL }, + { EXIFTAG_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ShutterSpeedValue", NULL }, + { EXIFTAG_APERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ApertureValue", NULL }, + { EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL }, + { EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL }, + { EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL }, + /*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance! + * However, there are two other EXIF tags where numerator indicates a special value and six other cases where the denominator indicates special values, + * which are not treated within LibTiff!! */ + { EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistance", NULL }, + { EXIFTAG_METERINGMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MeteringMode", NULL }, + { EXIFTAG_LIGHTSOURCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LightSource", NULL }, + { EXIFTAG_FLASH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Flash", NULL }, + { EXIFTAG_FOCALLENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalLength", NULL }, + { EXIFTAG_SUBJECTAREA, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "SubjectArea", NULL }, + { EXIFTAG_MAKERNOTE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "MakerNote", NULL }, + { EXIFTAG_USERCOMMENT, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "UserComment", NULL }, + { EXIFTAG_SUBSECTIME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTime", NULL }, + { EXIFTAG_SUBSECTIMEORIGINAL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTimeOriginal", NULL }, + { EXIFTAG_SUBSECTIMEDIGITIZED, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubSecTimeDigitized", NULL }, + { EXIFTAG_TEMPERATURE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Temperature", NULL }, + { EXIFTAG_HUMIDITY, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Humidity", NULL }, + { EXIFTAG_PRESSURE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Pressure", NULL }, + { EXIFTAG_WATERDEPTH, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "WaterDepth", NULL }, + { EXIFTAG_ACCELERATION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Acceleration", NULL }, + { EXIFTAG_CAMERAELEVATIONANGLE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CameraElevationAngle", NULL }, + { EXIFTAG_FLASHPIXVERSION, 4, 4, TIFF_UNDEFINED, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FlashpixVersion", NULL }, + { EXIFTAG_COLORSPACE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorSpace", NULL }, + { EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PixelXDimension", NULL }, + { EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PixelYDimension", NULL }, + { EXIFTAG_RELATEDSOUNDFILE, 13, 13, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RelatedSoundFile", NULL }, + { EXIFTAG_FLASHENERGY, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FlashEnergy", NULL }, + { EXIFTAG_SPATIALFREQUENCYRESPONSE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "SpatialFrequencyResponse", NULL }, + { EXIFTAG_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneXResolution", NULL }, + { EXIFTAG_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneYResolution", NULL }, + { EXIFTAG_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneResolutionUnit", NULL }, + { EXIFTAG_SUBJECTLOCATION, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectLocation", NULL }, + { EXIFTAG_EXPOSUREINDEX, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureIndex", NULL }, + { EXIFTAG_SENSINGMETHOD, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SensingMethod", NULL }, + { EXIFTAG_FILESOURCE, 1, 1, TIFF_UNDEFINED, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FileSource", NULL }, + { EXIFTAG_SCENETYPE, 1, 1, TIFF_UNDEFINED, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SceneType", NULL }, + { EXIFTAG_CFAPATTERN, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CFAPattern", NULL }, + { EXIFTAG_CUSTOMRENDERED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CustomRendered", NULL }, + { EXIFTAG_EXPOSUREMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureMode", NULL }, + { EXIFTAG_WHITEBALANCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "WhiteBalance", NULL }, + { EXIFTAG_DIGITALZOOMRATIO, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DigitalZoomRatio", NULL }, + { EXIFTAG_FOCALLENGTHIN35MMFILM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalLengthIn35mmFilm", NULL }, + { EXIFTAG_SCENECAPTURETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SceneCaptureType", NULL }, + { EXIFTAG_GAINCONTROL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "GainControl", NULL }, + { EXIFTAG_CONTRAST, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Contrast", NULL }, + { EXIFTAG_SATURATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Saturation", NULL }, + { EXIFTAG_SHARPNESS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Sharpness", NULL }, + { EXIFTAG_DEVICESETTINGDESCRIPTION, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "DeviceSettingDescription", NULL }, + { EXIFTAG_SUBJECTDISTANCERANGE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistanceRange", NULL }, + { EXIFTAG_IMAGEUNIQUEID, 33, 33, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageUniqueID", NULL }, + { EXIFTAG_CAMERAOWNERNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CameraOwnerName", NULL }, + { EXIFTAG_BODYSERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BodySerialNumber", NULL }, + { EXIFTAG_LENSSPECIFICATION, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LensSpecification", NULL }, + { EXIFTAG_LENSMAKE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LensMake", NULL }, + { EXIFTAG_LENSMODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LensModel", NULL }, + { EXIFTAG_LENSSERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "LensSerialNumber", NULL }, + { EXIFTAG_GAMMA, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Gamma", NULL }, + { EXIFTAG_COMPOSITEIMAGE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CompositeImage", NULL }, + { EXIFTAG_SOURCEIMAGENUMBEROFCOMPOSITEIMAGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SourceImageNumberOfCompositeImage", NULL }, + { EXIFTAG_SOURCEEXPOSURETIMESOFCOMPOSITEIMAGE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "SourceExposureTimesOfCompositeImage", NULL } +}; +/* + * EXIF-GPS tags (Version 2.31, July 2016; nothing changed for version 2.32 May 2019) + */ + +static const TIFFField +gpsFields[] = { + /* For the GPS tag definitions in gpsFields[] the standard definition for Rationals is TIFF_SETGET_DOUBLE and TIFF_SETGET_C0_FLOAT. + *-- ATTENTION: After the upgrade with Rational2Double, the GPSTAG values can now be written and also read in double precision! + * In order to achieve double precision for GPS tags: + * Standard definitions for GPSTAG is kept to TIFF_SETGET_DOUBLE + * and TIFF_SETGET_C0_FLOAT is changed to TIFF_SETGET_C0_DOUBLE. + */ + { GPSTAG_VERSIONID , 4, 4, TIFF_BYTE , 0, TIFF_SETGET_C0_UINT8 , TIFF_SETGET_UINT8 , FIELD_CUSTOM , 1, 0, "VersionID", NULL }, + { GPSTAG_LATITUDEREF , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "LatitudeRef", NULL }, + { GPSTAG_LATITUDE , 3, 3, TIFF_RATIONAL , 0, TIFF_SETGET_C0_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "Latitude", NULL }, + { GPSTAG_LONGITUDEREF , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "LongitudeRef", NULL }, + { GPSTAG_LONGITUDE , 3, 3, TIFF_RATIONAL , 0, TIFF_SETGET_C0_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "Longitude", NULL }, + { GPSTAG_ALTITUDEREF , 1, 1, TIFF_BYTE , 0, TIFF_SETGET_UINT8 , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "AltitudeRef", NULL }, + { GPSTAG_ALTITUDE , 1, 1, TIFF_RATIONAL , 0, TIFF_SETGET_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "Altitude", NULL }, + { GPSTAG_TIMESTAMP , 3, 3, TIFF_RATIONAL , 0, TIFF_SETGET_C0_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "TimeStamp", NULL }, + { GPSTAG_SATELLITES , -1, -1, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "Satellites", NULL }, + { GPSTAG_STATUS , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "Status", NULL }, + { GPSTAG_MEASUREMODE , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "MeasureMode", NULL }, + { GPSTAG_DOP , 1, 1, TIFF_RATIONAL , 0, TIFF_SETGET_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "DOP", NULL }, + { GPSTAG_SPEEDREF , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "SpeedRef", NULL }, + { GPSTAG_SPEED , 1, 1, TIFF_RATIONAL , 0, TIFF_SETGET_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "Speed", NULL }, + { GPSTAG_TRACKREF , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "TrackRef", NULL }, + { GPSTAG_TRACK , 1, 1, TIFF_RATIONAL , 0, TIFF_SETGET_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "Track", NULL }, + { GPSTAG_IMGDIRECTIONREF , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "ImgDirectionRef", NULL }, + { GPSTAG_IMGDIRECTION , 1, 1, TIFF_RATIONAL , 0, TIFF_SETGET_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "ImgDirection", NULL }, + { GPSTAG_MAPDATUM , -1, -1, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "MapDatum", NULL }, + { GPSTAG_DESTLATITUDEREF , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "DestLatitudeRef", NULL }, + { GPSTAG_DESTLATITUDE , 3, 3, TIFF_RATIONAL , 0, TIFF_SETGET_C0_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "DestLatitude", NULL }, + { GPSTAG_DESTLONGITUDEREF , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "DestLongitudeRef", NULL }, + { GPSTAG_DESTLONGITUDE , 3, 3, TIFF_RATIONAL , 0, TIFF_SETGET_C0_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "DestLongitude", NULL }, + { GPSTAG_DESTBEARINGREF , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "DestBearingRef", NULL }, + { GPSTAG_DESTBEARING , 1, 1, TIFF_RATIONAL , 0, TIFF_SETGET_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "DestBearing", NULL }, + { GPSTAG_DESTDISTANCEREF , 2, 2, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "DestDistanceRef", NULL }, + { GPSTAG_DESTDISTANCE , 1, 1, TIFF_RATIONAL , 0, TIFF_SETGET_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "DestDistance", NULL }, + { GPSTAG_PROCESSINGMETHOD , -1, -1, TIFF_UNDEFINED , 0, TIFF_SETGET_C16_UINT8 , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 1, "ProcessingMethod", NULL }, + { GPSTAG_AREAINFORMATION , -1, -1, TIFF_UNDEFINED , 0, TIFF_SETGET_C16_UINT8 , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 1, "AreaInformation", NULL }, + { GPSTAG_DATESTAMP , 11, 11, TIFF_ASCII , 0, TIFF_SETGET_ASCII , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "DateStamp", NULL }, + { GPSTAG_DIFFERENTIAL , 1, 1, TIFF_SHORT , 0, TIFF_SETGET_UINT16 , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "Differential", NULL }, + { GPSTAG_GPSHPOSITIONINGERROR , 1, 1, TIFF_RATIONAL , 0, TIFF_SETGET_DOUBLE , TIFF_SETGET_UNDEFINED , FIELD_CUSTOM , 1, 0, "HorizontalPositioningError", NULL } +}; + +static const TIFFFieldArray +tiffFieldArray = { tfiatImage, 0, TIFFArrayCount(tiffFields), (TIFFField*) tiffFields }; +static const TIFFFieldArray +exifFieldArray = { tfiatExif, 0, TIFFArrayCount(exifFields), (TIFFField*) exifFields }; +static const TIFFFieldArray +gpsFieldArray = { tfiatGps, 0, TIFFArrayCount(gpsFields), (TIFFField*) gpsFields }; + +/* + * We have our own local lfind() equivalent to avoid subtle differences + * in types passed to lfind() on different systems. + */ + +static void * +td_lfind(const void *key, const void *base, size_t *nmemb, size_t size, + int(*compar)(const void *, const void *)) +{ + char *element, *end; + + end = (char *)base + *nmemb * size; + for (element = (char *)base; element < end; element += size) + if (!compar(key, element)) /* key found */ + return element; + + return NULL; +} + +const TIFFFieldArray* +_TIFFGetFields(void) +{ + return(&tiffFieldArray); +} + +const TIFFFieldArray* +_TIFFGetExifFields(void) +{ + return(&exifFieldArray); +} + +const TIFFFieldArray* +_TIFFGetGpsFields(void) +{ + return(&gpsFieldArray); +} + +void +_TIFFSetupFields(TIFF* tif, const TIFFFieldArray* fieldarray) +{ + if (tif->tif_fields && tif->tif_nfields > 0) { + uint32_t i; + + for (i = 0; i < tif->tif_nfields; i++) { + TIFFField *fld = tif->tif_fields[i]; + if (fld->field_bit == FIELD_CUSTOM && + strncmp("Tag ", fld->field_name, 4) == 0) { + _TIFFfree(fld->field_name); + _TIFFfree(fld); + } + } + + _TIFFfree(tif->tif_fields); + tif->tif_fields = NULL; + tif->tif_nfields = 0; + } + if (!_TIFFMergeFields(tif, fieldarray->fields, fieldarray->count)) { + TIFFErrorExt(tif->tif_clientdata, "_TIFFSetupFields", + "Setting up field info failed"); + } +} + +static int __cdecl +tagCompare(const void* a, const void* b) +{ + const TIFFField* ta = *(const TIFFField**) a; + const TIFFField* tb = *(const TIFFField**) b; + /* NB: be careful of return values for 16-bit platforms */ + if (ta->field_tag != tb->field_tag) + return (int)ta->field_tag - (int)tb->field_tag; + else + return (ta->field_type == TIFF_ANY) ? + 0 : ((int)tb->field_type - (int)ta->field_type); +} + +static int +tagNameCompare(const void* a, const void* b) +{ + const TIFFField* ta = *(const TIFFField**) a; + const TIFFField* tb = *(const TIFFField**) b; + int ret = strcmp(ta->field_name, tb->field_name); + + if (ret) + return ret; + else + return (ta->field_type == TIFF_ANY) ? + 0 : ((int)tb->field_type - (int)ta->field_type); +} + +int +_TIFFMergeFields(TIFF* tif, const TIFFField info[], uint32_t n) +{ + static const char module[] = "_TIFFMergeFields"; + static const char reason[] = "for fields array"; + /* TIFFField** tp; */ + uint32_t i; + + tif->tif_foundfield = NULL; + + if (tif->tif_fields && tif->tif_nfields > 0) { + tif->tif_fields = (TIFFField**) + _TIFFCheckRealloc(tif, tif->tif_fields, + (tif->tif_nfields + n), + sizeof(TIFFField *), reason); + } else { + tif->tif_fields = (TIFFField **) + _TIFFCheckMalloc(tif, n, sizeof(TIFFField *), + reason); + } + if (!tif->tif_fields) { + TIFFErrorExt(tif->tif_clientdata, module, + "Failed to allocate fields array"); + return 0; + } + + /* tp = tif->tif_fields + tif->tif_nfields; */ + for (i = 0; i < n; i++) { + const TIFFField *fip = + TIFFFindField(tif, info[i].field_tag, TIFF_ANY); + + /* only add definitions that aren't already present */ + if (!fip) { + tif->tif_fields[tif->tif_nfields] = (TIFFField *) (info+i); + tif->tif_nfields++; + } + } + + /* Sort the field info by tag number */ + qsort(tif->tif_fields, tif->tif_nfields, + sizeof(TIFFField *), tagCompare); + + return n; +} + +void +_TIFFPrintFieldInfo(TIFF* tif, FILE* fd) +{ + uint32_t i; + + fprintf(fd, "%s: \n", tif->tif_name); + for (i = 0; i < tif->tif_nfields; i++) { + const TIFFField* fip = tif->tif_fields[i]; + fprintf(fd, "field[%2d] %5lu, %2d, %2d, %d, %2d, %5s, %5s, %s\n" + , (int)i + , (unsigned long) fip->field_tag + , fip->field_readcount, fip->field_writecount + , fip->field_type + , fip->field_bit + , fip->field_oktochange ? "TRUE" : "FALSE" + , fip->field_passcount ? "TRUE" : "FALSE" + , fip->field_name + ); + } +} + +/* + * Return size of TIFFDataType in bytes + */ +int +TIFFDataWidth(TIFFDataType type) +{ + switch(type) + { + case 0: /* nothing */ + case TIFF_BYTE: + case TIFF_ASCII: + case TIFF_SBYTE: + case TIFF_UNDEFINED: + return 1; + case TIFF_SHORT: + case TIFF_SSHORT: + return 2; + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_FLOAT: + case TIFF_IFD: + return 4; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_DOUBLE: + case TIFF_LONG8: + case TIFF_SLONG8: + case TIFF_IFD8: + return 8; + default: + return 0; /* will return 0 for unknown types */ + } +} + +/* + * Return size of TIFFDataType in bytes. + * + * XXX: We need a separate function to determine the space needed + * to store the value. For TIFF_RATIONAL values TIFFDataWidth() returns 8, + * but we use 4-byte float to represent rationals. + */ +int +_TIFFDataSize(TIFFDataType type) +{ + switch (type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_ASCII: + case TIFF_UNDEFINED: + return 1; + case TIFF_SHORT: + case TIFF_SSHORT: + return 2; + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_FLOAT: + case TIFF_IFD: + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + return 4; + case TIFF_DOUBLE: + case TIFF_LONG8: + case TIFF_SLONG8: + case TIFF_IFD8: + return 8; + default: + return 0; + } +} + +/* + * Rational2Double: + * Return size of TIFFSetGetFieldType in bytes. + * + * XXX: TIFF_RATIONAL values for FIELD_CUSTOM are stored internally as 4-byte float. + * However, some of them should be stored internally as 8-byte double. + * This is now managed by the SetGetField of the tag-definition! + */ +int +_TIFFSetGetFieldSize(TIFFSetGetFieldType setgettype) +{ + switch (setgettype) + { + case TIFF_SETGET_UNDEFINED: + case TIFF_SETGET_ASCII: + case TIFF_SETGET_C0_ASCII: + case TIFF_SETGET_C16_ASCII: + case TIFF_SETGET_C32_ASCII: + case TIFF_SETGET_OTHER: + return 0; + case TIFF_SETGET_UINT8: + case TIFF_SETGET_SINT8: + case TIFF_SETGET_C0_UINT8: + case TIFF_SETGET_C0_SINT8: + case TIFF_SETGET_C16_UINT8: + case TIFF_SETGET_C16_SINT8: + case TIFF_SETGET_C32_UINT8: + case TIFF_SETGET_C32_SINT8: + return 1; + case TIFF_SETGET_UINT16: + case TIFF_SETGET_SINT16: + case TIFF_SETGET_C0_UINT16: + case TIFF_SETGET_C0_SINT16: + case TIFF_SETGET_C16_UINT16: + case TIFF_SETGET_C16_SINT16: + case TIFF_SETGET_C32_UINT16: + case TIFF_SETGET_C32_SINT16: + return 2; + case TIFF_SETGET_INT: + case TIFF_SETGET_UINT32: + case TIFF_SETGET_SINT32: + case TIFF_SETGET_FLOAT: + case TIFF_SETGET_UINT16_PAIR: + case TIFF_SETGET_C0_UINT32: + case TIFF_SETGET_C0_SINT32: + case TIFF_SETGET_C0_FLOAT: + case TIFF_SETGET_C16_UINT32: + case TIFF_SETGET_C16_SINT32: + case TIFF_SETGET_C16_FLOAT: + case TIFF_SETGET_C32_UINT32: + case TIFF_SETGET_C32_SINT32: + case TIFF_SETGET_C32_FLOAT: + return 4; + case TIFF_SETGET_UINT64: + case TIFF_SETGET_SINT64: + case TIFF_SETGET_DOUBLE: + case TIFF_SETGET_IFD8: + case TIFF_SETGET_C0_UINT64: + case TIFF_SETGET_C0_SINT64: + case TIFF_SETGET_C0_DOUBLE: + case TIFF_SETGET_C0_IFD8: + case TIFF_SETGET_C16_UINT64: + case TIFF_SETGET_C16_SINT64: + case TIFF_SETGET_C16_DOUBLE: + case TIFF_SETGET_C16_IFD8: + case TIFF_SETGET_C32_UINT64: + case TIFF_SETGET_C32_SINT64: + case TIFF_SETGET_C32_DOUBLE: + case TIFF_SETGET_C32_IFD8: + return 8; + default: + return 0; + } +} /*-- _TIFFSetGetFieldSize --- */ + + +const TIFFField* +TIFFFindField(TIFF* tif, uint32_t tag, TIFFDataType dt) +{ + TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, 0, NULL, NULL}; + TIFFField* pkey = &key; + const TIFFField **ret; + if (tif->tif_foundfield && tif->tif_foundfield->field_tag == tag && + (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type)) + return tif->tif_foundfield; + + /* If we are invoked with no field information, then just return. */ + if (!tif->tif_fields) + return NULL; + + /* NB: use sorted search (e.g. binary search) */ + + key.field_tag = tag; + key.field_type = dt; + + ret = (const TIFFField **) bsearch(&pkey, tif->tif_fields, + tif->tif_nfields, + sizeof(TIFFField *), tagCompare); + return tif->tif_foundfield = (ret ? *ret : NULL); +} + +static const TIFFField* +_TIFFFindFieldByName(TIFF* tif, const char *field_name, TIFFDataType dt) +{ + TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, 0, NULL, NULL}; + TIFFField* pkey = &key; + const TIFFField **ret; + if (tif->tif_foundfield + && streq(tif->tif_foundfield->field_name, field_name) + && (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type)) + return (tif->tif_foundfield); + + /* If we are invoked with no field information, then just return. */ + if (!tif->tif_fields) + return NULL; + + /* NB: use linear search since list is sorted by key#, not name */ + + key.field_name = (char *)field_name; + key.field_type = dt; + + ret = (const TIFFField **) + td_lfind(&pkey, tif->tif_fields, &tif->tif_nfields, + sizeof(TIFFField *), tagNameCompare); + + return tif->tif_foundfield = (ret ? *ret : NULL); +} + +const TIFFField* +TIFFFieldWithTag(TIFF* tif, uint32_t tag) +{ + const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY); + if (!fip) { + TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithTag", + "Internal error, unknown tag 0x%x", + (unsigned int) tag); + } + return (fip); +} + +const TIFFField* +TIFFFieldWithName(TIFF* tif, const char *field_name) +{ + const TIFFField* fip = + _TIFFFindFieldByName(tif, field_name, TIFF_ANY); + if (!fip) { + TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithName", + "Internal error, unknown tag %s", field_name); + } + return (fip); +} + +uint32_t +TIFFFieldTag(const TIFFField* fip) +{ + return fip->field_tag; +} + +const char * +TIFFFieldName(const TIFFField* fip) +{ + return fip->field_name; +} + +TIFFDataType +TIFFFieldDataType(const TIFFField* fip) +{ + return fip->field_type; +} + +int +TIFFFieldPassCount(const TIFFField* fip) +{ + return fip->field_passcount; +} + +int +TIFFFieldReadCount(const TIFFField* fip) +{ + return fip->field_readcount; +} + +int +TIFFFieldWriteCount(const TIFFField* fip) +{ + return fip->field_writecount; +} + +const TIFFField* +_TIFFFindOrRegisterField(TIFF *tif, uint32_t tag, TIFFDataType dt) + +{ + const TIFFField *fld; + + fld = TIFFFindField(tif, tag, dt); + if (fld == NULL) { + fld = _TIFFCreateAnonField(tif, tag, dt); + if (!_TIFFMergeFields(tif, fld, 1)) + return NULL; + } + + return fld; +} + +TIFFField* +_TIFFCreateAnonField(TIFF *tif, uint32_t tag, TIFFDataType field_type) +{ + TIFFField *fld; + (void) tif; + + fld = (TIFFField *) _TIFFmalloc(sizeof (TIFFField)); + if (fld == NULL) + return NULL; + _TIFFmemset(fld, 0, sizeof(TIFFField)); + + fld->field_tag = tag; + fld->field_readcount = TIFF_VARIABLE2; + fld->field_writecount = TIFF_VARIABLE2; + fld->field_type = field_type; + fld->reserved = 0; + switch (field_type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: + fld->set_field_type = TIFF_SETGET_C32_UINT8; + fld->get_field_type = TIFF_SETGET_C32_UINT8; + break; + case TIFF_ASCII: + fld->set_field_type = TIFF_SETGET_C32_ASCII; + fld->get_field_type = TIFF_SETGET_C32_ASCII; + break; + case TIFF_SHORT: + fld->set_field_type = TIFF_SETGET_C32_UINT16; + fld->get_field_type = TIFF_SETGET_C32_UINT16; + break; + case TIFF_LONG: + fld->set_field_type = TIFF_SETGET_C32_UINT32; + fld->get_field_type = TIFF_SETGET_C32_UINT32; + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + fld->set_field_type = TIFF_SETGET_C32_FLOAT; + fld->get_field_type = TIFF_SETGET_C32_FLOAT; + break; + case TIFF_SBYTE: + fld->set_field_type = TIFF_SETGET_C32_SINT8; + fld->get_field_type = TIFF_SETGET_C32_SINT8; + break; + case TIFF_SSHORT: + fld->set_field_type = TIFF_SETGET_C32_SINT16; + fld->get_field_type = TIFF_SETGET_C32_SINT16; + break; + case TIFF_SLONG: + fld->set_field_type = TIFF_SETGET_C32_SINT32; + fld->get_field_type = TIFF_SETGET_C32_SINT32; + break; + case TIFF_DOUBLE: + fld->set_field_type = TIFF_SETGET_C32_DOUBLE; + fld->get_field_type = TIFF_SETGET_C32_DOUBLE; + break; + case TIFF_IFD: + case TIFF_IFD8: + fld->set_field_type = TIFF_SETGET_C32_IFD8; + fld->get_field_type = TIFF_SETGET_C32_IFD8; + break; + case TIFF_LONG8: + fld->set_field_type = TIFF_SETGET_C32_UINT64; + fld->get_field_type = TIFF_SETGET_C32_UINT64; + break; + case TIFF_SLONG8: + fld->set_field_type = TIFF_SETGET_C32_SINT64; + fld->get_field_type = TIFF_SETGET_C32_SINT64; + break; + default: + fld->set_field_type = TIFF_SETGET_UNDEFINED; + fld->get_field_type = TIFF_SETGET_UNDEFINED; + break; + } + fld->field_bit = FIELD_CUSTOM; + fld->field_oktochange = TRUE; + fld->field_passcount = TRUE; + fld->field_name = (char *) _TIFFmalloc(32); + if (fld->field_name == NULL) { + _TIFFfree(fld); + return NULL; + } + fld->field_subfields = NULL; + + /* + * note that this name is a special sign to TIFFClose() and + * _TIFFSetupFields() to free the field + */ + (void) snprintf(fld->field_name, 32, "Tag %d", (int) tag); + + return fld; +} + +/**************************************************************************** + * O B S O L E T E D I N T E R F A C E S + * + * Don't use this stuff in your applications, it may be removed in the future + * libtiff versions. + ****************************************************************************/ + +static TIFFSetGetFieldType +_TIFFSetGetType(TIFFDataType type, short count, unsigned char passcount) +{ + if (type == TIFF_ASCII && count == TIFF_VARIABLE && passcount == 0) + return TIFF_SETGET_ASCII; + + else if (count == 1 && passcount == 0) { + switch (type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: + return TIFF_SETGET_UINT8; + case TIFF_ASCII: + return TIFF_SETGET_ASCII; + case TIFF_SHORT: + return TIFF_SETGET_UINT16; + case TIFF_LONG: + return TIFF_SETGET_UINT32; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + return TIFF_SETGET_FLOAT; + case TIFF_SBYTE: + return TIFF_SETGET_SINT8; + case TIFF_SSHORT: + return TIFF_SETGET_SINT16; + case TIFF_SLONG: + return TIFF_SETGET_SINT32; + case TIFF_DOUBLE: + return TIFF_SETGET_DOUBLE; + case TIFF_IFD: + case TIFF_IFD8: + return TIFF_SETGET_IFD8; + case TIFF_LONG8: + return TIFF_SETGET_UINT64; + case TIFF_SLONG8: + return TIFF_SETGET_SINT64; + default: + return TIFF_SETGET_UNDEFINED; + } + } + + else if (count >= 1 && passcount == 0) { + switch (type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: + return TIFF_SETGET_C0_UINT8; + case TIFF_ASCII: + return TIFF_SETGET_C0_ASCII; + case TIFF_SHORT: + return TIFF_SETGET_C0_UINT16; + case TIFF_LONG: + return TIFF_SETGET_C0_UINT32; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + return TIFF_SETGET_C0_FLOAT; + case TIFF_SBYTE: + return TIFF_SETGET_C0_SINT8; + case TIFF_SSHORT: + return TIFF_SETGET_C0_SINT16; + case TIFF_SLONG: + return TIFF_SETGET_C0_SINT32; + case TIFF_DOUBLE: + return TIFF_SETGET_C0_DOUBLE; + case TIFF_IFD: + case TIFF_IFD8: + return TIFF_SETGET_C0_IFD8; + case TIFF_LONG8: + return TIFF_SETGET_C0_UINT64; + case TIFF_SLONG8: + return TIFF_SETGET_C0_SINT64; + default: + return TIFF_SETGET_UNDEFINED; + } + } + + else if (count == TIFF_VARIABLE && passcount == 1) { + switch (type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: + return TIFF_SETGET_C16_UINT8; + case TIFF_ASCII: + return TIFF_SETGET_C16_ASCII; + case TIFF_SHORT: + return TIFF_SETGET_C16_UINT16; + case TIFF_LONG: + return TIFF_SETGET_C16_UINT32; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + return TIFF_SETGET_C16_FLOAT; + case TIFF_SBYTE: + return TIFF_SETGET_C16_SINT8; + case TIFF_SSHORT: + return TIFF_SETGET_C16_SINT16; + case TIFF_SLONG: + return TIFF_SETGET_C16_SINT32; + case TIFF_DOUBLE: + return TIFF_SETGET_C16_DOUBLE; + case TIFF_IFD: + case TIFF_IFD8: + return TIFF_SETGET_C16_IFD8; + case TIFF_LONG8: + return TIFF_SETGET_C16_UINT64; + case TIFF_SLONG8: + return TIFF_SETGET_C16_SINT64; + default: + return TIFF_SETGET_UNDEFINED; + } + } + + else if (count == TIFF_VARIABLE2 && passcount == 1) { + switch (type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: + return TIFF_SETGET_C32_UINT8; + case TIFF_ASCII: + return TIFF_SETGET_C32_ASCII; + case TIFF_SHORT: + return TIFF_SETGET_C32_UINT16; + case TIFF_LONG: + return TIFF_SETGET_C32_UINT32; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + return TIFF_SETGET_C32_FLOAT; + case TIFF_SBYTE: + return TIFF_SETGET_C32_SINT8; + case TIFF_SSHORT: + return TIFF_SETGET_C32_SINT16; + case TIFF_SLONG: + return TIFF_SETGET_C32_SINT32; + case TIFF_DOUBLE: + return TIFF_SETGET_C32_DOUBLE; + case TIFF_IFD: + case TIFF_IFD8: + return TIFF_SETGET_C32_IFD8; + case TIFF_LONG8: + return TIFF_SETGET_C32_UINT64; + case TIFF_SLONG8: + return TIFF_SETGET_C32_SINT64; + default: + return TIFF_SETGET_UNDEFINED; + } + } + + return TIFF_SETGET_UNDEFINED; +} + +int +TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], uint32_t n) +{ + static const char module[] = "TIFFMergeFieldInfo"; + static const char reason[] = "for fields array"; + TIFFField *tp; + size_t nfields; + uint32_t i; + + if (tif->tif_nfieldscompat > 0) { + tif->tif_fieldscompat = (TIFFFieldArray *) + _TIFFCheckRealloc(tif, tif->tif_fieldscompat, + tif->tif_nfieldscompat + 1, + sizeof(TIFFFieldArray), reason); + } else { + tif->tif_fieldscompat = (TIFFFieldArray *) + _TIFFCheckMalloc(tif, 1, sizeof(TIFFFieldArray), + reason); + } + if (!tif->tif_fieldscompat) { + TIFFErrorExt(tif->tif_clientdata, module, + "Failed to allocate fields array"); + return -1; + } + nfields = tif->tif_nfieldscompat++; + + tif->tif_fieldscompat[nfields].type = tfiatOther; + tif->tif_fieldscompat[nfields].allocated_size = n; + tif->tif_fieldscompat[nfields].count = n; + tif->tif_fieldscompat[nfields].fields = + (TIFFField *)_TIFFCheckMalloc(tif, n, sizeof(TIFFField), + reason); + if (!tif->tif_fieldscompat[nfields].fields) { + TIFFErrorExt(tif->tif_clientdata, module, + "Failed to allocate fields array"); + return -1; + } + + tp = tif->tif_fieldscompat[nfields].fields; + for (i = 0; i < n; i++) { + tp->field_tag = info[i].field_tag; + tp->field_readcount = info[i].field_readcount; + tp->field_writecount = info[i].field_writecount; + tp->field_type = info[i].field_type; + tp->reserved = 0; + tp->set_field_type = + _TIFFSetGetType(info[i].field_type, + info[i].field_readcount, + info[i].field_passcount); + tp->get_field_type = + _TIFFSetGetType(info[i].field_type, + info[i].field_readcount, + info[i].field_passcount); + tp->field_bit = info[i].field_bit; + tp->field_oktochange = info[i].field_oktochange; + tp->field_passcount = info[i].field_passcount; + tp->field_name = info[i].field_name; + tp->field_subfields = NULL; + tp++; + } + + if (!_TIFFMergeFields(tif, tif->tif_fieldscompat[nfields].fields, n)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Setting up field info failed"); + return -1; + } + + return 0; +} + +int +_TIFFCheckFieldIsValidForCodec(TIFF *tif, ttag_t tag) +{ + /* Filter out non-codec specific tags */ + switch (tag) { + /* Shared tags */ + case TIFFTAG_PREDICTOR: + /* JPEG tags */ + case TIFFTAG_JPEGTABLES: + /* OJPEG tags */ + case TIFFTAG_JPEGIFOFFSET: + case TIFFTAG_JPEGIFBYTECOUNT: + case TIFFTAG_JPEGQTABLES: + case TIFFTAG_JPEGDCTABLES: + case TIFFTAG_JPEGACTABLES: + case TIFFTAG_JPEGPROC: + case TIFFTAG_JPEGRESTARTINTERVAL: + /* CCITT* */ + case TIFFTAG_BADFAXLINES: + case TIFFTAG_CLEANFAXDATA: + case TIFFTAG_CONSECUTIVEBADFAXLINES: + case TIFFTAG_GROUP3OPTIONS: + case TIFFTAG_GROUP4OPTIONS: + /* LERC */ + case TIFFTAG_LERC_PARAMETERS: + break; + default: + return 1; + } + /* Check if codec specific tags are allowed for the current + * compression scheme (codec) */ + switch (tif->tif_dir.td_compression) { + case COMPRESSION_LZW: + if (tag == TIFFTAG_PREDICTOR) + return 1; + break; + case COMPRESSION_PACKBITS: + /* No codec-specific tags */ + break; + case COMPRESSION_THUNDERSCAN: + /* No codec-specific tags */ + break; + case COMPRESSION_NEXT: + /* No codec-specific tags */ + break; + case COMPRESSION_JPEG: + if (tag == TIFFTAG_JPEGTABLES) + return 1; + break; + case COMPRESSION_OJPEG: + switch (tag) { + case TIFFTAG_JPEGIFOFFSET: + case TIFFTAG_JPEGIFBYTECOUNT: + case TIFFTAG_JPEGQTABLES: + case TIFFTAG_JPEGDCTABLES: + case TIFFTAG_JPEGACTABLES: + case TIFFTAG_JPEGPROC: + case TIFFTAG_JPEGRESTARTINTERVAL: + return 1; + } + break; + case COMPRESSION_CCITTRLE: + case COMPRESSION_CCITTRLEW: + case COMPRESSION_CCITTFAX3: + case COMPRESSION_CCITTFAX4: + switch (tag) { + case TIFFTAG_BADFAXLINES: + case TIFFTAG_CLEANFAXDATA: + case TIFFTAG_CONSECUTIVEBADFAXLINES: + return 1; + case TIFFTAG_GROUP3OPTIONS: + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX3) + return 1; + break; + case TIFFTAG_GROUP4OPTIONS: + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) + return 1; + break; + } + break; + case COMPRESSION_JBIG: + /* No codec-specific tags */ + break; + case COMPRESSION_DEFLATE: + case COMPRESSION_ADOBE_DEFLATE: + if (tag == TIFFTAG_PREDICTOR) + return 1; + break; + case COMPRESSION_PIXARLOG: + if (tag == TIFFTAG_PREDICTOR) + return 1; + break; + case COMPRESSION_SGILOG: + case COMPRESSION_SGILOG24: + /* No codec-specific tags */ + break; + case COMPRESSION_LZMA: + if (tag == TIFFTAG_PREDICTOR) + return 1; + break; + case COMPRESSION_ZSTD: + if (tag == TIFFTAG_PREDICTOR) + return 1; + break; + case COMPRESSION_LERC: + if (tag == TIFFTAG_LERC_PARAMETERS) + return 1; + break; + } + return 0; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_dirread.c b/libs/tiff/libtiff/tif_dirread.c new file mode 100644 index 00000000000..d84147a0e82 --- /dev/null +++ b/libs/tiff/libtiff/tif_dirread.c @@ -0,0 +1,6495 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Read Support Routines. + */ + +/* Suggested pending improvements: + * - add a field 'field_info' to the TIFFDirEntry structure, and set that with + * the pointer to the appropriate TIFFField structure early on in + * TIFFReadDirectory, so as to eliminate current possibly repetitive lookup. + */ + +#include "tiffconf.h" +#include "tiffiop.h" +#include +#include + +#define FAILED_FII ((uint32_t) -1) + +#ifdef HAVE_IEEEFP +# define TIFFCvtIEEEFloatToNative(tif, n, fp) +# define TIFFCvtIEEEDoubleToNative(tif, n, dp) +#else +extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32_t, float*); +extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32_t, double*); +#endif + +enum TIFFReadDirEntryErr { + TIFFReadDirEntryErrOk = 0, + TIFFReadDirEntryErrCount = 1, + TIFFReadDirEntryErrType = 2, + TIFFReadDirEntryErrIo = 3, + TIFFReadDirEntryErrRange = 4, + TIFFReadDirEntryErrPsdif = 5, + TIFFReadDirEntryErrSizesan = 6, + TIFFReadDirEntryErrAlloc = 7, +}; + +static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8_t* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32_t* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32_t* count, uint32_t desttypesize, void** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8_t** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8_t** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16_t** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16_t** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32_t** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32_t** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64_t** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64_t** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryDoubleArray(TIFF* tif, TIFFDirEntry* direntry, double** value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8Array(TIFF* tif, TIFFDirEntry* direntry, uint64_t** value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value); +#if 0 +static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value); +#endif + +static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8_t* value); +static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8_t* value); +static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value); +static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16_t* value); +static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32_t* value); +static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32_t* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64_t* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSrational(TIFF* tif, TIFFDirEntry* direntry, double* value); +static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64_t value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64_t value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64_t value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64_t value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongLong8(uint64_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong8(int64_t value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong(uint32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong8(uint64_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongSlong8(int64_t value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sbyte(int8_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sshort(int16_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong(int32_t value); +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong8(int64_t value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlong8Long8(uint64_t value); + +static enum TIFFReadDirEntryErr TIFFReadDirEntryData(TIFF* tif, uint64_t offset, tmsize_t size, void* dest); +static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, const char* module, const char* tagname, int recover); + +static void TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount); +static TIFFDirEntry* TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount, uint16_t tagid); +static void TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16_t tagid, uint32_t* fii); + +static int EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount); +static void MissingRequired(TIFF*, const char*); +static int TIFFCheckDirOffset(TIFF* tif, uint64_t diroff); +static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32_t); +static uint16_t TIFFFetchDirectory(TIFF* tif, uint64_t diroff, TIFFDirEntry** pdir, uint64_t* nextdiroff); +static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*, int recover); +static int TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32_t nstrips, uint64_t** lpp); +static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*); +static void ChopUpSingleUncompressedStrip(TIFF*); +static void TryChopUpUncompressedBigTiff(TIFF*); +static uint64_t TIFFReadUInt64(const uint8_t *value); +static int _TIFFGetMaxColorChannels(uint16_t photometric); + +static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount ); + +typedef union _UInt64Aligned_t +{ + double d; + uint64_t l; + uint32_t i[2]; + uint16_t s[4]; + uint8_t c[8]; +} UInt64Aligned_t; + +/* + Unaligned safe copy of a uint64_t value from an octet array. +*/ +static uint64_t TIFFReadUInt64(const uint8_t *value) +{ + UInt64Aligned_t result; + + result.c[0]=value[0]; + result.c[1]=value[1]; + result.c[2]=value[2]; + result.c[3]=value[3]; + result.c[4]=value[4]; + result.c[5]=value[5]; + result.c[6]=value[6]; + result.c[7]=value[7]; + + return result.l; +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8_t* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_UNDEFINED: /* Support to read TIFF_UNDEFINED with field_readcount==1 */ + TIFFReadDirEntryCheckedByte(tif,direntry,value); + return(TIFFReadDirEntryErrOk); + case TIFF_SBYTE: + { + int8_t m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeByteSbyte(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16_t m; + TIFFReadDirEntryCheckedShort(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeByteShort(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16_t m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeByteSshort(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32_t m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeByteLong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32_t m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeByteSlong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64_t m; + err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeByteLong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64_t m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeByteSlong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint8_t)m; + return(TIFFReadDirEntryErrOk); + } + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t m; + TIFFReadDirEntryCheckedByte(tif,direntry,&m); + *value=(uint16_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8_t m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeShortSbyte(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + TIFFReadDirEntryCheckedShort(tif,direntry,value); + return(TIFFReadDirEntryErrOk); + case TIFF_SSHORT: + { + int16_t m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeShortSshort(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32_t m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeShortLong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32_t m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeShortSlong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64_t m; + err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeShortLong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64_t m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeShortSlong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint16_t)m; + return(TIFFReadDirEntryErrOk); + } + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32_t* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t m; + TIFFReadDirEntryCheckedByte(tif,direntry,&m); + *value=(uint32_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8_t m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLongSbyte(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint32_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16_t m; + TIFFReadDirEntryCheckedShort(tif,direntry,&m); + *value=(uint32_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16_t m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLongSshort(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint32_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + TIFFReadDirEntryCheckedLong(tif,direntry,value); + return(TIFFReadDirEntryErrOk); + case TIFF_SLONG: + { + int32_t m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLongSlong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint32_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64_t m; + err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeLongLong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint32_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64_t m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeLongSlong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint32_t)m; + return(TIFFReadDirEntryErrOk); + } + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t m; + TIFFReadDirEntryCheckedByte(tif,direntry,&m); + *value=(uint64_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8_t m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLong8Sbyte(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint64_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16_t m; + TIFFReadDirEntryCheckedShort(tif,direntry,&m); + *value=(uint64_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16_t m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLong8Sshort(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint64_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32_t m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + *value=(uint64_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32_t m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + err=TIFFReadDirEntryCheckRangeLong8Slong(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint64_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + err=TIFFReadDirEntryCheckedLong8(tif,direntry,value); + return(err); + case TIFF_SLONG8: + { + int64_t m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + err=TIFFReadDirEntryCheckRangeLong8Slong8(m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(uint64_t)m; + return(TIFFReadDirEntryErrOk); + } + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t m; + TIFFReadDirEntryCheckedByte(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8_t m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16_t m; + TIFFReadDirEntryCheckedShort(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16_t m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32_t m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32_t m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64_t m; + err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); +#if defined(__WIN32__) && (_MSC_VER < 1500) + /* + * XXX: MSVC 6.0 does not support conversion + * of 64-bit integers into floating point + * values. + */ + *value = _TIFFUInt64ToFloat(m); +#else + *value=(float)m; +#endif + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64_t m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_RATIONAL: + { + double m; + err=TIFFReadDirEntryCheckedRational(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SRATIONAL: + { + double m; + err=TIFFReadDirEntryCheckedSrational(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_FLOAT: + TIFFReadDirEntryCheckedFloat(tif,direntry,value); + return(TIFFReadDirEntryErrOk); + case TIFF_DOUBLE: + { + double m; + err=TIFFReadDirEntryCheckedDouble(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + if ((m > FLT_MAX) || (m < -FLT_MAX)) + return(TIFFReadDirEntryErrRange); + *value=(float)m; + return(TIFFReadDirEntryErrOk); + } + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t m; + TIFFReadDirEntryCheckedByte(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8_t m; + TIFFReadDirEntryCheckedSbyte(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16_t m; + TIFFReadDirEntryCheckedShort(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16_t m; + TIFFReadDirEntryCheckedSshort(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32_t m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32_t m; + TIFFReadDirEntryCheckedSlong(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64_t m; + err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); +#if defined(__WIN32__) && (_MSC_VER < 1500) + /* + * XXX: MSVC 6.0 does not support conversion + * of 64-bit integers into floating point + * values. + */ + *value = _TIFFUInt64ToDouble(m); +#else + *value = (double)m; +#endif + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64_t m; + err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_RATIONAL: + err=TIFFReadDirEntryCheckedRational(tif,direntry,value); + return(err); + case TIFF_SRATIONAL: + err=TIFFReadDirEntryCheckedSrational(tif,direntry,value); + return(err); + case TIFF_FLOAT: + { + float m; + TIFFReadDirEntryCheckedFloat(tif,direntry,&m); + *value=(double)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_DOUBLE: + err=TIFFReadDirEntryCheckedDouble(tif,direntry,value); + return(err); + default: + return(TIFFReadDirEntryErrType); + } +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value) +{ + enum TIFFReadDirEntryErr err; + if (direntry->tdir_count!=1) + return(TIFFReadDirEntryErrCount); + switch (direntry->tdir_type) + { + case TIFF_LONG: + case TIFF_IFD: + { + uint32_t m; + TIFFReadDirEntryCheckedLong(tif,direntry,&m); + *value=(uint64_t)m; + return(TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + case TIFF_IFD8: + err=TIFFReadDirEntryCheckedLong8(tif,direntry,value); + return(err); + default: + return(TIFFReadDirEntryErrType); + } +} + + +#define INITIAL_THRESHOLD (1024 * 1024) +#define THRESHOLD_MULTIPLIER 10 +#define MAX_THRESHOLD (THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * INITIAL_THRESHOLD) + +static enum TIFFReadDirEntryErr TIFFReadDirEntryDataAndRealloc( + TIFF* tif, uint64_t offset, tmsize_t size, void** pdest) +{ +#if SIZEOF_SIZE_T == 8 + tmsize_t threshold = INITIAL_THRESHOLD; +#endif + tmsize_t already_read = 0; + + assert( !isMapped(tif) ); + + if (!SeekOK(tif,offset)) + return(TIFFReadDirEntryErrIo); + + /* On 64 bit processes, read first a maximum of 1 MB, then 10 MB, etc */ + /* so as to avoid allocating too much memory in case the file is too */ + /* short. We could ask for the file size, but this might be */ + /* expensive with some I/O layers (think of reading a gzipped file) */ + /* Restrict to 64 bit processes, so as to avoid reallocs() */ + /* on 32 bit processes where virtual memory is scarce. */ + while( already_read < size ) + { + void* new_dest; + tmsize_t bytes_read; + tmsize_t to_read = size - already_read; +#if SIZEOF_SIZE_T == 8 + if( to_read >= threshold && threshold < MAX_THRESHOLD ) + { + to_read = threshold; + threshold *= THRESHOLD_MULTIPLIER; + } +#endif + + new_dest = (uint8_t*) _TIFFrealloc( + *pdest, already_read + to_read); + if( new_dest == NULL ) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Failed to allocate memory for %s " + "(%"TIFF_SSIZE_FORMAT" elements of %"TIFF_SSIZE_FORMAT" bytes each)", + "TIFFReadDirEntryArray", + (tmsize_t) 1, already_read + to_read); + return TIFFReadDirEntryErrAlloc; + } + *pdest = new_dest; + + bytes_read = TIFFReadFile(tif, + (char*)*pdest + already_read, to_read); + already_read += bytes_read; + if (bytes_read != to_read) { + return TIFFReadDirEntryErrIo; + } + } + return TIFFReadDirEntryErrOk; +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryArrayWithLimit( + TIFF* tif, TIFFDirEntry* direntry, uint32_t* count, uint32_t desttypesize, + void** value, uint64_t maxcount) +{ + int typesize; + uint32_t datasize; + void* data; + uint64_t target_count64; + int original_datasize_clamped; + typesize=TIFFDataWidth(direntry->tdir_type); + + target_count64 = (direntry->tdir_count > maxcount) ? + maxcount : direntry->tdir_count; + + if ((target_count64==0)||(typesize==0)) + { + *value=0; + return(TIFFReadDirEntryErrOk); + } + (void) desttypesize; + + /* We just want to know if the original tag size is more than 4 bytes + * (classic TIFF) or 8 bytes (BigTIFF) + */ + original_datasize_clamped = + ((direntry->tdir_count > 10) ? 10 : (int)direntry->tdir_count) * typesize; + + /* + * As a sanity check, make sure we have no more than a 2GB tag array + * in either the current data type or the dest data type. This also + * avoids problems with overflow of tmsize_t on 32bit systems. + */ + if ((uint64_t)(2147483647 / typesize) < target_count64) + return(TIFFReadDirEntryErrSizesan); + if ((uint64_t)(2147483647 / desttypesize) < target_count64) + return(TIFFReadDirEntryErrSizesan); + + *count=(uint32_t)target_count64; + datasize=(*count)*typesize; + assert((tmsize_t)datasize>0); + + if( isMapped(tif) && datasize > (uint64_t)tif->tif_size ) + return TIFFReadDirEntryErrIo; + + if( !isMapped(tif) && + (((tif->tif_flags&TIFF_BIGTIFF) && datasize > 8) || + (!(tif->tif_flags&TIFF_BIGTIFF) && datasize > 4)) ) + { + data = NULL; + } + else + { + data=_TIFFCheckMalloc(tif, *count, typesize, "ReadDirEntryArray"); + if (data==0) + return(TIFFReadDirEntryErrAlloc); + } + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + /* Only the condition on original_datasize_clamped. The second + * one is implied, but Coverity Scan cannot see it. */ + if (original_datasize_clamped<=4 && datasize <= 4 ) + _TIFFmemcpy(data,&direntry->tdir_offset,datasize); + else + { + enum TIFFReadDirEntryErr err; + uint32_t offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + if( isMapped(tif) ) + err=TIFFReadDirEntryData(tif, (uint64_t)offset, (tmsize_t)datasize, data); + else + err=TIFFReadDirEntryDataAndRealloc(tif, (uint64_t)offset, (tmsize_t)datasize, &data); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + } + } + else + { + /* See above comment for the Classic TIFF case */ + if (original_datasize_clamped<=8 && datasize <= 8 ) + _TIFFmemcpy(data,&direntry->tdir_offset,datasize); + else + { + enum TIFFReadDirEntryErr err; + uint64_t offset = direntry->tdir_offset.toff_long8; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(&offset); + if( isMapped(tif) ) + err=TIFFReadDirEntryData(tif, (uint64_t)offset, (tmsize_t)datasize, data); + else + err=TIFFReadDirEntryDataAndRealloc(tif, (uint64_t)offset, (tmsize_t)datasize, &data); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + } + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32_t* count, uint32_t desttypesize, void** value) +{ + return TIFFReadDirEntryArrayWithLimit(tif, direntry, count, + desttypesize, value, ~((uint64_t)0)); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8_t** value) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void* origdata; + uint8_t* data; + switch (direntry->tdir_type) + { + case TIFF_ASCII: + case TIFF_UNDEFINED: + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,1,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_ASCII: + case TIFF_UNDEFINED: + case TIFF_BYTE: + *value=(uint8_t*)origdata; + return(TIFFReadDirEntryErrOk); + case TIFF_SBYTE: + { + int8_t* m; + uint32_t n; + m=(int8_t*)origdata; + for (n=0; ntdir_type) + { + case TIFF_SHORT: + { + uint16_t* ma; + uint8_t* mb; + uint32_t n; + ma=(uint16_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + err=TIFFReadDirEntryCheckRangeByteShort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8_t)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16_t* ma; + uint8_t* mb; + uint32_t n; + ma=(int16_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)ma); + err=TIFFReadDirEntryCheckRangeByteSshort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8_t)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32_t* ma; + uint8_t* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + err=TIFFReadDirEntryCheckRangeByteLong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8_t)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32_t* ma; + uint8_t* mb; + uint32_t n; + ma=(int32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)ma); + err=TIFFReadDirEntryCheckRangeByteSlong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8_t)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64_t* ma; + uint8_t* mb; + uint32_t n; + ma=(uint64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeByteLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8_t)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64_t* ma; + uint8_t* mb; + uint32_t n; + ma=(int64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)ma); + err=TIFFReadDirEntryCheckRangeByteSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint8_t)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8_t** value) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void* origdata; + int8_t* data; + switch (direntry->tdir_type) + { + case TIFF_UNDEFINED: + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,1,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_UNDEFINED: + case TIFF_BYTE: + { + uint8_t* m; + uint32_t n; + m=(uint8_t*)origdata; + for (n=0; ntdir_type) + { + case TIFF_SHORT: + { + uint16_t* ma; + int8_t* mb; + uint32_t n; + ma=(uint16_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + err=TIFFReadDirEntryCheckRangeSbyteShort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8_t)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16_t* ma; + int8_t* mb; + uint32_t n; + ma=(int16_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)ma); + err=TIFFReadDirEntryCheckRangeSbyteSshort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8_t)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32_t* ma; + int8_t* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + err=TIFFReadDirEntryCheckRangeSbyteLong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8_t)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32_t* ma; + int8_t* mb; + uint32_t n; + ma=(int32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)ma); + err=TIFFReadDirEntryCheckRangeSbyteSlong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8_t)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64_t* ma; + int8_t* mb; + uint32_t n; + ma=(uint64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeSbyteLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8_t)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64_t* ma; + int8_t* mb; + uint32_t n; + ma=(int64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)ma); + err=TIFFReadDirEntryCheckRangeSbyteSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int8_t)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16_t** value) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void* origdata; + uint16_t* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,2,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_SHORT: + *value=(uint16_t*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfShort(*value,count); + return(TIFFReadDirEntryErrOk); + case TIFF_SSHORT: + { + int16_t* m; + uint32_t n; + m=(int16_t*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)m); + err=TIFFReadDirEntryCheckRangeShortSshort(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(uint16_t*)origdata; + return(TIFFReadDirEntryErrOk); + } + } + data=(uint16_t*)_TIFFmalloc(count * 2); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t* ma; + uint16_t* mb; + uint32_t n; + ma=(uint8_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + err=TIFFReadDirEntryCheckRangeShortLong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint16_t)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32_t* ma; + uint16_t* mb; + uint32_t n; + ma=(int32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)ma); + err=TIFFReadDirEntryCheckRangeShortSlong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint16_t)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64_t* ma; + uint16_t* mb; + uint32_t n; + ma=(uint64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeShortLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint16_t)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64_t* ma; + uint16_t* mb; + uint32_t n; + ma=(int64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)ma); + err=TIFFReadDirEntryCheckRangeShortSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint16_t)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16_t** value) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void* origdata; + int16_t* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,2,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_SHORT: + { + uint16_t* m; + uint32_t n; + m=(uint16_t*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(m); + err=TIFFReadDirEntryCheckRangeSshortShort(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(int16_t*)origdata; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + *value=(int16_t*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfShort((uint16_t*)(*value), count); + return(TIFFReadDirEntryErrOk); + } + data=(int16_t*)_TIFFmalloc(count * 2); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t* ma; + int16_t* mb; + uint32_t n; + ma=(uint8_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + err=TIFFReadDirEntryCheckRangeSshortLong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int16_t)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32_t* ma; + int16_t* mb; + uint32_t n; + ma=(int32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)ma); + err=TIFFReadDirEntryCheckRangeSshortSlong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int16_t)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64_t* ma; + int16_t* mb; + uint32_t n; + ma=(uint64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeSshortLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int16_t)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64_t* ma; + int16_t* mb; + uint32_t n; + ma=(int64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)ma); + err=TIFFReadDirEntryCheckRangeSshortSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int16_t)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32_t** value) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void* origdata; + uint32_t* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_LONG: + *value=(uint32_t*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(*value,count); + return(TIFFReadDirEntryErrOk); + case TIFF_SLONG: + { + int32_t* m; + uint32_t n; + m=(int32_t*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)m); + err=TIFFReadDirEntryCheckRangeLongSlong(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(uint32_t*)origdata; + return(TIFFReadDirEntryErrOk); + } + } + data=(uint32_t*)_TIFFmalloc(count * 4); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t* ma; + uint32_t* mb; + uint32_t n; + ma=(uint8_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(uint32_t)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16_t* ma; + uint32_t* mb; + uint32_t n; + ma=(int16_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)ma); + err=TIFFReadDirEntryCheckRangeLongSshort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint32_t)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64_t* ma; + uint32_t* mb; + uint32_t n; + ma=(uint64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeLongLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint32_t)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64_t* ma; + uint32_t* mb; + uint32_t n; + ma=(int64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)ma); + err=TIFFReadDirEntryCheckRangeLongSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint32_t)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32_t** value) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void* origdata; + int32_t* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_LONG: + { + uint32_t* m; + uint32_t n; + m=(uint32_t*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)m); + err=TIFFReadDirEntryCheckRangeSlongLong(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(int32_t*)origdata; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + *value=(int32_t*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32_t*)(*value), count); + return(TIFFReadDirEntryErrOk); + } + data=(int32_t*)_TIFFmalloc(count * 4); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t* ma; + int32_t* mb; + uint32_t n; + ma=(uint8_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(int32_t)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16_t* ma; + int32_t* mb; + uint32_t n; + ma=(int16_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)ma); + *mb++=(int32_t)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64_t* ma; + int32_t* mb; + uint32_t n; + ma=(uint64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); + err=TIFFReadDirEntryCheckRangeSlongLong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int32_t)(*ma++); + } + } + break; + case TIFF_SLONG8: + { + int64_t* ma; + int32_t* mb; + uint32_t n; + ma=(int64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)ma); + err=TIFFReadDirEntryCheckRangeSlongSlong8(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(int32_t)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8ArrayWithLimit( + TIFF* tif, TIFFDirEntry* direntry, uint64_t** value, uint64_t maxcount) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void* origdata; + uint64_t* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArrayWithLimit(tif,direntry,&count,8,&origdata,maxcount); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_LONG8: + *value=(uint64_t*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8(*value,count); + return(TIFFReadDirEntryErrOk); + case TIFF_SLONG8: + { + int64_t* m; + uint32_t n; + m=(int64_t*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)m); + err=TIFFReadDirEntryCheckRangeLong8Slong8(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(uint64_t*)origdata; + return(TIFFReadDirEntryErrOk); + } + } + data=(uint64_t*)_TIFFmalloc(count * 8); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t* ma; + uint64_t* mb; + uint32_t n; + ma=(uint8_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(uint64_t)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16_t* ma; + uint64_t* mb; + uint32_t n; + ma=(int16_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)ma); + err=TIFFReadDirEntryCheckRangeLong8Sshort(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint64_t)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32_t* ma; + uint64_t* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + *mb++=(uint64_t)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32_t* ma; + uint64_t* mb; + uint32_t n; + ma=(int32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)ma); + err=TIFFReadDirEntryCheckRangeLong8Slong(*ma); + if (err!=TIFFReadDirEntryErrOk) + break; + *mb++=(uint64_t)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(data); + return(err); + } + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64_t** value) +{ + return TIFFReadDirEntryLong8ArrayWithLimit(tif, direntry, value, ~((uint64_t)0)); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64_t** value) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void* origdata; + int64_t* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_LONG8: + { + uint64_t* m; + uint32_t n; + m=(uint64_t*)origdata; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(m); + err=TIFFReadDirEntryCheckRangeSlong8Long8(*m); + if (err!=TIFFReadDirEntryErrOk) + { + _TIFFfree(origdata); + return(err); + } + m++; + } + *value=(int64_t*)origdata; + return(TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + *value=(int64_t*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8((uint64_t*)(*value), count); + return(TIFFReadDirEntryErrOk); + } + data=(int64_t*)_TIFFmalloc(count * 8); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t* ma; + int64_t* mb; + uint32_t n; + ma=(uint8_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(int64_t)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16_t* ma; + int64_t* mb; + uint32_t n; + ma=(int16_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)ma); + *mb++=(int64_t)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32_t* ma; + int64_t* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + *mb++=(int64_t)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32_t* ma; + int64_t* mb; + uint32_t n; + ma=(int32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)ma); + *mb++=(int64_t)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void* origdata; + float* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + case TIFF_DOUBLE: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,4,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_FLOAT: + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32_t*)origdata, count); + TIFFCvtIEEEDoubleToNative(tif,count,(float*)origdata); + *value=(float*)origdata; + return(TIFFReadDirEntryErrOk); + } + data=(float*)_TIFFmalloc(count*sizeof(float)); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t* ma; + float* mb; + uint32_t n; + ma=(uint8_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(float)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16_t* ma; + float* mb; + uint32_t n; + ma=(int16_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)ma); + *mb++=(float)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32_t* ma; + float* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + *mb++=(float)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32_t* ma; + float* mb; + uint32_t n; + ma=(int32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)ma); + *mb++=(float)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64_t* ma; + float* mb; + uint32_t n; + ma=(uint64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); +#if defined(__WIN32__) && (_MSC_VER < 1500) + /* + * XXX: MSVC 6.0 does not support + * conversion of 64-bit integers into + * floating point values. + */ + *mb++ = _TIFFUInt64ToFloat(*ma++); +#else + *mb++ = (float)(*ma++); +#endif + } + } + break; + case TIFF_SLONG8: + { + int64_t* ma; + float* mb; + uint32_t n; + ma=(int64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)ma); + *mb++=(float)(*ma++); + } + } + break; + case TIFF_RATIONAL: + { + uint32_t* ma; + uint32_t maa; + uint32_t mab; + float* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + maa=*ma++; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + mab=*ma++; + if (mab==0) + *mb++=0.0; + else + *mb++=(float)maa/(float)mab; + } + } + break; + case TIFF_SRATIONAL: + { + uint32_t* ma; + int32_t maa; + uint32_t mab; + float* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + maa=*(int32_t*)ma; + ma++; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + mab=*ma++; + if (mab==0) + *mb++=0.0; + else + *mb++=(float)maa/(float)mab; + } + } + break; + case TIFF_DOUBLE: + { + double* ma; + float* mb; + uint32_t n; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8((uint64_t*)origdata, count); + TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata); + ma=(double*)origdata; + mb=data; + for (n=0; n FLT_MAX ) + val = FLT_MAX; + else if( val < -FLT_MAX ) + val = -FLT_MAX; + *mb++=(float)val; + } + } + break; + } + _TIFFfree(origdata); + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryDoubleArray(TIFF* tif, TIFFDirEntry* direntry, double** value) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void* origdata; + double* data; + switch (direntry->tdir_type) + { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_LONG8: + case TIFF_SLONG8: + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + case TIFF_DOUBLE: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_DOUBLE: + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8((uint64_t*)origdata, count); + TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata); + *value=(double*)origdata; + return(TIFFReadDirEntryErrOk); + } + data=(double*)_TIFFmalloc(count*sizeof(double)); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_BYTE: + { + uint8_t* ma; + double* mb; + uint32_t n; + ma=(uint8_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort(ma); + *mb++=(double)(*ma++); + } + } + break; + case TIFF_SSHORT: + { + int16_t* ma; + double* mb; + uint32_t n; + ma=(int16_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)ma); + *mb++=(double)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32_t* ma; + double* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + *mb++=(double)(*ma++); + } + } + break; + case TIFF_SLONG: + { + int32_t* ma; + double* mb; + uint32_t n; + ma=(int32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)ma); + *mb++=(double)(*ma++); + } + } + break; + case TIFF_LONG8: + { + uint64_t* ma; + double* mb; + uint32_t n; + ma=(uint64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8(ma); +#if defined(__WIN32__) && (_MSC_VER < 1500) + /* + * XXX: MSVC 6.0 does not support + * conversion of 64-bit integers into + * floating point values. + */ + *mb++ = _TIFFUInt64ToDouble(*ma++); +#else + *mb++ = (double)(*ma++); +#endif + } + } + break; + case TIFF_SLONG8: + { + int64_t* ma; + double* mb; + uint32_t n; + ma=(int64_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)ma); + *mb++=(double)(*ma++); + } + } + break; + case TIFF_RATIONAL: + { + uint32_t* ma; + uint32_t maa; + uint32_t mab; + double* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + maa=*ma++; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + mab=*ma++; + if (mab==0) + *mb++=0.0; + else + *mb++=(double)maa/(double)mab; + } + } + break; + case TIFF_SRATIONAL: + { + uint32_t* ma; + int32_t maa; + uint32_t mab; + double* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + maa=*(int32_t*)ma; + ma++; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + mab=*ma++; + if (mab==0) + *mb++=0.0; + else + *mb++=(double)maa/(double)mab; + } + } + break; + case TIFF_FLOAT: + { + float* ma; + double* mb; + uint32_t n; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32_t*)origdata, count); + TIFFCvtIEEEFloatToNative(tif,count,(float*)origdata); + ma=(float*)origdata; + mb=data; + for (n=0; ntdir_type) + { + case TIFF_LONG: + case TIFF_LONG8: + case TIFF_IFD: + case TIFF_IFD8: + break; + default: + return(TIFFReadDirEntryErrType); + } + err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata); + if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) + { + *value=0; + return(err); + } + switch (direntry->tdir_type) + { + case TIFF_LONG8: + case TIFF_IFD8: + *value=(uint64_t*)origdata; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8(*value,count); + return(TIFFReadDirEntryErrOk); + } + data=(uint64_t*)_TIFFmalloc(count * 8); + if (data==0) + { + _TIFFfree(origdata); + return(TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_LONG: + case TIFF_IFD: + { + uint32_t* ma; + uint64_t* mb; + uint32_t n; + ma=(uint32_t*)origdata; + mb=data; + for (n=0; ntif_flags&TIFF_SWAB) + TIFFSwabLong(ma); + *mb++=(uint64_t)(*ma++); + } + } + break; + } + _TIFFfree(origdata); + *value=data; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value) +{ + enum TIFFReadDirEntryErr err; + uint16_t* m; + uint16_t* na; + uint16_t nb; + if (direntry->tdir_count<(uint64_t)tif->tif_dir.td_samplesperpixel) + return(TIFFReadDirEntryErrCount); + err=TIFFReadDirEntryShortArray(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk || m == NULL) + return(err); + na=m; + nb=tif->tif_dir.td_samplesperpixel; + *value=*na++; + nb--; + while (nb>0) + { + if (*na++!=*value) + { + err=TIFFReadDirEntryErrPsdif; + break; + } + nb--; + } + _TIFFfree(m); + return(err); +} + +#if 0 +static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value) +{ + enum TIFFReadDirEntryErr err; + double* m; + double* na; + uint16_t nb; + if (direntry->tdir_count<(uint64_t)tif->tif_dir.td_samplesperpixel) + return(TIFFReadDirEntryErrCount); + err=TIFFReadDirEntryDoubleArray(tif,direntry,&m); + if (err!=TIFFReadDirEntryErrOk) + return(err); + na=m; + nb=tif->tif_dir.td_samplesperpixel; + *value=*na++; + nb--; + while (nb>0) + { + if (*na++!=*value) + { + err=TIFFReadDirEntryErrPsdif; + break; + } + nb--; + } + _TIFFfree(m); + return(err); +} +#endif + +static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8_t* value) +{ + (void) tif; + *value=*(uint8_t*)(&direntry->tdir_offset); +} + +static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8_t* value) +{ + (void) tif; + *value=*(int8_t*)(&direntry->tdir_offset); +} + +static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16_t* value) +{ + *value = direntry->tdir_offset.toff_short; + /* *value=*(uint16_t*)(&direntry->tdir_offset); */ + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort(value); +} + +static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16_t* value) +{ + *value=*(int16_t*)(&direntry->tdir_offset); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)value); +} + +static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32_t* value) +{ + *value=*(uint32_t*)(&direntry->tdir_offset); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(value); +} + +static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32_t* value) +{ + *value=*(int32_t*)(&direntry->tdir_offset); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)value); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64_t* value) +{ + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + enum TIFFReadDirEntryErr err; + uint32_t offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,value); + if (err!=TIFFReadDirEntryErrOk) + return(err); + } + else + *value = direntry->tdir_offset.toff_long8; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(value); + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64_t* value) +{ + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + enum TIFFReadDirEntryErr err; + uint32_t offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,value); + if (err!=TIFFReadDirEntryErrOk) + return(err); + } + else + *value=*(int64_t*)(&direntry->tdir_offset); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)value); + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value) +{ + UInt64Aligned_t m; + + assert(sizeof(double)==8); + assert(sizeof(uint64_t) == 8); + assert(sizeof(uint32_t) == 4); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + enum TIFFReadDirEntryErr err; + uint32_t offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,m.i); + if (err!=TIFFReadDirEntryErrOk) + return(err); + } + else + m.l = direntry->tdir_offset.toff_long8; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(m.i,2); + /* Not completely sure what we should do when m.i[1]==0, but some */ + /* sanitizers do not like division by 0.0: */ + /* http://bugzilla.maptools.org/show_bug.cgi?id=2644 */ + if (m.i[0]==0 || m.i[1]==0) + *value=0.0; + else + *value=(double)m.i[0]/(double)m.i[1]; + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSrational(TIFF* tif, TIFFDirEntry* direntry, double* value) +{ + UInt64Aligned_t m; + assert(sizeof(double)==8); + assert(sizeof(uint64_t) == 8); + assert(sizeof(int32_t) == 4); + assert(sizeof(uint32_t) == 4); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + enum TIFFReadDirEntryErr err; + uint32_t offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,m.i); + if (err!=TIFFReadDirEntryErrOk) + return(err); + } + else + m.l=direntry->tdir_offset.toff_long8; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(m.i,2); + /* Not completely sure what we should do when m.i[1]==0, but some */ + /* sanitizers do not like division by 0.0: */ + /* http://bugzilla.maptools.org/show_bug.cgi?id=2644 */ + if ((int32_t)m.i[0] == 0 || m.i[1] == 0) + *value=0.0; + else + *value= (double)((int32_t)m.i[0]) / (double)m.i[1]; + return(TIFFReadDirEntryErrOk); +} + +static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value) +{ + union + { + float f; + uint32_t i; + } float_union; + assert(sizeof(float)==4); + assert(sizeof(uint32_t) == 4); + assert(sizeof(float_union)==4); + float_union.i=*(uint32_t*)(&direntry->tdir_offset); + *value=float_union.f; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)value); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value) +{ + assert(sizeof(double)==8); + assert(sizeof(uint64_t) == 8); + assert(sizeof(UInt64Aligned_t)==8); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + enum TIFFReadDirEntryErr err; + uint32_t offset = direntry->tdir_offset.toff_long; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,value); + if (err!=TIFFReadDirEntryErrOk) + return(err); + } + else + { + UInt64Aligned_t uint64_union; + uint64_union.l=direntry->tdir_offset.toff_long8; + *value=uint64_union.d; + } + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)value); + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8_t value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16_t value) +{ + if (value>0xFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16_t value) +{ + if ((value<0)||(value>0xFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32_t value) +{ + if (value>0xFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32_t value) +{ + if ((value<0)||(value>0xFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64_t value) +{ + if (value>0xFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64_t value) +{ + if ((value<0)||(value>0xFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8_t value) +{ + if (value>0x7F) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16_t value) +{ + if (value>0x7F) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16_t value) +{ + if ((value<-0x80)||(value>0x7F)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32_t value) +{ + if (value>0x7F) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32_t value) +{ + if ((value<-0x80)||(value>0x7F)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64_t value) +{ + if (value>0x7F) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64_t value) +{ + if ((value<-0x80)||(value>0x7F)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8_t value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16_t value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32_t value) +{ + if (value>0xFFFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32_t value) +{ + if ((value<0)||(value>0xFFFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64_t value) +{ + if (value>0xFFFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64_t value) +{ + if ((value<0)||(value>0xFFFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16_t value) +{ + if (value>0x7FFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32_t value) +{ + if (value>0x7FFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32_t value) +{ + if ((value<-0x8000)||(value>0x7FFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64_t value) +{ + if (value>0x7FFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64_t value) +{ + if ((value<-0x8000)||(value>0x7FFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8_t value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16_t value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32_t value) +{ + if (value<0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLongLong8(uint64_t value) +{ + if (value > UINT32_MAX) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLongSlong8(int64_t value) +{ + if ((value < 0) || (value > (int64_t) UINT32_MAX)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlongLong(uint32_t value) +{ + if (value > 0x7FFFFFFFUL) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +/* Check that the 8-byte unsigned value can fit in a 4-byte unsigned range */ +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlongLong8(uint64_t value) +{ + if (value > 0x7FFFFFFF) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +/* Check that the 8-byte signed value can fit in a 4-byte signed range */ +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlongSlong8(int64_t value) +{ + if ((value < 0-((int64_t) 0x7FFFFFFF + 1)) || (value > 0x7FFFFFFF)) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLong8Sbyte(int8_t value) +{ + if (value < 0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLong8Sshort(int16_t value) +{ + if (value < 0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLong8Slong(int32_t value) +{ + if (value < 0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeLong8Slong8(int64_t value) +{ + if (value < 0) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlong8Long8(uint64_t value) +{ + if (value > INT64_MAX) + return(TIFFReadDirEntryErrRange); + else + return(TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryData(TIFF* tif, uint64_t offset, tmsize_t size, void* dest) +{ + assert(size>0); + if (!isMapped(tif)) { + if (!SeekOK(tif,offset)) + return(TIFFReadDirEntryErrIo); + if (!ReadOK(tif,dest,size)) + return(TIFFReadDirEntryErrIo); + } else { + size_t ma,mb; + ma=(size_t)offset; + if((uint64_t)ma != offset || + ma > (~(size_t)0) - (size_t)size ) + { + return TIFFReadDirEntryErrIo; + } + mb=ma+size; + if (mb > (uint64_t)tif->tif_size) + return(TIFFReadDirEntryErrIo); + _TIFFmemcpy(dest,tif->tif_base+ma,size); + } + return(TIFFReadDirEntryErrOk); +} + +static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, const char* module, const char* tagname, int recover) +{ + if (!recover) { + switch (err) { + case TIFFReadDirEntryErrCount: + TIFFErrorExt(tif->tif_clientdata, module, + "Incorrect count for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrType: + TIFFErrorExt(tif->tif_clientdata, module, + "Incompatible type for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrIo: + TIFFErrorExt(tif->tif_clientdata, module, + "IO error during reading of \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrRange: + TIFFErrorExt(tif->tif_clientdata, module, + "Incorrect value for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrPsdif: + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot handle different values per sample for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrSizesan: + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on size of \"%s\" value failed", + tagname); + break; + case TIFFReadDirEntryErrAlloc: + TIFFErrorExt(tif->tif_clientdata, module, + "Out of memory reading of \"%s\"", + tagname); + break; + default: + assert(0); /* we should never get here */ + break; + } + } else { + switch (err) { + case TIFFReadDirEntryErrCount: + TIFFWarningExt(tif->tif_clientdata, module, + "Incorrect count for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrType: + TIFFWarningExt(tif->tif_clientdata, module, + "Incompatible type for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrIo: + TIFFWarningExt(tif->tif_clientdata, module, + "IO error during reading of \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrRange: + TIFFWarningExt(tif->tif_clientdata, module, + "Incorrect value for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrPsdif: + TIFFWarningExt(tif->tif_clientdata, module, + "Cannot handle different values per sample for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrSizesan: + TIFFWarningExt(tif->tif_clientdata, module, + "Sanity check on size of \"%s\" value failed; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrAlloc: + TIFFWarningExt(tif->tif_clientdata, module, + "Out of memory reading of \"%s\"; tag ignored", + tagname); + break; + default: + assert(0); /* we should never get here */ + break; + } + } +} + +/* + * Return the maximum number of color channels specified for a given photometric + * type. 0 is returned if photometric type isn't supported or no default value + * is defined by the specification. + */ +static int _TIFFGetMaxColorChannels(uint16_t photometric ) +{ + switch (photometric) { + case PHOTOMETRIC_PALETTE: + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + return 1; + case PHOTOMETRIC_YCBCR: + case PHOTOMETRIC_RGB: + case PHOTOMETRIC_CIELAB: + case PHOTOMETRIC_LOGLUV: + case PHOTOMETRIC_ITULAB: + case PHOTOMETRIC_ICCLAB: + return 3; + case PHOTOMETRIC_SEPARATED: + case PHOTOMETRIC_MASK: + return 4; + case PHOTOMETRIC_LOGL: + case PHOTOMETRIC_CFA: + default: + return 0; + } +} + +static int ByteCountLooksBad(TIFF* tif) +{ + /* + * Assume we have wrong StripByteCount value (in case + * of single strip) in following cases: + * - it is equal to zero along with StripOffset; + * - it is larger than file itself (in case of uncompressed + * image); + * - it is smaller than the size of the bytes per row + * multiplied on the number of rows. The last case should + * not be checked in the case of writing new image, + * because we may do not know the exact strip size + * until the whole image will be written and directory + * dumped out. + */ + uint64_t bytecount = TIFFGetStrileByteCount(tif, 0); + uint64_t offset = TIFFGetStrileOffset(tif, 0); + uint64_t filesize; + + if( offset == 0 ) + return 0; + if (bytecount == 0) + return 1; + if ( tif->tif_dir.td_compression != COMPRESSION_NONE ) + return 0; + filesize = TIFFGetFileSize(tif); + if( offset <= filesize && bytecount > filesize - offset ) + return 1; + if( tif->tif_mode == O_RDONLY ) + { + uint64_t scanlinesize = TIFFScanlineSize64(tif); + if( tif->tif_dir.td_imagelength > 0 && + scanlinesize > UINT64_MAX / tif->tif_dir.td_imagelength ) + { + return 1; + } + if( bytecount < scanlinesize * tif->tif_dir.td_imagelength) + return 1; + } + return 0; +} + + +/* + * Read the next TIFF directory from a file and convert it to the internal + * format. We read directories sequentially. + */ +int +TIFFReadDirectory(TIFF* tif) +{ + static const char module[] = "TIFFReadDirectory"; + TIFFDirEntry* dir; + uint16_t dircount; + TIFFDirEntry* dp; + uint16_t di; + const TIFFField* fip; + uint32_t fii=FAILED_FII; + toff_t nextdiroff; + int bitspersample_read = FALSE; + int color_channels; + + tif->tif_diroff=tif->tif_nextdiroff; + if (!TIFFCheckDirOffset(tif,tif->tif_nextdiroff)) + return 0; /* last offset or bad offset (IFD looping) */ + (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ + tif->tif_curdir++; + nextdiroff = tif->tif_nextdiroff; + dircount=TIFFFetchDirectory(tif,nextdiroff,&dir,&tif->tif_nextdiroff); + if (!dircount) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Failed to read directory at offset %" PRIu64, nextdiroff); + return 0; + } + TIFFReadDirectoryCheckOrder(tif,dir,dircount); + + /* + * Mark duplicates of any tag to be ignored (bugzilla 1994) + * to avoid certain pathological problems. + */ + { + TIFFDirEntry* ma; + uint16_t mb; + for (ma=dir, mb=0; mbtdir_tag == na->tdir_tag) { + na->tdir_ignore = TRUE; + } + } + } + } + + tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ + tif->tif_flags &= ~TIFF_BUF4WRITE; /* reset before new dir */ + tif->tif_flags &= ~TIFF_CHOPPEDUPARRAYS; + + /* free any old stuff and reinit */ + TIFFFreeDirectory(tif); + TIFFDefaultDirectory(tif); + /* + * Electronic Arts writes gray-scale TIFF files + * without a PlanarConfiguration directory entry. + * Thus we setup a default value here, even though + * the TIFF spec says there is no default value. + */ + TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG); + /* + * Setup default value and then make a pass over + * the fields to check type and tag information, + * and to extract info required to size data + * structures. A second pass is made afterwards + * to read in everything not taken in the first pass. + * But we must process the Compression tag first + * in order to merge in codec-private tag definitions (otherwise + * we may get complaints about unknown tags). However, the + * Compression tag may be dependent on the SamplesPerPixel + * tag value because older TIFF specs permitted Compression + * to be written as a SamplesPerPixel-count tag entry. + * Thus if we don't first figure out the correct SamplesPerPixel + * tag value then we may end up ignoring the Compression tag + * value because it has an incorrect count value (if the + * true value of SamplesPerPixel is not 1). + */ + dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_SAMPLESPERPIXEL); + if (dp) + { + if (!TIFFFetchNormalTag(tif,dp,0)) + goto bad; + dp->tdir_ignore = TRUE; + } + dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_COMPRESSION); + if (dp) + { + /* + * The 5.0 spec says the Compression tag has one value, while + * earlier specs say it has one value per sample. Because of + * this, we accept the tag if one value is supplied with either + * count. + */ + uint16_t value; + enum TIFFReadDirEntryErr err; + err=TIFFReadDirEntryShort(tif,dp,&value); + if (err==TIFFReadDirEntryErrCount) + err=TIFFReadDirEntryPersampleShort(tif,dp,&value); + if (err!=TIFFReadDirEntryErrOk) + { + TIFFReadDirEntryOutputErr(tif,err,module,"Compression",0); + goto bad; + } + if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,value)) + goto bad; + dp->tdir_ignore = TRUE; + } + else + { + if (!TIFFSetField(tif,TIFFTAG_COMPRESSION,COMPRESSION_NONE)) + goto bad; + } + /* + * First real pass over the directory. + */ + for (di=0, dp=dir; ditdir_ignore) + { + TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); + if (fii == FAILED_FII) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Unknown field with tag %"PRIu16" (0x%"PRIx16") encountered", + dp->tdir_tag,dp->tdir_tag); + /* the following knowingly leaks the + anonymous field structure */ + if (!_TIFFMergeFields(tif, + _TIFFCreateAnonField(tif, + dp->tdir_tag, + (TIFFDataType) dp->tdir_type), + 1)) { + TIFFWarningExt(tif->tif_clientdata, + module, + "Registering anonymous field with tag %"PRIu16" (0x%"PRIx16") failed", + dp->tdir_tag, + dp->tdir_tag); + dp->tdir_ignore = TRUE; + } else { + TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); + assert(fii != FAILED_FII); + } + } + } + if (!dp->tdir_ignore) + { + fip=tif->tif_fields[fii]; + if (fip->field_bit==FIELD_IGNORE) + dp->tdir_ignore = TRUE; + else + { + switch (dp->tdir_tag) + { + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEOFFSETS: + case TIFFTAG_TILEBYTECOUNTS: + TIFFSetFieldBit(tif,fip->field_bit); + break; + case TIFFTAG_IMAGEWIDTH: + case TIFFTAG_IMAGELENGTH: + case TIFFTAG_IMAGEDEPTH: + case TIFFTAG_TILELENGTH: + case TIFFTAG_TILEWIDTH: + case TIFFTAG_TILEDEPTH: + case TIFFTAG_PLANARCONFIG: + case TIFFTAG_ROWSPERSTRIP: + case TIFFTAG_EXTRASAMPLES: + if (!TIFFFetchNormalTag(tif,dp,0)) + goto bad; + dp->tdir_ignore = TRUE; + break; + default: + if( !_TIFFCheckFieldIsValidForCodec(tif, dp->tdir_tag) ) + dp->tdir_ignore = TRUE; + break; + } + } + } + } + /* + * XXX: OJPEG hack. + * If a) compression is OJPEG, b) planarconfig tag says it's separate, + * c) strip offsets/bytecounts tag are both present and + * d) both contain exactly one value, then we consistently find + * that the buggy implementation of the buggy compression scheme + * matches contig planarconfig best. So we 'fix-up' the tag here + */ + if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG)&& + (tif->tif_dir.td_planarconfig==PLANARCONFIG_SEPARATE)) + { + if (!_TIFFFillStriles(tif)) + goto bad; + dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_STRIPOFFSETS); + if ((dp!=0)&&(dp->tdir_count==1)) + { + dp=TIFFReadDirectoryFindEntry(tif,dir,dircount, + TIFFTAG_STRIPBYTECOUNTS); + if ((dp!=0)&&(dp->tdir_count==1)) + { + tif->tif_dir.td_planarconfig=PLANARCONFIG_CONTIG; + TIFFWarningExt(tif->tif_clientdata,module, + "Planarconfig tag value assumed incorrect, " + "assuming data is contig instead of chunky"); + } + } + } + /* + * Allocate directory structure and setup defaults. + */ + if (!TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) + { + MissingRequired(tif,"ImageLength"); + goto bad; + } + /* + * Setup appropriate structures (by strip or by tile) + */ + if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { + tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif); + tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth; + tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip; + tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth; + tif->tif_flags &= ~TIFF_ISTILED; + } else { + tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif); + tif->tif_flags |= TIFF_ISTILED; + } + if (!tif->tif_dir.td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot handle zero number of %s", + isTiled(tif) ? "tiles" : "strips"); + goto bad; + } + tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips; + if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE) + tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel; + if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) { +#ifdef OJPEG_SUPPORT + if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) && + (isTiled(tif)==0) && + (tif->tif_dir.td_nstrips==1)) { + /* + * XXX: OJPEG hack. + * If a) compression is OJPEG, b) it's not a tiled TIFF, + * and c) the number of strips is 1, + * then we tolerate the absence of stripoffsets tag, + * because, presumably, all required data is in the + * JpegInterchangeFormat stream. + */ + TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); + } else +#endif + { + MissingRequired(tif, + isTiled(tif) ? "TileOffsets" : "StripOffsets"); + goto bad; + } + } + /* + * Second pass: extract other information. + */ + for (di=0, dp=dir; ditdir_ignore) { + switch (dp->tdir_tag) + { + case TIFFTAG_MINSAMPLEVALUE: + case TIFFTAG_MAXSAMPLEVALUE: + case TIFFTAG_BITSPERSAMPLE: + case TIFFTAG_DATATYPE: + case TIFFTAG_SAMPLEFORMAT: + /* + * The MinSampleValue, MaxSampleValue, BitsPerSample + * DataType and SampleFormat tags are supposed to be + * written as one value/sample, but some vendors + * incorrectly write one value only -- so we accept + * that as well (yuck). Other vendors write correct + * value for NumberOfSamples, but incorrect one for + * BitsPerSample and friends, and we will read this + * too. + */ + { + uint16_t value; + enum TIFFReadDirEntryErr err; + err=TIFFReadDirEntryShort(tif,dp,&value); + if (err==TIFFReadDirEntryErrCount) + err=TIFFReadDirEntryPersampleShort(tif,dp,&value); + if (err!=TIFFReadDirEntryErrOk) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0); + goto bad; + } + if (!TIFFSetField(tif,dp->tdir_tag,value)) + goto bad; + if( dp->tdir_tag == TIFFTAG_BITSPERSAMPLE ) + bitspersample_read = TRUE; + } + break; + case TIFFTAG_SMINSAMPLEVALUE: + case TIFFTAG_SMAXSAMPLEVALUE: + { + + double *data = NULL; + enum TIFFReadDirEntryErr err; + uint32_t saved_flags; + int m; + if (dp->tdir_count != (uint64_t)tif->tif_dir.td_samplesperpixel) + err = TIFFReadDirEntryErrCount; + else + err = TIFFReadDirEntryDoubleArray(tif, dp, &data); + if (err!=TIFFReadDirEntryErrOk) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0); + goto bad; + } + saved_flags = tif->tif_flags; + tif->tif_flags |= TIFF_PERSAMPLE; + m = TIFFSetField(tif,dp->tdir_tag,data); + tif->tif_flags = saved_flags; + _TIFFfree(data); + if (!m) + goto bad; + } + break; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_TILEOFFSETS: + switch( dp->tdir_type ) + { + case TIFF_SHORT: + case TIFF_LONG: + case TIFF_LONG8: + break; + default: + /* Warn except if directory typically created with TIFFDeferStrileArrayWriting() */ + if( !(tif->tif_mode == O_RDWR && + dp->tdir_count == 0 && + dp->tdir_type == 0 && + dp->tdir_offset.toff_long8 == 0) ) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFWarningExt(tif->tif_clientdata,module, + "Invalid data type for tag %s", + fip ? fip->field_name : "unknown tagname"); + } + break; + } + _TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry), + dp, sizeof(TIFFDirEntry) ); + break; + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEBYTECOUNTS: + switch( dp->tdir_type ) + { + case TIFF_SHORT: + case TIFF_LONG: + case TIFF_LONG8: + break; + default: + /* Warn except if directory typically created with TIFFDeferStrileArrayWriting() */ + if( !(tif->tif_mode == O_RDWR && + dp->tdir_count == 0 && + dp->tdir_type == 0 && + dp->tdir_offset.toff_long8 == 0) ) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFWarningExt(tif->tif_clientdata,module, + "Invalid data type for tag %s", + fip ? fip->field_name : "unknown tagname"); + } + break; + } + _TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry), + dp, sizeof(TIFFDirEntry) ); + break; + case TIFFTAG_COLORMAP: + case TIFFTAG_TRANSFERFUNCTION: + { + enum TIFFReadDirEntryErr err; + uint32_t countpersample; + uint32_t countrequired; + uint32_t incrementpersample; + uint16_t* value=NULL; + /* It would be dangerous to instantiate those tag values */ + /* since if td_bitspersample has not yet been read (due to */ + /* unordered tags), it could be read afterwards with a */ + /* values greater than the default one (1), which may cause */ + /* crashes in user code */ + if( !bitspersample_read ) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFWarningExt(tif->tif_clientdata,module, + "Ignoring %s since BitsPerSample tag not found", + fip ? fip->field_name : "unknown tagname"); + continue; + } + /* ColorMap or TransferFunction for high bit */ + /* depths do not make much sense and could be */ + /* used as a denial of service vector */ + if (tif->tif_dir.td_bitspersample > 24) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFWarningExt(tif->tif_clientdata,module, + "Ignoring %s because BitsPerSample=%"PRIu16">24", + fip ? fip->field_name : "unknown tagname", + tif->tif_dir.td_bitspersample); + continue; + } + countpersample=(1U<tif_dir.td_bitspersample); + if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64_t)countpersample)) + { + countrequired=countpersample; + incrementpersample=0; + } + else + { + countrequired=3*countpersample; + incrementpersample=countpersample; + } + if (dp->tdir_count!=(uint64_t)countrequired) + err=TIFFReadDirEntryErrCount; + else + err=TIFFReadDirEntryShortArray(tif,dp,&value); + if (err!=TIFFReadDirEntryErrOk) + { + fip = TIFFFieldWithTag(tif,dp->tdir_tag); + TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",1); + } + else + { + TIFFSetField(tif,dp->tdir_tag,value,value+incrementpersample,value+2*incrementpersample); + _TIFFfree(value); + } + } + break; +/* BEGIN REV 4.0 COMPATIBILITY */ + case TIFFTAG_OSUBFILETYPE: + { + uint16_t valueo; + uint32_t value; + if (TIFFReadDirEntryShort(tif,dp,&valueo)==TIFFReadDirEntryErrOk) + { + switch (valueo) + { + case OFILETYPE_REDUCEDIMAGE: value=FILETYPE_REDUCEDIMAGE; break; + case OFILETYPE_PAGE: value=FILETYPE_PAGE; break; + default: value=0; break; + } + if (value!=0) + TIFFSetField(tif,TIFFTAG_SUBFILETYPE,value); + } + } + break; +/* END REV 4.0 COMPATIBILITY */ + default: + (void) TIFFFetchNormalTag(tif, dp, TRUE); + break; + } + } /* -- if (!dp->tdir_ignore) */ + } /* -- for-loop -- */ + + if( tif->tif_mode == O_RDWR && + tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 && + tif->tif_dir.td_stripoffset_entry.tdir_count == 0 && + tif->tif_dir.td_stripoffset_entry.tdir_type == 0 && + tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 ) + { + /* Directory typically created with TIFFDeferStrileArrayWriting() */ + TIFFSetupStrips(tif); + } + else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) ) + { + if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 ) + { + if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry), + tif->tif_dir.td_nstrips, + &tif->tif_dir.td_stripoffset_p)) + { + goto bad; + } + } + if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 ) + { + if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry), + tif->tif_dir.td_nstrips, + &tif->tif_dir.td_stripbytecount_p)) + { + goto bad; + } + } + } + + /* + * OJPEG hack: + * - If a) compression is OJPEG, and b) photometric tag is missing, + * then we consistently find that photometric should be YCbCr + * - If a) compression is OJPEG, and b) photometric tag says it's RGB, + * then we consistently find that the buggy implementation of the + * buggy compression scheme matches photometric YCbCr instead. + * - If a) compression is OJPEG, and b) bitspersample tag is missing, + * then we consistently find bitspersample should be 8. + * - If a) compression is OJPEG, b) samplesperpixel tag is missing, + * and c) photometric is RGB or YCbCr, then we consistently find + * samplesperpixel should be 3 + * - If a) compression is OJPEG, b) samplesperpixel tag is missing, + * and c) photometric is MINISWHITE or MINISBLACK, then we consistently + * find samplesperpixel should be 3 + */ + if (tif->tif_dir.td_compression==COMPRESSION_OJPEG) + { + if (!TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Photometric tag is missing, assuming data is YCbCr"); + if (!TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_YCBCR)) + goto bad; + } + else if (tif->tif_dir.td_photometric==PHOTOMETRIC_RGB) + { + tif->tif_dir.td_photometric=PHOTOMETRIC_YCBCR; + TIFFWarningExt(tif->tif_clientdata, module, + "Photometric tag value assumed incorrect, " + "assuming data is YCbCr instead of RGB"); + } + if (!TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) + { + TIFFWarningExt(tif->tif_clientdata,module, + "BitsPerSample tag is missing, assuming 8 bits per sample"); + if (!TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,8)) + goto bad; + } + if (!TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) + { + if (tif->tif_dir.td_photometric==PHOTOMETRIC_RGB) + { + TIFFWarningExt(tif->tif_clientdata,module, + "SamplesPerPixel tag is missing, " + "assuming correct SamplesPerPixel value is 3"); + if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3)) + goto bad; + } + if (tif->tif_dir.td_photometric==PHOTOMETRIC_YCBCR) + { + TIFFWarningExt(tif->tif_clientdata,module, + "SamplesPerPixel tag is missing, " + "applying correct SamplesPerPixel value of 3"); + if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3)) + goto bad; + } + else if ((tif->tif_dir.td_photometric==PHOTOMETRIC_MINISWHITE) + || (tif->tif_dir.td_photometric==PHOTOMETRIC_MINISBLACK)) + { + /* + * SamplesPerPixel tag is missing, but is not required + * by spec. Assume correct SamplesPerPixel value of 1. + */ + if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,1)) + goto bad; + } + } + } + + /* + * Make sure all non-color channels are extrasamples. + * If it's not the case, define them as such. + */ + color_channels = _TIFFGetMaxColorChannels(tif->tif_dir.td_photometric); + if (color_channels && tif->tif_dir.td_samplesperpixel - tif->tif_dir.td_extrasamples > color_channels) { + uint16_t old_extrasamples; + uint16_t *new_sampleinfo; + + TIFFWarningExt(tif->tif_clientdata,module, "Sum of Photometric type-related " + "color channels and ExtraSamples doesn't match SamplesPerPixel. " + "Defining non-color channels as ExtraSamples."); + + old_extrasamples = tif->tif_dir.td_extrasamples; + tif->tif_dir.td_extrasamples = (uint16_t) (tif->tif_dir.td_samplesperpixel - color_channels); + + // sampleinfo should contain information relative to these new extra samples + new_sampleinfo = (uint16_t*) _TIFFcalloc(tif->tif_dir.td_extrasamples, sizeof(uint16_t)); + if (!new_sampleinfo) { + TIFFErrorExt(tif->tif_clientdata, module, "Failed to allocate memory for " + "temporary new sampleinfo array " + "(%"PRIu16" 16 bit elements)", + tif->tif_dir.td_extrasamples); + goto bad; + } + + memcpy(new_sampleinfo, tif->tif_dir.td_sampleinfo, old_extrasamples * sizeof(uint16_t)); + _TIFFsetShortArray(&tif->tif_dir.td_sampleinfo, new_sampleinfo, tif->tif_dir.td_extrasamples); + _TIFFfree(new_sampleinfo); + } + + /* + * Verify Palette image has a Colormap. + */ + if (tif->tif_dir.td_photometric == PHOTOMETRIC_PALETTE && + !TIFFFieldSet(tif, FIELD_COLORMAP)) { + if ( tif->tif_dir.td_bitspersample>=8 && tif->tif_dir.td_samplesperpixel==3) + tif->tif_dir.td_photometric = PHOTOMETRIC_RGB; + else if (tif->tif_dir.td_bitspersample>=8) + tif->tif_dir.td_photometric = PHOTOMETRIC_MINISBLACK; + else { + MissingRequired(tif, "Colormap"); + goto bad; + } + } + /* + * OJPEG hack: + * We do no further messing with strip/tile offsets/bytecounts in OJPEG + * TIFFs + */ + if (tif->tif_dir.td_compression!=COMPRESSION_OJPEG) + { + /* + * Attempt to deal with a missing StripByteCounts tag. + */ + if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) { + /* + * Some manufacturers violate the spec by not giving + * the size of the strips. In this case, assume there + * is one uncompressed strip of data. + */ + if ((tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG && + tif->tif_dir.td_nstrips > 1) || + (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE && + tif->tif_dir.td_nstrips != (uint32_t)tif->tif_dir.td_samplesperpixel)) { + MissingRequired(tif, "StripByteCounts"); + goto bad; + } + TIFFWarningExt(tif->tif_clientdata, module, + "TIFF directory is missing required " + "\"StripByteCounts\" field, calculating from imagelength"); + if (EstimateStripByteCounts(tif, dir, dircount) < 0) + goto bad; + + } else if (tif->tif_dir.td_nstrips == 1 + && !(tif->tif_flags&TIFF_ISTILED) + && ByteCountLooksBad(tif)) { + /* + * XXX: Plexus (and others) sometimes give a value of + * zero for a tag when they don't know what the + * correct value is! Try and handle the simple case + * of estimating the size of a one strip image. + */ + TIFFWarningExt(tif->tif_clientdata, module, + "Bogus \"StripByteCounts\" field, ignoring and calculating from imagelength"); + if(EstimateStripByteCounts(tif, dir, dircount) < 0) + goto bad; + + } else if (!(tif->tif_flags&TIFF_DEFERSTRILELOAD) + && tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG + && tif->tif_dir.td_nstrips > 2 + && tif->tif_dir.td_compression == COMPRESSION_NONE + && TIFFGetStrileByteCount(tif, 0) != TIFFGetStrileByteCount(tif, 1) + && TIFFGetStrileByteCount(tif, 0) != 0 + && TIFFGetStrileByteCount(tif, 1) != 0 ) { + /* + * XXX: Some vendors fill StripByteCount array with + * absolutely wrong values (it can be equal to + * StripOffset array, for example). Catch this case + * here. + * + * We avoid this check if deferring strile loading + * as it would always force us to load the strip/tile + * information. + */ + TIFFWarningExt(tif->tif_clientdata, module, + "Wrong \"StripByteCounts\" field, ignoring and calculating from imagelength"); + if (EstimateStripByteCounts(tif, dir, dircount) < 0) + goto bad; + } + } + if (dir) + { + _TIFFfree(dir); + dir=NULL; + } + if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE)) + { + if (tif->tif_dir.td_bitspersample>=16) + tif->tif_dir.td_maxsamplevalue=0xFFFF; + else + tif->tif_dir.td_maxsamplevalue = (uint16_t)((1L << tif->tif_dir.td_bitspersample) - 1); + } + +#ifdef STRIPBYTECOUNTSORTED_UNUSED + /* + * XXX: We can optimize checking for the strip bounds using the sorted + * bytecounts array. See also comments for TIFFAppendToStrip() + * function in tif_write.c. + */ + if (!(tif->tif_flags&TIFF_DEFERSTRILELOAD) && tif->tif_dir.td_nstrips > 1) { + uint32_t strip; + + tif->tif_dir.td_stripbytecountsorted = 1; + for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) { + if (TIFFGetStrileOffset(tif, strip - 1) > + TIFFGetStrileOffset(tif, strip)) { + tif->tif_dir.td_stripbytecountsorted = 0; + break; + } + } + } +#endif + + /* + * An opportunity for compression mode dependent tag fixup + */ + (*tif->tif_fixuptags)(tif); + + /* + * Some manufacturers make life difficult by writing + * large amounts of uncompressed data as a single strip. + * This is contrary to the recommendations of the spec. + * The following makes an attempt at breaking such images + * into strips closer to the recommended 8k bytes. A + * side effect, however, is that the RowsPerStrip tag + * value may be changed. + */ + if ((tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)&& + (tif->tif_dir.td_nstrips==1)&& + (tif->tif_dir.td_compression==COMPRESSION_NONE)&& + ((tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED))==TIFF_STRIPCHOP)) + { + ChopUpSingleUncompressedStrip(tif); + } + + /* There are also uncompressed striped files with strips larger than */ + /* 2 GB, which make them unfriendly with a lot of code. If possible, */ + /* try to expose smaller "virtual" strips. */ + if( tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG && + tif->tif_dir.td_compression == COMPRESSION_NONE && + (tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP && + TIFFStripSize64(tif) > 0x7FFFFFFFUL ) + { + TryChopUpUncompressedBigTiff(tif); + } + + /* + * Clear the dirty directory flag. + */ + tif->tif_flags &= ~TIFF_DIRTYDIRECT; + tif->tif_flags &= ~TIFF_DIRTYSTRIP; + + /* + * Reinitialize i/o since we are starting on a new directory. + */ + tif->tif_row = (uint32_t) -1; + tif->tif_curstrip = (uint32_t) -1; + tif->tif_col = (uint32_t) -1; + tif->tif_curtile = (uint32_t) -1; + tif->tif_tilesize = (tmsize_t) -1; + + tif->tif_scanlinesize = TIFFScanlineSize(tif); + if (!tif->tif_scanlinesize) { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot handle zero scanline size"); + return (0); + } + + if (isTiled(tif)) { + tif->tif_tilesize = TIFFTileSize(tif); + if (!tif->tif_tilesize) { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot handle zero tile size"); + return (0); + } + } else { + if (!TIFFStripSize(tif)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot handle zero strip size"); + return (0); + } + } + return (1); +bad: + if (dir) + _TIFFfree(dir); + return (0); +} + +static void +TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount) +{ + static const char module[] = "TIFFReadDirectoryCheckOrder"; + uint16_t m; + uint16_t n; + TIFFDirEntry* o; + m=0; + for (n=0, o=dir; ntdir_tagtif_clientdata,module, + "Invalid TIFF directory; tags are not sorted in ascending order"); + break; + } + m=o->tdir_tag+1; + } +} + +static TIFFDirEntry* +TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount, uint16_t tagid) +{ + TIFFDirEntry* m; + uint16_t n; + (void) tif; + for (m=dir, n=0; ntdir_tag==tagid) + return(m); + } + return(0); +} + +static void +TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16_t tagid, uint32_t* fii) +{ + int32_t ma,mb,mc; + ma=-1; + mc=(int32_t)tif->tif_nfields; + while (1) + { + if (ma+1==mc) + { + *fii = FAILED_FII; + return; + } + mb=(ma+mc)/2; + if (tif->tif_fields[mb]->field_tag==(uint32_t)tagid) + break; + if (tif->tif_fields[mb]->field_tag<(uint32_t)tagid) + ma=mb; + else + mc=mb; + } + while (1) + { + if (mb==0) + break; + if (tif->tif_fields[mb-1]->field_tag!=(uint32_t)tagid) + break; + mb--; + } + *fii=mb; +} + +/* + * Read custom directory from the arbitrary offset. + * The code is very similar to TIFFReadDirectory(). + */ +int +TIFFReadCustomDirectory(TIFF* tif, toff_t diroff, + const TIFFFieldArray* infoarray) +{ + static const char module[] = "TIFFReadCustomDirectory"; + TIFFDirEntry* dir; + uint16_t dircount; + TIFFDirEntry* dp; + uint16_t di; + const TIFFField* fip; + uint32_t fii; + (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ + _TIFFSetupFields(tif, infoarray); + dircount=TIFFFetchDirectory(tif,diroff,&dir,NULL); + if (!dircount) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Failed to read custom directory at offset %" PRIu64,diroff); + return 0; + } + TIFFFreeDirectory(tif); + _TIFFmemset(&tif->tif_dir, 0, sizeof(TIFFDirectory)); + TIFFReadDirectoryCheckOrder(tif,dir,dircount); + for (di=0, dp=dir; ditdir_tag,&fii); + if (fii == FAILED_FII) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Unknown field with tag %"PRIu16" (0x%"PRIx16") encountered", + dp->tdir_tag, dp->tdir_tag); + if (!_TIFFMergeFields(tif, _TIFFCreateAnonField(tif, + dp->tdir_tag, + (TIFFDataType) dp->tdir_type), + 1)) { + TIFFWarningExt(tif->tif_clientdata, module, + "Registering anonymous field with tag %"PRIu16" (0x%"PRIx16") failed", + dp->tdir_tag, dp->tdir_tag); + dp->tdir_ignore = TRUE; + } else { + TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); + assert( fii != FAILED_FII ); + } + } + if (!dp->tdir_ignore) + { + fip=tif->tif_fields[fii]; + if (fip->field_bit==FIELD_IGNORE) + dp->tdir_ignore = TRUE; + else + { + /* check data type */ + while ((fip->field_type!=TIFF_ANY)&&(fip->field_type!=dp->tdir_type)) + { + fii++; + if ((fii==tif->tif_nfields)|| + (tif->tif_fields[fii]->field_tag!=(uint32_t)dp->tdir_tag)) + { + fii=0xFFFF; + break; + } + fip=tif->tif_fields[fii]; + } + if (fii==0xFFFF) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Wrong data type %"PRIu16" for \"%s\"; tag ignored", + dp->tdir_type,fip->field_name); + dp->tdir_ignore = TRUE; + } + else + { + /* check count if known in advance */ + if ((fip->field_readcount!=TIFF_VARIABLE)&& + (fip->field_readcount!=TIFF_VARIABLE2)) + { + uint32_t expected; + if (fip->field_readcount==TIFF_SPP) + expected=(uint32_t)tif->tif_dir.td_samplesperpixel; + else + expected=(uint32_t)fip->field_readcount; + if (!CheckDirCount(tif,dp,expected)) + dp->tdir_ignore = TRUE; + } + } + } + if (!dp->tdir_ignore) { + switch (dp->tdir_tag) + { + case EXIFTAG_SUBJECTDISTANCE: + (void)TIFFFetchSubjectDistance(tif, dp); + break; + default: + (void)TIFFFetchNormalTag(tif, dp, TRUE); + break; + } + } /*-- if (!dp->tdir_ignore) */ + } + } + if (dir) + _TIFFfree(dir); + return 1; +} + +/* + * EXIF is important special case of custom IFD, so we have a special + * function to read it. + */ +int +TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff) +{ + const TIFFFieldArray* exifFieldArray; + exifFieldArray = _TIFFGetExifFields(); + return TIFFReadCustomDirectory(tif, diroff, exifFieldArray); +} + +/* + *--: EXIF-GPS custom directory reading as another special case of custom IFD. + */ +int +TIFFReadGPSDirectory(TIFF* tif, toff_t diroff) +{ + const TIFFFieldArray* gpsFieldArray; + gpsFieldArray = _TIFFGetGpsFields(); + return TIFFReadCustomDirectory(tif, diroff, gpsFieldArray); +} + +static int +EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount) +{ + static const char module[] = "EstimateStripByteCounts"; + + TIFFDirEntry *dp; + TIFFDirectory *td = &tif->tif_dir; + uint32_t strip; + + /* Do not try to load stripbytecount as we will compute it */ + if( !_TIFFFillStrilesInternal( tif, 0 ) ) + return -1; + + if (td->td_stripbytecount_p) + _TIFFfree(td->td_stripbytecount_p); + td->td_stripbytecount_p = (uint64_t*) + _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64_t), + "for \"StripByteCounts\" array"); + if( td->td_stripbytecount_p == NULL ) + return -1; + + if (td->td_compression != COMPRESSION_NONE) { + uint64_t space; + uint64_t filesize; + uint16_t n; + filesize = TIFFGetFileSize(tif); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + space=sizeof(TIFFHeaderClassic)+2+dircount*12+4; + else + space=sizeof(TIFFHeaderBig)+8+dircount*20+8; + /* calculate amount of space used by indirect values */ + for (dp = dir, n = dircount; n > 0; n--, dp++) + { + uint32_t typewidth; + uint64_t datasize; + typewidth = TIFFDataWidth((TIFFDataType) dp->tdir_type); + if (typewidth == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot determine size of unknown tag type %"PRIu16, + dp->tdir_type); + return -1; + } + if( dp->tdir_count > UINT64_MAX / typewidth ) + return -1; + datasize= (uint64_t)typewidth * dp->tdir_count; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (datasize<=4) + datasize=0; + } + else + { + if (datasize<=8) + datasize=0; + } + if( space > UINT64_MAX - datasize ) + return -1; + space+=datasize; + } + if( filesize < space ) + /* we should perhaps return in error ? */ + space = filesize; + else + space = filesize - space; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + space /= td->td_samplesperpixel; + for (strip = 0; strip < td->td_nstrips; strip++) + td->td_stripbytecount_p[strip] = space; + /* + * This gross hack handles the case were the offset to + * the last strip is past the place where we think the strip + * should begin. Since a strip of data must be contiguous, + * it's safe to assume that we've overestimated the amount + * of data in the strip and trim this number back accordingly. + */ + strip--; + if (td->td_stripoffset_p[strip] > UINT64_MAX - td->td_stripbytecount_p[strip]) + return -1; + if (td->td_stripoffset_p[strip]+td->td_stripbytecount_p[strip] > filesize) { + if( td->td_stripoffset_p[strip] >= filesize ) { + /* Not sure what we should in that case... */ + td->td_stripbytecount_p[strip] = 0; + } else { + td->td_stripbytecount_p[strip] = filesize - td->td_stripoffset_p[strip]; + } + } + } else if (isTiled(tif)) { + uint64_t bytespertile = TIFFTileSize64(tif); + + for (strip = 0; strip < td->td_nstrips; strip++) + td->td_stripbytecount_p[strip] = bytespertile; + } else { + uint64_t rowbytes = TIFFScanlineSize64(tif); + uint32_t rowsperstrip = td->td_imagelength / td->td_stripsperimage; + for (strip = 0; strip < td->td_nstrips; strip++) + { + if( rowbytes > 0 && rowsperstrip > UINT64_MAX / rowbytes ) + return -1; + td->td_stripbytecount_p[strip] = rowbytes * rowsperstrip; + } + } + TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); + if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP)) + td->td_rowsperstrip = td->td_imagelength; + return 1; +} + +static void +MissingRequired(TIFF* tif, const char* tagname) +{ + static const char module[] = "MissingRequired"; + + TIFFErrorExt(tif->tif_clientdata, module, + "TIFF directory is missing required \"%s\" field", + tagname); +} + +/* + * Check the directory offset against the list of already seen directory + * offsets. This is a trick to prevent IFD looping. The one can create TIFF + * file with looped directory pointers. We will maintain a list of already + * seen directories and check every IFD offset against that list. + */ +static int +TIFFCheckDirOffset(TIFF* tif, uint64_t diroff) +{ + uint16_t n; + + if (diroff == 0) /* no more directories */ + return 0; + if (tif->tif_dirnumber == 65535) { + TIFFErrorExt(tif->tif_clientdata, "TIFFCheckDirOffset", + "Cannot handle more than 65535 TIFF directories"); + return 0; + } + + for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) { + if (tif->tif_dirlist[n] == diroff) + return 0; + } + + tif->tif_dirnumber++; + + if (tif->tif_dirlist == NULL || tif->tif_dirnumber > tif->tif_dirlistsize) { + uint64_t* new_dirlist; + + /* + * XXX: Reduce memory allocation granularity of the dirlist + * array. + */ + new_dirlist = (uint64_t*)_TIFFCheckRealloc(tif, tif->tif_dirlist, + tif->tif_dirnumber, 2 * sizeof(uint64_t), "for IFD list"); + if (!new_dirlist) + return 0; + if( tif->tif_dirnumber >= 32768 ) + tif->tif_dirlistsize = 65535; + else + tif->tif_dirlistsize = 2 * tif->tif_dirnumber; + tif->tif_dirlist = new_dirlist; + } + + tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff; + + return 1; +} + +/* + * Check the count field of a directory entry against a known value. The + * caller is expected to skip/ignore the tag if there is a mismatch. + */ +static int +CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32_t count) +{ + if ((uint64_t)count > dir->tdir_count) { + const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag); + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "incorrect count for field \"%s\" (%" PRIu64 ", expecting %"PRIu32"); tag ignored", + fip ? fip->field_name : "unknown tagname", + dir->tdir_count, count); + return (0); + } else if ((uint64_t)count < dir->tdir_count) { + const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag); + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "incorrect count for field \"%s\" (%" PRIu64 ", expecting %"PRIu32"); tag trimmed", + fip ? fip->field_name : "unknown tagname", + dir->tdir_count, count); + dir->tdir_count = count; + return (1); + } + return (1); +} + +/* + * Read IFD structure from the specified offset. If the pointer to + * nextdiroff variable has been specified, read it too. Function returns a + * number of fields in the directory or 0 if failed. + */ +static uint16_t +TIFFFetchDirectory(TIFF* tif, uint64_t diroff, TIFFDirEntry** pdir, + uint64_t *nextdiroff) +{ + static const char module[] = "TIFFFetchDirectory"; + + void* origdir; + uint16_t dircount16; + uint32_t dirsize; + TIFFDirEntry* dir; + uint8_t* ma; + TIFFDirEntry* mb; + uint16_t n; + + assert(pdir); + + tif->tif_diroff = diroff; + if (nextdiroff) + *nextdiroff = 0; + if (!isMapped(tif)) { + if (!SeekOK(tif, tif->tif_diroff)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (!ReadOK(tif, &dircount16, sizeof (uint16_t))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount16); + if (dircount16>4096) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on directory count failed, this is probably not a valid IFD offset"); + return 0; + } + dirsize = 12; + } else { + uint64_t dircount64; + if (!ReadOK(tif, &dircount64, sizeof (uint64_t))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>4096) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on directory count failed, this is probably not a valid IFD offset"); + return 0; + } + dircount16 = (uint16_t)dircount64; + dirsize = 20; + } + origdir = _TIFFCheckMalloc(tif, dircount16, + dirsize, "to read TIFF directory"); + if (origdir == NULL) + return 0; + if (!ReadOK(tif, origdir, (tmsize_t)(dircount16*dirsize))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%.100s: Can not read TIFF directory", + tif->tif_name); + _TIFFfree(origdir); + return 0; + } + /* + * Read offset to next directory for sequential scans if + * needed. + */ + if (nextdiroff) + { + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32_t nextdiroff32; + if (!ReadOK(tif, &nextdiroff32, sizeof(uint32_t))) + nextdiroff32 = 0; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&nextdiroff32); + *nextdiroff=nextdiroff32; + } else { + if (!ReadOK(tif, nextdiroff, sizeof(uint64_t))) + *nextdiroff = 0; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(nextdiroff); + } + } + } else { + tmsize_t m; + tmsize_t off; + if (tif->tif_diroff > (uint64_t)INT64_MAX) + { + TIFFErrorExt(tif->tif_clientdata,module,"Can not read TIFF directory count"); + return(0); + } + off = (tmsize_t) tif->tif_diroff; + + /* + * Check for integer overflow when validating the dir_off, + * otherwise a very high offset may cause an OOB read and + * crash the client. Make two comparisons instead of + * + * off + sizeof(uint16_t) > tif->tif_size + * + * to avoid overflow. + */ + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + m=off+sizeof(uint16_t); + if ((m tif->tif_size)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not read TIFF directory count"); + return 0; + } else { + _TIFFmemcpy(&dircount16, tif->tif_base + off, + sizeof(uint16_t)); + } + off += sizeof (uint16_t); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount16); + if (dircount16>4096) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on directory count failed, this is probably not a valid IFD offset"); + return 0; + } + dirsize = 12; + } + else + { + uint64_t dircount64; + m=off+sizeof(uint64_t); + if ((m tif->tif_size)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not read TIFF directory count"); + return 0; + } else { + _TIFFmemcpy(&dircount64, tif->tif_base + off, + sizeof(uint64_t)); + } + off += sizeof (uint64_t); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>4096) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on directory count failed, this is probably not a valid IFD offset"); + return 0; + } + dircount16 = (uint16_t)dircount64; + dirsize = 20; + } + if (dircount16 == 0 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on directory count failed, zero tag directories not supported"); + return 0; + } + origdir = _TIFFCheckMalloc(tif, dircount16, + dirsize, + "to read TIFF directory"); + if (origdir == NULL) + return 0; + m=off+dircount16*dirsize; + if ((mtif->tif_size)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not read TIFF directory"); + _TIFFfree(origdir); + return 0; + } else { + _TIFFmemcpy(origdir, tif->tif_base + off, + dircount16 * dirsize); + } + if (nextdiroff) { + off += dircount16 * dirsize; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32_t nextdiroff32; + m=off+sizeof(uint32_t); + if ((m tif->tif_size)) + nextdiroff32 = 0; + else + _TIFFmemcpy(&nextdiroff32, tif->tif_base + off, + sizeof (uint32_t)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&nextdiroff32); + *nextdiroff = nextdiroff32; + } + else + { + m=off+sizeof(uint64_t); + if ((m tif->tif_size)) + *nextdiroff = 0; + else + _TIFFmemcpy(nextdiroff, tif->tif_base + off, + sizeof (uint64_t)); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(nextdiroff); + } + } + } + dir = (TIFFDirEntry*)_TIFFCheckMalloc(tif, dircount16, + sizeof(TIFFDirEntry), + "to read TIFF directory"); + if (dir==0) + { + _TIFFfree(origdir); + return 0; + } + ma=(uint8_t*)origdir; + mb=dir; + for (n=0; ntdir_ignore = FALSE; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)ma); + mb->tdir_tag=*(uint16_t*)ma; + ma+=sizeof(uint16_t); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)ma); + mb->tdir_type=*(uint16_t*)ma; + ma+=sizeof(uint16_t); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)ma); + mb->tdir_count=(uint64_t)(*(uint32_t*)ma); + ma+=sizeof(uint32_t); + mb->tdir_offset.toff_long8=0; + *(uint32_t*)(&mb->tdir_offset)=*(uint32_t*)ma; + ma+=sizeof(uint32_t); + } + else + { + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)ma); + mb->tdir_count=TIFFReadUInt64(ma); + ma+=sizeof(uint64_t); + mb->tdir_offset.toff_long8=TIFFReadUInt64(ma); + ma+=sizeof(uint64_t); + } + mb++; + } + _TIFFfree(origdir); + *pdir = dir; + return dircount16; +} + +/* + * Fetch a tag that is not handled by special case code. + */ +static int +TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover) +{ + static const char module[] = "TIFFFetchNormalTag"; + enum TIFFReadDirEntryErr err; + uint32_t fii; + const TIFFField* fip = NULL; + TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii); + if( fii == FAILED_FII ) + { + TIFFErrorExt(tif->tif_clientdata, "TIFFFetchNormalTag", + "No definition found for tag %"PRIu16, + dp->tdir_tag); + return 0; + } + fip=tif->tif_fields[fii]; + assert(fip != NULL); /* should not happen */ + assert(fip->set_field_type!=TIFF_SETGET_OTHER); /* if so, we shouldn't arrive here but deal with this in specialized code */ + assert(fip->set_field_type!=TIFF_SETGET_INT); /* if so, we shouldn't arrive here as this is only the case for pseudo-tags */ + err=TIFFReadDirEntryErrOk; + switch (fip->set_field_type) + { + case TIFF_SETGET_UNDEFINED: + break; + case TIFF_SETGET_ASCII: + { + uint8_t* data; + assert(fip->field_passcount==0); + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + uint32_t mb = 0; + int n; + if (data != NULL) + { + uint8_t* ma = data; + while (mb<(uint32_t)dp->tdir_count) + { + if (*ma==0) + break; + ma++; + mb++; + } + } + if (mb+1<(uint32_t)dp->tdir_count) + TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" contains null byte in value; value incorrectly truncated during reading due to implementation limitations",fip->field_name); + else if (mb+1>(uint32_t)dp->tdir_count) + { + uint8_t* o; + TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte",fip->field_name); + if ((uint32_t)dp->tdir_count + 1 != dp->tdir_count + 1) + o=NULL; + else + o=_TIFFmalloc((uint32_t)dp->tdir_count + 1); + if (o==NULL) + { + if (data!=NULL) + _TIFFfree(data); + return(0); + } + _TIFFmemcpy(o,data,(uint32_t)dp->tdir_count); + o[(uint32_t)dp->tdir_count]=0; + if (data!=0) + _TIFFfree(data); + data=o; + } + n=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!n) + return(0); + } + } + break; + case TIFF_SETGET_UINT8: + { + uint8_t data=0; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryByte(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_UINT16: + { + uint16_t data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryShort(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_UINT32: + { + uint32_t data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryLong(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_UINT64: + { + uint64_t data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryLong8(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_FLOAT: + { + float data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryFloat(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_DOUBLE: + { + double data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryDouble(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_IFD8: + { + uint64_t data; + assert(fip->field_readcount==1); + assert(fip->field_passcount==0); + err=TIFFReadDirEntryIfd8(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + if (!TIFFSetField(tif,dp->tdir_tag,data)) + return(0); + } + } + break; + case TIFF_SETGET_UINT16_PAIR: + { + uint16_t* data; + assert(fip->field_readcount==2); + assert(fip->field_passcount==0); + if (dp->tdir_count!=2) { + TIFFWarningExt(tif->tif_clientdata,module, + "incorrect count for field \"%s\", expected 2, got %"PRIu64, + fip->field_name, dp->tdir_count); + return(0); + } + err=TIFFReadDirEntryShortArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + assert(data); /* avoid CLang static Analyzer false positive */ + m=TIFFSetField(tif,dp->tdir_tag,data[0],data[1]); + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C0_UINT8: + { + uint8_t* data; + assert(fip->field_readcount>=1); + assert(fip->field_passcount==0); + if (dp->tdir_count!=(uint64_t)fip->field_readcount) { + TIFFWarningExt(tif->tif_clientdata,module, + "incorrect count for field \"%s\", expected %d, got %"PRIu64, + fip->field_name,(int) fip->field_readcount, dp->tdir_count); + return 0; + } + else + { + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C0_UINT16: + { + uint16_t* data; + assert(fip->field_readcount>=1); + assert(fip->field_passcount==0); + if (dp->tdir_count!=(uint64_t)fip->field_readcount) + /* corrupt file */; + else + { + err=TIFFReadDirEntryShortArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C0_UINT32: + { + uint32_t* data; + assert(fip->field_readcount>=1); + assert(fip->field_passcount==0); + if (dp->tdir_count!=(uint64_t)fip->field_readcount) + /* corrupt file */; + else + { + err=TIFFReadDirEntryLongArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C0_FLOAT: + { + float* data; + assert(fip->field_readcount>=1); + assert(fip->field_passcount==0); + if (dp->tdir_count!=(uint64_t)fip->field_readcount) + /* corrupt file */; + else + { + err=TIFFReadDirEntryFloatArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + /*--: Rational2Double: Extend for Double Arrays and Rational-Arrays read into Double-Arrays. */ + case TIFF_SETGET_C0_DOUBLE: + { + double* data; + assert(fip->field_readcount>=1); + assert(fip->field_passcount==0); + if (dp->tdir_count!=(uint64_t)fip->field_readcount) + /* corrupt file */; + else + { + err=TIFFReadDirEntryDoubleArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif,dp->tdir_tag,data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_ASCII: + { + uint8_t* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + if( data != 0 && dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' ) + { + TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name); + data[dp->tdir_count-1] = '\0'; + } + m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_UINT8: + { + uint8_t* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_UINT16: + { + uint16_t* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryShortArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_UINT32: + { + uint32_t* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryLongArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_UINT64: + { + uint64_t* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryLong8Array(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_FLOAT: + { + float* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryFloatArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_DOUBLE: + { + double* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryDoubleArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C16_IFD8: + { + uint64_t* data; + assert(fip->field_readcount==TIFF_VARIABLE); + assert(fip->field_passcount==1); + if (dp->tdir_count>0xFFFF) + err=TIFFReadDirEntryErrCount; + else + { + err=TIFFReadDirEntryIfd8Array(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + } + break; + case TIFF_SETGET_C32_ASCII: + { + uint8_t* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + if( data != 0 && dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' ) + { + TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name); + data[dp->tdir_count-1] = '\0'; + } + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_UINT8: + { + uint8_t* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryByteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_SINT8: + { + int8_t* data = NULL; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntrySbyteArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_UINT16: + { + uint16_t* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryShortArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_SINT16: + { + int16_t* data = NULL; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntrySshortArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_UINT32: + { + uint32_t* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryLongArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_SINT32: + { + int32_t* data = NULL; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntrySlongArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_UINT64: + { + uint64_t* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryLong8Array(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_SINT64: + { + int64_t* data = NULL; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntrySlong8Array(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_FLOAT: + { + float* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryFloatArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_DOUBLE: + { + double* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryDoubleArray(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + case TIFF_SETGET_C32_IFD8: + { + uint64_t* data; + assert(fip->field_readcount==TIFF_VARIABLE2); + assert(fip->field_passcount==1); + err=TIFFReadDirEntryIfd8Array(tif,dp,&data); + if (err==TIFFReadDirEntryErrOk) + { + int m; + m=TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); + if (data!=0) + _TIFFfree(data); + if (!m) + return(0); + } + } + break; + default: + assert(0); /* we should never get here */ + break; + } + if (err!=TIFFReadDirEntryErrOk) + { + TIFFReadDirEntryOutputErr(tif,err,module,fip->field_name,recover); + return(0); + } + return(1); +} + +/* + * Fetch a set of offsets or lengths. + * While this routine says "strips", in fact it's also used for tiles. + */ +static int +TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32_t nstrips, uint64_t** lpp) +{ + static const char module[] = "TIFFFetchStripThing"; + enum TIFFReadDirEntryErr err; + uint64_t* data; + err=TIFFReadDirEntryLong8ArrayWithLimit(tif,dir,&data,nstrips); + if (err!=TIFFReadDirEntryErrOk) + { + const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag); + TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0); + return(0); + } + if (dir->tdir_count<(uint64_t)nstrips) + { + uint64_t* resizeddata; + const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag); + const char* pszMax = getenv("LIBTIFF_STRILE_ARRAY_MAX_RESIZE_COUNT"); + uint32_t max_nstrips = 1000000; + if( pszMax ) + max_nstrips = (uint32_t) atoi(pszMax); + TIFFReadDirEntryOutputErr(tif,TIFFReadDirEntryErrCount, + module, + fip ? fip->field_name : "unknown tagname", + ( nstrips <= max_nstrips ) ); + + if( nstrips > max_nstrips ) + { + _TIFFfree(data); + return(0); + } + + resizeddata=(uint64_t*)_TIFFCheckMalloc(tif, nstrips, sizeof(uint64_t), "for strip array"); + if (resizeddata==0) { + _TIFFfree(data); + return(0); + } + _TIFFmemcpy(resizeddata,data, (uint32_t)dir->tdir_count * sizeof(uint64_t)); + _TIFFmemset(resizeddata+(uint32_t)dir->tdir_count, 0, (nstrips - (uint32_t)dir->tdir_count) * sizeof(uint64_t)); + _TIFFfree(data); + data=resizeddata; + } + *lpp=data; + return(1); +} + +/* + * Fetch and set the SubjectDistance EXIF tag. + */ +static int +TIFFFetchSubjectDistance(TIFF* tif, TIFFDirEntry* dir) +{ + static const char module[] = "TIFFFetchSubjectDistance"; + enum TIFFReadDirEntryErr err; + UInt64Aligned_t m; + m.l=0; + assert(sizeof(double)==8); + assert(sizeof(uint64_t) == 8); + assert(sizeof(uint32_t) == 4); + if (dir->tdir_count!=1) + err=TIFFReadDirEntryErrCount; + else if (dir->tdir_type!=TIFF_RATIONAL) + err=TIFFReadDirEntryErrType; + else + { + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32_t offset; + offset=*(uint32_t*)(&dir->tdir_offset); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&offset); + err=TIFFReadDirEntryData(tif,offset,8,m.i); + } + else + { + m.l=dir->tdir_offset.toff_long8; + err=TIFFReadDirEntryErrOk; + } + } + if (err==TIFFReadDirEntryErrOk) + { + double n; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(m.i,2); + if (m.i[0]==0) + n=0.0; + else if (m.i[0]==0xFFFFFFFF || m.i[1]==0) + /* + * XXX: Numerator 0xFFFFFFFF means that we have infinite + * distance. Indicate that with a negative floating point + * SubjectDistance value. + */ + n=-1.0; + else + n=(double)m.i[0]/(double)m.i[1]; + return(TIFFSetField(tif,dir->tdir_tag,n)); + } + else + { + TIFFReadDirEntryOutputErr(tif,err,module,"SubjectDistance",TRUE); + return(0); + } +} + +static void allocChoppedUpStripArrays(TIFF* tif, uint32_t nstrips, + uint64_t stripbytes, uint32_t rowsperstrip) +{ + TIFFDirectory *td = &tif->tif_dir; + uint64_t bytecount; + uint64_t offset; + uint64_t last_offset; + uint64_t last_bytecount; + uint32_t i; + uint64_t *newcounts; + uint64_t *newoffsets; + + offset = TIFFGetStrileOffset(tif, 0); + last_offset = TIFFGetStrileOffset(tif, td->td_nstrips-1); + last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips-1); + if( last_offset > UINT64_MAX - last_bytecount || + last_offset + last_bytecount < offset ) + { + return; + } + bytecount = last_offset + last_bytecount - offset; + + newcounts = (uint64_t*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64_t), + "for chopped \"StripByteCounts\" array"); + newoffsets = (uint64_t*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64_t), + "for chopped \"StripOffsets\" array"); + if (newcounts == NULL || newoffsets == NULL) { + /* + * Unable to allocate new strip information, give up and use + * the original one strip information. + */ + if (newcounts != NULL) + _TIFFfree(newcounts); + if (newoffsets != NULL) + _TIFFfree(newoffsets); + return; + } + + /* + * Fill the strip information arrays with new bytecounts and offsets + * that reflect the broken-up format. + */ + for (i = 0; i < nstrips; i++) + { + if (stripbytes > bytecount) + stripbytes = bytecount; + newcounts[i] = stripbytes; + newoffsets[i] = stripbytes ? offset : 0; + offset += stripbytes; + bytecount -= stripbytes; + } + + /* + * Replace old single strip info with multi-strip info. + */ + td->td_stripsperimage = td->td_nstrips = nstrips; + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); + + _TIFFfree(td->td_stripbytecount_p); + _TIFFfree(td->td_stripoffset_p); + td->td_stripbytecount_p = newcounts; + td->td_stripoffset_p = newoffsets; +#ifdef STRIPBYTECOUNTSORTED_UNUSED + td->td_stripbytecountsorted = 1; +#endif + tif->tif_flags |= TIFF_CHOPPEDUPARRAYS; +} + + +/* + * Replace a single strip (tile) of uncompressed data by multiple strips + * (tiles), each approximately STRIP_SIZE_DEFAULT bytes. This is useful for + * dealing with large images or for dealing with machines with a limited + * amount memory. + */ +static void +ChopUpSingleUncompressedStrip(TIFF* tif) +{ + register TIFFDirectory *td = &tif->tif_dir; + uint64_t bytecount; + uint64_t offset; + uint32_t rowblock; + uint64_t rowblockbytes; + uint64_t stripbytes; + uint32_t nstrips; + uint32_t rowsperstrip; + + bytecount = TIFFGetStrileByteCount(tif, 0); + /* On a newly created file, just re-opened to be filled, we */ + /* don't want strip chop to trigger as it is going to cause issues */ + /* later ( StripOffsets and StripByteCounts improperly filled) . */ + if( bytecount == 0 && tif->tif_mode != O_RDONLY ) + return; + offset = TIFFGetStrileByteCount(tif, 0); + assert(td->td_planarconfig == PLANARCONFIG_CONTIG); + if ((td->td_photometric == PHOTOMETRIC_YCBCR)&& + (!isUpSampled(tif))) + rowblock = td->td_ycbcrsubsampling[1]; + else + rowblock = 1; + rowblockbytes = TIFFVTileSize64(tif, rowblock); + /* + * Make the rows hold at least one scanline, but fill specified amount + * of data if possible. + */ + if (rowblockbytes > STRIP_SIZE_DEFAULT) { + stripbytes = rowblockbytes; + rowsperstrip = rowblock; + } else if (rowblockbytes > 0 ) { + uint32_t rowblocksperstrip; + rowblocksperstrip = (uint32_t) (STRIP_SIZE_DEFAULT / rowblockbytes); + rowsperstrip = rowblocksperstrip * rowblock; + stripbytes = rowblocksperstrip * rowblockbytes; + } + else + return; + + /* + * never increase the number of rows per strip + */ + if (rowsperstrip >= td->td_rowsperstrip) + return; + nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip); + if( nstrips == 0 ) + return; + + /* If we are going to allocate a lot of memory, make sure that the */ + /* file is as big as needed */ + if( tif->tif_mode == O_RDONLY && + nstrips > 1000000 && + (offset >= TIFFGetFileSize(tif) || + stripbytes > (TIFFGetFileSize(tif) - offset) / (nstrips - 1)) ) + { + return; + } + + allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip); +} + + +/* + * Replace a file with contiguous strips > 2 GB of uncompressed data by + * multiple smaller strips. This is useful for + * dealing with large images or for dealing with machines with a limited + * amount memory. + */ +static void TryChopUpUncompressedBigTiff( TIFF* tif ) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32_t rowblock; + uint64_t rowblockbytes; + uint32_t i; + uint64_t stripsize; + uint32_t rowblocksperstrip; + uint32_t rowsperstrip; + uint64_t stripbytes; + uint32_t nstrips; + + stripsize = TIFFStripSize64(tif); + + assert( tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG ); + assert( tif->tif_dir.td_compression == COMPRESSION_NONE ); + assert( (tif->tif_flags&(TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP ); + assert( stripsize > 0x7FFFFFFFUL ); + + /* On a newly created file, just re-opened to be filled, we */ + /* don't want strip chop to trigger as it is going to cause issues */ + /* later ( StripOffsets and StripByteCounts improperly filled) . */ + if( TIFFGetStrileByteCount(tif, 0) == 0 && tif->tif_mode != O_RDONLY ) + return; + + if ((td->td_photometric == PHOTOMETRIC_YCBCR)&& + (!isUpSampled(tif))) + rowblock = td->td_ycbcrsubsampling[1]; + else + rowblock = 1; + rowblockbytes = TIFFVStripSize64(tif, rowblock); + if( rowblockbytes == 0 || rowblockbytes > 0x7FFFFFFFUL ) + { + /* In case of file with gigantic width */ + return; + } + + /* Check that the strips are contiguous and of the expected size */ + for( i = 0; i < td->td_nstrips; i++ ) + { + if( i == td->td_nstrips - 1 ) + { + if( TIFFGetStrileByteCount(tif, i) < TIFFVStripSize64( + tif, td->td_imagelength - i * td->td_rowsperstrip ) ) + { + return; + } + } + else + { + if( TIFFGetStrileByteCount(tif, i) != stripsize ) + { + return; + } + if( i > 0 && TIFFGetStrileOffset(tif, i) != + TIFFGetStrileOffset(tif, i-1) + TIFFGetStrileByteCount(tif, i-1) ) + { + return; + } + } + } + + /* Aim for 512 MB strips (that will still be manageable by 32 bit builds */ + rowblocksperstrip = (uint32_t) (512 * 1024 * 1024 / rowblockbytes); + if( rowblocksperstrip == 0 ) + rowblocksperstrip = 1; + rowsperstrip = rowblocksperstrip * rowblock; + stripbytes = rowblocksperstrip * rowblockbytes; + assert( stripbytes <= 0x7FFFFFFFUL ); + + nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip); + if( nstrips == 0 ) + return; + + /* If we are going to allocate a lot of memory, make sure that the */ + /* file is as big as needed */ + if( tif->tif_mode == O_RDONLY && + nstrips > 1000000 ) + { + uint64_t last_offset = TIFFGetStrileOffset(tif, td->td_nstrips - 1); + uint64_t filesize = TIFFGetFileSize(tif); + uint64_t last_bytecount = TIFFGetStrileByteCount(tif, td->td_nstrips - 1); + if( last_offset > filesize || + last_bytecount > filesize - last_offset ) + { + return; + } + } + + allocChoppedUpStripArrays(tif, nstrips, stripbytes, rowsperstrip); +} + + +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static uint64_t _TIFFUnsanitizedAddUInt64AndInt(uint64_t a, int b) +{ + return a + b; +} + +/* Read the value of [Strip|Tile]Offset or [Strip|Tile]ByteCount around + * strip/tile of number strile. Also fetch the neighbouring values using a + * 4096 byte page size. + */ +static +int _TIFFPartialReadStripArray(TIFF* tif, TIFFDirEntry* dirent, + int strile, uint64_t* panVals ) +{ + static const char module[] = "_TIFFPartialReadStripArray"; +#define IO_CACHE_PAGE_SIZE 4096 + + size_t sizeofval; + const int bSwab = (tif->tif_flags & TIFF_SWAB) != 0; + int sizeofvalint; + uint64_t nBaseOffset; + uint64_t nOffset; + uint64_t nOffsetStartPage; + uint64_t nOffsetEndPage; + tmsize_t nToRead; + tmsize_t nRead; + uint64_t nLastStripOffset; + int iStartBefore; + int i; + const uint32_t arraySize = tif->tif_dir.td_stripoffsetbyteallocsize; + unsigned char buffer[2 * IO_CACHE_PAGE_SIZE]; + + assert( dirent->tdir_count > 4 ); + + if( dirent->tdir_type == TIFF_SHORT ) + { + sizeofval = sizeof(uint16_t); + } + else if( dirent->tdir_type == TIFF_LONG ) + { + sizeofval = sizeof(uint32_t); + } + else if( dirent->tdir_type == TIFF_LONG8 ) + { + sizeofval = sizeof(uint64_t); + } + else if( dirent->tdir_type == TIFF_SLONG8 ) + { + /* Non conformant but used by some images as in */ + /* https://github.com/OSGeo/gdal/issues/2165 */ + sizeofval = sizeof(int64_t); + } + else + { + TIFFErrorExt(tif->tif_clientdata, module, + "Invalid type for [Strip|Tile][Offset/ByteCount] tag"); + panVals[strile] = 0; + return 0; + } + sizeofvalint = (int)(sizeofval); + + if( tif->tif_flags&TIFF_BIGTIFF ) + { + uint64_t offset = dirent->tdir_offset.toff_long8; + if( bSwab ) + TIFFSwabLong8(&offset); + nBaseOffset = offset; + } + else + { + uint32_t offset = dirent->tdir_offset.toff_long; + if( bSwab ) + TIFFSwabLong(&offset); + nBaseOffset = offset; + } + /* To avoid later unsigned integer overflows */ + if( nBaseOffset > (uint64_t)INT64_MAX ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot read offset/size for strile %d", strile); + panVals[strile] = 0; + return 0; + } + nOffset = nBaseOffset + sizeofval * strile; + nOffsetStartPage = + (nOffset / IO_CACHE_PAGE_SIZE) * IO_CACHE_PAGE_SIZE; + nOffsetEndPage = nOffsetStartPage + IO_CACHE_PAGE_SIZE; + + if( nOffset + sizeofval > nOffsetEndPage ) + nOffsetEndPage += IO_CACHE_PAGE_SIZE; +#undef IO_CACHE_PAGE_SIZE + + nLastStripOffset = nBaseOffset + arraySize * sizeofval; + if( nLastStripOffset < nOffsetEndPage ) + nOffsetEndPage = nLastStripOffset; + if( nOffsetStartPage >= nOffsetEndPage ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot read offset/size for strile %d", strile); + panVals[strile] = 0; + return 0; + } + if (!SeekOK(tif,nOffsetStartPage)) + { + panVals[strile] = 0; + return 0; + } + + nToRead = (tmsize_t)(nOffsetEndPage - nOffsetStartPage); + nRead = TIFFReadFile(tif, buffer, nToRead); + if( nRead < nToRead ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot read offset/size for strile around ~%d", strile); + return 0; + } + iStartBefore = -(int)((nOffset - nOffsetStartPage) / sizeofval); + if( strile + iStartBefore < 0 ) + iStartBefore = -strile; + for( i = iStartBefore; + (uint32_t)(strile + i) < arraySize && + _TIFFUnsanitizedAddUInt64AndInt(nOffset, (i + 1) * sizeofvalint) <= nOffsetEndPage; + ++i ) + { + if( dirent->tdir_type == TIFF_SHORT ) + { + uint16_t val; + memcpy(&val, + buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, + sizeof(val)); + if( bSwab ) + TIFFSwabShort(&val); + panVals[strile + i] = val; + } + else if( dirent->tdir_type == TIFF_LONG ) + { + uint32_t val; + memcpy(&val, + buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, + sizeof(val)); + if( bSwab ) + TIFFSwabLong(&val); + panVals[strile + i] = val; + } + else if( dirent->tdir_type == TIFF_LONG8 ) + { + uint64_t val; + memcpy(&val, + buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, + sizeof(val)); + if( bSwab ) + TIFFSwabLong8(&val); + panVals[strile + i] = val; + } + else /* if( dirent->tdir_type == TIFF_SLONG8 ) */ + { + /* Non conformant data type */ + int64_t val; + memcpy(&val, + buffer + (nOffset - nOffsetStartPage) + i * sizeofvalint, + sizeof(val)); + if( bSwab ) + TIFFSwabLong8((uint64_t*) &val); + panVals[strile + i] = (uint64_t) val; + } + } + return 1; +} + +static int _TIFFFetchStrileValue(TIFF* tif, + uint32_t strile, + TIFFDirEntry* dirent, + uint64_t** parray) +{ + static const char module[] = "_TIFFFetchStrileValue"; + TIFFDirectory *td = &tif->tif_dir; + if( strile >= dirent->tdir_count ) + { + return 0; + } + if( strile >= td->td_stripoffsetbyteallocsize ) + { + uint32_t nStripArrayAllocBefore = td->td_stripoffsetbyteallocsize; + uint32_t nStripArrayAllocNew; + uint64_t nArraySize64; + size_t nArraySize; + uint64_t* offsetArray; + uint64_t* bytecountArray; + + if( strile > 1000000 ) + { + uint64_t filesize = TIFFGetFileSize(tif); + /* Avoid excessive memory allocation attempt */ + /* For such a big blockid we need at least a TIFF_LONG per strile */ + /* for the offset array. */ + if( strile > filesize / sizeof(uint32_t) ) + { + TIFFErrorExt(tif->tif_clientdata, module, "File too short"); + return 0; + } + } + + if( td->td_stripoffsetbyteallocsize == 0 && + td->td_nstrips < 1024 * 1024 ) + { + nStripArrayAllocNew = td->td_nstrips; + } + else + { +#define TIFF_MAX(a,b) (((a)>(b)) ? (a) : (b)) +#define TIFF_MIN(a,b) (((a)<(b)) ? (a) : (b)) + nStripArrayAllocNew = TIFF_MAX(strile + 1, 1024U * 512U ); + if( nStripArrayAllocNew < 0xFFFFFFFFU / 2 ) + nStripArrayAllocNew *= 2; + nStripArrayAllocNew = TIFF_MIN(nStripArrayAllocNew, td->td_nstrips); + } + assert( strile < nStripArrayAllocNew ); + nArraySize64 = (uint64_t)sizeof(uint64_t) * nStripArrayAllocNew; + nArraySize = (size_t)(nArraySize64); +#if SIZEOF_SIZE_T == 4 + if( nArraySize != nArraySize64 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot allocate strip offset and bytecount arrays"); + return 0; + } +#endif + offsetArray = (uint64_t*)( + _TIFFrealloc( td->td_stripoffset_p, nArraySize ) ); + bytecountArray = (uint64_t*)( + _TIFFrealloc( td->td_stripbytecount_p, nArraySize ) ); + if( offsetArray ) + td->td_stripoffset_p = offsetArray; + if( bytecountArray ) + td->td_stripbytecount_p = bytecountArray; + if( offsetArray && bytecountArray ) + { + td->td_stripoffsetbyteallocsize = nStripArrayAllocNew; + /* Initialize new entries to ~0 / -1 */ + memset(td->td_stripoffset_p + nStripArrayAllocBefore, + 0xFF, + (td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * sizeof(uint64_t) ); + memset(td->td_stripbytecount_p + nStripArrayAllocBefore, + 0xFF, + (td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * sizeof(uint64_t) ); + } + else + { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot allocate strip offset and bytecount arrays"); + _TIFFfree(td->td_stripoffset_p); + td->td_stripoffset_p = NULL; + _TIFFfree(td->td_stripbytecount_p); + td->td_stripbytecount_p = NULL; + td->td_stripoffsetbyteallocsize = 0; + } + } + if( *parray == NULL || strile >= td->td_stripoffsetbyteallocsize ) + return 0; + + if( ~((*parray)[strile]) == 0 ) + { + if( !_TIFFPartialReadStripArray( tif, dirent, strile, *parray ) ) + { + (*parray)[strile] = 0; + return 0; + } + } + + return 1; +} + +static uint64_t _TIFFGetStrileOffsetOrByteCountValue(TIFF *tif, uint32_t strile, + TIFFDirEntry* dirent, + uint64_t** parray, + int *pbErr) +{ + TIFFDirectory *td = &tif->tif_dir; + if( pbErr ) + *pbErr = 0; + if( (tif->tif_flags&TIFF_DEFERSTRILELOAD) && !(tif->tif_flags&TIFF_CHOPPEDUPARRAYS) ) + { + if( !(tif->tif_flags&TIFF_LAZYSTRILELOAD) || + /* If the values may fit in the toff_long/toff_long8 member */ + /* then use _TIFFFillStriles to simplify _TIFFFetchStrileValue */ + dirent->tdir_count <= 4 ) + { + if( !_TIFFFillStriles(tif) ) + { + if( pbErr ) + *pbErr = 1; + /* Do not return, as we want this function to always */ + /* return the same value if called several times with */ + /* the same arguments */ + } + } + else + { + if( !_TIFFFetchStrileValue(tif, strile, dirent, parray) ) + { + if( pbErr ) + *pbErr = 1; + return 0; + } + } + } + if( *parray == NULL || strile >= td->td_nstrips ) + { + if( pbErr ) + *pbErr = 1; + return 0; + } + return (*parray)[strile]; +} + +/* Return the value of the TileOffsets/StripOffsets array for the specified tile/strile */ +uint64_t TIFFGetStrileOffset(TIFF *tif, uint32_t strile) +{ + return TIFFGetStrileOffsetWithErr(tif, strile, NULL); +} + +/* Return the value of the TileOffsets/StripOffsets array for the specified tile/strile */ +uint64_t TIFFGetStrileOffsetWithErr(TIFF *tif, uint32_t strile, int *pbErr) +{ + TIFFDirectory *td = &tif->tif_dir; + return _TIFFGetStrileOffsetOrByteCountValue(tif, strile, + &(td->td_stripoffset_entry), + &(td->td_stripoffset_p), pbErr); +} + +/* Return the value of the TileByteCounts/StripByteCounts array for the specified tile/strile */ +uint64_t TIFFGetStrileByteCount(TIFF *tif, uint32_t strile) +{ + return TIFFGetStrileByteCountWithErr(tif, strile, NULL); +} + +/* Return the value of the TileByteCounts/StripByteCounts array for the specified tile/strile */ +uint64_t TIFFGetStrileByteCountWithErr(TIFF *tif, uint32_t strile, int *pbErr) +{ + TIFFDirectory *td = &tif->tif_dir; + return _TIFFGetStrileOffsetOrByteCountValue(tif, strile, + &(td->td_stripbytecount_entry), + &(td->td_stripbytecount_p), pbErr); +} + + +int _TIFFFillStriles( TIFF *tif ) +{ + return _TIFFFillStrilesInternal( tif, 1 ); +} + +static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount ) +{ + register TIFFDirectory *td = &tif->tif_dir; + int return_value = 1; + + /* Do not do anything if TIFF_DEFERSTRILELOAD is not set */ + if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) || (tif->tif_flags&TIFF_CHOPPEDUPARRAYS) != 0 ) + return 1; + + if( tif->tif_flags&TIFF_LAZYSTRILELOAD ) + { + /* In case of lazy loading, reload completely the arrays */ + _TIFFfree(td->td_stripoffset_p); + _TIFFfree(td->td_stripbytecount_p); + td->td_stripoffset_p = NULL; + td->td_stripbytecount_p = NULL; + td->td_stripoffsetbyteallocsize = 0; + tif->tif_flags &= ~TIFF_LAZYSTRILELOAD; + } + + /* If stripoffset array is already loaded, exit with success */ + if( td->td_stripoffset_p != NULL ) + return 1; + + /* If tdir_count was canceled, then we already got there, but in error */ + if( td->td_stripoffset_entry.tdir_count == 0 ) + return 0; + + if (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry), + td->td_nstrips,&td->td_stripoffset_p)) + { + return_value = 0; + } + + if (loadStripByteCount && + !TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry), + td->td_nstrips,&td->td_stripbytecount_p)) + { + return_value = 0; + } + + _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); + _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); + +#ifdef STRIPBYTECOUNTSORTED_UNUSED + if (tif->tif_dir.td_nstrips > 1 && return_value == 1 ) { + uint32_t strip; + + tif->tif_dir.td_stripbytecountsorted = 1; + for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) { + if (tif->tif_dir.td_stripoffset_p[strip - 1] > + tif->tif_dir.td_stripoffset_p[strip]) { + tif->tif_dir.td_stripbytecountsorted = 0; + break; + } + } + } +#endif + + return return_value; +} + + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_dirwrite.c b/libs/tiff/libtiff/tif_dirwrite.c new file mode 100644 index 00000000000..12d67be6a26 --- /dev/null +++ b/libs/tiff/libtiff/tif_dirwrite.c @@ -0,0 +1,3738 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Write Support Routines. + */ +#include "tiffiop.h" +#include /*--: for Rational2Double */ +#include /*--: for Rational2Double */ + +#ifdef HAVE_IEEEFP +#define TIFFCvtNativeToIEEEFloat(tif, n, fp) +#define TIFFCvtNativeToIEEEDouble(tif, n, dp) +#else +extern void TIFFCvtNativeToIEEEFloat(TIFF* tif, uint32_t n, float* fp); +extern void TIFFCvtNativeToIEEEDouble(TIFF* tif, uint32_t n, double* dp); +#endif + +static int TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64_t* pdiroff); + +static int TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value); +#if 0 +static int TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value); +#endif + +static int TIFFWriteDirectoryTagAscii(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, char* value); +static int TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint8_t* value); +#ifdef notdef +static int TIFFWriteDirectoryTagByte(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint8_t value); +#endif +static int TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint8_t* value); +#if 0 +static int TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint8_t value); +#endif +#ifdef notdef +static int TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int8_t value); +#endif +static int TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int8_t* value); +#if 0 +static int TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int8_t value); +#endif +static int TIFFWriteDirectoryTagShort(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint16_t value); +static int TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint16_t* value); +static int TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint16_t value); +#ifdef notdef +static int TIFFWriteDirectoryTagSshort(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int16_t value); +#endif +static int TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int16_t* value); +#if 0 +static int TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int16_t value); +#endif +static int TIFFWriteDirectoryTagLong(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t value); +static int TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint32_t* value); +#if 0 +static int TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t value); +#endif +#ifdef notdef +static int TIFFWriteDirectoryTagSlong(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int32_t value); +#endif +static int TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int32_t* value); +#if 0 +static int TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int32_t value); +#endif +#ifdef notdef +static int TIFFWriteDirectoryTagLong8(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint64_t value); +#endif +static int TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value); +#ifdef notdef +static int TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int64_t value); +#endif +static int TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int64_t* value); +static int TIFFWriteDirectoryTagRational(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value); +static int TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value); +static int TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value); +#ifdef notdef +static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, float value); +#endif +static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value); +#if 0 +static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, float value); +#endif +#ifdef notdef +static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value); +#endif +static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value); +#if 0 +static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value); +#endif +static int TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint32_t* value); +#ifdef notdef +static int TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value); +#endif +static int TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t value); +static int TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value); +static int TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value); +#ifdef notdef +static int TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value); +#endif +static int TIFFWriteDirectoryTagColormap(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir); +static int TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir); +static int TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir); + +static int TIFFWriteDirectoryTagCheckedAscii(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, char* value); +static int TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint8_t* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint8_t value); +#endif +static int TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint8_t* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int8_t value); +#endif +static int TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int8_t* value); +static int TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint16_t value); +static int TIFFWriteDirectoryTagCheckedShortArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint16_t* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int16_t value); +#endif +static int TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int16_t* value); +static int TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t value); +static int TIFFWriteDirectoryTagCheckedLongArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint32_t* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int32_t value); +#endif +static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int32_t* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint64_t value); +#endif +static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int64_t value); +#endif +static int TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int64_t* value); +static int TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value); +static int TIFFWriteDirectoryTagCheckedRationalArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value); +static int TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value); + +/*--: Rational2Double: New functions to support true double-precision for custom rational tag types. */ +static int TIFFWriteDirectoryTagRationalDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value); +static int TIFFWriteDirectoryTagSrationalDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value); +static int TIFFWriteDirectoryTagCheckedRationalDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value); +static int TIFFWriteDirectoryTagCheckedSrationalDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value); +static void DoubleToRational(double value, uint32_t *num, uint32_t *denom); +static void DoubleToSrational(double value, int32_t *num, int32_t *denom); +#if 0 +static void DoubleToRational_direct(double value, unsigned long *num, unsigned long *denom); +static void DoubleToSrational_direct(double value, long *num, long *denom); +#endif + +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, float value); +#endif +static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value); +#ifdef notdef +static int TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value); +#endif +static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value); +static int TIFFWriteDirectoryTagCheckedIfdArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint32_t* value); +static int TIFFWriteDirectoryTagCheckedIfd8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value); + +static int TIFFWriteDirectoryTagData(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint16_t datatype, uint32_t count, uint32_t datalength, void* data); + +static int TIFFLinkDirectory(TIFF*); + +/* + * Write the contents of the current directory + * to the specified file. This routine doesn't + * handle overwriting a directory with auxiliary + * storage that's been changed. + */ +int +TIFFWriteDirectory(TIFF* tif) +{ + return TIFFWriteDirectorySec(tif,TRUE,TRUE,NULL); +} + +/* + * This is an advanced writing function that must be used in a particular + * sequence, and generally together with TIFFForceStrileArrayWriting(), + * to make its intended effect. Its aim is to modify the location + * where the [Strip/Tile][Offsets/ByteCounts] arrays are located in the file. + * More precisely, when TIFFWriteCheck() will be called, the tag entries for + * those arrays will be written with type = count = offset = 0 as a temporary + * value. + * + * Its effect is only valid for the current directory, and before + * TIFFWriteDirectory() is first called, and will be reset when + * changing directory. + * + * The typical sequence of calls is: + * TIFFOpen() + * [ TIFFCreateDirectory(tif) ] + * Set fields with calls to TIFFSetField(tif, ...) + * TIFFDeferStrileArrayWriting(tif) + * TIFFWriteCheck(tif, ...) + * TIFFWriteDirectory(tif) + * ... potentially create other directories and come back to the above directory + * TIFFForceStrileArrayWriting(tif): emit the arrays at the end of file + * + * Returns 1 in case of success, 0 otherwise. + */ +int TIFFDeferStrileArrayWriting(TIFF* tif) +{ + static const char module[] = "TIFFDeferStrileArrayWriting"; + if (tif->tif_mode == O_RDONLY) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "File opened in read-only mode"); + return 0; + } + if( tif->tif_diroff != 0 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Directory has already been written"); + return 0; + } + + tif->tif_dir.td_deferstrilearraywriting = TRUE; + return 1; +} + +/* + * Similar to TIFFWriteDirectory(), writes the directory out + * but leaves all data structures in memory so that it can be + * written again. This will make a partially written TIFF file + * readable before it is successfully completed/closed. + */ +int +TIFFCheckpointDirectory(TIFF* tif) +{ + int rc; + /* Setup the strips arrays, if they haven't already been. */ + if (tif->tif_dir.td_stripoffset_p == NULL) + (void) TIFFSetupStrips(tif); + rc = TIFFWriteDirectorySec(tif,TRUE,FALSE,NULL); + (void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END)); + return rc; +} + +int +TIFFWriteCustomDirectory(TIFF* tif, uint64_t* pdiroff) +{ + return TIFFWriteDirectorySec(tif,FALSE,FALSE,pdiroff); +} + +/* + * Similar to TIFFWriteDirectory(), but if the directory has already + * been written once, it is relocated to the end of the file, in case it + * has changed in size. Note that this will result in the loss of the + * previously used directory space. + */ +int +TIFFRewriteDirectory( TIFF *tif ) +{ + static const char module[] = "TIFFRewriteDirectory"; + + /* We don't need to do anything special if it hasn't been written. */ + if( tif->tif_diroff == 0 ) + return TIFFWriteDirectory( tif ); + + /* + * Find and zero the pointer to this directory, so that TIFFLinkDirectory + * will cause it to be added after this directories current pre-link. + */ + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (tif->tif_header.classic.tiff_diroff == tif->tif_diroff) + { + tif->tif_header.classic.tiff_diroff = 0; + tif->tif_diroff = 0; + + TIFFSeekFile(tif,4,SEEK_SET); + if (!WriteOK(tif, &(tif->tif_header.classic.tiff_diroff),4)) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error updating TIFF header"); + return (0); + } + } + else + { + uint32_t nextdir; + nextdir = tif->tif_header.classic.tiff_diroff; + while(1) { + uint16_t dircount; + uint32_t nextnextdir; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount, 2)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + (void) TIFFSeekFile(tif, + nextdir+2+dircount*12, SEEK_SET); + if (!ReadOK(tif, &nextnextdir, 4)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextnextdir); + if (nextnextdir==tif->tif_diroff) + { + uint32_t m; + m=0; + (void) TIFFSeekFile(tif, + nextdir+2+dircount*12, SEEK_SET); + if (!WriteOK(tif, &m, 4)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + tif->tif_diroff=0; + break; + } + nextdir=nextnextdir; + } + } + } + else + { + if (tif->tif_header.big.tiff_diroff == tif->tif_diroff) + { + tif->tif_header.big.tiff_diroff = 0; + tif->tif_diroff = 0; + + TIFFSeekFile(tif,8,SEEK_SET); + if (!WriteOK(tif, &(tif->tif_header.big.tiff_diroff),8)) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error updating TIFF header"); + return (0); + } + } + else + { + uint64_t nextdir; + nextdir = tif->tif_header.big.tiff_diroff; + while(1) { + uint64_t dircount64; + uint16_t dircount; + uint64_t nextnextdir; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount64, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>0xFFFF) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on tag count failed, likely corrupt TIFF"); + return (0); + } + dircount=(uint16_t)dircount64; + (void) TIFFSeekFile(tif, + nextdir+8+dircount*20, SEEK_SET); + if (!ReadOK(tif, &nextnextdir, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&nextnextdir); + if (nextnextdir==tif->tif_diroff) + { + uint64_t m; + m=0; + (void) TIFFSeekFile(tif, + nextdir+8+dircount*20, SEEK_SET); + if (!WriteOK(tif, &m, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + tif->tif_diroff=0; + break; + } + nextdir=nextnextdir; + } + } + } + + /* + * Now use TIFFWriteDirectory() normally. + */ + + return TIFFWriteDirectory( tif ); +} + +static int +TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64_t* pdiroff) +{ + static const char module[] = "TIFFWriteDirectorySec"; + uint32_t ndir; + TIFFDirEntry* dir; + uint32_t dirsize; + void* dirmem; + uint32_t m; + if (tif->tif_mode == O_RDONLY) + return (1); + + _TIFFFillStriles( tif ); + + /* + * Clear write state so that subsequent images with + * different characteristics get the right buffers + * setup for them. + */ + if (imagedone) + { + if (tif->tif_flags & TIFF_POSTENCODE) + { + tif->tif_flags &= ~TIFF_POSTENCODE; + if (!(*tif->tif_postencode)(tif)) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Error post-encoding before directory write"); + return (0); + } + } + (*tif->tif_close)(tif); /* shutdown encoder */ + /* + * Flush any data that might have been written + * by the compression close+cleanup routines. But + * be careful not to write stuff if we didn't add data + * in the previous steps as the "rawcc" data may well be + * a previously read tile/strip in mixed read/write mode. + */ + if (tif->tif_rawcc > 0 + && (tif->tif_flags & TIFF_BEENWRITING) != 0 ) + { + if( !TIFFFlushData1(tif) ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Error flushing data before directory write"); + return (0); + } + } + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) + { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawcc = 0; + tif->tif_rawdatasize = 0; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = 0; + } + tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP); + } + dir=NULL; + dirmem=NULL; + dirsize=0; + while (1) + { + ndir=0; + if (isimage) + { + if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) + { + if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_IMAGEWIDTH,tif->tif_dir.td_imagewidth)) + goto bad; + if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_IMAGELENGTH,tif->tif_dir.td_imagelength)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS)) + { + if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_TILEWIDTH,tif->tif_dir.td_tilewidth)) + goto bad; + if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_TILELENGTH,tif->tif_dir.td_tilelength)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_RESOLUTION)) + { + if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_XRESOLUTION,tif->tif_dir.td_xresolution)) + goto bad; + if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_YRESOLUTION,tif->tif_dir.td_yresolution)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_POSITION)) + { + if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_XPOSITION,tif->tif_dir.td_xposition)) + goto bad; + if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_YPOSITION,tif->tif_dir.td_yposition)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_SUBFILETYPE)) + { + if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_SUBFILETYPE,tif->tif_dir.td_subfiletype)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) + { + if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_BITSPERSAMPLE,tif->tif_dir.td_bitspersample)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_COMPRESSION)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_COMPRESSION,tif->tif_dir.td_compression)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_PHOTOMETRIC,tif->tif_dir.td_photometric)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_THRESHHOLDING)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_THRESHHOLDING,tif->tif_dir.td_threshholding)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_FILLORDER)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_FILLORDER,tif->tif_dir.td_fillorder)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_ORIENTATION)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_ORIENTATION,tif->tif_dir.td_orientation)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_SAMPLESPERPIXEL,tif->tif_dir.td_samplesperpixel)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP)) + { + if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_ROWSPERSTRIP,tif->tif_dir.td_rowsperstrip)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE)) + { + if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_MINSAMPLEVALUE,tif->tif_dir.td_minsamplevalue)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE)) + { + if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_MAXSAMPLEVALUE,tif->tif_dir.td_maxsamplevalue)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_PLANARCONFIG)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_PLANARCONFIG,tif->tif_dir.td_planarconfig)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_RESOLUTIONUNIT,tif->tif_dir.td_resolutionunit)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_PAGENUMBER)) + { + if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_PAGENUMBER,2,&tif->tif_dir.td_pagenumber[0])) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_STRIPBYTECOUNTS)) + { + if (!isTiled(tif)) + { + if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount_p)) + goto bad; + } + else + { + if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount_p)) + goto bad; + } + } + if (TIFFFieldSet(tif,FIELD_STRIPOFFSETS)) + { + if (!isTiled(tif)) + { + /* td_stripoffset_p might be NULL in an odd OJPEG case. See + * tif_dirread.c around line 3634. + * XXX: OJPEG hack. + * If a) compression is OJPEG, b) it's not a tiled TIFF, + * and c) the number of strips is 1, + * then we tolerate the absence of stripoffsets tag, + * because, presumably, all required data is in the + * JpegInterchangeFormat stream. + * We can get here when using tiffset on such a file. + * See http://bugzilla.maptools.org/show_bug.cgi?id=2500 + */ + if (tif->tif_dir.td_stripoffset_p != NULL && + !TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset_p)) + goto bad; + } + else + { + if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset_p)) + goto bad; + } + } + if (TIFFFieldSet(tif,FIELD_COLORMAP)) + { + if (!TIFFWriteDirectoryTagColormap(tif,&ndir,dir)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_EXTRASAMPLES)) + { + if (tif->tif_dir.td_extrasamples) + { + uint16_t na; + uint16_t* nb; + TIFFGetFieldDefaulted(tif,TIFFTAG_EXTRASAMPLES,&na,&nb); + if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_EXTRASAMPLES,na,nb)) + goto bad; + } + } + if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT)) + { + if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_SAMPLEFORMAT,tif->tif_dir.td_sampleformat)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE)) + { + if (!TIFFWriteDirectoryTagSampleformatArray(tif,&ndir,dir,TIFFTAG_SMINSAMPLEVALUE,tif->tif_dir.td_samplesperpixel,tif->tif_dir.td_sminsamplevalue)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE)) + { + if (!TIFFWriteDirectoryTagSampleformatArray(tif,&ndir,dir,TIFFTAG_SMAXSAMPLEVALUE,tif->tif_dir.td_samplesperpixel,tif->tif_dir.td_smaxsamplevalue)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH)) + { + if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_IMAGEDEPTH,tif->tif_dir.td_imagedepth)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_TILEDEPTH)) + { + if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_TILEDEPTH,tif->tif_dir.td_tiledepth)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS)) + { + if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_HALFTONEHINTS,2,&tif->tif_dir.td_halftonehints[0])) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING)) + { + if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_YCBCRSUBSAMPLING,2,&tif->tif_dir.td_ycbcrsubsampling[0])) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING)) + { + if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_YCBCRPOSITIONING,tif->tif_dir.td_ycbcrpositioning)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_REFBLACKWHITE)) + { + if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,TIFFTAG_REFERENCEBLACKWHITE,6,tif->tif_dir.td_refblackwhite)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION)) + { + if (!TIFFWriteDirectoryTagTransferfunction(tif,&ndir,dir)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_INKNAMES)) + { + if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,TIFFTAG_INKNAMES,tif->tif_dir.td_inknameslen,tif->tif_dir.td_inknames)) + goto bad; + } + if (TIFFFieldSet(tif,FIELD_SUBIFD)) + { + if (!TIFFWriteDirectoryTagSubifd(tif,&ndir,dir)) + goto bad; + } + { + uint32_t n; + for (n=0; ntif_nfields; n++) { + const TIFFField* o; + o = tif->tif_fields[n]; + if ((o->field_bit>=FIELD_CODEC)&&(TIFFFieldSet(tif,o->field_bit))) + { + switch (o->get_field_type) + { + case TIFF_SETGET_ASCII: + { + uint32_t pa; + char* pb; + assert(o->field_type==TIFF_ASCII); + assert(o->field_readcount==TIFF_VARIABLE); + assert(o->field_passcount==0); + TIFFGetField(tif,o->field_tag,&pb); + pa=(uint32_t)(strlen(pb)); + if (!TIFFWriteDirectoryTagAscii(tif, &ndir, dir, (uint16_t)o->field_tag, pa, pb)) + goto bad; + } + break; + case TIFF_SETGET_UINT16: + { + uint16_t p; + assert(o->field_type==TIFF_SHORT); + assert(o->field_readcount==1); + assert(o->field_passcount==0); + TIFFGetField(tif,o->field_tag,&p); + if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir, (uint16_t)o->field_tag, p)) + goto bad; + } + break; + case TIFF_SETGET_UINT32: + { + uint32_t p; + assert(o->field_type==TIFF_LONG); + assert(o->field_readcount==1); + assert(o->field_passcount==0); + TIFFGetField(tif,o->field_tag,&p); + if (!TIFFWriteDirectoryTagLong(tif, &ndir, dir, (uint16_t)o->field_tag, p)) + goto bad; + } + break; + case TIFF_SETGET_C32_UINT8: + { + uint32_t pa; + void* pb; + assert(o->field_type==TIFF_UNDEFINED); + assert(o->field_readcount==TIFF_VARIABLE2); + assert(o->field_passcount==1); + TIFFGetField(tif,o->field_tag,&pa,&pb); + if (!TIFFWriteDirectoryTagUndefinedArray(tif, &ndir, dir, (uint16_t)o->field_tag, pa, pb)) + goto bad; + } + break; + default: + TIFFErrorExt(tif->tif_clientdata,module, + "Cannot write tag %"PRIu32" (%s)", + TIFFFieldTag(o), + o->field_name ? o->field_name : "unknown"); + goto bad; + } + } + } + } + } + for (m=0; m<(uint32_t)(tif->tif_dir.td_customValueCount); m++) + { + uint16_t tag = (uint16_t)tif->tif_dir.td_customValues[m].info->field_tag; + uint32_t count = tif->tif_dir.td_customValues[m].count; + switch (tif->tif_dir.td_customValues[m].info->field_type) + { + case TIFF_ASCII: + if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_UNDEFINED: + if (!TIFFWriteDirectoryTagUndefinedArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_BYTE: + if (!TIFFWriteDirectoryTagByteArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SBYTE: + if (!TIFFWriteDirectoryTagSbyteArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SHORT: + if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SSHORT: + if (!TIFFWriteDirectoryTagSshortArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_LONG: + if (!TIFFWriteDirectoryTagLongArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SLONG: + if (!TIFFWriteDirectoryTagSlongArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_LONG8: + if (!TIFFWriteDirectoryTagLong8Array(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_SLONG8: + if (!TIFFWriteDirectoryTagSlong8Array(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_RATIONAL: + { + /*-- Rational2Double: For Rationals evaluate "set_field_type" to determine internal storage size. */ + int tv_size; + tv_size = _TIFFSetGetFieldSize(tif->tif_dir.td_customValues[m].info->set_field_type); + if (tv_size == 8) { + if (!TIFFWriteDirectoryTagRationalDoubleArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + } else { + /*-- default should be tv_size == 4 */ + if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + /*-- ToDo: After Testing, this should be removed and tv_size==4 should be set as default. */ + if (tv_size != 4) { + TIFFErrorExt(0,"TIFFLib: _TIFFWriteDirectorySec()", "Rational2Double: .set_field_type in not 4 but %d", tv_size); + } + } + } + break; + case TIFF_SRATIONAL: + { + /*-- Rational2Double: For Rationals evaluate "set_field_type" to determine internal storage size. */ + int tv_size; + tv_size = _TIFFSetGetFieldSize(tif->tif_dir.td_customValues[m].info->set_field_type); + if (tv_size == 8) { + if (!TIFFWriteDirectoryTagSrationalDoubleArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + } else { + /*-- default should be tv_size == 4 */ + if (!TIFFWriteDirectoryTagSrationalArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + /*-- ToDo: After Testing, this should be removed and tv_size==4 should be set as default. */ + if (tv_size != 4) { + TIFFErrorExt(0,"TIFFLib: _TIFFWriteDirectorySec()", "Rational2Double: .set_field_type in not 4 but %d", tv_size); + } + } + } + break; + case TIFF_FLOAT: + if (!TIFFWriteDirectoryTagFloatArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_DOUBLE: + if (!TIFFWriteDirectoryTagDoubleArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_IFD: + if (!TIFFWriteDirectoryTagIfdArray(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + case TIFF_IFD8: + if (!TIFFWriteDirectoryTagIfdIfd8Array(tif,&ndir,dir,tag,count,tif->tif_dir.td_customValues[m].value)) + goto bad; + break; + default: + assert(0); /* we should never get here */ + break; + } + } + if (dir!=NULL) + break; + dir=_TIFFmalloc(ndir*sizeof(TIFFDirEntry)); + if (dir==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + goto bad; + } + if (isimage) + { + if ((tif->tif_diroff==0)&&(!TIFFLinkDirectory(tif))) + goto bad; + } + else + tif->tif_diroff=(TIFFSeekFile(tif,0,SEEK_END)+1)&(~((toff_t)1)); + if (pdiroff!=NULL) + *pdiroff=tif->tif_diroff; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + dirsize=2+ndir*12+4; + else + dirsize=8+ndir*20+8; + tif->tif_dataoff=tif->tif_diroff+dirsize; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + tif->tif_dataoff=(uint32_t)tif->tif_dataoff; + if ((tif->tif_dataofftif_diroff)||(tif->tif_dataoff<(uint64_t)dirsize)) + { + TIFFErrorExt(tif->tif_clientdata,module,"Maximum TIFF file size exceeded"); + goto bad; + } + if (tif->tif_dataoff&1) + tif->tif_dataoff++; + if (isimage) + tif->tif_curdir++; + } + if (isimage) + { + if (TIFFFieldSet(tif,FIELD_SUBIFD)&&(tif->tif_subifdoff==0)) + { + uint32_t na; + TIFFDirEntry* nb; + for (na=0, nb=dir; ; na++, nb++) + { + if( na == ndir ) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Cannot find SubIFD tag"); + goto bad; + } + if (nb->tdir_tag==TIFFTAG_SUBIFD) + break; + } + if (!(tif->tif_flags&TIFF_BIGTIFF)) + tif->tif_subifdoff=tif->tif_diroff+2+na*12+8; + else + tif->tif_subifdoff=tif->tif_diroff+8+na*20+12; + } + } + dirmem=_TIFFmalloc(dirsize); + if (dirmem==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + goto bad; + } + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint8_t* n; + uint32_t nTmp; + TIFFDirEntry* o; + n=dirmem; + *(uint16_t*)n=(uint16_t)ndir; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)n); + n+=2; + o=dir; + for (m=0; mtdir_tag; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)n); + n+=2; + *(uint16_t*)n=o->tdir_type; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)n); + n+=2; + nTmp = (uint32_t)o->tdir_count; + _TIFFmemcpy(n,&nTmp,4); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)n); + n+=4; + /* This is correct. The data has been */ + /* swabbed previously in TIFFWriteDirectoryTagData */ + _TIFFmemcpy(n,&o->tdir_offset,4); + n+=4; + o++; + } + nTmp = (uint32_t)tif->tif_nextdiroff; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&nTmp); + _TIFFmemcpy(n,&nTmp,4); + } + else + { + uint8_t* n; + TIFFDirEntry* o; + n=dirmem; + *(uint64_t*)n=ndir; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)n); + n+=8; + o=dir; + for (m=0; mtdir_tag; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)n); + n+=2; + *(uint16_t*)n=o->tdir_type; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)n); + n+=2; + _TIFFmemcpy(n,&o->tdir_count,8); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)n); + n+=8; + _TIFFmemcpy(n,&o->tdir_offset,8); + n+=8; + o++; + } + _TIFFmemcpy(n,&tif->tif_nextdiroff,8); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)n); + } + _TIFFfree(dir); + dir=NULL; + if (!SeekOK(tif,tif->tif_diroff)) + { + TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory"); + goto bad; + } + if (!WriteOK(tif,dirmem,(tmsize_t)dirsize)) + { + TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory"); + goto bad; + } + _TIFFfree(dirmem); + if (imagedone) + { + TIFFFreeDirectory(tif); + tif->tif_flags &= ~TIFF_DIRTYDIRECT; + tif->tif_flags &= ~TIFF_DIRTYSTRIP; + (*tif->tif_cleanup)(tif); + /* + * Reset directory-related state for subsequent + * directories. + */ + TIFFCreateDirectory(tif); + } + return(1); +bad: + if (dir!=NULL) + _TIFFfree(dir); + if (dirmem!=NULL) + _TIFFfree(dirmem); + return(0); +} + +static int8_t TIFFClampDoubleToInt8(double val ) +{ + if( val > 127 ) + return 127; + if( val < -128 || val != val ) + return -128; + return (int8_t)val; +} + +static int16_t TIFFClampDoubleToInt16(double val ) +{ + if( val > 32767 ) + return 32767; + if( val < -32768 || val != val ) + return -32768; + return (int16_t)val; +} + +static int32_t TIFFClampDoubleToInt32(double val ) +{ + if( val > 0x7FFFFFFF ) + return 0x7FFFFFFF; + if( val < -0x7FFFFFFF-1 || val != val ) + return -0x7FFFFFFF-1; + return (int32_t)val; +} + +static uint8_t TIFFClampDoubleToUInt8(double val ) +{ + if( val < 0 ) + return 0; + if( val > 255 || val != val ) + return 255; + return (uint8_t)val; +} + +static uint16_t TIFFClampDoubleToUInt16(double val ) +{ + if( val < 0 ) + return 0; + if( val > 65535 || val != val ) + return 65535; + return (uint16_t)val; +} + +static uint32_t TIFFClampDoubleToUInt32(double val ) +{ + if( val < 0 ) + return 0; + if( val > 0xFFFFFFFFU || val != val ) + return 0xFFFFFFFFU; + return (uint32_t)val; +} + +static int +TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value) +{ + static const char module[] = "TIFFWriteDirectoryTagSampleformatArray"; + void* conv; + uint32_t i; + int ok; + conv = _TIFFmalloc(count*sizeof(double)); + if (conv == NULL) + { + TIFFErrorExt(tif->tif_clientdata, module, "Out of memory"); + return (0); + } + + switch (tif->tif_dir.td_sampleformat) + { + case SAMPLEFORMAT_IEEEFP: + if (tif->tif_dir.td_bitspersample<=32) + { + for (i = 0; i < count; ++i) + ((float*)conv)[i] = _TIFFClampDoubleToFloat(value[i]); + ok = TIFFWriteDirectoryTagFloatArray(tif,ndir,dir,tag,count,(float*)conv); + } + else + { + ok = TIFFWriteDirectoryTagDoubleArray(tif,ndir,dir,tag,count,value); + } + break; + case SAMPLEFORMAT_INT: + if (tif->tif_dir.td_bitspersample<=8) + { + for (i = 0; i < count; ++i) + ((int8_t*)conv)[i] = TIFFClampDoubleToInt8(value[i]); + ok = TIFFWriteDirectoryTagSbyteArray(tif,ndir,dir,tag,count,(int8_t*)conv); + } + else if (tif->tif_dir.td_bitspersample<=16) + { + for (i = 0; i < count; ++i) + ((int16_t*)conv)[i] = TIFFClampDoubleToInt16(value[i]); + ok = TIFFWriteDirectoryTagSshortArray(tif,ndir,dir,tag,count,(int16_t*)conv); + } + else + { + for (i = 0; i < count; ++i) + ((int32_t*)conv)[i] = TIFFClampDoubleToInt32(value[i]); + ok = TIFFWriteDirectoryTagSlongArray(tif,ndir,dir,tag,count,(int32_t*)conv); + } + break; + case SAMPLEFORMAT_UINT: + if (tif->tif_dir.td_bitspersample<=8) + { + for (i = 0; i < count; ++i) + ((uint8_t*)conv)[i] = TIFFClampDoubleToUInt8(value[i]); + ok = TIFFWriteDirectoryTagByteArray(tif,ndir,dir,tag,count,(uint8_t*)conv); + } + else if (tif->tif_dir.td_bitspersample<=16) + { + for (i = 0; i < count; ++i) + ((uint16_t*)conv)[i] = TIFFClampDoubleToUInt16(value[i]); + ok = TIFFWriteDirectoryTagShortArray(tif,ndir,dir,tag,count,(uint16_t*)conv); + } + else + { + for (i = 0; i < count; ++i) + ((uint32_t*)conv)[i] = TIFFClampDoubleToUInt32(value[i]); + ok = TIFFWriteDirectoryTagLongArray(tif,ndir,dir,tag,count,(uint32_t*)conv); + } + break; + default: + ok = 0; + } + + _TIFFfree(conv); + return (ok); +} + +#if 0 +static int +TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value) +{ + switch (tif->tif_dir.td_sampleformat) + { + case SAMPLEFORMAT_IEEEFP: + if (tif->tif_dir.td_bitspersample<=32) + return(TIFFWriteDirectoryTagFloatPerSample(tif,ndir,dir,tag,(float)value)); + else + return(TIFFWriteDirectoryTagDoublePerSample(tif,ndir,dir,tag,value)); + case SAMPLEFORMAT_INT: + if (tif->tif_dir.td_bitspersample<=8) + return(TIFFWriteDirectoryTagSbytePerSample(tif,ndir,dir,tag,(int8_t)value)); + else if (tif->tif_dir.td_bitspersample<=16) + return(TIFFWriteDirectoryTagSshortPerSample(tif,ndir,dir,tag,(int16_t)value)); + else + return(TIFFWriteDirectoryTagSlongPerSample(tif,ndir,dir,tag,(int32_t)value)); + case SAMPLEFORMAT_UINT: + if (tif->tif_dir.td_bitspersample<=8) + return(TIFFWriteDirectoryTagBytePerSample(tif,ndir,dir,tag,(uint8_t)value)); + else if (tif->tif_dir.td_bitspersample<=16) + return(TIFFWriteDirectoryTagShortPerSample(tif,ndir,dir,tag,(uint16_t)value)); + else + return(TIFFWriteDirectoryTagLongPerSample(tif,ndir,dir,tag,(uint32_t)value)); + default: + return(1); + } +} +#endif + +static int +TIFFWriteDirectoryTagAscii(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, char* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedAscii(tif,ndir,dir,tag,count,value)); +} + +static int +TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint8_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedUndefinedArray(tif,ndir,dir,tag,count,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagByte(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint8_t value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedByte(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint8_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int +TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint8_t value) +{ + static const char module[] = "TIFFWriteDirectoryTagBytePerSample"; + uint8_t* m; + uint8_t* na; + uint16_t nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint8_t)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +#ifdef notdef +static int +TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int8_t value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSbyte(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int8_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int +TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int8_t value) +{ + static const char module[] = "TIFFWriteDirectoryTagSbytePerSample"; + int8_t* m; + int8_t* na; + uint16_t nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int8_t)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +static int +TIFFWriteDirectoryTagShort(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint16_t value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,value)); +} + +static int +TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint16_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,value)); +} + +static int +TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint16_t value) +{ + static const char module[] = "TIFFWriteDirectoryTagShortPerSample"; + uint16_t* m; + uint16_t* na; + uint16_t nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint16_t)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagSshort(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int16_t value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSshort(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int16_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int +TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int16_t value) +{ + static const char module[] = "TIFFWriteDirectoryTagSshortPerSample"; + int16_t* m; + int16_t* na; + uint16_t nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int16_t)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +static int +TIFFWriteDirectoryTagLong(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value)); +} + +static int +TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint32_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int +TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t value) +{ + static const char module[] = "TIFFWriteDirectoryTagLongPerSample"; + uint32_t* m; + uint32_t* na; + uint16_t nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint32_t)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +#ifdef notdef +static int +TIFFWriteDirectoryTagSlong(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int32_t value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSlong(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int32_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int +TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int32_t value) +{ + static const char module[] = "TIFFWriteDirectoryTagSlongPerSample"; + int32_t* m; + int32_t* na; + uint16_t nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int32_t)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +#ifdef notdef +static int +TIFFWriteDirectoryTagLong8(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint64_t value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedLong8(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int64_t value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSlong8(tif,ndir,dir,tag,value)); +} +#endif + +static int +TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int64_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSlong8Array(tif,ndir,dir,tag,count,value)); +} + +static int +TIFFWriteDirectoryTagRational(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedRational(tif,ndir,dir,tag,value)); +} + +static int +TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedRationalArray(tif,ndir,dir,tag,count,value)); +} + +static int +TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSrationalArray(tif,ndir,dir,tag,count,value)); +} + +/*-- Rational2Double: additional write functions */ +static int +TIFFWriteDirectoryTagRationalDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedRationalDoubleArray(tif,ndir,dir,tag,count,value)); +} + +static int +TIFFWriteDirectoryTagSrationalDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedSrationalDoubleArray(tif,ndir,dir,tag,count,value)); +} + +#ifdef notdef +static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, float value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedFloat(tif,ndir,dir,tag,value)); +} +#endif + +static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, float value) +{ + static const char module[] = "TIFFWriteDirectoryTagFloatPerSample"; + float* m; + float* na; + uint16_t nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(float)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +#ifdef notdef +static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedDouble(tif,ndir,dir,tag,value)); +} +#endif + +static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,count,value)); +} + +#if 0 +static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value) +{ + static const char module[] = "TIFFWriteDirectoryTagDoublePerSample"; + double* m; + double* na; + uint16_t nb; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(double)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=m, nb=0; nbtif_dir.td_samplesperpixel; na++, nb++) + *na=value; + o=TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m); + _TIFFfree(m); + return(o); +} +#endif + +static int +TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint32_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + return(TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,tag,count,value)); +} +#endif + +static int +TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t value) +{ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + if (value<=0xFFFF) + return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,(uint16_t)value)); + else + return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value)); +} + +static int _WriteAsType(TIFF* tif, uint64_t strile_size, uint64_t uncompressed_threshold) +{ + const uint16_t compression = tif->tif_dir.td_compression; + if ( compression == COMPRESSION_NONE ) + { + return strile_size > uncompressed_threshold; + } + else if ( compression == COMPRESSION_JPEG || + compression == COMPRESSION_LZW || + compression == COMPRESSION_ADOBE_DEFLATE || + compression == COMPRESSION_LZMA || + compression == COMPRESSION_LERC || + compression == COMPRESSION_ZSTD || + compression == COMPRESSION_WEBP ) + { + /* For a few select compression types, we assume that in the worst */ + /* case the compressed size will be 10 times the uncompressed size */ + /* This is overly pessismistic ! */ + return strile_size >= uncompressed_threshold / 10; + } + return 1; +} + +static int WriteAsLong8(TIFF* tif, uint64_t strile_size) +{ + return _WriteAsType(tif, strile_size, 0xFFFFFFFFU); +} + +static int WriteAsLong4(TIFF* tif, uint64_t strile_size) +{ + return _WriteAsType(tif, strile_size, 0xFFFFU); +} + +/************************************************************************/ +/* TIFFWriteDirectoryTagLongLong8Array() */ +/* */ +/* Write out LONG8 array and write a SHORT/LONG/LONG8 depending */ +/* on strile size and Classic/BigTIFF mode. */ +/************************************************************************/ + +static int +TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value) +{ + static const char module[] = "TIFFWriteDirectoryTagLongLong8Array"; + int o; + int write_aslong4; + + /* is this just a counting pass? */ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + + if( tif->tif_dir.td_deferstrilearraywriting ) + { + return TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_NOTYPE, 0, 0, NULL); + } + + if( tif->tif_flags&TIFF_BIGTIFF ) + { + int write_aslong8 = 1; + /* In the case of ByteCounts array, we may be able to write them on */ + /* LONG if the strip/tilesize is not too big. */ + /* Also do that for count > 1 in the case someone would want to create */ + /* a single-strip file with a growing height, in which case using */ + /* LONG8 will be safer. */ + if( count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS ) + { + write_aslong8 = WriteAsLong8(tif, TIFFStripSize64(tif)); + } + else if( count > 1 && tag == TIFFTAG_TILEBYTECOUNTS ) + { + write_aslong8 = WriteAsLong8(tif, TIFFTileSize64(tif)); + } + if( write_aslong8 ) + { + return TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir, + tag,count,value); + } + } + + write_aslong4 = 1; + if( count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS ) + { + write_aslong4 = WriteAsLong4(tif, TIFFStripSize64(tif)); + } + else if( count > 1 && tag == TIFFTAG_TILEBYTECOUNTS ) + { + write_aslong4 = WriteAsLong4(tif, TIFFTileSize64(tif)); + } + if( write_aslong4 ) + { + /* + ** For classic tiff we want to verify everything is in range for LONG + ** and convert to long format. + */ + + uint32_t* p = _TIFFmalloc(count * sizeof(uint32_t)); + uint32_t* q; + uint64_t* ma; + uint32_t mb; + + if (p==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + + for (q=p, ma=value, mb=0; mb0xFFFFFFFF) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Attempt to write value larger than 0xFFFFFFFF in LONG array."); + _TIFFfree(p); + return(0); + } + *q= (uint32_t)(*ma); + } + + o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p); + _TIFFfree(p); + } + else + { + uint16_t* p = _TIFFmalloc(count * sizeof(uint16_t)); + uint16_t* q; + uint64_t* ma; + uint32_t mb; + + if (p==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + + for (q=p, ma=value, mb=0; mb0xFFFF) + { + /* Should not happen normally given the check we did before */ + TIFFErrorExt(tif->tif_clientdata,module, + "Attempt to write value larger than 0xFFFF in SHORT array."); + _TIFFfree(p); + return(0); + } + *q= (uint16_t)(*ma); + } + + o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,p); + _TIFFfree(p); + } + + return(o); +} + +/************************************************************************/ +/* TIFFWriteDirectoryTagIfdIfd8Array() */ +/* */ +/* Write either IFD8 or IFD array depending on file type. */ +/************************************************************************/ + +static int +TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value) +{ + static const char module[] = "TIFFWriteDirectoryTagIfdIfd8Array"; + uint64_t* ma; + uint32_t mb; + uint32_t* p; + uint32_t* q; + int o; + + /* is this just a counting pass? */ + if (dir==NULL) + { + (*ndir)++; + return(1); + } + + /* We always write IFD8 for BigTIFF, no checking needed. */ + if( tif->tif_flags&TIFF_BIGTIFF ) + return TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir, + tag,count,value); + + /* + ** For classic tiff we want to verify everything is in range for IFD + ** and convert to long format. + */ + + p = _TIFFmalloc(count*sizeof(uint32_t)); + if (p==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + + for (q=p, ma=value, mb=0; mb0xFFFFFFFF) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file."); + _TIFFfree(p); + return(0); + } + *q= (uint32_t)(*ma); + } + + o=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,p); + _TIFFfree(p); + + return(o); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value) +{ + static const char module[] = "TIFFWriteDirectoryTagShortLongLong8Array"; + uint64_t* ma; + uint32_t mb; + uint8_t n; + int o; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + n=0; + for (ma=value, mb=0; mb0xFFFF)) + n=1; + if ((n==1)&&(*ma>0xFFFFFFFF)) + { + n=2; + break; + } + } + if (n==0) + { + uint16_t* p; + uint16_t* q; + p=_TIFFmalloc(count*sizeof(uint16_t)); + if (p==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (ma=value, mb=0, q=p; mbtif_clientdata,module,"Out of memory"); + return(0); + } + for (ma=value, mb=0, q=p; mbtif_dir.td_bitspersample); + n=_TIFFmalloc(3*m*sizeof(uint16_t)); + if (n==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + _TIFFmemcpy(&n[0],tif->tif_dir.td_colormap[0],m*sizeof(uint16_t)); + _TIFFmemcpy(&n[m],tif->tif_dir.td_colormap[1],m*sizeof(uint16_t)); + _TIFFmemcpy(&n[2*m],tif->tif_dir.td_colormap[2],m*sizeof(uint16_t)); + o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_COLORMAP,3*m,n); + _TIFFfree(n); + return(o); +} + +static int +TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir) +{ + static const char module[] = "TIFFWriteDirectoryTagTransferfunction"; + uint32_t m; + uint16_t n; + uint16_t* o; + int p; + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=(1<tif_dir.td_bitspersample); + n=tif->tif_dir.td_samplesperpixel-tif->tif_dir.td_extrasamples; + /* + * Check if the table can be written as a single column, + * or if it must be written as 3 columns. Note that we + * write a 3-column tag if there are 2 samples/pixel and + * a single column of data won't suffice--hmm. + */ + if (n>3) + n=3; + if (n==3) + { + if (tif->tif_dir.td_transferfunction[2] == NULL || + !_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16_t))) + n=2; + } + if (n==2) + { + if (tif->tif_dir.td_transferfunction[1] == NULL || + !_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16_t))) + n=1; + } + if (n==0) + n=1; + o=_TIFFmalloc(n*m*sizeof(uint16_t)); + if (o==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + _TIFFmemcpy(&o[0],tif->tif_dir.td_transferfunction[0],m*sizeof(uint16_t)); + if (n>1) + _TIFFmemcpy(&o[m],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16_t)); + if (n>2) + _TIFFmemcpy(&o[2*m],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16_t)); + p=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_TRANSFERFUNCTION,n*m,o); + _TIFFfree(o); + return(p); +} + +static int +TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir) +{ + static const char module[] = "TIFFWriteDirectoryTagSubifd"; + uint64_t m; + int n; + if (tif->tif_dir.td_nsubifd==0) + return(1); + if (dir==NULL) + { + (*ndir)++; + return(1); + } + m=tif->tif_dataoff; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32_t* o; + uint64_t* pa; + uint32_t* pb; + uint16_t p; + o=_TIFFmalloc(tif->tif_dir.td_nsubifd*sizeof(uint32_t)); + if (o==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + pa=tif->tif_dir.td_subifd; + pb=o; + for (p=0; p < tif->tif_dir.td_nsubifd; p++) + { + assert(pa != 0); + + /* Could happen if an classicTIFF has a SubIFD of type LONG8 (which is illegal) */ + if( *pa > 0xFFFFFFFFUL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Illegal value for SubIFD tag"); + _TIFFfree(o); + return(0); + } + *pb++=(uint32_t)(*pa++); + } + n=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,o); + _TIFFfree(o); + } + else + n=TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,tif->tif_dir.td_subifd); + if (!n) + return(0); + /* + * Total hack: if this directory includes a SubIFD + * tag then force the next directories to be + * written as ``sub directories'' of this one. This + * is used to write things like thumbnails and + * image masks that one wants to keep out of the + * normal directory linkage access mechanism. + */ + tif->tif_flags|=TIFF_INSUBIFD; + tif->tif_nsubifd=tif->tif_dir.td_nsubifd; + if (tif->tif_dir.td_nsubifd==1) + tif->tif_subifdoff=0; + else + tif->tif_subifdoff=m; + return(1); +} + +static int +TIFFWriteDirectoryTagCheckedAscii(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, char* value) +{ + assert(sizeof(char)==1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_ASCII,count,count,value)); +} + +static int +TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint8_t* value) +{ + assert(sizeof(uint8_t) == 1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_UNDEFINED,count,count,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint8_t value) +{ + assert(sizeof(uint8_t)==1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,1,1,&value)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint8_t* value) +{ + assert(sizeof(uint8_t) == 1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,count,count,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int8_t value) +{ + assert(sizeof(int8_t)==1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,1,1,&value)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int8_t* value) +{ + assert(sizeof(int8_t) == 1); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,count,count,value)); +} + +static int +TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint16_t value) +{ + uint16_t m; + assert(sizeof(uint16_t) == 2); + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort(&m); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SHORT,1,2,&m)); +} + +static int +TIFFWriteDirectoryTagCheckedShortArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint16_t* value) +{ + assert(count<0x80000000); + assert(sizeof(uint16_t) == 2); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfShort(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SHORT,count,count*2,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int16_t value) +{ + int16_t m; + assert(sizeof(int16_t)==2); + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort((uint16_t*)(&m)); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,1,2,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int16_t* value) +{ + assert(count<0x80000000); + assert(sizeof(int16_t) == 2); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfShort((uint16_t*)value, count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,count,count*2,value)); +} + +static int +TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t value) +{ + uint32_t m; + assert(sizeof(uint32_t) == 4); + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&m); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG,1,4,&m)); +} + +static int +TIFFWriteDirectoryTagCheckedLongArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint32_t* value) +{ + assert(count<0x40000000); + assert(sizeof(uint32_t) == 4); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG,count,count*4,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int32_t value) +{ + int32_t m; + assert(sizeof(int32_t)==4); + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong((uint32_t*)(&m)); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,1,4,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int32_t* value) +{ + assert(count<0x40000000); + assert(sizeof(int32_t) == 4); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32_t*)value, count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,count,count*4,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint64_t value) +{ + uint64_t m; + assert(sizeof(uint64_t)==8); + if( !(tif->tif_flags&TIFF_BIGTIFF) ) { + TIFFErrorExt(tif->tif_clientdata,"TIFFWriteDirectoryTagCheckedLong8","LONG8 not allowed for ClassicTIFF"); + return(0); + } + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(&m); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,1,8,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value) +{ + assert(count<0x20000000); + assert(sizeof(uint64_t) == 8); + if( !(tif->tif_flags&TIFF_BIGTIFF) ) { + TIFFErrorExt(tif->tif_clientdata,"TIFFWriteDirectoryTagCheckedLong8Array","LONG8 not allowed for ClassicTIFF"); + return(0); + } + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,count,count*8,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, int64_t value) +{ + int64_t m; + assert(sizeof(int64_t)==8); + if( !(tif->tif_flags&TIFF_BIGTIFF) ) { + TIFFErrorExt(tif->tif_clientdata,"TIFFWriteDirectoryTagCheckedSlong8","SLONG8 not allowed for ClassicTIFF"); + return(0); + } + m=value; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8((uint64_t*)(&m)); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,1,8,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, int64_t* value) +{ + assert(count<0x20000000); + assert(sizeof(int64_t) == 8); + if( !(tif->tif_flags&TIFF_BIGTIFF) ) { + TIFFErrorExt(tif->tif_clientdata,"TIFFWriteDirectoryTagCheckedSlong8Array","SLONG8 not allowed for ClassicTIFF"); + return(0); + } + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8((uint64_t*)value, count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,count,count*8,value)); +} + +static int +TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value) +{ + static const char module[] = "TIFFWriteDirectoryTagCheckedRational"; + uint32_t m[2]; + assert(sizeof(uint32_t) == 4); + if (value < 0) + { + TIFFErrorExt(tif->tif_clientdata, module, "Negative value is illegal"); + return 0; + } + else if (value != value) + { + TIFFErrorExt(tif->tif_clientdata, module, "Not-a-number value is illegal"); + return 0; + } +#ifdef not_def + else if (value==0.0) + { + m[0]=0; + m[1]=1; + } + else if (value <= 0xFFFFFFFFU && value==(double)(uint32_t)value) + { + m[0]=(uint32_t)value; + m[1]=1; + } + else if (value<1.0) + { + m[0]=(uint32_t)(value*0xFFFFFFFF); + m[1]=0xFFFFFFFF; + } + else + { + m[0]=0xFFFFFFFF; + m[1]=(uint32_t)(0xFFFFFFFF/value); + } +#else + /*--Rational2Double: New function also used for non-custom rational tags. + * However, could be omitted here, because TIFFWriteDirectoryTagCheckedRational() is not used by code for custom tags, + * only by code for named-tiff-tags like FIELD_RESOLUTION and FIELD_POSITION */ + else { + DoubleToRational(value, &m[0], &m[1]); + } +#endif + + if (tif->tif_flags&TIFF_SWAB) + { + TIFFSwabLong(&m[0]); + TIFFSwabLong(&m[1]); + } + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,1,8,&m[0])); +} + +static int +TIFFWriteDirectoryTagCheckedRationalArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value) +{ + static const char module[] = "TIFFWriteDirectoryTagCheckedRationalArray"; + uint32_t* m; + float* na; + uint32_t* nb; + uint32_t nc; + int o; + assert(sizeof(uint32_t) == 4); + m=_TIFFmalloc(count*2*sizeof(uint32_t)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=value, nb=m, nc=0; nc= 0 && *na <= (float)0xFFFFFFFFU && + *na==(float)(uint32_t)(*na)) + { + nb[0]=(uint32_t)(*na); + nb[1]=1; + } + else if (*na<1.0) + { + nb[0]=(uint32_t)((double)(*na)*0xFFFFFFFF); + nb[1]=0xFFFFFFFF; + } + else + { + nb[0]=0xFFFFFFFF; + nb[1]=(uint32_t)((double)0xFFFFFFFF/(*na)); + } +#else + /*-- Rational2Double: Also for float precision accuracy is sometimes enhanced --*/ + DoubleToRational(*na, &nb[0], &nb[1]); +#endif + } + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(m,count*2); + o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,count,count*8,&m[0]); + _TIFFfree(m); + return(o); +} + +static int +TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value) +{ + static const char module[] = "TIFFWriteDirectoryTagCheckedSrationalArray"; + int32_t* m; + float* na; + int32_t* nb; + uint32_t nc; + int o; + assert(sizeof(int32_t) == 4); + m=_TIFFmalloc(count*2*sizeof(int32_t)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=value, nb=m, nc=0; nc-1.0) + { + nb[0]=-(int32_t)((double)(-*na)*0x7FFFFFFF); + nb[1]=0x7FFFFFFF; + } + else + { + nb[0]=-0x7FFFFFFF; + nb[1]=(int32_t)((double)0x7FFFFFFF/(-*na)); + } + } + else + { + if (*na==(int32_t)(*na)) + { + nb[0]=(int32_t)(*na); + nb[1]=1; + } + else if (*na<1.0) + { + nb[0]=(int32_t)((double)(*na)*0x7FFFFFFF); + nb[1]=0x7FFFFFFF; + } + else + { + nb[0]=0x7FFFFFFF; + nb[1]=(int32_t)((double)0x7FFFFFFF/(*na)); + } + } +#else + /*-- Rational2Double: Also for float precision accuracy is sometimes enhanced --*/ + DoubleToSrational(*na, &nb[0], &nb[1]); +#endif + } + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32_t*)m, count * 2); + o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SRATIONAL,count,count*8,&m[0]); + _TIFFfree(m); + return(o); +} + +/*-- Rational2Double: additional write functions for double arrays */ +static int +TIFFWriteDirectoryTagCheckedRationalDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value) +{ + static const char module[] = "TIFFWriteDirectoryTagCheckedRationalDoubleArray"; + uint32_t* m; + double* na; + uint32_t* nb; + uint32_t nc; + int o; + assert(sizeof(uint32_t) == 4); + m=_TIFFmalloc(count*2*sizeof(uint32_t)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=value, nb=m, nc=0; nctif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(m,count*2); + o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,count,count*8,&m[0]); + _TIFFfree(m); + return(o); +} /*-- TIFFWriteDirectoryTagCheckedRationalDoubleArray() ------- */ + +static int +TIFFWriteDirectoryTagCheckedSrationalDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value) +{ + static const char module[] = "TIFFWriteDirectoryTagCheckedSrationalDoubleArray"; + int32_t* m; + double* na; + int32_t* nb; + uint32_t nc; + int o; + assert(sizeof(int32_t) == 4); + m=_TIFFmalloc(count*2*sizeof(int32_t)); + if (m==NULL) + { + TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); + return(0); + } + for (na=value, nb=m, nc=0; nctif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong((uint32_t*)m, count * 2); + o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SRATIONAL,count,count*8,&m[0]); + _TIFFfree(m); + return(o); +} /*--- TIFFWriteDirectoryTagCheckedSrationalDoubleArray() -------- */ + +#if 0 +static +void DoubleToRational_direct(double value, unsigned long *num, unsigned long *denom) +{ + /*--- OLD Code for debugging and comparison ---- */ + /* code merged from TIFFWriteDirectoryTagCheckedRationalArray() and TIFFWriteDirectoryTagCheckedRational() */ + + /* First check for zero and also check for negative numbers (which are illegal for RATIONAL) + * and also check for "not-a-number". In each case just set this to zero to support also rational-arrays. + */ + if (value<=0.0 || value != value) + { + *num=0; + *denom=1; + } + else if (value <= 0xFFFFFFFFU && (value==(double)(uint32_t)(value))) /* check for integer values */ + { + *num=(uint32_t)(value); + *denom=1; + } + else if (value<1.0) + { + *num = (uint32_t)((value) * (double)0xFFFFFFFFU); + *denom=0xFFFFFFFFU; + } + else + { + *num=0xFFFFFFFFU; + *denom=(uint32_t)((double)0xFFFFFFFFU/(value)); + } +} /*-- DoubleToRational_direct() -------------- */ +#endif + +#if 0 +static +void DoubleToSrational_direct(double value, long *num, long *denom) +{ + /*--- OLD Code for debugging and comparison -- SIGNED-version ----*/ + /* code was amended from original TIFFWriteDirectoryTagCheckedSrationalArray() */ + + /* First check for zero and also check for negative numbers (which are illegal for RATIONAL) + * and also check for "not-a-number". In each case just set this to zero to support also rational-arrays. + */ + if (value<0.0) + { + if (value==(int32_t)(value)) + { + *num=(int32_t)(value); + *denom=1; + } + else if (value>-1.0) + { + *num=-(int32_t)((-value) * (double)0x7FFFFFFF); + *denom=0x7FFFFFFF; + } + else + { + *num=-0x7FFFFFFF; + *denom=(int32_t)((double)0x7FFFFFFF / (-value)); + } + } + else + { + if (value==(int32_t)(value)) + { + *num=(int32_t)(value); + *denom=1; + } + else if (value<1.0) + { + *num=(int32_t)((value) *(double)0x7FFFFFFF); + *denom=0x7FFFFFFF; + } + else + { + *num=0x7FFFFFFF; + *denom=(int32_t)((double)0x7FFFFFFF / (value)); + } + } +} /*-- DoubleToSrational_direct() --------------*/ +#endif + +//#define DOUBLE2RAT_DEBUGOUTPUT +/** ----- Rational2Double: Double To Rational Conversion ---------------------------------------------------------- +* There is a mathematical theorem to convert real numbers into a rational (integer fraction) number. +* This is called "continuous fraction" which uses the Euclidean algorithm to find the greatest common divisor (GCD). +* (ref. e.g. https://de.wikipedia.org/wiki/Kettenbruch or https://en.wikipedia.org/wiki/Continued_fraction +* https://en.wikipedia.org/wiki/Euclidean_algorithm) +* The following functions implement the +* - ToRationalEuclideanGCD() auxiliary function which mainly implements euclidean GCD +* - DoubleToRational() conversion function for un-signed rationals +* - DoubleToSrational() conversion function for signed rationals +------------------------------------------------------------------------------------------------------------------*/ + +/**---- ToRationalEuclideanGCD() ----------------------------------------- +* Calculates the rational fractional of a double input value +* using the Euclidean algorithm to find the greatest common divisor (GCD) +------------------------------------------------------------------------*/ +static +void ToRationalEuclideanGCD(double value, int blnUseSignedRange, int blnUseSmallRange, uint64_t *ullNum, uint64_t *ullDenom) +{ + /* Internally, the integer variables can be bigger than the external ones, + * as long as the result will fit into the external variable size. + */ + uint64_t numSum[3] = { 0, 1, 0 }, denomSum[3] = { 1, 0, 0 }; + uint64_t aux, bigNum, bigDenom; + uint64_t returnLimit; + int i; + uint64_t nMax; + double fMax; + unsigned long maxDenom; + /*-- nMax and fMax defines the initial accuracy of the starting fractional, + * or better, the highest used integer numbers used within the starting fractional (bigNum/bigDenom). + * There are two approaches, which can accidentally lead to different accuracies just depending on the value. + * Therefore, blnUseSmallRange steers this behavior. + * For long long nMax = ((9223372036854775807-1)/2); for long nMax = ((2147483647-1)/2); + */ + if (blnUseSmallRange) { + nMax = (uint64_t)((2147483647 - 1) / 2); /* for ULONG range */ + } + else { + nMax = ((9223372036854775807 - 1) / 2); /* for ULLONG range */ + } + fMax = (double)nMax; + + /*-- For the Euclidean GCD define the denominator range, so that it stays within size of unsigned long variables. + * maxDenom should be LONG_MAX for negative values and ULONG_MAX for positive ones. + * Also the final returned value of ullNum and ullDenom is limited according to signed- or unsigned-range. + */ + if (blnUseSignedRange) { + maxDenom = 2147483647UL; /*LONG_MAX = 0x7FFFFFFFUL*/ + returnLimit = maxDenom; + } + else { + maxDenom = 0xFFFFFFFFUL; /*ULONG_MAX = 0xFFFFFFFFUL*/ + returnLimit = maxDenom; + } + + /*-- First generate a rational fraction (bigNum/bigDenom) which represents the value + * as a rational number with the highest accuracy. Therefore, uint64_t (uint64_t) is needed. + * This rational fraction is then reduced using the Euclidean algorithm to find the greatest common divisor (GCD). + * bigNum = big numinator of value without fraction (or cut residual fraction) + * bigDenom = big denominator of value + *-- Break-criteria so that uint64_t cast to "bigNum" introduces no error and bigDenom has no overflow, + * and stop with enlargement of fraction when the double-value of it reaches an integer number without fractional part. + */ + bigDenom = 1; + while ((value != floor(value)) && (value < fMax) && (bigDenom < nMax)) { + bigDenom <<= 1; + value *= 2; + } + bigNum = (uint64_t)value; + + /*-- Start Euclidean algorithm to find the greatest common divisor (GCD) -- */ +#define MAX_ITERATIONS 64 + for (i = 0; i < MAX_ITERATIONS; i++) { + uint64_t val; + /* if bigDenom is not zero, calculate integer part of fraction. */ + if (bigDenom == 0) { + break; + } + val = bigNum / bigDenom; + + /* Set bigDenom to reminder of bigNum/bigDenom and bigNum to previous denominator bigDenom. */ + aux = bigNum; + bigNum = bigDenom; + bigDenom = aux % bigDenom; + + /* calculate next denominator and check for its given maximum */ + aux = val; + if (denomSum[1] * val + denomSum[0] >= maxDenom) { + aux = (maxDenom - denomSum[0]) / denomSum[1]; + if (aux * 2 >= val || denomSum[1] >= maxDenom) + i = (MAX_ITERATIONS + 1); /* exit but execute rest of for-loop */ + else + break; + } + /* calculate next numerator to numSum2 and save previous one to numSum0; numSum1 just copy of numSum2. */ + numSum[2] = aux * numSum[1] + numSum[0]; + numSum[0] = numSum[1]; + numSum[1] = numSum[2]; + /* calculate next denominator to denomSum2 and save previous one to denomSum0; denomSum1 just copy of denomSum2. */ + denomSum[2] = aux * denomSum[1] + denomSum[0]; + denomSum[0] = denomSum[1]; + denomSum[1] = denomSum[2]; + } + + /*-- Check and adapt for final variable size and return values; reduces internal accuracy; denominator is kept in ULONG-range with maxDenom -- */ + while (numSum[1] > returnLimit || denomSum[1] > returnLimit) { + numSum[1] = numSum[1] / 2; + denomSum[1] = denomSum[1] / 2; + } + + /* return values */ + *ullNum = numSum[1]; + *ullDenom = denomSum[1]; + +} /*-- ToRationalEuclideanGCD() -------------- */ + + +/**---- DoubleToRational() ----------------------------------------------- +* Calculates the rational fractional of a double input value +* for UN-SIGNED rationals, +* using the Euclidean algorithm to find the greatest common divisor (GCD) +------------------------------------------------------------------------*/ +static +void DoubleToRational(double value, uint32_t *num, uint32_t *denom) +{ + /*---- UN-SIGNED RATIONAL ---- */ + double dblDiff, dblDiff2; + uint64_t ullNum, ullDenom, ullNum2, ullDenom2; + + /*-- Check for negative values. If so it is an error. */ + /* Test written that way to catch NaN */ + if (!(value >= 0)) { + *num = *denom = 0; + TIFFErrorExt(0, "TIFFLib: DoubleToRational()", " Negative Value for Unsigned Rational given."); + return; + } + + /*-- Check for too big numbers (> ULONG_MAX) -- */ + if (value > 0xFFFFFFFFUL) { + *num = 0xFFFFFFFFU; + *denom = 0; + return; + } + /*-- Check for easy integer numbers -- */ + if (value == (uint32_t)(value)) { + *num = (uint32_t)value; + *denom = 1; + return; + } + /*-- Check for too small numbers for "unsigned long" type rationals -- */ + if (value < 1.0 / (double)0xFFFFFFFFUL) { + *num = 0; + *denom = 0xFFFFFFFFU; + return; + } + + /*-- There are two approaches using the Euclidean algorithm, + * which can accidentally lead to different accuracies just depending on the value. + * Try both and define which one was better. + */ + ToRationalEuclideanGCD(value, FALSE, FALSE, &ullNum, &ullDenom); + ToRationalEuclideanGCD(value, FALSE, TRUE, &ullNum2, &ullDenom2); + /*-- Double-Check, that returned values fit into ULONG :*/ + if (ullNum > 0xFFFFFFFFUL || ullDenom > 0xFFFFFFFFUL || ullNum2 > 0xFFFFFFFFUL || ullDenom2 > 0xFFFFFFFFUL) { + TIFFErrorExt(0, "TIFFLib: DoubleToRational()", " Num or Denom exceeds ULONG: val=%14.6f, num=%12"PRIu64", denom=%12"PRIu64" | num2=%12"PRIu64", denom2=%12"PRIu64"", value, ullNum, ullDenom, ullNum2, ullDenom2); + assert(0); + } + + /* Check, which one has higher accuracy and take that. */ + dblDiff = fabs(value - ((double)ullNum / (double)ullDenom)); + dblDiff2 = fabs(value - ((double)ullNum2 / (double)ullDenom2)); + if (dblDiff < dblDiff2) { + *num = (uint32_t)ullNum; + *denom = (uint32_t)ullDenom; + } + else { + *num = (uint32_t)ullNum2; + *denom = (uint32_t)ullDenom2; + } +} /*-- DoubleToRational() -------------- */ + +/**---- DoubleToSrational() ----------------------------------------------- +* Calculates the rational fractional of a double input value +* for SIGNED rationals, +* using the Euclidean algorithm to find the greatest common divisor (GCD) +------------------------------------------------------------------------*/ +static +void DoubleToSrational(double value, int32_t *num, int32_t *denom) +{ + /*---- SIGNED RATIONAL ----*/ + int neg = 1; + double dblDiff, dblDiff2; + uint64_t ullNum, ullDenom, ullNum2, ullDenom2; + + /*-- Check for negative values and use then the positive one for internal calculations, but take the sign into account before returning. */ + if (value < 0) { neg = -1; value = -value; } + + /*-- Check for too big numbers (> LONG_MAX) -- */ + if (value > 0x7FFFFFFFL) { + *num = 0x7FFFFFFFL; + *denom = 0; + return; + } + /*-- Check for easy numbers -- */ + if (value == (int32_t)(value)) { + *num = (int32_t)(neg * value); + *denom = 1; + return; + } + /*-- Check for too small numbers for "long" type rationals -- */ + if (value < 1.0 / (double)0x7FFFFFFFL) { + *num = 0; + *denom = 0x7FFFFFFFL; + return; + } + + /*-- There are two approaches using the Euclidean algorithm, + * which can accidentally lead to different accuracies just depending on the value. + * Try both and define which one was better. + * Furthermore, set behavior of ToRationalEuclideanGCD() to the range of signed-long. + */ + ToRationalEuclideanGCD(value, TRUE, FALSE, &ullNum, &ullDenom); + ToRationalEuclideanGCD(value, TRUE, TRUE, &ullNum2, &ullDenom2); + /*-- Double-Check, that returned values fit into LONG :*/ + if (ullNum > 0x7FFFFFFFL || ullDenom > 0x7FFFFFFFL || ullNum2 > 0x7FFFFFFFL || ullDenom2 > 0x7FFFFFFFL) { + TIFFErrorExt(0, "TIFFLib: DoubleToSrational()", " Num or Denom exceeds LONG: val=%14.6f, num=%12"PRIu64", denom=%12"PRIu64" | num2=%12"PRIu64", denom2=%12"PRIu64"", neg*value, ullNum, ullDenom, ullNum2, ullDenom2); + assert(0); + } + + /* Check, which one has higher accuracy and take that. */ + dblDiff = fabs(value - ((double)ullNum / (double)ullDenom)); + dblDiff2 = fabs(value - ((double)ullNum2 / (double)ullDenom2)); + if (dblDiff < dblDiff2) { + *num = (int32_t)(neg * (long)ullNum); + *denom = (int32_t)ullDenom; + } + else { + *num = (int32_t)(neg * (long)ullNum2); + *denom = (int32_t)ullDenom2; + } +} /*-- DoubleToSrational() --------------*/ + + + + + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, float value) +{ + float m; + assert(sizeof(float)==4); + m=value; + TIFFCvtNativeToIEEEFloat(tif,1,&m); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabFloat(&m); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,1,4,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, float* value) +{ + assert(count<0x40000000); + assert(sizeof(float)==4); + TIFFCvtNativeToIEEEFloat(tif,count,&value); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfFloat(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,count,count*4,value)); +} + +#ifdef notdef +static int +TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, double value) +{ + double m; + assert(sizeof(double)==8); + m=value; + TIFFCvtNativeToIEEEDouble(tif,1,&m); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabDouble(&m); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_DOUBLE,1,8,&m)); +} +#endif + +static int +TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, double* value) +{ + assert(count<0x20000000); + assert(sizeof(double)==8); + TIFFCvtNativeToIEEEDouble(tif,count,&value); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfDouble(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_DOUBLE,count,count*8,value)); +} + +static int +TIFFWriteDirectoryTagCheckedIfdArray(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint32_t* value) +{ + assert(count<0x40000000); + assert(sizeof(uint32_t) == 4); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_IFD,count,count*4,value)); +} + +static int +TIFFWriteDirectoryTagCheckedIfd8Array(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint32_t count, uint64_t* value) +{ + assert(count<0x20000000); + assert(sizeof(uint64_t) == 8); + assert(tif->tif_flags&TIFF_BIGTIFF); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabArrayOfLong8(value,count); + return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_IFD8,count,count*8,value)); +} + +static int +TIFFWriteDirectoryTagData(TIFF* tif, uint32_t* ndir, TIFFDirEntry* dir, uint16_t tag, uint16_t datatype, uint32_t count, uint32_t datalength, void* data) +{ + static const char module[] = "TIFFWriteDirectoryTagData"; + uint32_t m; + m=0; + while (m<(*ndir)) + { + assert(dir[m].tdir_tag!=tag); + if (dir[m].tdir_tag>tag) + break; + m++; + } + if (m<(*ndir)) + { + uint32_t n; + for (n=*ndir; n>m; n--) + dir[n]=dir[n-1]; + } + dir[m].tdir_tag=tag; + dir[m].tdir_type=datatype; + dir[m].tdir_count=count; + dir[m].tdir_offset.toff_long8 = 0; + if (datalength<=((tif->tif_flags&TIFF_BIGTIFF)?0x8U:0x4U)) + { + if( data && datalength ) + { + _TIFFmemcpy(&dir[m].tdir_offset,data,datalength); + } + } + else + { + uint64_t na,nb; + na=tif->tif_dataoff; + nb=na+datalength; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + nb=(uint32_t)nb; + if ((nbtif_clientdata,module,"Maximum TIFF file size exceeded"); + return(0); + } + if (!SeekOK(tif,na)) + { + TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data"); + return(0); + } + assert(datalength<0x80000000UL); + if (!WriteOK(tif,data,(tmsize_t)datalength)) + { + TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data"); + return(0); + } + tif->tif_dataoff=nb; + if (tif->tif_dataoff&1) + tif->tif_dataoff++; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32_t o; + o=(uint32_t)na; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong(&o); + _TIFFmemcpy(&dir[m].tdir_offset,&o,4); + } + else + { + dir[m].tdir_offset.toff_long8 = na; + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8(&dir[m].tdir_offset.toff_long8); + } + } + (*ndir)++; + return(1); +} + +/* + * Link the current directory into the directory chain for the file. + */ +static int +TIFFLinkDirectory(TIFF* tif) +{ + static const char module[] = "TIFFLinkDirectory"; + + tif->tif_diroff = (TIFFSeekFile(tif,0,SEEK_END)+1) & (~((toff_t)1)); + + /* + * Handle SubIFDs + */ + if (tif->tif_flags & TIFF_INSUBIFD) + { + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32_t m; + m = (uint32_t)tif->tif_diroff; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&m); + (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); + if (!WriteOK(tif, &m, 4)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing SubIFD directory link"); + return (0); + } + /* + * Advance to the next SubIFD or, if this is + * the last one configured, revert back to the + * normal directory linkage. + */ + if (--tif->tif_nsubifd) + tif->tif_subifdoff += 4; + else + tif->tif_flags &= ~TIFF_INSUBIFD; + return (1); + } + else + { + uint64_t m; + m = tif->tif_diroff; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&m); + (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); + if (!WriteOK(tif, &m, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing SubIFD directory link"); + return (0); + } + /* + * Advance to the next SubIFD or, if this is + * the last one configured, revert back to the + * normal directory linkage. + */ + if (--tif->tif_nsubifd) + tif->tif_subifdoff += 8; + else + tif->tif_flags &= ~TIFF_INSUBIFD; + return (1); + } + } + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32_t m; + uint32_t nextdir; + m = (uint32_t)(tif->tif_diroff); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&m); + if (tif->tif_header.classic.tiff_diroff == 0) { + /* + * First directory, overwrite offset in header. + */ + tif->tif_header.classic.tiff_diroff = (uint32_t) tif->tif_diroff; + (void) TIFFSeekFile(tif,4, SEEK_SET); + if (!WriteOK(tif, &m, 4)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing TIFF header"); + return (0); + } + return (1); + } + /* + * Not the first directory, search to the last and append. + */ + nextdir = tif->tif_header.classic.tiff_diroff; + while(1) { + uint16_t dircount; + uint32_t nextnextdir; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount, 2)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + (void) TIFFSeekFile(tif, + nextdir+2+dircount*12, SEEK_SET); + if (!ReadOK(tif, &nextnextdir, 4)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextnextdir); + if (nextnextdir==0) + { + (void) TIFFSeekFile(tif, + nextdir+2+dircount*12, SEEK_SET); + if (!WriteOK(tif, &m, 4)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + break; + } + nextdir=nextnextdir; + } + } + else + { + uint64_t m; + uint64_t nextdir; + m = tif->tif_diroff; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&m); + if (tif->tif_header.big.tiff_diroff == 0) { + /* + * First directory, overwrite offset in header. + */ + tif->tif_header.big.tiff_diroff = tif->tif_diroff; + (void) TIFFSeekFile(tif,8, SEEK_SET); + if (!WriteOK(tif, &m, 8)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Error writing TIFF header"); + return (0); + } + return (1); + } + /* + * Not the first directory, search to the last and append. + */ + nextdir = tif->tif_header.big.tiff_diroff; + while(1) { + uint64_t dircount64; + uint16_t dircount; + uint64_t nextnextdir; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount64, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64>0xFFFF) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sanity check on tag count failed, likely corrupt TIFF"); + return (0); + } + dircount=(uint16_t)dircount64; + (void) TIFFSeekFile(tif, + nextdir+8+dircount*20, SEEK_SET); + if (!ReadOK(tif, &nextnextdir, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&nextnextdir); + if (nextnextdir==0) + { + (void) TIFFSeekFile(tif, + nextdir+8+dircount*20, SEEK_SET); + if (!WriteOK(tif, &m, 8)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + break; + } + nextdir=nextnextdir; + } + } + return (1); +} + +/************************************************************************/ +/* TIFFRewriteField() */ +/* */ +/* Rewrite a field in the directory on disk without regard to */ +/* updating the TIFF directory structure in memory. Currently */ +/* only supported for field that already exist in the on-disk */ +/* directory. Mainly used for updating stripoffset / */ +/* stripbytecount values after the directory is already on */ +/* disk. */ +/* */ +/* Returns zero on failure, and one on success. */ +/************************************************************************/ + +int +_TIFFRewriteField(TIFF* tif, uint16_t tag, TIFFDataType in_datatype, + tmsize_t count, void* data) +{ + static const char module[] = "TIFFResetField"; + /* const TIFFField* fip = NULL; */ + uint16_t dircount; + tmsize_t dirsize; + uint8_t direntry_raw[20]; + uint16_t entry_tag = 0; + uint16_t entry_type = 0; + uint64_t entry_count = 0; + uint64_t entry_offset = 0; + int value_in_entry = 0; + uint64_t read_offset; + uint8_t *buf_to_write = NULL; + TIFFDataType datatype; + +/* -------------------------------------------------------------------- */ +/* Find field definition. */ +/* -------------------------------------------------------------------- */ + /*fip =*/ TIFFFindField(tif, tag, TIFF_ANY); + +/* -------------------------------------------------------------------- */ +/* Do some checking this is a straight forward case. */ +/* -------------------------------------------------------------------- */ + if( isMapped(tif) ) + { + TIFFErrorExt( tif->tif_clientdata, module, + "Memory mapped files not currently supported for this operation." ); + return 0; + } + + if( tif->tif_diroff == 0 ) + { + TIFFErrorExt( tif->tif_clientdata, module, + "Attempt to reset field on directory not already on disk." ); + return 0; + } + +/* -------------------------------------------------------------------- */ +/* Read the directory entry count. */ +/* -------------------------------------------------------------------- */ + if (!SeekOK(tif, tif->tif_diroff)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + + read_offset = tif->tif_diroff; + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if (!ReadOK(tif, &dircount, sizeof (uint16_t))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + dirsize = 12; + read_offset += 2; + } else { + uint64_t dircount64; + if (!ReadOK(tif, &dircount64, sizeof (uint64_t))) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + dircount = (uint16_t)dircount64; + dirsize = 20; + read_offset += 8; + } + +/* -------------------------------------------------------------------- */ +/* Read through directory to find target tag. */ +/* -------------------------------------------------------------------- */ + while( dircount > 0 ) + { + if (!ReadOK(tif, direntry_raw, dirsize)) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not read TIFF directory entry.", + tif->tif_name); + return 0; + } + + memcpy( &entry_tag, direntry_raw + 0, sizeof(uint16_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort( &entry_tag ); + + if( entry_tag == tag ) + break; + + read_offset += dirsize; + } + + if( entry_tag != tag ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Could not find tag %"PRIu16".", + tif->tif_name, tag ); + return 0; + } + +/* -------------------------------------------------------------------- */ +/* Extract the type, count and offset for this entry. */ +/* -------------------------------------------------------------------- */ + memcpy( &entry_type, direntry_raw + 2, sizeof(uint16_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort( &entry_type ); + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32_t value; + + memcpy( &value, direntry_raw + 4, sizeof(uint32_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong( &value ); + entry_count = value; + + memcpy( &value, direntry_raw + 8, sizeof(uint32_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong( &value ); + entry_offset = value; + } + else + { + memcpy( &entry_count, direntry_raw + 4, sizeof(uint64_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8( &entry_count ); + + memcpy( &entry_offset, direntry_raw + 12, sizeof(uint64_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8( &entry_offset ); + } + +/* -------------------------------------------------------------------- */ +/* When a dummy tag was written due to TIFFDeferStrileArrayWriting() */ +/* -------------------------------------------------------------------- */ + if( entry_offset == 0 && entry_count == 0 && entry_type == 0 ) + { + if( tag == TIFFTAG_TILEOFFSETS || tag == TIFFTAG_STRIPOFFSETS ) + { + entry_type = (tif->tif_flags&TIFF_BIGTIFF) ? TIFF_LONG8 : TIFF_LONG; + } + else + { + int write_aslong8 = 1; + if( count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS ) + { + write_aslong8 = WriteAsLong8(tif, TIFFStripSize64(tif)); + } + else if( count > 1 && tag == TIFFTAG_TILEBYTECOUNTS ) + { + write_aslong8 = WriteAsLong8(tif, TIFFTileSize64(tif)); + } + if( write_aslong8 ) + { + entry_type = TIFF_LONG8; + } + else + { + int write_aslong4 = 1; + if( count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS ) + { + write_aslong4 = WriteAsLong4(tif, TIFFStripSize64(tif)); + } + else if( count > 1 && tag == TIFFTAG_TILEBYTECOUNTS ) + { + write_aslong4 = WriteAsLong4(tif, TIFFTileSize64(tif)); + } + if( write_aslong4 ) + { + entry_type = TIFF_LONG; + } + else + { + entry_type = TIFF_SHORT; + } + } + } + } + +/* -------------------------------------------------------------------- */ +/* What data type do we want to write this as? */ +/* -------------------------------------------------------------------- */ + if( TIFFDataWidth(in_datatype) == 8 && !(tif->tif_flags&TIFF_BIGTIFF) ) + { + if( in_datatype == TIFF_LONG8 ) + datatype = entry_type == TIFF_SHORT ? TIFF_SHORT : TIFF_LONG; + else if( in_datatype == TIFF_SLONG8 ) + datatype = TIFF_SLONG; + else if( in_datatype == TIFF_IFD8 ) + datatype = TIFF_IFD; + else + datatype = in_datatype; + } + else + { + if( in_datatype == TIFF_LONG8 && + (entry_type == TIFF_SHORT || entry_type == TIFF_LONG || + entry_type == TIFF_LONG8 ) ) + datatype = entry_type; + else if( in_datatype == TIFF_SLONG8 && + (entry_type == TIFF_SLONG || entry_type == TIFF_SLONG8 ) ) + datatype = entry_type; + else if( in_datatype == TIFF_IFD8 && + (entry_type == TIFF_IFD || entry_type == TIFF_IFD8 ) ) + datatype = entry_type; + else + datatype = in_datatype; + } + +/* -------------------------------------------------------------------- */ +/* Prepare buffer of actual data to write. This includes */ +/* swabbing as needed. */ +/* -------------------------------------------------------------------- */ + buf_to_write = + (uint8_t *)_TIFFCheckMalloc(tif, count, TIFFDataWidth(datatype), + "for field buffer."); + if (!buf_to_write) + return 0; + + if( datatype == in_datatype ) + memcpy( buf_to_write, data, count * TIFFDataWidth(datatype) ); + else if( datatype == TIFF_SLONG && in_datatype == TIFF_SLONG8 ) + { + tmsize_t i; + + for( i = 0; i < count; i++ ) + { + ((int32_t *) buf_to_write)[i] = + (int32_t) ((int64_t *) data)[i]; + if((int64_t) ((int32_t *) buf_to_write)[i] != ((int64_t *) data)[i] ) + { + _TIFFfree( buf_to_write ); + TIFFErrorExt( tif->tif_clientdata, module, + "Value exceeds 32bit range of output type." ); + return 0; + } + } + } + else if( (datatype == TIFF_LONG && in_datatype == TIFF_LONG8) + || (datatype == TIFF_IFD && in_datatype == TIFF_IFD8) ) + { + tmsize_t i; + + for( i = 0; i < count; i++ ) + { + ((uint32_t *) buf_to_write)[i] = + (uint32_t) ((uint64_t *) data)[i]; + if((uint64_t) ((uint32_t *) buf_to_write)[i] != ((uint64_t *) data)[i] ) + { + _TIFFfree( buf_to_write ); + TIFFErrorExt( tif->tif_clientdata, module, + "Value exceeds 32bit range of output type." ); + return 0; + } + } + } + else if( datatype == TIFF_SHORT && in_datatype == TIFF_LONG8 ) + { + tmsize_t i; + + for( i = 0; i < count; i++ ) + { + ((uint16_t *) buf_to_write)[i] = + (uint16_t) ((uint64_t *) data)[i]; + if((uint64_t) ((uint16_t *) buf_to_write)[i] != ((uint64_t *) data)[i] ) + { + _TIFFfree( buf_to_write ); + TIFFErrorExt( tif->tif_clientdata, module, + "Value exceeds 16bit range of output type." ); + return 0; + } + } + } + else + { + TIFFErrorExt( tif->tif_clientdata, module, + "Unhandled type conversion." ); + return 0; + } + + if( TIFFDataWidth(datatype) > 1 && (tif->tif_flags&TIFF_SWAB) ) + { + if( TIFFDataWidth(datatype) == 2 ) + TIFFSwabArrayOfShort((uint16_t *) buf_to_write, count ); + else if( TIFFDataWidth(datatype) == 4 ) + TIFFSwabArrayOfLong((uint32_t *) buf_to_write, count ); + else if( TIFFDataWidth(datatype) == 8 ) + TIFFSwabArrayOfLong8((uint64_t *) buf_to_write, count ); + } + +/* -------------------------------------------------------------------- */ +/* Is this a value that fits into the directory entry? */ +/* -------------------------------------------------------------------- */ + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + if( TIFFDataWidth(datatype) * count <= 4 ) + { + entry_offset = read_offset + 8; + value_in_entry = 1; + } + } + else + { + if( TIFFDataWidth(datatype) * count <= 8 ) + { + entry_offset = read_offset + 12; + value_in_entry = 1; + } + } + + if( (tag == TIFFTAG_TILEOFFSETS || tag == TIFFTAG_STRIPOFFSETS) && + tif->tif_dir.td_stripoffset_entry.tdir_count == 0 && + tif->tif_dir.td_stripoffset_entry.tdir_type == 0 && + tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 ) + { + tif->tif_dir.td_stripoffset_entry.tdir_type = datatype; + tif->tif_dir.td_stripoffset_entry.tdir_count = count; + } + else if( (tag == TIFFTAG_TILEBYTECOUNTS || tag == TIFFTAG_STRIPBYTECOUNTS) && + tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 ) + { + tif->tif_dir.td_stripbytecount_entry.tdir_type = datatype; + tif->tif_dir.td_stripbytecount_entry.tdir_count = count; + } + +/* -------------------------------------------------------------------- */ +/* If the tag type, and count match, then we just write it out */ +/* over the old values without altering the directory entry at */ +/* all. */ +/* -------------------------------------------------------------------- */ + if( entry_count == (uint64_t)count && entry_type == (uint16_t) datatype ) + { + if (!SeekOK(tif, entry_offset)) { + _TIFFfree( buf_to_write ); + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) { + _TIFFfree( buf_to_write ); + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + + _TIFFfree( buf_to_write ); + return 1; + } + +/* -------------------------------------------------------------------- */ +/* Otherwise, we write the new tag data at the end of the file. */ +/* -------------------------------------------------------------------- */ + if( !value_in_entry ) + { + entry_offset = TIFFSeekFile(tif,0,SEEK_END); + + if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) { + _TIFFfree( buf_to_write ); + TIFFErrorExt(tif->tif_clientdata, module, + "Error writing directory link"); + return (0); + } + } + else + { + memcpy( &entry_offset, buf_to_write, count*TIFFDataWidth(datatype)); + } + + _TIFFfree( buf_to_write ); + buf_to_write = 0; + +/* -------------------------------------------------------------------- */ +/* Adjust the directory entry. */ +/* -------------------------------------------------------------------- */ + entry_type = datatype; + entry_count = (uint64_t)count; + memcpy( direntry_raw + 2, &entry_type, sizeof(uint16_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabShort( (uint16_t *) (direntry_raw + 2) ); + + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + uint32_t value; + + value = (uint32_t) entry_count; + memcpy( direntry_raw + 4, &value, sizeof(uint32_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong( (uint32_t *) (direntry_raw + 4) ); + + value = (uint32_t) entry_offset; + memcpy( direntry_raw + 8, &value, sizeof(uint32_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong( (uint32_t *) (direntry_raw + 8) ); + } + else + { + memcpy( direntry_raw + 4, &entry_count, sizeof(uint64_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8( (uint64_t *) (direntry_raw + 4) ); + + memcpy( direntry_raw + 12, &entry_offset, sizeof(uint64_t) ); + if (tif->tif_flags&TIFF_SWAB) + TIFFSwabLong8( (uint64_t *) (direntry_raw + 12) ); + } + +/* -------------------------------------------------------------------- */ +/* Write the directory entry out to disk. */ +/* -------------------------------------------------------------------- */ + if (!SeekOK(tif, read_offset )) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + + if (!WriteOK(tif, direntry_raw,dirsize)) + { + TIFFErrorExt(tif->tif_clientdata, module, + "%s: Can not write TIFF directory entry.", + tif->tif_name); + return 0; + } + + return 1; +} +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_dumpmode.c b/libs/tiff/libtiff/tif_dumpmode.c new file mode 100644 index 00000000000..f1d3c4addc4 --- /dev/null +++ b/libs/tiff/libtiff/tif_dumpmode.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * "Null" Compression Algorithm Support. + */ +#include "tiffiop.h" + +static int +DumpFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +/* + * Encode a hunk of pixels. + */ +static int +DumpModeEncode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s) +{ + (void) s; + while (cc > 0) { + tmsize_t n; + + n = cc; + if (tif->tif_rawcc + n > tif->tif_rawdatasize) + n = tif->tif_rawdatasize - tif->tif_rawcc; + + assert( n > 0 ); + + /* + * Avoid copy if client has setup raw + * data buffer to avoid extra copy. + */ + if (tif->tif_rawcp != pp) + _TIFFmemcpy(tif->tif_rawcp, pp, n); + tif->tif_rawcp += n; + tif->tif_rawcc += n; + pp += n; + cc -= n; + if (tif->tif_rawcc >= tif->tif_rawdatasize && + !TIFFFlushData1(tif)) + return (0); + } + return (1); +} + +/* + * Decode a hunk of pixels. + */ +static int +DumpModeDecode(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s) +{ + static const char module[] = "DumpModeDecode"; + (void) s; + if (tif->tif_rawcc < cc) { + TIFFErrorExt(tif->tif_clientdata, module, +"Not enough data for scanline %"PRIu32", expected a request for at most %"TIFF_SSIZE_FORMAT" bytes, got a request for %"TIFF_SSIZE_FORMAT" bytes", + tif->tif_row, + tif->tif_rawcc, + cc); + return (0); + } + /* + * Avoid copy if client has setup raw + * data buffer to avoid extra copy. + */ + if (tif->tif_rawcp != buf) + _TIFFmemcpy(buf, tif->tif_rawcp, cc); + tif->tif_rawcp += cc; + tif->tif_rawcc -= cc; + return (1); +} + +/* + * Seek forwards nrows in the current strip. + */ +static int +DumpModeSeek(TIFF* tif, uint32_t nrows) +{ + tif->tif_rawcp += nrows * tif->tif_scanlinesize; + tif->tif_rawcc -= nrows * tif->tif_scanlinesize; + return (1); +} + +/* + * Initialize dump mode. + */ +int +TIFFInitDumpMode(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_fixuptags = DumpFixupTags; + tif->tif_decoderow = DumpModeDecode; + tif->tif_decodestrip = DumpModeDecode; + tif->tif_decodetile = DumpModeDecode; + tif->tif_encoderow = DumpModeEncode; + tif->tif_encodestrip = DumpModeEncode; + tif->tif_encodetile = DumpModeEncode; + tif->tif_seek = DumpModeSeek; + return (1); +} +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_error.c b/libs/tiff/libtiff/tif_error.c new file mode 100644 index 00000000000..9e0cb82f7dc --- /dev/null +++ b/libs/tiff/libtiff/tif_error.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +TIFFErrorHandlerExt _TIFFerrorHandlerExt = NULL; + +TIFFErrorHandler +TIFFSetErrorHandler(TIFFErrorHandler handler) +{ + TIFFErrorHandler prev = _TIFFerrorHandler; + _TIFFerrorHandler = handler; + return (prev); +} + +TIFFErrorHandlerExt +TIFFSetErrorHandlerExt(TIFFErrorHandlerExt handler) +{ + TIFFErrorHandlerExt prev = _TIFFerrorHandlerExt; + _TIFFerrorHandlerExt = handler; + return (prev); +} + +void WINAPIV +TIFFError(const char* module, const char* fmt, ...) +{ + va_list ap; + if (_TIFFerrorHandler) { + va_start(ap, fmt); + (*_TIFFerrorHandler)(module, fmt, ap); + va_end(ap); + } + if (_TIFFerrorHandlerExt) { + va_start(ap, fmt); + (*_TIFFerrorHandlerExt)(0, module, fmt, ap); + va_end(ap); + } +} + +void WINAPIV +TIFFErrorExt(thandle_t fd, const char* module, const char* fmt, ...) +{ + va_list ap; + if (_TIFFerrorHandler) { + va_start(ap, fmt); + (*_TIFFerrorHandler)(module, fmt, ap); + va_end(ap); + } + if (_TIFFerrorHandlerExt) { + va_start(ap, fmt); + (*_TIFFerrorHandlerExt)(fd, module, fmt, ap); + va_end(ap); + } +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_fax3.c b/libs/tiff/libtiff/tif_fax3.c new file mode 100644 index 00000000000..99f73621be7 --- /dev/null +++ b/libs/tiff/libtiff/tif_fax3.c @@ -0,0 +1,1597 @@ +/* + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef CCITT_SUPPORT +/* + * TIFF Library. + * + * CCITT Group 3 (T.4) and Group 4 (T.6) Compression Support. + * + * This file contains support for decoding and encoding TIFF + * compression algorithms 2, 3, 4, and 32771. + * + * Decoder support is derived, with permission, from the code + * in Frank Cringle's viewfax program; + * Copyright (C) 1990, 1995 Frank D. Cringle. + */ +#include "tif_fax3.h" +#define G3CODES +#include "t4.h" +#include + +/* + * Compression+decompression state blocks are + * derived from this ``base state'' block. + */ +typedef struct { + int rw_mode; /* O_RDONLY for decode, else encode */ + int mode; /* operating mode */ + tmsize_t rowbytes; /* bytes in a decoded scanline */ + uint32_t rowpixels; /* pixels in a scanline */ + + uint16_t cleanfaxdata; /* CleanFaxData tag */ + uint32_t badfaxrun; /* BadFaxRun tag */ + uint32_t badfaxlines; /* BadFaxLines tag */ + uint32_t groupoptions; /* Group 3/4 options tag */ + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFPrintMethod printdir; /* super-class method */ +} Fax3BaseState; +#define Fax3State(tif) ((Fax3BaseState*) (tif)->tif_data) + +typedef enum { G3_1D, G3_2D } Ttag; +typedef struct { + Fax3BaseState b; + + /* Decoder state info */ + const unsigned char* bitmap; /* bit reversal table */ + uint32_t data; /* current i/o byte/word */ + int bit; /* current i/o bit in byte */ + int EOLcnt; /* count of EOL codes recognized */ + TIFFFaxFillFunc fill; /* fill routine */ + uint32_t* runs; /* b&w runs for current/previous row */ + uint32_t nruns; /* size of the refruns / curruns arrays */ + uint32_t* refruns; /* runs for reference line */ + uint32_t* curruns; /* runs for current line */ + + /* Encoder state info */ + Ttag tag; /* encoding state */ + unsigned char* refline; /* reference line for 2d decoding */ + int k; /* #rows left that can be 2d encoded */ + int maxk; /* max #rows that can be 2d encoded */ + + int line; +} Fax3CodecState; +#define DecoderState(tif) ((Fax3CodecState*) Fax3State(tif)) +#define EncoderState(tif) ((Fax3CodecState*) Fax3State(tif)) + +#define is2DEncoding(sp) (sp->b.groupoptions & GROUP3OPT_2DENCODING) +#define isAligned(p,t) ((((size_t)(p)) & (sizeof (t)-1)) == 0) + +/* + * Group 3 and Group 4 Decoding. + */ + +/* + * These macros glue the TIFF library state to + * the state expected by Frank's decoder. + */ +#define DECLARE_STATE(tif, sp, mod) \ + static const char module[] = mod; \ + Fax3CodecState* sp = DecoderState(tif); \ + int a0; /* reference element */ \ + int lastx = sp->b.rowpixels; /* last element in row */ \ + uint32_t BitAcc; /* bit accumulator */ \ + int BitsAvail; /* # valid bits in BitAcc */ \ + int RunLength; /* length of current run */ \ + unsigned char* cp; /* next byte of input data */ \ + unsigned char* ep; /* end of input data */ \ + uint32_t* pa; /* place to stuff next run */ \ + uint32_t* thisrun; /* current row's run array */ \ + int EOLcnt; /* # EOL codes recognized */ \ + const unsigned char* bitmap = sp->bitmap; /* input data bit reverser */ \ + const TIFFFaxTabEnt* TabEnt +#define DECLARE_STATE_2D(tif, sp, mod) \ + DECLARE_STATE(tif, sp, mod); \ + int b1; /* next change on prev line */ \ + uint32_t* pb /* next run in reference line */\ +/* + * Load any state that may be changed during decoding. + */ +#define CACHE_STATE(tif, sp) do { \ + BitAcc = sp->data; \ + BitsAvail = sp->bit; \ + EOLcnt = sp->EOLcnt; \ + cp = (unsigned char*) tif->tif_rawcp; \ + ep = cp + tif->tif_rawcc; \ +} while (0) +/* + * Save state possibly changed during decoding. + */ +#define UNCACHE_STATE(tif, sp) do { \ + sp->bit = BitsAvail; \ + sp->data = BitAcc; \ + sp->EOLcnt = EOLcnt; \ + tif->tif_rawcc -= (tmsize_t)((uint8_t*) cp - tif->tif_rawcp); \ + tif->tif_rawcp = (uint8_t*) cp; \ +} while (0) + +/* + * Setup state for decoding a strip. + */ +static int +Fax3PreDecode(TIFF* tif, uint16_t s) +{ + Fax3CodecState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + sp->bit = 0; /* force initial read */ + sp->data = 0; + sp->EOLcnt = 0; /* force initial scan for EOL */ + /* + * Decoder assumes lsb-to-msb bit order. Note that we select + * this here rather than in Fax3SetupState so that viewers can + * hold the image open, fiddle with the FillOrder tag value, + * and then re-decode the image. Otherwise they'd need to close + * and open the image to get the state reset. + */ + sp->bitmap = + TIFFGetBitRevTable(tif->tif_dir.td_fillorder != FILLORDER_LSB2MSB); + sp->curruns = sp->runs; + if (sp->refruns) { /* init reference line to white */ + sp->refruns = sp->runs + sp->nruns; + sp->refruns[0] = (uint32_t) sp->b.rowpixels; + sp->refruns[1] = 0; + } + sp->line = 0; + return (1); +} + +/* + * Routine for handling various errors/conditions. + * Note how they are "glued into the decoder" by + * overriding the definitions used by the decoder. + */ + +static void +Fax3Unexpected(const char* module, TIFF* tif, uint32_t line, uint32_t a0) +{ + TIFFErrorExt(tif->tif_clientdata, module, "Bad code word at line %"PRIu32" of %s %"PRIu32" (x %"PRIu32")", + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0); +} +#define unexpected(table, a0) Fax3Unexpected(module, tif, sp->line, a0) + +static void +Fax3Extension(const char* module, TIFF* tif, uint32_t line, uint32_t a0) +{ + TIFFErrorExt(tif->tif_clientdata, module, + "Uncompressed data (not supported) at line %"PRIu32" of %s %"PRIu32" (x %"PRIu32")", + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0); +} +#define extension(a0) Fax3Extension(module, tif, sp->line, a0) + +static void +Fax3BadLength(const char* module, TIFF* tif, uint32_t line, uint32_t a0, uint32_t lastx) +{ + TIFFWarningExt(tif->tif_clientdata, module, "%s at line %"PRIu32" of %s %"PRIu32" (got %"PRIu32", expected %"PRIu32")", + a0 < lastx ? "Premature EOL" : "Line length mismatch", + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0, lastx); +} +#define badlength(a0,lastx) Fax3BadLength(module, tif, sp->line, a0, lastx) + +static void +Fax3PrematureEOF(const char* module, TIFF* tif, uint32_t line, uint32_t a0) +{ + TIFFWarningExt(tif->tif_clientdata, module, "Premature EOF at line %"PRIu32" of %s %"PRIu32" (x %"PRIu32")", + line, isTiled(tif) ? "tile" : "strip", + (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), + a0); +} +#define prematureEOF(a0) Fax3PrematureEOF(module, tif, sp->line, a0) + +#define Nop + +/** + * Decode the requested amount of G3 1D-encoded data. + * @param buf destination buffer + * @param occ available bytes in destination buffer + * @param s number of planes (ignored) + * @returns 1 for success, -1 in case of error + */ +static int +Fax3Decode1D(TIFF* tif, uint8_t* buf, tmsize_t occ, uint16_t s) +{ + DECLARE_STATE(tif, sp, "Fax3Decode1D"); + (void) s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (-1); + } + CACHE_STATE(tif, sp); + thisrun = sp->curruns; + while (occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08"PRIX32", BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %"PRIu32"\n", tif->tif_row); + fflush(stdout); +#endif + SYNC_EOL(EOF1D); + EXPAND1D(EOF1Da); + (*sp->fill)(buf, thisrun, pa, lastx); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOF1D: /* premature EOF */ + CLEANUP_RUNS(); + EOF1Da: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} + +#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; } +/* + * Decode the requested amount of G3 2D-encoded data. + */ +static int +Fax3Decode2D(TIFF* tif, uint8_t* buf, tmsize_t occ, uint16_t s) +{ + DECLARE_STATE_2D(tif, sp, "Fax3Decode2D"); + int is1D; /* current line is 1d/2d-encoded */ + (void) s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (-1); + } + CACHE_STATE(tif, sp); + while (occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun = sp->curruns; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08"PRIX32", BitsAvail = %d EOLcnt = %d", + BitAcc, BitsAvail, EOLcnt); +#endif + SYNC_EOL(EOF2D); + NeedBits8(1, EOF2D); + is1D = GetBits(1); /* 1D/2D-encoding tag bit */ + ClrBits(1); +#ifdef FAX3_DEBUG + printf(" %s\n-------------------- %"PRIu32"\n", + is1D ? "1D" : "2D", tif->tif_row); + fflush(stdout); +#endif + pb = sp->refruns; + b1 = *pb++; + if (is1D) + EXPAND1D(EOF2Da); + else + EXPAND2D(EOF2Da); + (*sp->fill)(buf, thisrun, pa, lastx); + if (pa < thisrun + sp->nruns) { + SETVALUE(0); /* imaginary change for reference */ + } + SWAP(uint32_t*, sp->curruns, sp->refruns); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOF2D: /* premature EOF */ + CLEANUP_RUNS(); + EOF2Da: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} +#undef SWAP + +/* + * Bit-fill a row according to the white/black + * runs generated during G3/G4 decoding. + */ +void +_TIFFFax3fillruns(unsigned char* buf, uint32_t* runs, uint32_t* erun, uint32_t lastx) +{ + static const unsigned char _fillmasks[] = + { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; + unsigned char* cp; + uint32_t x, bx, run; + int32_t n; + + if ((erun-runs)&1) + *erun++ = 0; + x = 0; + for (; runs < erun; runs += 2) { + run = runs[0]; + if (x+run > lastx || run > lastx ) + run = runs[0] = (uint32_t) (lastx - x); + if (run) { + cp = buf + (x>>3); + bx = x&7; + if (run > 8-bx) { + if (bx) { /* align to byte boundary */ + *cp++ &= 0xff << (8-bx); + run -= 8-bx; + } + if( (n = run >> 3) != 0 ) { /* multiple bytes to fill */ + memset( cp, 0, n ); + cp += n; + run &= 7; + } + if (run) + cp[0] &= 0xff >> run; + } else + cp[0] &= ~(_fillmasks[run]>>bx); + x += runs[0]; + } + run = runs[1]; + if (x+run > lastx || run > lastx ) + run = runs[1] = lastx - x; + if (run) { + cp = buf + (x>>3); + bx = x&7; + if (run > 8-bx) { + if (bx) { /* align to byte boundary */ + *cp++ |= 0xff >> bx; + run -= 8-bx; + } + if( (n = run>>3) != 0 ) { /* multiple bytes to fill */ + memset( cp, 0xff, n ); + cp += n; + run &= 7; + } + /* Explicit 0xff masking to make icc -check=conversions happy */ + if (run) + cp[0] = (unsigned char)((cp[0] | (0xff00 >> run))&0xff); + } else + cp[0] |= _fillmasks[run]>>bx; + x += runs[1]; + } + } + assert(x == lastx); +} +#undef ZERO +#undef FILL + +static int +Fax3FixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +/* + * Setup G3/G4-related compression/decompression state + * before data is processed. This routine is called once + * per image -- it sets up different state based on whether + * or not decoding or encoding is being done and whether + * 1D- or 2D-encoded data is involved. + */ +static int +Fax3SetupState(TIFF* tif) +{ + static const char module[] = "Fax3SetupState"; + TIFFDirectory* td = &tif->tif_dir; + Fax3BaseState* sp = Fax3State(tif); + int needsRefLine; + Fax3CodecState* dsp = (Fax3CodecState*) Fax3State(tif); + tmsize_t rowbytes; + uint32_t rowpixels; + + if (td->td_bitspersample != 1) { + TIFFErrorExt(tif->tif_clientdata, module, + "Bits/sample must be 1 for Group 3/4 encoding/decoding"); + return (0); + } + /* + * Calculate the scanline/tile widths. + */ + if (isTiled(tif)) { + rowbytes = TIFFTileRowSize(tif); + rowpixels = td->td_tilewidth; + } else { + rowbytes = TIFFScanlineSize(tif); + rowpixels = td->td_imagewidth; + } + if ((int64_t)rowbytes < ((int64_t)rowpixels + 7) / 8) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Inconsistent number of bytes per row : rowbytes=%" PRId64 " rowpixels=%" PRIu32, + (int64_t) rowbytes, rowpixels); + return (0); + } + sp->rowbytes = rowbytes; + sp->rowpixels = rowpixels; + /* + * Allocate any additional space required for decoding/encoding. + */ + needsRefLine = ( + (sp->groupoptions & GROUP3OPT_2DENCODING) || + td->td_compression == COMPRESSION_CCITTFAX4 + ); + + /* + Assure that allocation computations do not overflow. + + TIFFroundup and TIFFSafeMultiply return zero on integer overflow + */ + dsp->runs=(uint32_t*) NULL; + dsp->nruns = TIFFroundup_32(rowpixels,32); + if (needsRefLine) { + dsp->nruns = TIFFSafeMultiply(uint32_t, dsp->nruns, 2); + } + if ((dsp->nruns == 0) || (TIFFSafeMultiply(uint32_t, dsp->nruns, 2) == 0)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Row pixels integer overflow (rowpixels %"PRIu32")", + rowpixels); + return (0); + } + dsp->runs = (uint32_t*) _TIFFCheckMalloc(tif, + TIFFSafeMultiply(uint32_t, dsp->nruns, 2), + sizeof (uint32_t), + "for Group 3/4 run arrays"); + if (dsp->runs == NULL) + return (0); + memset( dsp->runs, 0, TIFFSafeMultiply(uint32_t,dsp->nruns,2)*sizeof(uint32_t)); + dsp->curruns = dsp->runs; + if (needsRefLine) + dsp->refruns = dsp->runs + dsp->nruns; + else + dsp->refruns = NULL; + if (td->td_compression == COMPRESSION_CCITTFAX3 + && is2DEncoding(dsp)) { /* NB: default is 1D routine */ + tif->tif_decoderow = Fax3Decode2D; + tif->tif_decodestrip = Fax3Decode2D; + tif->tif_decodetile = Fax3Decode2D; + } + + if (needsRefLine) { /* 2d encoding */ + Fax3CodecState* esp = EncoderState(tif); + /* + * 2d encoding requires a scanline + * buffer for the ``reference line''; the + * scanline against which delta encoding + * is referenced. The reference line must + * be initialized to be ``white'' (done elsewhere). + */ + esp->refline = (unsigned char*) _TIFFmalloc(rowbytes); + if (esp->refline == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for Group 3/4 reference line"); + return (0); + } + } else /* 1d encoding */ + EncoderState(tif)->refline = NULL; + + return (1); +} + +/* + * CCITT Group 3 FAX Encoding. + */ + +#define Fax3FlushBits(tif, sp) { \ + if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) { \ + if( !TIFFFlushData1(tif) ) \ + return 0; \ + } \ + *(tif)->tif_rawcp++ = (uint8_t) (sp)->data; \ + (tif)->tif_rawcc++; \ + (sp)->data = 0, (sp)->bit = 8; \ +} +#define _FlushBits(tif) { \ + if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) { \ + if( !TIFFFlushData1(tif) ) \ + return 0; \ + } \ + *(tif)->tif_rawcp++ = (uint8_t) data; \ + (tif)->tif_rawcc++; \ + data = 0, bit = 8; \ +} +static const int _msbmask[9] = + { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; +#define _PutBits(tif, bits, length) { \ + while (length > bit) { \ + data |= bits >> (length - bit); \ + length -= bit; \ + _FlushBits(tif); \ + } \ + assert( length < 9 ); \ + data |= (bits & _msbmask[length]) << (bit - length); \ + bit -= length; \ + if (bit == 0) \ + _FlushBits(tif); \ +} + +/* + * Write a variable-length bit-value to + * the output stream. Values are + * assumed to be at most 16 bits. + */ +static int +Fax3PutBits(TIFF* tif, unsigned int bits, unsigned int length) +{ + Fax3CodecState* sp = EncoderState(tif); + unsigned int bit = sp->bit; + int data = sp->data; + + _PutBits(tif, bits, length); + + sp->data = data; + sp->bit = bit; + return 1; +} + +/* + * Write a code to the output stream. + */ +#define putcode(tif, te) Fax3PutBits(tif, (te)->code, (te)->length) + +#ifdef FAX3_DEBUG +#define DEBUG_COLOR(w) (tab == TIFFFaxWhiteCodes ? w "W" : w "B") +#define DEBUG_PRINT(what,len) { \ + int t; \ + printf("%08"PRIX32"/%-2d: %s%5d\t", data, bit, DEBUG_COLOR(what), len); \ + for (t = length-1; t >= 0; t--) \ + putchar(code & (1<bit; + int data = sp->data; + unsigned int code, length; + + while (span >= 2624) { + const tableentry* te = &tab[63 + (2560>>6)]; + code = te->code; + length = te->length; +#ifdef FAX3_DEBUG + DEBUG_PRINT("MakeUp", te->runlen); +#endif + _PutBits(tif, code, length); + span -= te->runlen; + } + if (span >= 64) { + const tableentry* te = &tab[63 + (span>>6)]; + assert(te->runlen == 64*(span>>6)); + code = te->code; + length = te->length; +#ifdef FAX3_DEBUG + DEBUG_PRINT("MakeUp", te->runlen); +#endif + _PutBits(tif, code, length); + span -= te->runlen; + } + code = tab[span].code; + length = tab[span].length; +#ifdef FAX3_DEBUG + DEBUG_PRINT(" Term", tab[span].runlen); +#endif + _PutBits(tif, code, length); + + sp->data = data; + sp->bit = bit; + + return 1; +} + +/* + * Write an EOL code to the output stream. The zero-fill + * logic for byte-aligning encoded scanlines is handled + * here. We also handle writing the tag bit for the next + * scanline when doing 2d encoding. + */ +static int +Fax3PutEOL(TIFF* tif) +{ + Fax3CodecState* sp = EncoderState(tif); + unsigned int bit = sp->bit; + int data = sp->data; + unsigned int code, length, tparm; + + if (sp->b.groupoptions & GROUP3OPT_FILLBITS) { + /* + * Force bit alignment so EOL will terminate on + * a byte boundary. That is, force the bit alignment + * to 16-12 = 4 before putting out the EOL code. + */ + int align = 8 - 4; + if (align != sp->bit) { + if (align > sp->bit) + align = sp->bit + (8 - align); + else + align = sp->bit - align; + tparm=align; + _PutBits(tif, 0, tparm); + } + } + code = EOL; + length = 12; + if (is2DEncoding(sp)) { + code = (code<<1) | (sp->tag == G3_1D); + length++; + } + _PutBits(tif, code, length); + + sp->data = data; + sp->bit = bit; + + return 1; +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +Fax3PreEncode(TIFF* tif, uint16_t s) +{ + Fax3CodecState* sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + sp->bit = 8; + sp->data = 0; + sp->tag = G3_1D; + /* + * This is necessary for Group 4; otherwise it isn't + * needed because the first scanline of each strip ends + * up being copied into the refline. + */ + if (sp->refline) + _TIFFmemset(sp->refline, 0x00, sp->b.rowbytes); + if (is2DEncoding(sp)) { + float res = tif->tif_dir.td_yresolution; + /* + * The CCITT spec says that when doing 2d encoding, you + * should only do it on K consecutive scanlines, where K + * depends on the resolution of the image being encoded + * (2 for <= 200 lpi, 4 for > 200 lpi). Since the directory + * code initializes td_yresolution to 0, this code will + * select a K of 2 unless the YResolution tag is set + * appropriately. (Note also that we fudge a little here + * and use 150 lpi to avoid problems with units conversion.) + */ + if (tif->tif_dir.td_resolutionunit == RESUNIT_CENTIMETER) + res *= 2.54f; /* convert to inches */ + sp->maxk = (res > 150 ? 4 : 2); + sp->k = sp->maxk-1; + } else + sp->k = sp->maxk = 0; + sp->line = 0; + return (1); +} + +static const unsigned char zeroruns[256] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 - 0xff */ +}; +static const unsigned char oneruns[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */ + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, /* 0xf0 - 0xff */ +}; + +/* + * Find a span of ones or zeros using the supplied + * table. The ``base'' of the bit string is supplied + * along with the start+end bit indices. + */ +static inline int32_t +find0span(unsigned char* bp, int32_t bs, int32_t be) +{ + int32_t bits = be - bs; + int32_t n, span; + + bp += bs>>3; + /* + * Check partial byte on lhs. + */ + if (bits > 0 && (n = (bs & 7)) != 0) { + span = zeroruns[(*bp << n) & 0xff]; + if (span > 8-n) /* table value too generous */ + span = 8-n; + if (span > bits) /* constrain span to bit range */ + span = bits; + if (n+span < 8) /* doesn't extend to edge of byte */ + return (span); + bits -= span; + bp++; + } else + span = 0; + if (bits >= (int32_t)(2 * 8 * sizeof(int64_t))) { + int64_t* lp; + /* + * Align to int64_t boundary and check int64_t words. + */ + while (!isAligned(bp, int64_t)) { + if (*bp != 0x00) + return (span + zeroruns[*bp]); + span += 8; + bits -= 8; + bp++; + } + lp = (int64_t*) bp; + while ((bits >= (int32_t)(8 * sizeof(int64_t))) && (0 == *lp)) { + span += 8*sizeof (int64_t); + bits -= 8*sizeof (int64_t); + lp++; + } + bp = (unsigned char*) lp; + } + /* + * Scan full bytes for all 0's. + */ + while (bits >= 8) { + if (*bp != 0x00) /* end of run */ + return (span + zeroruns[*bp]); + span += 8; + bits -= 8; + bp++; + } + /* + * Check partial byte on rhs. + */ + if (bits > 0) { + n = zeroruns[*bp]; + span += (n > bits ? bits : n); + } + return (span); +} + +static inline int32_t +find1span(unsigned char* bp, int32_t bs, int32_t be) +{ + int32_t bits = be - bs; + int32_t n, span; + + bp += bs>>3; + /* + * Check partial byte on lhs. + */ + if (bits > 0 && (n = (bs & 7)) != 0) { + span = oneruns[(*bp << n) & 0xff]; + if (span > 8-n) /* table value too generous */ + span = 8-n; + if (span > bits) /* constrain span to bit range */ + span = bits; + if (n+span < 8) /* doesn't extend to edge of byte */ + return (span); + bits -= span; + bp++; + } else + span = 0; + if (bits >= (int32_t)(2 * 8 * sizeof(int64_t))) { + int64_t* lp; + /* + * Align to int64_t boundary and check int64_t words. + */ + while (!isAligned(bp, int64_t)) { + if (*bp != 0xff) + return (span + oneruns[*bp]); + span += 8; + bits -= 8; + bp++; + } + lp = (int64_t*) bp; + while ((bits >= (int32_t)(8 * sizeof(int64_t))) && (~((uint64_t)0) == (uint64_t)*lp)) { + span += 8*sizeof (int64_t); + bits -= 8*sizeof (int64_t); + lp++; + } + bp = (unsigned char*) lp; + } + /* + * Scan full bytes for all 1's. + */ + while (bits >= 8) { + if (*bp != 0xff) /* end of run */ + return (span + oneruns[*bp]); + span += 8; + bits -= 8; + bp++; + } + /* + * Check partial byte on rhs. + */ + if (bits > 0) { + n = oneruns[*bp]; + span += (n > bits ? bits : n); + } + return (span); +} + +/* + * Return the offset of the next bit in the range + * [bs..be] that is different from the specified + * color. The end, be, is returned if no such bit + * exists. + */ +#define finddiff(_cp, _bs, _be, _color) \ + (_bs + (_color ? find1span(_cp,_bs,_be) : find0span(_cp,_bs,_be))) +/* + * Like finddiff, but also check the starting bit + * against the end in case start > end. + */ +#define finddiff2(_cp, _bs, _be, _color) \ + (_bs < _be ? finddiff(_cp,_bs,_be,_color) : _be) + +/* + * 1d-encode a row of pixels. The encoding is + * a sequence of all-white or all-black spans + * of pixels encoded with Huffman codes. + */ +static int +Fax3Encode1DRow(TIFF* tif, unsigned char* bp, uint32_t bits) +{ + Fax3CodecState* sp = EncoderState(tif); + int32_t span; + uint32_t bs = 0; + + for (;;) { + span = find0span(bp, bs, bits); /* white span */ + if( !putspan(tif, span, TIFFFaxWhiteCodes) ) + return 0; + bs += span; + if (bs >= bits) + break; + span = find1span(bp, bs, bits); /* black span */ + if( !putspan(tif, span, TIFFFaxBlackCodes) ) + return 0; + bs += span; + if (bs >= bits) + break; + } + if (sp->b.mode & (FAXMODE_BYTEALIGN|FAXMODE_WORDALIGN)) { + if (sp->bit != 8) /* byte-align */ + Fax3FlushBits(tif, sp); + if ((sp->b.mode&FAXMODE_WORDALIGN) && + !isAligned(tif->tif_rawcp, uint16_t)) + Fax3FlushBits(tif, sp); + } + return (1); +} + +static const tableentry horizcode = + { 3, 0x1, 0 }; /* 001 */ +static const tableentry passcode = + { 4, 0x1, 0 }; /* 0001 */ +static const tableentry vcodes[7] = { + { 7, 0x03, 0 }, /* 0000 011 */ + { 6, 0x03, 0 }, /* 0000 11 */ + { 3, 0x03, 0 }, /* 011 */ + { 1, 0x1, 0 }, /* 1 */ + { 3, 0x2, 0 }, /* 010 */ + { 6, 0x02, 0 }, /* 0000 10 */ + { 7, 0x02, 0 } /* 0000 010 */ +}; + +/* + * 2d-encode a row of pixels. Consult the CCITT + * documentation for the algorithm. + */ +static int +Fax3Encode2DRow(TIFF* tif, unsigned char* bp, unsigned char* rp, uint32_t bits) +{ +#define PIXEL(buf,ix) ((((buf)[(ix)>>3]) >> (7-((ix)&7))) & 1) + uint32_t a0 = 0; + uint32_t a1 = (PIXEL(bp, 0) != 0 ? 0 : finddiff(bp, 0, bits, 0)); + uint32_t b1 = (PIXEL(rp, 0) != 0 ? 0 : finddiff(rp, 0, bits, 0)); + uint32_t a2, b2; + + for (;;) { + b2 = finddiff2(rp, b1, bits, PIXEL(rp,b1)); + if (b2 >= a1) { + /* Naive computation triggers -fsanitize=undefined,unsigned-integer-overflow */ + /* although it is correct unless the difference between both is < 31 bit */ + /* int32_t d = b1 - a1; */ + int32_t d = (b1 >= a1 && b1 - a1 <= 3U) ? (int32_t)(b1 - a1) : + (b1 < a1 && a1 - b1 <= 3U) ? -(int32_t)(a1 - b1) : 0x7FFFFFFF; + if (!(-3 <= d && d <= 3)) { /* horizontal mode */ + a2 = finddiff2(bp, a1, bits, PIXEL(bp,a1)); + if( !putcode(tif, &horizcode) ) + return 0; + if (a0+a1 == 0 || PIXEL(bp, a0) == 0) { + if( !putspan(tif, a1-a0, TIFFFaxWhiteCodes) ) + return 0; + if( !putspan(tif, a2-a1, TIFFFaxBlackCodes) ) + return 0; + } else { + if( !putspan(tif, a1-a0, TIFFFaxBlackCodes) ) + return 0; + if( !putspan(tif, a2-a1, TIFFFaxWhiteCodes) ) + return 0; + } + a0 = a2; + } else { /* vertical mode */ + if( !putcode(tif, &vcodes[d+3]) ) + return 0; + a0 = a1; + } + } else { /* pass mode */ + if( !putcode(tif, &passcode) ) + return 0; + a0 = b2; + } + if (a0 >= bits) + break; + a1 = finddiff(bp, a0, bits, PIXEL(bp,a0)); + b1 = finddiff(rp, a0, bits, !PIXEL(bp,a0)); + b1 = finddiff(rp, b1, bits, PIXEL(bp,a0)); + } + return (1); +#undef PIXEL +} + +/* + * Encode a buffer of pixels. + */ +static int +Fax3Encode(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "Fax3Encode"; + Fax3CodecState* sp = EncoderState(tif); + (void) s; + if (cc % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be written"); + return (0); + } + while (cc > 0) { + if ((sp->b.mode & FAXMODE_NOEOL) == 0) + { + if( !Fax3PutEOL(tif) ) + return 0; + } + if (is2DEncoding(sp)) { + if (sp->tag == G3_1D) { + if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels)) + return (0); + sp->tag = G3_2D; + } else { + if (!Fax3Encode2DRow(tif, bp, sp->refline, + sp->b.rowpixels)) + return (0); + sp->k--; + } + if (sp->k == 0) { + sp->tag = G3_1D; + sp->k = sp->maxk-1; + } else + _TIFFmemcpy(sp->refline, bp, sp->b.rowbytes); + } else { + if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels)) + return (0); + } + bp += sp->b.rowbytes; + cc -= sp->b.rowbytes; + } + return (1); +} + +static int +Fax3PostEncode(TIFF* tif) +{ + Fax3CodecState* sp = EncoderState(tif); + + if (sp->bit != 8) + Fax3FlushBits(tif, sp); + return (1); +} + +static int +_Fax3Close(TIFF* tif) +{ + if ((Fax3State(tif)->mode & FAXMODE_NORTC) == 0 && tif->tif_rawcp) { + Fax3CodecState* sp = EncoderState(tif); + unsigned int code = EOL; + unsigned int length = 12; + int i; + + if (is2DEncoding(sp)) { + code = (code<<1) | (sp->tag == G3_1D); + length++; + } + for (i = 0; i < 6; i++) + Fax3PutBits(tif, code, length); + Fax3FlushBits(tif, sp); + } + return 1; +} + +static void +Fax3Close(TIFF* tif) +{ + _Fax3Close(tif); +} + +static void +Fax3Cleanup(TIFF* tif) +{ + Fax3CodecState* sp = DecoderState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->b.vgetparent; + tif->tif_tagmethods.vsetfield = sp->b.vsetparent; + tif->tif_tagmethods.printdir = sp->b.printdir; + + if (sp->runs) + _TIFFfree(sp->runs); + if (sp->refline) + _TIFFfree(sp->refline); + + _TIFFfree(tif->tif_data); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +#define FIELD_BADFAXLINES (FIELD_CODEC+0) +#define FIELD_CLEANFAXDATA (FIELD_CODEC+1) +#define FIELD_BADFAXRUN (FIELD_CODEC+2) + +#define FIELD_OPTIONS (FIELD_CODEC+7) + +static const TIFFField faxFields[] = { + { TIFFTAG_FAXMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "FaxMode", NULL }, + { TIFFTAG_FAXFILLFUNC, 0, 0, TIFF_ANY, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "FaxFillFunc", NULL }, + { TIFFTAG_BADFAXLINES, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_BADFAXLINES, TRUE, FALSE, "BadFaxLines", NULL }, + { TIFFTAG_CLEANFAXDATA, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UINT16, FIELD_CLEANFAXDATA, TRUE, FALSE, "CleanFaxData", NULL }, + { TIFFTAG_CONSECUTIVEBADFAXLINES, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_BADFAXRUN, TRUE, FALSE, "ConsecutiveBadFaxLines", NULL }}; +static const TIFFField fax3Fields[] = { + { TIFFTAG_GROUP3OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group3Options", NULL }, +}; +static const TIFFField fax4Fields[] = { + { TIFFTAG_GROUP4OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group4Options", NULL }, +}; + +static int +Fax3VSetField(TIFF* tif, uint32_t tag, va_list ap) +{ + Fax3BaseState* sp = Fax3State(tif); + const TIFFField* fip; + + assert(sp != 0); + assert(sp->vsetparent != 0); + + switch (tag) { + case TIFFTAG_FAXMODE: + sp->mode = (int) va_arg(ap, int); + return 1; /* NB: pseudo tag */ + case TIFFTAG_FAXFILLFUNC: + DecoderState(tif)->fill = va_arg(ap, TIFFFaxFillFunc); + return 1; /* NB: pseudo tag */ + case TIFFTAG_GROUP3OPTIONS: + /* XXX: avoid reading options if compression mismatches. */ + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX3) + sp->groupoptions = (uint32_t) va_arg(ap, uint32_t); + break; + case TIFFTAG_GROUP4OPTIONS: + /* XXX: avoid reading options if compression mismatches. */ + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) + sp->groupoptions = (uint32_t) va_arg(ap, uint32_t); + break; + case TIFFTAG_BADFAXLINES: + sp->badfaxlines = (uint32_t) va_arg(ap, uint32_t); + break; + case TIFFTAG_CLEANFAXDATA: + sp->cleanfaxdata = (uint16_t) va_arg(ap, uint16_vap); + break; + case TIFFTAG_CONSECUTIVEBADFAXLINES: + sp->badfaxrun = (uint32_t) va_arg(ap, uint32_t); + break; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + + if ((fip = TIFFFieldWithTag(tif, tag)) != NULL) + TIFFSetFieldBit(tif, fip->field_bit); + else + return 0; + + tif->tif_flags |= TIFF_DIRTYDIRECT; + return 1; +} + +static int +Fax3VGetField(TIFF* tif, uint32_t tag, va_list ap) +{ + Fax3BaseState* sp = Fax3State(tif); + + assert(sp != 0); + + switch (tag) { + case TIFFTAG_FAXMODE: + *va_arg(ap, int*) = sp->mode; + break; + case TIFFTAG_FAXFILLFUNC: + *va_arg(ap, TIFFFaxFillFunc*) = DecoderState(tif)->fill; + break; + case TIFFTAG_GROUP3OPTIONS: + case TIFFTAG_GROUP4OPTIONS: + *va_arg(ap, uint32_t*) = sp->groupoptions; + break; + case TIFFTAG_BADFAXLINES: + *va_arg(ap, uint32_t*) = sp->badfaxlines; + break; + case TIFFTAG_CLEANFAXDATA: + *va_arg(ap, uint16_t*) = sp->cleanfaxdata; + break; + case TIFFTAG_CONSECUTIVEBADFAXLINES: + *va_arg(ap, uint32_t*) = sp->badfaxrun; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static void +Fax3PrintDir(TIFF* tif, FILE* fd, long flags) +{ + Fax3BaseState* sp = Fax3State(tif); + + assert(sp != 0); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_OPTIONS)) { + const char* sep = " "; + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) { + fprintf(fd, " Group 4 Options:"); + if (sp->groupoptions & GROUP4OPT_UNCOMPRESSED) + fprintf(fd, "%suncompressed data", sep); + } else { + + fprintf(fd, " Group 3 Options:"); + if (sp->groupoptions & GROUP3OPT_2DENCODING) { + fprintf(fd, "%s2-d encoding", sep); + sep = "+"; + } + if (sp->groupoptions & GROUP3OPT_FILLBITS) { + fprintf(fd, "%sEOL padding", sep); + sep = "+"; + } + if (sp->groupoptions & GROUP3OPT_UNCOMPRESSED) + fprintf(fd, "%suncompressed data", sep); + } + fprintf(fd, " (%" PRIu32 " = 0x%" PRIx32 ")\n", + sp->groupoptions, + sp->groupoptions); + } + if (TIFFFieldSet(tif,FIELD_CLEANFAXDATA)) { + fprintf(fd, " Fax Data:"); + switch (sp->cleanfaxdata) { + case CLEANFAXDATA_CLEAN: + fprintf(fd, " clean"); + break; + case CLEANFAXDATA_REGENERATED: + fprintf(fd, " receiver regenerated"); + break; + case CLEANFAXDATA_UNCLEAN: + fprintf(fd, " uncorrected errors"); + break; + } + fprintf(fd, " (%"PRIu16" = 0x%"PRIx16")\n", + sp->cleanfaxdata, sp->cleanfaxdata); + } + if (TIFFFieldSet(tif,FIELD_BADFAXLINES)) + fprintf(fd, " Bad Fax Lines: %" PRIu32 "\n", + sp->badfaxlines); + if (TIFFFieldSet(tif,FIELD_BADFAXRUN)) + fprintf(fd, " Consecutive Bad Fax Lines: %" PRIu32 "\n", + sp->badfaxrun); + if (sp->printdir) + (*sp->printdir)(tif, fd, flags); +} + +static int +InitCCITTFax3(TIFF* tif) +{ + static const char module[] = "InitCCITTFax3"; + Fax3BaseState* sp; + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, faxFields, TIFFArrayCount(faxFields))) { + TIFFErrorExt(tif->tif_clientdata, "InitCCITTFax3", + "Merging common CCITT Fax codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t*) + _TIFFmalloc(sizeof (Fax3CodecState)); + + if (tif->tif_data == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for state block"); + return (0); + } + _TIFFmemset(tif->tif_data, 0, sizeof (Fax3CodecState)); + + sp = Fax3State(tif); + sp->rw_mode = tif->tif_mode; + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = Fax3VGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = Fax3VSetField; /* hook for codec tags */ + sp->printdir = tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir = Fax3PrintDir; /* hook for codec tags */ + sp->groupoptions = 0; + + if (sp->rw_mode == O_RDONLY) /* FIXME: improve for in place update */ + tif->tif_flags |= TIFF_NOBITREV; /* decoder does bit reversal */ + DecoderState(tif)->runs = NULL; + TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, _TIFFFax3fillruns); + EncoderState(tif)->refline = NULL; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = Fax3FixupTags; + tif->tif_setupdecode = Fax3SetupState; + tif->tif_predecode = Fax3PreDecode; + tif->tif_decoderow = Fax3Decode1D; + tif->tif_decodestrip = Fax3Decode1D; + tif->tif_decodetile = Fax3Decode1D; + tif->tif_setupencode = Fax3SetupState; + tif->tif_preencode = Fax3PreEncode; + tif->tif_postencode = Fax3PostEncode; + tif->tif_encoderow = Fax3Encode; + tif->tif_encodestrip = Fax3Encode; + tif->tif_encodetile = Fax3Encode; + tif->tif_close = Fax3Close; + tif->tif_cleanup = Fax3Cleanup; + + return (1); +} + +int +TIFFInitCCITTFax3(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, fax3Fields, + TIFFArrayCount(fax3Fields))) { + TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax3", + "Merging CCITT Fax 3 codec-specific tags failed"); + return 0; + } + + /* + * The default format is Class/F-style w/o RTC. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_CLASSF); + } else + return 01; +} + +/* + * CCITT Group 4 (T.6) Facsimile-compatible + * Compression Scheme Support. + */ + +#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; } +/* + * Decode the requested amount of G4-encoded data. + */ +static int +Fax4Decode(TIFF* tif, uint8_t* buf, tmsize_t occ, uint16_t s) +{ + DECLARE_STATE_2D(tif, sp, "Fax4Decode"); + (void) s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (-1); + } + CACHE_STATE(tif, sp); + while (occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun = sp->curruns; + pb = sp->refruns; + b1 = *pb++; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08"PRIX32", BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); +#endif + EXPAND2D(EOFG4); + if (EOLcnt) + goto EOFG4; + if (((lastx + 7) >> 3) > (int)occ) /* check for buffer overrun */ + { + TIFFErrorExt(tif->tif_clientdata, module, + "Buffer overrun detected : %"TIFF_SSIZE_FORMAT" bytes available, %d bits needed", + occ, lastx); + return -1; + } + (*sp->fill)(buf, thisrun, pa, lastx); + SETVALUE(0); /* imaginary change for reference */ + SWAP(uint32_t*, sp->curruns, sp->refruns); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOFG4: + NeedBits16( 13, BADG4 ); + BADG4: +#ifdef FAX3_DEBUG + if( GetBits(13) != 0x1001 ) + fputs( "Bad EOFB\n", stderr ); +#endif + ClrBits( 13 ); + if (((lastx + 7) >> 3) > (int)occ) /* check for buffer overrun */ + { + TIFFErrorExt(tif->tif_clientdata, module, + "Buffer overrun detected : %"TIFF_SSIZE_FORMAT" bytes available, %d bits needed", + occ, lastx); + return -1; + } + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return ( sp->line ? 1 : -1); /* don't error on badly-terminated strips */ + } + UNCACHE_STATE(tif, sp); + return (1); +} +#undef SWAP + +/* + * Encode the requested amount of data. + */ +static int +Fax4Encode(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "Fax4Encode"; + Fax3CodecState *sp = EncoderState(tif); + (void) s; + if (cc % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be written"); + return (0); + } + while (cc > 0) { + if (!Fax3Encode2DRow(tif, bp, sp->refline, sp->b.rowpixels)) + return (0); + _TIFFmemcpy(sp->refline, bp, sp->b.rowbytes); + bp += sp->b.rowbytes; + cc -= sp->b.rowbytes; + } + return (1); +} + +static int +Fax4PostEncode(TIFF* tif) +{ + Fax3CodecState *sp = EncoderState(tif); + + /* terminate strip w/ EOFB */ + Fax3PutBits(tif, EOL, 12); + Fax3PutBits(tif, EOL, 12); + if (sp->bit != 8) + Fax3FlushBits(tif, sp); + return (1); +} + +int +TIFFInitCCITTFax4(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, fax4Fields, + TIFFArrayCount(fax4Fields))) { + TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax4", + "Merging CCITT Fax 4 codec-specific tags failed"); + return 0; + } + + tif->tif_decoderow = Fax4Decode; + tif->tif_decodestrip = Fax4Decode; + tif->tif_decodetile = Fax4Decode; + tif->tif_encoderow = Fax4Encode; + tif->tif_encodestrip = Fax4Encode; + tif->tif_encodetile = Fax4Encode; + tif->tif_postencode = Fax4PostEncode; + /* + * Suppress RTC at the end of each strip. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_NORTC); + } else + return (0); +} + +/* + * CCITT Group 3 1-D Modified Huffman RLE Compression Support. + * (Compression algorithms 2 and 32771) + */ + +/* + * Decode the requested amount of RLE-encoded data. + */ +static int +Fax3DecodeRLE(TIFF* tif, uint8_t* buf, tmsize_t occ, uint16_t s) +{ + DECLARE_STATE(tif, sp, "Fax3DecodeRLE"); + int mode = sp->b.mode; + (void) s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (-1); + } + CACHE_STATE(tif, sp); + thisrun = sp->curruns; + while (occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08"PRIX32", BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %"PRIu32"\n", tif->tif_row); + fflush(stdout); +#endif + EXPAND1D(EOFRLE); + (*sp->fill)(buf, thisrun, pa, lastx); + /* + * Cleanup at the end of the row. + */ + if (mode & FAXMODE_BYTEALIGN) { + int n = BitsAvail - (BitsAvail &~ 7); + ClrBits(n); + } else if (mode & FAXMODE_WORDALIGN) { + int n = BitsAvail - (BitsAvail &~ 15); + ClrBits(n); + if (BitsAvail == 0 && !isAligned(cp, uint16_t)) + cp++; + } + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + sp->line++; + continue; + EOFRLE: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} + +int +TIFFInitCCITTRLE(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + tif->tif_decoderow = Fax3DecodeRLE; + tif->tif_decodestrip = Fax3DecodeRLE; + tif->tif_decodetile = Fax3DecodeRLE; + /* + * Suppress RTC+EOLs when encoding and byte-align data. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, + FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_BYTEALIGN); + } else + return (0); +} + +int +TIFFInitCCITTRLEW(TIFF* tif, int scheme) +{ + (void) scheme; + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + tif->tif_decoderow = Fax3DecodeRLE; + tif->tif_decodestrip = Fax3DecodeRLE; + tif->tif_decodetile = Fax3DecodeRLE; + /* + * Suppress RTC+EOLs when encoding and word-align data. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, + FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_WORDALIGN); + } else + return (0); +} +#endif /* CCITT_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_fax3.h b/libs/tiff/libtiff/tif_fax3.h new file mode 100644 index 00000000000..fdafe4920dc --- /dev/null +++ b/libs/tiff/libtiff/tif_fax3.h @@ -0,0 +1,567 @@ +/* + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _FAX3_ +#define _FAX3_ +/* + * TIFF Library. + * + * CCITT Group 3 (T.4) and Group 4 (T.6) Decompression Support. + * + * Decoder support is derived, with permission, from the code + * in Frank Cringle's viewfax program; + * Copyright (C) 1990, 1995 Frank D. Cringle. + */ +#include "tiff.h" + +/* + * To override the default routine used to image decoded + * spans one can use the pseudo tag TIFFTAG_FAXFILLFUNC. + * The routine must have the type signature given below; + * for example: + * + * fillruns(unsigned char* buf, uint32_t* runs, uint32_t* erun, uint32_t lastx) + * + * where buf is place to set the bits, runs is the array of b&w run + * lengths (white then black), erun is the last run in the array, and + * lastx is the width of the row in pixels. Fill routines can assume + * the run array has room for at least lastx runs and can overwrite + * data in the run array as needed (e.g. to append zero runs to bring + * the count up to a nice multiple). + */ +typedef void (*TIFFFaxFillFunc)(unsigned char*, uint32_t*, uint32_t*, uint32_t); + +/* + * The default run filler; made external for other decoders. + */ +#if defined(__cplusplus) +extern "C" { +#endif +extern void _TIFFFax3fillruns(unsigned char*, uint32_t*, uint32_t*, uint32_t); +#if defined(__cplusplus) +} +#endif + + +/* finite state machine codes */ +#define S_Null 0 +#define S_Pass 1 +#define S_Horiz 2 +#define S_V0 3 +#define S_VR 4 +#define S_VL 5 +#define S_Ext 6 +#define S_TermW 7 +#define S_TermB 8 +#define S_MakeUpW 9 +#define S_MakeUpB 10 +#define S_MakeUp 11 +#define S_EOL 12 + +/* WARNING: do not change the layout of this structure as the HylaFAX software */ +/* really depends on it. See http://bugzilla.maptools.org/show_bug.cgi?id=2636 */ +typedef struct { /* state table entry */ + unsigned char State; /* see above */ + unsigned char Width; /* width of code in bits */ + uint32_t Param; /* unsigned 32-bit run length in bits (holds on 16 bit actually, but cannot be changed. See above warning) */ +} TIFFFaxTabEnt; + +extern const TIFFFaxTabEnt TIFFFaxMainTable[]; +extern const TIFFFaxTabEnt TIFFFaxWhiteTable[]; +extern const TIFFFaxTabEnt TIFFFaxBlackTable[]; + +/* + * The following macros define the majority of the G3/G4 decoder + * algorithm using the state tables defined elsewhere. To build + * a decoder you need some setup code and some glue code. Note + * that you may also need/want to change the way the NeedBits* + * macros get input data if, for example, you know the data to be + * decoded is properly aligned and oriented (doing so before running + * the decoder can be a big performance win). + * + * Consult the decoder in the TIFF library for an idea of what you + * need to define and setup to make use of these definitions. + * + * NB: to enable a debugging version of these macros define FAX3_DEBUG + * before including this file. Trace output goes to stdout. + */ + +#ifndef EndOfData +#define EndOfData() (cp >= ep) +#endif +/* + * Need <=8 or <=16 bits of input data. Unlike viewfax we + * cannot use/assume a word-aligned, properly bit swizzled + * input data set because data may come from an arbitrarily + * aligned, read-only source such as a memory-mapped file. + * Note also that the viewfax decoder does not check for + * running off the end of the input data buffer. This is + * possible for G3-encoded data because it prescans the input + * data to count EOL markers, but can cause problems for G4 + * data. In any event, we don't prescan and must watch for + * running out of data since we can't permit the library to + * scan past the end of the input data buffer. + * + * Finally, note that we must handle remaindered data at the end + * of a strip specially. The coder asks for a fixed number of + * bits when scanning for the next code. This may be more bits + * than are actually present in the data stream. If we appear + * to run out of data but still have some number of valid bits + * remaining then we makeup the requested amount with zeros and + * return successfully. If the returned data is incorrect then + * we should be called again and get a premature EOF error; + * otherwise we should get the right answer. + */ +#ifndef NeedBits8 +#define NeedBits8(n,eoflab) do { \ + if (BitsAvail < (n)) { \ + if (EndOfData()) { \ + if (BitsAvail == 0) /* no valid bits */ \ + goto eoflab; \ + BitsAvail = (n); /* pad with zeros */ \ + } else { \ + BitAcc |= ((uint32_t) bitmap[*cp++])<>= (n); \ +} while (0) + +#ifdef FAX3_DEBUG +static const char* StateNames[] = { + "Null ", + "Pass ", + "Horiz ", + "V0 ", + "VR ", + "VL ", + "Ext ", + "TermW ", + "TermB ", + "MakeUpW", + "MakeUpB", + "MakeUp ", + "EOL ", +}; +#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0') +#define LOOKUP8(wid,tab,eoflab) do { \ + int t; \ + NeedBits8(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \ + StateNames[TabEnt->State], TabEnt->Param); \ + for (t = 0; t < TabEnt->Width; t++) \ + DEBUG_SHOW; \ + putchar('\n'); \ + fflush(stdout); \ + ClrBits(TabEnt->Width); \ +} while (0) +#define LOOKUP16(wid,tab,eoflab) do { \ + int t; \ + NeedBits16(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \ + StateNames[TabEnt->State], TabEnt->Param); \ + for (t = 0; t < TabEnt->Width; t++) \ + DEBUG_SHOW; \ + putchar('\n'); \ + fflush(stdout); \ + ClrBits(TabEnt->Width); \ +} while (0) + +#define SETVALUE(x) do { \ + *pa++ = RunLength + (x); \ + printf("SETVALUE: %d\t%d\n", RunLength + (x), a0); \ + a0 += x; \ + RunLength = 0; \ +} while (0) +#else +#define LOOKUP8(wid,tab,eoflab) do { \ + NeedBits8(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + ClrBits(TabEnt->Width); \ +} while (0) +#define LOOKUP16(wid,tab,eoflab) do { \ + NeedBits16(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + ClrBits(TabEnt->Width); \ +} while (0) + +/* + * Append a run to the run length array for the + * current row and reset decoding state. + */ +#define SETVALUE(x) do { \ + if (pa >= thisrun + sp->nruns) { \ + TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ + sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ + return (-1); \ + } \ + *pa++ = RunLength + (x); \ + a0 += (x); \ + RunLength = 0; \ +} while (0) +#endif + +/* + * Synchronize input decoding at the start of each + * row by scanning for an EOL (if appropriate) and + * skipping any trash data that might be present + * after a decoding error. Note that the decoding + * done elsewhere that recognizes an EOL only consumes + * 11 consecutive zero bits. This means that if EOLcnt + * is non-zero then we still need to scan for the final flag + * bit that is part of the EOL code. + */ +#define SYNC_EOL(eoflab) do { \ + if (EOLcnt == 0) { \ + for (;;) { \ + NeedBits16(11,eoflab); \ + if (GetBits(11) == 0) \ + break; \ + ClrBits(1); \ + } \ + } \ + for (;;) { \ + NeedBits8(8,eoflab); \ + if (GetBits(8)) \ + break; \ + ClrBits(8); \ + } \ + while (GetBits(1) == 0) \ + ClrBits(1); \ + ClrBits(1); /* EOL bit */ \ + EOLcnt = 0; /* reset EOL counter/flag */ \ +} while (0) + +/* + * Cleanup the array of runs after decoding a row. + * We adjust final runs to insure the user buffer is not + * overwritten and/or undecoded area is white filled. + */ +#define CLEANUP_RUNS() do { \ + if (RunLength) \ + SETVALUE(0); \ + if (a0 != lastx) { \ + badlength(a0, lastx); \ + while (a0 > lastx && pa > thisrun) \ + a0 -= *--pa; \ + if (a0 < lastx) { \ + if (a0 < 0) \ + a0 = 0; \ + if ((pa-thisrun)&1) \ + SETVALUE(0); \ + SETVALUE(lastx - a0); \ + } else if (a0 > lastx) { \ + SETVALUE(lastx); \ + SETVALUE(0); \ + } \ + } \ +} while (0) + +/* + * Decode a line of 1D-encoded data. + * + * The line expanders are written as macros so that they can be reused + * but still have direct access to the local variables of the "calling" + * function. + * + * Note that unlike the original version we have to explicitly test for + * a0 >= lastx after each black/white run is decoded. This is because + * the original code depended on the input data being zero-padded to + * insure the decoder recognized an EOL before running out of data. + */ +#define EXPAND1D(eoflab) do { \ + for (;;) { \ + for (;;) { \ + LOOKUP16(12, TIFFFaxWhiteTable, eof1d); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto done1d; \ + case S_TermW: \ + SETVALUE(TabEnt->Param); \ + goto doneWhite1d; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("WhiteTable", a0); \ + goto done1d; \ + } \ + } \ + doneWhite1d: \ + if (a0 >= lastx) \ + goto done1d; \ + for (;;) { \ + LOOKUP16(13, TIFFFaxBlackTable, eof1d); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto done1d; \ + case S_TermB: \ + SETVALUE(TabEnt->Param); \ + goto doneBlack1d; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("BlackTable", a0); \ + goto done1d; \ + } \ + } \ + doneBlack1d: \ + if (a0 >= lastx) \ + goto done1d; \ + if( *(pa-1) == 0 && *(pa-2) == 0 ) \ + pa -= 2; \ + } \ +eof1d: \ + prematureEOF(a0); \ + CLEANUP_RUNS(); \ + goto eoflab; \ +done1d: \ + CLEANUP_RUNS(); \ +} while (0) + +/* + * Update the value of b1 using the array + * of runs for the reference line. + */ +#define CHECK_b1 do { \ + if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \ + if( pb + 1 >= sp->refruns + sp->nruns) { \ + TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ + sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ + return (-1); \ + } \ + b1 += pb[0] + pb[1]; \ + pb += 2; \ + } \ +} while (0) + +/* + * Expand a row of 2D-encoded data. + */ +#define EXPAND2D(eoflab) do { \ + while (a0 < lastx) { \ + if (pa >= thisrun + sp->nruns) { \ + TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ + sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ + return (-1); \ + } \ + LOOKUP8(7, TIFFFaxMainTable, eof2d); \ + switch (TabEnt->State) { \ + case S_Pass: \ + CHECK_b1; \ + if( pb + 1 >= sp->refruns + sp->nruns) { \ + TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ + sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ + return (-1); \ + } \ + b1 += *pb++; \ + RunLength += b1 - a0; \ + a0 = b1; \ + b1 += *pb++; \ + break; \ + case S_Horiz: \ + if ((pa-thisrun)&1) { \ + for (;;) { /* black first */ \ + LOOKUP16(13, TIFFFaxBlackTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVALUE(TabEnt->Param); \ + goto doneWhite2da; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badBlack2d; \ + } \ + } \ + doneWhite2da:; \ + for (;;) { /* then white */ \ + LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVALUE(TabEnt->Param); \ + goto doneBlack2da; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badWhite2d; \ + } \ + } \ + doneBlack2da:; \ + } else { \ + for (;;) { /* white first */ \ + LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVALUE(TabEnt->Param); \ + goto doneWhite2db; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badWhite2d; \ + } \ + } \ + doneWhite2db:; \ + for (;;) { /* then black */ \ + LOOKUP16(13, TIFFFaxBlackTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVALUE(TabEnt->Param); \ + goto doneBlack2db; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badBlack2d; \ + } \ + } \ + doneBlack2db:; \ + } \ + CHECK_b1; \ + break; \ + case S_V0: \ + CHECK_b1; \ + SETVALUE(b1 - a0); \ + if( pb >= sp->refruns + sp->nruns) { \ + TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ + sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ + return (-1); \ + } \ + b1 += *pb++; \ + break; \ + case S_VR: \ + CHECK_b1; \ + SETVALUE(b1 - a0 + TabEnt->Param); \ + if( pb >= sp->refruns + sp->nruns) { \ + TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ + sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ + return (-1); \ + } \ + b1 += *pb++; \ + break; \ + case S_VL: \ + CHECK_b1; \ + if (b1 < (int) (a0 + TabEnt->Param)) { \ + unexpected("VL", a0); \ + goto eol2d; \ + } \ + SETVALUE(b1 - a0 - TabEnt->Param); \ + b1 -= *--pb; \ + break; \ + case S_Ext: \ + *pa++ = lastx - a0; \ + extension(a0); \ + goto eol2d; \ + case S_EOL: \ + *pa++ = lastx - a0; \ + NeedBits8(4,eof2d); \ + if (GetBits(4)) \ + unexpected("EOL", a0); \ + ClrBits(4); \ + EOLcnt = 1; \ + goto eol2d; \ + default: \ + badMain2d: \ + unexpected("MainTable", a0); \ + goto eol2d; \ + badBlack2d: \ + unexpected("BlackTable", a0); \ + goto eol2d; \ + badWhite2d: \ + unexpected("WhiteTable", a0); \ + goto eol2d; \ + eof2d: \ + prematureEOF(a0); \ + CLEANUP_RUNS(); \ + goto eoflab; \ + } \ + } \ + if (RunLength) { \ + if (RunLength + a0 < lastx) { \ + /* expect a final V0 */ \ + NeedBits8(1,eof2d); \ + if (!GetBits(1)) \ + goto badMain2d; \ + ClrBits(1); \ + } \ + SETVALUE(0); \ + } \ +eol2d: \ + CLEANUP_RUNS(); \ +} while (0) +#endif /* _FAX3_ */ +/* vim: set ts=8 sts=4 sw=4 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_fax3sm.c b/libs/tiff/libtiff/tif_fax3sm.c new file mode 100644 index 00000000000..ba2fc532e80 --- /dev/null +++ b/libs/tiff/libtiff/tif_fax3sm.c @@ -0,0 +1,1261 @@ +/* WARNING, this file was automatically generated by the + mkg3states program */ +#include +#include "tiff.h" +#include "tif_fax3.h" + const TIFFFaxTabEnt TIFFFaxMainTable[128] = { +{12,7,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0}, +{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{5,6,2},{3,1,0},{5,3,1},{3,1,0}, +{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0}, +{4,3,1},{3,1,0},{5,7,3},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}, +{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{4,6,2},{3,1,0}, +{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0}, +{2,3,0},{3,1,0},{4,3,1},{3,1,0},{6,7,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0}, +{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}, +{5,6,2},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0}, +{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{4,7,3},{3,1,0},{5,3,1},{3,1,0}, +{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0}, +{4,3,1},{3,1,0},{4,6,2},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}, +{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0} +}; + const TIFFFaxTabEnt TIFFFaxWhiteTable[4096] = { +{12,11,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1792},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6}, +{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3}, +{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15}, +{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17}, +{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128}, +{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5}, +{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6}, +{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1856},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8}, +{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5}, +{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14}, +{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16}, +{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128}, +{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9}, +{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4}, +{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6}, +{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15}, +{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{11,12,2112},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6}, +{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7}, +{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8}, +{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16}, +{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128}, +{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5}, +{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3}, +{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2368},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6}, +{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3}, +{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15}, +{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17}, +{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128}, +{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5}, +{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6}, +{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8}, +{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5}, +{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14}, +{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16}, +{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128}, +{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{11,12,1984},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9}, +{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4}, +{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6}, +{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15}, +{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1920},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6}, +{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3}, +{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15}, +{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17}, +{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128}, +{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5}, +{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6}, +{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2240},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8}, +{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5}, +{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14}, +{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16}, +{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128}, +{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9}, +{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4}, +{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6}, +{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15}, +{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{11,12,2496},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6}, +{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7}, +{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8}, +{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{12,11,0},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16}, +{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128}, +{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5}, +{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3}, +{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1792},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6}, +{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3}, +{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15}, +{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17}, +{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128}, +{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5}, +{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6}, +{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8}, +{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5}, +{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14}, +{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16}, +{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128}, +{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{11,11,1856},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9}, +{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4}, +{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6}, +{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15}, +{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2176},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6}, +{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3}, +{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15}, +{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17}, +{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128}, +{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5}, +{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6}, +{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2432},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8}, +{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5}, +{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14}, +{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16}, +{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128}, +{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9}, +{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4}, +{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6}, +{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15}, +{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{11,12,2048},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6}, +{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7}, +{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8}, +{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16}, +{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128}, +{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5}, +{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3}, +{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1920},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4}, +{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6}, +{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3}, +{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15}, +{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17}, +{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128}, +{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5}, +{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6}, +{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7}, +{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8}, +{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5}, +{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14}, +{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16}, +{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128}, +{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5}, +{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{11,12,2304},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3}, +{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9}, +{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5}, +{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4}, +{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6}, +{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3}, +{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15}, +{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17}, +{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128}, +{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5}, +{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6}, +{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3}, +{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9}, +{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7}, +{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8}, +{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5}, +{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4}, +{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6}, +{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2560},{7,4,3}, +{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14}, +{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16}, +{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}, +{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128}, +{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5}, +{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4}, +{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6}, +{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3}, +{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64}, +{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9}, +{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7}, +{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8}, +{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7} +}; + const TIFFFaxTabEnt TIFFFaxBlackTable[8192] = { +{12,11,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,23},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,25},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,128},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,56},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,30},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,57},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,21},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,54},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,52},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,48},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2112},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,44},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,36},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,384},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,28},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,60},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,40},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2368},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,12,1984},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,50},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,34},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1664},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,26},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1408},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,32},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,61},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,42},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,13,1024},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,768},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,62},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2240},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,46},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,38},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,512},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,19},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2496},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,25},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,12,192},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1280},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,31},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,58},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,21},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,896},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,640},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,49},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2176},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,45},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,37},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,12,448},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,29},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,1536},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,41},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2432},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2048},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,51},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,35},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,320},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,27},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,59},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,33},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,256},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,43},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,1152},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,55},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,63},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,12,2304},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,47},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,39},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,53},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2560},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,25},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,12,128},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,56},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,30},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,57},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,21},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,54},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,52},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,48},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2112},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,44},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,36},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,12,384},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,28},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,60},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,40},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,12,2368},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,1984},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,50},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,34},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,13,1728},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,26},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,1472},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,32},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,61},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,42},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1088},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,832},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,62},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2240},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,46},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,38},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,576},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2496},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,25},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,192},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1344},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,31},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1856},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,58},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,21},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{10,13,960},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,13,704},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,49},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2176},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,45},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,37},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,448},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,29},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1600},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,41},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{11,12,2432},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2048},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,51},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,35},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{10,12,320},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,27},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,59},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,33},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,256},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,43},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1216},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,55},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,63},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2304},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,12,47},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,39},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,12,53},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2560},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2}, +{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3}, +{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2}, +{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3}, +{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2}, +{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3}, +{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2}, +{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3}, +{8,3,4},{8,2,2} +}; +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_flush.c b/libs/tiff/libtiff/tif_flush.c new file mode 100644 index 00000000000..f7fa2072ab7 --- /dev/null +++ b/libs/tiff/libtiff/tif_flush.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +int +TIFFFlush(TIFF* tif) +{ + if( tif->tif_mode == O_RDONLY ) + return 1; + + if (!TIFFFlushData(tif)) + return (0); + + /* In update (r+) mode we try to detect the case where + only the strip/tile map has been altered, and we try to + rewrite only that portion of the directory without + making any other changes */ + + if( (tif->tif_flags & TIFF_DIRTYSTRIP) + && !(tif->tif_flags & TIFF_DIRTYDIRECT) + && tif->tif_mode == O_RDWR ) + { + if( TIFFForceStrileArrayWriting(tif) ) + return 1; + } + + if ((tif->tif_flags & (TIFF_DIRTYDIRECT|TIFF_DIRTYSTRIP)) + && !TIFFRewriteDirectory(tif)) + return (0); + + return (1); +} + +/* + * This is an advanced writing function that must be used in a particular + * sequence, and together with TIFFDeferStrileArrayWriting(), + * to make its intended effect. Its aim is to force the writing of + * the [Strip/Tile][Offsets/ByteCounts] arrays at the end of the file, when + * they have not yet been rewritten. + * + * The typical sequence of calls is: + * TIFFOpen() + * [ TIFFCreateDirectory(tif) ] + * Set fields with calls to TIFFSetField(tif, ...) + * TIFFDeferStrileArrayWriting(tif) + * TIFFWriteCheck(tif, ...) + * TIFFWriteDirectory(tif) + * ... potentially create other directories and come back to the above directory + * TIFFForceStrileArrayWriting(tif) + * + * Returns 1 in case of success, 0 otherwise. + */ +int TIFFForceStrileArrayWriting(TIFF* tif) +{ + static const char module[] = "TIFFForceStrileArrayWriting"; + const int isTiled = TIFFIsTiled(tif); + + if (tif->tif_mode == O_RDONLY) + { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "File opened in read-only mode"); + return 0; + } + if( tif->tif_diroff == 0 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Directory has not yet been written"); + return 0; + } + if( (tif->tif_flags & TIFF_DIRTYDIRECT) != 0 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Directory has changes other than the strile arrays. " + "TIFFRewriteDirectory() should be called instead"); + return 0; + } + + if( !(tif->tif_flags & TIFF_DIRTYSTRIP) ) + { + if( !(tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 && + tif->tif_dir.td_stripoffset_entry.tdir_count == 0 && + tif->tif_dir.td_stripoffset_entry.tdir_type == 0 && + tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0) ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Function not called together with " + "TIFFDeferStrileArrayWriting()"); + return 0; + } + + if (tif->tif_dir.td_stripoffset_p == NULL && !TIFFSetupStrips(tif)) + return 0; + } + + if( _TIFFRewriteField( tif, + isTiled ? TIFFTAG_TILEOFFSETS : + TIFFTAG_STRIPOFFSETS, + TIFF_LONG8, + tif->tif_dir.td_nstrips, + tif->tif_dir.td_stripoffset_p ) + && _TIFFRewriteField( tif, + isTiled ? TIFFTAG_TILEBYTECOUNTS : + TIFFTAG_STRIPBYTECOUNTS, + TIFF_LONG8, + tif->tif_dir.td_nstrips, + tif->tif_dir.td_stripbytecount_p ) ) + { + tif->tif_flags &= ~TIFF_DIRTYSTRIP; + tif->tif_flags &= ~TIFF_BEENWRITING; + return 1; + } + + return 0; +} + +/* + * Flush buffered data to the file. + * + * Frank Warmerdam'2000: I modified this to return 1 if TIFF_BEENWRITING + * is not set, so that TIFFFlush() will proceed to write out the directory. + * The documentation says returning 1 is an error indicator, but not having + * been writing isn't exactly a an error. Hopefully this doesn't cause + * problems for other people. + */ +int +TIFFFlushData(TIFF* tif) +{ + if ((tif->tif_flags & TIFF_BEENWRITING) == 0) + return (1); + if (tif->tif_flags & TIFF_POSTENCODE) { + tif->tif_flags &= ~TIFF_POSTENCODE; + if (!(*tif->tif_postencode)(tif)) + return (0); + } + return (TIFFFlushData1(tif)); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_jpeg.c b/libs/tiff/libtiff/tif_jpeg.c new file mode 100644 index 00000000000..6076c1177a4 --- /dev/null +++ b/libs/tiff/libtiff/tif_jpeg.c @@ -0,0 +1,2603 @@ +/* + * Copyright (c) 1994-1997 Sam Leffler + * Copyright (c) 1994-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN + +#include "tiffiop.h" +#include + +#ifdef JPEG_SUPPORT + +/* + * TIFF Library + * + * JPEG Compression support per TIFF Technical Note #2 + * (*not* per the original TIFF 6.0 spec). + * + * This file is simply an interface to the libjpeg library written by + * the Independent JPEG Group. You need release 5 or later of the IJG + * code, which you can find on the Internet at ftp.uu.net:/graphics/jpeg/. + * + * Contributed by Tom Lane . + */ +#include + +int TIFFFillStrip(TIFF* tif, uint32_t strip); +int TIFFFillTile(TIFF* tif, uint32_t tile); +int TIFFReInitJPEG_12( TIFF *tif, int scheme, int is_encode ); +int TIFFJPEGIsFullStripRequired_12(TIFF* tif); + +/* We undefine FAR to avoid conflict with JPEG definition */ + +#ifdef FAR +#undef FAR +#endif + +/* + Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is + not defined. Unfortunately, the MinGW and Borland compilers include + a typedef for INT32, which causes a conflict. MSVC does not include + a conflicting typedef given the headers which are included. +*/ +#if defined(__BORLANDC__) || defined(__MINGW32__) +# define XMD_H 1 +#endif + +/* + The windows RPCNDR.H file defines boolean, but defines it with the + unsigned char size. You should compile JPEG library using appropriate + definitions in jconfig.h header, but many users compile library in wrong + way. That causes errors of the following type: + + "JPEGLib: JPEG parameter struct mismatch: library thinks size is 432, + caller expects 464" + + For such users we will fix the problem here. See install.doc file from + the JPEG library distribution for details. +*/ + +/* Define "boolean" as unsigned char, not int, per Windows custom. */ +#if defined(__WIN32__) && !defined(__MINGW32__) +# ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ + typedef unsigned char boolean; +# endif +# define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ +#endif + +#include "jpeglib.h" +#include "jerror.h" + +/* + * Do we want to do special processing suitable for when JSAMPLE is a + * 16bit value? + */ + +#if defined(JPEG_LIB_MK1) +# define JPEG_LIB_MK1_OR_12BIT 1 +#elif BITS_IN_JSAMPLE == 12 +# define JPEG_LIB_MK1_OR_12BIT 1 +#endif + +/* + * We are using width_in_blocks which is supposed to be private to + * libjpeg. Unfortunately, the libjpeg delivered with Cygwin has + * renamed this member to width_in_data_units. Since the header has + * also renamed a define, use that unique define name in order to + * detect the problem header and adjust to suit. + */ +#if defined(D_MAX_DATA_UNITS_IN_MCU) +#define width_in_blocks width_in_data_units +#endif + +/* + * On some machines it may be worthwhile to use _setjmp or sigsetjmp + * in place of plain setjmp. These macros will make it easier. + */ +#define SETJMP(jbuf) setjmp(jbuf) +#define LONGJMP(jbuf,code) longjmp(jbuf,code) +#define JMP_BUF jmp_buf + +typedef struct jpeg_destination_mgr jpeg_destination_mgr; +typedef struct jpeg_source_mgr jpeg_source_mgr; +typedef struct jpeg_error_mgr jpeg_error_mgr; + +/* + * State block for each open TIFF file using + * libjpeg to do JPEG compression/decompression. + * + * libjpeg's visible state is either a jpeg_compress_struct + * or jpeg_decompress_struct depending on which way we + * are going. comm can be used to refer to the fields + * which are common to both. + * + * NB: cinfo is required to be the first member of JPEGState, + * so we can safely cast JPEGState* -> jpeg_xxx_struct* + * and vice versa! + */ +typedef struct { + union { + struct jpeg_compress_struct c; + struct jpeg_decompress_struct d; + struct jpeg_common_struct comm; + } cinfo; /* NB: must be first */ + int cinfo_initialized; + + jpeg_error_mgr err; /* libjpeg error manager */ + JMP_BUF exit_jmpbuf; /* for catching libjpeg failures */ + + struct jpeg_progress_mgr progress; + /* + * The following two members could be a union, but + * they're small enough that it's not worth the effort. + */ + jpeg_destination_mgr dest; /* data dest for compression */ + jpeg_source_mgr src; /* data source for decompression */ + /* private state */ + TIFF* tif; /* back link needed by some code */ + uint16_t photometric; /* copy of PhotometricInterpretation */ + uint16_t h_sampling; /* luminance sampling factors */ + uint16_t v_sampling; + tmsize_t bytesperline; /* decompressed bytes per scanline */ + /* pointers to intermediate buffers when processing downsampled data */ + JSAMPARRAY ds_buffer[MAX_COMPONENTS]; + int scancount; /* number of "scanlines" accumulated */ + int samplesperclump; + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFPrintMethod printdir; /* super-class method */ + TIFFStripMethod defsparent; /* super-class method */ + TIFFTileMethod deftparent; /* super-class method */ + /* pseudo-tag fields */ + void* jpegtables; /* JPEGTables tag value, or NULL */ + uint32_t jpegtables_length; /* number of bytes in same */ + int jpegquality; /* Compression quality level */ + int jpegcolormode; /* Auto RGB<=>YCbCr convert? */ + int jpegtablesmode; /* What to put in JPEGTables */ + + int ycbcrsampling_fetched; + int max_allowed_scan_number; +} JPEGState; + +#define JState(tif) ((JPEGState*)(tif)->tif_data) + +static int JPEGDecode(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s); +static int JPEGDecodeRaw(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s); +static int JPEGEncode(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s); +static int JPEGEncodeRaw(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s); +static int JPEGInitializeLibJPEG(TIFF * tif, int decode ); +static int DecodeRowError(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s); + +#define FIELD_JPEGTABLES (FIELD_CODEC+0) + +static const TIFFField jpegFields[] = { + { TIFFTAG_JPEGTABLES, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_C32_UINT8, FIELD_JPEGTABLES, FALSE, TRUE, "JPEGTables", NULL }, + { TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL }, + { TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL }, + { TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL } +}; + +/* + * libjpeg interface layer. + * + * We use setjmp/longjmp to return control to libtiff + * when a fatal error is encountered within the JPEG + * library. We also direct libjpeg error and warning + * messages through the appropriate libtiff handlers. + */ + +/* + * Error handling routines (these replace corresponding + * IJG routines from jerror.c). These are used for both + * compression and decompression. + */ +static void +TIFFjpeg_error_exit(j_common_ptr cinfo) +{ + JPEGState *sp = (JPEGState *) cinfo; /* NB: cinfo assumed first */ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message) (cinfo, buffer); + TIFFErrorExt(sp->tif->tif_clientdata, "JPEGLib", "%s", buffer); /* display the error message */ + jpeg_abort(cinfo); /* clean up libjpeg state */ + LONGJMP(sp->exit_jmpbuf, 1); /* return to libtiff caller */ +} + +/* + * This routine is invoked only for warning messages, + * since error_exit does its own thing and trace_level + * is never set > 0. + */ +static void +TIFFjpeg_output_message(j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message) (cinfo, buffer); + TIFFWarningExt(((JPEGState *) cinfo)->tif->tif_clientdata, "JPEGLib", "%s", buffer); +} + +/* Avoid the risk of denial-of-service on crafted JPEGs with an insane */ +/* number of scans. */ +/* See http://www.libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf */ +static void +TIFFjpeg_progress_monitor(j_common_ptr cinfo) +{ + JPEGState *sp = (JPEGState *) cinfo; /* NB: cinfo assumed first */ + if (cinfo->is_decompressor) + { + const int scan_no = + ((j_decompress_ptr)cinfo)->input_scan_number; + if (scan_no >= sp->max_allowed_scan_number) + { + TIFFErrorExt(((JPEGState *) cinfo)->tif->tif_clientdata, + "TIFFjpeg_progress_monitor", + "Scan number %d exceeds maximum scans (%d). This limit " + "can be raised through the LIBTIFF_JPEG_MAX_ALLOWED_SCAN_NUMBER " + "environment variable.", + scan_no, sp->max_allowed_scan_number); + + jpeg_abort(cinfo); /* clean up libjpeg state */ + LONGJMP(sp->exit_jmpbuf, 1); /* return to libtiff caller */ + } + } +} + + +/* + * Interface routines. This layer of routines exists + * primarily to limit side-effects from using setjmp. + * Also, normal/error returns are converted into return + * values per libtiff practice. + */ +#define CALLJPEG(sp, fail, op) (SETJMP((sp)->exit_jmpbuf) ? (fail) : (op)) +#define CALLVJPEG(sp, op) CALLJPEG(sp, 0, ((op),1)) + +static int +TIFFjpeg_create_compress(JPEGState* sp) +{ + /* initialize JPEG error handling */ + sp->cinfo.c.err = jpeg_std_error(&sp->err); + sp->err.error_exit = TIFFjpeg_error_exit; + sp->err.output_message = TIFFjpeg_output_message; + + /* set client_data to avoid UMR warning from tools like Purify */ + sp->cinfo.c.client_data = NULL; + + return CALLVJPEG(sp, jpeg_create_compress(&sp->cinfo.c)); +} + +static int +TIFFjpeg_create_decompress(JPEGState* sp) +{ + /* initialize JPEG error handling */ + sp->cinfo.d.err = jpeg_std_error(&sp->err); + sp->err.error_exit = TIFFjpeg_error_exit; + sp->err.output_message = TIFFjpeg_output_message; + + /* set client_data to avoid UMR warning from tools like Purify */ + sp->cinfo.d.client_data = NULL; + + return CALLVJPEG(sp, jpeg_create_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_set_defaults(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_set_defaults(&sp->cinfo.c)); +} + +static int +TIFFjpeg_set_colorspace(JPEGState* sp, J_COLOR_SPACE colorspace) +{ + return CALLVJPEG(sp, jpeg_set_colorspace(&sp->cinfo.c, colorspace)); +} + +static int +TIFFjpeg_set_quality(JPEGState* sp, int quality, boolean force_baseline) +{ + return CALLVJPEG(sp, + jpeg_set_quality(&sp->cinfo.c, quality, force_baseline)); +} + +static int +TIFFjpeg_suppress_tables(JPEGState* sp, boolean suppress) +{ + return CALLVJPEG(sp, jpeg_suppress_tables(&sp->cinfo.c, suppress)); +} + +static int +TIFFjpeg_start_compress(JPEGState* sp, boolean write_all_tables) +{ + return CALLVJPEG(sp, + jpeg_start_compress(&sp->cinfo.c, write_all_tables)); +} + +static int +TIFFjpeg_write_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int num_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c, + scanlines, (JDIMENSION) num_lines)); +} + +static int +TIFFjpeg_write_raw_data(JPEGState* sp, JSAMPIMAGE data, int num_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_write_raw_data(&sp->cinfo.c, + data, (JDIMENSION) num_lines)); +} + +static int +TIFFjpeg_finish_compress(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_finish_compress(&sp->cinfo.c)); +} + +static int +TIFFjpeg_write_tables(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_write_tables(&sp->cinfo.c)); +} + +static int +TIFFjpeg_read_header(JPEGState* sp, boolean require_image) +{ + return CALLJPEG(sp, -1, jpeg_read_header(&sp->cinfo.d, require_image)); +} + +static int +TIFFjpeg_has_multiple_scans(JPEGState* sp) +{ + return CALLJPEG(sp, 0, jpeg_has_multiple_scans(&sp->cinfo.d)); +} + +static int +TIFFjpeg_start_decompress(JPEGState* sp) +{ + const char* sz_max_allowed_scan_number; + /* progress monitor */ + sp->cinfo.d.progress = &sp->progress; + sp->progress.progress_monitor = TIFFjpeg_progress_monitor; + sp->max_allowed_scan_number = 100; + sz_max_allowed_scan_number = getenv("LIBTIFF_JPEG_MAX_ALLOWED_SCAN_NUMBER"); + if( sz_max_allowed_scan_number ) + sp->max_allowed_scan_number = atoi(sz_max_allowed_scan_number); + + return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_read_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int max_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d, + scanlines, (JDIMENSION) max_lines)); +} + +static int +TIFFjpeg_read_raw_data(JPEGState* sp, JSAMPIMAGE data, int max_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_read_raw_data(&sp->cinfo.d, + data, (JDIMENSION) max_lines)); +} + +static int +TIFFjpeg_finish_decompress(JPEGState* sp) +{ + return CALLJPEG(sp, -1, (int) jpeg_finish_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_abort(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_abort(&sp->cinfo.comm)); +} + +static int +TIFFjpeg_destroy(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_destroy(&sp->cinfo.comm)); +} + +static JSAMPARRAY +TIFFjpeg_alloc_sarray(JPEGState* sp, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +{ + return CALLJPEG(sp, (JSAMPARRAY) NULL, + (*sp->cinfo.comm.mem->alloc_sarray) + (&sp->cinfo.comm, pool_id, samplesperrow, numrows)); +} + +/* + * JPEG library destination data manager. + * These routines direct compressed data from libjpeg into the + * libtiff output buffer. + */ + +static void +std_init_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; + sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; +} + +static boolean +std_empty_output_buffer(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + /* the entire buffer has been filled */ + tif->tif_rawcc = tif->tif_rawdatasize; + +#ifdef IPPJ_HUFF + /* + * The Intel IPP performance library does not necessarily fill up + * the whole output buffer on each pass, so only dump out the parts + * that have been filled. + * http://trac.osgeo.org/gdal/wiki/JpegIPP + */ + if ( sp->dest.free_in_buffer >= 0 ) { + tif->tif_rawcc = tif->tif_rawdatasize - sp->dest.free_in_buffer; + } +#endif + + if( !TIFFFlushData1(tif) ) + return FALSE; + sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; + sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; + + return (TRUE); +} + +static void +std_term_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + tif->tif_rawcp = (uint8_t*) sp->dest.next_output_byte; + tif->tif_rawcc = + tif->tif_rawdatasize - (tmsize_t) sp->dest.free_in_buffer; + /* NB: libtiff does the final buffer flush */ +} + +static void +TIFFjpeg_data_dest(JPEGState* sp, TIFF* tif) +{ + (void) tif; + sp->cinfo.c.dest = &sp->dest; + sp->dest.init_destination = std_init_destination; + sp->dest.empty_output_buffer = std_empty_output_buffer; + sp->dest.term_destination = std_term_destination; +} + +/* + * Alternate destination manager for outputting to JPEGTables field. + */ + +static void +tables_init_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + /* while building, jpegtables_length is allocated buffer size */ + sp->dest.next_output_byte = (JOCTET*) sp->jpegtables; + sp->dest.free_in_buffer = (size_t) sp->jpegtables_length; +} + +static boolean +tables_empty_output_buffer(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + void* newbuf; + + /* the entire buffer has been filled; enlarge it by 1000 bytes */ + newbuf = _TIFFrealloc((void*) sp->jpegtables, + (tmsize_t) (sp->jpegtables_length + 1000)); + if (newbuf == NULL) + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 100); + sp->dest.next_output_byte = (JOCTET*) newbuf + sp->jpegtables_length; + sp->dest.free_in_buffer = (size_t) 1000; + sp->jpegtables = newbuf; + sp->jpegtables_length += 1000; + return (TRUE); +} + +static void +tables_term_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + /* set tables length to number of bytes actually emitted */ + sp->jpegtables_length -= (uint32_t) sp->dest.free_in_buffer; +} + +static int +TIFFjpeg_tables_dest(JPEGState* sp, TIFF* tif) +{ + (void) tif; + /* + * Allocate a working buffer for building tables. + * Initial size is 1000 bytes, which is usually adequate. + */ + if (sp->jpegtables) + _TIFFfree(sp->jpegtables); + sp->jpegtables_length = 1000; + sp->jpegtables = (void*) _TIFFmalloc((tmsize_t) sp->jpegtables_length); + if (sp->jpegtables == NULL) { + sp->jpegtables_length = 0; + TIFFErrorExt(sp->tif->tif_clientdata, "TIFFjpeg_tables_dest", "No space for JPEGTables"); + return (0); + } + sp->cinfo.c.dest = &sp->dest; + sp->dest.init_destination = tables_init_destination; + sp->dest.empty_output_buffer = tables_empty_output_buffer; + sp->dest.term_destination = tables_term_destination; + return (1); +} + +/* + * JPEG library source data manager. + * These routines supply compressed data to libjpeg. + */ + +static void +std_init_source(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + sp->src.next_input_byte = (const JOCTET*) tif->tif_rawdata; + sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc; +} + +static boolean +std_fill_input_buffer(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState* ) cinfo; + static const JOCTET dummy_EOI[2] = { 0xFF, JPEG_EOI }; + +#ifdef IPPJ_HUFF + /* + * The Intel IPP performance library does not necessarily read the whole + * input buffer in one pass, so it is possible to get here with data + * yet to read. + * + * We just return without doing anything, until the entire buffer has + * been read. + * http://trac.osgeo.org/gdal/wiki/JpegIPP + */ + if( sp->src.bytes_in_buffer > 0 ) { + return (TRUE); + } +#endif + + /* + * Normally the whole strip/tile is read and so we don't need to do + * a fill. In the case of CHUNKY_STRIP_READ_SUPPORT we might not have + * all the data, but the rawdata is refreshed between scanlines and + * we push this into the io machinery in JPEGDecode(). + * http://trac.osgeo.org/gdal/ticket/3894 + */ + + WARNMS(cinfo, JWRN_JPEG_EOF); + /* insert a fake EOI marker */ + sp->src.next_input_byte = dummy_EOI; + sp->src.bytes_in_buffer = 2; + return (TRUE); +} + +static void +std_skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + JPEGState* sp = (JPEGState*) cinfo; + + if (num_bytes > 0) { + if ((size_t)num_bytes > sp->src.bytes_in_buffer) { + /* oops, buffer overrun */ + (void) std_fill_input_buffer(cinfo); + } else { + sp->src.next_input_byte += (size_t) num_bytes; + sp->src.bytes_in_buffer -= (size_t) num_bytes; + } + } +} + +static void +std_term_source(j_decompress_ptr cinfo) +{ + /* No work necessary here */ + (void) cinfo; +} + +static void +TIFFjpeg_data_src(JPEGState* sp) +{ + sp->cinfo.d.src = &sp->src; + sp->src.init_source = std_init_source; + sp->src.fill_input_buffer = std_fill_input_buffer; + sp->src.skip_input_data = std_skip_input_data; + sp->src.resync_to_restart = jpeg_resync_to_restart; + sp->src.term_source = std_term_source; + sp->src.bytes_in_buffer = 0; /* for safety */ + sp->src.next_input_byte = NULL; +} + +/* + * Alternate source manager for reading from JPEGTables. + * We can share all the code except for the init routine. + */ + +static void +tables_init_source(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + sp->src.next_input_byte = (const JOCTET*) sp->jpegtables; + sp->src.bytes_in_buffer = (size_t) sp->jpegtables_length; +} + +static void +TIFFjpeg_tables_src(JPEGState* sp) +{ + TIFFjpeg_data_src(sp); + sp->src.init_source = tables_init_source; +} + +/* + * Allocate downsampled-data buffers needed for downsampled I/O. + * We use values computed in jpeg_start_compress or jpeg_start_decompress. + * We use libjpeg's allocator so that buffers will be released automatically + * when done with strip/tile. + * This is also a handy place to compute samplesperclump, bytesperline. + */ +static int +alloc_downsampled_buffers(TIFF* tif, jpeg_component_info* comp_info, + int num_components) +{ + JPEGState* sp = JState(tif); + int ci; + jpeg_component_info* compptr; + JSAMPARRAY buf; + int samples_per_clump = 0; + + for (ci = 0, compptr = comp_info; ci < num_components; + ci++, compptr++) { + samples_per_clump += compptr->h_samp_factor * + compptr->v_samp_factor; + buf = TIFFjpeg_alloc_sarray(sp, JPOOL_IMAGE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor*DCTSIZE)); + if (buf == NULL) + return (0); + sp->ds_buffer[ci] = buf; + } + sp->samplesperclump = samples_per_clump; + return (1); +} + + +/* + * JPEG Decoding. + */ + +#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING + +#define JPEG_MARKER_SOF0 0xC0 +#define JPEG_MARKER_SOF1 0xC1 +#define JPEG_MARKER_SOF2 0xC2 +#define JPEG_MARKER_SOF9 0xC9 +#define JPEG_MARKER_SOF10 0xCA +#define JPEG_MARKER_DHT 0xC4 +#define JPEG_MARKER_SOI 0xD8 +#define JPEG_MARKER_SOS 0xDA +#define JPEG_MARKER_DQT 0xDB +#define JPEG_MARKER_DRI 0xDD +#define JPEG_MARKER_APP0 0xE0 +#define JPEG_MARKER_COM 0xFE +struct JPEGFixupTagsSubsamplingData +{ + TIFF* tif; + void* buffer; + uint32_t buffersize; + uint8_t* buffercurrentbyte; + uint32_t bufferbytesleft; + uint64_t fileoffset; + uint64_t filebytesleft; + uint8_t filepositioned; +}; +static void JPEGFixupTagsSubsampling(TIFF* tif); +static int JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData* data); +static int JPEGFixupTagsSubsamplingReadByte(struct JPEGFixupTagsSubsamplingData* data, uint8_t* result); +static int JPEGFixupTagsSubsamplingReadWord(struct JPEGFixupTagsSubsamplingData* data, uint16_t* result); +static void JPEGFixupTagsSubsamplingSkip(struct JPEGFixupTagsSubsamplingData* data, uint16_t skiplength); + +#endif + +static int +JPEGFixupTags(TIFF* tif) +{ +#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING + JPEGState* sp = JState(tif); + if ((tif->tif_dir.td_photometric==PHOTOMETRIC_YCBCR)&& + (tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)&& + (tif->tif_dir.td_samplesperpixel==3) && + !sp->ycbcrsampling_fetched) + JPEGFixupTagsSubsampling(tif); +#endif + + return(1); +} + +#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING + +static void +JPEGFixupTagsSubsampling(TIFF* tif) +{ + /* + * Some JPEG-in-TIFF produces do not emit the YCBCRSUBSAMPLING values in + * the TIFF tags, but still use non-default (2,2) values within the jpeg + * data stream itself. In order for TIFF applications to work properly + * - for instance to get the strip buffer size right - it is imperative + * that the subsampling be available before we start reading the image + * data normally. This function will attempt to analyze the first strip in + * order to get the sampling values from the jpeg data stream. + * + * Note that JPEGPreDeocode() will produce a fairly loud warning when the + * discovered sampling does not match the default sampling (2,2) or whatever + * was actually in the tiff tags. + * + * See the bug in bugzilla for details: + * + * http://bugzilla.remotesensing.org/show_bug.cgi?id=168 + * + * Frank Warmerdam, July 2002 + * Joris Van Damme, May 2007 + */ + static const char module[] = "JPEGFixupTagsSubsampling"; + struct JPEGFixupTagsSubsamplingData m; + uint64_t fileoffset = TIFFGetStrileOffset(tif, 0); + + if( fileoffset == 0 ) + { + /* Do not even try to check if the first strip/tile does not + yet exist, as occurs when GDAL has created a new NULL file + for instance. */ + return; + } + + m.tif=tif; + m.buffersize=2048; + m.buffer=_TIFFmalloc(m.buffersize); + if (m.buffer==NULL) + { + TIFFWarningExt(tif->tif_clientdata,module, + "Unable to allocate memory for auto-correcting of subsampling values; auto-correcting skipped"); + return; + } + m.buffercurrentbyte=NULL; + m.bufferbytesleft=0; + m.fileoffset=fileoffset; + m.filepositioned=0; + m.filebytesleft=TIFFGetStrileByteCount(tif, 0); + if (!JPEGFixupTagsSubsamplingSec(&m)) + TIFFWarningExt(tif->tif_clientdata,module, + "Unable to auto-correct subsampling values, likely corrupt JPEG compressed data in first strip/tile; auto-correcting skipped"); + _TIFFfree(m.buffer); +} + +static int +JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData* data) +{ + static const char module[] = "JPEGFixupTagsSubsamplingSec"; + uint8_t m; + while (1) + { + while (1) + { + if (!JPEGFixupTagsSubsamplingReadByte(data,&m)) + return(0); + if (m==255) + break; + } + while (1) + { + if (!JPEGFixupTagsSubsamplingReadByte(data,&m)) + return(0); + if (m!=255) + break; + } + switch (m) + { + case JPEG_MARKER_SOI: + /* this type of marker has no data and should be skipped */ + break; + case JPEG_MARKER_COM: + case JPEG_MARKER_APP0: + case JPEG_MARKER_APP0+1: + case JPEG_MARKER_APP0+2: + case JPEG_MARKER_APP0+3: + case JPEG_MARKER_APP0+4: + case JPEG_MARKER_APP0+5: + case JPEG_MARKER_APP0+6: + case JPEG_MARKER_APP0+7: + case JPEG_MARKER_APP0+8: + case JPEG_MARKER_APP0+9: + case JPEG_MARKER_APP0+10: + case JPEG_MARKER_APP0+11: + case JPEG_MARKER_APP0+12: + case JPEG_MARKER_APP0+13: + case JPEG_MARKER_APP0+14: + case JPEG_MARKER_APP0+15: + case JPEG_MARKER_DQT: + case JPEG_MARKER_SOS: + case JPEG_MARKER_DHT: + case JPEG_MARKER_DRI: + /* this type of marker has data, but it has no use to us and should be skipped */ + { + uint16_t n; + if (!JPEGFixupTagsSubsamplingReadWord(data,&n)) + return(0); + if (n<2) + return(0); + n-=2; + if (n>0) + JPEGFixupTagsSubsamplingSkip(data,n); + } + break; + case JPEG_MARKER_SOF0: /* Baseline sequential Huffman */ + case JPEG_MARKER_SOF1: /* Extended sequential Huffman */ + case JPEG_MARKER_SOF2: /* Progressive Huffman: normally not allowed by TechNote, but that doesn't hurt supporting it */ + case JPEG_MARKER_SOF9: /* Extended sequential arithmetic */ + case JPEG_MARKER_SOF10: /* Progressive arithmetic: normally not allowed by TechNote, but that doesn't hurt supporting it */ + /* this marker contains the subsampling factors we're scanning for */ + { + uint16_t n; + uint16_t o; + uint8_t p; + uint8_t ph,pv; + if (!JPEGFixupTagsSubsamplingReadWord(data,&n)) + return(0); + if (n!=8+data->tif->tif_dir.td_samplesperpixel*3) + return(0); + JPEGFixupTagsSubsamplingSkip(data,7); + if (!JPEGFixupTagsSubsamplingReadByte(data,&p)) + return(0); + ph=(p>>4); + pv=(p&15); + JPEGFixupTagsSubsamplingSkip(data,1); + for (o=1; otif->tif_dir.td_samplesperpixel; o++) + { + JPEGFixupTagsSubsamplingSkip(data,1); + if (!JPEGFixupTagsSubsamplingReadByte(data,&p)) + return(0); + if (p!=0x11) + { + TIFFWarningExt(data->tif->tif_clientdata,module, + "Subsampling values inside JPEG compressed data have no TIFF equivalent, auto-correction of TIFF subsampling values failed"); + return(1); + } + JPEGFixupTagsSubsamplingSkip(data,1); + } + if (((ph!=1)&&(ph!=2)&&(ph!=4))||((pv!=1)&&(pv!=2)&&(pv!=4))) + { + TIFFWarningExt(data->tif->tif_clientdata,module, + "Subsampling values inside JPEG compressed data have no TIFF equivalent, auto-correction of TIFF subsampling values failed"); + return(1); + } + if ((ph!=data->tif->tif_dir.td_ycbcrsubsampling[0])||(pv!=data->tif->tif_dir.td_ycbcrsubsampling[1])) + { + TIFFWarningExt(data->tif->tif_clientdata,module, + "Auto-corrected former TIFF subsampling values [%"PRIu16",%"PRIu16"] to match subsampling values inside JPEG compressed data [%"PRIu8",%"PRIu8"]", + data->tif->tif_dir.td_ycbcrsubsampling[0], + data->tif->tif_dir.td_ycbcrsubsampling[1], + ph, pv); + data->tif->tif_dir.td_ycbcrsubsampling[0]=ph; + data->tif->tif_dir.td_ycbcrsubsampling[1]=pv; + } + } + return(1); + default: + return(0); + } + } +} + +static int +JPEGFixupTagsSubsamplingReadByte(struct JPEGFixupTagsSubsamplingData* data, uint8_t* result) +{ + if (data->bufferbytesleft==0) + { + uint32_t m; + if (data->filebytesleft==0) + return(0); + if (!data->filepositioned) + { + if (TIFFSeekFile(data->tif,data->fileoffset,SEEK_SET) == (toff_t)-1) + { + return 0; + } + data->filepositioned=1; + } + m=data->buffersize; + if ((uint64_t)m > data->filebytesleft) + m=(uint32_t)data->filebytesleft; + assert(m<0x80000000UL); + if (TIFFReadFile(data->tif,data->buffer,(tmsize_t)m)!=(tmsize_t)m) + return(0); + data->buffercurrentbyte=data->buffer; + data->bufferbytesleft=m; + data->fileoffset+=m; + data->filebytesleft-=m; + } + *result=*data->buffercurrentbyte; + data->buffercurrentbyte++; + data->bufferbytesleft--; + return(1); +} + +static int +JPEGFixupTagsSubsamplingReadWord(struct JPEGFixupTagsSubsamplingData* data, uint16_t* result) +{ + uint8_t ma; + uint8_t mb; + if (!JPEGFixupTagsSubsamplingReadByte(data,&ma)) + return(0); + if (!JPEGFixupTagsSubsamplingReadByte(data,&mb)) + return(0); + *result=(ma<<8)|mb; + return(1); +} + +static void +JPEGFixupTagsSubsamplingSkip(struct JPEGFixupTagsSubsamplingData* data, uint16_t skiplength) +{ + if ((uint32_t)skiplength <= data->bufferbytesleft) + { + data->buffercurrentbyte+=skiplength; + data->bufferbytesleft-=skiplength; + } + else + { + uint16_t m; + m=(uint16_t)(skiplength - data->bufferbytesleft); + if (m<=data->filebytesleft) + { + data->bufferbytesleft=0; + data->fileoffset+=m; + data->filebytesleft-=m; + data->filepositioned=0; + } + else + { + data->bufferbytesleft=0; + data->filebytesleft=0; + } + } +} + +#endif + + +static int +JPEGSetupDecode(TIFF* tif) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + +#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFInitJPEG) + if( tif->tif_dir.td_bitspersample == 12 ) + return TIFFReInitJPEG_12( tif, COMPRESSION_JPEG, 0 ); +#endif + + JPEGInitializeLibJPEG( tif, TRUE ); + + assert(sp != NULL); + assert(sp->cinfo.comm.is_decompressor); + + /* Read JPEGTables if it is present */ + if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) { + TIFFjpeg_tables_src(sp); + if(TIFFjpeg_read_header(sp,FALSE) != JPEG_HEADER_TABLES_ONLY) { + TIFFErrorExt(tif->tif_clientdata, "JPEGSetupDecode", "Bogus JPEGTables field"); + return (0); + } + } + + /* Grab parameters that are same for all strips/tiles */ + sp->photometric = td->td_photometric; + switch (sp->photometric) { + case PHOTOMETRIC_YCBCR: + sp->h_sampling = td->td_ycbcrsubsampling[0]; + sp->v_sampling = td->td_ycbcrsubsampling[1]; + break; + default: + /* TIFF 6.0 forbids subsampling of all other color spaces */ + sp->h_sampling = 1; + sp->v_sampling = 1; + break; + } + + /* Set up for reading normal data */ + TIFFjpeg_data_src(sp); + tif->tif_postdecode = _TIFFNoPostDecode; /* override byte swapping */ + return (1); +} + +/* Returns 1 if the full strip should be read, even when doing scanline per */ +/* scanline decoding. This happens when the JPEG stream uses multiple scans. */ +/* Currently only called in CHUNKY_STRIP_READ_SUPPORT mode through */ +/* scanline interface. */ +/* Only reads tif->tif_dir.td_bitspersample, tif->tif_rawdata and */ +/* tif->tif_rawcc members. */ +/* Can be called independently of the usual setup/predecode/decode states */ +int TIFFJPEGIsFullStripRequired(TIFF* tif) +{ + int ret; + JPEGState state; + +#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFJPEGIsFullStripRequired) + if( tif->tif_dir.td_bitspersample == 12 ) + return TIFFJPEGIsFullStripRequired_12( tif ); +#endif + + memset(&state, 0, sizeof(JPEGState)); + state.tif = tif; + + TIFFjpeg_create_decompress(&state); + + TIFFjpeg_data_src(&state); + + if (TIFFjpeg_read_header(&state, TRUE) != JPEG_HEADER_OK) + { + TIFFjpeg_destroy(&state); + return (0); + } + ret = TIFFjpeg_has_multiple_scans(&state); + + TIFFjpeg_destroy(&state); + + return ret; +} + +/* + * Set up for decoding a strip or tile. + */ +/*ARGSUSED*/ static int +JPEGPreDecode(TIFF* tif, uint16_t s) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGPreDecode"; + uint32_t segment_width, segment_height; + int downsampled_output; + int ci; + + assert(sp != NULL); + + if (sp->cinfo.comm.is_decompressor == 0) + { + tif->tif_setupdecode( tif ); + } + + assert(sp->cinfo.comm.is_decompressor); + /* + * Reset decoder state from any previous strip/tile, + * in case application didn't read the whole strip. + */ + if (!TIFFjpeg_abort(sp)) + return (0); + /* + * Read the header for this strip/tile. + */ + + if (TIFFjpeg_read_header(sp, TRUE) != JPEG_HEADER_OK) + return (0); + + tif->tif_rawcp = (uint8_t*) sp->src.next_input_byte; + tif->tif_rawcc = sp->src.bytes_in_buffer; + + /* + * Check image parameters and set decompression parameters. + */ + if (isTiled(tif)) { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + sp->bytesperline = TIFFTileRowSize(tif); + } else { + segment_width = td->td_imagewidth; + segment_height = td->td_imagelength - tif->tif_row; + if (segment_height > td->td_rowsperstrip) + segment_height = td->td_rowsperstrip; + sp->bytesperline = TIFFScanlineSize(tif); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { + /* + * For PC 2, scale down the expected strip/tile size + * to match a downsampled component + */ + segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); + segment_height = TIFFhowmany_32(segment_height, sp->v_sampling); + } + if (sp->cinfo.d.image_width < segment_width || + sp->cinfo.d.image_height < segment_height) { + TIFFWarningExt(tif->tif_clientdata, module, + "Improper JPEG strip/tile size, " + "expected %"PRIu32"x%"PRIu32", got %ux%u", + segment_width, segment_height, + sp->cinfo.d.image_width, + sp->cinfo.d.image_height); + } + if( sp->cinfo.d.image_width == segment_width && + sp->cinfo.d.image_height > segment_height && + tif->tif_row + segment_height == td->td_imagelength && + !isTiled(tif) ) { + /* Some files have a last strip, that should be truncated, */ + /* but their JPEG codestream has still the maximum strip */ + /* height. Warn about this as this is non compliant, but */ + /* we can safely recover from that. */ + TIFFWarningExt(tif->tif_clientdata, module, + "JPEG strip size exceeds expected dimensions," + " expected %"PRIu32"x%"PRIu32", got %ux%u", + segment_width, segment_height, + sp->cinfo.d.image_width, sp->cinfo.d.image_height); + } + else if (sp->cinfo.d.image_width > segment_width || + sp->cinfo.d.image_height > segment_height) { + /* + * This case could be dangerous, if the strip or tile size has + * been reported as less than the amount of data jpeg will + * return, some potential security issues arise. Catch this + * case and error out. + */ + TIFFErrorExt(tif->tif_clientdata, module, + "JPEG strip/tile size exceeds expected dimensions," + " expected %"PRIu32"x%"PRIu32", got %ux%u", + segment_width, segment_height, + sp->cinfo.d.image_width, sp->cinfo.d.image_height); + return (0); + } + if (sp->cinfo.d.num_components != + (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1)) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG component count"); + return (0); + } +#ifdef JPEG_LIB_MK1 + if (12 != td->td_bitspersample && 8 != td->td_bitspersample) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG data precision"); + return (0); + } + sp->cinfo.d.data_precision = td->td_bitspersample; + sp->cinfo.d.bits_in_jsample = td->td_bitspersample; +#else + if (sp->cinfo.d.data_precision != td->td_bitspersample) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG data precision"); + return (0); + } +#endif + + /* In some cases, libjpeg needs to allocate a lot of memory */ + /* http://www.libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf */ + if( TIFFjpeg_has_multiple_scans(sp) ) + { + /* In this case libjpeg will need to allocate memory or backing */ + /* store for all coefficients */ + /* See call to jinit_d_coef_controller() from master_selection() */ + /* in libjpeg */ + + /* 1 MB for regular libjpeg usage */ + toff_t nRequiredMemory = 1024 * 1024; + + for (ci = 0; ci < sp->cinfo.d.num_components; ci++) { + const jpeg_component_info *compptr = &(sp->cinfo.d.comp_info[ci]); + if( compptr->h_samp_factor > 0 && compptr->v_samp_factor > 0 ) + { + nRequiredMemory += (toff_t)( + ((compptr->width_in_blocks + compptr->h_samp_factor - 1) / compptr->h_samp_factor)) * + ((compptr->height_in_blocks + compptr->v_samp_factor - 1) / compptr->v_samp_factor) * + sizeof(JBLOCK); + } + } + + if( sp->cinfo.d.mem->max_memory_to_use > 0 && + nRequiredMemory > (toff_t)(sp->cinfo.d.mem->max_memory_to_use) && + getenv("LIBTIFF_ALLOW_LARGE_LIBJPEG_MEM_ALLOC") == NULL ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Reading this image would require libjpeg to allocate " + "at least %"PRIu64" bytes. " + "This is disabled since above the %ld threshold. " + "You may override this restriction by defining the " + "LIBTIFF_ALLOW_LARGE_LIBJPEG_MEM_ALLOC environment variable, " + "or setting the JPEGMEM environment variable to a value greater " + "or equal to '%"PRIu64"M'", + nRequiredMemory, + sp->cinfo.d.mem->max_memory_to_use, + (nRequiredMemory + 1000000u - 1u) / 1000000u); + return 0; + } + } + + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + /* Component 0 should have expected sampling factors */ + if (sp->cinfo.d.comp_info[0].h_samp_factor != sp->h_sampling || + sp->cinfo.d.comp_info[0].v_samp_factor != sp->v_sampling) { + TIFFErrorExt(tif->tif_clientdata, module, + "Improper JPEG sampling factors %d,%d\n" + "Apparently should be %"PRIu16",%"PRIu16".", + sp->cinfo.d.comp_info[0].h_samp_factor, + sp->cinfo.d.comp_info[0].v_samp_factor, + sp->h_sampling, sp->v_sampling); + return (0); + } + /* Rest should have sampling factors 1,1 */ + for (ci = 1; ci < sp->cinfo.d.num_components; ci++) { + if (sp->cinfo.d.comp_info[ci].h_samp_factor != 1 || + sp->cinfo.d.comp_info[ci].v_samp_factor != 1) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors"); + return (0); + } + } + } else { + /* PC 2's single component should have sampling factors 1,1 */ + if (sp->cinfo.d.comp_info[0].h_samp_factor != 1 || + sp->cinfo.d.comp_info[0].v_samp_factor != 1) { + TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors"); + return (0); + } + } + downsampled_output = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + sp->photometric == PHOTOMETRIC_YCBCR && + sp->jpegcolormode == JPEGCOLORMODE_RGB) { + /* Convert YCbCr to RGB */ + sp->cinfo.d.jpeg_color_space = JCS_YCbCr; + sp->cinfo.d.out_color_space = JCS_RGB; + } else { + /* Suppress colorspace handling */ + sp->cinfo.d.jpeg_color_space = JCS_UNKNOWN; + sp->cinfo.d.out_color_space = JCS_UNKNOWN; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + (sp->h_sampling != 1 || sp->v_sampling != 1)) + downsampled_output = TRUE; + /* XXX what about up-sampling? */ + } + if (downsampled_output) { + /* Need to use raw-data interface to libjpeg */ + sp->cinfo.d.raw_data_out = TRUE; +#if JPEG_LIB_VERSION >= 70 + sp->cinfo.d.do_fancy_upsampling = FALSE; +#endif /* JPEG_LIB_VERSION >= 70 */ + tif->tif_decoderow = DecodeRowError; + tif->tif_decodestrip = JPEGDecodeRaw; + tif->tif_decodetile = JPEGDecodeRaw; + } else { + /* Use normal interface to libjpeg */ + sp->cinfo.d.raw_data_out = FALSE; + tif->tif_decoderow = JPEGDecode; + tif->tif_decodestrip = JPEGDecode; + tif->tif_decodetile = JPEGDecode; + } + /* Start JPEG decompressor */ + if (!TIFFjpeg_start_decompress(sp)) + return (0); + /* Allocate downsampled-data buffers if needed */ + if (downsampled_output) { + if (!alloc_downsampled_buffers(tif, sp->cinfo.d.comp_info, + sp->cinfo.d.num_components)) + return (0); + sp->scancount = DCTSIZE; /* mark buffer empty */ + } + return (1); +} + +/* + * Decode a chunk of pixels. + * "Standard" case: returned data is not downsampled. + */ +#if !JPEG_LIB_MK1_OR_12BIT +static int +JPEGDecode(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s) +{ + JPEGState *sp = JState(tif); + tmsize_t nrows; + (void) s; + + /* + ** Update available information, buffer may have been refilled + ** between decode requests + */ + sp->src.next_input_byte = (const JOCTET*) tif->tif_rawcp; + sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc; + + if( sp->bytesperline == 0 ) + return 0; + + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "fractional scanline not read"); + + if( nrows > (tmsize_t) sp->cinfo.d.image_height ) + nrows = sp->cinfo.d.image_height; + + /* data is expected to be read in multiples of a scanline */ + if (nrows) + { + do + { + /* + * In the libjpeg6b-9a 8bit case. We read directly into + * the TIFF buffer. + */ + JSAMPROW bufptr = (JSAMPROW)buf; + + if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1) + return (0); + + ++tif->tif_row; + buf += sp->bytesperline; + cc -= sp->bytesperline; + } while (--nrows > 0); + } + + /* Update information on consumed data */ + tif->tif_rawcp = (uint8_t*) sp->src.next_input_byte; + tif->tif_rawcc = sp->src.bytes_in_buffer; + + /* Close down the decompressor if we've finished the strip or tile. */ + return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height + || TIFFjpeg_finish_decompress(sp); +} +#endif /* !JPEG_LIB_MK1_OR_12BIT */ + +#if JPEG_LIB_MK1_OR_12BIT +/*ARGSUSED*/ static int +JPEGDecode(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s) +{ + JPEGState *sp = JState(tif); + tmsize_t nrows; + (void) s; + + /* + ** Update available information, buffer may have been refilled + ** between decode requests + */ + sp->src.next_input_byte = (const JOCTET*) tif->tif_rawcp; + sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc; + + if( sp->bytesperline == 0 ) + return 0; + + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "fractional scanline not read"); + + if( nrows > (tmsize_t) sp->cinfo.d.image_height ) + nrows = sp->cinfo.d.image_height; + + /* data is expected to be read in multiples of a scanline */ + if (nrows) + { + JSAMPROW line_work_buf = NULL; + + /* + * For 6B, only use temporary buffer for 12 bit imagery. + * For Mk1 always use it. + */ + if( sp->cinfo.d.data_precision == 12 ) + { + line_work_buf = (JSAMPROW) + _TIFFmalloc(sizeof(short) * sp->cinfo.d.output_width + * sp->cinfo.d.num_components ); + } + + do + { + if( line_work_buf != NULL ) + { + /* + * In the MK1 case, we always read into a 16bit + * buffer, and then pack down to 12bit or 8bit. + * In 6B case we only read into 16 bit buffer + * for 12bit data, which we need to repack. + */ + if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1) + return (0); + + if( sp->cinfo.d.data_precision == 12 ) + { + int value_pairs = (sp->cinfo.d.output_width + * sp->cinfo.d.num_components) / 2; + int iPair; + + for( iPair = 0; iPair < value_pairs; iPair++ ) + { + unsigned char *out_ptr = + ((unsigned char *) buf) + iPair * 3; + JSAMPLE *in_ptr = line_work_buf + iPair * 2; + + out_ptr[0] = (unsigned char)((in_ptr[0] & 0xff0) >> 4); + out_ptr[1] = (unsigned char)(((in_ptr[0] & 0xf) << 4) + | ((in_ptr[1] & 0xf00) >> 8)); + out_ptr[2] = (unsigned char)(((in_ptr[1] & 0xff) >> 0)); + } + } + else if( sp->cinfo.d.data_precision == 8 ) + { + int value_count = (sp->cinfo.d.output_width + * sp->cinfo.d.num_components); + int iValue; + + for( iValue = 0; iValue < value_count; iValue++ ) + { + ((unsigned char *) buf)[iValue] = + line_work_buf[iValue] & 0xff; + } + } + } + + ++tif->tif_row; + buf += sp->bytesperline; + cc -= sp->bytesperline; + } while (--nrows > 0); + + if( line_work_buf != NULL ) + _TIFFfree( line_work_buf ); + } + + /* Update information on consumed data */ + tif->tif_rawcp = (uint8_t*) sp->src.next_input_byte; + tif->tif_rawcc = sp->src.bytes_in_buffer; + + /* Close down the decompressor if we've finished the strip or tile. */ + return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height + || TIFFjpeg_finish_decompress(sp); +} +#endif /* JPEG_LIB_MK1_OR_12BIT */ + +/*ARGSUSED*/ static int +DecodeRowError(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s) + +{ + (void) buf; + (void) cc; + (void) s; + + TIFFErrorExt(tif->tif_clientdata, "TIFFReadScanline", + "scanline oriented access is not supported for downsampled JPEG compressed images, consider enabling TIFF_JPEGCOLORMODE as JPEGCOLORMODE_RGB." ); + return 0; +} + +/* + * Decode a chunk of pixels. + * Returned data is downsampled per sampling factors. + */ +/*ARGSUSED*/ static int +JPEGDecodeRaw(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s) +{ + JPEGState *sp = JState(tif); + tmsize_t nrows; + TIFFDirectory *td = &tif->tif_dir; + (void) s; + + nrows = sp->cinfo.d.image_height; + /* For last strip, limit number of rows to its truncated height */ + /* even if the codestream height is larger (which is not compliant, */ + /* but that we tolerate) */ + if((uint32_t)nrows > td->td_imagelength - tif->tif_row && !isTiled(tif) ) + nrows = td->td_imagelength - tif->tif_row; + + /* data is expected to be read in multiples of a scanline */ + if ( nrows != 0 ) { + + /* Cb,Cr both have sampling factors 1, so this is correct */ + JDIMENSION clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width; + int samples_per_clump = sp->samplesperclump; + +#if defined(JPEG_LIB_MK1_OR_12BIT) + unsigned short* tmpbuf = _TIFFmalloc(sizeof(unsigned short) * + sp->cinfo.d.output_width * + sp->cinfo.d.num_components); + if(tmpbuf==NULL) { + TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw", + "Out of memory"); + return 0; + } +#endif + + do { + jpeg_component_info *compptr; + int ci, clumpoffset; + + if( cc < sp->bytesperline ) { + TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw", + "application buffer not large enough for all data."); + return 0; + } + + /* Reload downsampled-data buffer if needed */ + if (sp->scancount >= DCTSIZE) { + int n = sp->cinfo.d.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_read_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + sp->scancount = 0; + } + /* + * Fastest way to unseparate data is to make one pass + * over the scanline for each row of each component. + */ + clumpoffset = 0; /* first sample in clump */ + for (ci = 0, compptr = sp->cinfo.d.comp_info; + ci < sp->cinfo.d.num_components; + ci++, compptr++) { + int hsamp = compptr->h_samp_factor; + int vsamp = compptr->v_samp_factor; + int ypos; + + for (ypos = 0; ypos < vsamp; ypos++) { + JSAMPLE *inptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; + JDIMENSION nclump; +#if defined(JPEG_LIB_MK1_OR_12BIT) + JSAMPLE *outptr = (JSAMPLE*)tmpbuf + clumpoffset; +#else + JSAMPLE *outptr = (JSAMPLE*)buf + clumpoffset; + if (cc < (tmsize_t)(clumpoffset + (tmsize_t)samples_per_clump*(clumps_per_line-1) + hsamp)) { + TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw", + "application buffer not large enough for all data, possible subsampling issue"); + return 0; + } +#endif + + if (hsamp == 1) { + /* fast path for at least Cb and Cr */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + outptr[0] = *inptr++; + outptr += samples_per_clump; + } + } else { + int xpos; + + /* general case */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + for (xpos = 0; xpos < hsamp; xpos++) + outptr[xpos] = *inptr++; + outptr += samples_per_clump; + } + } + clumpoffset += hsamp; + } + } + +#if defined(JPEG_LIB_MK1_OR_12BIT) + { + if (sp->cinfo.d.data_precision == 8) + { + int i=0; + int len = sp->cinfo.d.output_width * sp->cinfo.d.num_components; + for (i=0; icinfo.d.output_width + * sp->cinfo.d.num_components) / 2; + int iPair; + for( iPair = 0; iPair < value_pairs; iPair++ ) + { + unsigned char *out_ptr = ((unsigned char *) buf) + iPair * 3; + JSAMPLE *in_ptr = (JSAMPLE *) (tmpbuf + iPair * 2); + out_ptr[0] = (unsigned char)((in_ptr[0] & 0xff0) >> 4); + out_ptr[1] = (unsigned char)(((in_ptr[0] & 0xf) << 4) + | ((in_ptr[1] & 0xf00) >> 8)); + out_ptr[2] = (unsigned char)(((in_ptr[1] & 0xff) >> 0)); + } + } + } +#endif + + sp->scancount ++; + tif->tif_row += sp->v_sampling; + + buf += sp->bytesperline; + cc -= sp->bytesperline; + + nrows -= sp->v_sampling; + } while (nrows > 0); + +#if defined(JPEG_LIB_MK1_OR_12BIT) + _TIFFfree(tmpbuf); +#endif + + } + + /* Close down the decompressor if done. */ + return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height + || TIFFjpeg_finish_decompress(sp); +} + + +/* + * JPEG Encoding. + */ + +static void +unsuppress_quant_table (JPEGState* sp, int tblno) +{ + JQUANT_TBL* qtbl; + + if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL) + qtbl->sent_table = FALSE; +} + +static void +suppress_quant_table (JPEGState* sp, int tblno) +{ + JQUANT_TBL* qtbl; + + if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL) + qtbl->sent_table = TRUE; +} + +static void +unsuppress_huff_table (JPEGState* sp, int tblno) +{ + JHUFF_TBL* htbl; + + if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = FALSE; + if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = FALSE; +} + +static void +suppress_huff_table (JPEGState* sp, int tblno) +{ + JHUFF_TBL* htbl; + + if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = TRUE; + if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = TRUE; +} + +static int +prepare_JPEGTables(TIFF* tif) +{ + JPEGState* sp = JState(tif); + + /* Initialize quant tables for current quality setting */ + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + return (0); + /* Mark only the tables we want for output */ + /* NB: chrominance tables are currently used only with YCbCr */ + if (!TIFFjpeg_suppress_tables(sp, TRUE)) + return (0); + if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) { + unsuppress_quant_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_quant_table(sp, 1); + } + if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) { + unsuppress_huff_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_huff_table(sp, 1); + } + /* Direct libjpeg output into jpegtables */ + if (!TIFFjpeg_tables_dest(sp, tif)) + return (0); + /* Emit tables-only datastream */ + if (!TIFFjpeg_write_tables(sp)) + return (0); + + return (1); +} + +static int +JPEGSetupEncode(TIFF* tif) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGSetupEncode"; + +#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFInitJPEG) + if( tif->tif_dir.td_bitspersample == 12 ) + return TIFFReInitJPEG_12( tif, COMPRESSION_JPEG, 1 ); +#endif + + JPEGInitializeLibJPEG( tif, FALSE ); + + assert(sp != NULL); + assert(!sp->cinfo.comm.is_decompressor); + + sp->photometric = td->td_photometric; + + /* + * Initialize all JPEG parameters to default values. + * Note that jpeg_set_defaults needs legal values for + * in_color_space and input_components. + */ + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + sp->cinfo.c.input_components = td->td_samplesperpixel; + if (sp->photometric == PHOTOMETRIC_YCBCR) { + if (sp->jpegcolormode == JPEGCOLORMODE_RGB) { + sp->cinfo.c.in_color_space = JCS_RGB; + } else { + sp->cinfo.c.in_color_space = JCS_YCbCr; + } + } else { + if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1) + sp->cinfo.c.in_color_space = JCS_GRAYSCALE; + else if (td->td_photometric == PHOTOMETRIC_RGB && td->td_samplesperpixel == 3) + sp->cinfo.c.in_color_space = JCS_RGB; + else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4) + sp->cinfo.c.in_color_space = JCS_CMYK; + else + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + } + } else { + sp->cinfo.c.input_components = 1; + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + } + if (!TIFFjpeg_set_defaults(sp)) + return (0); + /* Set per-file parameters */ + switch (sp->photometric) { + case PHOTOMETRIC_YCBCR: + sp->h_sampling = td->td_ycbcrsubsampling[0]; + sp->v_sampling = td->td_ycbcrsubsampling[1]; + if( sp->h_sampling == 0 || sp->v_sampling == 0 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Invalig horizontal/vertical sampling value"); + return (0); + } + if( td->td_bitspersample > 16 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "BitsPerSample %"PRIu16" not allowed for JPEG", + td->td_bitspersample); + return (0); + } + + /* + * A ReferenceBlackWhite field *must* be present since the + * default value is inappropriate for YCbCr. Fill in the + * proper value if application didn't set it. + */ + { + float *ref; + if (!TIFFGetField(tif, TIFFTAG_REFERENCEBLACKWHITE, + &ref)) { + float refbw[6]; + long top = 1L << td->td_bitspersample; + refbw[0] = 0; + refbw[1] = (float)(top-1L); + refbw[2] = (float)(top>>1); + refbw[3] = refbw[1]; + refbw[4] = refbw[2]; + refbw[5] = refbw[1]; + TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE, + refbw); + } + } + break; + case PHOTOMETRIC_PALETTE: /* disallowed by Tech Note */ + case PHOTOMETRIC_MASK: + TIFFErrorExt(tif->tif_clientdata, module, + "PhotometricInterpretation %"PRIu16" not allowed for JPEG", + sp->photometric); + return (0); + default: + /* TIFF 6.0 forbids subsampling of all other color spaces */ + sp->h_sampling = 1; + sp->v_sampling = 1; + break; + } + + /* Verify miscellaneous parameters */ + + /* + * This would need work if libtiff ever supports different + * depths for different components, or if libjpeg ever supports + * run-time selection of depth. Neither is imminent. + */ +#ifdef JPEG_LIB_MK1 + /* BITS_IN_JSAMPLE now permits 8 and 12 --- dgilbert */ + if (td->td_bitspersample != 8 && td->td_bitspersample != 12) +#else + if (td->td_bitspersample != BITS_IN_JSAMPLE ) +#endif + { + TIFFErrorExt(tif->tif_clientdata, module, "BitsPerSample %"PRIu16" not allowed for JPEG", + td->td_bitspersample); + return (0); + } + sp->cinfo.c.data_precision = td->td_bitspersample; +#ifdef JPEG_LIB_MK1 + sp->cinfo.c.bits_in_jsample = td->td_bitspersample; +#endif + if (isTiled(tif)) { + if ((td->td_tilelength % (sp->v_sampling * DCTSIZE)) != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "JPEG tile height must be multiple of %"PRIu32, + (uint32_t)(sp->v_sampling * DCTSIZE)); + return (0); + } + if ((td->td_tilewidth % (sp->h_sampling * DCTSIZE)) != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "JPEG tile width must be multiple of %"PRIu32, + (uint32_t)(sp->h_sampling * DCTSIZE)); + return (0); + } + } else { + if (td->td_rowsperstrip < td->td_imagelength && + (td->td_rowsperstrip % (sp->v_sampling * DCTSIZE)) != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "RowsPerStrip must be multiple of %"PRIu32" for JPEG", + (uint32_t)(sp->v_sampling * DCTSIZE)); + return (0); + } + } + + /* Create a JPEGTables field if appropriate */ + if (sp->jpegtablesmode & (JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF)) { + if( sp->jpegtables == NULL + || memcmp(sp->jpegtables,"\0\0\0\0\0\0\0\0\0",8) == 0 ) + { + if (!prepare_JPEGTables(tif)) + return (0); + /* Mark the field present */ + /* Can't use TIFFSetField since BEENWRITING is already set! */ + tif->tif_flags |= TIFF_DIRTYDIRECT; + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + } + } else { + /* We do not support application-supplied JPEGTables, */ + /* so mark the field not present */ + TIFFClrFieldBit(tif, FIELD_JPEGTABLES); + } + + /* Direct libjpeg output to libtiff's output buffer */ + TIFFjpeg_data_dest(sp, tif); + + return (1); +} + +/* + * Set encoding state at the start of a strip or tile. + */ +static int +JPEGPreEncode(TIFF* tif, uint16_t s) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGPreEncode"; + uint32_t segment_width, segment_height; + int downsampled_input; + + assert(sp != NULL); + + if (sp->cinfo.comm.is_decompressor == 1) + { + tif->tif_setupencode( tif ); + } + + assert(!sp->cinfo.comm.is_decompressor); + /* + * Set encoding parameters for this strip/tile. + */ + if (isTiled(tif)) { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + sp->bytesperline = TIFFTileRowSize(tif); + } else { + segment_width = td->td_imagewidth; + segment_height = td->td_imagelength - tif->tif_row; + if (segment_height > td->td_rowsperstrip) + segment_height = td->td_rowsperstrip; + sp->bytesperline = TIFFScanlineSize(tif); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { + /* for PC 2, scale down the strip/tile size + * to match a downsampled component + */ + segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); + segment_height = TIFFhowmany_32(segment_height, sp->v_sampling); + } + if (segment_width > 65535 || segment_height > 65535) { + TIFFErrorExt(tif->tif_clientdata, module, "Strip/tile too large for JPEG"); + return (0); + } + sp->cinfo.c.image_width = segment_width; + sp->cinfo.c.image_height = segment_height; + downsampled_input = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + sp->cinfo.c.input_components = td->td_samplesperpixel; + if (sp->photometric == PHOTOMETRIC_YCBCR) { + if (sp->jpegcolormode != JPEGCOLORMODE_RGB) { + if (sp->h_sampling != 1 || sp->v_sampling != 1) + downsampled_input = TRUE; + } + if (!TIFFjpeg_set_colorspace(sp, JCS_YCbCr)) + return (0); + /* + * Set Y sampling factors; + * we assume jpeg_set_colorspace() set the rest to 1 + */ + sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling; + sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling; + } else { + if (!TIFFjpeg_set_colorspace(sp, sp->cinfo.c.in_color_space)) + return (0); + /* jpeg_set_colorspace set all sampling factors to 1 */ + } + } else { + if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) + return (0); + sp->cinfo.c.comp_info[0].component_id = s; + /* jpeg_set_colorspace() set sampling factors to 1 */ + if (sp->photometric == PHOTOMETRIC_YCBCR && s > 0) { + sp->cinfo.c.comp_info[0].quant_tbl_no = 1; + sp->cinfo.c.comp_info[0].dc_tbl_no = 1; + sp->cinfo.c.comp_info[0].ac_tbl_no = 1; + } + } + /* ensure libjpeg won't write any extraneous markers */ + sp->cinfo.c.write_JFIF_header = FALSE; + sp->cinfo.c.write_Adobe_marker = FALSE; + /* set up table handling correctly */ + /* calling TIFFjpeg_set_quality() causes quantization tables to be flagged */ + /* as being to be emitted, which we don't want in the JPEGTABLESMODE_QUANT */ + /* mode, so we must manually suppress them. However TIFFjpeg_set_quality() */ + /* should really be called when dealing with files with directories with */ + /* mixed qualities. see http://trac.osgeo.org/gdal/ticket/3539 */ + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + return (0); + if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) { + suppress_quant_table(sp, 0); + suppress_quant_table(sp, 1); + } + else { + unsuppress_quant_table(sp, 0); + unsuppress_quant_table(sp, 1); + } + if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) + { + /* Explicit suppression is only needed if we did not go through the */ + /* prepare_JPEGTables() code path, which may be the case if updating */ + /* an existing file */ + suppress_huff_table(sp, 0); + suppress_huff_table(sp, 1); + sp->cinfo.c.optimize_coding = FALSE; + } + else + sp->cinfo.c.optimize_coding = TRUE; + if (downsampled_input) { + /* Need to use raw-data interface to libjpeg */ + sp->cinfo.c.raw_data_in = TRUE; + tif->tif_encoderow = JPEGEncodeRaw; + tif->tif_encodestrip = JPEGEncodeRaw; + tif->tif_encodetile = JPEGEncodeRaw; + } else { + /* Use normal interface to libjpeg */ + sp->cinfo.c.raw_data_in = FALSE; + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; + } + /* Start JPEG compressor */ + if (!TIFFjpeg_start_compress(sp, FALSE)) + return (0); + /* Allocate downsampled-data buffers if needed */ + if (downsampled_input) { + if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info, + sp->cinfo.c.num_components)) + return (0); + } + sp->scancount = 0; + + return (1); +} + +/* + * Encode a chunk of pixels. + * "Standard" case: incoming data is not downsampled. + */ +static int +JPEGEncode(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s) +{ + JPEGState *sp = JState(tif); + tmsize_t nrows; + JSAMPROW bufptr[1]; + short *line16 = NULL; + int line16_count = 0; + + (void) s; + assert(sp != NULL); + /* data is expected to be supplied in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, + "fractional scanline discarded"); + + /* The last strip will be limited to image size */ + if( !isTiled(tif) && tif->tif_row+nrows > tif->tif_dir.td_imagelength ) + nrows = tif->tif_dir.td_imagelength - tif->tif_row; + + if( sp->cinfo.c.data_precision == 12 ) + { + line16_count = (int)((sp->bytesperline * 2) / 3); + line16 = (short *) _TIFFmalloc(sizeof(short) * line16_count); + if (!line16) + { + TIFFErrorExt(tif->tif_clientdata, + "JPEGEncode", + "Failed to allocate memory"); + + return 0; + } + } + + while (nrows-- > 0) { + + if( sp->cinfo.c.data_precision == 12 ) + { + + int value_pairs = line16_count / 2; + int iPair; + + bufptr[0] = (JSAMPROW) line16; + + for( iPair = 0; iPair < value_pairs; iPair++ ) + { + unsigned char *in_ptr = + ((unsigned char *) buf) + iPair * 3; + JSAMPLE *out_ptr = (JSAMPLE *) (line16 + iPair * 2); + + out_ptr[0] = (in_ptr[0] << 4) | ((in_ptr[1] & 0xf0) >> 4); + out_ptr[1] = ((in_ptr[1] & 0x0f) << 8) | in_ptr[2]; + } + } + else + { + bufptr[0] = (JSAMPROW) buf; + } + if (TIFFjpeg_write_scanlines(sp, bufptr, 1) != 1) + return (0); + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + + if( sp->cinfo.c.data_precision == 12 ) + { + _TIFFfree( line16 ); + } + + return (1); +} + +/* + * Encode a chunk of pixels. + * Incoming data is expected to be downsampled per sampling factors. + */ +static int +JPEGEncodeRaw(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s) +{ + JPEGState *sp = JState(tif); + JSAMPLE* inptr; + JSAMPLE* outptr; + tmsize_t nrows; + JDIMENSION clumps_per_line, nclump; + int clumpoffset, ci, xpos, ypos; + jpeg_component_info* compptr; + int samples_per_clump = sp->samplesperclump; + tmsize_t bytesperclumpline; + + (void) s; + assert(sp != NULL); + /* data is expected to be supplied in multiples of a clumpline */ + /* a clumpline is equivalent to v_sampling desubsampled scanlines */ + /* TODO: the following calculation of bytesperclumpline, should substitute calculation of sp->bytesperline, except that it is per v_sampling lines */ + bytesperclumpline = ((((tmsize_t)sp->cinfo.c.image_width+sp->h_sampling-1)/sp->h_sampling) + *((tmsize_t)sp->h_sampling*sp->v_sampling+2)*sp->cinfo.c.data_precision+7) + /8; + + nrows = ( cc / bytesperclumpline ) * sp->v_sampling; + if (cc % bytesperclumpline) + TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline discarded"); + + /* Cb,Cr both have sampling factors 1, so this is correct */ + clumps_per_line = sp->cinfo.c.comp_info[1].downsampled_width; + + while (nrows > 0) { + /* + * Fastest way to separate the data is to make one pass + * over the scanline for each row of each component. + */ + clumpoffset = 0; /* first sample in clump */ + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; + ci++, compptr++) { + int hsamp = compptr->h_samp_factor; + int vsamp = compptr->v_samp_factor; + int padding = (int) (compptr->width_in_blocks * DCTSIZE - + clumps_per_line * hsamp); + for (ypos = 0; ypos < vsamp; ypos++) { + inptr = ((JSAMPLE*) buf) + clumpoffset; + outptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; + if (hsamp == 1) { + /* fast path for at least Cb and Cr */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + *outptr++ = inptr[0]; + inptr += samples_per_clump; + } + } else { + /* general case */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + for (xpos = 0; xpos < hsamp; xpos++) + *outptr++ = inptr[xpos]; + inptr += samples_per_clump; + } + } + /* pad each scanline as needed */ + for (xpos = 0; xpos < padding; xpos++) { + *outptr = outptr[-1]; + outptr++; + } + clumpoffset += hsamp; + } + } + sp->scancount++; + if (sp->scancount >= DCTSIZE) { + int n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + sp->scancount = 0; + } + tif->tif_row += sp->v_sampling; + buf += bytesperclumpline; + nrows -= sp->v_sampling; + } + return (1); +} + +/* + * Finish up at the end of a strip or tile. + */ +static int +JPEGPostEncode(TIFF* tif) +{ + JPEGState *sp = JState(tif); + + if (sp->scancount > 0) { + /* + * Need to emit a partial bufferload of downsampled data. + * Pad the data vertically. + */ + int ci, ypos, n; + jpeg_component_info* compptr; + + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; + ci++, compptr++) { + int vsamp = compptr->v_samp_factor; + tmsize_t row_width = compptr->width_in_blocks * DCTSIZE + * sizeof(JSAMPLE); + for (ypos = sp->scancount * vsamp; + ypos < DCTSIZE * vsamp; ypos++) { + _TIFFmemcpy((void*)sp->ds_buffer[ci][ypos], + (void*)sp->ds_buffer[ci][ypos-1], + row_width); + + } + } + n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + } + + return (TIFFjpeg_finish_compress(JState(tif))); +} + +static void +JPEGCleanup(TIFF* tif) +{ + JPEGState *sp = JState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + tif->tif_tagmethods.printdir = sp->printdir; + if( sp->cinfo_initialized ) + TIFFjpeg_destroy(sp); /* release libjpeg resources */ + if (sp->jpegtables) /* tag value */ + _TIFFfree(sp->jpegtables); + _TIFFfree(tif->tif_data); /* release local state */ + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static void +JPEGResetUpsampled( TIFF* tif ) +{ + JPEGState* sp = JState(tif); + TIFFDirectory* td = &tif->tif_dir; + + /* + * Mark whether returned data is up-sampled or not so TIFFStripSize + * and TIFFTileSize return values that reflect the true amount of + * data. + */ + tif->tif_flags &= ~TIFF_UPSAMPLED; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + if (td->td_photometric == PHOTOMETRIC_YCBCR && + sp->jpegcolormode == JPEGCOLORMODE_RGB) { + tif->tif_flags |= TIFF_UPSAMPLED; + } else { +#ifdef notdef + if (td->td_ycbcrsubsampling[0] != 1 || + td->td_ycbcrsubsampling[1] != 1) + ; /* XXX what about up-sampling? */ +#endif + } + } + + /* + * Must recalculate cached tile size in case sampling state changed. + * Should we really be doing this now if image size isn't set? + */ + if( tif->tif_tilesize > 0 ) + tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t)(-1); + if( tif->tif_scanlinesize > 0 ) + tif->tif_scanlinesize = TIFFScanlineSize(tif); +} + +static int +JPEGVSetField(TIFF* tif, uint32_t tag, va_list ap) +{ + JPEGState* sp = JState(tif); + const TIFFField* fip; + uint32_t v32; + + assert(sp != NULL); + + switch (tag) { + case TIFFTAG_JPEGTABLES: + v32 = (uint32_t) va_arg(ap, uint32_t); + if (v32 == 0) { + /* XXX */ + return (0); + } + _TIFFsetByteArray(&sp->jpegtables, va_arg(ap, void*), v32); + sp->jpegtables_length = v32; + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + break; + case TIFFTAG_JPEGQUALITY: + sp->jpegquality = (int) va_arg(ap, int); + return (1); /* pseudo tag */ + case TIFFTAG_JPEGCOLORMODE: + sp->jpegcolormode = (int) va_arg(ap, int); + JPEGResetUpsampled( tif ); + return (1); /* pseudo tag */ + case TIFFTAG_PHOTOMETRIC: + { + int ret_value = (*sp->vsetparent)(tif, tag, ap); + JPEGResetUpsampled( tif ); + return ret_value; + } + case TIFFTAG_JPEGTABLESMODE: + sp->jpegtablesmode = (int) va_arg(ap, int); + return (1); /* pseudo tag */ + case TIFFTAG_YCBCRSUBSAMPLING: + /* mark the fact that we have a real ycbcrsubsampling! */ + sp->ycbcrsampling_fetched = 1; + /* should we be recomputing upsampling info here? */ + return (*sp->vsetparent)(tif, tag, ap); + default: + return (*sp->vsetparent)(tif, tag, ap); + } + + if ((fip = TIFFFieldWithTag(tif, tag)) != NULL) { + TIFFSetFieldBit(tif, fip->field_bit); + } else { + return (0); + } + + tif->tif_flags |= TIFF_DIRTYDIRECT; + return (1); +} + +static int +JPEGVGetField(TIFF* tif, uint32_t tag, va_list ap) +{ + JPEGState* sp = JState(tif); + + assert(sp != NULL); + + switch (tag) { + case TIFFTAG_JPEGTABLES: + *va_arg(ap, uint32_t*) = sp->jpegtables_length; + *va_arg(ap, const void**) = sp->jpegtables; + break; + case TIFFTAG_JPEGQUALITY: + *va_arg(ap, int*) = sp->jpegquality; + break; + case TIFFTAG_JPEGCOLORMODE: + *va_arg(ap, int*) = sp->jpegcolormode; + break; + case TIFFTAG_JPEGTABLESMODE: + *va_arg(ap, int*) = sp->jpegtablesmode; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static void +JPEGPrintDir(TIFF* tif, FILE* fd, long flags) +{ + JPEGState* sp = JState(tif); + + assert(sp != NULL); + (void) flags; + + if( sp != NULL ) { + if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) + fprintf(fd, " JPEG Tables: (%"PRIu32" bytes)\n", + sp->jpegtables_length); + if (sp->printdir) + (*sp->printdir)(tif, fd, flags); + } +} + +static uint32_t +JPEGDefaultStripSize(TIFF* tif, uint32_t s) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + s = (*sp->defsparent)(tif, s); + if (s < td->td_imagelength) + s = TIFFroundup_32(s, td->td_ycbcrsubsampling[1] * DCTSIZE); + return (s); +} + +static void +JPEGDefaultTileSize(TIFF* tif, uint32_t* tw, uint32_t* th) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + (*sp->deftparent)(tif, tw, th); + *tw = TIFFroundup_32(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE); + *th = TIFFroundup_32(*th, td->td_ycbcrsubsampling[1] * DCTSIZE); +} + +/* + * The JPEG library initialized used to be done in TIFFInitJPEG(), but + * now that we allow a TIFF file to be opened in update mode it is necessary + * to have some way of deciding whether compression or decompression is + * desired other than looking at tif->tif_mode. We accomplish this by + * examining {TILE/STRIP}BYTECOUNTS to see if there is a non-zero entry. + * If so, we assume decompression is desired. + * + * This is tricky, because TIFFInitJPEG() is called while the directory is + * being read, and generally speaking the BYTECOUNTS tag won't have been read + * at that point. So we try to defer jpeg library initialization till we + * do have that tag ... basically any access that might require the compressor + * or decompressor that occurs after the reading of the directory. + * + * In an ideal world compressors or decompressors would be setup + * at the point where a single tile or strip was accessed (for read or write) + * so that stuff like update of missing tiles, or replacement of tiles could + * be done. However, we aren't trying to crack that nut just yet ... + * + * NFW, Feb 3rd, 2003. + */ + +static int JPEGInitializeLibJPEG( TIFF * tif, int decompress ) +{ + JPEGState* sp = JState(tif); + + if(sp->cinfo_initialized) + { + if( !decompress && sp->cinfo.comm.is_decompressor ) + TIFFjpeg_destroy( sp ); + else if( decompress && !sp->cinfo.comm.is_decompressor ) + TIFFjpeg_destroy( sp ); + else + return 1; + + sp->cinfo_initialized = 0; + } + + /* + * Initialize libjpeg. + */ + if ( decompress ) { + if (!TIFFjpeg_create_decompress(sp)) + return (0); + } else { + if (!TIFFjpeg_create_compress(sp)) + return (0); +#ifndef TIFF_JPEG_MAX_MEMORY_TO_USE +#define TIFF_JPEG_MAX_MEMORY_TO_USE (10 * 1024 * 1024) +#endif + /* libjpeg turbo 1.5.2 honours max_memory_to_use, but has no backing */ + /* store implementation, so better not set max_memory_to_use ourselves. */ + /* See https://github.com/libjpeg-turbo/libjpeg-turbo/issues/162 */ + if( sp->cinfo.c.mem->max_memory_to_use > 0 ) + { + /* This is to address bug related in ticket GDAL #1795. */ + if (getenv("JPEGMEM") == NULL) + { + /* Increase the max memory usable. This helps when creating files */ + /* with "big" tile, without using libjpeg temporary files. */ + /* For example a 512x512 tile with 3 bands */ + /* requires 1.5 MB which is above libjpeg 1MB default */ + if( sp->cinfo.c.mem->max_memory_to_use < TIFF_JPEG_MAX_MEMORY_TO_USE ) + sp->cinfo.c.mem->max_memory_to_use = TIFF_JPEG_MAX_MEMORY_TO_USE; + } + } + } + + sp->cinfo_initialized = TRUE; + + return 1; +} + +int +TIFFInitJPEG(TIFF* tif, int scheme) +{ + JPEGState* sp; + + (void)scheme; + assert(scheme == COMPRESSION_JPEG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, jpegFields, TIFFArrayCount(jpegFields))) { + TIFFErrorExt(tif->tif_clientdata, + "TIFFInitJPEG", + "Merging JPEG codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t*) _TIFFmalloc(sizeof (JPEGState)); + + if (tif->tif_data == NULL) { + TIFFErrorExt(tif->tif_clientdata, + "TIFFInitJPEG", "No space for JPEG state block"); + return 0; + } + _TIFFmemset(tif->tif_data, 0, sizeof(JPEGState)); + + sp = JState(tif); + sp->tif = tif; /* back link */ + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = JPEGVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = JPEGVSetField; /* hook for codec tags */ + sp->printdir = tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir = JPEGPrintDir; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->jpegtables = NULL; + sp->jpegtables_length = 0; + sp->jpegquality = 75; /* Default IJG quality */ + sp->jpegcolormode = JPEGCOLORMODE_RAW; + sp->jpegtablesmode = JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF; + sp->ycbcrsampling_fetched = 0; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = JPEGFixupTags; + tif->tif_setupdecode = JPEGSetupDecode; + tif->tif_predecode = JPEGPreDecode; + tif->tif_decoderow = JPEGDecode; + tif->tif_decodestrip = JPEGDecode; + tif->tif_decodetile = JPEGDecode; + tif->tif_setupencode = JPEGSetupEncode; + tif->tif_preencode = JPEGPreEncode; + tif->tif_postencode = JPEGPostEncode; + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; + tif->tif_cleanup = JPEGCleanup; + sp->defsparent = tif->tif_defstripsize; + tif->tif_defstripsize = JPEGDefaultStripSize; + sp->deftparent = tif->tif_deftilesize; + tif->tif_deftilesize = JPEGDefaultTileSize; + tif->tif_flags |= TIFF_NOBITREV; /* no bit reversal, please */ + + sp->cinfo_initialized = FALSE; + + /* + ** Create a JPEGTables field if no directory has yet been created. + ** We do this just to ensure that sufficient space is reserved for + ** the JPEGTables field. It will be properly created the right + ** size later. + */ + if( tif->tif_diroff == 0 ) + { +#define SIZE_OF_JPEGTABLES 2000 +/* +The following line assumes incorrectly that all JPEG-in-TIFF files will have +a JPEGTABLES tag generated and causes null-filled JPEGTABLES tags to be written +when the JPEG data is placed with TIFFWriteRawStrip. The field bit should be +set, anyway, later when actual JPEGTABLES header is generated, so removing it +here hopefully is harmless. + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); +*/ + sp->jpegtables_length = SIZE_OF_JPEGTABLES; + sp->jpegtables = (void *) _TIFFmalloc(sp->jpegtables_length); + if (sp->jpegtables) + { + _TIFFmemset(sp->jpegtables, 0, SIZE_OF_JPEGTABLES); + } + else + { + TIFFErrorExt(tif->tif_clientdata, + "TIFFInitJPEG", + "Failed to allocate memory for JPEG tables"); + return 0; + } +#undef SIZE_OF_JPEGTABLES + } + + return 1; +} +#endif /* JPEG_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_luv.c b/libs/tiff/libtiff/tif_luv.c new file mode 100644 index 00000000000..13765eab23c --- /dev/null +++ b/libs/tiff/libtiff/tif_luv.c @@ -0,0 +1,1749 @@ +/* + * Copyright (c) 1997 Greg Ward Larson + * Copyright (c) 1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler, Greg Larson and Silicon Graphics may not be used in any + * advertising or publicity relating to the software without the specific, + * prior written permission of Sam Leffler, Greg Larson and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER, GREG LARSON OR SILICON GRAPHICS BE LIABLE + * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef LOGLUV_SUPPORT + +/* + * TIFF Library. + * LogLuv compression support for high dynamic range images. + * + * Contributed by Greg Larson. + * + * LogLuv image support uses the TIFF library to store 16 or 10-bit + * log luminance values with 8 bits each of u and v or a 14-bit index. + * + * The codec can take as input and produce as output 32-bit IEEE float values + * as well as 16-bit integer values. A 16-bit luminance is interpreted + * as a sign bit followed by a 15-bit integer that is converted + * to and from a linear magnitude using the transformation: + * + * L = 2^( (Le+.5)/256 - 64 ) # real from 15-bit + * + * Le = floor( 256*(log2(L) + 64) ) # 15-bit from real + * + * The actual conversion to world luminance units in candelas per sq. meter + * requires an additional multiplier, which is stored in the TIFFTAG_STONITS. + * This value is usually set such that a reasonable exposure comes from + * clamping decoded luminances above 1 to 1 in the displayed image. + * + * The 16-bit values for u and v may be converted to real values by dividing + * each by 32768. (This allows for negative values, which aren't useful as + * far as we know, but are left in case of future improvements in human + * color vision.) + * + * Conversion from (u,v), which is actually the CIE (u',v') system for + * you color scientists, is accomplished by the following transformation: + * + * u = 4*x / (-2*x + 12*y + 3) + * v = 9*y / (-2*x + 12*y + 3) + * + * x = 9*u / (6*u - 16*v + 12) + * y = 4*v / (6*u - 16*v + 12) + * + * This process is greatly simplified by passing 32-bit IEEE floats + * for each of three CIE XYZ coordinates. The codec then takes care + * of conversion to and from LogLuv, though the application is still + * responsible for interpreting the TIFFTAG_STONITS calibration factor. + * + * By definition, a CIE XYZ vector of [1 1 1] corresponds to a neutral white + * point of (x,y)=(1/3,1/3). However, most color systems assume some other + * white point, such as D65, and an absolute color conversion to XYZ then + * to another color space with a different white point may introduce an + * unwanted color cast to the image. It is often desirable, therefore, to + * perform a white point conversion that maps the input white to [1 1 1] + * in XYZ, then record the original white point using the TIFFTAG_WHITEPOINT + * tag value. A decoder that demands absolute color calibration may use + * this white point tag to get back the original colors, but usually it + * will be ignored and the new white point will be used instead that + * matches the output color space. + * + * Pixel information is compressed into one of two basic encodings, depending + * on the setting of the compression tag, which is one of COMPRESSION_SGILOG + * or COMPRESSION_SGILOG24. For COMPRESSION_SGILOG, greyscale data is + * stored as: + * + * 1 15 + * |-+---------------| + * + * COMPRESSION_SGILOG color data is stored as: + * + * 1 15 8 8 + * |-+---------------|--------+--------| + * S Le ue ve + * + * For the 24-bit COMPRESSION_SGILOG24 color format, the data is stored as: + * + * 10 14 + * |----------|--------------| + * Le' Ce + * + * There is no sign bit in the 24-bit case, and the (u,v) chromaticity is + * encoded as an index for optimal color resolution. The 10 log bits are + * defined by the following conversions: + * + * L = 2^((Le'+.5)/64 - 12) # real from 10-bit + * + * Le' = floor( 64*(log2(L) + 12) ) # 10-bit from real + * + * The 10 bits of the smaller format may be converted into the 15 bits of + * the larger format by multiplying by 4 and adding 13314. Obviously, + * a smaller range of magnitudes is covered (about 5 orders of magnitude + * instead of 38), and the lack of a sign bit means that negative luminances + * are not allowed. (Well, they aren't allowed in the real world, either, + * but they are useful for certain types of image processing.) + * + * The desired user format is controlled by the setting the internal + * pseudo tag TIFFTAG_SGILOGDATAFMT to one of: + * SGILOGDATAFMT_FLOAT = IEEE 32-bit float XYZ values + * SGILOGDATAFMT_16BIT = 16-bit integer encodings of logL, u and v + * Raw data i/o is also possible using: + * SGILOGDATAFMT_RAW = 32-bit unsigned integer with encoded pixel + * In addition, the following decoding is provided for ease of display: + * SGILOGDATAFMT_8BIT = 8-bit default RGB gamma-corrected values + * + * For grayscale images, we provide the following data formats: + * SGILOGDATAFMT_FLOAT = IEEE 32-bit float Y values + * SGILOGDATAFMT_16BIT = 16-bit integer w/ encoded luminance + * SGILOGDATAFMT_8BIT = 8-bit gray monitor values + * + * Note that the COMPRESSION_SGILOG applies a simple run-length encoding + * scheme by separating the logL, u and v bytes for each row and applying + * a PackBits type of compression. Since the 24-bit encoding is not + * adaptive, the 32-bit color format takes less space in many cases. + * + * Further control is provided over the conversion from higher-resolution + * formats to final encoded values through the pseudo tag + * TIFFTAG_SGILOGENCODE: + * SGILOGENCODE_NODITHER = do not dither encoded values + * SGILOGENCODE_RANDITHER = apply random dithering during encoding + * + * The default value of this tag is SGILOGENCODE_NODITHER for + * COMPRESSION_SGILOG to maximize run-length encoding and + * SGILOGENCODE_RANDITHER for COMPRESSION_SGILOG24 to turn + * quantization errors into noise. + */ + +#include +#include +#include + +/* + * State block for each open TIFF + * file using LogLuv compression/decompression. + */ +typedef struct logLuvState LogLuvState; + +struct logLuvState { + int encoder_state; /* 1 if encoder correctly initialized */ + int user_datafmt; /* user data format */ + int encode_meth; /* encoding method */ + int pixel_size; /* bytes per pixel */ + + uint8_t* tbuf; /* translation buffer */ + tmsize_t tbuflen; /* buffer length */ + void (*tfunc)(LogLuvState*, uint8_t*, tmsize_t); + + TIFFVSetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +}; + +#define DecoderState(tif) ((LogLuvState*) (tif)->tif_data) +#define EncoderState(tif) ((LogLuvState*) (tif)->tif_data) + +#define SGILOGDATAFMT_UNKNOWN -1 + +#define MINRUN 4 /* minimum run length */ + +/* + * Decode a string of 16-bit gray pixels. + */ +static int +LogL16Decode(TIFF* tif, uint8_t* op, tmsize_t occ, uint16_t s) +{ + static const char module[] = "LogL16Decode"; + LogLuvState* sp = DecoderState(tif); + int shft; + tmsize_t i; + tmsize_t npixels; + unsigned char* bp; + int16_t* tp; + int16_t b; + tmsize_t cc; + int rc; + + (void)s; + assert(s == 0); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_16BIT) + tp = (int16_t*) op; + else { + if(sp->tbuflen < npixels) { + TIFFErrorExt(tif->tif_clientdata, module, + "Translation buffer too short"); + return (0); + } + tp = (int16_t*) sp->tbuf; + } + _TIFFmemset((void*) tp, 0, npixels*sizeof (tp[0])); + + bp = (unsigned char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + /* get each byte string */ + for (shft = 8; shft >= 0; shft -=8) { + for (i = 0; i < npixels && cc > 0; ) { + if (*bp >= 128) { /* run */ + if( cc < 2 ) + break; + rc = *bp++ + (2-128); + b = (int16_t)(*bp++ << shft); + cc -= 2; + while (rc-- && i < npixels) + tp[i++] |= b; + } else { /* non-run */ + rc = *bp++; /* nul is noop */ + while (--cc && rc-- && i < npixels) + tp[i++] |= (int16_t)*bp++ << shft; + } + } + if (i != npixels) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at row %"PRIu32" (short %"TIFF_SSIZE_FORMAT" pixels)", + tif->tif_row, + npixels - i); + tif->tif_rawcp = (uint8_t*) bp; + tif->tif_rawcc = cc; + return (0); + } + } + (*sp->tfunc)(sp, op, npixels); + tif->tif_rawcp = (uint8_t*) bp; + tif->tif_rawcc = cc; + return (1); +} + +/* + * Decode a string of 24-bit pixels. + */ +static int +LogLuvDecode24(TIFF* tif, uint8_t* op, tmsize_t occ, uint16_t s) +{ + static const char module[] = "LogLuvDecode24"; + LogLuvState* sp = DecoderState(tif); + tmsize_t cc; + tmsize_t i; + tmsize_t npixels; + unsigned char* bp; + uint32_t* tp; + + (void)s; + assert(s == 0); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32_t *)op; + else { + if(sp->tbuflen < npixels) { + TIFFErrorExt(tif->tif_clientdata, module, + "Translation buffer too short"); + return (0); + } + tp = (uint32_t *) sp->tbuf; + } + /* copy to array of uint32_t */ + bp = (unsigned char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + for (i = 0; i < npixels && cc >= 3; i++) { + tp[i] = bp[0] << 16 | bp[1] << 8 | bp[2]; + bp += 3; + cc -= 3; + } + tif->tif_rawcp = (uint8_t*) bp; + tif->tif_rawcc = cc; + if (i != npixels) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at row %"PRIu32" (short %"TIFF_SSIZE_FORMAT" pixels)", + tif->tif_row, + npixels - i); + return (0); + } + (*sp->tfunc)(sp, op, npixels); + return (1); +} + +/* + * Decode a string of 32-bit pixels. + */ +static int +LogLuvDecode32(TIFF* tif, uint8_t* op, tmsize_t occ, uint16_t s) +{ + static const char module[] = "LogLuvDecode32"; + LogLuvState* sp; + int shft; + tmsize_t i; + tmsize_t npixels; + unsigned char* bp; + uint32_t* tp; + uint32_t b; + tmsize_t cc; + int rc; + + (void)s; + assert(s == 0); + sp = DecoderState(tif); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32_t*) op; + else { + if(sp->tbuflen < npixels) { + TIFFErrorExt(tif->tif_clientdata, module, + "Translation buffer too short"); + return (0); + } + tp = (uint32_t*) sp->tbuf; + } + _TIFFmemset((void*) tp, 0, npixels*sizeof (tp[0])); + + bp = (unsigned char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + /* get each byte string */ + for (shft = 24; shft >= 0; shft -=8) { + for (i = 0; i < npixels && cc > 0; ) { + if (*bp >= 128) { /* run */ + if( cc < 2 ) + break; + rc = *bp++ + (2-128); + b = (uint32_t)*bp++ << shft; + cc -= 2; + while (rc-- && i < npixels) + tp[i++] |= b; + } else { /* non-run */ + rc = *bp++; /* nul is noop */ + while (--cc && rc-- && i < npixels) + tp[i++] |= (uint32_t)*bp++ << shft; + } + } + if (i != npixels) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at row %"PRIu32" (short %"TIFF_SSIZE_FORMAT" pixels)", + tif->tif_row, + npixels - i); + tif->tif_rawcp = (uint8_t*) bp; + tif->tif_rawcc = cc; + return (0); + } + } + (*sp->tfunc)(sp, op, npixels); + tif->tif_rawcp = (uint8_t*) bp; + tif->tif_rawcc = cc; + return (1); +} + +/* + * Decode a strip of pixels. We break it into rows to + * maintain synchrony with the encode algorithm, which + * is row by row. + */ +static int +LogLuvDecodeStrip(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + tmsize_t rowlen = TIFFScanlineSize(tif); + + if (rowlen == 0) + return 0; + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) { + bp += rowlen; + cc -= rowlen; + } + return (cc == 0); +} + +/* + * Decode a tile of pixels. We break it into rows to + * maintain synchrony with the encode algorithm, which + * is row by row. + */ +static int +LogLuvDecodeTile(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + tmsize_t rowlen = TIFFTileRowSize(tif); + + if (rowlen == 0) + return 0; + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) { + bp += rowlen; + cc -= rowlen; + } + return (cc == 0); +} + +/* + * Encode a row of 16-bit pixels. + */ +static int +LogL16Encode(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "LogL16Encode"; + LogLuvState* sp = EncoderState(tif); + int shft; + tmsize_t i; + tmsize_t j; + tmsize_t npixels; + uint8_t* op; + int16_t* tp; + int16_t b; + tmsize_t occ; + int rc=0, mask; + tmsize_t beg; + + (void)s; + assert(s == 0); + assert(sp != NULL); + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_16BIT) + tp = (int16_t*) bp; + else { + tp = (int16_t*) sp->tbuf; + if(sp->tbuflen < npixels) { + TIFFErrorExt(tif->tif_clientdata, module, + "Translation buffer too short"); + return (0); + } + (*sp->tfunc)(sp, bp, npixels); + } + /* compress each byte string */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (shft = 8; shft >= 0; shft -=8) { + for (i = 0; i < npixels; i += rc) { + if (occ < 4) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (0); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + mask = 0xff << shft; /* find next run */ + for (beg = i; beg < npixels; beg += rc) { + b = (int16_t) (tp[beg] & mask); + rc = 1; + while (rc < 127+2 && beg+rc < npixels && + (tp[beg+rc] & mask) == b) + rc++; + if (rc >= MINRUN) + break; /* long enough */ + } + if (beg-i > 1 && beg-i < MINRUN) { + b = (int16_t) (tp[i] & mask);/*check short run */ + j = i+1; + while ((tp[j++] & mask) == b) + if (j == beg) { + *op++ = (uint8_t)(128 - 2 + j - i); + *op++ = (uint8_t)(b >> shft); + occ -= 2; + i = beg; + break; + } + } + while (i < beg) { /* write out non-run */ + if ((j = beg-i) > 127) j = 127; + if (occ < j+3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (0); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = (uint8_t) j; occ--; + while (j--) { + *op++ = (uint8_t) (tp[i++] >> shft & 0xff); + occ--; + } + } + if (rc >= MINRUN) { /* write out run */ + *op++ = (uint8_t) (128 - 2 + rc); + *op++ = (uint8_t) (tp[beg] >> shft & 0xff); + occ -= 2; + } else + rc = 0; + } + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (1); +} + +/* + * Encode a row of 24-bit pixels. + */ +static int +LogLuvEncode24(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "LogLuvEncode24"; + LogLuvState* sp = EncoderState(tif); + tmsize_t i; + tmsize_t npixels; + tmsize_t occ; + uint8_t* op; + uint32_t* tp; + + (void)s; + assert(s == 0); + assert(sp != NULL); + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32_t*) bp; + else { + tp = (uint32_t*) sp->tbuf; + if(sp->tbuflen < npixels) { + TIFFErrorExt(tif->tif_clientdata, module, + "Translation buffer too short"); + return (0); + } + (*sp->tfunc)(sp, bp, npixels); + } + /* write out encoded pixels */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (i = npixels; i--; ) { + if (occ < 3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (0); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = (uint8_t)(*tp >> 16); + *op++ = (uint8_t)(*tp >> 8 & 0xff); + *op++ = (uint8_t)(*tp++ & 0xff); + occ -= 3; + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (1); +} + +/* + * Encode a row of 32-bit pixels. + */ +static int +LogLuvEncode32(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "LogLuvEncode32"; + LogLuvState* sp = EncoderState(tif); + int shft; + tmsize_t i; + tmsize_t j; + tmsize_t npixels; + uint8_t* op; + uint32_t* tp; + uint32_t b; + tmsize_t occ; + int rc=0, mask; + tmsize_t beg; + + (void)s; + assert(s == 0); + assert(sp != NULL); + + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32_t*) bp; + else { + tp = (uint32_t*) sp->tbuf; + if(sp->tbuflen < npixels) { + TIFFErrorExt(tif->tif_clientdata, module, + "Translation buffer too short"); + return (0); + } + (*sp->tfunc)(sp, bp, npixels); + } + /* compress each byte string */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (shft = 24; shft >= 0; shft -=8) { + for (i = 0; i < npixels; i += rc) { + if (occ < 4) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (0); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + mask = 0xff << shft; /* find next run */ + for (beg = i; beg < npixels; beg += rc) { + b = tp[beg] & mask; + rc = 1; + while (rc < 127+2 && beg+rc < npixels && + (tp[beg+rc] & mask) == b) + rc++; + if (rc >= MINRUN) + break; /* long enough */ + } + if (beg-i > 1 && beg-i < MINRUN) { + b = tp[i] & mask; /* check short run */ + j = i+1; + while ((tp[j++] & mask) == b) + if (j == beg) { + *op++ = (uint8_t)(128 - 2 + j - i); + *op++ = (uint8_t)(b >> shft); + occ -= 2; + i = beg; + break; + } + } + while (i < beg) { /* write out non-run */ + if ((j = beg-i) > 127) j = 127; + if (occ < j+3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (0); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = (uint8_t) j; occ--; + while (j--) { + *op++ = (uint8_t)(tp[i++] >> shft & 0xff); + occ--; + } + } + if (rc >= MINRUN) { /* write out run */ + *op++ = (uint8_t) (128 - 2 + rc); + *op++ = (uint8_t)(tp[beg] >> shft & 0xff); + occ -= 2; + } else + rc = 0; + } + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (1); +} + +/* + * Encode a strip of pixels. We break it into rows to + * avoid encoding runs across row boundaries. + */ +static int +LogLuvEncodeStrip(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + tmsize_t rowlen = TIFFScanlineSize(tif); + + if (rowlen == 0) + return 0; + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) { + bp += rowlen; + cc -= rowlen; + } + return (cc == 0); +} + +/* + * Encode a tile of pixels. We break it into rows to + * avoid encoding runs across row boundaries. + */ +static int +LogLuvEncodeTile(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + tmsize_t rowlen = TIFFTileRowSize(tif); + + if (rowlen == 0) + return 0; + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) { + bp += rowlen; + cc -= rowlen; + } + return (cc == 0); +} + +/* + * Encode/Decode functions for converting to and from user formats. + */ + +#include "uvcode.h" + +#ifndef UVSCALE +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#undef log2 /* Conflict with C'99 function */ +#define log2(x) ((1./M_LN2)*log(x)) +#undef exp2 /* Conflict with C'99 function */ +#define exp2(x) exp(M_LN2*(x)) + +static int tiff_itrunc(double x, int m) +{ + if( m == SGILOGENCODE_NODITHER ) + return (int)x; + /* Silence CoverityScan warning about bad crypto function */ + /* coverity[dont_call] */ + return (int)(x + rand()*(1./RAND_MAX) - .5); +} + +#if !LOGLUV_PUBLIC +static +#endif +double +LogL16toY(int p16) /* compute luminance from 16-bit LogL */ +{ + int Le = p16 & 0x7fff; + double Y; + + if (!Le) + return (0.); + Y = exp(M_LN2/256.*(Le+.5) - M_LN2*64.); + return (!(p16 & 0x8000) ? Y : -Y); +} + +#if !LOGLUV_PUBLIC +static +#endif +int +LogL16fromY(double Y, int em) /* get 16-bit LogL from Y */ +{ + if (Y >= 1.8371976e19) + return (0x7fff); + if (Y <= -1.8371976e19) + return (0xffff); + if (Y > 5.4136769e-20) + return tiff_itrunc(256.*(log2(Y) + 64.), em); + if (Y < -5.4136769e-20) + return (~0x7fff | tiff_itrunc(256.*(log2(-Y) + 64.), em)); + return (0); +} + +static void +L16toY(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + int16_t* l16 = (int16_t*) sp->tbuf; + float* yp = (float*) op; + + while (n-- > 0) + *yp++ = (float)LogL16toY(*l16++); +} + +static void +L16toGry(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + int16_t* l16 = (int16_t*) sp->tbuf; + uint8_t* gp = (uint8_t*) op; + + while (n-- > 0) { + double Y = LogL16toY(*l16++); + *gp++ = (uint8_t) ((Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256. * sqrt(Y))); + } +} + +static void +L16fromY(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + int16_t* l16 = (int16_t*) sp->tbuf; + float* yp = (float*) op; + + while (n-- > 0) + *l16++ = (int16_t) (LogL16fromY(*yp++, sp->encode_meth)); +} + +#if !LOGLUV_PUBLIC +static +#endif +void +XYZtoRGB24(float xyz[3], uint8_t rgb[3]) +{ + double r, g, b; + /* assume CCIR-709 primaries */ + r = 2.690*xyz[0] + -1.276*xyz[1] + -0.414*xyz[2]; + g = -1.022*xyz[0] + 1.978*xyz[1] + 0.044*xyz[2]; + b = 0.061*xyz[0] + -0.224*xyz[1] + 1.163*xyz[2]; + /* assume 2.0 gamma for speed */ + /* could use integer sqrt approx., but this is probably faster */ + rgb[0] = (uint8_t)((r <= 0.) ? 0 : (r >= 1.) ? 255 : (int)(256. * sqrt(r))); + rgb[1] = (uint8_t)((g <= 0.) ? 0 : (g >= 1.) ? 255 : (int)(256. * sqrt(g))); + rgb[2] = (uint8_t)((b <= 0.) ? 0 : (b >= 1.) ? 255 : (int)(256. * sqrt(b))); +} + +#if !LOGLUV_PUBLIC +static +#endif +double +LogL10toY(int p10) /* compute luminance from 10-bit LogL */ +{ + if (p10 == 0) + return (0.); + return (exp(M_LN2/64.*(p10+.5) - M_LN2*12.)); +} + +#if !LOGLUV_PUBLIC +static +#endif +int +LogL10fromY(double Y, int em) /* get 10-bit LogL from Y */ +{ + if (Y >= 15.742) + return (0x3ff); + else if (Y <= .00024283) + return (0); + else + return tiff_itrunc(64.*(log2(Y) + 12.), em); +} + +#define NANGLES 100 +#define uv2ang(u, v) ( (NANGLES*.499999999/M_PI) \ + * atan2((v)-V_NEU,(u)-U_NEU) + .5*NANGLES ) + +static int +oog_encode(double u, double v) /* encode out-of-gamut chroma */ +{ + static int oog_table[NANGLES]; + static int initialized = 0; + register int i; + + if (!initialized) { /* set up perimeter table */ + double eps[NANGLES], ua, va, ang, epsa; + int ui, vi, ustep; + for (i = NANGLES; i--; ) + eps[i] = 2.; + for (vi = UV_NVS; vi--; ) { + va = UV_VSTART + (vi+.5)*UV_SQSIZ; + ustep = uv_row[vi].nus-1; + if (vi == UV_NVS-1 || vi == 0 || ustep <= 0) + ustep = 1; + for (ui = uv_row[vi].nus-1; ui >= 0; ui -= ustep) { + ua = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ; + ang = uv2ang(ua, va); + i = (int) ang; + epsa = fabs(ang - (i+.5)); + if (epsa < eps[i]) { + oog_table[i] = uv_row[vi].ncum + ui; + eps[i] = epsa; + } + } + } + for (i = NANGLES; i--; ) /* fill any holes */ + if (eps[i] > 1.5) { + int i1, i2; + for (i1 = 1; i1 < NANGLES/2; i1++) + if (eps[(i+i1)%NANGLES] < 1.5) + break; + for (i2 = 1; i2 < NANGLES/2; i2++) + if (eps[(i+NANGLES-i2)%NANGLES] < 1.5) + break; + if (i1 < i2) + oog_table[i] = + oog_table[(i+i1)%NANGLES]; + else + oog_table[i] = + oog_table[(i+NANGLES-i2)%NANGLES]; + } + initialized = 1; + } + i = (int) uv2ang(u, v); /* look up hue angle */ + return (oog_table[i]); +} + +#undef uv2ang +#undef NANGLES + +#if !LOGLUV_PUBLIC +static +#endif +int +uv_encode(double u, double v, int em) /* encode (u',v') coordinates */ +{ + register int vi, ui; + + if (v < UV_VSTART) + return oog_encode(u, v); + vi = tiff_itrunc((v - UV_VSTART)*(1./UV_SQSIZ), em); + if (vi >= UV_NVS) + return oog_encode(u, v); + if (u < uv_row[vi].ustart) + return oog_encode(u, v); + ui = tiff_itrunc((u - uv_row[vi].ustart)*(1./UV_SQSIZ), em); + if (ui >= uv_row[vi].nus) + return oog_encode(u, v); + + return (uv_row[vi].ncum + ui); +} + +#if !LOGLUV_PUBLIC +static +#endif +int +uv_decode(double *up, double *vp, int c) /* decode (u',v') index */ +{ + int upper, lower; + register int ui, vi; + + if (c < 0 || c >= UV_NDIVS) + return (-1); + lower = 0; /* binary search */ + upper = UV_NVS; + while (upper - lower > 1) { + vi = (lower + upper) >> 1; + ui = c - uv_row[vi].ncum; + if (ui > 0) + lower = vi; + else if (ui < 0) + upper = vi; + else { + lower = vi; + break; + } + } + vi = lower; + ui = c - uv_row[vi].ncum; + *up = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ; + *vp = UV_VSTART + (vi+.5)*UV_SQSIZ; + return (0); +} + +#if !LOGLUV_PUBLIC +static +#endif +void +LogLuv24toXYZ(uint32_t p, float XYZ[3]) +{ + int Ce; + double L, u, v, s, x, y; + /* decode luminance */ + L = LogL10toY(p>>14 & 0x3ff); + if (L <= 0.) { + XYZ[0] = XYZ[1] = XYZ[2] = 0.; + return; + } + /* decode color */ + Ce = p & 0x3fff; + if (uv_decode(&u, &v, Ce) < 0) { + u = U_NEU; v = V_NEU; + } + s = 1./(6.*u - 16.*v + 12.); + x = 9.*u * s; + y = 4.*v * s; + /* convert to XYZ */ + XYZ[0] = (float)(x/y * L); + XYZ[1] = (float)L; + XYZ[2] = (float)((1.-x-y)/y * L); +} + +#if !LOGLUV_PUBLIC +static +#endif +uint32_t +LogLuv24fromXYZ(float XYZ[3], int em) +{ + int Le, Ce; + double u, v, s; + /* encode luminance */ + Le = LogL10fromY(XYZ[1], em); + /* encode color */ + s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2]; + if (!Le || s <= 0.) { + u = U_NEU; + v = V_NEU; + } else { + u = 4.*XYZ[0] / s; + v = 9.*XYZ[1] / s; + } + Ce = uv_encode(u, v, em); + if (Ce < 0) /* never happens */ + Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER); + /* combine encodings */ + return (Le << 14 | Ce); +} + +static void +Luv24toXYZ(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + uint32_t* luv = (uint32_t*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + LogLuv24toXYZ(*luv, xyz); + xyz += 3; + luv++; + } +} + +static void +Luv24toLuv48(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + uint32_t* luv = (uint32_t*) sp->tbuf; + int16_t* luv3 = (int16_t*) op; + + while (n-- > 0) { + double u, v; + + *luv3++ = (int16_t)((*luv >> 12 & 0xffd) + 13314); + if (uv_decode(&u, &v, *luv&0x3fff) < 0) { + u = U_NEU; + v = V_NEU; + } + *luv3++ = (int16_t)(u * (1L << 15)); + *luv3++ = (int16_t)(v * (1L << 15)); + luv++; + } +} + +static void +Luv24toRGB(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + uint32_t* luv = (uint32_t*) sp->tbuf; + uint8_t* rgb = (uint8_t*) op; + + while (n-- > 0) { + float xyz[3]; + + LogLuv24toXYZ(*luv++, xyz); + XYZtoRGB24(xyz, rgb); + rgb += 3; + } +} + +static void +Luv24fromXYZ(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + uint32_t* luv = (uint32_t*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + *luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth); + xyz += 3; + } +} + +static void +Luv24fromLuv48(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + uint32_t* luv = (uint32_t*) sp->tbuf; + int16_t* luv3 = (int16_t*) op; + + while (n-- > 0) { + int Le, Ce; + + if (luv3[0] <= 0) + Le = 0; + else if (luv3[0] >= (1<<12)+3314) + Le = (1<<10) - 1; + else if (sp->encode_meth == SGILOGENCODE_NODITHER) + Le = (luv3[0]-3314) >> 2; + else + Le = tiff_itrunc(.25*(luv3[0]-3314.), sp->encode_meth); + + Ce = uv_encode((luv3[1]+.5)/(1<<15), (luv3[2]+.5)/(1<<15), + sp->encode_meth); + if (Ce < 0) /* never happens */ + Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER); + *luv++ = (uint32_t)Le << 14 | Ce; + luv3 += 3; + } +} + +#if !LOGLUV_PUBLIC +static +#endif +void +LogLuv32toXYZ(uint32_t p, float XYZ[3]) +{ + double L, u, v, s, x, y; + /* decode luminance */ + L = LogL16toY((int)p >> 16); + if (L <= 0.) { + XYZ[0] = XYZ[1] = XYZ[2] = 0.; + return; + } + /* decode color */ + u = 1./UVSCALE * ((p>>8 & 0xff) + .5); + v = 1./UVSCALE * ((p & 0xff) + .5); + s = 1./(6.*u - 16.*v + 12.); + x = 9.*u * s; + y = 4.*v * s; + /* convert to XYZ */ + XYZ[0] = (float)(x/y * L); + XYZ[1] = (float)L; + XYZ[2] = (float)((1.-x-y)/y * L); +} + +#if !LOGLUV_PUBLIC +static +#endif +uint32_t +LogLuv32fromXYZ(float XYZ[3], int em) +{ + unsigned int Le, ue, ve; + double u, v, s; + /* encode luminance */ + Le = (unsigned int)LogL16fromY(XYZ[1], em); + /* encode color */ + s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2]; + if (!Le || s <= 0.) { + u = U_NEU; + v = V_NEU; + } else { + u = 4.*XYZ[0] / s; + v = 9.*XYZ[1] / s; + } + if (u <= 0.) ue = 0; + else ue = tiff_itrunc(UVSCALE*u, em); + if (ue > 255) ue = 255; + if (v <= 0.) ve = 0; + else ve = tiff_itrunc(UVSCALE*v, em); + if (ve > 255) ve = 255; + /* combine encodings */ + return (Le << 16 | ue << 8 | ve); +} + +static void +Luv32toXYZ(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + uint32_t* luv = (uint32_t*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + LogLuv32toXYZ(*luv++, xyz); + xyz += 3; + } +} + +static void +Luv32toLuv48(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + uint32_t* luv = (uint32_t*) sp->tbuf; + int16_t* luv3 = (int16_t*) op; + + while (n-- > 0) { + double u, v; + + *luv3++ = (int16_t)(*luv >> 16); + u = 1./UVSCALE * ((*luv>>8 & 0xff) + .5); + v = 1./UVSCALE * ((*luv & 0xff) + .5); + *luv3++ = (int16_t)(u * (1L << 15)); + *luv3++ = (int16_t)(v * (1L << 15)); + luv++; + } +} + +static void +Luv32toRGB(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + uint32_t* luv = (uint32_t*) sp->tbuf; + uint8_t* rgb = (uint8_t*) op; + + while (n-- > 0) { + float xyz[3]; + + LogLuv32toXYZ(*luv++, xyz); + XYZtoRGB24(xyz, rgb); + rgb += 3; + } +} + +static void +Luv32fromXYZ(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + uint32_t* luv = (uint32_t*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + *luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth); + xyz += 3; + } +} + +static void +Luv32fromLuv48(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + uint32_t* luv = (uint32_t*) sp->tbuf; + int16_t* luv3 = (int16_t*) op; + + if (sp->encode_meth == SGILOGENCODE_NODITHER) { + while (n-- > 0) { + *luv++ = (uint32_t)luv3[0] << 16 | + (luv3[1]*(uint32_t)(UVSCALE + .5) >> 7 & 0xff00) | + (luv3[2]*(uint32_t)(UVSCALE + .5) >> 15 & 0xff); + luv3 += 3; + } + return; + } + while (n-- > 0) { + *luv++ = (uint32_t)luv3[0] << 16 | + (tiff_itrunc(luv3[1]*(UVSCALE/(1<<15)), sp->encode_meth) << 8 & 0xff00) | + (tiff_itrunc(luv3[2]*(UVSCALE/(1<<15)), sp->encode_meth) & 0xff); + luv3 += 3; + } +} + +static void +_logLuvNop(LogLuvState* sp, uint8_t* op, tmsize_t n) +{ + (void) sp; (void) op; (void) n; +} + +static int +LogL16GuessDataFmt(TIFFDirectory *td) +{ +#define PACK(s,b,f) (((b)<<6)|((s)<<3)|(f)) + switch (PACK(td->td_samplesperpixel, td->td_bitspersample, td->td_sampleformat)) { + case PACK(1, 32, SAMPLEFORMAT_IEEEFP): + return (SGILOGDATAFMT_FLOAT); + case PACK(1, 16, SAMPLEFORMAT_VOID): + case PACK(1, 16, SAMPLEFORMAT_INT): + case PACK(1, 16, SAMPLEFORMAT_UINT): + return (SGILOGDATAFMT_16BIT); + case PACK(1, 8, SAMPLEFORMAT_VOID): + case PACK(1, 8, SAMPLEFORMAT_UINT): + return (SGILOGDATAFMT_8BIT); + } +#undef PACK + return (SGILOGDATAFMT_UNKNOWN); +} + +static tmsize_t +multiply_ms(tmsize_t m1, tmsize_t m2) +{ + return _TIFFMultiplySSize(NULL, m1, m2, NULL); +} + +static int +LogL16InitState(TIFF* tif) +{ + static const char module[] = "LogL16InitState"; + TIFFDirectory *td = &tif->tif_dir; + LogLuvState* sp = DecoderState(tif); + + assert(sp != NULL); + assert(td->td_photometric == PHOTOMETRIC_LOGL); + + if( td->td_samplesperpixel != 1 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Sorry, can not handle LogL image with %s=%"PRIu16, + "Samples/pixel", td->td_samplesperpixel); + return 0; + } + + /* for some reason, we can't do this in TIFFInitLogL16 */ + if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN) + sp->user_datafmt = LogL16GuessDataFmt(td); + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->pixel_size = sizeof (float); + break; + case SGILOGDATAFMT_16BIT: + sp->pixel_size = sizeof (int16_t); + break; + case SGILOGDATAFMT_8BIT: + sp->pixel_size = sizeof (uint8_t); + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "No support for converting user data format to LogL"); + return (0); + } + if( isTiled(tif) ) + sp->tbuflen = multiply_ms(td->td_tilewidth, td->td_tilelength); + else if( td->td_rowsperstrip < td->td_imagelength ) + sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_rowsperstrip); + else + sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_imagelength); + if (multiply_ms(sp->tbuflen, sizeof (int16_t)) == 0 || + (sp->tbuf = (uint8_t*) _TIFFmalloc(sp->tbuflen * sizeof (int16_t))) == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, "No space for SGILog translation buffer"); + return (0); + } + return (1); +} + +static int +LogLuvGuessDataFmt(TIFFDirectory *td) +{ + int guess; + + /* + * If the user didn't tell us their datafmt, + * take our best guess from the bitspersample. + */ +#define PACK(a,b) (((a)<<3)|(b)) + switch (PACK(td->td_bitspersample, td->td_sampleformat)) { + case PACK(32, SAMPLEFORMAT_IEEEFP): + guess = SGILOGDATAFMT_FLOAT; + break; + case PACK(32, SAMPLEFORMAT_VOID): + case PACK(32, SAMPLEFORMAT_UINT): + case PACK(32, SAMPLEFORMAT_INT): + guess = SGILOGDATAFMT_RAW; + break; + case PACK(16, SAMPLEFORMAT_VOID): + case PACK(16, SAMPLEFORMAT_INT): + case PACK(16, SAMPLEFORMAT_UINT): + guess = SGILOGDATAFMT_16BIT; + break; + case PACK( 8, SAMPLEFORMAT_VOID): + case PACK( 8, SAMPLEFORMAT_UINT): + guess = SGILOGDATAFMT_8BIT; + break; + default: + guess = SGILOGDATAFMT_UNKNOWN; + break; +#undef PACK + } + /* + * Double-check samples per pixel. + */ + switch (td->td_samplesperpixel) { + case 1: + if (guess != SGILOGDATAFMT_RAW) + guess = SGILOGDATAFMT_UNKNOWN; + break; + case 3: + if (guess == SGILOGDATAFMT_RAW) + guess = SGILOGDATAFMT_UNKNOWN; + break; + default: + guess = SGILOGDATAFMT_UNKNOWN; + break; + } + return (guess); +} + +static int +LogLuvInitState(TIFF* tif) +{ + static const char module[] = "LogLuvInitState"; + TIFFDirectory* td = &tif->tif_dir; + LogLuvState* sp = DecoderState(tif); + + assert(sp != NULL); + assert(td->td_photometric == PHOTOMETRIC_LOGLUV); + + /* for some reason, we can't do this in TIFFInitLogLuv */ + if (td->td_planarconfig != PLANARCONFIG_CONTIG) { + TIFFErrorExt(tif->tif_clientdata, module, + "SGILog compression cannot handle non-contiguous data"); + return (0); + } + if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN) + sp->user_datafmt = LogLuvGuessDataFmt(td); + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->pixel_size = 3*sizeof (float); + break; + case SGILOGDATAFMT_16BIT: + sp->pixel_size = 3*sizeof (int16_t); + break; + case SGILOGDATAFMT_RAW: + sp->pixel_size = sizeof (uint32_t); + break; + case SGILOGDATAFMT_8BIT: + sp->pixel_size = 3*sizeof (uint8_t); + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "No support for converting user data format to LogLuv"); + return (0); + } + if( isTiled(tif) ) + sp->tbuflen = multiply_ms(td->td_tilewidth, td->td_tilelength); + else if( td->td_rowsperstrip < td->td_imagelength ) + sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_rowsperstrip); + else + sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_imagelength); + if (multiply_ms(sp->tbuflen, sizeof (uint32_t)) == 0 || + (sp->tbuf = (uint8_t*) _TIFFmalloc(sp->tbuflen * sizeof (uint32_t))) == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, "No space for SGILog translation buffer"); + return (0); + } + return (1); +} + +static int +LogLuvFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +static int +LogLuvSetupDecode(TIFF* tif) +{ + static const char module[] = "LogLuvSetupDecode"; + LogLuvState* sp = DecoderState(tif); + TIFFDirectory* td = &tif->tif_dir; + + tif->tif_postdecode = _TIFFNoPostDecode; + switch (td->td_photometric) { + case PHOTOMETRIC_LOGLUV: + if (!LogLuvInitState(tif)) + break; + if (td->td_compression == COMPRESSION_SGILOG24) { + tif->tif_decoderow = LogLuvDecode24; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv24toXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv24toLuv48; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = Luv24toRGB; + break; + } + } else { + tif->tif_decoderow = LogLuvDecode32; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv32toXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv32toLuv48; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = Luv32toRGB; + break; + } + } + return (1); + case PHOTOMETRIC_LOGL: + if (!LogL16InitState(tif)) + break; + tif->tif_decoderow = LogL16Decode; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = L16toY; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = L16toGry; + break; + } + return (1); + default: + TIFFErrorExt(tif->tif_clientdata, module, + "Inappropriate photometric interpretation %"PRIu16" for SGILog compression; %s", + td->td_photometric, "must be either LogLUV or LogL"); + break; + } + return (0); +} + +static int +LogLuvSetupEncode(TIFF* tif) +{ + static const char module[] = "LogLuvSetupEncode"; + LogLuvState* sp = EncoderState(tif); + TIFFDirectory* td = &tif->tif_dir; + + switch (td->td_photometric) { + case PHOTOMETRIC_LOGLUV: + if (!LogLuvInitState(tif)) + return (0); + if (td->td_compression == COMPRESSION_SGILOG24) { + tif->tif_encoderow = LogLuvEncode24; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv24fromXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv24fromLuv48; + break; + case SGILOGDATAFMT_RAW: + break; + default: + goto notsupported; + } + } else { + tif->tif_encoderow = LogLuvEncode32; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv32fromXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv32fromLuv48; + break; + case SGILOGDATAFMT_RAW: + break; + default: + goto notsupported; + } + } + break; + case PHOTOMETRIC_LOGL: + if (!LogL16InitState(tif)) + return (0); + tif->tif_encoderow = LogL16Encode; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = L16fromY; + break; + case SGILOGDATAFMT_16BIT: + break; + default: + goto notsupported; + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "Inappropriate photometric interpretation %"PRIu16" for SGILog compression; %s", + td->td_photometric, "must be either LogLUV or LogL"); + return (0); + } + sp->encoder_state = 1; + return (1); +notsupported: + TIFFErrorExt(tif->tif_clientdata, module, + "SGILog compression supported only for %s, or raw data", + td->td_photometric == PHOTOMETRIC_LOGL ? "Y, L" : "XYZ, Luv"); + return (0); +} + +static void +LogLuvClose(TIFF* tif) +{ + LogLuvState* sp = (LogLuvState*) tif->tif_data; + TIFFDirectory *td = &tif->tif_dir; + + assert(sp != 0); + /* + * For consistency, we always want to write out the same + * bitspersample and sampleformat for our TIFF file, + * regardless of the data format being used by the application. + * Since this routine is called after tags have been set but + * before they have been recorded in the file, we reset them here. + * Note: this is really a nasty approach. See PixarLogClose + */ + if( sp->encoder_state ) + { + /* See PixarLogClose. Might avoid issues with tags whose size depends + * on those below, but not completely sure this is enough. */ + td->td_samplesperpixel = + (td->td_photometric == PHOTOMETRIC_LOGL) ? 1 : 3; + td->td_bitspersample = 16; + td->td_sampleformat = SAMPLEFORMAT_INT; + } +} + +static void +LogLuvCleanup(TIFF* tif) +{ + LogLuvState* sp = (LogLuvState *)tif->tif_data; + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->tbuf) + _TIFFfree(sp->tbuf); + _TIFFfree(sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int +LogLuvVSetField(TIFF* tif, uint32_t tag, va_list ap) +{ + static const char module[] = "LogLuvVSetField"; + LogLuvState* sp = DecoderState(tif); + int bps, fmt; + + switch (tag) { + case TIFFTAG_SGILOGDATAFMT: + sp->user_datafmt = (int) va_arg(ap, int); + /* + * Tweak the TIFF header so that the rest of libtiff knows what + * size of data will be passed between app and library, and + * assume that the app knows what it is doing and is not + * confused by these header manipulations... + */ + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + bps = 32; + fmt = SAMPLEFORMAT_IEEEFP; + break; + case SGILOGDATAFMT_16BIT: + bps = 16; + fmt = SAMPLEFORMAT_INT; + break; + case SGILOGDATAFMT_RAW: + bps = 32; + fmt = SAMPLEFORMAT_UINT; + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + break; + case SGILOGDATAFMT_8BIT: + bps = 8; + fmt = SAMPLEFORMAT_UINT; + break; + default: + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "Unknown data format %d for LogLuv compression", + sp->user_datafmt); + return (0); + } + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, fmt); + /* + * Must recalculate sizes should bits/sample change. + */ + tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t) -1; + tif->tif_scanlinesize = TIFFScanlineSize(tif); + return (1); + case TIFFTAG_SGILOGENCODE: + sp->encode_meth = (int) va_arg(ap, int); + if (sp->encode_meth != SGILOGENCODE_NODITHER && + sp->encode_meth != SGILOGENCODE_RANDITHER) { + TIFFErrorExt(tif->tif_clientdata, module, + "Unknown encoding %d for LogLuv compression", + sp->encode_meth); + return (0); + } + return (1); + default: + return (*sp->vsetparent)(tif, tag, ap); + } +} + +static int +LogLuvVGetField(TIFF* tif, uint32_t tag, va_list ap) +{ + LogLuvState *sp = (LogLuvState *)tif->tif_data; + + switch (tag) { + case TIFFTAG_SGILOGDATAFMT: + *va_arg(ap, int*) = sp->user_datafmt; + return (1); + default: + return (*sp->vgetparent)(tif, tag, ap); + } +} + +static const TIFFField LogLuvFields[] = { + { TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogDataFmt", NULL}, + { TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogEncode", NULL} +}; + +int +TIFFInitSGILog(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitSGILog"; + LogLuvState* sp; + + assert(scheme == COMPRESSION_SGILOG24 || scheme == COMPRESSION_SGILOG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, LogLuvFields, + TIFFArrayCount(LogLuvFields))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging SGILog codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t*) _TIFFmalloc(sizeof (LogLuvState)); + if (tif->tif_data == NULL) + goto bad; + sp = (LogLuvState*) tif->tif_data; + _TIFFmemset((void*)sp, 0, sizeof (*sp)); + sp->user_datafmt = SGILOGDATAFMT_UNKNOWN; + sp->encode_meth = (scheme == COMPRESSION_SGILOG24) ? + SGILOGENCODE_RANDITHER : SGILOGENCODE_NODITHER; + sp->tfunc = _logLuvNop; + + /* + * Install codec methods. + * NB: tif_decoderow & tif_encoderow are filled + * in at setup time. + */ + tif->tif_fixuptags = LogLuvFixupTags; + tif->tif_setupdecode = LogLuvSetupDecode; + tif->tif_decodestrip = LogLuvDecodeStrip; + tif->tif_decodetile = LogLuvDecodeTile; + tif->tif_setupencode = LogLuvSetupEncode; + tif->tif_encodestrip = LogLuvEncodeStrip; + tif->tif_encodetile = LogLuvEncodeTile; + tif->tif_close = LogLuvClose; + tif->tif_cleanup = LogLuvCleanup; + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = LogLuvVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = LogLuvVSetField; /* hook for codec tags */ + + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "%s: No space for LogLuv state block", tif->tif_name); + return (0); +} +#endif /* LOGLUV_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_lzw.c b/libs/tiff/libtiff/tif_lzw.c new file mode 100644 index 00000000000..c06aec408fa --- /dev/null +++ b/libs/tiff/libtiff/tif_lzw.c @@ -0,0 +1,1218 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef LZW_SUPPORT +/* + * TIFF Library. + * Rev 5.0 Lempel-Ziv & Welch Compression Support + * + * This code is derived from the compress program whose code is + * derived from software contributed to Berkeley by James A. Woods, + * derived from original work by Spencer Thomas and Joseph Orost. + * + * The original Berkeley copyright notice appears below in its entirety. + */ +#include "tif_predict.h" + +#include + +/* + * NB: The 5.0 spec describes a different algorithm than Aldus + * implements. Specifically, Aldus does code length transitions + * one code earlier than should be done (for real LZW). + * Earlier versions of this library implemented the correct + * LZW algorithm, but emitted codes in a bit order opposite + * to the TIFF spec. Thus, to maintain compatibility w/ Aldus + * we interpret MSB-LSB ordered codes to be images written w/ + * old versions of this library, but otherwise adhere to the + * Aldus "off by one" algorithm. + * + * Future revisions to the TIFF spec are expected to "clarify this issue". + */ +#define LZW_COMPAT /* include backwards compatibility code */ +/* + * Each strip of data is supposed to be terminated by a CODE_EOI. + * If the following #define is included, the decoder will also + * check for end-of-strip w/o seeing this code. This makes the + * library more robust, but also slower. + */ +#define LZW_CHECKEOS /* include checks for strips w/o EOI code */ + +#define MAXCODE(n) ((1L<<(n))-1) +/* + * The TIFF spec specifies that encoded bit + * strings range from 9 to 12 bits. + */ +#define BITS_MIN 9 /* start with 9 bits */ +#define BITS_MAX 12 /* max of 12 bit strings */ +/* predefined codes */ +#define CODE_CLEAR 256 /* code to clear string table */ +#define CODE_EOI 257 /* end-of-information code */ +#define CODE_FIRST 258 /* first free code entry */ +#define CODE_MAX MAXCODE(BITS_MAX) +#define HSIZE 9001L /* 91% occupancy */ +#define HSHIFT (13-8) +#ifdef LZW_COMPAT +/* NB: +1024 is for compatibility with old files */ +#define CSIZE (MAXCODE(BITS_MAX)+1024L) +#else +#define CSIZE (MAXCODE(BITS_MAX)+1L) +#endif + +/* + * State block for each open TIFF file using LZW + * compression/decompression. Note that the predictor + * state block must be first in this data structure. + */ +typedef struct { + TIFFPredictorState predict; /* predictor super class */ + + unsigned short nbits; /* # of bits/code */ + unsigned short maxcode; /* maximum code for lzw_nbits */ + unsigned short free_ent; /* next free entry in hash table */ + unsigned long nextdata; /* next bits of i/o */ + long nextbits; /* # of valid bits in lzw_nextdata */ + + int rw_mode; /* preserve rw_mode from init */ +} LZWBaseState; + +#define lzw_nbits base.nbits +#define lzw_maxcode base.maxcode +#define lzw_free_ent base.free_ent +#define lzw_nextdata base.nextdata +#define lzw_nextbits base.nextbits + +/* + * Encoding-specific state. + */ +typedef uint16_t hcode_t; /* codes fit in 16 bits */ +typedef struct { + long hash; + hcode_t code; +} hash_t; + +/* + * Decoding-specific state. + */ +typedef struct code_ent { + struct code_ent *next; + unsigned short length; /* string len, including this token */ + unsigned char value; /* data value */ + unsigned char firstchar; /* first token of string */ +} code_t; + +typedef int (*decodeFunc)(TIFF*, uint8_t*, tmsize_t, uint16_t); + +typedef struct { + LZWBaseState base; + + /* Decoding specific data */ + long dec_nbitsmask; /* lzw_nbits 1 bits, right adjusted */ + long dec_restart; /* restart count */ +#ifdef LZW_CHECKEOS + uint64_t dec_bitsleft; /* available bits in raw data */ + tmsize_t old_tif_rawcc; /* value of tif_rawcc at the end of the previous TIFLZWDecode() call */ +#endif + decodeFunc dec_decode; /* regular or backwards compatible */ + code_t* dec_codep; /* current recognized code */ + code_t* dec_oldcodep; /* previously recognized code */ + code_t* dec_free_entp; /* next free entry */ + code_t* dec_maxcodep; /* max available entry */ + code_t* dec_codetab; /* kept separate for small machines */ + + /* Encoding specific data */ + int enc_oldcode; /* last code encountered */ + long enc_checkpoint; /* point at which to clear table */ +#define CHECK_GAP 10000 /* enc_ratio check interval */ + long enc_ratio; /* current compression ratio */ + long enc_incount; /* (input) data bytes encoded */ + long enc_outcount; /* encoded (output) bytes */ + uint8_t* enc_rawlimit; /* bound on tif_rawdata buffer */ + hash_t* enc_hashtab; /* kept separate for small machines */ +} LZWCodecState; + +#define LZWState(tif) ((LZWBaseState*) (tif)->tif_data) +#define DecoderState(tif) ((LZWCodecState*) LZWState(tif)) +#define EncoderState(tif) ((LZWCodecState*) LZWState(tif)) + +static int LZWDecode(TIFF* tif, uint8_t* op0, tmsize_t occ0, uint16_t s); +#ifdef LZW_COMPAT +static int LZWDecodeCompat(TIFF* tif, uint8_t* op0, tmsize_t occ0, uint16_t s); +#endif +static void cl_hash(LZWCodecState*); + +/* + * LZW Decoder. + */ + +#ifdef LZW_CHECKEOS +/* + * This check shouldn't be necessary because each + * strip is suppose to be terminated with CODE_EOI. + */ +#define NextCode(_tif, _sp, _bp, _code, _get) { \ + if ((_sp)->dec_bitsleft < (uint64_t)nbits) { \ + TIFFWarningExt(_tif->tif_clientdata, module, \ + "LZWDecode: Strip %"PRIu32" not terminated with EOI code", \ + _tif->tif_curstrip); \ + _code = CODE_EOI; \ + } else { \ + _get(_sp,_bp,_code); \ + (_sp)->dec_bitsleft -= nbits; \ + } \ +} +#else +#define NextCode(tif, sp, bp, code, get) get(sp, bp, code) +#endif + +static int +LZWFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +static int +LZWSetupDecode(TIFF* tif) +{ + static const char module[] = "LZWSetupDecode"; + LZWCodecState* sp = DecoderState(tif); + int code; + + if( sp == NULL ) + { + /* + * Allocate state block so tag methods have storage to record + * values. + */ + tif->tif_data = (uint8_t*) _TIFFmalloc(sizeof(LZWCodecState)); + if (tif->tif_data == NULL) + { + TIFFErrorExt(tif->tif_clientdata, module, "No space for LZW state block"); + return (0); + } + + sp = DecoderState(tif); + sp->dec_codetab = NULL; + sp->dec_decode = NULL; + + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + } + + if (sp->dec_codetab == NULL) { + sp->dec_codetab = (code_t*)_TIFFmalloc(CSIZE*sizeof (code_t)); + if (sp->dec_codetab == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for LZW code table"); + return (0); + } + /* + * Pre-load the table. + */ + code = 255; + do { + sp->dec_codetab[code].value = (unsigned char)code; + sp->dec_codetab[code].firstchar = (unsigned char)code; + sp->dec_codetab[code].length = 1; + sp->dec_codetab[code].next = NULL; + } while (code--); + /* + * Zero-out the unused entries + */ + /* Silence false positive */ + /* coverity[overrun-buffer-arg] */ + _TIFFmemset(&sp->dec_codetab[CODE_CLEAR], 0, + (CODE_FIRST - CODE_CLEAR) * sizeof (code_t)); + } + return (1); +} + +/* + * Setup state for decoding a strip. + */ +static int +LZWPreDecode(TIFF* tif, uint16_t s) +{ + static const char module[] = "LZWPreDecode"; + LZWCodecState *sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + if( sp->dec_codetab == NULL ) + { + tif->tif_setupdecode( tif ); + if( sp->dec_codetab == NULL ) + return (0); + } + + /* + * Check for old bit-reversed codes. + */ + if (tif->tif_rawcc >= 2 && + tif->tif_rawdata[0] == 0 && (tif->tif_rawdata[1] & 0x1)) { +#ifdef LZW_COMPAT + if (!sp->dec_decode) { + TIFFWarningExt(tif->tif_clientdata, module, + "Old-style LZW codes, convert file"); + /* + * Override default decoding methods with + * ones that deal with the old coding. + * Otherwise the predictor versions set + * above will call the compatibility routines + * through the dec_decode method. + */ + tif->tif_decoderow = LZWDecodeCompat; + tif->tif_decodestrip = LZWDecodeCompat; + tif->tif_decodetile = LZWDecodeCompat; + /* + * If doing horizontal differencing, must + * re-setup the predictor logic since we + * switched the basic decoder methods... + */ + (*tif->tif_setupdecode)(tif); + sp->dec_decode = LZWDecodeCompat; + } + sp->lzw_maxcode = MAXCODE(BITS_MIN); +#else /* !LZW_COMPAT */ + if (!sp->dec_decode) { + TIFFErrorExt(tif->tif_clientdata, module, + "Old-style LZW codes not supported"); + sp->dec_decode = LZWDecode; + } + return (0); +#endif/* !LZW_COMPAT */ + } else { + sp->lzw_maxcode = MAXCODE(BITS_MIN)-1; + sp->dec_decode = LZWDecode; + } + sp->lzw_nbits = BITS_MIN; + sp->lzw_nextbits = 0; + sp->lzw_nextdata = 0; + + sp->dec_restart = 0; + sp->dec_nbitsmask = MAXCODE(BITS_MIN); +#ifdef LZW_CHECKEOS + sp->dec_bitsleft = 0; + sp->old_tif_rawcc = 0; +#endif + sp->dec_free_entp = sp->dec_codetab + CODE_FIRST; + /* + * Zero entries that are not yet filled in. We do + * this to guard against bogus input data that causes + * us to index into undefined entries. If you can + * come up with a way to safely bounds-check input codes + * while decoding then you can remove this operation. + */ + _TIFFmemset(sp->dec_free_entp, 0, (CSIZE-CODE_FIRST)*sizeof (code_t)); + sp->dec_oldcodep = &sp->dec_codetab[-1]; + sp->dec_maxcodep = &sp->dec_codetab[sp->dec_nbitsmask-1]; + return (1); +} + +/* + * Decode a "hunk of data". + */ +#define GetNextCode(sp, bp, code) { \ + nextdata = (nextdata<<8) | *(bp)++; \ + nextbits += 8; \ + if (nextbits < nbits) { \ + nextdata = (nextdata<<8) | *(bp)++; \ + nextbits += 8; \ + } \ + code = (hcode_t)((nextdata >> (nextbits-nbits)) & nbitsmask); \ + nextbits -= nbits; \ +} + +static void +codeLoop(TIFF* tif, const char* module) +{ + TIFFErrorExt(tif->tif_clientdata, module, + "Bogus encoding, loop in the code table; scanline %"PRIu32, + tif->tif_row); +} + +static int +LZWDecode(TIFF* tif, uint8_t* op0, tmsize_t occ0, uint16_t s) +{ + static const char module[] = "LZWDecode"; + LZWCodecState *sp = DecoderState(tif); + char *op = (char*) op0; + long occ = (long) occ0; + char *tp; + unsigned char *bp; + hcode_t code; + int len; + long nbits, nextbits, nbitsmask; + unsigned long nextdata; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + (void) s; + assert(sp != NULL); + assert(sp->dec_codetab != NULL); + + /* + Fail if value does not fit in long. + */ + if ((tmsize_t) occ != occ0) + return (0); + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) { + long residue; + + codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { + /* + * Residue from previous decode is sufficient + * to satisfy decode request. Skip to the + * start of the decoded string, place decoded + * values in the output buffer, and return. + */ + sp->dec_restart += occ; + do { + codep = codep->next; + } while (--residue > occ && codep); + if (codep) { + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); + } + return (1); + } + /* + * Residue satisfies only part of the decode request. + */ + op += residue; + occ -= residue; + tp = op; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = (char)t; + } while (--residue && codep); + sp->dec_restart = 0; + } + + bp = (unsigned char *)tif->tif_rawcp; +#ifdef LZW_CHECKEOS + sp->dec_bitsleft += (((uint64_t)tif->tif_rawcc - sp->old_tif_rawcc) << 3); +#endif + nbits = sp->lzw_nbits; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + nbitsmask = sp->dec_nbitsmask; + oldcodep = sp->dec_oldcodep; + free_entp = sp->dec_free_entp; + maxcodep = sp->dec_maxcodep; + + while (occ > 0) { + NextCode(tif, sp, bp, code, GetNextCode); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + do { + free_entp = sp->dec_codetab + CODE_FIRST; + _TIFFmemset(free_entp, 0, + (CSIZE - CODE_FIRST) * sizeof (code_t)); + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask-1; + NextCode(tif, sp, bp, code, GetNextCode); + } while (code == CODE_CLEAR); /* consecutive CODE_CLEAR codes */ + if (code == CODE_EOI) + break; + if (code > CODE_CLEAR) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Corrupted LZW table at scanline %"PRIu32, + tif->tif_row); + return (0); + } + *op++ = (char)code; + occ--; + oldcodep = sp->dec_codetab + code; + continue; + } + codep = sp->dec_codetab + code; + + /* + * Add the new entry to the code table. + */ + if (free_entp < &sp->dec_codetab[0] || + free_entp >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, module, + "Corrupted LZW table at scanline %"PRIu32, + tif->tif_row); + return (0); + } + + free_entp->next = oldcodep; + if (free_entp->next < &sp->dec_codetab[0] || + free_entp->next >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, module, + "Corrupted LZW table at scanline %"PRIu32, + tif->tif_row); + return (0); + } + free_entp->firstchar = free_entp->next->firstchar; + free_entp->length = free_entp->next->length+1; + free_entp->value = (codep < free_entp) ? + codep->firstchar : free_entp->firstchar; + if (++free_entp > maxcodep) { + if (++nbits > BITS_MAX) /* should not happen */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = sp->dec_codetab + nbitsmask-1; + } + oldcodep = codep; + if (code >= 256) { + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + if(codep->length == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Wrong length of decoded string: " + "data probably corrupted at scanline %"PRIu32, + tif->tif_row); + return (0); + } + if (codep->length > occ) { + /* + * String is too long for decode buffer, + * locate portion that will fit, copy to + * the decode buffer, and setup restart + * logic for the next decoding call. + */ + sp->dec_codep = codep; + do { + codep = codep->next; + } while (codep && codep->length > occ); + if (codep) { + sp->dec_restart = (long)occ; + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); + if (codep) + codeLoop(tif, module); + } + break; + } + len = codep->length; + tp = op + len; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = (char)t; + } while (codep && tp > op); + if (codep) { + codeLoop(tif, module); + break; + } + assert(occ >= len); + op += len; + occ -= len; + } else { + *op++ = (char)code; + occ--; + } + } + + tif->tif_rawcc -= (tmsize_t)((uint8_t*) bp - tif->tif_rawcp ); + tif->tif_rawcp = (uint8_t*) bp; +#ifdef LZW_CHECKEOS + sp->old_tif_rawcc = tif->tif_rawcc; +#endif + sp->lzw_nbits = (unsigned short) nbits; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->dec_nbitsmask = nbitsmask; + sp->dec_oldcodep = oldcodep; + sp->dec_free_entp = free_entp; + sp->dec_maxcodep = maxcodep; + + if (occ > 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %"PRIu32" (short %ld bytes)", + tif->tif_row, occ); + return (0); + } + return (1); +} + +#ifdef LZW_COMPAT +/* + * Decode a "hunk of data" for old images. + */ +#define GetNextCodeCompat(sp, bp, code) { \ + nextdata |= (unsigned long) *(bp)++ << nextbits; \ + nextbits += 8; \ + if (nextbits < nbits) { \ + nextdata |= (unsigned long) *(bp)++ << nextbits;\ + nextbits += 8; \ + } \ + code = (hcode_t)(nextdata & nbitsmask); \ + nextdata >>= nbits; \ + nextbits -= nbits; \ +} + +static int +LZWDecodeCompat(TIFF* tif, uint8_t* op0, tmsize_t occ0, uint16_t s) +{ + static const char module[] = "LZWDecodeCompat"; + LZWCodecState *sp = DecoderState(tif); + char *op = (char*) op0; + long occ = (long) occ0; + char *tp; + unsigned char *bp; + int code, nbits; + int len; + long nextbits, nextdata, nbitsmask; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + (void) s; + assert(sp != NULL); + + /* + Fail if value does not fit in long. + */ + if ((tmsize_t) occ != occ0) + return (0); + + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) { + long residue; + + codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { + /* + * Residue from previous decode is sufficient + * to satisfy decode request. Skip to the + * start of the decoded string, place decoded + * values in the output buffer, and return. + */ + sp->dec_restart += occ; + do { + codep = codep->next; + } while (--residue > occ); + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ); + return (1); + } + /* + * Residue satisfies only part of the decode request. + */ + op += residue; + occ -= residue; + tp = op; + do { + *--tp = codep->value; + codep = codep->next; + } while (--residue); + sp->dec_restart = 0; + } + + bp = (unsigned char *)tif->tif_rawcp; +#ifdef LZW_CHECKEOS + sp->dec_bitsleft += (((uint64_t)tif->tif_rawcc - sp->old_tif_rawcc) << 3); +#endif + nbits = sp->lzw_nbits; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + nbitsmask = sp->dec_nbitsmask; + oldcodep = sp->dec_oldcodep; + free_entp = sp->dec_free_entp; + maxcodep = sp->dec_maxcodep; + + while (occ > 0) { + NextCode(tif, sp, bp, code, GetNextCodeCompat); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + do { + free_entp = sp->dec_codetab + CODE_FIRST; + _TIFFmemset(free_entp, 0, + (CSIZE - CODE_FIRST) * sizeof (code_t)); + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask; + NextCode(tif, sp, bp, code, GetNextCodeCompat); + } while (code == CODE_CLEAR); /* consecutive CODE_CLEAR codes */ + if (code == CODE_EOI) + break; + if (code > CODE_CLEAR) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "LZWDecode: Corrupted LZW table at scanline %"PRIu32, + tif->tif_row); + return (0); + } + *op++ = (char)code; + occ--; + oldcodep = sp->dec_codetab + code; + continue; + } + codep = sp->dec_codetab + code; + + /* + * Add the new entry to the code table. + */ + if (free_entp < &sp->dec_codetab[0] || + free_entp >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, module, + "Corrupted LZW table at scanline %"PRIu32, tif->tif_row); + return (0); + } + + free_entp->next = oldcodep; + if (free_entp->next < &sp->dec_codetab[0] || + free_entp->next >= &sp->dec_codetab[CSIZE]) { + TIFFErrorExt(tif->tif_clientdata, module, + "Corrupted LZW table at scanline %"PRIu32, tif->tif_row); + return (0); + } + free_entp->firstchar = free_entp->next->firstchar; + free_entp->length = free_entp->next->length+1; + free_entp->value = (codep < free_entp) ? + codep->firstchar : free_entp->firstchar; + if (++free_entp > maxcodep) { + if (++nbits > BITS_MAX) /* should not happen */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = sp->dec_codetab + nbitsmask; + } + oldcodep = codep; + if (code >= 256) { + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + if(codep->length == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Wrong length of decoded " + "string: data probably corrupted at scanline %"PRIu32, + tif->tif_row); + return (0); + } + if (codep->length > occ) { + /* + * String is too long for decode buffer, + * locate portion that will fit, copy to + * the decode buffer, and setup restart + * logic for the next decoding call. + */ + sp->dec_codep = codep; + do { + codep = codep->next; + } while (codep->length > occ); + sp->dec_restart = occ; + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ); + break; + } + len = codep->length; + tp = op + len; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = (char)t; + } while (codep && tp > op); + assert(occ >= len); + op += len; + occ -= len; + } else { + *op++ = (char)code; + occ--; + } + } + + tif->tif_rawcc -= (tmsize_t)((uint8_t*) bp - tif->tif_rawcp ); + tif->tif_rawcp = (uint8_t*) bp; +#ifdef LZW_CHECKEOS + sp->old_tif_rawcc = tif->tif_rawcc; +#endif + sp->lzw_nbits = (unsigned short)nbits; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->dec_nbitsmask = nbitsmask; + sp->dec_oldcodep = oldcodep; + sp->dec_free_entp = free_entp; + sp->dec_maxcodep = maxcodep; + + if (occ > 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %"PRIu32" (short %ld bytes)", + tif->tif_row, occ); + return (0); + } + return (1); +} +#endif /* LZW_COMPAT */ + +/* + * LZW Encoding. + */ + +static int +LZWSetupEncode(TIFF* tif) +{ + static const char module[] = "LZWSetupEncode"; + LZWCodecState* sp = EncoderState(tif); + + assert(sp != NULL); + sp->enc_hashtab = (hash_t*) _TIFFmalloc(HSIZE*sizeof (hash_t)); + if (sp->enc_hashtab == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for LZW hash table"); + return (0); + } + return (1); +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +LZWPreEncode(TIFF* tif, uint16_t s) +{ + LZWCodecState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + + if( sp->enc_hashtab == NULL ) + { + tif->tif_setupencode( tif ); + } + + sp->lzw_nbits = BITS_MIN; + sp->lzw_maxcode = MAXCODE(BITS_MIN); + sp->lzw_free_ent = CODE_FIRST; + sp->lzw_nextbits = 0; + sp->lzw_nextdata = 0; + sp->enc_checkpoint = CHECK_GAP; + sp->enc_ratio = 0; + sp->enc_incount = 0; + sp->enc_outcount = 0; + /* + * The 4 here insures there is space for 2 max-sized + * codes in LZWEncode and LZWPostDecode. + */ + sp->enc_rawlimit = tif->tif_rawdata + tif->tif_rawdatasize-1 - 4; + cl_hash(sp); /* clear hash table */ + sp->enc_oldcode = (hcode_t) -1; /* generates CODE_CLEAR in LZWEncode */ + return (1); +} + +#define CALCRATIO(sp, rat) { \ + if (incount > 0x007fffff) { /* NB: shift will overflow */\ + rat = outcount >> 8; \ + rat = (rat == 0 ? 0x7fffffff : incount/rat); \ + } else \ + rat = (incount<<8) / outcount; \ +} + +/* Explicit 0xff masking to make icc -check=conversions happy */ +#define PutNextCode(op, c) { \ + nextdata = (nextdata << nbits) | c; \ + nextbits += nbits; \ + *op++ = (unsigned char)((nextdata >> (nextbits-8))&0xff); \ + nextbits -= 8; \ + if (nextbits >= 8) { \ + *op++ = (unsigned char)((nextdata >> (nextbits-8))&0xff); \ + nextbits -= 8; \ + } \ + outcount += nbits; \ +} + +/* + * Encode a chunk of pixels. + * + * Uses an open addressing double hashing (no chaining) on the + * prefix code/next character combination. We do a variant of + * Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's + * relatively-prime secondary probe. Here, the modular division + * first probe is gives way to a faster exclusive-or manipulation. + * Also do block compression with an adaptive reset, whereby the + * code table is cleared when the compression ratio decreases, + * but after the table fills. The variable-length output codes + * are re-sized at this point, and a CODE_CLEAR is generated + * for the decoder. + */ +static int +LZWEncode(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + register LZWCodecState *sp = EncoderState(tif); + register long fcode; + register hash_t *hp; + register int h, c; + hcode_t ent; + long disp; + long incount, outcount, checkpoint; + unsigned long nextdata; + long nextbits; + int free_ent, maxcode, nbits; + uint8_t* op; + uint8_t* limit; + + (void) s; + if (sp == NULL) + return (0); + + assert(sp->enc_hashtab != NULL); + + /* + * Load local state. + */ + incount = sp->enc_incount; + outcount = sp->enc_outcount; + checkpoint = sp->enc_checkpoint; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + free_ent = sp->lzw_free_ent; + maxcode = sp->lzw_maxcode; + nbits = sp->lzw_nbits; + op = tif->tif_rawcp; + limit = sp->enc_rawlimit; + ent = (hcode_t)sp->enc_oldcode; + + if (ent == (hcode_t) -1 && cc > 0) { + /* + * NB: This is safe because it can only happen + * at the start of a strip where we know there + * is space in the data buffer. + */ + PutNextCode(op, CODE_CLEAR); + ent = *bp++; cc--; incount++; + } + while (cc > 0) { + c = *bp++; cc--; incount++; + fcode = ((long)c << BITS_MAX) + ent; + h = (c << HSHIFT) ^ ent; /* xor hashing */ +#ifdef _WINDOWS + /* + * Check hash index for an overflow. + */ + if (h >= HSIZE) + h -= HSIZE; +#endif + hp = &sp->enc_hashtab[h]; + if (hp->hash == fcode) { + ent = hp->code; + continue; + } + if (hp->hash >= 0) { + /* + * Primary hash failed, check secondary hash. + */ + disp = HSIZE - h; + if (h == 0) + disp = 1; + do { + /* + * Avoid pointer arithmetic because of + * wraparound problems with segments. + */ + if ((h -= disp) < 0) + h += HSIZE; + hp = &sp->enc_hashtab[h]; + if (hp->hash == fcode) { + ent = hp->code; + goto hit; + } + } while (hp->hash >= 0); + } + /* + * New entry, emit code and add to table. + */ + /* + * Verify there is space in the buffer for the code + * and any potential Clear code that might be emitted + * below. The value of limit is setup so that there + * are at least 4 bytes free--room for 2 codes. + */ + if (op > limit) { + tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata); + if( !TIFFFlushData1(tif) ) + return 0; + op = tif->tif_rawdata; + } + PutNextCode(op, ent); + ent = (hcode_t)c; + hp->code = (hcode_t)(free_ent++); + hp->hash = fcode; + if (free_ent == CODE_MAX-1) { + /* table is full, emit clear code and reset */ + cl_hash(sp); + sp->enc_ratio = 0; + incount = 0; + outcount = 0; + free_ent = CODE_FIRST; + PutNextCode(op, CODE_CLEAR); + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + } else { + /* + * If the next entry is going to be too big for + * the code size, then increase it, if possible. + */ + if (free_ent > maxcode) { + nbits++; + assert(nbits <= BITS_MAX); + maxcode = (int) MAXCODE(nbits); + } else if (incount >= checkpoint) { + long rat; + /* + * Check compression ratio and, if things seem + * to be slipping, clear the hash table and + * reset state. The compression ratio is a + * 24+8-bit fractional number. + */ + checkpoint = incount+CHECK_GAP; + CALCRATIO(sp, rat); + if (rat <= sp->enc_ratio) { + cl_hash(sp); + sp->enc_ratio = 0; + incount = 0; + outcount = 0; + free_ent = CODE_FIRST; + PutNextCode(op, CODE_CLEAR); + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + } else + sp->enc_ratio = rat; + } + } + hit: + ; + } + + /* + * Restore global state. + */ + sp->enc_incount = incount; + sp->enc_outcount = outcount; + sp->enc_checkpoint = checkpoint; + sp->enc_oldcode = ent; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->lzw_free_ent = (unsigned short)free_ent; + sp->lzw_maxcode = (unsigned short)maxcode; + sp->lzw_nbits = (unsigned short)nbits; + tif->tif_rawcp = op; + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ +static int +LZWPostEncode(TIFF* tif) +{ + register LZWCodecState *sp = EncoderState(tif); + uint8_t* op = tif->tif_rawcp; + long nextbits = sp->lzw_nextbits; + unsigned long nextdata = sp->lzw_nextdata; + long outcount = sp->enc_outcount; + int nbits = sp->lzw_nbits; + + if (op > sp->enc_rawlimit) { + tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata); + if( !TIFFFlushData1(tif) ) + return 0; + op = tif->tif_rawdata; + } + if (sp->enc_oldcode != (hcode_t) -1) { + int free_ent = sp->lzw_free_ent; + + PutNextCode(op, sp->enc_oldcode); + sp->enc_oldcode = (hcode_t) -1; + free_ent ++; + + if (free_ent == CODE_MAX-1) { + /* table is full, emit clear code and reset */ + outcount = 0; + PutNextCode(op, CODE_CLEAR); + nbits = BITS_MIN; + } else { + /* + * If the next entry is going to be too big for + * the code size, then increase it, if possible. + */ + if (free_ent > sp->lzw_maxcode) { + nbits++; + assert(nbits <= BITS_MAX); + } + } + } + PutNextCode(op, CODE_EOI); + /* Explicit 0xff masking to make icc -check=conversions happy */ + if (nextbits > 0) + *op++ = (unsigned char)((nextdata << (8-nextbits))&0xff); + tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata); + return (1); +} + +/* + * Reset encoding hash table. + */ +static void +cl_hash(LZWCodecState* sp) +{ + register hash_t *hp = &sp->enc_hashtab[HSIZE-1]; + register long i = HSIZE-8; + + do { + i -= 8; + hp[-7].hash = -1; + hp[-6].hash = -1; + hp[-5].hash = -1; + hp[-4].hash = -1; + hp[-3].hash = -1; + hp[-2].hash = -1; + hp[-1].hash = -1; + hp[ 0].hash = -1; + hp -= 8; + } while (i >= 0); + for (i += 8; i > 0; i--, hp--) + hp->hash = -1; +} + +static void +LZWCleanup(TIFF* tif) +{ + (void)TIFFPredictorCleanup(tif); + + assert(tif->tif_data != 0); + + if (DecoderState(tif)->dec_codetab) + _TIFFfree(DecoderState(tif)->dec_codetab); + + if (EncoderState(tif)->enc_hashtab) + _TIFFfree(EncoderState(tif)->enc_hashtab); + + _TIFFfree(tif->tif_data); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +int +TIFFInitLZW(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitLZW"; + (void)scheme; + assert(scheme == COMPRESSION_LZW); + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t*) _TIFFmalloc(sizeof (LZWCodecState)); + if (tif->tif_data == NULL) + goto bad; + DecoderState(tif)->dec_codetab = NULL; + DecoderState(tif)->dec_decode = NULL; + EncoderState(tif)->enc_hashtab = NULL; + LZWState(tif)->rw_mode = tif->tif_mode; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = LZWFixupTags; + tif->tif_setupdecode = LZWSetupDecode; + tif->tif_predecode = LZWPreDecode; + tif->tif_decoderow = LZWDecode; + tif->tif_decodestrip = LZWDecode; + tif->tif_decodetile = LZWDecode; + tif->tif_setupencode = LZWSetupEncode; + tif->tif_preencode = LZWPreEncode; + tif->tif_postencode = LZWPostEncode; + tif->tif_encoderow = LZWEncode; + tif->tif_encodestrip = LZWEncode; + tif->tif_encodetile = LZWEncode; + tif->tif_cleanup = LZWCleanup; + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "No space for LZW state block"); + return (0); +} + +/* + * Copyright (c) 1985, 1986 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods, derived from original work by Spencer Thomas + * and Joseph Orost. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#endif /* LZW_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_next.c b/libs/tiff/libtiff/tif_next.c new file mode 100644 index 00000000000..695fc5d4b00 --- /dev/null +++ b/libs/tiff/libtiff/tif_next.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef NEXT_SUPPORT +/* + * TIFF Library. + * + * NeXT 2-bit Grey Scale Compression Algorithm Support + */ + +#define SETPIXEL(op, v) { \ + switch (npixels++ & 3) { \ + case 0: op[0] = (unsigned char) ((v) << 6); break; \ + case 1: op[0] |= (v) << 4; break; \ + case 2: op[0] |= (v) << 2; break; \ + case 3: *op++ |= (v); op_offset++; break; \ + } \ +} + +#define LITERALROW 0x00 +#define LITERALSPAN 0x40 +#define WHITE ((1<<2)-1) + +static int +NeXTDecode(TIFF* tif, uint8_t* buf, tmsize_t occ, uint16_t s) +{ + static const char module[] = "NeXTDecode"; + unsigned char *bp, *op; + tmsize_t cc; + uint8_t* row; + tmsize_t scanline, n; + + (void) s; + /* + * Each scanline is assumed to start off as all + * white (we assume a PhotometricInterpretation + * of ``min-is-black''). + */ + for (op = (unsigned char*) buf, cc = occ; cc-- > 0;) + *op++ = 0xff; + + bp = (unsigned char *)tif->tif_rawcp; + cc = tif->tif_rawcc; + scanline = tif->tif_scanlinesize; + if (occ % scanline) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (0); + } + for (row = buf; cc > 0 && occ > 0; occ -= scanline, row += scanline) { + n = *bp++; + cc--; + switch (n) { + case LITERALROW: + /* + * The entire scanline is given as literal values. + */ + if (cc < scanline) + goto bad; + _TIFFmemcpy(row, bp, scanline); + bp += scanline; + cc -= scanline; + break; + case LITERALSPAN: { + tmsize_t off; + /* + * The scanline has a literal span that begins at some + * offset. + */ + if( cc < 4 ) + goto bad; + off = (bp[0] * 256) + bp[1]; + n = (bp[2] * 256) + bp[3]; + if (cc < 4+n || off+n > scanline) + goto bad; + _TIFFmemcpy(row+off, bp+4, n); + bp += 4+n; + cc -= 4+n; + break; + } + default: { + uint32_t npixels = 0, grey; + tmsize_t op_offset = 0; + uint32_t imagewidth = tif->tif_dir.td_imagewidth; + if( isTiled(tif) ) + imagewidth = tif->tif_dir.td_tilewidth; + + /* + * The scanline is composed of a sequence of constant + * color ``runs''. We shift into ``run mode'' and + * interpret bytes as codes of the form + * until we've filled the scanline. + */ + op = row; + for (;;) { + grey = (uint32_t)((n >> 6) & 0x3); + n &= 0x3f; + /* + * Ensure the run does not exceed the scanline + * bounds, potentially resulting in a security + * issue. + */ + while (n-- > 0 && npixels < imagewidth && op_offset < scanline) + SETPIXEL(op, grey); + if (npixels >= imagewidth) + break; + if (op_offset >= scanline ) { + TIFFErrorExt(tif->tif_clientdata, module, "Invalid data for scanline %"PRIu32, + tif->tif_row); + return (0); + } + if (cc == 0) + goto bad; + n = *bp++; + cc--; + } + break; + } + } + } + tif->tif_rawcp = (uint8_t*) bp; + tif->tif_rawcc = cc; + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, "Not enough data for scanline %"PRIu32, + tif->tif_row); + return (0); +} + +static int +NeXTPreDecode(TIFF* tif, uint16_t s) +{ + static const char module[] = "NeXTPreDecode"; + TIFFDirectory *td = &tif->tif_dir; + (void)s; + + if( td->td_bitspersample != 2 ) + { + TIFFErrorExt(tif->tif_clientdata, module, "Unsupported BitsPerSample = %"PRIu16, + td->td_bitspersample); + return (0); + } + return (1); +} + +int +TIFFInitNeXT(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_predecode = NeXTPreDecode; + tif->tif_decoderow = NeXTDecode; + tif->tif_decodestrip = NeXTDecode; + tif->tif_decodetile = NeXTDecode; + return (1); +} +#endif /* NEXT_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_open.c b/libs/tiff/libtiff/tif_open.c new file mode 100644 index 00000000000..9724162e4ad --- /dev/null +++ b/libs/tiff/libtiff/tif_open.c @@ -0,0 +1,742 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +/* + * Dummy functions to fill the omitted client procedures. + */ +static int +_tiffDummyMapProc(thandle_t fd, void** pbase, toff_t* psize) +{ + (void) fd; (void) pbase; (void) psize; + return (0); +} + +static void +_tiffDummyUnmapProc(thandle_t fd, void* base, toff_t size) +{ + (void) fd; (void) base; (void) size; +} + +int +_TIFFgetMode(const char* mode, const char* module) +{ + int m = -1; + + switch (mode[0]) { + case 'r': + m = O_RDONLY; + if (mode[1] == '+') + m = O_RDWR; + break; + case 'w': + case 'a': + m = O_RDWR|O_CREAT; + if (mode[0] == 'w') + m |= O_TRUNC; + break; + default: + TIFFErrorExt(0, module, "\"%s\": Bad mode", mode); + break; + } + return (m); +} + +TIFF* +TIFFClientOpen( + const char* name, const char* mode, + thandle_t clientdata, + TIFFReadWriteProc readproc, + TIFFReadWriteProc writeproc, + TIFFSeekProc seekproc, + TIFFCloseProc closeproc, + TIFFSizeProc sizeproc, + TIFFMapFileProc mapproc, + TIFFUnmapFileProc unmapproc +) +{ + static const char module[] = "TIFFClientOpen"; + TIFF *tif; + int m; + const char* cp; + + /* The following are configuration checks. They should be redundant, but should not + * compile to any actual code in an optimised release build anyway. If any of them + * fail, (makefile-based or other) configuration is not correct */ + assert(sizeof(uint8_t) == 1); + assert(sizeof(int8_t) == 1); + assert(sizeof(uint16_t) == 2); + assert(sizeof(int16_t) == 2); + assert(sizeof(uint32_t) == 4); + assert(sizeof(int32_t) == 4); + assert(sizeof(uint64_t) == 8); + assert(sizeof(int64_t) == 8); + assert(sizeof(tmsize_t)==sizeof(void*)); + { + union{ + uint8_t a8[2]; + uint16_t a16; + } n; + n.a8[0]=1; + n.a8[1]=0; + (void)n; + #ifdef WORDS_BIGENDIAN + assert(n.a16==256); + #else + assert(n.a16==1); + #endif + } + + m = _TIFFgetMode(mode, module); + if (m == -1) + goto bad2; + tif = (TIFF *)_TIFFmalloc((tmsize_t)(sizeof (TIFF) + strlen(name) + 1)); + if (tif == NULL) { + TIFFErrorExt(clientdata, module, "%s: Out of memory (TIFF structure)", name); + goto bad2; + } + _TIFFmemset(tif, 0, sizeof (*tif)); + tif->tif_name = (char *)tif + sizeof (TIFF); + strcpy(tif->tif_name, name); + tif->tif_mode = m &~ (O_CREAT|O_TRUNC); + tif->tif_curdir = (uint16_t) -1; /* non-existent directory */ + tif->tif_curoff = 0; + tif->tif_curstrip = (uint32_t) -1; /* invalid strip */ + tif->tif_row = (uint32_t) -1; /* read/write pre-increment */ + tif->tif_clientdata = clientdata; + if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) { + TIFFErrorExt(clientdata, module, + "One of the client procedures is NULL pointer."); + _TIFFfree(tif); + goto bad2; + } + tif->tif_readproc = readproc; + tif->tif_writeproc = writeproc; + tif->tif_seekproc = seekproc; + tif->tif_closeproc = closeproc; + tif->tif_sizeproc = sizeproc; + if (mapproc) + tif->tif_mapproc = mapproc; + else + tif->tif_mapproc = _tiffDummyMapProc; + if (unmapproc) + tif->tif_unmapproc = unmapproc; + else + tif->tif_unmapproc = _tiffDummyUnmapProc; + _TIFFSetDefaultCompressionState(tif); /* setup default state */ + /* + * Default is to return data MSB2LSB and enable the + * use of memory-mapped files and strip chopping when + * a file is opened read-only. + */ + tif->tif_flags = FILLORDER_MSB2LSB; + if (m == O_RDONLY ) + tif->tif_flags |= TIFF_MAPPED; + + #ifdef STRIPCHOP_DEFAULT + if (m == O_RDONLY || m == O_RDWR) + tif->tif_flags |= STRIPCHOP_DEFAULT; + #endif + + /* + * Process library-specific flags in the open mode string. + * The following flags may be used to control intrinsic library + * behavior that may or may not be desirable (usually for + * compatibility with some application that claims to support + * TIFF but only supports some brain dead idea of what the + * vendor thinks TIFF is): + * + * 'l' use little-endian byte order for creating a file + * 'b' use big-endian byte order for creating a file + * 'L' read/write information using LSB2MSB bit order + * 'B' read/write information using MSB2LSB bit order + * 'H' read/write information using host bit order + * 'M' enable use of memory-mapped files when supported + * 'm' disable use of memory-mapped files + * 'C' enable strip chopping support when reading + * 'c' disable strip chopping support + * 'h' read TIFF header only, do not load the first IFD + * '4' ClassicTIFF for creating a file (default) + * '8' BigTIFF for creating a file + * 'D' enable use of deferred strip/tile offset/bytecount array loading. + * 'O' on-demand loading of values instead of whole array loading (implies D) + * + * The use of the 'l' and 'b' flags is strongly discouraged. + * These flags are provided solely because numerous vendors, + * typically on the PC, do not correctly support TIFF; they + * only support the Intel little-endian byte order. This + * support is not configured by default because it supports + * the violation of the TIFF spec that says that readers *MUST* + * support both byte orders. It is strongly recommended that + * you not use this feature except to deal with busted apps + * that write invalid TIFF. And even in those cases you should + * bang on the vendors to fix their software. + * + * The 'L', 'B', and 'H' flags are intended for applications + * that can optimize operations on data by using a particular + * bit order. By default the library returns data in MSB2LSB + * bit order for compatibility with older versions of this + * library. Returning data in the bit order of the native CPU + * makes the most sense but also requires applications to check + * the value of the FillOrder tag; something they probably do + * not do right now. + * + * The 'M' and 'm' flags are provided because some virtual memory + * systems exhibit poor behavior when large images are mapped. + * These options permit clients to control the use of memory-mapped + * files on a per-file basis. + * + * The 'C' and 'c' flags are provided because the library support + * for chopping up large strips into multiple smaller strips is not + * application-transparent and as such can cause problems. The 'c' + * option permits applications that only want to look at the tags, + * for example, to get the unadulterated TIFF tag information. + */ + for (cp = mode; *cp; cp++) + switch (*cp) { + case 'b': + #ifndef WORDS_BIGENDIAN + if (m&O_CREAT) + tif->tif_flags |= TIFF_SWAB; + #endif + break; + case 'l': + #ifdef WORDS_BIGENDIAN + if ((m&O_CREAT)) + tif->tif_flags |= TIFF_SWAB; + #endif + break; + case 'B': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + FILLORDER_MSB2LSB; + break; + case 'L': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + FILLORDER_LSB2MSB; + break; + case 'H': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + HOST_FILLORDER; + break; + case 'M': + if (m == O_RDONLY) + tif->tif_flags |= TIFF_MAPPED; + break; + case 'm': + if (m == O_RDONLY) + tif->tif_flags &= ~TIFF_MAPPED; + break; + case 'C': + if (m == O_RDONLY) + tif->tif_flags |= TIFF_STRIPCHOP; + break; + case 'c': + if (m == O_RDONLY) + tif->tif_flags &= ~TIFF_STRIPCHOP; + break; + case 'h': + tif->tif_flags |= TIFF_HEADERONLY; + break; + case '8': + if (m&O_CREAT) + tif->tif_flags |= TIFF_BIGTIFF; + break; + case 'D': + tif->tif_flags |= TIFF_DEFERSTRILELOAD; + break; + case 'O': + if( m == O_RDONLY ) + tif->tif_flags |= (TIFF_LAZYSTRILELOAD | TIFF_DEFERSTRILELOAD); + break; + } + +#ifdef DEFER_STRILE_LOAD + /* Compatibility with old DEFER_STRILE_LOAD compilation flag */ + /* Probably unneeded, since to the best of my knowledge (E. Rouault) */ + /* GDAL was the only user of this, and will now use the new 'D' flag */ + tif->tif_flags |= TIFF_DEFERSTRILELOAD; +#endif + + /* + * Read in TIFF header. + */ + if ((m & O_TRUNC) || + !ReadOK(tif, &tif->tif_header, sizeof (TIFFHeaderClassic))) { + if (tif->tif_mode == O_RDONLY) { + TIFFErrorExt(tif->tif_clientdata, name, + "Cannot read TIFF header"); + goto bad; + } + /* + * Setup header and write. + */ + #ifdef WORDS_BIGENDIAN + tif->tif_header.common.tiff_magic = (tif->tif_flags & TIFF_SWAB) + ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN; + #else + tif->tif_header.common.tiff_magic = (tif->tif_flags & TIFF_SWAB) + ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN; + #endif + if (!(tif->tif_flags&TIFF_BIGTIFF)) + { + tif->tif_header.common.tiff_version = TIFF_VERSION_CLASSIC; + tif->tif_header.classic.tiff_diroff = 0; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&tif->tif_header.common.tiff_version); + tif->tif_header_size = sizeof(TIFFHeaderClassic); + } + else + { + tif->tif_header.common.tiff_version = TIFF_VERSION_BIG; + tif->tif_header.big.tiff_offsetsize = 8; + tif->tif_header.big.tiff_unused = 0; + tif->tif_header.big.tiff_diroff = 0; + if (tif->tif_flags & TIFF_SWAB) + { + TIFFSwabShort(&tif->tif_header.common.tiff_version); + TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize); + } + tif->tif_header_size = sizeof (TIFFHeaderBig); + } + /* + * The doc for "fopen" for some STD_C_LIBs says that if you + * open a file for modify ("+"), then you must fseek (or + * fflush?) between any freads and fwrites. This is not + * necessary on most systems, but has been shown to be needed + * on Solaris. + */ + TIFFSeekFile( tif, 0, SEEK_SET ); + if (!WriteOK(tif, &tif->tif_header, (tmsize_t)(tif->tif_header_size))) { + TIFFErrorExt(tif->tif_clientdata, name, + "Error writing TIFF header"); + goto bad; + } + /* + * Setup the byte order handling. + */ + if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) { + #ifndef WORDS_BIGENDIAN + tif->tif_flags |= TIFF_SWAB; + #endif + } else { + #ifdef WORDS_BIGENDIAN + tif->tif_flags |= TIFF_SWAB; + #endif + } + /* + * Setup default directory. + */ + if (!TIFFDefaultDirectory(tif)) + goto bad; + tif->tif_diroff = 0; + tif->tif_dirlist = NULL; + tif->tif_dirlistsize = 0; + tif->tif_dirnumber = 0; + return (tif); + } + /* + * Setup the byte order handling. + */ + if (tif->tif_header.common.tiff_magic != TIFF_BIGENDIAN && + tif->tif_header.common.tiff_magic != TIFF_LITTLEENDIAN + #if MDI_SUPPORT + && + #if HOST_BIGENDIAN + tif->tif_header.common.tiff_magic != MDI_BIGENDIAN + #else + tif->tif_header.common.tiff_magic != MDI_LITTLEENDIAN + #endif + ) { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF or MDI file, bad magic number %"PRIu16" (0x%"PRIx16")", + #else + ) { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF file, bad magic number %"PRIu16" (0x%"PRIx16")", + #endif + tif->tif_header.common.tiff_magic, + tif->tif_header.common.tiff_magic); + goto bad; + } + if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) { + #ifndef WORDS_BIGENDIAN + tif->tif_flags |= TIFF_SWAB; + #endif + } else { + #ifdef WORDS_BIGENDIAN + tif->tif_flags |= TIFF_SWAB; + #endif + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&tif->tif_header.common.tiff_version); + if ((tif->tif_header.common.tiff_version != TIFF_VERSION_CLASSIC)&& + (tif->tif_header.common.tiff_version != TIFF_VERSION_BIG)) { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF file, bad version number %"PRIu16" (0x%"PRIx16")", + tif->tif_header.common.tiff_version, + tif->tif_header.common.tiff_version); + goto bad; + } + if (tif->tif_header.common.tiff_version == TIFF_VERSION_CLASSIC) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&tif->tif_header.classic.tiff_diroff); + tif->tif_header_size = sizeof(TIFFHeaderClassic); + } + else + { + if (!ReadOK(tif, ((uint8_t*)(&tif->tif_header) + sizeof(TIFFHeaderClassic)), (sizeof(TIFFHeaderBig) - sizeof(TIFFHeaderClassic)))) + { + TIFFErrorExt(tif->tif_clientdata, name, + "Cannot read TIFF header"); + goto bad; + } + if (tif->tif_flags & TIFF_SWAB) + { + TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize); + TIFFSwabLong8(&tif->tif_header.big.tiff_diroff); + } + if (tif->tif_header.big.tiff_offsetsize != 8) + { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF file, bad BigTIFF offsetsize %"PRIu16" (0x%"PRIx16")", + tif->tif_header.big.tiff_offsetsize, + tif->tif_header.big.tiff_offsetsize); + goto bad; + } + if (tif->tif_header.big.tiff_unused != 0) + { + TIFFErrorExt(tif->tif_clientdata, name, + "Not a TIFF file, bad BigTIFF unused %"PRIu16" (0x%"PRIx16")", + tif->tif_header.big.tiff_unused, + tif->tif_header.big.tiff_unused); + goto bad; + } + tif->tif_header_size = sizeof(TIFFHeaderBig); + tif->tif_flags |= TIFF_BIGTIFF; + } + tif->tif_flags |= TIFF_MYBUFFER; + tif->tif_rawcp = tif->tif_rawdata = 0; + tif->tif_rawdatasize = 0; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = 0; + + switch (mode[0]) { + case 'r': + if (!(tif->tif_flags&TIFF_BIGTIFF)) + tif->tif_nextdiroff = tif->tif_header.classic.tiff_diroff; + else + tif->tif_nextdiroff = tif->tif_header.big.tiff_diroff; + /* + * Try to use a memory-mapped file if the client + * has not explicitly suppressed usage with the + * 'm' flag in the open mode (see above). + */ + if (tif->tif_flags & TIFF_MAPPED) + { + toff_t n; + if (TIFFMapFileContents(tif,(void**)(&tif->tif_base),&n)) + { + tif->tif_size=(tmsize_t)n; + assert((toff_t)tif->tif_size==n); + } + else + tif->tif_flags &= ~TIFF_MAPPED; + } + /* + * Sometimes we do not want to read the first directory (for example, + * it may be broken) and want to proceed to other directories. I this + * case we use the TIFF_HEADERONLY flag to open file and return + * immediately after reading TIFF header. + */ + if (tif->tif_flags & TIFF_HEADERONLY) + return (tif); + + /* + * Setup initial directory. + */ + if (TIFFReadDirectory(tif)) { + tif->tif_rawcc = (tmsize_t)-1; + tif->tif_flags |= TIFF_BUFFERSETUP; + return (tif); + } + break; + case 'a': + /* + * New directories are automatically append + * to the end of the directory chain when they + * are written out (see TIFFWriteDirectory). + */ + if (!TIFFDefaultDirectory(tif)) + goto bad; + return (tif); + } +bad: + tif->tif_mode = O_RDONLY; /* XXX avoid flush */ + TIFFCleanup(tif); +bad2: + return ((TIFF*)0); +} + +/* + * Query functions to access private data. + */ + +/* + * Return open file's name. + */ +const char * +TIFFFileName(TIFF* tif) +{ + return (tif->tif_name); +} + +/* + * Set the file name. + */ +const char * +TIFFSetFileName(TIFF* tif, const char *name) +{ + const char* old_name = tif->tif_name; + tif->tif_name = (char *)name; + return (old_name); +} + +/* + * Return open file's I/O descriptor. + */ +int +TIFFFileno(TIFF* tif) +{ + return (tif->tif_fd); +} + +/* + * Set open file's I/O descriptor, and return previous value. + */ +int +TIFFSetFileno(TIFF* tif, int fd) +{ + int old_fd = tif->tif_fd; + tif->tif_fd = fd; + return old_fd; +} + +/* + * Return open file's clientdata. + */ +thandle_t +TIFFClientdata(TIFF* tif) +{ + return (tif->tif_clientdata); +} + +/* + * Set open file's clientdata, and return previous value. + */ +thandle_t +TIFFSetClientdata(TIFF* tif, thandle_t newvalue) +{ + thandle_t m = tif->tif_clientdata; + tif->tif_clientdata = newvalue; + return m; +} + +/* + * Return read/write mode. + */ +int +TIFFGetMode(TIFF* tif) +{ + return (tif->tif_mode); +} + +/* + * Return read/write mode. + */ +int +TIFFSetMode(TIFF* tif, int mode) +{ + int old_mode = tif->tif_mode; + tif->tif_mode = mode; + return (old_mode); +} + +/* + * Return nonzero if file is organized in + * tiles; zero if organized as strips. + */ +int +TIFFIsTiled(TIFF* tif) +{ + return (isTiled(tif)); +} + +/* + * Return current row being read/written. + */ +uint32_t +TIFFCurrentRow(TIFF* tif) +{ + return (tif->tif_row); +} + +/* + * Return index of the current directory. + */ +uint16_t +TIFFCurrentDirectory(TIFF* tif) +{ + return (tif->tif_curdir); +} + +/* + * Return current strip. + */ +uint32_t +TIFFCurrentStrip(TIFF* tif) +{ + return (tif->tif_curstrip); +} + +/* + * Return current tile. + */ +uint32_t +TIFFCurrentTile(TIFF* tif) +{ + return (tif->tif_curtile); +} + +/* + * Return nonzero if the file has byte-swapped data. + */ +int +TIFFIsByteSwapped(TIFF* tif) +{ + return ((tif->tif_flags & TIFF_SWAB) != 0); +} + +/* + * Return nonzero if the data is returned up-sampled. + */ +int +TIFFIsUpSampled(TIFF* tif) +{ + return (isUpSampled(tif)); +} + +/* + * Return nonzero if the data is returned in MSB-to-LSB bit order. + */ +int +TIFFIsMSB2LSB(TIFF* tif) +{ + return (isFillOrder(tif, FILLORDER_MSB2LSB)); +} + +/* + * Return nonzero if given file was written in big-endian order. + */ +int +TIFFIsBigEndian(TIFF* tif) +{ + return (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN); +} + +/* + * Return pointer to file read method. + */ +TIFFReadWriteProc +TIFFGetReadProc(TIFF* tif) +{ + return (tif->tif_readproc); +} + +/* + * Return pointer to file write method. + */ +TIFFReadWriteProc +TIFFGetWriteProc(TIFF* tif) +{ + return (tif->tif_writeproc); +} + +/* + * Return pointer to file seek method. + */ +TIFFSeekProc +TIFFGetSeekProc(TIFF* tif) +{ + return (tif->tif_seekproc); +} + +/* + * Return pointer to file close method. + */ +TIFFCloseProc +TIFFGetCloseProc(TIFF* tif) +{ + return (tif->tif_closeproc); +} + +/* + * Return pointer to file size requesting method. + */ +TIFFSizeProc +TIFFGetSizeProc(TIFF* tif) +{ + return (tif->tif_sizeproc); +} + +/* + * Return pointer to memory mapping method. + */ +TIFFMapFileProc +TIFFGetMapFileProc(TIFF* tif) +{ + return (tif->tif_mapproc); +} + +/* + * Return pointer to memory unmapping method. + */ +TIFFUnmapFileProc +TIFFGetUnmapFileProc(TIFF* tif) +{ + return (tif->tif_unmapproc); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_packbits.c b/libs/tiff/libtiff/tif_packbits.c new file mode 100644 index 00000000000..76569ad7cde --- /dev/null +++ b/libs/tiff/libtiff/tif_packbits.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef PACKBITS_SUPPORT +/* + * TIFF Library. + * + * PackBits Compression Algorithm Support + */ +#include + +static int +PackBitsPreEncode(TIFF* tif, uint16_t s) +{ + (void) s; + + tif->tif_data = (uint8_t*)_TIFFmalloc(sizeof(tmsize_t)); + if (tif->tif_data == NULL) + return (0); + /* + * Calculate the scanline/tile-width size in bytes. + */ + if (isTiled(tif)) + *(tmsize_t*)tif->tif_data = TIFFTileRowSize(tif); + else + *(tmsize_t*)tif->tif_data = TIFFScanlineSize(tif); + return (1); +} + +static int +PackBitsPostEncode(TIFF* tif) +{ + if (tif->tif_data) + _TIFFfree(tif->tif_data); + return (1); +} + +/* + * Encode a run of pixels. + */ +static int +PackBitsEncode(TIFF* tif, uint8_t* buf, tmsize_t cc, uint16_t s) +{ + unsigned char* bp = (unsigned char*) buf; + uint8_t* op; + uint8_t* ep; + uint8_t* lastliteral; + long n, slop; + int b; + enum { BASE, LITERAL, RUN, LITERAL_RUN } state; + + (void) s; + op = tif->tif_rawcp; + ep = tif->tif_rawdata + tif->tif_rawdatasize; + state = BASE; + lastliteral = 0; + while (cc > 0) { + /* + * Find the longest string of identical bytes. + */ + b = *bp++; + cc--; + n = 1; + for (; cc > 0 && b == *bp; cc--, bp++) + n++; + again: + if (op + 2 >= ep) { /* insure space for new data */ + /* + * Be careful about writing the last + * literal. Must write up to that point + * and then copy the remainder to the + * front of the buffer. + */ + if (state == LITERAL || state == LITERAL_RUN) { + slop = (long)(op - lastliteral); + tif->tif_rawcc += (tmsize_t)(lastliteral - tif->tif_rawcp); + if (!TIFFFlushData1(tif)) + return (0); + op = tif->tif_rawcp; + while (slop-- > 0) + *op++ = *lastliteral++; + lastliteral = tif->tif_rawcp; + } else { + tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp); + if (!TIFFFlushData1(tif)) + return (0); + op = tif->tif_rawcp; + } + } + switch (state) { + case BASE: /* initial state, set run/literal */ + if (n > 1) { + state = RUN; + if (n > 128) { + *op++ = (uint8_t) -127; + *op++ = (uint8_t) b; + n -= 128; + goto again; + } + *op++ = (uint8_t)(-(n - 1)); + *op++ = (uint8_t) b; + } else { + lastliteral = op; + *op++ = 0; + *op++ = (uint8_t) b; + state = LITERAL; + } + break; + case LITERAL: /* last object was literal string */ + if (n > 1) { + state = LITERAL_RUN; + if (n > 128) { + *op++ = (uint8_t) -127; + *op++ = (uint8_t) b; + n -= 128; + goto again; + } + *op++ = (uint8_t)(-(n - 1)); /* encode run */ + *op++ = (uint8_t) b; + } else { /* extend literal */ + if (++(*lastliteral) == 127) + state = BASE; + *op++ = (uint8_t) b; + } + break; + case RUN: /* last object was run */ + if (n > 1) { + if (n > 128) { + *op++ = (uint8_t) -127; + *op++ = (uint8_t) b; + n -= 128; + goto again; + } + *op++ = (uint8_t)(-(n - 1)); + *op++ = (uint8_t) b; + } else { + lastliteral = op; + *op++ = 0; + *op++ = (uint8_t) b; + state = LITERAL; + } + break; + case LITERAL_RUN: /* literal followed by a run */ + /* + * Check to see if previous run should + * be converted to a literal, in which + * case we convert literal-run-literal + * to a single literal. + */ + if (n == 1 && op[-2] == (uint8_t) -1 && + *lastliteral < 126) { + state = (((*lastliteral) += 2) == 127 ? + BASE : LITERAL); + op[-2] = op[-1]; /* replicate */ + } else + state = RUN; + goto again; + } + } + tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp); + tif->tif_rawcp = op; + return (1); +} + +/* + * Encode a rectangular chunk of pixels. We break it up + * into row-sized pieces to insure that encoded runs do + * not span rows. Otherwise, there can be problems with + * the decoder if data is read, for example, by scanlines + * when it was encoded by strips. + */ +static int +PackBitsEncodeChunk(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + tmsize_t rowsize = *(tmsize_t*)tif->tif_data; + + while (cc > 0) { + tmsize_t chunk = rowsize; + + if( cc < chunk ) + chunk = cc; + + if (PackBitsEncode(tif, bp, chunk, s) < 0) + return (-1); + bp += chunk; + cc -= chunk; + } + return (1); +} + +static int +PackBitsDecode(TIFF* tif, uint8_t* op, tmsize_t occ, uint16_t s) +{ + static const char module[] = "PackBitsDecode"; + char *bp; + tmsize_t cc; + long n; + int b; + + (void) s; + bp = (char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + while (cc > 0 && occ > 0) { + n = (long) *bp++; + cc--; + /* + * Watch out for compilers that + * don't sign extend chars... + */ + if (n >= 128) + n -= 256; + if (n < 0) { /* replicate next byte -n+1 times */ + if (n == -128) /* nop */ + continue; + n = -n + 1; + if( occ < (tmsize_t)n ) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Discarding %"TIFF_SSIZE_FORMAT" bytes to avoid buffer overrun", + (tmsize_t)n - occ); + n = (long)occ; + } + if( cc == 0 ) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Terminating PackBitsDecode due to lack of data."); + break; + } + occ -= n; + b = *bp++; + cc--; + while (n-- > 0) + *op++ = (uint8_t) b; + } else { /* copy next n+1 bytes literally */ + if (occ < (tmsize_t)(n + 1)) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Discarding %"TIFF_SSIZE_FORMAT" bytes to avoid buffer overrun", + (tmsize_t)n - occ + 1); + n = (long)occ - 1; + } + if (cc < (tmsize_t) (n+1)) + { + TIFFWarningExt(tif->tif_clientdata, module, + "Terminating PackBitsDecode due to lack of data."); + break; + } + _TIFFmemcpy(op, bp, ++n); + op += n; occ -= n; + bp += n; cc -= n; + } + } + tif->tif_rawcp = (uint8_t*) bp; + tif->tif_rawcc = cc; + if (occ > 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data for scanline %"PRIu32, + tif->tif_row); + return (0); + } + return (1); +} + +int +TIFFInitPackBits(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = PackBitsDecode; + tif->tif_decodestrip = PackBitsDecode; + tif->tif_decodetile = PackBitsDecode; + tif->tif_preencode = PackBitsPreEncode; + tif->tif_postencode = PackBitsPostEncode; + tif->tif_encoderow = PackBitsEncode; + tif->tif_encodestrip = PackBitsEncodeChunk; + tif->tif_encodetile = PackBitsEncodeChunk; + return (1); +} +#endif /* PACKBITS_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_pixarlog.c b/libs/tiff/libtiff/tif_pixarlog.c new file mode 100644 index 00000000000..87c67097fc0 --- /dev/null +++ b/libs/tiff/libtiff/tif_pixarlog.c @@ -0,0 +1,1480 @@ +/* + * Copyright (c) 1996-1997 Sam Leffler + * Copyright (c) 1996 Pixar + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Pixar, Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Pixar, Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL PIXAR, SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef PIXARLOG_SUPPORT + +/* + * TIFF Library. + * PixarLog Compression Support + * + * Contributed by Dan McCoy. + * + * PixarLog film support uses the TIFF library to store companded + * 11 bit values into a tiff file, which are compressed using the + * zip compressor. + * + * The codec can take as input and produce as output 32-bit IEEE float values + * as well as 16-bit or 8-bit unsigned integer values. + * + * On writing any of the above are converted into the internal + * 11-bit log format. In the case of 8 and 16 bit values, the + * input is assumed to be unsigned linear color values that represent + * the range 0-1. In the case of IEEE values, the 0-1 range is assumed to + * be the normal linear color range, in addition over 1 values are + * accepted up to a value of about 25.0 to encode "hot" highlights and such. + * The encoding is lossless for 8-bit values, slightly lossy for the + * other bit depths. The actual color precision should be better + * than the human eye can perceive with extra room to allow for + * error introduced by further image computation. As with any quantized + * color format, it is possible to perform image calculations which + * expose the quantization error. This format should certainly be less + * susceptible to such errors than standard 8-bit encodings, but more + * susceptible than straight 16-bit or 32-bit encodings. + * + * On reading the internal format is converted to the desired output format. + * The program can request which format it desires by setting the internal + * pseudo tag TIFFTAG_PIXARLOGDATAFMT to one of these possible values: + * PIXARLOGDATAFMT_FLOAT = provide IEEE float values. + * PIXARLOGDATAFMT_16BIT = provide unsigned 16-bit integer values + * PIXARLOGDATAFMT_8BIT = provide unsigned 8-bit integer values + * + * alternately PIXARLOGDATAFMT_8BITABGR provides unsigned 8-bit integer + * values with the difference that if there are exactly three or four channels + * (rgb or rgba) it swaps the channel order (bgr or abgr). + * + * PIXARLOGDATAFMT_11BITLOG provides the internal encoding directly + * packed in 16-bit values. However no tools are supplied for interpreting + * these values. + * + * "hot" (over 1.0) areas written in floating point get clamped to + * 1.0 in the integer data types. + * + * When the file is closed after writing, the bit depth and sample format + * are set always to appear as if 8-bit data has been written into it. + * That way a naive program unaware of the particulars of the encoding + * gets the format it is most likely able to handle. + * + * The codec does it's own horizontal differencing step on the coded + * values so the libraries predictor stuff should be turned off. + * The codec also handle byte swapping the encoded values as necessary + * since the library does not have the information necessary + * to know the bit depth of the raw unencoded buffer. + * + * NOTE: This decoder does not appear to update tif_rawcp, and tif_rawcc. + * This can cause problems with the implementation of CHUNKY_STRIP_READ_SUPPORT + * as noted in http://trac.osgeo.org/gdal/ticket/3894. FrankW - Jan'11 + */ + +#include "tif_predict.h" +#include "zlib.h" + +#include +#include +#include + +/* Tables for converting to/from 11 bit coded values */ + +#define TSIZE 2048 /* decode table size (11-bit tokens) */ +#define TSIZEP1 2049 /* Plus one for slop */ +#define ONE 1250 /* token value of 1.0 exactly */ +#define RATIO 1.004 /* nominal ratio for log part */ + +#define CODE_MASK 0x7ff /* 11 bits. */ + +static float Fltsize; +static float LogK1, LogK2; + +#define REPEAT(n, op) { int i; i=n; do { i--; op; } while (i>0); } + +static void +horizontalAccumulateF(uint16_t *wp, int n, int stride, float *op, + float *ToLinearF) +{ + register unsigned int cr, cg, cb, ca, mask; + register float t0, t1, t2, t3; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + t0 = ToLinearF[cr = (wp[0] & mask)]; + t1 = ToLinearF[cg = (wp[1] & mask)]; + t2 = ToLinearF[cb = (wp[2] & mask)]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + t0 = ToLinearF[(cr += wp[0]) & mask]; + t1 = ToLinearF[(cg += wp[1]) & mask]; + t2 = ToLinearF[(cb += wp[2]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + } + } else if (stride == 4) { + t0 = ToLinearF[cr = (wp[0] & mask)]; + t1 = ToLinearF[cg = (wp[1] & mask)]; + t2 = ToLinearF[cb = (wp[2] & mask)]; + t3 = ToLinearF[ca = (wp[3] & mask)]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + t0 = ToLinearF[(cr += wp[0]) & mask]; + t1 = ToLinearF[(cg += wp[1]) & mask]; + t2 = ToLinearF[(cb += wp[2]) & mask]; + t3 = ToLinearF[(ca += wp[3]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else { + REPEAT(stride, *op = ToLinearF[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinearF[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate12(uint16_t *wp, int n, int stride, int16_t *op, + float *ToLinearF) +{ + register unsigned int cr, cg, cb, ca, mask; + register float t0, t1, t2, t3; + +#define SCALE12 2048.0F +#define CLAMP12(t) (((t) < 3071) ? (uint16_t) (t) : 3071) + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + t0 = ToLinearF[cr = (wp[0] & mask)] * SCALE12; + t1 = ToLinearF[cg = (wp[1] & mask)] * SCALE12; + t2 = ToLinearF[cb = (wp[2] & mask)] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12; + t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12; + t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + } + } else if (stride == 4) { + t0 = ToLinearF[cr = (wp[0] & mask)] * SCALE12; + t1 = ToLinearF[cg = (wp[1] & mask)] * SCALE12; + t2 = ToLinearF[cb = (wp[2] & mask)] * SCALE12; + t3 = ToLinearF[ca = (wp[3] & mask)] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + op[3] = CLAMP12(t3); + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12; + t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12; + t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12; + t3 = ToLinearF[(ca += wp[3]) & mask] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + op[3] = CLAMP12(t3); + } + } else { + REPEAT(stride, t0 = ToLinearF[*wp&mask] * SCALE12; + *op = CLAMP12(t0); wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; t0 = ToLinearF[wp[stride]&mask]*SCALE12; + *op = CLAMP12(t0); wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate16(uint16_t *wp, int n, int stride, uint16_t *op, + uint16_t *ToLinear16) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = ToLinear16[cr = (wp[0] & mask)]; + op[1] = ToLinear16[cg = (wp[1] & mask)]; + op[2] = ToLinear16[cb = (wp[2] & mask)]; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + op[0] = ToLinear16[(cr += wp[0]) & mask]; + op[1] = ToLinear16[(cg += wp[1]) & mask]; + op[2] = ToLinear16[(cb += wp[2]) & mask]; + } + } else if (stride == 4) { + op[0] = ToLinear16[cr = (wp[0] & mask)]; + op[1] = ToLinear16[cg = (wp[1] & mask)]; + op[2] = ToLinear16[cb = (wp[2] & mask)]; + op[3] = ToLinear16[ca = (wp[3] & mask)]; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + op[0] = ToLinear16[(cr += wp[0]) & mask]; + op[1] = ToLinear16[(cg += wp[1]) & mask]; + op[2] = ToLinear16[(cb += wp[2]) & mask]; + op[3] = ToLinear16[(ca += wp[3]) & mask]; + } + } else { + REPEAT(stride, *op = ToLinear16[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear16[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +/* + * Returns the log encoded 11-bit values with the horizontal + * differencing undone. + */ +static void +horizontalAccumulate11(uint16_t *wp, int n, int stride, uint16_t *op) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = wp[0]; op[1] = wp[1]; op[2] = wp[2]; + cr = wp[0]; cg = wp[1]; cb = wp[2]; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + op[0] = (uint16_t)((cr += wp[0]) & mask); + op[1] = (uint16_t)((cg += wp[1]) & mask); + op[2] = (uint16_t)((cb += wp[2]) & mask); + } + } else if (stride == 4) { + op[0] = wp[0]; op[1] = wp[1]; + op[2] = wp[2]; op[3] = wp[3]; + cr = wp[0]; cg = wp[1]; cb = wp[2]; ca = wp[3]; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + op[0] = (uint16_t)((cr += wp[0]) & mask); + op[1] = (uint16_t)((cg += wp[1]) & mask); + op[2] = (uint16_t)((cb += wp[2]) & mask); + op[3] = (uint16_t)((ca += wp[3]) & mask); + } + } else { + REPEAT(stride, *op = *wp&mask; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = *wp&mask; wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate8(uint16_t *wp, int n, int stride, unsigned char *op, + unsigned char *ToLinear8) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = ToLinear8[cr = (wp[0] & mask)]; + op[1] = ToLinear8[cg = (wp[1] & mask)]; + op[2] = ToLinear8[cb = (wp[2] & mask)]; + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + op += 3; + op[0] = ToLinear8[(cr += wp[0]) & mask]; + op[1] = ToLinear8[(cg += wp[1]) & mask]; + op[2] = ToLinear8[(cb += wp[2]) & mask]; + } + } else if (stride == 4) { + op[0] = ToLinear8[cr = (wp[0] & mask)]; + op[1] = ToLinear8[cg = (wp[1] & mask)]; + op[2] = ToLinear8[cb = (wp[2] & mask)]; + op[3] = ToLinear8[ca = (wp[3] & mask)]; + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + op += 4; + op[0] = ToLinear8[(cr += wp[0]) & mask]; + op[1] = ToLinear8[(cg += wp[1]) & mask]; + op[2] = ToLinear8[(cb += wp[2]) & mask]; + op[3] = ToLinear8[(ca += wp[3]) & mask]; + } + } else { + REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + + +static void +horizontalAccumulate8abgr(uint16_t *wp, int n, int stride, unsigned char *op, + unsigned char *ToLinear8) +{ + register unsigned int cr, cg, cb, ca, mask; + register unsigned char t0, t1, t2, t3; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = 0; + t1 = ToLinear8[cb = (wp[2] & mask)]; + t2 = ToLinear8[cg = (wp[1] & mask)]; + t3 = ToLinear8[cr = (wp[0] & mask)]; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + op += 4; + op[0] = 0; + t1 = ToLinear8[(cb += wp[2]) & mask]; + t2 = ToLinear8[(cg += wp[1]) & mask]; + t3 = ToLinear8[(cr += wp[0]) & mask]; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else if (stride == 4) { + t0 = ToLinear8[ca = (wp[3] & mask)]; + t1 = ToLinear8[cb = (wp[2] & mask)]; + t2 = ToLinear8[cg = (wp[1] & mask)]; + t3 = ToLinear8[cr = (wp[0] & mask)]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + op += 4; + t0 = ToLinear8[(ca += wp[3]) & mask]; + t1 = ToLinear8[(cb += wp[2]) & mask]; + t2 = ToLinear8[(cg += wp[1]) & mask]; + t3 = ToLinear8[(cr += wp[0]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else { + REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +/* + * State block for each open TIFF + * file using PixarLog compression/decompression. + */ +typedef struct { + TIFFPredictorState predict; + z_stream stream; + tmsize_t tbuf_size; /* only set/used on reading for now */ + uint16_t *tbuf; + uint16_t stride; + int state; + int user_datafmt; + int quality; +#define PLSTATE_INIT 1 + + TIFFVSetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + + float *ToLinearF; + uint16_t *ToLinear16; + unsigned char *ToLinear8; + uint16_t *FromLT2; + uint16_t *From14; /* Really for 16-bit data, but we shift down 2 */ + uint16_t *From8; + +} PixarLogState; + +static int +PixarLogMakeTables(PixarLogState *sp) +{ + +/* + * We make several tables here to convert between various external + * representations (float, 16-bit, and 8-bit) and the internal + * 11-bit companded representation. The 11-bit representation has two + * distinct regions. A linear bottom end up through .018316 in steps + * of about .000073, and a region of constant ratio up to about 25. + * These floating point numbers are stored in the main table ToLinearF. + * All other tables are derived from this one. The tables (and the + * ratios) are continuous at the internal seam. + */ + + int nlin, lt2size; + int i, j; + double b, c, linstep, v; + float *ToLinearF; + uint16_t *ToLinear16; + unsigned char *ToLinear8; + uint16_t *FromLT2; + uint16_t *From14; /* Really for 16-bit data, but we shift down 2 */ + uint16_t *From8; + + c = log(RATIO); + nlin = (int)(1./c); /* nlin must be an integer */ + c = 1./nlin; + b = exp(-c*ONE); /* multiplicative scale factor [b*exp(c*ONE) = 1] */ + linstep = b*c*exp(1.); + + LogK1 = (float)(1./c); /* if (v >= 2) token = k1*log(v*k2) */ + LogK2 = (float)(1./b); + lt2size = (int)(2./linstep) + 1; + FromLT2 = (uint16_t *)_TIFFmalloc(lt2size * sizeof(uint16_t)); + From14 = (uint16_t *)_TIFFmalloc(16384 * sizeof(uint16_t)); + From8 = (uint16_t *)_TIFFmalloc(256 * sizeof(uint16_t)); + ToLinearF = (float *)_TIFFmalloc(TSIZEP1 * sizeof(float)); + ToLinear16 = (uint16_t *)_TIFFmalloc(TSIZEP1 * sizeof(uint16_t)); + ToLinear8 = (unsigned char *)_TIFFmalloc(TSIZEP1 * sizeof(unsigned char)); + if (FromLT2 == NULL || From14 == NULL || From8 == NULL || + ToLinearF == NULL || ToLinear16 == NULL || ToLinear8 == NULL) { + if (FromLT2) _TIFFfree(FromLT2); + if (From14) _TIFFfree(From14); + if (From8) _TIFFfree(From8); + if (ToLinearF) _TIFFfree(ToLinearF); + if (ToLinear16) _TIFFfree(ToLinear16); + if (ToLinear8) _TIFFfree(ToLinear8); + sp->FromLT2 = NULL; + sp->From14 = NULL; + sp->From8 = NULL; + sp->ToLinearF = NULL; + sp->ToLinear16 = NULL; + sp->ToLinear8 = NULL; + return 0; + } + + j = 0; + + for (i = 0; i < nlin; i++) { + v = i * linstep; + ToLinearF[j++] = (float)v; + } + + for (i = nlin; i < TSIZE; i++) + ToLinearF[j++] = (float)(b*exp(c*i)); + + ToLinearF[2048] = ToLinearF[2047]; + + for (i = 0; i < TSIZEP1; i++) { + v = ToLinearF[i]*65535.0 + 0.5; + ToLinear16[i] = (v > 65535.0) ? 65535 : (uint16_t)v; + v = ToLinearF[i]*255.0 + 0.5; + ToLinear8[i] = (v > 255.0) ? 255 : (unsigned char)v; + } + + j = 0; + for (i = 0; i < lt2size; i++) { + if ((i*linstep)*(i*linstep) > ToLinearF[j]*ToLinearF[j+1]) + j++; + FromLT2[i] = (uint16_t)j; + } + + /* + * Since we lose info anyway on 16-bit data, we set up a 14-bit + * table and shift 16-bit values down two bits on input. + * saves a little table space. + */ + j = 0; + for (i = 0; i < 16384; i++) { + while ((i/16383.)*(i/16383.) > ToLinearF[j]*ToLinearF[j+1]) + j++; + From14[i] = (uint16_t)j; + } + + j = 0; + for (i = 0; i < 256; i++) { + while ((i/255.)*(i/255.) > ToLinearF[j]*ToLinearF[j+1]) + j++; + From8[i] = (uint16_t)j; + } + + Fltsize = (float)(lt2size/2); + + sp->ToLinearF = ToLinearF; + sp->ToLinear16 = ToLinear16; + sp->ToLinear8 = ToLinear8; + sp->FromLT2 = FromLT2; + sp->From14 = From14; + sp->From8 = From8; + + return 1; +} + +#define DecoderState(tif) ((PixarLogState*) (tif)->tif_data) +#define EncoderState(tif) ((PixarLogState*) (tif)->tif_data) + +static int PixarLogEncode(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s); +static int PixarLogDecode(TIFF* tif, uint8_t* op, tmsize_t occ, uint16_t s); + +#define PIXARLOGDATAFMT_UNKNOWN -1 + +static int +PixarLogGuessDataFmt(TIFFDirectory *td) +{ + int guess = PIXARLOGDATAFMT_UNKNOWN; + int format = td->td_sampleformat; + + /* If the user didn't tell us his datafmt, + * take our best guess from the bitspersample. + */ + switch (td->td_bitspersample) { + case 32: + if (format == SAMPLEFORMAT_IEEEFP) + guess = PIXARLOGDATAFMT_FLOAT; + break; + case 16: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_16BIT; + break; + case 12: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_INT) + guess = PIXARLOGDATAFMT_12BITPICIO; + break; + case 11: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_11BITLOG; + break; + case 8: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_8BIT; + break; + } + + return guess; +} + +static tmsize_t +multiply_ms(tmsize_t m1, tmsize_t m2) +{ + return _TIFFMultiplySSize(NULL, m1, m2, NULL); +} + +static tmsize_t +add_ms(tmsize_t m1, tmsize_t m2) +{ + assert(m1 >= 0 && m2 >= 0); + /* if either input is zero, assume overflow already occurred */ + if (m1 == 0 || m2 == 0) + return 0; + else if (m1 > TIFF_TMSIZE_T_MAX - m2) + return 0; + + return m1 + m2; +} + +static int +PixarLogFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +static int +PixarLogSetupDecode(TIFF* tif) +{ + static const char module[] = "PixarLogSetupDecode"; + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = DecoderState(tif); + tmsize_t tbuf_size; + uint32_t strip_height; + + assert(sp != NULL); + + /* This function can possibly be called several times by */ + /* PredictorSetupDecode() if this function succeeds but */ + /* PredictorSetup() fails */ + if( (sp->state & PLSTATE_INIT) != 0 ) + return 1; + + strip_height = td->td_rowsperstrip; + if( strip_height > td->td_imagelength ) + strip_height = td->td_imagelength; + + /* Make sure no byte swapping happens on the data + * after decompression. */ + tif->tif_postdecode = _TIFFNoPostDecode; + + /* for some reason, we can't do this in TIFFInitPixarLog */ + + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + tbuf_size = multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth), + strip_height), sizeof(uint16_t)); + /* add one more stride in case input ends mid-stride */ + tbuf_size = add_ms(tbuf_size, sizeof(uint16_t) * sp->stride); + if (tbuf_size == 0) + return (0); /* TODO: this is an error return without error report through TIFFErrorExt */ + sp->tbuf = (uint16_t *) _TIFFmalloc(tbuf_size); + if (sp->tbuf == NULL) + return (0); + sp->tbuf_size = tbuf_size; + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) + sp->user_datafmt = PixarLogGuessDataFmt(td); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) { + _TIFFfree(sp->tbuf); + sp->tbuf = NULL; + sp->tbuf_size = 0; + TIFFErrorExt(tif->tif_clientdata, module, + "PixarLog compression can't handle bits depth/data format combination (depth: %"PRIu16")", + td->td_bitspersample); + return (0); + } + + if (inflateInit(&sp->stream) != Z_OK) { + _TIFFfree(sp->tbuf); + sp->tbuf = NULL; + sp->tbuf_size = 0; + TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg ? sp->stream.msg : "(null)"); + return (0); + } else { + sp->state |= PLSTATE_INIT; + return (1); + } +} + +/* + * Setup state for decoding a strip. + */ +static int +PixarLogPreDecode(TIFF* tif, uint16_t s) +{ + static const char module[] = "PixarLogPreDecode"; + PixarLogState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + sp->stream.next_in = tif->tif_rawdata; + assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + appropriately even before we simplify it */ + sp->stream.avail_in = (uInt) tif->tif_rawcc; + if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc) + { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size"); + return (0); + } + return (inflateReset(&sp->stream) == Z_OK); +} + +static int +PixarLogDecode(TIFF* tif, uint8_t* op, tmsize_t occ, uint16_t s) +{ + static const char module[] = "PixarLogDecode"; + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = DecoderState(tif); + tmsize_t i; + tmsize_t nsamples; + int llen; + uint16_t *up; + + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + nsamples = occ / sizeof(float); /* XXX float == 32 bits */ + break; + case PIXARLOGDATAFMT_16BIT: + case PIXARLOGDATAFMT_12BITPICIO: + case PIXARLOGDATAFMT_11BITLOG: + nsamples = occ / sizeof(uint16_t); /* XXX uint16_t == 16 bits */ + break; + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + nsamples = occ; + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "%"PRIu16" bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + + llen = sp->stride * td->td_imagewidth; + + (void) s; + assert(sp != NULL); + + sp->stream.next_in = tif->tif_rawcp; + sp->stream.avail_in = (uInt) tif->tif_rawcc; + + sp->stream.next_out = (unsigned char *) sp->tbuf; + assert(sizeof(sp->stream.avail_out)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + appropriately even before we simplify it */ + sp->stream.avail_out = (uInt) (nsamples * sizeof(uint16_t)); + if (sp->stream.avail_out != nsamples * sizeof(uint16_t)) + { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size"); + return (0); + } + /* Check that we will not fill more than what was allocated */ + if ((tmsize_t)sp->stream.avail_out > sp->tbuf_size) + { + TIFFErrorExt(tif->tif_clientdata, module, "sp->stream.avail_out > sp->tbuf_size"); + return (0); + } + do { + int state = inflate(&sp->stream, Z_PARTIAL_FLUSH); + if (state == Z_STREAM_END) { + break; /* XXX */ + } + if (state == Z_DATA_ERROR) { + TIFFErrorExt(tif->tif_clientdata, module, + "Decoding error at scanline %"PRIu32", %s", + tif->tif_row, sp->stream.msg ? sp->stream.msg : "(null)"); + return (0); + } + if (state != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", + sp->stream.msg ? sp->stream.msg : "(null)"); + return (0); + } + } while (sp->stream.avail_out > 0); + + /* hopefully, we got all the bytes we needed */ + if (sp->stream.avail_out != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %"PRIu32" (short %u bytes)", + tif->tif_row, sp->stream.avail_out); + return (0); + } + + tif->tif_rawcp = sp->stream.next_in; + tif->tif_rawcc = sp->stream.avail_in; + + up = sp->tbuf; + /* Swap bytes in the data if from a different endian machine. */ + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabArrayOfShort(up, nsamples); + + /* + * if llen is not an exact multiple of nsamples, the decode operation + * may overflow the output buffer, so truncate it enough to prevent + * that but still salvage as much data as possible. + */ + if (nsamples % llen) { + TIFFWarningExt(tif->tif_clientdata, module, + "stride %d is not a multiple of sample count, " + "%"TIFF_SSIZE_FORMAT", data truncated.", llen, nsamples); + nsamples -= nsamples % llen; + } + + for (i = 0; i < nsamples; i += llen, up += llen) { + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + horizontalAccumulateF(up, llen, sp->stride, + (float *)op, sp->ToLinearF); + op += llen * sizeof(float); + break; + case PIXARLOGDATAFMT_16BIT: + horizontalAccumulate16(up, llen, sp->stride, + (uint16_t *)op, sp->ToLinear16); + op += llen * sizeof(uint16_t); + break; + case PIXARLOGDATAFMT_12BITPICIO: + horizontalAccumulate12(up, llen, sp->stride, + (int16_t *)op, sp->ToLinearF); + op += llen * sizeof(int16_t); + break; + case PIXARLOGDATAFMT_11BITLOG: + horizontalAccumulate11(up, llen, sp->stride, + (uint16_t *)op); + op += llen * sizeof(uint16_t); + break; + case PIXARLOGDATAFMT_8BIT: + horizontalAccumulate8(up, llen, sp->stride, + (unsigned char *)op, sp->ToLinear8); + op += llen * sizeof(unsigned char); + break; + case PIXARLOGDATAFMT_8BITABGR: + horizontalAccumulate8abgr(up, llen, sp->stride, + (unsigned char *)op, sp->ToLinear8); + op += llen * sizeof(unsigned char); + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "Unsupported bits/sample: %"PRIu16, + td->td_bitspersample); + return (0); + } + } + + return (1); +} + +static int +PixarLogSetupEncode(TIFF* tif) +{ + static const char module[] = "PixarLogSetupEncode"; + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = EncoderState(tif); + tmsize_t tbuf_size; + + assert(sp != NULL); + + /* for some reason, we can't do this in TIFFInitPixarLog */ + + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + tbuf_size = multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth), + td->td_rowsperstrip), sizeof(uint16_t)); + if (tbuf_size == 0) + return (0); /* TODO: this is an error return without error report through TIFFErrorExt */ + sp->tbuf = (uint16_t *) _TIFFmalloc(tbuf_size); + if (sp->tbuf == NULL) + return (0); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) + sp->user_datafmt = PixarLogGuessDataFmt(td); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) { + TIFFErrorExt(tif->tif_clientdata, module, "PixarLog compression can't handle %"PRIu16" bit linear encodings", td->td_bitspersample); + return (0); + } + + if (deflateInit(&sp->stream, sp->quality) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s", sp->stream.msg ? sp->stream.msg : "(null)"); + return (0); + } else { + sp->state |= PLSTATE_INIT; + return (1); + } +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +PixarLogPreEncode(TIFF* tif, uint16_t s) +{ + static const char module[] = "PixarLogPreEncode"; + PixarLogState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + sp->stream.next_out = tif->tif_rawdata; + assert(sizeof(sp->stream.avail_out)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + appropriately even before we simplify it */ + sp->stream.avail_out = (uInt)tif->tif_rawdatasize; + if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) + { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size"); + return (0); + } + return (deflateReset(&sp->stream) == Z_OK); +} + +static void +horizontalDifferenceF(float *ip, int n, int stride, uint16_t *wp, uint16_t *FromLT2) +{ + int32_t r1, g1, b1, a1, r2, g2, b2, a2, mask; + float fltsize = Fltsize; + +#define CLAMP(v) ( (v<(float)0.) ? 0 \ + : (v<(float)2.) ? FromLT2[(int)(v*fltsize)] \ + : (v>(float)24.2) ? 2047 \ + : LogK1*log(v*LogK2) + 0.5 ) + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = (uint16_t) CLAMP(ip[0]); + g2 = wp[1] = (uint16_t) CLAMP(ip[1]); + b2 = wp[2] = (uint16_t) CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + ip += 3; + r1 = (int32_t) CLAMP(ip[0]); wp[0] = (uint16_t)((r1 - r2) & mask); r2 = r1; + g1 = (int32_t) CLAMP(ip[1]); wp[1] = (uint16_t)((g1 - g2) & mask); g2 = g1; + b1 = (int32_t) CLAMP(ip[2]); wp[2] = (uint16_t)((b1 - b2) & mask); b2 = b1; + } + } else if (stride == 4) { + r2 = wp[0] = (uint16_t) CLAMP(ip[0]); + g2 = wp[1] = (uint16_t) CLAMP(ip[1]); + b2 = wp[2] = (uint16_t) CLAMP(ip[2]); + a2 = wp[3] = (uint16_t) CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + ip += 4; + r1 = (int32_t) CLAMP(ip[0]); wp[0] = (uint16_t)((r1 - r2) & mask); r2 = r1; + g1 = (int32_t) CLAMP(ip[1]); wp[1] = (uint16_t)((g1 - g2) & mask); g2 = g1; + b1 = (int32_t) CLAMP(ip[2]); wp[2] = (uint16_t)((b1 - b2) & mask); b2 = b1; + a1 = (int32_t) CLAMP(ip[3]); wp[3] = (uint16_t)((a1 - a2) & mask); a2 = a1; + } + } else { + REPEAT(stride, wp[0] = (uint16_t) CLAMP(ip[0]); wp++; ip++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[0] = (uint16_t)(((int32_t)CLAMP(ip[0]) - (int32_t)CLAMP(ip[-stride])) & mask); + wp++; ip++) + n -= stride; + } + } + } +} + +static void +horizontalDifference16(unsigned short *ip, int n, int stride, + unsigned short *wp, uint16_t *From14) +{ + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; + +/* assumption is unsigned pixel values */ +#undef CLAMP +#define CLAMP(v) From14[(v) >> 2] + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + ip += 3; + r1 = CLAMP(ip[0]); wp[0] = (uint16_t)((r1 - r2) & mask); r2 = r1; + g1 = CLAMP(ip[1]); wp[1] = (uint16_t)((g1 - g2) & mask); g2 = g1; + b1 = CLAMP(ip[2]); wp[2] = (uint16_t)((b1 - b2) & mask); b2 = b1; + } + } else if (stride == 4) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + ip += 4; + r1 = CLAMP(ip[0]); wp[0] = (uint16_t)((r1 - r2) & mask); r2 = r1; + g1 = CLAMP(ip[1]); wp[1] = (uint16_t)((g1 - g2) & mask); g2 = g1; + b1 = CLAMP(ip[2]); wp[2] = (uint16_t)((b1 - b2) & mask); b2 = b1; + a1 = CLAMP(ip[3]); wp[3] = (uint16_t)((a1 - a2) & mask); a2 = a1; + } + } else { + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp++; ip++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[0] = (uint16_t)((CLAMP(ip[0]) - CLAMP(ip[-stride])) & mask); + wp++; ip++) + n -= stride; + } + } + } +} + + +static void +horizontalDifference8(unsigned char *ip, int n, int stride, + unsigned short *wp, uint16_t *From8) +{ + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; + +#undef CLAMP +#define CLAMP(v) (From8[(v)]) + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + r1 = CLAMP(ip[3]); wp[3] = (uint16_t)((r1 - r2) & mask); r2 = r1; + g1 = CLAMP(ip[4]); wp[4] = (uint16_t)((g1 - g2) & mask); g2 = g1; + b1 = CLAMP(ip[5]); wp[5] = (uint16_t)((b1 - b2) & mask); b2 = b1; + wp += 3; + ip += 3; + } + } else if (stride == 4) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + r1 = CLAMP(ip[4]); wp[4] = (uint16_t)((r1 - r2) & mask); r2 = r1; + g1 = CLAMP(ip[5]); wp[5] = (uint16_t)((g1 - g2) & mask); g2 = g1; + b1 = CLAMP(ip[6]); wp[6] = (uint16_t)((b1 - b2) & mask); b2 = b1; + a1 = CLAMP(ip[7]); wp[7] = (uint16_t)((a1 - a2) & mask); a2 = a1; + wp += 4; + ip += 4; + } + } else { + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp++; ip++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[0] = (uint16_t)((CLAMP(ip[0]) - CLAMP(ip[-stride])) & mask); + wp++; ip++) + n -= stride; + } + } + } +} + +/* + * Encode a chunk of pixels. + */ +static int +PixarLogEncode(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "PixarLogEncode"; + TIFFDirectory *td = &tif->tif_dir; + PixarLogState *sp = EncoderState(tif); + tmsize_t i; + tmsize_t n; + int llen; + unsigned short * up; + + (void) s; + + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + n = cc / sizeof(float); /* XXX float == 32 bits */ + break; + case PIXARLOGDATAFMT_16BIT: + case PIXARLOGDATAFMT_12BITPICIO: + case PIXARLOGDATAFMT_11BITLOG: + n = cc / sizeof(uint16_t); /* XXX uint16_t == 16 bits */ + break; + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + n = cc; + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "%"PRIu16" bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + + llen = sp->stride * td->td_imagewidth; + /* Check against the number of elements (of size uint16_t) of sp->tbuf */ + if( n > ((tmsize_t)td->td_rowsperstrip * llen) ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Too many input bytes provided"); + return 0; + } + + for (i = 0, up = sp->tbuf; i < n; i += llen, up += llen) { + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + horizontalDifferenceF((float *)bp, llen, + sp->stride, up, sp->FromLT2); + bp += llen * sizeof(float); + break; + case PIXARLOGDATAFMT_16BIT: + horizontalDifference16((uint16_t *)bp, llen, + sp->stride, up, sp->From14); + bp += llen * sizeof(uint16_t); + break; + case PIXARLOGDATAFMT_8BIT: + horizontalDifference8((unsigned char *)bp, llen, + sp->stride, up, sp->From8); + bp += llen * sizeof(unsigned char); + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "%"PRIu16" bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + } + + sp->stream.next_in = (unsigned char *) sp->tbuf; + assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + appropriately even before we simplify it */ + sp->stream.avail_in = (uInt) (n * sizeof(uint16_t)); + if ((sp->stream.avail_in / sizeof(uint16_t)) != (uInt) n) + { + TIFFErrorExt(tif->tif_clientdata, module, + "ZLib cannot deal with buffers this size"); + return (0); + } + + do { + if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "Encoder error: %s", + sp->stream.msg ? sp->stream.msg : "(null)"); + return (0); + } + if (sp->stream.avail_out == 0) { + tif->tif_rawcc = tif->tif_rawdatasize; + if (!TIFFFlushData1(tif)) + return 0; + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (uInt) tif->tif_rawdatasize; /* this is a safe typecast, as check is made already in PixarLogPreEncode */ + } + } while (sp->stream.avail_in > 0); + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ + +static int +PixarLogPostEncode(TIFF* tif) +{ + static const char module[] = "PixarLogPostEncode"; + PixarLogState *sp = EncoderState(tif); + int state; + + sp->stream.avail_in = 0; + + do { + state = deflate(&sp->stream, Z_FINISH); + switch (state) { + case Z_STREAM_END: + case Z_OK: + if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) { + tif->tif_rawcc = + tif->tif_rawdatasize - sp->stream.avail_out; + if (!TIFFFlushData1(tif)) + return 0; + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (uInt) tif->tif_rawdatasize; /* this is a safe typecast, as check is made already in PixarLogPreEncode */ + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", + sp->stream.msg ? sp->stream.msg : "(null)"); + return (0); + } + } while (state != Z_STREAM_END); + return (1); +} + +static void +PixarLogClose(TIFF* tif) +{ + PixarLogState* sp = (PixarLogState*) tif->tif_data; + TIFFDirectory *td = &tif->tif_dir; + + assert(sp != 0); + /* In a really sneaky (and really incorrect, and untruthful, and + * troublesome, and error-prone) maneuver that completely goes against + * the spirit of TIFF, and breaks TIFF, on close, we covertly + * modify both bitspersample and sampleformat in the directory to + * indicate 8-bit linear. This way, the decode "just works" even for + * readers that don't know about PixarLog, or how to set + * the PIXARLOGDATFMT pseudo-tag. + */ + + if (sp->state&PLSTATE_INIT) { + /* We test the state to avoid an issue such as in + * http://bugzilla.maptools.org/show_bug.cgi?id=2604 + * What appends in that case is that the bitspersample is 1 and + * a TransferFunction is set. The size of the TransferFunction + * depends on 1<td_bitspersample = 8; + td->td_sampleformat = SAMPLEFORMAT_UINT; + } +} + +static void +PixarLogCleanup(TIFF* tif) +{ + PixarLogState* sp = (PixarLogState*) tif->tif_data; + + assert(sp != 0); + + (void)TIFFPredictorCleanup(tif); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->FromLT2) _TIFFfree(sp->FromLT2); + if (sp->From14) _TIFFfree(sp->From14); + if (sp->From8) _TIFFfree(sp->From8); + if (sp->ToLinearF) _TIFFfree(sp->ToLinearF); + if (sp->ToLinear16) _TIFFfree(sp->ToLinear16); + if (sp->ToLinear8) _TIFFfree(sp->ToLinear8); + if (sp->state&PLSTATE_INIT) { + if (tif->tif_mode == O_RDONLY) + inflateEnd(&sp->stream); + else + deflateEnd(&sp->stream); + } + if (sp->tbuf) + _TIFFfree(sp->tbuf); + _TIFFfree(sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int +PixarLogVSetField(TIFF* tif, uint32_t tag, va_list ap) +{ + static const char module[] = "PixarLogVSetField"; + PixarLogState *sp = (PixarLogState *)tif->tif_data; + int result; + + switch (tag) { + case TIFFTAG_PIXARLOGQUALITY: + sp->quality = (int) va_arg(ap, int); + if (tif->tif_mode != O_RDONLY && (sp->state&PLSTATE_INIT)) { + if (deflateParams(&sp->stream, + sp->quality, Z_DEFAULT_STRATEGY) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", + sp->stream.msg ? sp->stream.msg : "(null)"); + return (0); + } + } + return (1); + case TIFFTAG_PIXARLOGDATAFMT: + sp->user_datafmt = (int) va_arg(ap, int); + /* Tweak the TIFF header so that the rest of libtiff knows what + * size of data will be passed between app and library, and + * assume that the app knows what it is doing and is not + * confused by these header manipulations... + */ + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_11BITLOG: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_12BITPICIO: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + break; + case PIXARLOGDATAFMT_16BIT: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_FLOAT: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); + break; + } + /* + * Must recalculate sizes should bits/sample change. + */ + tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t)(-1); + tif->tif_scanlinesize = TIFFScanlineSize(tif); + result = 1; /* NB: pseudo tag */ + break; + default: + result = (*sp->vsetparent)(tif, tag, ap); + } + return (result); +} + +static int +PixarLogVGetField(TIFF* tif, uint32_t tag, va_list ap) +{ + PixarLogState *sp = (PixarLogState *)tif->tif_data; + + switch (tag) { + case TIFFTAG_PIXARLOGQUALITY: + *va_arg(ap, int*) = sp->quality; + break; + case TIFFTAG_PIXARLOGDATAFMT: + *va_arg(ap, int*) = sp->user_datafmt; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static const TIFFField pixarlogFields[] = { + {TIFFTAG_PIXARLOGDATAFMT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL}, + {TIFFTAG_PIXARLOGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL} +}; + +int +TIFFInitPixarLog(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitPixarLog"; + + PixarLogState* sp; + + (void)scheme; + assert(scheme == COMPRESSION_PIXARLOG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, pixarlogFields, + TIFFArrayCount(pixarlogFields))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging PixarLog codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t*) _TIFFmalloc(sizeof (PixarLogState)); + if (tif->tif_data == NULL) + goto bad; + sp = (PixarLogState*) tif->tif_data; + _TIFFmemset(sp, 0, sizeof (*sp)); + sp->stream.data_type = Z_BINARY; + sp->user_datafmt = PIXARLOGDATAFMT_UNKNOWN; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = PixarLogFixupTags; + tif->tif_setupdecode = PixarLogSetupDecode; + tif->tif_predecode = PixarLogPreDecode; + tif->tif_decoderow = PixarLogDecode; + tif->tif_decodestrip = PixarLogDecode; + tif->tif_decodetile = PixarLogDecode; + tif->tif_setupencode = PixarLogSetupEncode; + tif->tif_preencode = PixarLogPreEncode; + tif->tif_postencode = PixarLogPostEncode; + tif->tif_encoderow = PixarLogEncode; + tif->tif_encodestrip = PixarLogEncode; + tif->tif_encodetile = PixarLogEncode; + tif->tif_close = PixarLogClose; + tif->tif_cleanup = PixarLogCleanup; + + /* Override SetField so we can handle our private pseudo-tag */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = PixarLogVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = PixarLogVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->quality = Z_DEFAULT_COMPRESSION; /* default comp. level */ + sp->state = 0; + + /* we don't wish to use the predictor, + * the default is none, which predictor value 1 + */ + (void) TIFFPredictorInit(tif); + + /* + * build the companding tables + */ + PixarLogMakeTables(sp); + + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "No space for PixarLog state block"); + return (0); +} +#endif /* PIXARLOG_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_predict.c b/libs/tiff/libtiff/tif_predict.c new file mode 100644 index 00000000000..4aa4af69e3a --- /dev/null +++ b/libs/tiff/libtiff/tif_predict.c @@ -0,0 +1,879 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Predictor Tag Support (used by multiple codecs). + */ +#include "tiffiop.h" +#include "tif_predict.h" + +#define PredictorState(tif) ((TIFFPredictorState*) (tif)->tif_data) + +static int horAcc8(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int horAcc16(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int horAcc32(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int swabHorAcc16(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int swabHorAcc32(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int horDiff8(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int horDiff16(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int horDiff32(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int swabHorDiff16(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int swabHorDiff32(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int fpAcc(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int fpDiff(TIFF* tif, uint8_t* cp0, tmsize_t cc); +static int PredictorDecodeRow(TIFF* tif, uint8_t* op0, tmsize_t occ0, uint16_t s); +static int PredictorDecodeTile(TIFF* tif, uint8_t* op0, tmsize_t occ0, uint16_t s); +static int PredictorEncodeRow(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s); +static int PredictorEncodeTile(TIFF* tif, uint8_t* bp0, tmsize_t cc0, uint16_t s); + +static int +PredictorSetup(TIFF* tif) +{ + static const char module[] = "PredictorSetup"; + + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + switch (sp->predictor) /* no differencing */ + { + case PREDICTOR_NONE: + return 1; + case PREDICTOR_HORIZONTAL: + if (td->td_bitspersample != 8 + && td->td_bitspersample != 16 + && td->td_bitspersample != 32) { + TIFFErrorExt(tif->tif_clientdata, module, + "Horizontal differencing \"Predictor\" not supported with %"PRIu16"-bit samples", + td->td_bitspersample); + return 0; + } + break; + case PREDICTOR_FLOATINGPOINT: + if (td->td_sampleformat != SAMPLEFORMAT_IEEEFP) { + TIFFErrorExt(tif->tif_clientdata, module, + "Floating point \"Predictor\" not supported with %"PRIu16" data format", + td->td_sampleformat); + return 0; + } + if (td->td_bitspersample != 16 + && td->td_bitspersample != 24 + && td->td_bitspersample != 32 + && td->td_bitspersample != 64) { /* Should 64 be allowed? */ + TIFFErrorExt(tif->tif_clientdata, module, + "Floating point \"Predictor\" not supported with %"PRIu16"-bit samples", + td->td_bitspersample); + return 0; + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "\"Predictor\" value %d not supported", + sp->predictor); + return 0; + } + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + /* + * Calculate the scanline/tile-width size in bytes. + */ + if (isTiled(tif)) + sp->rowsize = TIFFTileRowSize(tif); + else + sp->rowsize = TIFFScanlineSize(tif); + if (sp->rowsize == 0) + return 0; + + return 1; +} + +static int +PredictorSetupDecode(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + /* Note: when PredictorSetup() fails, the effets of setupdecode() */ + /* will not be "canceled" so setupdecode() might be robust to */ + /* be called several times. */ + if (!(*sp->setupdecode)(tif) || !PredictorSetup(tif)) + return 0; + + if (sp->predictor == 2) { + switch (td->td_bitspersample) { + case 8: sp->decodepfunc = horAcc8; break; + case 16: sp->decodepfunc = horAcc16; break; + case 32: sp->decodepfunc = horAcc32; break; + } + /* + * Override default decoding method with one that does the + * predictor stuff. + */ + if( tif->tif_decoderow != PredictorDecodeRow ) + { + sp->decoderow = tif->tif_decoderow; + tif->tif_decoderow = PredictorDecodeRow; + sp->decodestrip = tif->tif_decodestrip; + tif->tif_decodestrip = PredictorDecodeTile; + sp->decodetile = tif->tif_decodetile; + tif->tif_decodetile = PredictorDecodeTile; + } + + /* + * If the data is horizontally differenced 16-bit data that + * requires byte-swapping, then it must be byte swapped before + * the accumulation step. We do this with a special-purpose + * routine and override the normal post decoding logic that + * the library setup when the directory was read. + */ + if (tif->tif_flags & TIFF_SWAB) { + if (sp->decodepfunc == horAcc16) { + sp->decodepfunc = swabHorAcc16; + tif->tif_postdecode = _TIFFNoPostDecode; + } else if (sp->decodepfunc == horAcc32) { + sp->decodepfunc = swabHorAcc32; + tif->tif_postdecode = _TIFFNoPostDecode; + } + } + } + + else if (sp->predictor == 3) { + sp->decodepfunc = fpAcc; + /* + * Override default decoding method with one that does the + * predictor stuff. + */ + if( tif->tif_decoderow != PredictorDecodeRow ) + { + sp->decoderow = tif->tif_decoderow; + tif->tif_decoderow = PredictorDecodeRow; + sp->decodestrip = tif->tif_decodestrip; + tif->tif_decodestrip = PredictorDecodeTile; + sp->decodetile = tif->tif_decodetile; + tif->tif_decodetile = PredictorDecodeTile; + } + /* + * The data should not be swapped outside of the floating + * point predictor, the accumulation routine should return + * byres in the native order. + */ + if (tif->tif_flags & TIFF_SWAB) { + tif->tif_postdecode = _TIFFNoPostDecode; + } + /* + * Allocate buffer to keep the decoded bytes before + * rearranging in the right order + */ + } + + return 1; +} + +static int +PredictorSetupEncode(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + if (!(*sp->setupencode)(tif) || !PredictorSetup(tif)) + return 0; + + if (sp->predictor == 2) { + switch (td->td_bitspersample) { + case 8: sp->encodepfunc = horDiff8; break; + case 16: sp->encodepfunc = horDiff16; break; + case 32: sp->encodepfunc = horDiff32; break; + } + /* + * Override default encoding method with one that does the + * predictor stuff. + */ + if( tif->tif_encoderow != PredictorEncodeRow ) + { + sp->encoderow = tif->tif_encoderow; + tif->tif_encoderow = PredictorEncodeRow; + sp->encodestrip = tif->tif_encodestrip; + tif->tif_encodestrip = PredictorEncodeTile; + sp->encodetile = tif->tif_encodetile; + tif->tif_encodetile = PredictorEncodeTile; + } + + /* + * If the data is horizontally differenced 16-bit data that + * requires byte-swapping, then it must be byte swapped after + * the differentiation step. We do this with a special-purpose + * routine and override the normal post decoding logic that + * the library setup when the directory was read. + */ + if (tif->tif_flags & TIFF_SWAB) { + if (sp->encodepfunc == horDiff16) { + sp->encodepfunc = swabHorDiff16; + tif->tif_postdecode = _TIFFNoPostDecode; + } else if (sp->encodepfunc == horDiff32) { + sp->encodepfunc = swabHorDiff32; + tif->tif_postdecode = _TIFFNoPostDecode; + } + } + } + + else if (sp->predictor == 3) { + sp->encodepfunc = fpDiff; + /* + * Override default encoding method with one that does the + * predictor stuff. + */ + if( tif->tif_encoderow != PredictorEncodeRow ) + { + sp->encoderow = tif->tif_encoderow; + tif->tif_encoderow = PredictorEncodeRow; + sp->encodestrip = tif->tif_encodestrip; + tif->tif_encodestrip = PredictorEncodeTile; + sp->encodetile = tif->tif_encodetile; + tif->tif_encodetile = PredictorEncodeTile; + } + } + + return 1; +} + +#define REPEAT4(n, op) \ + switch (n) { \ + default: { \ + tmsize_t i; for (i = n-4; i > 0; i--) { op; } } /*-fallthrough*/ \ + case 4: op; /*-fallthrough*/ \ + case 3: op; /*-fallthrough*/ \ + case 2: op; /*-fallthrough*/ \ + case 1: op; /*-fallthrough*/ \ + case 0: ; \ + } + +/* Remarks related to C standard compliance in all below functions : */ +/* - to avoid any undefined behavior, we only operate on unsigned types */ +/* since the behavior of "overflows" is defined (wrap over) */ +/* - when storing into the byte stream, we explicitly mask with 0xff so */ +/* as to make icc -check=conversions happy (not necessary by the standard) */ + +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int +horAcc8(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + + unsigned char* cp = (unsigned char*) cp0; + if((cc%stride)!=0) + { + TIFFErrorExt(tif->tif_clientdata, "horAcc8", + "%s", "(cc%stride)!=0"); + return 0; + } + + if (cc > stride) { + /* + * Pipeline the most common cases. + */ + if (stride == 3) { + unsigned int cr = cp[0]; + unsigned int cg = cp[1]; + unsigned int cb = cp[2]; + cc -= 3; + cp += 3; + while (cc>0) { + cp[0] = (unsigned char) ((cr += cp[0]) & 0xff); + cp[1] = (unsigned char) ((cg += cp[1]) & 0xff); + cp[2] = (unsigned char) ((cb += cp[2]) & 0xff); + cc -= 3; + cp += 3; + } + } else if (stride == 4) { + unsigned int cr = cp[0]; + unsigned int cg = cp[1]; + unsigned int cb = cp[2]; + unsigned int ca = cp[3]; + cc -= 4; + cp += 4; + while (cc>0) { + cp[0] = (unsigned char) ((cr += cp[0]) & 0xff); + cp[1] = (unsigned char) ((cg += cp[1]) & 0xff); + cp[2] = (unsigned char) ((cb += cp[2]) & 0xff); + cp[3] = (unsigned char) ((ca += cp[3]) & 0xff); + cc -= 4; + cp += 4; + } + } else { + cc -= stride; + do { + REPEAT4(stride, cp[stride] = + (unsigned char) ((cp[stride] + *cp) & 0xff); cp++) + cc -= stride; + } while (cc>0); + } + } + return 1; +} + +static int +swabHorAcc16(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + uint16_t* wp = (uint16_t*) cp0; + tmsize_t wc = cc / 2; + + TIFFSwabArrayOfShort(wp, wc); + return horAcc16(tif, cp0, cc); +} + +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int +horAcc16(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + uint16_t* wp = (uint16_t*) cp0; + tmsize_t wc = cc / 2; + + if((cc%(2*stride))!=0) + { + TIFFErrorExt(tif->tif_clientdata, "horAcc16", + "%s", "cc%(2*stride))!=0"); + return 0; + } + + if (wc > stride) { + wc -= stride; + do { + REPEAT4(stride, wp[stride] = (uint16_t)(((unsigned int)wp[stride] + (unsigned int)wp[0]) & 0xffff); wp++) + wc -= stride; + } while (wc > 0); + } + return 1; +} + +static int +swabHorAcc32(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + uint32_t* wp = (uint32_t*) cp0; + tmsize_t wc = cc / 4; + + TIFFSwabArrayOfLong(wp, wc); + return horAcc32(tif, cp0, cc); +} + +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int +horAcc32(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + uint32_t* wp = (uint32_t*) cp0; + tmsize_t wc = cc / 4; + + if((cc%(4*stride))!=0) + { + TIFFErrorExt(tif->tif_clientdata, "horAcc32", + "%s", "cc%(4*stride))!=0"); + return 0; + } + + if (wc > stride) { + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while (wc > 0); + } + return 1; +} + +/* + * Floating point predictor accumulation routine. + */ +static int +fpAcc(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + uint32_t bps = tif->tif_dir.td_bitspersample / 8; + tmsize_t wc = cc / bps; + tmsize_t count = cc; + uint8_t *cp = (uint8_t *) cp0; + uint8_t *tmp; + + if(cc%(bps*stride)!=0) + { + TIFFErrorExt(tif->tif_clientdata, "fpAcc", + "%s", "cc%(bps*stride))!=0"); + return 0; + } + + tmp = (uint8_t *)_TIFFmalloc(cc); + if (!tmp) + return 0; + + while (count > stride) { + REPEAT4(stride, cp[stride] = + (unsigned char) ((cp[stride] + cp[0]) & 0xff); cp++) + count -= stride; + } + + _TIFFmemcpy(tmp, cp0, cc); + cp = (uint8_t *) cp0; + for (count = 0; count < wc; count++) { + uint32_t byte; + for (byte = 0; byte < bps; byte++) { + #if WORDS_BIGENDIAN + cp[bps * count + byte] = tmp[byte * wc + count]; + #else + cp[bps * count + byte] = + tmp[(bps - byte - 1) * wc + count]; + #endif + } + } + _TIFFfree(tmp); + return 1; +} + +/* + * Decode a scanline and apply the predictor routine. + */ +static int +PredictorDecodeRow(TIFF* tif, uint8_t* op0, tmsize_t occ0, uint16_t s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->decoderow != NULL); + assert(sp->decodepfunc != NULL); + + if ((*sp->decoderow)(tif, op0, occ0, s)) { + return (*sp->decodepfunc)(tif, op0, occ0); + } else + return 0; +} + +/* + * Decode a tile/strip and apply the predictor routine. + * Note that horizontal differencing must be done on a + * row-by-row basis. The width of a "row" has already + * been calculated at pre-decode time according to the + * strip/tile dimensions. + */ +static int +PredictorDecodeTile(TIFF* tif, uint8_t* op0, tmsize_t occ0, uint16_t s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->decodetile != NULL); + + if ((*sp->decodetile)(tif, op0, occ0, s)) { + tmsize_t rowsize = sp->rowsize; + assert(rowsize > 0); + if((occ0%rowsize) !=0) + { + TIFFErrorExt(tif->tif_clientdata, "PredictorDecodeTile", + "%s", "occ0%rowsize != 0"); + return 0; + } + assert(sp->decodepfunc != NULL); + while (occ0 > 0) { + if( !(*sp->decodepfunc)(tif, op0, rowsize) ) + return 0; + occ0 -= rowsize; + op0 += rowsize; + } + return 1; + } else + return 0; +} + +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int +horDiff8(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tmsize_t stride = sp->stride; + unsigned char* cp = (unsigned char*) cp0; + + if((cc%stride)!=0) + { + TIFFErrorExt(tif->tif_clientdata, "horDiff8", + "%s", "(cc%stride)!=0"); + return 0; + } + + if (cc > stride) { + cc -= stride; + /* + * Pipeline the most common cases. + */ + if (stride == 3) { + unsigned int r1, g1, b1; + unsigned int r2 = cp[0]; + unsigned int g2 = cp[1]; + unsigned int b2 = cp[2]; + do { + r1 = cp[3]; cp[3] = (unsigned char)((r1-r2)&0xff); r2 = r1; + g1 = cp[4]; cp[4] = (unsigned char)((g1-g2)&0xff); g2 = g1; + b1 = cp[5]; cp[5] = (unsigned char)((b1-b2)&0xff); b2 = b1; + cp += 3; + } while ((cc -= 3) > 0); + } else if (stride == 4) { + unsigned int r1, g1, b1, a1; + unsigned int r2 = cp[0]; + unsigned int g2 = cp[1]; + unsigned int b2 = cp[2]; + unsigned int a2 = cp[3]; + do { + r1 = cp[4]; cp[4] = (unsigned char)((r1-r2)&0xff); r2 = r1; + g1 = cp[5]; cp[5] = (unsigned char)((g1-g2)&0xff); g2 = g1; + b1 = cp[6]; cp[6] = (unsigned char)((b1-b2)&0xff); b2 = b1; + a1 = cp[7]; cp[7] = (unsigned char)((a1-a2)&0xff); a2 = a1; + cp += 4; + } while ((cc -= 4) > 0); + } else { + cp += cc - 1; + do { + REPEAT4(stride, cp[stride] = (unsigned char)((cp[stride] - cp[0])&0xff); cp--) + } while ((cc -= stride) > 0); + } + } + return 1; +} + +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int +horDiff16(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tmsize_t stride = sp->stride; + uint16_t *wp = (uint16_t*) cp0; + tmsize_t wc = cc/2; + + if((cc%(2*stride))!=0) + { + TIFFErrorExt(tif->tif_clientdata, "horDiff8", + "%s", "(cc%(2*stride))!=0"); + return 0; + } + + if (wc > stride) { + wc -= stride; + wp += wc - 1; + do { + REPEAT4(stride, wp[stride] = (uint16_t)(((unsigned int)wp[stride] - (unsigned int)wp[0]) & 0xffff); wp--) + wc -= stride; + } while (wc > 0); + } + return 1; +} + +static int +swabHorDiff16(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + uint16_t* wp = (uint16_t*) cp0; + tmsize_t wc = cc / 2; + + if( !horDiff16(tif, cp0, cc) ) + return 0; + + TIFFSwabArrayOfShort(wp, wc); + return 1; +} + +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int +horDiff32(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tmsize_t stride = sp->stride; + uint32_t *wp = (uint32_t*) cp0; + tmsize_t wc = cc/4; + + if((cc%(4*stride))!=0) + { + TIFFErrorExt(tif->tif_clientdata, "horDiff32", + "%s", "(cc%(4*stride))!=0"); + return 0; + } + + if (wc > stride) { + wc -= stride; + wp += wc - 1; + do { + REPEAT4(stride, wp[stride] -= wp[0]; wp--) + wc -= stride; + } while (wc > 0); + } + return 1; +} + +static int +swabHorDiff32(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + uint32_t* wp = (uint32_t*) cp0; + tmsize_t wc = cc / 4; + + if( !horDiff32(tif, cp0, cc) ) + return 0; + + TIFFSwabArrayOfLong(wp, wc); + return 1; +} + +/* + * Floating point predictor differencing routine. + */ +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int +fpDiff(TIFF* tif, uint8_t* cp0, tmsize_t cc) +{ + tmsize_t stride = PredictorState(tif)->stride; + uint32_t bps = tif->tif_dir.td_bitspersample / 8; + tmsize_t wc = cc / bps; + tmsize_t count; + uint8_t *cp = (uint8_t *) cp0; + uint8_t *tmp; + + if((cc%(bps*stride))!=0) + { + TIFFErrorExt(tif->tif_clientdata, "fpDiff", + "%s", "(cc%(bps*stride))!=0"); + return 0; + } + + tmp = (uint8_t *)_TIFFmalloc(cc); + if (!tmp) + return 0; + + _TIFFmemcpy(tmp, cp0, cc); + for (count = 0; count < wc; count++) { + uint32_t byte; + for (byte = 0; byte < bps; byte++) { + #if WORDS_BIGENDIAN + cp[byte * wc + count] = tmp[bps * count + byte]; + #else + cp[(bps - byte - 1) * wc + count] = + tmp[bps * count + byte]; + #endif + } + } + _TIFFfree(tmp); + + cp = (uint8_t *) cp0; + cp += cc - stride - 1; + for (count = cc; count > stride; count -= stride) + REPEAT4(stride, cp[stride] = (unsigned char)((cp[stride] - cp[0])&0xff); cp--) + return 1; +} + +static int +PredictorEncodeRow(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->encodepfunc != NULL); + assert(sp->encoderow != NULL); + + /* XXX horizontal differencing alters user's data XXX */ + if( !(*sp->encodepfunc)(tif, bp, cc) ) + return 0; + return (*sp->encoderow)(tif, bp, cc, s); +} + +static int +PredictorEncodeTile(TIFF* tif, uint8_t* bp0, tmsize_t cc0, uint16_t s) +{ + static const char module[] = "PredictorEncodeTile"; + TIFFPredictorState *sp = PredictorState(tif); + uint8_t *working_copy; + tmsize_t cc = cc0, rowsize; + unsigned char* bp; + int result_code; + + assert(sp != NULL); + assert(sp->encodepfunc != NULL); + assert(sp->encodetile != NULL); + + /* + * Do predictor manipulation in a working buffer to avoid altering + * the callers buffer. http://trac.osgeo.org/gdal/ticket/1965 + */ + working_copy = (uint8_t*) _TIFFmalloc(cc0); + if( working_copy == NULL ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Out of memory allocating %" PRId64 " byte temp buffer.", + (int64_t) cc0 ); + return 0; + } + memcpy( working_copy, bp0, cc0 ); + bp = working_copy; + + rowsize = sp->rowsize; + assert(rowsize > 0); + if((cc0%rowsize)!=0) + { + TIFFErrorExt(tif->tif_clientdata, "PredictorEncodeTile", + "%s", "(cc0%rowsize)!=0"); + _TIFFfree( working_copy ); + return 0; + } + while (cc > 0) { + (*sp->encodepfunc)(tif, bp, rowsize); + cc -= rowsize; + bp += rowsize; + } + result_code = (*sp->encodetile)(tif, working_copy, cc0, s); + + _TIFFfree( working_copy ); + + return result_code; +} + +#define FIELD_PREDICTOR (FIELD_CODEC+0) /* XXX */ + +static const TIFFField predictFields[] = { + { TIFFTAG_PREDICTOR, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UINT16, FIELD_PREDICTOR, FALSE, FALSE, "Predictor", NULL }, +}; + +static int +PredictorVSetField(TIFF* tif, uint32_t tag, va_list ap) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->vsetparent != NULL); + + switch (tag) { + case TIFFTAG_PREDICTOR: + sp->predictor = (uint16_t) va_arg(ap, uint16_vap); + TIFFSetFieldBit(tif, FIELD_PREDICTOR); + break; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + tif->tif_flags |= TIFF_DIRTYDIRECT; + return 1; +} + +static int +PredictorVGetField(TIFF* tif, uint32_t tag, va_list ap) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->vgetparent != NULL); + + switch (tag) { + case TIFFTAG_PREDICTOR: + *va_arg(ap, uint16_t*) = (uint16_t)sp->predictor; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return 1; +} + +static void +PredictorPrintDir(TIFF* tif, FILE* fd, long flags) +{ + TIFFPredictorState* sp = PredictorState(tif); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_PREDICTOR)) { + fprintf(fd, " Predictor: "); + switch (sp->predictor) { + case 1: fprintf(fd, "none "); break; + case 2: fprintf(fd, "horizontal differencing "); break; + case 3: fprintf(fd, "floating point predictor "); break; + } + fprintf(fd, "%d (0x%x)\n", sp->predictor, sp->predictor); + } + if (sp->printdir) + (*sp->printdir)(tif, fd, flags); +} + +int +TIFFPredictorInit(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + + assert(sp != 0); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, predictFields, + TIFFArrayCount(predictFields))) { + TIFFErrorExt(tif->tif_clientdata, "TIFFPredictorInit", + "Merging Predictor codec-specific tags failed"); + return 0; + } + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = + PredictorVGetField;/* hook for predictor tag */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = + PredictorVSetField;/* hook for predictor tag */ + sp->printdir = tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir = + PredictorPrintDir; /* hook for predictor tag */ + + sp->setupdecode = tif->tif_setupdecode; + tif->tif_setupdecode = PredictorSetupDecode; + sp->setupencode = tif->tif_setupencode; + tif->tif_setupencode = PredictorSetupEncode; + + sp->predictor = 1; /* default value */ + sp->encodepfunc = NULL; /* no predictor routine */ + sp->decodepfunc = NULL; /* no predictor routine */ + return 1; +} + +int +TIFFPredictorCleanup(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + tif->tif_tagmethods.printdir = sp->printdir; + tif->tif_setupdecode = sp->setupdecode; + tif->tif_setupencode = sp->setupencode; + + return 1; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_predict.h b/libs/tiff/libtiff/tif_predict.h new file mode 100644 index 00000000000..597faa16210 --- /dev/null +++ b/libs/tiff/libtiff/tif_predict.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1995-1997 Sam Leffler + * Copyright (c) 1995-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFPREDICT_ +#define _TIFFPREDICT_ + +#include "tiffio.h" +#include "tiffiop.h" + +/* + * ``Library-private'' Support for the Predictor Tag + */ + +typedef int (*TIFFEncodeDecodeMethod)(TIFF* tif, uint8_t* buf, tmsize_t size); + +/* + * Codecs that want to support the Predictor tag must place + * this structure first in their private state block so that + * the predictor code can cast tif_data to find its state. + */ +typedef struct { + int predictor; /* predictor tag value */ + tmsize_t stride; /* sample stride over data */ + tmsize_t rowsize; /* tile/strip row size */ + + TIFFCodeMethod encoderow; /* parent codec encode/decode row */ + TIFFCodeMethod encodestrip; /* parent codec encode/decode strip */ + TIFFCodeMethod encodetile; /* parent codec encode/decode tile */ + TIFFEncodeDecodeMethod encodepfunc; /* horizontal differencer */ + + TIFFCodeMethod decoderow; /* parent codec encode/decode row */ + TIFFCodeMethod decodestrip; /* parent codec encode/decode strip */ + TIFFCodeMethod decodetile; /* parent codec encode/decode tile */ + TIFFEncodeDecodeMethod decodepfunc; /* horizontal accumulator */ + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFPrintMethod printdir; /* super-class method */ + TIFFBoolMethod setupdecode; /* super-class method */ + TIFFBoolMethod setupencode; /* super-class method */ +} TIFFPredictorState; + +#if defined(__cplusplus) +extern "C" { +#endif +extern int TIFFPredictorInit(TIFF*); +extern int TIFFPredictorCleanup(TIFF*); +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFPREDICT_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_read.c b/libs/tiff/libtiff/tif_read.c new file mode 100644 index 00000000000..a4c60b4fd8f --- /dev/null +++ b/libs/tiff/libtiff/tif_read.c @@ -0,0 +1,1556 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * Scanline-oriented Read Support + */ +#include "tiffiop.h" +#include + +int TIFFFillStrip(TIFF* tif, uint32_t strip); +int TIFFFillTile(TIFF* tif, uint32_t tile); +static int TIFFStartStrip(TIFF* tif, uint32_t strip); +static int TIFFStartTile(TIFF* tif, uint32_t tile); +static int TIFFCheckRead(TIFF*, int); +static tmsize_t +TIFFReadRawStrip1(TIFF* tif, uint32_t strip, void* buf, tmsize_t size, const char* module); +static tmsize_t +TIFFReadRawTile1(TIFF* tif, uint32_t tile, void* buf, tmsize_t size, const char* module); + +#define NOSTRIP ((uint32_t)(-1)) /* undefined state */ +#define NOTILE ((uint32_t)(-1)) /* undefined state */ + +#define INITIAL_THRESHOLD (1024 * 1024) +#define THRESHOLD_MULTIPLIER 10 +#define MAX_THRESHOLD (THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * INITIAL_THRESHOLD) + +#define TIFF_INT64_MAX ((((int64_t)0x7FFFFFFF) << 32) | 0xFFFFFFFF) + +/* Read 'size' bytes in tif_rawdata buffer starting at offset 'rawdata_offset' + * Returns 1 in case of success, 0 otherwise. */ +static int TIFFReadAndRealloc(TIFF* tif, tmsize_t size, + tmsize_t rawdata_offset, + int is_strip, uint32_t strip_or_tile, + const char* module ) +{ +#if SIZEOF_SIZE_T == 8 + tmsize_t threshold = INITIAL_THRESHOLD; +#endif + tmsize_t already_read = 0; + + +#if SIZEOF_SIZE_T != 8 + /* On 32 bit processes, if the request is large enough, check against */ + /* file size */ + if( size > 1000 * 1000 * 1000 ) + { + uint64_t filesize = TIFFGetFileSize(tif); + if((uint64_t)size >= filesize ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Chunk size requested is larger than file size."); + return 0; + } + } +#endif + + /* On 64 bit processes, read first a maximum of 1 MB, then 10 MB, etc */ + /* so as to avoid allocating too much memory in case the file is too */ + /* short. We could ask for the file size, but this might be */ + /* expensive with some I/O layers (think of reading a gzipped file) */ + /* Restrict to 64 bit processes, so as to avoid reallocs() */ + /* on 32 bit processes where virtual memory is scarce. */ + while( already_read < size ) + { + tmsize_t bytes_read; + tmsize_t to_read = size - already_read; +#if SIZEOF_SIZE_T == 8 + if( to_read >= threshold && threshold < MAX_THRESHOLD && + already_read + to_read + rawdata_offset > tif->tif_rawdatasize ) + { + to_read = threshold; + threshold *= THRESHOLD_MULTIPLIER; + } +#endif + if (already_read + to_read + rawdata_offset > tif->tif_rawdatasize) { + uint8_t* new_rawdata; + assert((tif->tif_flags & TIFF_MYBUFFER) != 0); + tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64( + (uint64_t)already_read + to_read + rawdata_offset, 1024); + if (tif->tif_rawdatasize==0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Invalid buffer size"); + return 0; + } + new_rawdata = (uint8_t*) _TIFFrealloc( + tif->tif_rawdata, tif->tif_rawdatasize); + if( new_rawdata == 0 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for data buffer at scanline %"PRIu32, + tif->tif_row); + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = 0; + tif->tif_rawdatasize = 0; + return 0; + } + tif->tif_rawdata = new_rawdata; + } + if( tif->tif_rawdata == NULL ) + { + /* should not happen in practice but helps CoverityScan */ + return 0; + } + + bytes_read = TIFFReadFile(tif, + tif->tif_rawdata + rawdata_offset + already_read, to_read); + already_read += bytes_read; + if (bytes_read != to_read) { + memset( tif->tif_rawdata + rawdata_offset + already_read, 0, + tif->tif_rawdatasize - rawdata_offset - already_read ); + if( is_strip ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at scanline %"PRIu32"; got %"TIFF_SSIZE_FORMAT" bytes, " + "expected %"TIFF_SSIZE_FORMAT, + tif->tif_row, + already_read, + size); + } + else + { + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at row %"PRIu32", col %"PRIu32", tile %"PRIu32"; " + "got %"TIFF_SSIZE_FORMAT" bytes, expected %"TIFF_SSIZE_FORMAT"", + tif->tif_row, + tif->tif_col, + strip_or_tile, + already_read, + size); + } + return 0; + } + } + return 1; +} + + +static int +TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) +{ + static const char module[] = "TIFFFillStripPartial"; + register TIFFDirectory *td = &tif->tif_dir; + tmsize_t unused_data; + uint64_t read_offset; + tmsize_t to_read; + tmsize_t read_ahead_mod; + /* tmsize_t bytecountm; */ + + /* + * Expand raw data buffer, if needed, to hold data + * strip coming from file (perhaps should set upper + * bound on the size of a buffer we'll use?). + */ + + /* bytecountm=(tmsize_t) TIFFGetStrileByteCount(tif, strip); */ + + /* Not completely sure where the * 2 comes from, but probably for */ + /* an exponentional growth strategy of tif_rawdatasize */ + if( read_ahead < TIFF_TMSIZE_T_MAX / 2 ) + read_ahead_mod = read_ahead * 2; + else + read_ahead_mod = read_ahead; + if (read_ahead_mod > tif->tif_rawdatasize) { + assert( restart ); + + tif->tif_curstrip = NOSTRIP; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Data buffer too small to hold part of strip %d", + strip); + return (0); + } + } + + if( restart ) + { + tif->tif_rawdataloaded = 0; + tif->tif_rawdataoff = 0; + } + + /* + ** If we are reading more data, move any unused data to the + ** start of the buffer. + */ + if( tif->tif_rawdataloaded > 0 ) + unused_data = tif->tif_rawdataloaded - (tif->tif_rawcp - tif->tif_rawdata); + else + unused_data = 0; + + if( unused_data > 0 ) + { + assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); + memmove( tif->tif_rawdata, tif->tif_rawcp, unused_data ); + } + + /* + ** Seek to the point in the file where more data should be read. + */ + read_offset = TIFFGetStrileOffset(tif, strip) + + tif->tif_rawdataoff + tif->tif_rawdataloaded; + + if (!SeekOK(tif, read_offset)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at scanline %"PRIu32", strip %d", + tif->tif_row, strip); + return 0; + } + + /* + ** How much do we want to read? + */ + if( read_ahead_mod > tif->tif_rawdatasize ) + to_read = read_ahead_mod - unused_data; + else + to_read = tif->tif_rawdatasize - unused_data; + if((uint64_t) to_read > TIFFGetStrileByteCount(tif, strip) + - tif->tif_rawdataoff - tif->tif_rawdataloaded ) + { + to_read = (tmsize_t) TIFFGetStrileByteCount(tif, strip) + - tif->tif_rawdataoff - tif->tif_rawdataloaded; + } + + assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); + if( !TIFFReadAndRealloc( tif, to_read, unused_data, + 1, /* is_strip */ + 0, /* strip_or_tile */ + module) ) + { + return 0; + } + + tif->tif_rawdataoff = tif->tif_rawdataoff + tif->tif_rawdataloaded - unused_data ; + tif->tif_rawdataloaded = unused_data + to_read; + + tif->tif_rawcc = tif->tif_rawdataloaded; + tif->tif_rawcp = tif->tif_rawdata; + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) { + assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); + TIFFReverseBits(tif->tif_rawdata + unused_data, to_read ); + } + + /* + ** When starting a strip from the beginning we need to + ** restart the decoder. + */ + if( restart ) + { + +#ifdef JPEG_SUPPORT + /* A bit messy since breaks the codec abstraction. Ultimately */ + /* there should be a function pointer for that, but it seems */ + /* only JPEG is affected. */ + /* For JPEG, if there are multiple scans (can generally be known */ + /* with the read_ahead used), we need to read the whole strip */ + if( tif->tif_dir.td_compression==COMPRESSION_JPEG && + (uint64_t)tif->tif_rawcc < TIFFGetStrileByteCount(tif, strip) ) + { + if( TIFFJPEGIsFullStripRequired(tif) ) + { + return TIFFFillStrip(tif, strip); + } + } +#endif + + return TIFFStartStrip(tif, strip); + } + else + { + return 1; + } +} + +/* + * Seek to a random row+sample in a file. + * + * Only used by TIFFReadScanline, and is only used on + * strip organized files. We do some tricky stuff to try + * and avoid reading the whole compressed raw data for big + * strips. + */ +static int +TIFFSeek(TIFF* tif, uint32_t row, uint16_t sample ) +{ + register TIFFDirectory *td = &tif->tif_dir; + uint32_t strip; + int whole_strip; + tmsize_t read_ahead = 0; + + /* + ** Establish what strip we are working from. + */ + if (row >= td->td_imagelength) { /* out of range */ + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%"PRIu32": Row out of range, max %"PRIu32"", + row, + td->td_imagelength); + return (0); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%"PRIu16": Sample out of range, max %"PRIu16"", + sample, td->td_samplesperpixel); + return (0); + } + strip = (uint32_t)sample * td->td_stripsperimage + row / td->td_rowsperstrip; + } else + strip = row / td->td_rowsperstrip; + + /* + * Do we want to treat this strip as one whole chunk or + * read it a few lines at a time? + */ +#if defined(CHUNKY_STRIP_READ_SUPPORT) + whole_strip = TIFFGetStrileByteCount(tif, strip) < 10 + || isMapped(tif); + if( td->td_compression == COMPRESSION_LERC || + td->td_compression == COMPRESSION_JBIG ) + { + /* Ideally plugins should have a way to declare they don't support + * chunk strip */ + whole_strip = 1; + } +#else + whole_strip = 1; +#endif + + if( !whole_strip ) + { + /* 16 is for YCbCr mode where we may need to read 16 */ + /* lines at a time to get a decompressed line, and 5000 */ + /* is some constant value, for example for JPEG tables */ + if( tif->tif_scanlinesize < TIFF_TMSIZE_T_MAX / 16 && + tif->tif_scanlinesize * 16 < TIFF_TMSIZE_T_MAX - 5000 ) + { + read_ahead = tif->tif_scanlinesize * 16 + 5000; + } + else + { + read_ahead = tif->tif_scanlinesize; + } + } + + /* + * If we haven't loaded this strip, do so now, possibly + * only reading the first part. + */ + if (strip != tif->tif_curstrip) { /* different strip, refill */ + + if( whole_strip ) + { + if (!TIFFFillStrip(tif, strip)) + return (0); + } + else + { + if( !TIFFFillStripPartial(tif,strip,read_ahead,1) ) + return 0; + } + } + + /* + ** If we already have some data loaded, do we need to read some more? + */ + else if( !whole_strip ) + { + if( ((tif->tif_rawdata + tif->tif_rawdataloaded) - tif->tif_rawcp) < read_ahead + && (uint64_t) tif->tif_rawdataoff + tif->tif_rawdataloaded < TIFFGetStrileByteCount(tif, strip) ) + { + if( !TIFFFillStripPartial(tif,strip,read_ahead,0) ) + return 0; + } + } + + if (row < tif->tif_row) { + /* + * Moving backwards within the same strip: backup + * to the start and then decode forward (below). + * + * NB: If you're planning on lots of random access within a + * strip, it's better to just read and decode the entire + * strip, and then access the decoded data in a random fashion. + */ + + if( tif->tif_rawdataoff != 0 ) + { + if( !TIFFFillStripPartial(tif,strip,read_ahead,1) ) + return 0; + } + else + { + if (!TIFFStartStrip(tif, strip)) + return (0); + } + } + + if (row != tif->tif_row) { + /* + * Seek forward to the desired row. + */ + + /* TODO: Will this really work with partial buffers? */ + + if (!(*tif->tif_seek)(tif, row - tif->tif_row)) + return (0); + tif->tif_row = row; + } + + return (1); +} + +int +TIFFReadScanline(TIFF* tif, void* buf, uint32_t row, uint16_t sample) +{ + int e; + + if (!TIFFCheckRead(tif, 0)) + return (-1); + if( (e = TIFFSeek(tif, row, sample)) != 0) { + /* + * Decompress desired row into user buffer. + */ + e = (*tif->tif_decoderow) + (tif, (uint8_t*) buf, tif->tif_scanlinesize, sample); + + /* we are now poised at the beginning of the next row */ + tif->tif_row = row + 1; + + if (e) + (*tif->tif_postdecode)(tif, (uint8_t*) buf, + tif->tif_scanlinesize); + } + return (e > 0 ? 1 : -1); +} + +/* + * Calculate the strip size according to the number of + * rows in the strip (check for truncated last strip on any + * of the separations). + */ +static tmsize_t TIFFReadEncodedStripGetStripSize(TIFF* tif, uint32_t strip, uint16_t* pplane) +{ + static const char module[] = "TIFFReadEncodedStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint32_t rowsperstrip; + uint32_t stripsperplane; + uint32_t stripinplane; + uint32_t rows; + tmsize_t stripsize; + if (!TIFFCheckRead(tif,0)) + return((tmsize_t)(-1)); + if (strip>=td->td_nstrips) + { + TIFFErrorExt(tif->tif_clientdata,module, + "%"PRIu32": Strip out of range, max %"PRIu32, strip, + td->td_nstrips); + return((tmsize_t)(-1)); + } + + rowsperstrip=td->td_rowsperstrip; + if (rowsperstrip>td->td_imagelength) + rowsperstrip=td->td_imagelength; + stripsperplane= TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip); + stripinplane=(strip%stripsperplane); + if( pplane ) *pplane=(uint16_t)(strip / stripsperplane); + rows=td->td_imagelength-stripinplane*rowsperstrip; + if (rows>rowsperstrip) + rows=rowsperstrip; + stripsize=TIFFVStripSize(tif,rows); + if (stripsize==0) + return((tmsize_t)(-1)); + return stripsize; +} + +/* + * Read a strip of data and decompress the specified + * amount into the user-supplied buffer. + */ +tmsize_t +TIFFReadEncodedStrip(TIFF* tif, uint32_t strip, void* buf, tmsize_t size) +{ + static const char module[] = "TIFFReadEncodedStrip"; + TIFFDirectory *td = &tif->tif_dir; + tmsize_t stripsize; + uint16_t plane; + + stripsize=TIFFReadEncodedStripGetStripSize(tif, strip, &plane); + if (stripsize==((tmsize_t)(-1))) + return((tmsize_t)(-1)); + + /* shortcut to avoid an extra memcpy() */ + if( td->td_compression == COMPRESSION_NONE && + size!=(tmsize_t)(-1) && size >= stripsize && + !isMapped(tif) && + ((tif->tif_flags&TIFF_NOREADRAW)==0) ) + { + if (TIFFReadRawStrip1(tif, strip, buf, stripsize, module) != stripsize) + return ((tmsize_t)(-1)); + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(buf,stripsize); + + (*tif->tif_postdecode)(tif,buf,stripsize); + return (stripsize); + } + + if ((size!=(tmsize_t)(-1))&&(sizetif_decodestrip)(tif,buf,stripsize,plane)<=0) + return((tmsize_t)(-1)); + (*tif->tif_postdecode)(tif,buf,stripsize); + return(stripsize); +} + +/* Variant of TIFFReadEncodedStrip() that does + * * if *buf == NULL, *buf = _TIFFmalloc(bufsizetoalloc) only after TIFFFillStrip() has + * succeeded. This avoid excessive memory allocation in case of truncated + * file. + * * calls regular TIFFReadEncodedStrip() if *buf != NULL + */ +tmsize_t +_TIFFReadEncodedStripAndAllocBuffer(TIFF* tif, uint32_t strip, + void **buf, tmsize_t bufsizetoalloc, + tmsize_t size_to_read) +{ + tmsize_t this_stripsize; + uint16_t plane; + + if( *buf != NULL ) + { + return TIFFReadEncodedStrip(tif, strip, *buf, size_to_read); + } + + this_stripsize=TIFFReadEncodedStripGetStripSize(tif, strip, &plane); + if (this_stripsize==((tmsize_t)(-1))) + return((tmsize_t)(-1)); + + if ((size_to_read!=(tmsize_t)(-1))&&(size_to_readtif_clientdata, TIFFFileName(tif), "No space for strip buffer"); + return((tmsize_t)(-1)); + } + _TIFFmemset(*buf, 0, bufsizetoalloc); + + if ((*tif->tif_decodestrip)(tif,*buf,this_stripsize,plane)<=0) + return((tmsize_t)(-1)); + (*tif->tif_postdecode)(tif,*buf,this_stripsize); + return(this_stripsize); + + +} + +static tmsize_t +TIFFReadRawStrip1(TIFF* tif, uint32_t strip, void* buf, tmsize_t size, + const char* module) +{ + assert((tif->tif_flags&TIFF_NOREADRAW)==0); + if (!isMapped(tif)) { + tmsize_t cc; + + if (!SeekOK(tif, TIFFGetStrileOffset(tif, strip))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at scanline %"PRIu32", strip %"PRIu32, + tif->tif_row, strip); + return ((tmsize_t)(-1)); + } + cc = TIFFReadFile(tif, buf, size); + if (cc != size) { + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at scanline %"PRIu32"; got %"TIFF_SSIZE_FORMAT" bytes, expected %"TIFF_SSIZE_FORMAT, + tif->tif_row, + cc, + size); + return ((tmsize_t)(-1)); + } + } else { + tmsize_t ma = 0; + tmsize_t n; + if ((TIFFGetStrileOffset(tif, strip) > (uint64_t)TIFF_TMSIZE_T_MAX) || + ((ma=(tmsize_t)TIFFGetStrileOffset(tif, strip))>tif->tif_size)) + { + n=0; + } + else if( ma > TIFF_TMSIZE_T_MAX - size ) + { + n=0; + } + else + { + tmsize_t mb=ma+size; + if (mb>tif->tif_size) + n=tif->tif_size-ma; + else + n=size; + } + if (n!=size) { + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at scanline %"PRIu32", strip %"PRIu32"; got %"TIFF_SSIZE_FORMAT" bytes, expected %"TIFF_SSIZE_FORMAT, + tif->tif_row, + strip, + n, + size); + return ((tmsize_t)(-1)); + } + _TIFFmemcpy(buf, tif->tif_base + ma, + size); + } + return (size); +} + +static tmsize_t +TIFFReadRawStripOrTile2(TIFF* tif, uint32_t strip_or_tile, int is_strip, + tmsize_t size, const char* module) +{ + assert( !isMapped(tif) ); + assert((tif->tif_flags&TIFF_NOREADRAW)==0); + + if (!SeekOK(tif, TIFFGetStrileOffset(tif, strip_or_tile))) { + if( is_strip ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at scanline %"PRIu32", strip %"PRIu32, + tif->tif_row, + strip_or_tile); + } + else + { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at row %"PRIu32", col %"PRIu32", tile %"PRIu32, + tif->tif_row, + tif->tif_col, + strip_or_tile); + } + return ((tmsize_t)(-1)); + } + + if( !TIFFReadAndRealloc( tif, size, 0, is_strip, + strip_or_tile, module ) ) + { + return ((tmsize_t)(-1)); + } + + return (size); +} + +/* + * Read a strip of data from the file. + */ +tmsize_t +TIFFReadRawStrip(TIFF* tif, uint32_t strip, void* buf, tmsize_t size) +{ + static const char module[] = "TIFFReadRawStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint64_t bytecount64; + tmsize_t bytecountm; + + if (!TIFFCheckRead(tif, 0)) + return ((tmsize_t)(-1)); + if (strip >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, + "%"PRIu32": Strip out of range, max %"PRIu32, + strip, + td->td_nstrips); + return ((tmsize_t)(-1)); + } + if (tif->tif_flags&TIFF_NOREADRAW) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Compression scheme does not support access to raw uncompressed data"); + return ((tmsize_t)(-1)); + } + bytecount64 = TIFFGetStrileByteCount(tif, strip); + if (size != (tmsize_t)(-1) && (uint64_t)size <= bytecount64) + bytecountm = size; + else + bytecountm = _TIFFCastUInt64ToSSize(tif, bytecount64, module); + if( bytecountm == 0 ) { + return ((tmsize_t)(-1)); + } + return (TIFFReadRawStrip1(tif, strip, buf, bytecountm, module)); +} + +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static uint64_t NoSanitizeSubUInt64(uint64_t a, uint64_t b) +{ + return a - b; +} + +/* + * Read the specified strip and setup for decoding. The data buffer is + * expanded, as necessary, to hold the strip's data. + */ +int +TIFFFillStrip(TIFF* tif, uint32_t strip) +{ + static const char module[] = "TIFFFillStrip"; + TIFFDirectory *td = &tif->tif_dir; + + if ((tif->tif_flags&TIFF_NOREADRAW)==0) + { + uint64_t bytecount = TIFFGetStrileByteCount(tif, strip); + if( bytecount == 0 || bytecount > (uint64_t)TIFF_INT64_MAX ) { + TIFFErrorExt(tif->tif_clientdata, module, + "Invalid strip byte count %"PRIu64", strip %"PRIu32, + bytecount, + strip); + return (0); + } + + /* To avoid excessive memory allocations: */ + /* Byte count should normally not be larger than a number of */ + /* times the uncompressed size plus some margin */ + if( bytecount > 1024 * 1024 ) + { + /* 10 and 4096 are just values that could be adjusted. */ + /* Hopefully they are safe enough for all codecs */ + tmsize_t stripsize = TIFFStripSize(tif); + if( stripsize != 0 && + (bytecount - 4096) / 10 > (uint64_t)stripsize ) + { + uint64_t newbytecount = (uint64_t)stripsize * 10 + 4096; + if( newbytecount == 0 || newbytecount > (uint64_t)TIFF_INT64_MAX ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Too large strip byte count %"PRIu64", strip %"PRIu32". Limiting to %"PRIu64, + bytecount, + strip, + newbytecount); + bytecount = newbytecount; + } + } + } + + if (isMapped(tif)) { + /* + * We must check for overflow, potentially causing + * an OOB read. Instead of simple + * + * TIFFGetStrileOffset(tif, strip)+bytecount > tif->tif_size + * + * comparison (which can overflow) we do the following + * two comparisons: + */ + if (bytecount > (uint64_t)tif->tif_size || + TIFFGetStrileOffset(tif, strip) > (uint64_t)tif->tif_size - bytecount) { + /* + * This error message might seem strange, but + * it's what would happen if a read were done + * instead. + */ + TIFFErrorExt(tif->tif_clientdata, module, + + "Read error on strip %"PRIu32"; " + "got %"PRIu64" bytes, expected %"PRIu64, + strip, + NoSanitizeSubUInt64(tif->tif_size, TIFFGetStrileOffset(tif, strip)), + bytecount); + tif->tif_curstrip = NOSTRIP; + return (0); + } + } + + if (isMapped(tif) && + (isFillOrder(tif, td->td_fillorder) + || (tif->tif_flags & TIFF_NOBITREV))) { + /* + * The image is mapped into memory and we either don't + * need to flip bits or the compression routine is + * going to handle this operation itself. In this + * case, avoid copying the raw data and instead just + * reference the data from the memory mapped file + * image. This assumes that the decompression + * routines do not modify the contents of the raw data + * buffer (if they try to, the application will get a + * fault since the file is mapped read-only). + */ + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + } + tif->tif_flags &= ~TIFF_MYBUFFER; + tif->tif_rawdatasize = (tmsize_t)bytecount; + tif->tif_rawdata = tif->tif_base + (tmsize_t)TIFFGetStrileOffset(tif, strip); + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = (tmsize_t) bytecount; + + /* + * When we have tif_rawdata reference directly into the memory mapped file + * we need to be pretty careful about how we use the rawdata. It is not + * a general purpose working buffer as it normally otherwise is. So we + * keep track of this fact to avoid using it improperly. + */ + tif->tif_flags |= TIFF_BUFFERMMAP; + } else { + /* + * Expand raw data buffer, if needed, to hold data + * strip coming from file (perhaps should set upper + * bound on the size of a buffer we'll use?). + */ + tmsize_t bytecountm; + bytecountm=(tmsize_t)bytecount; + if ((uint64_t)bytecountm != bytecount) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + return(0); + } + if (bytecountm > tif->tif_rawdatasize) { + tif->tif_curstrip = NOSTRIP; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Data buffer too small to hold strip %"PRIu32, + strip); + return (0); + } + } + if (tif->tif_flags&TIFF_BUFFERMMAP) { + tif->tif_curstrip = NOSTRIP; + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + tif->tif_flags &= ~TIFF_BUFFERMMAP; + } + + if( isMapped(tif) ) + { + if (bytecountm > tif->tif_rawdatasize && + !TIFFReadBufferSetup(tif, 0, bytecountm)) + { + return (0); + } + if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata, + bytecountm, module) != bytecountm) + { + return (0); + } + } + else + { + if (TIFFReadRawStripOrTile2(tif, strip, 1, + bytecountm, module) != bytecountm) + { + return (0); + } + } + + + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = bytecountm; + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, bytecountm); + } + } + return (TIFFStartStrip(tif, strip)); +} + +/* + * Tile-oriented Read Support + * Contributed by Nancy Cam (Silicon Graphics). + */ + +/* + * Read and decompress a tile of data. The + * tile is selected by the (x,y,z,s) coordinates. + */ +tmsize_t +TIFFReadTile(TIFF* tif, void* buf, uint32_t x, uint32_t y, uint32_t z, uint16_t s) +{ + if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s)) + return ((tmsize_t)(-1)); + return (TIFFReadEncodedTile(tif, + TIFFComputeTile(tif, x, y, z, s), buf, (tmsize_t)(-1))); +} + +/* + * Read a tile of data and decompress the specified + * amount into the user-supplied buffer. + */ +tmsize_t +TIFFReadEncodedTile(TIFF* tif, uint32_t tile, void* buf, tmsize_t size) +{ + static const char module[] = "TIFFReadEncodedTile"; + TIFFDirectory *td = &tif->tif_dir; + tmsize_t tilesize = tif->tif_tilesize; + + if (!TIFFCheckRead(tif, 1)) + return ((tmsize_t)(-1)); + if (tile >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, + "%"PRIu32": Tile out of range, max %"PRIu32, + tile, td->td_nstrips); + return ((tmsize_t)(-1)); + } + + /* shortcut to avoid an extra memcpy() */ + if( td->td_compression == COMPRESSION_NONE && + size!=(tmsize_t)(-1) && size >= tilesize && + !isMapped(tif) && + ((tif->tif_flags&TIFF_NOREADRAW)==0) ) + { + if (TIFFReadRawTile1(tif, tile, buf, tilesize, module) != tilesize) + return ((tmsize_t)(-1)); + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(buf,tilesize); + + (*tif->tif_postdecode)(tif,buf,tilesize); + return (tilesize); + } + + if (size == (tmsize_t)(-1)) + size = tilesize; + else if (size > tilesize) + size = tilesize; + if (TIFFFillTile(tif, tile) && (*tif->tif_decodetile)(tif, + (uint8_t*) buf, size, (uint16_t)(tile / td->td_stripsperimage))) { + (*tif->tif_postdecode)(tif, (uint8_t*) buf, size); + return (size); + } else + return ((tmsize_t)(-1)); +} + +/* Variant of TIFFReadTile() that does + * * if *buf == NULL, *buf = _TIFFmalloc(bufsizetoalloc) only after TIFFFillTile() has + * succeeded. This avoid excessive memory allocation in case of truncated + * file. + * * calls regular TIFFReadEncodedTile() if *buf != NULL + */ +tmsize_t +_TIFFReadTileAndAllocBuffer(TIFF* tif, + void **buf, tmsize_t bufsizetoalloc, + uint32_t x, uint32_t y, uint32_t z, uint16_t s) +{ + if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s)) + return ((tmsize_t)(-1)); + return (_TIFFReadEncodedTileAndAllocBuffer(tif, + TIFFComputeTile(tif, x, y, z, s), + buf, bufsizetoalloc, + (tmsize_t)(-1))); +} + +/* Variant of TIFFReadEncodedTile() that does + * * if *buf == NULL, *buf = _TIFFmalloc(bufsizetoalloc) only after TIFFFillTile() has + * succeeded. This avoid excessive memory allocation in case of truncated + * file. + * * calls regular TIFFReadEncodedTile() if *buf != NULL + */ +tmsize_t +_TIFFReadEncodedTileAndAllocBuffer(TIFF* tif, uint32_t tile, + void **buf, tmsize_t bufsizetoalloc, + tmsize_t size_to_read) +{ + static const char module[] = "_TIFFReadEncodedTileAndAllocBuffer"; + TIFFDirectory *td = &tif->tif_dir; + tmsize_t tilesize = tif->tif_tilesize; + + if( *buf != NULL ) + { + return TIFFReadEncodedTile(tif, tile, *buf, size_to_read); + } + + if (!TIFFCheckRead(tif, 1)) + return ((tmsize_t)(-1)); + if (tile >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, + "%"PRIu32": Tile out of range, max %"PRIu32, + tile, td->td_nstrips); + return ((tmsize_t)(-1)); + } + + if (!TIFFFillTile(tif,tile)) + return((tmsize_t)(-1)); + + *buf = _TIFFmalloc(bufsizetoalloc); + if (*buf == NULL) { + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), + "No space for tile buffer"); + return((tmsize_t)(-1)); + } + _TIFFmemset(*buf, 0, bufsizetoalloc); + + if (size_to_read == (tmsize_t)(-1)) + size_to_read = tilesize; + else if (size_to_read > tilesize) + size_to_read = tilesize; + if( (*tif->tif_decodetile)(tif, + (uint8_t*) *buf, size_to_read, (uint16_t)(tile / td->td_stripsperimage))) { + (*tif->tif_postdecode)(tif, (uint8_t*) *buf, size_to_read); + return (size_to_read); + } else + return ((tmsize_t)(-1)); +} + +static tmsize_t +TIFFReadRawTile1(TIFF* tif, uint32_t tile, void* buf, tmsize_t size, const char* module) +{ + assert((tif->tif_flags&TIFF_NOREADRAW)==0); + if (!isMapped(tif)) { + tmsize_t cc; + + if (!SeekOK(tif, TIFFGetStrileOffset(tif, tile))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at row %"PRIu32", col %"PRIu32", tile %"PRIu32, + tif->tif_row, + tif->tif_col, + tile); + return ((tmsize_t)(-1)); + } + cc = TIFFReadFile(tif, buf, size); + if (cc != size) { + TIFFErrorExt(tif->tif_clientdata, module, + "Read error at row %"PRIu32", col %"PRIu32"; got %"TIFF_SSIZE_FORMAT" bytes, expected %"TIFF_SSIZE_FORMAT, + tif->tif_row, + tif->tif_col, + cc, + size); + return ((tmsize_t)(-1)); + } + } else { + tmsize_t ma,mb; + tmsize_t n; + ma=(tmsize_t)TIFFGetStrileOffset(tif, tile); + mb=ma+size; + if ((TIFFGetStrileOffset(tif, tile) > (uint64_t)TIFF_TMSIZE_T_MAX) || (ma > tif->tif_size)) + n=0; + else if ((mbtif->tif_size)) + n=tif->tif_size-ma; + else + n=size; + if (n!=size) { + TIFFErrorExt(tif->tif_clientdata, module, +"Read error at row %"PRIu32", col %"PRIu32", tile %"PRIu32"; got %"TIFF_SSIZE_FORMAT" bytes, expected %"TIFF_SSIZE_FORMAT, + tif->tif_row, + tif->tif_col, + tile, + n, + size); + return ((tmsize_t)(-1)); + } + _TIFFmemcpy(buf, tif->tif_base + ma, size); + } + return (size); +} + +/* + * Read a tile of data from the file. + */ +tmsize_t +TIFFReadRawTile(TIFF* tif, uint32_t tile, void* buf, tmsize_t size) +{ + static const char module[] = "TIFFReadRawTile"; + TIFFDirectory *td = &tif->tif_dir; + uint64_t bytecount64; + tmsize_t bytecountm; + + if (!TIFFCheckRead(tif, 1)) + return ((tmsize_t)(-1)); + if (tile >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, + "%"PRIu32": Tile out of range, max %"PRIu32, + tile, td->td_nstrips); + return ((tmsize_t)(-1)); + } + if (tif->tif_flags&TIFF_NOREADRAW) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Compression scheme does not support access to raw uncompressed data"); + return ((tmsize_t)(-1)); + } + bytecount64 = TIFFGetStrileByteCount(tif, tile); + if (size != (tmsize_t)(-1) && (uint64_t)size <= bytecount64) + bytecountm = size; + else + bytecountm = _TIFFCastUInt64ToSSize(tif, bytecount64, module); + if( bytecountm == 0 ) { + return ((tmsize_t)(-1)); + } + return (TIFFReadRawTile1(tif, tile, buf, bytecountm, module)); +} + +/* + * Read the specified tile and setup for decoding. The data buffer is + * expanded, as necessary, to hold the tile's data. + */ +int +TIFFFillTile(TIFF* tif, uint32_t tile) +{ + static const char module[] = "TIFFFillTile"; + TIFFDirectory *td = &tif->tif_dir; + + if ((tif->tif_flags&TIFF_NOREADRAW)==0) + { + uint64_t bytecount = TIFFGetStrileByteCount(tif, tile); + if( bytecount == 0 || bytecount > (uint64_t)TIFF_INT64_MAX ) { + TIFFErrorExt(tif->tif_clientdata, module, + "%"PRIu64": Invalid tile byte count, tile %"PRIu32, + bytecount, + tile); + return (0); + } + + /* To avoid excessive memory allocations: */ + /* Byte count should normally not be larger than a number of */ + /* times the uncompressed size plus some margin */ + if( bytecount > 1024 * 1024 ) + { + /* 10 and 4096 are just values that could be adjusted. */ + /* Hopefully they are safe enough for all codecs */ + tmsize_t stripsize = TIFFTileSize(tif); + if( stripsize != 0 && + (bytecount - 4096) / 10 > (uint64_t)stripsize ) + { + uint64_t newbytecount = (uint64_t)stripsize * 10 + 4096; + if( newbytecount == 0 || newbytecount > (uint64_t)TIFF_INT64_MAX ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Too large tile byte count %"PRIu64", tile %"PRIu32". Limiting to %"PRIu64, + bytecount, + tile, + newbytecount); + bytecount = newbytecount; + } + } + } + + if (isMapped(tif)) { + /* + * We must check for overflow, potentially causing + * an OOB read. Instead of simple + * + * TIFFGetStrileOffset(tif, tile)+bytecount > tif->tif_size + * + * comparison (which can overflow) we do the following + * two comparisons: + */ + if (bytecount > (uint64_t)tif->tif_size || + TIFFGetStrileOffset(tif, tile) > (uint64_t)tif->tif_size - bytecount) { + tif->tif_curtile = NOTILE; + return (0); + } + } + + if (isMapped(tif) && + (isFillOrder(tif, td->td_fillorder) + || (tif->tif_flags & TIFF_NOBITREV))) { + /* + * The image is mapped into memory and we either don't + * need to flip bits or the compression routine is + * going to handle this operation itself. In this + * case, avoid copying the raw data and instead just + * reference the data from the memory mapped file + * image. This assumes that the decompression + * routines do not modify the contents of the raw data + * buffer (if they try to, the application will get a + * fault since the file is mapped read-only). + */ + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + } + tif->tif_flags &= ~TIFF_MYBUFFER; + + tif->tif_rawdatasize = (tmsize_t)bytecount; + tif->tif_rawdata = + tif->tif_base + (tmsize_t)TIFFGetStrileOffset(tif, tile); + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = (tmsize_t) bytecount; + tif->tif_flags |= TIFF_BUFFERMMAP; + } else { + /* + * Expand raw data buffer, if needed, to hold data + * tile coming from file (perhaps should set upper + * bound on the size of a buffer we'll use?). + */ + tmsize_t bytecountm; + bytecountm=(tmsize_t)bytecount; + if ((uint64_t)bytecountm != bytecount) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + return(0); + } + if (bytecountm > tif->tif_rawdatasize) { + tif->tif_curtile = NOTILE; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Data buffer too small to hold tile %"PRIu32, + tile); + return (0); + } + } + if (tif->tif_flags&TIFF_BUFFERMMAP) { + tif->tif_curtile = NOTILE; + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + tif->tif_flags &= ~TIFF_BUFFERMMAP; + } + + if( isMapped(tif) ) + { + if (bytecountm > tif->tif_rawdatasize && + !TIFFReadBufferSetup(tif, 0, bytecountm)) + { + return (0); + } + if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata, + bytecountm, module) != bytecountm) + { + return (0); + } + } + else + { + if (TIFFReadRawStripOrTile2(tif, tile, 0, + bytecountm, module) != bytecountm) + { + return (0); + } + } + + + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = bytecountm; + + if (tif->tif_rawdata != NULL && + !isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, + tif->tif_rawdataloaded); + } + } + return (TIFFStartTile(tif, tile)); +} + +/* + * Setup the raw data buffer in preparation for + * reading a strip of raw data. If the buffer + * is specified as zero, then a buffer of appropriate + * size is allocated by the library. Otherwise, + * the client must guarantee that the buffer is + * large enough to hold any individual strip of + * raw data. + */ +int +TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size) +{ + static const char module[] = "TIFFReadBufferSetup"; + + assert((tif->tif_flags&TIFF_NOREADRAW)==0); + tif->tif_flags &= ~TIFF_BUFFERMMAP; + + if (tif->tif_rawdata) { + if (tif->tif_flags & TIFF_MYBUFFER) + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + } + if (bp) { + tif->tif_rawdatasize = size; + tif->tif_rawdata = (uint8_t*) bp; + tif->tif_flags &= ~TIFF_MYBUFFER; + } else { + tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64((uint64_t)size, 1024); + if (tif->tif_rawdatasize==0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Invalid buffer size"); + return (0); + } + /* Initialize to zero to avoid uninitialized buffers in case of */ + /* short reads (http://bugzilla.maptools.org/show_bug.cgi?id=2651) */ + tif->tif_rawdata = (uint8_t*) _TIFFcalloc(1, tif->tif_rawdatasize); + tif->tif_flags |= TIFF_MYBUFFER; + } + if (tif->tif_rawdata == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, + "No space for data buffer at scanline %"PRIu32, + tif->tif_row); + tif->tif_rawdatasize = 0; + return (0); + } + return (1); +} + +/* + * Set state to appear as if a + * strip has just been read in. + */ +static int +TIFFStartStrip(TIFF* tif, uint32_t strip) +{ + TIFFDirectory *td = &tif->tif_dir; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupdecode)(tif)) + return (0); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_curstrip = strip; + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + tif->tif_flags &= ~TIFF_BUF4WRITE; + + if (tif->tif_flags&TIFF_NOREADRAW) + { + tif->tif_rawcp = NULL; + tif->tif_rawcc = 0; + } + else + { + tif->tif_rawcp = tif->tif_rawdata; + if( tif->tif_rawdataloaded > 0 ) + tif->tif_rawcc = tif->tif_rawdataloaded; + else + tif->tif_rawcc = (tmsize_t)TIFFGetStrileByteCount(tif, strip); + } + if ((*tif->tif_predecode)(tif, + (uint16_t)(strip / td->td_stripsperimage)) == 0 ) { + /* Needed for example for scanline access, if tif_predecode */ + /* fails, and we try to read the same strip again. Without invalidating */ + /* tif_curstrip, we'd call tif_decoderow() on a possibly invalid */ + /* codec state. */ + tif->tif_curstrip = NOSTRIP; + return 0; + } + return 1; +} + +/* + * Set state to appear as if a + * tile has just been read in. + */ +static int +TIFFStartTile(TIFF* tif, uint32_t tile) +{ + static const char module[] = "TIFFStartTile"; + TIFFDirectory *td = &tif->tif_dir; + uint32_t howmany32; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupdecode)(tif)) + return (0); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_curtile = tile; + howmany32=TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth); + if (howmany32 == 0) { + TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles"); + return 0; + } + tif->tif_row = (tile % howmany32) * td->td_tilelength; + howmany32=TIFFhowmany_32(td->td_imagelength, td->td_tilelength); + if (howmany32 == 0) { + TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles"); + return 0; + } + tif->tif_col = (tile % howmany32) * td->td_tilewidth; + tif->tif_flags &= ~TIFF_BUF4WRITE; + if (tif->tif_flags&TIFF_NOREADRAW) + { + tif->tif_rawcp = NULL; + tif->tif_rawcc = 0; + } + else + { + tif->tif_rawcp = tif->tif_rawdata; + if( tif->tif_rawdataloaded > 0 ) + tif->tif_rawcc = tif->tif_rawdataloaded; + else + tif->tif_rawcc = (tmsize_t)TIFFGetStrileByteCount(tif, tile); + } + return ((*tif->tif_predecode)(tif, + (uint16_t)(tile / td->td_stripsperimage))); +} + +static int +TIFFCheckRead(TIFF* tif, int tiles) +{ + if (tif->tif_mode == O_WRONLY) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "File not open for reading"); + return (0); + } + if (tiles ^ isTiled(tif)) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, tiles ? + "Can not read tiles from a striped image" : + "Can not read scanlines from a tiled image"); + return (0); + } + return (1); +} + +/* Use the provided input buffer (inbuf, insize) and decompress it into + * (outbuf, outsize). + * This function replaces the use of TIFFReadEncodedStrip()/TIFFReadEncodedTile() + * when the user can provide the buffer for the input data, for example when + * he wants to avoid libtiff to read the strile offset/count values from the + * [Strip|Tile][Offsets/ByteCounts] array. + * inbuf content must be writable (if bit reversal is needed) + * Returns 1 in case of success, 0 otherwise. + */ +int TIFFReadFromUserBuffer(TIFF* tif, uint32_t strile, + void* inbuf, tmsize_t insize, + void* outbuf, tmsize_t outsize) +{ + static const char module[] = "TIFFReadFromUserBuffer"; + TIFFDirectory *td = &tif->tif_dir; + int ret = 1; + uint32_t old_tif_flags = tif->tif_flags; + tmsize_t old_rawdatasize = tif->tif_rawdatasize; + void* old_rawdata = tif->tif_rawdata; + + if (tif->tif_mode == O_WRONLY) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "File not open for reading"); + return 0; + } + if (tif->tif_flags&TIFF_NOREADRAW) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Compression scheme does not support access to raw uncompressed data"); + return 0; + } + + tif->tif_flags &= ~TIFF_MYBUFFER; + tif->tif_flags |= TIFF_BUFFERMMAP; + tif->tif_rawdatasize = insize; + tif->tif_rawdata = inbuf; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = insize; + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + { + TIFFReverseBits(inbuf, insize); + } + + if( TIFFIsTiled(tif) ) + { + if( !TIFFStartTile(tif, strile) || + !(*tif->tif_decodetile)(tif, (uint8_t*) outbuf, outsize, + (uint16_t)(strile / td->td_stripsperimage)) ) + { + ret = 0; + } + } + else + { + uint32_t rowsperstrip=td->td_rowsperstrip; + uint32_t stripsperplane; + if (rowsperstrip>td->td_imagelength) + rowsperstrip=td->td_imagelength; + stripsperplane= TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip); + if( !TIFFStartStrip(tif, strile) || + !(*tif->tif_decodestrip)(tif, (uint8_t*) outbuf, outsize, + (uint16_t)(strile / stripsperplane)) ) + { + ret = 0; + } + } + if( ret ) + { + (*tif->tif_postdecode)(tif, (uint8_t*) outbuf, outsize); + } + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + { + TIFFReverseBits(inbuf, insize); + } + + tif->tif_flags = old_tif_flags; + tif->tif_rawdatasize = old_rawdatasize; + tif->tif_rawdata = old_rawdata; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = 0; + + return ret; +} + +void +_TIFFNoPostDecode(TIFF* tif, uint8_t* buf, tmsize_t cc) +{ + (void) tif; (void) buf; (void) cc; +} + +void +_TIFFSwab16BitData(TIFF* tif, uint8_t* buf, tmsize_t cc) +{ + (void) tif; + assert((cc & 1) == 0); + TIFFSwabArrayOfShort((uint16_t*) buf, cc / 2); +} + +void +_TIFFSwab24BitData(TIFF* tif, uint8_t* buf, tmsize_t cc) +{ + (void) tif; + assert((cc % 3) == 0); + TIFFSwabArrayOfTriples((uint8_t*) buf, cc / 3); +} + +void +_TIFFSwab32BitData(TIFF* tif, uint8_t* buf, tmsize_t cc) +{ + (void) tif; + assert((cc & 3) == 0); + TIFFSwabArrayOfLong((uint32_t*) buf, cc / 4); +} + +void +_TIFFSwab64BitData(TIFF* tif, uint8_t* buf, tmsize_t cc) +{ + (void) tif; + assert((cc & 7) == 0); + TIFFSwabArrayOfDouble((double*) buf, cc/8); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_strip.c b/libs/tiff/libtiff/tif_strip.c new file mode 100644 index 00000000000..d7b27526261 --- /dev/null +++ b/libs/tiff/libtiff/tif_strip.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Strip-organized Image Support Routines. + */ +#include "tiffiop.h" + +/* + * Compute which strip a (row,sample) value is in. + */ +uint32_t +TIFFComputeStrip(TIFF* tif, uint32_t row, uint16_t sample) +{ + static const char module[] = "TIFFComputeStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint32_t strip; + + strip = row / td->td_rowsperstrip; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, module, + "%lu: Sample out of range, max %lu", + (unsigned long) sample, (unsigned long) td->td_samplesperpixel); + return (0); + } + strip += (uint32_t)sample * td->td_stripsperimage; + } + return (strip); +} + +/* + * Compute how many strips are in an image. + */ +uint32_t +TIFFNumberOfStrips(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32_t nstrips; + + nstrips = (td->td_rowsperstrip == (uint32_t) -1 ? 1 : + TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip)); + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + nstrips = _TIFFMultiply32(tif, nstrips, (uint32_t)td->td_samplesperpixel, + "TIFFNumberOfStrips"); + return (nstrips); +} + +/* + * Compute the # bytes in a variable height, row-aligned strip. + */ +uint64_t +TIFFVStripSize64(TIFF* tif, uint32_t nrows) +{ + static const char module[] = "TIFFVStripSize64"; + TIFFDirectory *td = &tif->tif_dir; + if (nrows==(uint32_t)(-1)) + nrows=td->td_imagelength; + if ((td->td_planarconfig==PLANARCONFIG_CONTIG)&& + (td->td_photometric == PHOTOMETRIC_YCBCR)&& + (!isUpSampled(tif))) + { + /* + * Packed YCbCr data contain one Cb+Cr for every + * HorizontalSampling*VerticalSampling Y values. + * Must also roundup width and height when calculating + * since images that are not a multiple of the + * horizontal/vertical subsampling area include + * YCbCr data for the extended image. + */ + uint16_t ycbcrsubsampling[2]; + uint16_t samplingblock_samples; + uint32_t samplingblocks_hor; + uint32_t samplingblocks_ver; + uint64_t samplingrow_samples; + uint64_t samplingrow_size; + if(td->td_samplesperpixel!=3) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Invalid td_samplesperpixel value"); + return 0; + } + TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,ycbcrsubsampling+0, + ycbcrsubsampling+1); + if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4) + ||(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && ycbcrsubsampling[1] != 4)) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Invalid YCbCr subsampling (%dx%d)", + ycbcrsubsampling[0], + ycbcrsubsampling[1] ); + return 0; + } + samplingblock_samples=ycbcrsubsampling[0]*ycbcrsubsampling[1]+2; + samplingblocks_hor=TIFFhowmany_32(td->td_imagewidth,ycbcrsubsampling[0]); + samplingblocks_ver=TIFFhowmany_32(nrows,ycbcrsubsampling[1]); + samplingrow_samples=_TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module); + samplingrow_size=TIFFhowmany8_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module)); + return(_TIFFMultiply64(tif,samplingrow_size,samplingblocks_ver,module)); + } + else + return(_TIFFMultiply64(tif,nrows,TIFFScanlineSize64(tif),module)); +} +tmsize_t +TIFFVStripSize(TIFF* tif, uint32_t nrows) +{ + static const char module[] = "TIFFVStripSize"; + uint64_t m; + m=TIFFVStripSize64(tif,nrows); + return _TIFFCastUInt64ToSSize(tif, m, module); +} + +/* + * Compute the # bytes in a raw strip. + */ +uint64_t +TIFFRawStripSize64(TIFF* tif, uint32_t strip) +{ + static const char module[] = "TIFFRawStripSize64"; + uint64_t bytecount = TIFFGetStrileByteCount(tif, strip); + + if (bytecount == 0) + { + TIFFErrorExt(tif->tif_clientdata, module, + "%"PRIu64": Invalid strip byte count, strip %lu", + (uint64_t) bytecount, + (unsigned long) strip); + bytecount = (uint64_t) -1; + } + + return bytecount; +} +tmsize_t +TIFFRawStripSize(TIFF* tif, uint32_t strip) +{ + static const char module[] = "TIFFRawStripSize"; + uint64_t m; + tmsize_t n; + m=TIFFRawStripSize64(tif,strip); + if (m==(uint64_t)(-1)) + n=(tmsize_t)(-1); + else + { + n=(tmsize_t)m; + if ((uint64_t)n != m) + { + TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); + n=0; + } + } + return(n); +} + +/* + * Compute the # bytes in a (row-aligned) strip. + * + * Note that if RowsPerStrip is larger than the + * recorded ImageLength, then the strip size is + * truncated to reflect the actual space required + * to hold the strip. + */ +uint64_t +TIFFStripSize64(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + uint32_t rps = td->td_rowsperstrip; + if (rps > td->td_imagelength) + rps = td->td_imagelength; + return (TIFFVStripSize64(tif, rps)); +} +tmsize_t +TIFFStripSize(TIFF* tif) +{ + static const char module[] = "TIFFStripSize"; + uint64_t m; + m=TIFFStripSize64(tif); + return _TIFFCastUInt64ToSSize(tif, m, module); +} + +/* + * Compute a default strip size based on the image + * characteristics and a requested value. If the + * request is <1 then we choose a strip size according + * to certain heuristics. + */ +uint32_t +TIFFDefaultStripSize(TIFF* tif, uint32_t request) +{ + return (*tif->tif_defstripsize)(tif, request); +} + +uint32_t +_TIFFDefaultStripSize(TIFF* tif, uint32_t s) +{ + if ((int32_t) s < 1) { + /* + * If RowsPerStrip is unspecified, try to break the + * image up into strips that are approximately + * STRIP_SIZE_DEFAULT bytes long. + */ + uint64_t scanlinesize; + uint64_t rows; + scanlinesize=TIFFScanlineSize64(tif); + if (scanlinesize==0) + scanlinesize=1; + rows= (uint64_t)STRIP_SIZE_DEFAULT / scanlinesize; + if (rows==0) + rows=1; + else if (rows>0xFFFFFFFF) + rows=0xFFFFFFFF; + s=(uint32_t)rows; + } + return (s); +} + +/* + * Return the number of bytes to read/write in a call to + * one of the scanline-oriented i/o routines. Note that + * this number may be 1/samples-per-pixel if data is + * stored as separate planes. + * The ScanlineSize in case of YCbCrSubsampling is defined as the + * strip size divided by the strip height, i.e. the size of a pack of vertical + * subsampling lines divided by vertical subsampling. It should thus make + * sense when multiplied by a multiple of vertical subsampling. + */ +uint64_t +TIFFScanlineSize64(TIFF* tif) +{ + static const char module[] = "TIFFScanlineSize64"; + TIFFDirectory *td = &tif->tif_dir; + uint64_t scanline_size; + if (td->td_planarconfig==PLANARCONFIG_CONTIG) + { + if ((td->td_photometric==PHOTOMETRIC_YCBCR)&& + (td->td_samplesperpixel==3)&& + (!isUpSampled(tif))) + { + uint16_t ycbcrsubsampling[2]; + uint16_t samplingblock_samples; + uint32_t samplingblocks_hor; + uint64_t samplingrow_samples; + uint64_t samplingrow_size; + if(td->td_samplesperpixel!=3) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Invalid td_samplesperpixel value"); + return 0; + } + TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING, + ycbcrsubsampling+0, + ycbcrsubsampling+1); + if (((ycbcrsubsampling[0]!=1)&&(ycbcrsubsampling[0]!=2)&&(ycbcrsubsampling[0]!=4)) || + ((ycbcrsubsampling[1]!=1)&&(ycbcrsubsampling[1]!=2)&&(ycbcrsubsampling[1]!=4))) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Invalid YCbCr subsampling"); + return 0; + } + samplingblock_samples = ycbcrsubsampling[0]*ycbcrsubsampling[1]+2; + samplingblocks_hor = TIFFhowmany_32(td->td_imagewidth,ycbcrsubsampling[0]); + samplingrow_samples = _TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module); + samplingrow_size = TIFFhowmany_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module),8); + scanline_size = (samplingrow_size/ycbcrsubsampling[1]); + } + else + { + uint64_t scanline_samples; + scanline_samples=_TIFFMultiply64(tif,td->td_imagewidth,td->td_samplesperpixel,module); + scanline_size=TIFFhowmany_64(_TIFFMultiply64(tif,scanline_samples,td->td_bitspersample,module),8); + } + } + else + { + scanline_size=TIFFhowmany_64(_TIFFMultiply64(tif,td->td_imagewidth,td->td_bitspersample,module),8); + } + if (scanline_size == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Computed scanline size is zero"); + return 0; + } + return(scanline_size); +} +tmsize_t +TIFFScanlineSize(TIFF* tif) +{ + static const char module[] = "TIFFScanlineSize"; + uint64_t m; + m=TIFFScanlineSize64(tif); + return _TIFFCastUInt64ToSSize(tif, m, module); +} + +/* + * Return the number of bytes required to store a complete + * decoded and packed raster scanline (as opposed to the + * I/O size returned by TIFFScanlineSize which may be less + * if data is store as separate planes). + */ +uint64_t +TIFFRasterScanlineSize64(TIFF* tif) +{ + static const char module[] = "TIFFRasterScanlineSize64"; + TIFFDirectory *td = &tif->tif_dir; + uint64_t scanline; + + scanline = _TIFFMultiply64(tif, td->td_bitspersample, td->td_imagewidth, module); + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + scanline = _TIFFMultiply64(tif, scanline, td->td_samplesperpixel, module); + return (TIFFhowmany8_64(scanline)); + } else + return (_TIFFMultiply64(tif, TIFFhowmany8_64(scanline), + td->td_samplesperpixel, module)); +} +tmsize_t +TIFFRasterScanlineSize(TIFF* tif) +{ + static const char module[] = "TIFFRasterScanlineSize"; + uint64_t m; + m=TIFFRasterScanlineSize64(tif); + return _TIFFCastUInt64ToSSize(tif, m, module); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_swab.c b/libs/tiff/libtiff/tif_swab.c new file mode 100644 index 00000000000..3d4bb6ca3f2 --- /dev/null +++ b/libs/tiff/libtiff/tif_swab.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library Bit & Byte Swapping Support. + * + * XXX We assume short = 16-bits and long = 32-bits XXX + */ +#include "tiffiop.h" + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabShort) +void +TIFFSwabShort(uint16_t* wp) +{ + register unsigned char* cp = (unsigned char*) wp; + unsigned char t; + assert(sizeof(uint16_t) == 2); + t = cp[1]; cp[1] = cp[0]; cp[0] = t; +} +#endif + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabLong) +void +TIFFSwabLong(uint32_t* lp) +{ + register unsigned char* cp = (unsigned char*) lp; + unsigned char t; + assert(sizeof(uint32_t) == 4); + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; +} +#endif + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabLong8) +void +TIFFSwabLong8(uint64_t* lp) +{ + register unsigned char* cp = (unsigned char*) lp; + unsigned char t; + assert(sizeof(uint64_t) == 8); + t = cp[7]; cp[7] = cp[0]; cp[0] = t; + t = cp[6]; cp[6] = cp[1]; cp[1] = t; + t = cp[5]; cp[5] = cp[2]; cp[2] = t; + t = cp[4]; cp[4] = cp[3]; cp[3] = t; +} +#endif + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabArrayOfShort) +void +TIFFSwabArrayOfShort(register uint16_t* wp, tmsize_t n) +{ + register unsigned char* cp; + register unsigned char t; + assert(sizeof(uint16_t) == 2); + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char*) wp; + t = cp[1]; cp[1] = cp[0]; cp[0] = t; + wp++; + } +} +#endif + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabArrayOfTriples) +void +TIFFSwabArrayOfTriples(register uint8_t* tp, tmsize_t n) +{ + unsigned char* cp; + unsigned char t; + + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char*) tp; + t = cp[2]; cp[2] = cp[0]; cp[0] = t; + tp += 3; + } +} +#endif + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabArrayOfLong) +void +TIFFSwabArrayOfLong(register uint32_t* lp, tmsize_t n) +{ + register unsigned char *cp; + register unsigned char t; + assert(sizeof(uint32_t) == 4); + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char *)lp; + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; + lp++; + } +} +#endif + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabArrayOfLong8) +void +TIFFSwabArrayOfLong8(register uint64_t* lp, tmsize_t n) +{ + register unsigned char *cp; + register unsigned char t; + assert(sizeof(uint64_t) == 8); + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char *)lp; + t = cp[7]; cp[7] = cp[0]; cp[0] = t; + t = cp[6]; cp[6] = cp[1]; cp[1] = t; + t = cp[5]; cp[5] = cp[2]; cp[2] = t; + t = cp[4]; cp[4] = cp[3]; cp[3] = t; + lp++; + } +} +#endif + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabFloat) +void +TIFFSwabFloat(float* fp) +{ + register unsigned char* cp = (unsigned char*) fp; + unsigned char t; + assert(sizeof(float)==4); + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; +} +#endif + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabArrayOfFloat) +void +TIFFSwabArrayOfFloat(register float* fp, tmsize_t n) +{ + register unsigned char *cp; + register unsigned char t; + assert(sizeof(float)==4); + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char *)fp; + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; + fp++; + } +} +#endif + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabDouble) +void +TIFFSwabDouble(double *dp) +{ + register unsigned char* cp = (unsigned char*) dp; + unsigned char t; + assert(sizeof(double)==8); + t = cp[7]; cp[7] = cp[0]; cp[0] = t; + t = cp[6]; cp[6] = cp[1]; cp[1] = t; + t = cp[5]; cp[5] = cp[2]; cp[2] = t; + t = cp[4]; cp[4] = cp[3]; cp[3] = t; +} +#endif + +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabArrayOfDouble) +void +TIFFSwabArrayOfDouble(double* dp, tmsize_t n) +{ + register unsigned char *cp; + register unsigned char t; + assert(sizeof(double)==8); + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char *)dp; + t = cp[7]; cp[7] = cp[0]; cp[0] = t; + t = cp[6]; cp[6] = cp[1]; cp[1] = t; + t = cp[5]; cp[5] = cp[2]; cp[2] = t; + t = cp[4]; cp[4] = cp[3]; cp[3] = t; + dp++; + } +} +#endif + +/* + * Bit reversal tables. TIFFBitRevTable[] gives + * the bit reversed value of . Used in various + * places in the library when the FillOrder requires + * bit reversal of byte values (e.g. CCITT Fax 3 + * encoding/decoding). TIFFNoBitRevTable is provided + * for algorithms that want an equivalent table that + * do not reverse bit values. + */ +static const unsigned char TIFFBitRevTable[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; +static const unsigned char TIFFNoBitRevTable[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}; + +const unsigned char* +TIFFGetBitRevTable(int reversed) +{ + return (reversed ? TIFFBitRevTable : TIFFNoBitRevTable); +} + +void +TIFFReverseBits(uint8_t* cp, tmsize_t n) +{ + for (; n > 8; n -= 8) { + cp[0] = TIFFBitRevTable[cp[0]]; + cp[1] = TIFFBitRevTable[cp[1]]; + cp[2] = TIFFBitRevTable[cp[2]]; + cp[3] = TIFFBitRevTable[cp[3]]; + cp[4] = TIFFBitRevTable[cp[4]]; + cp[5] = TIFFBitRevTable[cp[5]]; + cp[6] = TIFFBitRevTable[cp[6]]; + cp[7] = TIFFBitRevTable[cp[7]]; + cp += 8; + } + while (n-- > 0) { + *cp = TIFFBitRevTable[*cp]; + cp++; + } +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_thunder.c b/libs/tiff/libtiff/tif_thunder.c new file mode 100644 index 00000000000..3e703d8b2d0 --- /dev/null +++ b/libs/tiff/libtiff/tif_thunder.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#include +#ifdef THUNDER_SUPPORT +/* + * TIFF Library. + * + * ThunderScan 4-bit Compression Algorithm Support + */ + +/* + * ThunderScan uses an encoding scheme designed for + * 4-bit pixel values. Data is encoded in bytes, with + * each byte split into a 2-bit code word and a 6-bit + * data value. The encoding gives raw data, runs of + * pixels, or pixel values encoded as a delta from the + * previous pixel value. For the latter, either 2-bit + * or 3-bit delta values are used, with the deltas packed + * into a single byte. + */ +#define THUNDER_DATA 0x3f /* mask for 6-bit data */ +#define THUNDER_CODE 0xc0 /* mask for 2-bit code word */ +/* code values */ +#define THUNDER_RUN 0x00 /* run of pixels w/ encoded count */ +#define THUNDER_2BITDELTAS 0x40 /* 3 pixels w/ encoded 2-bit deltas */ +#define DELTA2_SKIP 2 /* skip code for 2-bit deltas */ +#define THUNDER_3BITDELTAS 0x80 /* 2 pixels w/ encoded 3-bit deltas */ +#define DELTA3_SKIP 4 /* skip code for 3-bit deltas */ +#define THUNDER_RAW 0xc0 /* raw data encoded */ + +static const int twobitdeltas[4] = { 0, 1, 0, -1 }; +static const int threebitdeltas[8] = { 0, 1, 2, 3, 0, -3, -2, -1 }; + +#define SETPIXEL(op, v) { \ + lastpixel = (v) & 0xf; \ + if ( npixels < maxpixels ) \ + { \ + if (npixels++ & 1) \ + *op++ |= lastpixel; \ + else \ + op[0] = (uint8_t) (lastpixel << 4); \ + } \ +} + +static int +ThunderSetupDecode(TIFF* tif) +{ + static const char module[] = "ThunderSetupDecode"; + + if( tif->tif_dir.td_bitspersample != 4 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Wrong bitspersample value (%d), Thunder decoder only supports 4bits per sample.", + (int) tif->tif_dir.td_bitspersample ); + return 0; + } + + + return (1); +} + +static int +ThunderDecode(TIFF* tif, uint8_t* op, tmsize_t maxpixels) +{ + static const char module[] = "ThunderDecode"; + register unsigned char *bp; + register tmsize_t cc; + unsigned int lastpixel; + tmsize_t npixels; + + bp = (unsigned char *)tif->tif_rawcp; + cc = tif->tif_rawcc; + lastpixel = 0; + npixels = 0; + while (cc > 0 && npixels < maxpixels) { + int n, delta; + + n = *bp++; + cc--; + switch (n & THUNDER_CODE) { + case THUNDER_RUN: /* pixel run */ + /* + * Replicate the last pixel n times, + * where n is the lower-order 6 bits. + */ + if (npixels & 1) { + op[0] |= lastpixel; + lastpixel = *op++; npixels++; n--; + } else + lastpixel |= lastpixel << 4; + npixels += n; + if (npixels < maxpixels) { + for (; n > 0; n -= 2) + *op++ = (uint8_t) lastpixel; + } + if (n == -1) + *--op &= 0xf0; + lastpixel &= 0xf; + break; + case THUNDER_2BITDELTAS: /* 2-bit deltas */ + if ((delta = ((n >> 4) & 3)) != DELTA2_SKIP) + SETPIXEL(op, (unsigned)((int)lastpixel + twobitdeltas[delta])); + if ((delta = ((n >> 2) & 3)) != DELTA2_SKIP) + SETPIXEL(op, (unsigned)((int)lastpixel + twobitdeltas[delta])); + if ((delta = (n & 3)) != DELTA2_SKIP) + SETPIXEL(op, (unsigned)((int)lastpixel + twobitdeltas[delta])); + break; + case THUNDER_3BITDELTAS: /* 3-bit deltas */ + if ((delta = ((n >> 3) & 7)) != DELTA3_SKIP) + SETPIXEL(op, (unsigned)((int)lastpixel + threebitdeltas[delta])); + if ((delta = (n & 7)) != DELTA3_SKIP) + SETPIXEL(op, (unsigned)((int)lastpixel + threebitdeltas[delta])); + break; + case THUNDER_RAW: /* raw data */ + SETPIXEL(op, n); + break; + } + } + tif->tif_rawcp = (uint8_t*) bp; + tif->tif_rawcc = cc; + if (npixels != maxpixels) { + TIFFErrorExt(tif->tif_clientdata, module, + "%s data at scanline %lu (%"PRIu64" != %"PRIu64")", + npixels < maxpixels ? "Not enough" : "Too much", + (unsigned long) tif->tif_row, + (uint64_t) npixels, + (uint64_t) maxpixels); + return (0); + } + + return (1); +} + +static int +ThunderDecodeRow(TIFF* tif, uint8_t* buf, tmsize_t occ, uint16_t s) +{ + static const char module[] = "ThunderDecodeRow"; + uint8_t* row = buf; + + (void) s; + if (occ % tif->tif_scanlinesize) + { + TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read"); + return (0); + } + while (occ > 0) { + if (!ThunderDecode(tif, row, tif->tif_dir.td_imagewidth)) + return (0); + occ -= tif->tif_scanlinesize; + row += tif->tif_scanlinesize; + } + return (1); +} + +int +TIFFInitThunderScan(TIFF* tif, int scheme) +{ + (void) scheme; + + tif->tif_setupdecode = ThunderSetupDecode; + tif->tif_decoderow = ThunderDecodeRow; + tif->tif_decodestrip = ThunderDecodeRow; + return (1); +} +#endif /* THUNDER_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_tile.c b/libs/tiff/libtiff/tif_tile.c new file mode 100644 index 00000000000..058be9f7883 --- /dev/null +++ b/libs/tiff/libtiff/tif_tile.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Tiled Image Support Routines. + */ +#include "tiffiop.h" + +/* + * Compute which tile an (x,y,z,s) value is in. + */ +uint32_t +TIFFComputeTile(TIFF* tif, uint32_t x, uint32_t y, uint32_t z, uint16_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32_t dx = td->td_tilewidth; + uint32_t dy = td->td_tilelength; + uint32_t dz = td->td_tiledepth; + uint32_t tile = 1; + + if (td->td_imagedepth == 1) + z = 0; + if (dx == (uint32_t) -1) + dx = td->td_imagewidth; + if (dy == (uint32_t) -1) + dy = td->td_imagelength; + if (dz == (uint32_t) -1) + dz = td->td_imagedepth; + if (dx != 0 && dy != 0 && dz != 0) { + uint32_t xpt = TIFFhowmany_32(td->td_imagewidth, dx); + uint32_t ypt = TIFFhowmany_32(td->td_imagelength, dy); + uint32_t zpt = TIFFhowmany_32(td->td_imagedepth, dz); + + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + tile = (xpt*ypt*zpt)*s + + (xpt*ypt)*(z/dz) + + xpt*(y/dy) + + x/dx; + else + tile = (xpt*ypt)*(z/dz) + xpt*(y/dy) + x/dx; + } + return (tile); +} + +/* + * Check an (x,y,z,s) coordinate + * against the image bounds. + */ +int +TIFFCheckTile(TIFF* tif, uint32_t x, uint32_t y, uint32_t z, uint16_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (x >= td->td_imagewidth) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Col out of range, max %lu", + (unsigned long) x, + (unsigned long) (td->td_imagewidth - 1)); + return (0); + } + if (y >= td->td_imagelength) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Row out of range, max %lu", + (unsigned long) y, + (unsigned long) (td->td_imagelength - 1)); + return (0); + } + if (z >= td->td_imagedepth) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Depth out of range, max %lu", + (unsigned long) z, + (unsigned long) (td->td_imagedepth - 1)); + return (0); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && + s >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, + "%lu: Sample out of range, max %lu", + (unsigned long) s, + (unsigned long) (td->td_samplesperpixel - 1)); + return (0); + } + return (1); +} + +/* + * Compute how many tiles are in an image. + */ +uint32_t +TIFFNumberOfTiles(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32_t dx = td->td_tilewidth; + uint32_t dy = td->td_tilelength; + uint32_t dz = td->td_tiledepth; + uint32_t ntiles; + + if (dx == (uint32_t) -1) + dx = td->td_imagewidth; + if (dy == (uint32_t) -1) + dy = td->td_imagelength; + if (dz == (uint32_t) -1) + dz = td->td_imagedepth; + ntiles = (dx == 0 || dy == 0 || dz == 0) ? 0 : + _TIFFMultiply32(tif, _TIFFMultiply32(tif, TIFFhowmany_32(td->td_imagewidth, dx), + TIFFhowmany_32(td->td_imagelength, dy), + "TIFFNumberOfTiles"), + TIFFhowmany_32(td->td_imagedepth, dz), "TIFFNumberOfTiles"); + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + ntiles = _TIFFMultiply32(tif, ntiles, td->td_samplesperpixel, + "TIFFNumberOfTiles"); + return (ntiles); +} + +/* + * Compute the # bytes in each row of a tile. + */ +uint64_t +TIFFTileRowSize64(TIFF* tif) +{ + static const char module[] = "TIFFTileRowSize64"; + TIFFDirectory *td = &tif->tif_dir; + uint64_t rowsize; + uint64_t tilerowsize; + + if (td->td_tilelength == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Tile length is zero"); + return 0; + } + if (td->td_tilewidth == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Tile width is zero"); + return (0); + } + rowsize = _TIFFMultiply64(tif, td->td_bitspersample, td->td_tilewidth, + "TIFFTileRowSize"); + if (td->td_planarconfig == PLANARCONFIG_CONTIG) + { + if (td->td_samplesperpixel == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Samples per pixel is zero"); + return 0; + } + rowsize = _TIFFMultiply64(tif, rowsize, td->td_samplesperpixel, + "TIFFTileRowSize"); + } + tilerowsize=TIFFhowmany8_64(rowsize); + if (tilerowsize == 0) + { + TIFFErrorExt(tif->tif_clientdata,module,"Computed tile row size is zero"); + return 0; + } + return (tilerowsize); +} +tmsize_t +TIFFTileRowSize(TIFF* tif) +{ + static const char module[] = "TIFFTileRowSize"; + uint64_t m; + m=TIFFTileRowSize64(tif); + return _TIFFCastUInt64ToSSize(tif, m, module); +} + +/* + * Compute the # bytes in a variable length, row-aligned tile. + */ +uint64_t +TIFFVTileSize64(TIFF* tif, uint32_t nrows) +{ + static const char module[] = "TIFFVTileSize64"; + TIFFDirectory *td = &tif->tif_dir; + if (td->td_tilelength == 0 || td->td_tilewidth == 0 || + td->td_tiledepth == 0) + return (0); + if ((td->td_planarconfig==PLANARCONFIG_CONTIG)&& + (td->td_photometric==PHOTOMETRIC_YCBCR)&& + (td->td_samplesperpixel==3)&& + (!isUpSampled(tif))) + { + /* + * Packed YCbCr data contain one Cb+Cr for every + * HorizontalSampling*VerticalSampling Y values. + * Must also roundup width and height when calculating + * since images that are not a multiple of the + * horizontal/vertical subsampling area include + * YCbCr data for the extended image. + */ + uint16_t ycbcrsubsampling[2]; + uint16_t samplingblock_samples; + uint32_t samplingblocks_hor; + uint32_t samplingblocks_ver; + uint64_t samplingrow_samples; + uint64_t samplingrow_size; + TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,ycbcrsubsampling+0, + ycbcrsubsampling+1); + if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4) + ||(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && ycbcrsubsampling[1] != 4)) + { + TIFFErrorExt(tif->tif_clientdata,module, + "Invalid YCbCr subsampling (%dx%d)", + ycbcrsubsampling[0], + ycbcrsubsampling[1] ); + return 0; + } + samplingblock_samples=ycbcrsubsampling[0]*ycbcrsubsampling[1]+2; + samplingblocks_hor=TIFFhowmany_32(td->td_tilewidth,ycbcrsubsampling[0]); + samplingblocks_ver=TIFFhowmany_32(nrows,ycbcrsubsampling[1]); + samplingrow_samples=_TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module); + samplingrow_size=TIFFhowmany8_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module)); + return(_TIFFMultiply64(tif,samplingrow_size,samplingblocks_ver,module)); + } + else + return(_TIFFMultiply64(tif,nrows,TIFFTileRowSize64(tif),module)); +} +tmsize_t +TIFFVTileSize(TIFF* tif, uint32_t nrows) +{ + static const char module[] = "TIFFVTileSize"; + uint64_t m; + m=TIFFVTileSize64(tif,nrows); + return _TIFFCastUInt64ToSSize(tif, m, module); +} + +/* + * Compute the # bytes in a row-aligned tile. + */ +uint64_t +TIFFTileSize64(TIFF* tif) +{ + return (TIFFVTileSize64(tif, tif->tif_dir.td_tilelength)); +} +tmsize_t +TIFFTileSize(TIFF* tif) +{ + static const char module[] = "TIFFTileSize"; + uint64_t m; + m=TIFFTileSize64(tif); + return _TIFFCastUInt64ToSSize(tif, m, module); +} + +/* + * Compute a default tile size based on the image + * characteristics and a requested value. If a + * request is <1 then we choose a size according + * to certain heuristics. + */ +void +TIFFDefaultTileSize(TIFF* tif, uint32_t* tw, uint32_t* th) +{ + (*tif->tif_deftilesize)(tif, tw, th); +} + +void +_TIFFDefaultTileSize(TIFF* tif, uint32_t* tw, uint32_t* th) +{ + (void) tif; + if (*(int32_t*) tw < 1) + *tw = 256; + if (*(int32_t*) th < 1) + *th = 256; + /* roundup to a multiple of 16 per the spec */ + if (*tw & 0xf) + *tw = TIFFroundup_32(*tw, 16); + if (*th & 0xf) + *th = TIFFroundup_32(*th, 16); +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_warning.c b/libs/tiff/libtiff/tif_warning.c new file mode 100644 index 00000000000..8bba83da67d --- /dev/null +++ b/libs/tiff/libtiff/tif_warning.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +TIFFErrorHandlerExt _TIFFwarningHandlerExt = NULL; + +TIFFErrorHandler +TIFFSetWarningHandler(TIFFErrorHandler handler) +{ + TIFFErrorHandler prev = _TIFFwarningHandler; + _TIFFwarningHandler = handler; + return (prev); +} + +TIFFErrorHandlerExt +TIFFSetWarningHandlerExt(TIFFErrorHandlerExt handler) +{ + TIFFErrorHandlerExt prev = _TIFFwarningHandlerExt; + _TIFFwarningHandlerExt = handler; + return (prev); +} + +void WINAPIV +TIFFWarning(const char* module, const char* fmt, ...) +{ + va_list ap; + if (_TIFFwarningHandler) { + va_start(ap, fmt); + (*_TIFFwarningHandler)(module, fmt, ap); + va_end(ap); + } + if (_TIFFwarningHandlerExt) { + va_start(ap, fmt); + (*_TIFFwarningHandlerExt)(0, module, fmt, ap); + va_end(ap); + } +} + +void WINAPIV +TIFFWarningExt(thandle_t fd, const char* module, const char* fmt, ...) +{ + va_list ap; + if (_TIFFwarningHandler) { + va_start(ap, fmt); + (*_TIFFwarningHandler)(module, fmt, ap); + va_end(ap); + } + if (_TIFFwarningHandlerExt) { + va_start(ap, fmt); + (*_TIFFwarningHandlerExt)(fd, module, fmt, ap); + va_end(ap); + } +} + + +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_win32.c b/libs/tiff/libtiff/tif_win32.c new file mode 100644 index 00000000000..c6ca1519cb0 --- /dev/null +++ b/libs/tiff/libtiff/tif_win32.c @@ -0,0 +1,437 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library Win32-specific Routines. Adapted from tif_unix.c 4/5/95 by + * Scott Wagner (wagner@itek.com), Itek Graphix, Rochester, NY USA + */ + +#include "tiffiop.h" + +#include + +/* + CreateFileA/CreateFileW return type 'HANDLE' while TIFFFdOpen() takes 'int', + which is formally incompatible and can even seemingly be of different size: + HANDLE is 64 bit under Win64, while int is still 32 bits there. + + However, only the lower 32 bits of a HANDLE are significant under Win64 as, + for interoperability reasons, they must have the same values in 32- and + 64-bit programs running on the same system, see + + https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication + + Because of this, it is safe to define the following trivial functions for + casting between ints and HANDLEs, which are only really needed to avoid + compiler warnings (and, perhaps, to make the code slightly more clear). + Note that using the intermediate cast to "intptr_t" is crucial for warning + avoidance, as this integer type has the same size as HANDLE in all builds. +*/ + +static inline thandle_t thandle_from_int(int ifd) +{ + return (thandle_t)(intptr_t)ifd; +} + +static inline int thandle_to_int(thandle_t fd) +{ + return (int)(intptr_t)fd; +} + +static tmsize_t +_tiffReadProc(thandle_t fd, void* buf, tmsize_t size) +{ + /* tmsize_t is 64bit on 64bit systems, but the WinAPI ReadFile takes + * 32bit sizes, so we loop through the data in suitable 32bit sized + * chunks */ + uint8_t* ma; + uint64_t mb; + DWORD n; + DWORD o; + tmsize_t p; + ma=(uint8_t*)buf; + mb=size; + p=0; + while (mb>0) + { + n=0x80000000UL; + if ((uint64_t)n>mb) + n=(DWORD)mb; + if (!ReadFile(fd,(LPVOID)ma,n,&o,NULL)) + return(0); + ma+=o; + mb-=o; + p+=o; + if (o!=n) + break; + } + return(p); +} + +static tmsize_t +_tiffWriteProc(thandle_t fd, void* buf, tmsize_t size) +{ + /* tmsize_t is 64bit on 64bit systems, but the WinAPI WriteFile takes + * 32bit sizes, so we loop through the data in suitable 32bit sized + * chunks */ + uint8_t* ma; + uint64_t mb; + DWORD n; + DWORD o; + tmsize_t p; + ma=(uint8_t*)buf; + mb=size; + p=0; + while (mb>0) + { + n=0x80000000UL; + if ((uint64_t)n>mb) + n=(DWORD)mb; + if (!WriteFile(fd,(LPVOID)ma,n,&o,NULL)) + return(0); + ma+=o; + mb-=o; + p+=o; + if (o!=n) + break; + } + return(p); +} + +static uint64_t +_tiffSeekProc(thandle_t fd, uint64_t off, int whence) +{ + LARGE_INTEGER offli; + DWORD dwMoveMethod; + offli.QuadPart = off; + switch(whence) + { + case SEEK_SET: + dwMoveMethod = FILE_BEGIN; + break; + case SEEK_CUR: + dwMoveMethod = FILE_CURRENT; + break; + case SEEK_END: + dwMoveMethod = FILE_END; + break; + default: + dwMoveMethod = FILE_BEGIN; + break; + } + offli.LowPart=SetFilePointer(fd,offli.LowPart,&offli.HighPart,dwMoveMethod); + if ((offli.LowPart==INVALID_SET_FILE_POINTER)&&(GetLastError()!=NO_ERROR)) + offli.QuadPart=0; + return(offli.QuadPart); +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (CloseHandle(fd) ? 0 : -1); +} + +static uint64_t +_tiffSizeProc(thandle_t fd) +{ + LARGE_INTEGER m; + if (GetFileSizeEx(fd,&m)) + return(m.QuadPart); + else + return(0); +} + +static int +_tiffDummyMapProc(thandle_t fd, void** pbase, toff_t* psize) +{ + (void) fd; + (void) pbase; + (void) psize; + return (0); +} + +/* + * From "Hermann Josef Hill" : + * + * Windows uses both a handle and a pointer for file mapping, + * but according to the SDK documentation and Richter's book + * "Advanced Windows Programming" it is safe to free the handle + * after obtaining the file mapping pointer + * + * This removes a nasty OS dependency and cures a problem + * with Visual C++ 5.0 + */ +static int +_tiffMapProc(thandle_t fd, void** pbase, toff_t* psize) +{ + uint64_t size; + tmsize_t sizem; + HANDLE hMapFile; + + size = _tiffSizeProc(fd); + sizem = (tmsize_t)size; + if (!size || (uint64_t)sizem!=size) + return (0); + + /* By passing in 0 for the maximum file size, it specifies that we + create a file mapping object for the full file size. */ + hMapFile = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, 0, NULL); + if (hMapFile == NULL) + return (0); + *pbase = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); + CloseHandle(hMapFile); + if (*pbase == NULL) + return (0); + *psize = size; + return(1); +} + +static void +_tiffDummyUnmapProc(thandle_t fd, void* base, toff_t size) +{ + (void) fd; + (void) base; + (void) size; +} + +static void +_tiffUnmapProc(thandle_t fd, void* base, toff_t size) +{ + (void) fd; + (void) size; + UnmapViewOfFile(base); +} + +/* + * Open a TIFF file descriptor for read/writing. + * Note that TIFFFdOpen and TIFFOpen recognise the character 'u' in the mode + * string, which forces the file to be opened unmapped. + */ +TIFF* +TIFFFdOpen(int ifd, const char* name, const char* mode) +{ + TIFF* tif; + int fSuppressMap; + int m; + fSuppressMap=0; + for (m=0; mode[m]!=0; m++) + { + if (mode[m]=='u') + { + fSuppressMap=1; + break; + } + } + tif = TIFFClientOpen(name, mode, thandle_from_int(ifd), + _tiffReadProc, _tiffWriteProc, + _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, + fSuppressMap ? _tiffDummyMapProc : _tiffMapProc, + fSuppressMap ? _tiffDummyUnmapProc : _tiffUnmapProc); + if (tif) + tif->tif_fd = ifd; + return (tif); +} + +#ifndef _WIN32_WCE + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + thandle_t fd; + int m; + DWORD dwMode; + TIFF* tif; + + m = _TIFFgetMode(mode, module); + + switch(m) { + case O_RDONLY: dwMode = OPEN_EXISTING; break; + case O_RDWR: dwMode = OPEN_ALWAYS; break; + case O_RDWR|O_CREAT: dwMode = OPEN_ALWAYS; break; + case O_RDWR|O_TRUNC: dwMode = CREATE_ALWAYS; break; + case O_RDWR|O_CREAT|O_TRUNC: dwMode = CREATE_ALWAYS; break; + default: return ((TIFF*)0); + } + + fd = (thandle_t)CreateFileA(name, + (m == O_RDONLY)?GENERIC_READ:(GENERIC_READ | GENERIC_WRITE), + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwMode, + (m == O_RDONLY)?FILE_ATTRIBUTE_READONLY:FILE_ATTRIBUTE_NORMAL, + NULL); + if (fd == INVALID_HANDLE_VALUE) { + TIFFErrorExt(0, module, "%s: Cannot open", name); + return ((TIFF *)0); + } + + tif = TIFFFdOpen(thandle_to_int(fd), name, mode); + if(!tif) + CloseHandle(fd); + return tif; +} + +/* + * Open a TIFF file with a Unicode filename, for read/writing. + */ +TIFF* +TIFFOpenW(const wchar_t* name, const char* mode) +{ + static const char module[] = "TIFFOpenW"; + thandle_t fd; + int m; + DWORD dwMode; + int mbsize; + char *mbname; + TIFF *tif; + + m = _TIFFgetMode(mode, module); + + switch(m) { + case O_RDONLY: dwMode = OPEN_EXISTING; break; + case O_RDWR: dwMode = OPEN_ALWAYS; break; + case O_RDWR|O_CREAT: dwMode = OPEN_ALWAYS; break; + case O_RDWR|O_TRUNC: dwMode = CREATE_ALWAYS; break; + case O_RDWR|O_CREAT|O_TRUNC: dwMode = CREATE_ALWAYS; break; + default: return ((TIFF*)0); + } + + fd = (thandle_t)CreateFileW(name, + (m == O_RDONLY)?GENERIC_READ:(GENERIC_READ|GENERIC_WRITE), + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwMode, + (m == O_RDONLY)?FILE_ATTRIBUTE_READONLY:FILE_ATTRIBUTE_NORMAL, + NULL); + if (fd == INVALID_HANDLE_VALUE) { + TIFFErrorExt(0, module, "%S: Cannot open", name); + return ((TIFF *)0); + } + + mbname = NULL; + mbsize = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL); + if (mbsize > 0) { + mbname = (char *)_TIFFmalloc(mbsize); + if (!mbname) { + TIFFErrorExt(0, module, + "Can't allocate space for filename conversion buffer"); + return ((TIFF*)0); + } + + WideCharToMultiByte(CP_ACP, 0, name, -1, mbname, mbsize, + NULL, NULL); + } + + tif = TIFFFdOpen(thandle_to_int(fd), + (mbname != NULL) ? mbname : "", mode); + if(!tif) + CloseHandle(fd); + + _TIFFfree(mbname); + + return tif; +} + +#endif /* ndef _WIN32_WCE */ + +void* +_TIFFmalloc(tmsize_t s) +{ + if (s == 0) + return ((void *) NULL); + + return (malloc((size_t) s)); +} + +void* _TIFFcalloc(tmsize_t nmemb, tmsize_t siz) +{ + if( nmemb == 0 || siz == 0 ) + return ((void *) NULL); + + return calloc((size_t) nmemb, (size_t)siz); +} + +void +_TIFFfree(void* p) +{ + free(p); +} + +void* +_TIFFrealloc(void* p, tmsize_t s) +{ + return (realloc(p, (size_t) s)); +} + +void +_TIFFmemset(void* p, int v, tmsize_t c) +{ + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(void* d, const void* s, tmsize_t c) +{ + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const void* p1, const void* p2, tmsize_t c) +{ + return (memcmp(p1, p2, (size_t) c)); +} + +#ifndef _WIN32_WCE + +static void +Win32WarningHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFwarningHandler = Win32WarningHandler; + +static void +Win32ErrorHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFerrorHandler = Win32ErrorHandler; + +#endif /* ndef _WIN32_WCE */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_write.c b/libs/tiff/libtiff/tif_write.c new file mode 100644 index 00000000000..b5ef21d0816 --- /dev/null +++ b/libs/tiff/libtiff/tif_write.c @@ -0,0 +1,857 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Scanline-oriented Write Support + */ +#include "tiffiop.h" +#include + +#define STRIPINCR 20 /* expansion factor on strip array */ + +#define WRITECHECKSTRIPS(tif, module) \ + (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),0,module)) +#define WRITECHECKTILES(tif, module) \ + (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),1,module)) +#define BUFFERCHECK(tif) \ + ((((tif)->tif_flags & TIFF_BUFFERSETUP) && tif->tif_rawdata) || \ + TIFFWriteBufferSetup((tif), NULL, (tmsize_t) -1)) + +static int TIFFGrowStrips(TIFF* tif, uint32_t delta, const char* module); +static int TIFFAppendToStrip(TIFF* tif, uint32_t strip, uint8_t* data, tmsize_t cc); + +int +TIFFWriteScanline(TIFF* tif, void* buf, uint32_t row, uint16_t sample) +{ + static const char module[] = "TIFFWriteScanline"; + register TIFFDirectory *td; + int status, imagegrew = 0; + uint32_t strip; + + if (!WRITECHECKSTRIPS(tif, module)) + return (-1); + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized more intelligently (using + * directory information). + */ + if (!BUFFERCHECK(tif)) + return (-1); + tif->tif_flags |= TIFF_BUF4WRITE; /* not strictly sure this is right*/ + + td = &tif->tif_dir; + /* + * Extend image length if needed + * (but only for PlanarConfig=1). + */ + if (row >= td->td_imagelength) { /* extend image */ + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not change \"ImageLength\" when using separate planes"); + return (-1); + } + td->td_imagelength = row+1; + imagegrew = 1; + } + /* + * Calculate strip and check for crossings. + */ + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, module, + "%lu: Sample out of range, max %lu", + (unsigned long) sample, (unsigned long) td->td_samplesperpixel); + return (-1); + } + strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip; + } else + strip = row / td->td_rowsperstrip; + /* + * Check strip array to make sure there's space. We don't support + * dynamically growing files that have data organized in separate + * bitplanes because it's too painful. In that case we require that + * the imagelength be set properly before the first write (so that the + * strips array will be fully allocated above). + */ + if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module)) + return (-1); + if (strip != tif->tif_curstrip) { + /* + * Changing strips -- flush any data present. + */ + if (!TIFFFlushData(tif)) + return (-1); + tif->tif_curstrip = strip; + /* + * Watch out for a growing image. The value of strips/image + * will initially be 1 (since it can't be deduced until the + * imagelength is known). + */ + if (strip >= td->td_stripsperimage && imagegrew) + td->td_stripsperimage = + TIFFhowmany_32(td->td_imagelength,td->td_rowsperstrip); + if (td->td_stripsperimage == 0) { + TIFFErrorExt(tif->tif_clientdata, module, "Zero strips per image"); + return (-1); + } + tif->tif_row = + (strip % td->td_stripsperimage) * td->td_rowsperstrip; + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return (-1); + tif->tif_flags |= TIFF_CODERSETUP; + } + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + if( td->td_stripbytecount_p[strip] > 0 ) + { + /* if we are writing over existing tiles, zero length */ + td->td_stripbytecount_p[strip] = 0; + + /* this forces TIFFAppendToStrip() to do a seek */ + tif->tif_curoff = 0; + } + + if (!(*tif->tif_preencode)(tif, sample)) + return (-1); + tif->tif_flags |= TIFF_POSTENCODE; + } + /* + * Ensure the write is either sequential or at the + * beginning of a strip (or that we can randomly + * access the data -- i.e. no encoding). + */ + if (row != tif->tif_row) { + if (row < tif->tif_row) { + /* + * Moving backwards within the same strip: + * backup to the start and then decode + * forward (below). + */ + tif->tif_row = (strip % td->td_stripsperimage) * + td->td_rowsperstrip; + tif->tif_rawcp = tif->tif_rawdata; + } + /* + * Seek forward to the desired row. + */ + if (!(*tif->tif_seek)(tif, row - tif->tif_row)) + return (-1); + tif->tif_row = row; + } + + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode(tif, (uint8_t*) buf, tif->tif_scanlinesize ); + + status = (*tif->tif_encoderow)(tif, (uint8_t*) buf, + tif->tif_scanlinesize, sample); + + /* we are now poised at the beginning of the next row */ + tif->tif_row = row + 1; + return (status); +} + +/* Make sure that at the first attempt of rewriting a tile/strip, we will have */ +/* more bytes available in the output buffer than the previous byte count, */ +/* so that TIFFAppendToStrip() will detect the overflow when it is called the first */ +/* time if the new compressed tile is bigger than the older one. (GDAL #4771) */ +static int _TIFFReserveLargeEnoughWriteBuffer(TIFF* tif, uint32_t strip_or_tile) +{ + TIFFDirectory *td = &tif->tif_dir; + if( td->td_stripbytecount_p[strip_or_tile] > 0 ) + { + /* The +1 is to ensure at least one extra bytes */ + /* The +4 is because the LZW encoder flushes 4 bytes before the limit */ + uint64_t safe_buffer_size = (uint64_t)(td->td_stripbytecount_p[strip_or_tile] + 1 + 4); + if( tif->tif_rawdatasize <= (tmsize_t)safe_buffer_size ) + { + if( !(TIFFWriteBufferSetup(tif, NULL, + (tmsize_t)TIFFroundup_64(safe_buffer_size, 1024))) ) + return 0; + } + + /* Force TIFFAppendToStrip() to consider placing data at end + of file. */ + tif->tif_curoff = 0; + } + return 1; +} + +/* + * Encode the supplied data and write it to the + * specified strip. + * + * NB: Image length must be setup before writing. + */ +tmsize_t +TIFFWriteEncodedStrip(TIFF* tif, uint32_t strip, void* data, tmsize_t cc) +{ + static const char module[] = "TIFFWriteEncodedStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint16_t sample; + + if (!WRITECHECKSTRIPS(tif, module)) + return ((tmsize_t) -1); + /* + * Check strip array to make sure there's space. + * We don't support dynamically growing files that + * have data organized in separate bitplanes because + * it's too painful. In that case we require that + * the imagelength be set properly before the first + * write (so that the strips array will be fully + * allocated above). + */ + if (strip >= td->td_nstrips) { + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not grow image by strips when using separate planes"); + return ((tmsize_t) -1); + } + if (!TIFFGrowStrips(tif, 1, module)) + return ((tmsize_t) -1); + td->td_stripsperimage = + TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip); + } + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized according to the directory + * info. + */ + if (!BUFFERCHECK(tif)) + return ((tmsize_t) -1); + + tif->tif_flags |= TIFF_BUF4WRITE; + tif->tif_curstrip = strip; + + if( !_TIFFReserveLargeEnoughWriteBuffer(tif, strip) ) { + return ((tmsize_t)(-1)); + } + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + if (td->td_stripsperimage == 0) { + TIFFErrorExt(tif->tif_clientdata, module, "Zero strips per image"); + return ((tmsize_t) -1); + } + + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return ((tmsize_t) -1); + tif->tif_flags |= TIFF_CODERSETUP; + } + + tif->tif_flags &= ~TIFF_POSTENCODE; + + /* shortcut to avoid an extra memcpy() */ + if( td->td_compression == COMPRESSION_NONE ) + { + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode(tif, (uint8_t*) data, cc ); + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits((uint8_t*) data, cc); + + if (cc > 0 && + !TIFFAppendToStrip(tif, strip, (uint8_t*) data, cc)) + return ((tmsize_t) -1); + return (cc); + } + + sample = (uint16_t)(strip / td->td_stripsperimage); + if (!(*tif->tif_preencode)(tif, sample)) + return ((tmsize_t) -1); + + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode(tif, (uint8_t*) data, cc ); + + if (!(*tif->tif_encodestrip)(tif, (uint8_t*) data, cc, sample)) + return ((tmsize_t) -1); + if (!(*tif->tif_postencode)(tif)) + return ((tmsize_t) -1); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc); + if (tif->tif_rawcc > 0 && + !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc)) + return ((tmsize_t) -1); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + return (cc); +} + +/* + * Write the supplied data to the specified strip. + * + * NB: Image length must be setup before writing. + */ +tmsize_t +TIFFWriteRawStrip(TIFF* tif, uint32_t strip, void* data, tmsize_t cc) +{ + static const char module[] = "TIFFWriteRawStrip"; + TIFFDirectory *td = &tif->tif_dir; + + if (!WRITECHECKSTRIPS(tif, module)) + return ((tmsize_t) -1); + /* + * Check strip array to make sure there's space. + * We don't support dynamically growing files that + * have data organized in separate bitplanes because + * it's too painful. In that case we require that + * the imagelength be set properly before the first + * write (so that the strips array will be fully + * allocated above). + */ + if (strip >= td->td_nstrips) { + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFErrorExt(tif->tif_clientdata, module, + "Can not grow image by strips when using separate planes"); + return ((tmsize_t) -1); + } + /* + * Watch out for a growing image. The value of + * strips/image will initially be 1 (since it + * can't be deduced until the imagelength is known). + */ + if (strip >= td->td_stripsperimage) + td->td_stripsperimage = + TIFFhowmany_32(td->td_imagelength,td->td_rowsperstrip); + if (!TIFFGrowStrips(tif, 1, module)) + return ((tmsize_t) -1); + } + tif->tif_curstrip = strip; + if (td->td_stripsperimage == 0) { + TIFFErrorExt(tif->tif_clientdata, module,"Zero strips per image"); + return ((tmsize_t) -1); + } + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + return (TIFFAppendToStrip(tif, strip, (uint8_t*) data, cc) ? + cc : (tmsize_t) -1); +} + +/* + * Write and compress a tile of data. The + * tile is selected by the (x,y,z,s) coordinates. + */ +tmsize_t +TIFFWriteTile(TIFF* tif, void* buf, uint32_t x, uint32_t y, uint32_t z, uint16_t s) +{ + if (!TIFFCheckTile(tif, x, y, z, s)) + return ((tmsize_t)(-1)); + /* + * NB: A tile size of -1 is used instead of tif_tilesize knowing + * that TIFFWriteEncodedTile will clamp this to the tile size. + * This is done because the tile size may not be defined until + * after the output buffer is setup in TIFFWriteBufferSetup. + */ + return (TIFFWriteEncodedTile(tif, + TIFFComputeTile(tif, x, y, z, s), buf, (tmsize_t)(-1))); +} + +/* + * Encode the supplied data and write it to the + * specified tile. There must be space for the + * data. The function clamps individual writes + * to a tile to the tile size, but does not (and + * can not) check that multiple writes to the same + * tile do not write more than tile size data. + * + * NB: Image length must be setup before writing; this + * interface does not support automatically growing + * the image on each write (as TIFFWriteScanline does). + */ +tmsize_t +TIFFWriteEncodedTile(TIFF* tif, uint32_t tile, void* data, tmsize_t cc) +{ + static const char module[] = "TIFFWriteEncodedTile"; + TIFFDirectory *td; + uint16_t sample; + uint32_t howmany32; + + if (!WRITECHECKTILES(tif, module)) + return ((tmsize_t)(-1)); + td = &tif->tif_dir; + if (tile >= td->td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, "Tile %lu out of range, max %lu", + (unsigned long) tile, (unsigned long) td->td_nstrips); + return ((tmsize_t)(-1)); + } + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized more intelligently (using + * directory information). + */ + if (!BUFFERCHECK(tif)) + return ((tmsize_t)(-1)); + + tif->tif_flags |= TIFF_BUF4WRITE; + tif->tif_curtile = tile; + + if( !_TIFFReserveLargeEnoughWriteBuffer(tif, tile) ) { + return ((tmsize_t)(-1)); + } + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + /* + * Compute tiles per row & per column to compute + * current row and column + */ + howmany32=TIFFhowmany_32(td->td_imagelength, td->td_tilelength); + if (howmany32 == 0) { + TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles"); + return ((tmsize_t)(-1)); + } + tif->tif_row = (tile % howmany32) * td->td_tilelength; + howmany32=TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth); + if (howmany32 == 0) { + TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles"); + return ((tmsize_t)(-1)); + } + tif->tif_col = (tile % howmany32) * td->td_tilewidth; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return ((tmsize_t)(-1)); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_flags &= ~TIFF_POSTENCODE; + + /* + * Clamp write amount to the tile size. This is mostly + * done so that callers can pass in some large number + * (e.g. -1) and have the tile size used instead. + */ + if ( cc < 1 || cc > tif->tif_tilesize) + cc = tif->tif_tilesize; + + /* shortcut to avoid an extra memcpy() */ + if( td->td_compression == COMPRESSION_NONE ) + { + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode(tif, (uint8_t*) data, cc ); + + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits((uint8_t*) data, cc); + + if (cc > 0 && + !TIFFAppendToStrip(tif, tile, (uint8_t*) data, cc)) + return ((tmsize_t) -1); + return (cc); + } + + sample = (uint16_t)(tile / td->td_stripsperimage); + if (!(*tif->tif_preencode)(tif, sample)) + return ((tmsize_t)(-1)); + /* swab if needed - note that source buffer will be altered */ + tif->tif_postdecode(tif, (uint8_t*) data, cc ); + + if (!(*tif->tif_encodetile)(tif, (uint8_t*) data, cc, sample)) + return ((tmsize_t) -1); + if (!(*tif->tif_postencode)(tif)) + return ((tmsize_t)(-1)); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits((uint8_t*)tif->tif_rawdata, tif->tif_rawcc); + if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile, + tif->tif_rawdata, tif->tif_rawcc)) + return ((tmsize_t)(-1)); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + return (cc); +} + +/* + * Write the supplied data to the specified strip. + * There must be space for the data; we don't check + * if strips overlap! + * + * NB: Image length must be setup before writing; this + * interface does not support automatically growing + * the image on each write (as TIFFWriteScanline does). + */ +tmsize_t +TIFFWriteRawTile(TIFF* tif, uint32_t tile, void* data, tmsize_t cc) +{ + static const char module[] = "TIFFWriteRawTile"; + + if (!WRITECHECKTILES(tif, module)) + return ((tmsize_t)(-1)); + if (tile >= tif->tif_dir.td_nstrips) { + TIFFErrorExt(tif->tif_clientdata, module, "Tile %lu out of range, max %lu", + (unsigned long) tile, + (unsigned long) tif->tif_dir.td_nstrips); + return ((tmsize_t)(-1)); + } + return (TIFFAppendToStrip(tif, tile, (uint8_t*) data, cc) ? + cc : (tmsize_t)(-1)); +} + +#define isUnspecified(tif, f) \ + (TIFFFieldSet(tif,f) && (tif)->tif_dir.td_imagelength == 0) + +int +TIFFSetupStrips(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + + if (isTiled(tif)) + td->td_stripsperimage = + isUnspecified(tif, FIELD_TILEDIMENSIONS) ? + td->td_samplesperpixel : TIFFNumberOfTiles(tif); + else + td->td_stripsperimage = + isUnspecified(tif, FIELD_ROWSPERSTRIP) ? + td->td_samplesperpixel : TIFFNumberOfStrips(tif); + td->td_nstrips = td->td_stripsperimage; + /* TIFFWriteDirectoryTagData has a limitation to 0x80000000U bytes */ + if( td->td_nstrips >= 0x80000000U / ((tif->tif_flags&TIFF_BIGTIFF)?0x8U:0x4U) ) + { + TIFFErrorExt(tif->tif_clientdata, "TIFFSetupStrips", + "Too large Strip/Tile Offsets/ByteCounts arrays"); + return 0; + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + td->td_stripsperimage /= td->td_samplesperpixel; + td->td_stripoffset_p = (uint64_t *) + _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64_t), + "for \"StripOffsets\" array"); + td->td_stripbytecount_p = (uint64_t *) + _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64_t), + "for \"StripByteCounts\" array"); + if (td->td_stripoffset_p == NULL || td->td_stripbytecount_p == NULL) + return (0); + /* + * Place data at the end-of-file + * (by setting offsets to zero). + */ + _TIFFmemset(td->td_stripoffset_p, 0, td->td_nstrips*sizeof (uint64_t)); + _TIFFmemset(td->td_stripbytecount_p, 0, td->td_nstrips*sizeof (uint64_t)); + TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); + TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); + return (1); +} +#undef isUnspecified + +/* + * Verify file is writable and that the directory + * information is setup properly. In doing the latter + * we also "freeze" the state of the directory so + * that important information is not changed. + */ +int +TIFFWriteCheck(TIFF* tif, int tiles, const char* module) +{ + if (tif->tif_mode == O_RDONLY) { + TIFFErrorExt(tif->tif_clientdata, module, "File not open for writing"); + return (0); + } + if (tiles ^ isTiled(tif)) { + TIFFErrorExt(tif->tif_clientdata, module, tiles ? + "Can not write tiles to a striped image" : + "Can not write scanlines to a tiled image"); + return (0); + } + + _TIFFFillStriles( tif ); + + /* + * On the first write verify all the required information + * has been setup and initialize any data structures that + * had to wait until directory information was set. + * Note that a lot of our work is assumed to remain valid + * because we disallow any of the important parameters + * from changing after we start writing (i.e. once + * TIFF_BEENWRITING is set, TIFFSetField will only allow + * the image's length to be changed). + */ + if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Must set \"ImageWidth\" before writing data"); + return (0); + } + if (tif->tif_dir.td_samplesperpixel == 1) { + /* + * Planarconfiguration is irrelevant in case of single band + * images and need not be included. We will set it anyway, + * because this field is used in other parts of library even + * in the single band case. + */ + if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) + tif->tif_dir.td_planarconfig = PLANARCONFIG_CONTIG; + } else { + if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { + TIFFErrorExt(tif->tif_clientdata, module, + "Must set \"PlanarConfiguration\" before writing data"); + return (0); + } + } + if (tif->tif_dir.td_stripoffset_p == NULL && !TIFFSetupStrips(tif)) { + tif->tif_dir.td_nstrips = 0; + TIFFErrorExt(tif->tif_clientdata, module, "No space for %s arrays", + isTiled(tif) ? "tile" : "strip"); + return (0); + } + if (isTiled(tif)) + { + tif->tif_tilesize = TIFFTileSize(tif); + if (tif->tif_tilesize == 0) + return (0); + } + else + tif->tif_tilesize = (tmsize_t)(-1); + tif->tif_scanlinesize = TIFFScanlineSize(tif); + if (tif->tif_scanlinesize == 0) + return (0); + tif->tif_flags |= TIFF_BEENWRITING; + + if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 && + tif->tif_dir.td_stripoffset_entry.tdir_count == 0 && + tif->tif_dir.td_stripoffset_entry.tdir_type == 0 && + tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 && + tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 && + !(tif->tif_flags & TIFF_DIRTYDIRECT) ) + { + TIFFForceStrileArrayWriting(tif); + } + + return (1); +} + +/* + * Setup the raw data buffer used for encoding. + */ +int +TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size) +{ + static const char module[] = "TIFFWriteBufferSetup"; + + if (tif->tif_rawdata) { + if (tif->tif_flags & TIFF_MYBUFFER) { + _TIFFfree(tif->tif_rawdata); + tif->tif_flags &= ~TIFF_MYBUFFER; + } + tif->tif_rawdata = NULL; + } + if (size == (tmsize_t)(-1)) { + size = (isTiled(tif) ? + tif->tif_tilesize : TIFFStripSize(tif)); + + /* Adds 10% margin for cases where compression would expand a bit */ + if( size < TIFF_TMSIZE_T_MAX - size / 10 ) + size += size / 10; + /* + * Make raw data buffer at least 8K + */ + if (size < 8*1024) + size = 8*1024; + bp = NULL; /* NB: force malloc */ + } + if (bp == NULL) { + bp = _TIFFmalloc(size); + if (bp == NULL) { + TIFFErrorExt(tif->tif_clientdata, module, "No space for output buffer"); + return (0); + } + tif->tif_flags |= TIFF_MYBUFFER; + } else + tif->tif_flags &= ~TIFF_MYBUFFER; + tif->tif_rawdata = (uint8_t*) bp; + tif->tif_rawdatasize = size; + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_flags |= TIFF_BUFFERSETUP; + return (1); +} + +/* + * Grow the strip data structures by delta strips. + */ +static int +TIFFGrowStrips(TIFF* tif, uint32_t delta, const char* module) +{ + TIFFDirectory *td = &tif->tif_dir; + uint64_t* new_stripoffset; + uint64_t* new_stripbytecount; + + assert(td->td_planarconfig == PLANARCONFIG_CONTIG); + new_stripoffset = (uint64_t*)_TIFFrealloc(td->td_stripoffset_p, + (td->td_nstrips + delta) * sizeof (uint64_t)); + new_stripbytecount = (uint64_t*)_TIFFrealloc(td->td_stripbytecount_p, + (td->td_nstrips + delta) * sizeof (uint64_t)); + if (new_stripoffset == NULL || new_stripbytecount == NULL) { + if (new_stripoffset) + _TIFFfree(new_stripoffset); + if (new_stripbytecount) + _TIFFfree(new_stripbytecount); + td->td_nstrips = 0; + TIFFErrorExt(tif->tif_clientdata, module, "No space to expand strip arrays"); + return (0); + } + td->td_stripoffset_p = new_stripoffset; + td->td_stripbytecount_p = new_stripbytecount; + _TIFFmemset(td->td_stripoffset_p + td->td_nstrips, + 0, delta*sizeof (uint64_t)); + _TIFFmemset(td->td_stripbytecount_p + td->td_nstrips, + 0, delta*sizeof (uint64_t)); + td->td_nstrips += delta; + tif->tif_flags |= TIFF_DIRTYDIRECT; + + return (1); +} + +/* + * Append the data to the specified strip. + */ +static int +TIFFAppendToStrip(TIFF* tif, uint32_t strip, uint8_t* data, tmsize_t cc) +{ + static const char module[] = "TIFFAppendToStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint64_t m; + int64_t old_byte_count = -1; + + if (td->td_stripoffset_p[strip] == 0 || tif->tif_curoff == 0) { + assert(td->td_nstrips > 0); + + if( td->td_stripbytecount_p[strip] != 0 + && td->td_stripoffset_p[strip] != 0 + && td->td_stripbytecount_p[strip] >= (uint64_t) cc ) + { + /* + * There is already tile data on disk, and the new tile + * data we have will fit in the same space. The only + * aspect of this that is risky is that there could be + * more data to append to this strip before we are done + * depending on how we are getting called. + */ + if (!SeekOK(tif, td->td_stripoffset_p[strip])) { + TIFFErrorExt(tif->tif_clientdata, module, + "Seek error at scanline %lu", + (unsigned long)tif->tif_row); + return (0); + } + } + else + { + /* + * Seek to end of file, and set that as our location to + * write this strip. + */ + td->td_stripoffset_p[strip] = TIFFSeekFile(tif, 0, SEEK_END); + tif->tif_flags |= TIFF_DIRTYSTRIP; + } + + tif->tif_curoff = td->td_stripoffset_p[strip]; + + /* + * We are starting a fresh strip/tile, so set the size to zero. + */ + old_byte_count = td->td_stripbytecount_p[strip]; + td->td_stripbytecount_p[strip] = 0; + } + + m = tif->tif_curoff+cc; + if (!(tif->tif_flags&TIFF_BIGTIFF)) + m = (uint32_t)m; + if ((mtif_curoff)||(m<(uint64_t)cc)) + { + TIFFErrorExt(tif->tif_clientdata, module, "Maximum TIFF file size exceeded"); + return (0); + } + if (!WriteOK(tif, data, cc)) { + TIFFErrorExt(tif->tif_clientdata, module, "Write error at scanline %lu", + (unsigned long) tif->tif_row); + return (0); + } + tif->tif_curoff = m; + td->td_stripbytecount_p[strip] += cc; + + if((int64_t) td->td_stripbytecount_p[strip] != old_byte_count ) + tif->tif_flags |= TIFF_DIRTYSTRIP; + + return (1); +} + +/* + * Internal version of TIFFFlushData that can be + * called by ``encodestrip routines'' w/o concern + * for infinite recursion. + */ +int +TIFFFlushData1(TIFF* tif) +{ + if (tif->tif_rawcc > 0 && tif->tif_flags & TIFF_BUF4WRITE ) { + if (!isFillOrder(tif, tif->tif_dir.td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits((uint8_t*)tif->tif_rawdata, + tif->tif_rawcc); + if (!TIFFAppendToStrip(tif, + isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip, + tif->tif_rawdata, tif->tif_rawcc)) + { + /* We update those variables even in case of error since there's */ + /* code that doesn't really check the return code of this */ + /* function */ + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + return (0); + } + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + } + return (1); +} + +/* + * Set the current write offset. This should only be + * used to set the offset to a known previous location + * (very carefully), or to 0 so that the next write gets + * appended to the end of the file. + */ +void +TIFFSetWriteOffset(TIFF* tif, toff_t off) +{ + tif->tif_curoff = off; +} + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tif_zip.c b/libs/tiff/libtiff/tif_zip.c new file mode 100644 index 00000000000..be35e49b5c0 --- /dev/null +++ b/libs/tiff/libtiff/tif_zip.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 1995-1997 Sam Leffler + * Copyright (c) 1995-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef ZIP_SUPPORT +/* + * TIFF Library. + * + * ZIP (aka Deflate) Compression Support + * + * This file is an interface to the zlib library written by + * Jean-loup Gailly and Mark Adler. You must use version 1.0 or later + * of the library. + * + * Optionally, libdeflate (https://github.com/ebiggers/libdeflate) may be used + * to do the compression and decompression, but only for whole strips and tiles. + * For scanline access, zlib will be sued as a fallback. + */ +#include "tif_predict.h" +#include "zlib.h" + +#if LIBDEFLATE_SUPPORT +#include "libdeflate.h" +#endif +#define LIBDEFLATE_MAX_COMPRESSION_LEVEL 12 + +#include + +/* + * Sigh, ZLIB_VERSION is defined as a string so there's no + * way to do a proper check here. Instead we guess based + * on the presence of #defines that were added between the + * 0.95 and 1.0 distributions. + */ +#if !defined(Z_NO_COMPRESSION) || !defined(Z_DEFLATED) +#error "Antiquated ZLIB software; you must use version 1.0 or later" +#endif + +#define SAFE_MSG(sp) ((sp)->stream.msg == NULL ? "" : (sp)->stream.msg) + +/* + * State block for each open TIFF + * file using ZIP compression/decompression. + */ +typedef struct { + TIFFPredictorState predict; + z_stream stream; + int zipquality; /* compression level */ + int state; /* state flags */ + int subcodec; /* DEFLATE_SUBCODEC_ZLIB or DEFLATE_SUBCODEC_LIBDEFLATE */ +#if LIBDEFLATE_SUPPORT + int libdeflate_state; /* -1 = until first time ZIPEncode() / ZIPDecode() is called, 0 = use zlib, 1 = use libdeflate */ + struct libdeflate_decompressor* libdeflate_dec; + struct libdeflate_compressor* libdeflate_enc; +#endif +#define ZSTATE_INIT_DECODE 0x01 +#define ZSTATE_INIT_ENCODE 0x02 + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +} ZIPState; + +#define ZState(tif) ((ZIPState*) (tif)->tif_data) +#define DecoderState(tif) ZState(tif) +#define EncoderState(tif) ZState(tif) + +static int ZIPEncode(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s); +static int ZIPDecode(TIFF* tif, uint8_t* op, tmsize_t occ, uint16_t s); + +static int +ZIPFixupTags(TIFF* tif) +{ + (void) tif; + return (1); +} + +static int +ZIPSetupDecode(TIFF* tif) +{ + static const char module[] = "ZIPSetupDecode"; + ZIPState* sp = DecoderState(tif); + + assert(sp != NULL); + + /* if we were last encoding, terminate this mode */ + if (sp->state & ZSTATE_INIT_ENCODE) { + deflateEnd(&sp->stream); + sp->state = 0; + } + + /* This function can possibly be called several times by */ + /* PredictorSetupDecode() if this function succeeds but */ + /* PredictorSetup() fails */ + if ((sp->state & ZSTATE_INIT_DECODE) == 0 && + inflateInit(&sp->stream) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s", SAFE_MSG(sp)); + return (0); + } else { + sp->state |= ZSTATE_INIT_DECODE; + return (1); + } +} + +/* + * Setup state for decoding a strip. + */ +static int +ZIPPreDecode(TIFF* tif, uint16_t s) +{ + ZIPState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + + if( (sp->state & ZSTATE_INIT_DECODE) == 0 ) + tif->tif_setupdecode( tif ); + +#if LIBDEFLATE_SUPPORT + sp->libdeflate_state = -1; +#endif + sp->stream.next_in = tif->tif_rawdata; + assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + appropriately even before we simplify it */ + sp->stream.avail_in = (uint64_t)tif->tif_rawcc < 0xFFFFFFFFU ? (uInt) tif->tif_rawcc : 0xFFFFFFFFU; + return (inflateReset(&sp->stream) == Z_OK); +} + +static int +ZIPDecode(TIFF* tif, uint8_t* op, tmsize_t occ, uint16_t s) +{ + static const char module[] = "ZIPDecode"; + ZIPState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + assert(sp->state == ZSTATE_INIT_DECODE); + +#if LIBDEFLATE_SUPPORT + if( sp->libdeflate_state == 1 ) + return 0; + + /* If we have libdeflate support and we are asked to read a whole */ + /* strip/tile, then go for using it */ + do { + TIFFDirectory *td = &tif->tif_dir; + + if( sp->libdeflate_state == 0 ) + break; + if( sp->subcodec == DEFLATE_SUBCODEC_ZLIB ) + break; + + /* Check if we are in the situation where we can use libdeflate */ + if (isTiled(tif)) { + if( TIFFTileSize64(tif) != (uint64_t)occ ) + break; + } else { + uint32_t strip_height = td->td_imagelength - tif->tif_row; + if (strip_height > td->td_rowsperstrip) + strip_height = td->td_rowsperstrip; + if( TIFFVStripSize64(tif, strip_height) != (uint64_t)occ ) + break; + } + + /* Check for overflow */ + if( (size_t)tif->tif_rawcc != (uint64_t)tif->tif_rawcc ) + break; + if( (size_t)occ != (uint64_t)occ ) + break; + + /* Go for decompression using libdeflate */ + { + enum libdeflate_result res; + if( sp->libdeflate_dec == NULL ) + { + sp->libdeflate_dec = libdeflate_alloc_decompressor(); + if( sp->libdeflate_dec == NULL ) + { + break; + } + } + + sp->libdeflate_state = 1; + + res = libdeflate_zlib_decompress( + sp->libdeflate_dec, tif->tif_rawcp, (size_t)tif->tif_rawcc, op, (size_t)occ, NULL); + + tif->tif_rawcp += tif->tif_rawcc; + tif->tif_rawcc = 0; + + /* We accept LIBDEFLATE_INSUFFICIENT_SPACE has a return */ + /* There are odd files in the wild where the last strip, when */ + /* it is smaller in height than td_rowsperstrip, actually contains */ + /* data for td_rowsperstrip lines. Just ignore that silently. */ + if( res != LIBDEFLATE_SUCCESS && + res != LIBDEFLATE_INSUFFICIENT_SPACE ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Decoding error at scanline %lu", + (unsigned long) tif->tif_row); + return 0; + } + + return 1; + } + } while(0); + sp->libdeflate_state = 0; +#endif /* LIBDEFLATE_SUPPORT */ + + sp->stream.next_in = tif->tif_rawcp; + + sp->stream.next_out = op; + assert(sizeof(sp->stream.avail_out)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + appropriately even before we simplify it */ + do { + int state; + uInt avail_in_before = (uint64_t)tif->tif_rawcc <= 0xFFFFFFFFU ? (uInt)tif->tif_rawcc : 0xFFFFFFFFU; + uInt avail_out_before = (uint64_t)occ < 0xFFFFFFFFU ? (uInt) occ : 0xFFFFFFFFU; + sp->stream.avail_in = avail_in_before; + sp->stream.avail_out = avail_out_before; + state = inflate(&sp->stream, Z_PARTIAL_FLUSH); + tif->tif_rawcc -= (avail_in_before - sp->stream.avail_in); + occ -= (avail_out_before - sp->stream.avail_out); + if (state == Z_STREAM_END) + break; + if (state == Z_DATA_ERROR) { + TIFFErrorExt(tif->tif_clientdata, module, + "Decoding error at scanline %lu, %s", + (unsigned long) tif->tif_row, SAFE_MSG(sp)); + return (0); + } + if (state != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, + "ZLib error: %s", SAFE_MSG(sp)); + return (0); + } + } while (occ > 0); + if (occ != 0) { + TIFFErrorExt(tif->tif_clientdata, module, + "Not enough data at scanline %lu (short %" PRIu64 " bytes)", + (unsigned long) tif->tif_row, (uint64_t) occ); + return (0); + } + + tif->tif_rawcp = sp->stream.next_in; + + return (1); +} + +static int +ZIPSetupEncode(TIFF* tif) +{ + static const char module[] = "ZIPSetupEncode"; + ZIPState* sp = EncoderState(tif); + int cappedQuality; + + assert(sp != NULL); + if (sp->state & ZSTATE_INIT_DECODE) { + inflateEnd(&sp->stream); + sp->state = 0; + } + + cappedQuality = sp->zipquality; + if( cappedQuality > Z_BEST_COMPRESSION ) + cappedQuality = Z_BEST_COMPRESSION; + + if (deflateInit(&sp->stream, cappedQuality) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "%s", SAFE_MSG(sp)); + return (0); + } else { + sp->state |= ZSTATE_INIT_ENCODE; + return (1); + } +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +ZIPPreEncode(TIFF* tif, uint16_t s) +{ + ZIPState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + if( sp->state != ZSTATE_INIT_ENCODE ) + tif->tif_setupencode( tif ); + +#if LIBDEFLATE_SUPPORT + sp->libdeflate_state = -1; +#endif + sp->stream.next_out = tif->tif_rawdata; + assert(sizeof(sp->stream.avail_out)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + appropriately even before we simplify it */ + sp->stream.avail_out = (uint64_t)tif->tif_rawdatasize <= 0xFFFFFFFFU ? (uInt)tif->tif_rawdatasize : 0xFFFFFFFFU; + return (deflateReset(&sp->stream) == Z_OK); +} + +/* + * Encode a chunk of pixels. + */ +static int +ZIPEncode(TIFF* tif, uint8_t* bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "ZIPEncode"; + ZIPState *sp = EncoderState(tif); + + assert(sp != NULL); + assert(sp->state == ZSTATE_INIT_ENCODE); + + (void) s; + +#if LIBDEFLATE_SUPPORT + if( sp->libdeflate_state == 1 ) + return 0; + + /* If we have libdeflate support and we are asked to write a whole */ + /* strip/tile, then go for using it */ + do { + TIFFDirectory *td = &tif->tif_dir; + + if( sp->libdeflate_state == 0 ) + break; + if( sp->subcodec == DEFLATE_SUBCODEC_ZLIB ) + break; + + /* Libdeflate does not support the 0-compression level */ + if( sp->zipquality == Z_NO_COMPRESSION ) + break; + + /* Check if we are in the situation where we can use libdeflate */ + if (isTiled(tif)) { + if( TIFFTileSize64(tif) != (uint64_t)cc ) + break; + } else { + uint32_t strip_height = td->td_imagelength - tif->tif_row; + if (strip_height > td->td_rowsperstrip) + strip_height = td->td_rowsperstrip; + if( TIFFVStripSize64(tif, strip_height) != (uint64_t)cc ) + break; + } + + /* Check for overflow */ + if( (size_t)tif->tif_rawdatasize != (uint64_t)tif->tif_rawdatasize ) + break; + if( (size_t)cc != (uint64_t)cc ) + break; + + /* Go for compression using libdeflate */ + { + size_t nCompressedBytes; + if( sp->libdeflate_enc == NULL ) + { + /* To get results as good as zlib, we asked for an extra */ + /* level of compression */ + sp->libdeflate_enc = libdeflate_alloc_compressor( + sp->zipquality == Z_DEFAULT_COMPRESSION ? 7 : + sp->zipquality >= 6 && sp->zipquality <= 9 ? sp->zipquality + 1 : + sp->zipquality); + if( sp->libdeflate_enc == NULL ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Cannot allocate compressor"); + break; + } + } + + /* Make sure the output buffer is large enough for the worse case. */ + /* In TIFFWriteBufferSetup(), when libtiff allocates the buffer */ + /* we've taken a 10% margin over the uncompressed size, which should */ + /* be large enough even for the the worse case scenario. */ + if( libdeflate_zlib_compress_bound(sp->libdeflate_enc, (size_t)cc) > + (size_t)tif->tif_rawdatasize) + { + break; + } + + sp->libdeflate_state = 1; + nCompressedBytes = libdeflate_zlib_compress( + sp->libdeflate_enc, bp, (size_t)cc, tif->tif_rawdata, (size_t)tif->tif_rawdatasize); + + if( nCompressedBytes == 0 ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Encoder error at scanline %lu", + (unsigned long) tif->tif_row); + return 0; + } + + tif->tif_rawcc = nCompressedBytes; + + if( !TIFFFlushData1(tif) ) + return 0; + + return 1; + } + } while(0); + sp->libdeflate_state = 0; +#endif /* LIBDEFLATE_SUPPORT */ + + sp->stream.next_in = bp; + assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised, + we need to simplify this code to reflect a ZLib that is likely updated + to deal with 8byte memory sizes, though this code will respond + appropriately even before we simplify it */ + do { + uInt avail_in_before = (uint64_t)cc <= 0xFFFFFFFFU ? (uInt)cc : 0xFFFFFFFFU; + sp->stream.avail_in = avail_in_before; + if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, + "Encoder error: %s", + SAFE_MSG(sp)); + return (0); + } + if (sp->stream.avail_out == 0) { + tif->tif_rawcc = tif->tif_rawdatasize; + if (!TIFFFlushData1(tif)) + return 0; + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (uint64_t)tif->tif_rawdatasize <= 0xFFFFFFFFU ? (uInt)tif->tif_rawdatasize : 0xFFFFFFFFU; + } + cc -= (avail_in_before - sp->stream.avail_in); + } while (cc > 0); + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ +static int +ZIPPostEncode(TIFF* tif) +{ + static const char module[] = "ZIPPostEncode"; + ZIPState *sp = EncoderState(tif); + int state; + +#if LIBDEFLATE_SUPPORT + if( sp->libdeflate_state == 1 ) + return 1; +#endif + + sp->stream.avail_in = 0; + do { + state = deflate(&sp->stream, Z_FINISH); + switch (state) { + case Z_STREAM_END: + case Z_OK: + if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) + { + tif->tif_rawcc = tif->tif_rawdatasize - sp->stream.avail_out; + if (!TIFFFlushData1(tif)) + return 0; + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (uint64_t)tif->tif_rawdatasize <= 0xFFFFFFFFU ? (uInt)tif->tif_rawdatasize : 0xFFFFFFFFU; + } + break; + default: + TIFFErrorExt(tif->tif_clientdata, module, + "ZLib error: %s", SAFE_MSG(sp)); + return (0); + } + } while (state != Z_STREAM_END); + return (1); +} + +static void +ZIPCleanup(TIFF* tif) +{ + ZIPState* sp = ZState(tif); + + assert(sp != 0); + + (void)TIFFPredictorCleanup(tif); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->state & ZSTATE_INIT_ENCODE) { + deflateEnd(&sp->stream); + sp->state = 0; + } else if( sp->state & ZSTATE_INIT_DECODE) { + inflateEnd(&sp->stream); + sp->state = 0; + } + +#if LIBDEFLATE_SUPPORT + if( sp->libdeflate_dec ) + libdeflate_free_decompressor(sp->libdeflate_dec); + if( sp->libdeflate_enc ) + libdeflate_free_compressor(sp->libdeflate_enc); +#endif + + _TIFFfree(sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int +ZIPVSetField(TIFF* tif, uint32_t tag, va_list ap) +{ + static const char module[] = "ZIPVSetField"; + ZIPState* sp = ZState(tif); + + switch (tag) { + case TIFFTAG_ZIPQUALITY: + sp->zipquality = (int) va_arg(ap, int); + if( sp->zipquality < Z_DEFAULT_COMPRESSION || + sp->zipquality > LIBDEFLATE_MAX_COMPRESSION_LEVEL ) { + TIFFErrorExt(tif->tif_clientdata, module, + "Invalid ZipQuality value. Should be in [-1,%d] range", + LIBDEFLATE_MAX_COMPRESSION_LEVEL); + return 0; + } + + if ( sp->state&ZSTATE_INIT_ENCODE ) { + int cappedQuality = sp->zipquality; + if( cappedQuality > Z_BEST_COMPRESSION ) + cappedQuality = Z_BEST_COMPRESSION; + if (deflateParams(&sp->stream, + cappedQuality, Z_DEFAULT_STRATEGY) != Z_OK) { + TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s", + SAFE_MSG(sp)); + return (0); + } + } + +#if LIBDEFLATE_SUPPORT + if( sp->libdeflate_enc ) + { + libdeflate_free_compressor(sp->libdeflate_enc); + sp->libdeflate_enc = NULL; + } +#endif + + return (1); + + case TIFFTAG_DEFLATE_SUBCODEC: + sp->subcodec = (int) va_arg(ap, int); + if( sp->subcodec != DEFLATE_SUBCODEC_ZLIB && + sp->subcodec != DEFLATE_SUBCODEC_LIBDEFLATE ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "Invalid DeflateCodec value."); + return 0; + } +#if !LIBDEFLATE_SUPPORT + if( sp->subcodec == DEFLATE_SUBCODEC_LIBDEFLATE ) + { + TIFFErrorExt(tif->tif_clientdata, module, + "DeflateCodec = DEFLATE_SUBCODEC_LIBDEFLATE unsupported in this build"); + return 0; + } +#endif + return 1; + + default: + return (*sp->vsetparent)(tif, tag, ap); + } + /*NOTREACHED*/ +} + +static int +ZIPVGetField(TIFF* tif, uint32_t tag, va_list ap) +{ + ZIPState* sp = ZState(tif); + + switch (tag) { + case TIFFTAG_ZIPQUALITY: + *va_arg(ap, int*) = sp->zipquality; + break; + + case TIFFTAG_DEFLATE_SUBCODEC: + *va_arg(ap, int*) = sp->subcodec; + break; + + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static const TIFFField zipFields[] = { + { TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL }, + { TIFFTAG_DEFLATE_SUBCODEC, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL }, +}; + +int +TIFFInitZIP(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitZIP"; + ZIPState* sp; + + assert( (scheme == COMPRESSION_DEFLATE) + || (scheme == COMPRESSION_ADOBE_DEFLATE)); +#ifdef NDEBUG + (void)scheme; +#endif + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, zipFields, TIFFArrayCount(zipFields))) { + TIFFErrorExt(tif->tif_clientdata, module, + "Merging Deflate codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t*) _TIFFcalloc(sizeof (ZIPState), 1); + if (tif->tif_data == NULL) + goto bad; + sp = ZState(tif); + sp->stream.zalloc = NULL; + sp->stream.zfree = NULL; + sp->stream.opaque = NULL; + sp->stream.data_type = Z_BINARY; + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = ZIPVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = ZIPVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->zipquality = Z_DEFAULT_COMPRESSION; /* default comp. level */ + sp->state = 0; +#if LIBDEFLATE_SUPPORT + sp->subcodec = DEFLATE_SUBCODEC_LIBDEFLATE; +#else + sp->subcodec = DEFLATE_SUBCODEC_ZLIB; +#endif + + /* + * Install codec methods. + */ + tif->tif_fixuptags = ZIPFixupTags; + tif->tif_setupdecode = ZIPSetupDecode; + tif->tif_predecode = ZIPPreDecode; + tif->tif_decoderow = ZIPDecode; + tif->tif_decodestrip = ZIPDecode; + tif->tif_decodetile = ZIPDecode; + tif->tif_setupencode = ZIPSetupEncode; + tif->tif_preencode = ZIPPreEncode; + tif->tif_postencode = ZIPPostEncode; + tif->tif_encoderow = ZIPEncode; + tif->tif_encodestrip = ZIPEncode; + tif->tif_encodetile = ZIPEncode; + tif->tif_cleanup = ZIPCleanup; + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + return (1); +bad: + TIFFErrorExt(tif->tif_clientdata, module, + "No space for ZIP state block"); + return (0); +} +#endif /* ZIP_SUPPORT */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tiff.h b/libs/tiff/libtiff/tiff.h new file mode 100644 index 00000000000..bd79270c77b --- /dev/null +++ b/libs/tiff/libtiff/tiff.h @@ -0,0 +1,814 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFF_ +#define _TIFF_ + +#include "tiffconf.h" + +/* + * Tag Image File Format (TIFF) + * + * Based on Rev 6.0 from: + * Developer's Desk + * Aldus Corporation + * 411 First Ave. South + * Suite 200 + * Seattle, WA 98104 + * 206-622-5500 + * + * (http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf) + * + * For BigTIFF design notes see the following links + * http://www.remotesensing.org/libtiff/bigtiffdesign.html + * http://www.awaresystems.be/imaging/tiff/bigtiff.html + */ + +#define TIFF_VERSION_CLASSIC 42 +#define TIFF_VERSION_BIG 43 + +#define TIFF_BIGENDIAN 0x4d4d +#define TIFF_LITTLEENDIAN 0x4949 +#define MDI_LITTLEENDIAN 0x5045 +#define MDI_BIGENDIAN 0x4550 + +/* + * Intrinsic data types required by the file format: + * + * 8-bit quantities int8_t/uint_8_t + * 16-bit quantities int16_t/uint_16_t + * 32-bit quantities int32_t/uint_32_t + * 64-bit quantities int64_t/uint_64_t + * strings unsigned char* + */ +#ifdef __GNUC__ +#define TIFF_GCC_DEPRECATED __attribute__((deprecated)) +#else +#define TIFF_GCC_DEPRECATED +#endif +#ifdef _MSC_VER +#define TIFF_MSC_DEPRECATED __declspec(deprecated("libtiff type deprecated; please use corresponding C99 stdint.h type")) +#else +#define TIFF_MSC_DEPRECATED +#endif + +#ifndef TIFF_DISABLE_DEPRECATED +typedef TIFF_MSC_DEPRECATED int8_t int8 TIFF_GCC_DEPRECATED; +typedef TIFF_MSC_DEPRECATED uint8_t uint8 TIFF_GCC_DEPRECATED; + +typedef TIFF_MSC_DEPRECATED int16_t int16 TIFF_GCC_DEPRECATED; +typedef TIFF_MSC_DEPRECATED uint16_t uint16 TIFF_GCC_DEPRECATED; + +typedef TIFF_MSC_DEPRECATED int32_t int32 TIFF_GCC_DEPRECATED; +typedef TIFF_MSC_DEPRECATED uint32_t uint32 TIFF_GCC_DEPRECATED; + +typedef TIFF_MSC_DEPRECATED int64_t int64 TIFF_GCC_DEPRECATED; +typedef TIFF_MSC_DEPRECATED uint64_t uint64 TIFF_GCC_DEPRECATED; +#endif /* TIFF_DISABLE_DEPRECATED */ + + +/* + * Some types as promoted in a variable argument list + * We use uint16_vap rather then directly using int, because this way + * we document the type we actually want to pass through, conceptually, + * rather then confusing the issue by merely stating the type it gets + * promoted to + */ + +typedef int uint16_vap; + +/* + * TIFF header. + */ +typedef struct { + uint16_t tiff_magic; /* magic number (defines byte order) */ + uint16_t tiff_version; /* TIFF version number */ +} TIFFHeaderCommon; +typedef struct { + uint16_t tiff_magic; /* magic number (defines byte order) */ + uint16_t tiff_version; /* TIFF version number */ + uint32_t tiff_diroff; /* byte offset to first directory */ +} TIFFHeaderClassic; +typedef struct { + uint16_t tiff_magic; /* magic number (defines byte order) */ + uint16_t tiff_version; /* TIFF version number */ + uint16_t tiff_offsetsize; /* size of offsets, should be 8 */ + uint16_t tiff_unused; /* unused word, should be 0 */ + uint64_t tiff_diroff; /* byte offset to first directory */ +} TIFFHeaderBig; + + +/* + * NB: In the comments below, + * - items marked with a + are obsoleted by revision 5.0, + * - items marked with a ! are introduced in revision 6.0. + * - items marked with a % are introduced post revision 6.0. + * - items marked with a $ are obsoleted by revision 6.0. + * - items marked with a & are introduced by Adobe DNG specification. + */ + +/* + * Tag data type information. + * + * Note: RATIONALs are the ratio of two 32-bit integer values. + *--: + * Note2: TIFF_IFD8 data type is used in tiffFields[]-tag definition in order to distinguish the write-handling + of those tags between ClassicTIFF and BigTiff: + For ClassicTIFF libtiff writes a 32-bit value and the TIFF_IFD type-id into the file + For BigTIFF libtiff writes a 64-bit value and the TIFF_IFD8 type-id into the file + */ +typedef enum { + TIFF_NOTYPE = 0, /* placeholder */ + TIFF_BYTE = 1, /* 8-bit unsigned integer */ + TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */ + TIFF_SHORT = 3, /* 16-bit unsigned integer */ + TIFF_LONG = 4, /* 32-bit unsigned integer */ + TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */ + TIFF_SBYTE = 6, /* !8-bit signed integer */ + TIFF_UNDEFINED = 7, /* !8-bit untyped data */ + TIFF_SSHORT = 8, /* !16-bit signed integer */ + TIFF_SLONG = 9, /* !32-bit signed integer */ + TIFF_SRATIONAL = 10, /* !64-bit signed fraction */ + TIFF_FLOAT = 11, /* !32-bit IEEE floating point */ + TIFF_DOUBLE = 12, /* !64-bit IEEE floating point */ + TIFF_IFD = 13, /* %32-bit unsigned integer (offset) */ + TIFF_LONG8 = 16, /* BigTIFF 64-bit unsigned integer */ + TIFF_SLONG8 = 17, /* BigTIFF 64-bit signed integer */ + TIFF_IFD8 = 18 /* BigTIFF 64-bit unsigned integer (offset) */ +} TIFFDataType; + +/* + * TIFF Tag Definitions. + */ +#define TIFFTAG_SUBFILETYPE 254 /* subfile data descriptor */ +#define FILETYPE_REDUCEDIMAGE 0x1 /* reduced resolution version */ +#define FILETYPE_PAGE 0x2 /* one page of many */ +#define FILETYPE_MASK 0x4 /* transparency mask */ +#define TIFFTAG_OSUBFILETYPE 255 /* +kind of data in subfile */ +#define OFILETYPE_IMAGE 1 /* full resolution image data */ +#define OFILETYPE_REDUCEDIMAGE 2 /* reduced size image data */ +#define OFILETYPE_PAGE 3 /* one page of many */ +#define TIFFTAG_IMAGEWIDTH 256 /* image width in pixels */ +#define TIFFTAG_IMAGELENGTH 257 /* image height in pixels */ +#define TIFFTAG_BITSPERSAMPLE 258 /* bits per channel (sample) */ +#define TIFFTAG_COMPRESSION 259 /* data compression technique */ +#define COMPRESSION_NONE 1 /* dump mode */ +#define COMPRESSION_CCITTRLE 2 /* CCITT modified Huffman RLE */ +#define COMPRESSION_CCITTFAX3 3 /* CCITT Group 3 fax encoding */ +#define COMPRESSION_CCITT_T4 3 /* CCITT T.4 (TIFF 6 name) */ +#define COMPRESSION_CCITTFAX4 4 /* CCITT Group 4 fax encoding */ +#define COMPRESSION_CCITT_T6 4 /* CCITT T.6 (TIFF 6 name) */ +#define COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */ +#define COMPRESSION_OJPEG 6 /* !6.0 JPEG */ +#define COMPRESSION_JPEG 7 /* %JPEG DCT compression */ +#define COMPRESSION_T85 9 /* !TIFF/FX T.85 JBIG compression */ +#define COMPRESSION_T43 10 /* !TIFF/FX T.43 colour by layered JBIG compression */ +#define COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */ +#define COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */ +#define COMPRESSION_PACKBITS 32773 /* Macintosh RLE */ +#define COMPRESSION_THUNDERSCAN 32809 /* ThunderScan RLE */ +/* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT */ +#define COMPRESSION_DCS 32947 /* Kodak DCS encoding */ +#define COMPRESSION_JBIG 34661 /* ISO JBIG */ +#define COMPRESSION_SGILOG 34676 /* SGI Log Luminance RLE */ +#define COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */ +#define COMPRESSION_JP2000 34712 /* Leadtools JPEG2000 */ +#define COMPRESSION_LERC 34887 /* ESRI Lerc codec: https://github.com/Esri/lerc */ +/* compression codes 34887-34889 are reserved for ESRI */ +#define COMPRESSION_LZMA 34925 /* LZMA2 */ +#define COMPRESSION_ZSTD 50000 /* ZSTD: WARNING not registered in Adobe-maintained registry */ +#define COMPRESSION_WEBP 50001 /* WEBP: WARNING not registered in Adobe-maintained registry */ +#define COMPRESSION_JXL 50002 /* JPEGXL: WARNING not registered in Adobe-maintained registry */ +#define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */ +#define PHOTOMETRIC_MINISWHITE 0 /* min value is white */ +#define PHOTOMETRIC_MINISBLACK 1 /* min value is black */ +#define PHOTOMETRIC_RGB 2 /* RGB color model */ +#define PHOTOMETRIC_PALETTE 3 /* color map indexed */ +#define PHOTOMETRIC_MASK 4 /* $holdout mask */ +#define PHOTOMETRIC_SEPARATED 5 /* !color separations */ +#define PHOTOMETRIC_YCBCR 6 /* !CCIR 601 */ +#define PHOTOMETRIC_CIELAB 8 /* !1976 CIE L*a*b* */ +#define PHOTOMETRIC_ICCLAB 9 /* ICC L*a*b* [Adobe TIFF Technote 4] */ +#define PHOTOMETRIC_ITULAB 10 /* ITU L*a*b* */ +#define PHOTOMETRIC_CFA 32803 /* color filter array */ +#define PHOTOMETRIC_LOGL 32844 /* CIE Log2(L) */ +#define PHOTOMETRIC_LOGLUV 32845 /* CIE Log2(L) (u',v') */ +#define TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */ +#define THRESHHOLD_BILEVEL 1 /* b&w art scan */ +#define THRESHHOLD_HALFTONE 2 /* or dithered scan */ +#define THRESHHOLD_ERRORDIFFUSE 3 /* usually floyd-steinberg */ +#define TIFFTAG_CELLWIDTH 264 /* +dithering matrix width */ +#define TIFFTAG_CELLLENGTH 265 /* +dithering matrix height */ +#define TIFFTAG_FILLORDER 266 /* data order within a byte */ +#define FILLORDER_MSB2LSB 1 /* most significant -> least */ +#define FILLORDER_LSB2MSB 2 /* least significant -> most */ +#define TIFFTAG_DOCUMENTNAME 269 /* name of doc. image is from */ +#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */ +#define TIFFTAG_MAKE 271 /* scanner manufacturer name */ +#define TIFFTAG_MODEL 272 /* scanner model name/number */ +#define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */ +#define TIFFTAG_ORIENTATION 274 /* +image orientation */ +#define ORIENTATION_TOPLEFT 1 /* row 0 top, col 0 lhs */ +#define ORIENTATION_TOPRIGHT 2 /* row 0 top, col 0 rhs */ +#define ORIENTATION_BOTRIGHT 3 /* row 0 bottom, col 0 rhs */ +#define ORIENTATION_BOTLEFT 4 /* row 0 bottom, col 0 lhs */ +#define ORIENTATION_LEFTTOP 5 /* row 0 lhs, col 0 top */ +#define ORIENTATION_RIGHTTOP 6 /* row 0 rhs, col 0 top */ +#define ORIENTATION_RIGHTBOT 7 /* row 0 rhs, col 0 bottom */ +#define ORIENTATION_LEFTBOT 8 /* row 0 lhs, col 0 bottom */ +#define TIFFTAG_SAMPLESPERPIXEL 277 /* samples per pixel */ +#define TIFFTAG_ROWSPERSTRIP 278 /* rows per strip of data */ +#define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */ +#define TIFFTAG_MINSAMPLEVALUE 280 /* +minimum sample value */ +#define TIFFTAG_MAXSAMPLEVALUE 281 /* +maximum sample value */ +#define TIFFTAG_XRESOLUTION 282 /* pixels/resolution in x */ +#define TIFFTAG_YRESOLUTION 283 /* pixels/resolution in y */ +#define TIFFTAG_PLANARCONFIG 284 /* storage organization */ +#define PLANARCONFIG_CONTIG 1 /* single image plane */ +#define PLANARCONFIG_SEPARATE 2 /* separate planes of data */ +#define TIFFTAG_PAGENAME 285 /* page name image is from */ +#define TIFFTAG_XPOSITION 286 /* x page offset of image lhs */ +#define TIFFTAG_YPOSITION 287 /* y page offset of image lhs */ +#define TIFFTAG_FREEOFFSETS 288 /* +byte offset to free block */ +#define TIFFTAG_FREEBYTECOUNTS 289 /* +sizes of free blocks */ +#define TIFFTAG_GRAYRESPONSEUNIT 290 /* $gray scale curve accuracy */ +#define GRAYRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define GRAYRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define GRAYRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define GRAYRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define GRAYRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_GRAYRESPONSECURVE 291 /* $gray scale response curve */ +#define TIFFTAG_GROUP3OPTIONS 292 /* 32 flag bits */ +#define TIFFTAG_T4OPTIONS 292 /* TIFF 6.0 proper name alias */ +#define GROUP3OPT_2DENCODING 0x1 /* 2-dimensional coding */ +#define GROUP3OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define GROUP3OPT_FILLBITS 0x4 /* fill to byte boundary */ +#define TIFFTAG_GROUP4OPTIONS 293 /* 32 flag bits */ +#define TIFFTAG_T6OPTIONS 293 /* TIFF 6.0 proper name */ +#define GROUP4OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define TIFFTAG_RESOLUTIONUNIT 296 /* units of resolutions */ +#define RESUNIT_NONE 1 /* no meaningful units */ +#define RESUNIT_INCH 2 /* english */ +#define RESUNIT_CENTIMETER 3 /* metric */ +#define TIFFTAG_PAGENUMBER 297 /* page numbers of multi-page */ +#define TIFFTAG_COLORRESPONSEUNIT 300 /* $color curve accuracy */ +#define COLORRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define COLORRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define COLORRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define COLORRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define COLORRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_TRANSFERFUNCTION 301 /* !colorimetry info */ +#define TIFFTAG_SOFTWARE 305 /* name & release */ +#define TIFFTAG_DATETIME 306 /* creation date and time */ +#define TIFFTAG_ARTIST 315 /* creator of image */ +#define TIFFTAG_HOSTCOMPUTER 316 /* machine where created */ +#define TIFFTAG_PREDICTOR 317 /* prediction scheme w/ LZW */ +#define PREDICTOR_NONE 1 /* no prediction scheme used */ +#define PREDICTOR_HORIZONTAL 2 /* horizontal differencing */ +#define PREDICTOR_FLOATINGPOINT 3 /* floating point predictor */ +#define TIFFTAG_WHITEPOINT 318 /* image white point */ +#define TIFFTAG_PRIMARYCHROMATICITIES 319 /* !primary chromaticities */ +#define TIFFTAG_COLORMAP 320 /* RGB map for palette image */ +#define TIFFTAG_HALFTONEHINTS 321 /* !highlight+shadow info */ +#define TIFFTAG_TILEWIDTH 322 /* !tile width in pixels */ +#define TIFFTAG_TILELENGTH 323 /* !tile height in pixels */ +#define TIFFTAG_TILEOFFSETS 324 /* !offsets to data tiles */ +#define TIFFTAG_TILEBYTECOUNTS 325 /* !byte counts for tiles */ +#define TIFFTAG_BADFAXLINES 326 /* lines w/ wrong pixel count */ +#define TIFFTAG_CLEANFAXDATA 327 /* regenerated line info */ +#define CLEANFAXDATA_CLEAN 0 /* no errors detected */ +#define CLEANFAXDATA_REGENERATED 1 /* receiver regenerated lines */ +#define CLEANFAXDATA_UNCLEAN 2 /* uncorrected errors exist */ +#define TIFFTAG_CONSECUTIVEBADFAXLINES 328 /* max consecutive bad lines */ +#define TIFFTAG_SUBIFD 330 /* subimage descriptors */ +#define TIFFTAG_INKSET 332 /* !inks in separated image */ +#define INKSET_CMYK 1 /* !cyan-magenta-yellow-black color */ +#define INKSET_MULTIINK 2 /* !multi-ink or hi-fi color */ +#define TIFFTAG_INKNAMES 333 /* !ascii names of inks */ +#define TIFFTAG_NUMBEROFINKS 334 /* !number of inks */ +#define TIFFTAG_DOTRANGE 336 /* !0% and 100% dot codes */ +#define TIFFTAG_TARGETPRINTER 337 /* !separation target */ +#define TIFFTAG_EXTRASAMPLES 338 /* !info about extra samples */ +#define EXTRASAMPLE_UNSPECIFIED 0 /* !unspecified data */ +#define EXTRASAMPLE_ASSOCALPHA 1 /* !associated alpha data */ +#define EXTRASAMPLE_UNASSALPHA 2 /* !unassociated alpha data */ +#define TIFFTAG_SAMPLEFORMAT 339 /* !data sample format */ +#define SAMPLEFORMAT_UINT 1 /* !unsigned integer data */ +#define SAMPLEFORMAT_INT 2 /* !signed integer data */ +#define SAMPLEFORMAT_IEEEFP 3 /* !IEEE floating point data */ +#define SAMPLEFORMAT_VOID 4 /* !untyped data */ +#define SAMPLEFORMAT_COMPLEXINT 5 /* !complex signed int */ +#define SAMPLEFORMAT_COMPLEXIEEEFP 6 /* !complex ieee floating */ +#define TIFFTAG_SMINSAMPLEVALUE 340 /* !variable MinSampleValue */ +#define TIFFTAG_SMAXSAMPLEVALUE 341 /* !variable MaxSampleValue */ +#define TIFFTAG_CLIPPATH 343 /* %ClipPath + [Adobe TIFF technote 2] */ +#define TIFFTAG_XCLIPPATHUNITS 344 /* %XClipPathUnits + [Adobe TIFF technote 2] */ +#define TIFFTAG_YCLIPPATHUNITS 345 /* %YClipPathUnits + [Adobe TIFF technote 2] */ +#define TIFFTAG_INDEXED 346 /* %Indexed + [Adobe TIFF Technote 3] */ +#define TIFFTAG_JPEGTABLES 347 /* %JPEG table stream */ +#define TIFFTAG_OPIPROXY 351 /* %OPI Proxy [Adobe TIFF technote] */ +/* Tags 400-435 are from the TIFF/FX spec */ +#define TIFFTAG_GLOBALPARAMETERSIFD 400 /* ! */ +#define TIFFTAG_PROFILETYPE 401 /* ! */ +#define PROFILETYPE_UNSPECIFIED 0 /* ! */ +#define PROFILETYPE_G3_FAX 1 /* ! */ +#define TIFFTAG_FAXPROFILE 402 /* ! */ +#define FAXPROFILE_S 1 /* !TIFF/FX FAX profile S */ +#define FAXPROFILE_F 2 /* !TIFF/FX FAX profile F */ +#define FAXPROFILE_J 3 /* !TIFF/FX FAX profile J */ +#define FAXPROFILE_C 4 /* !TIFF/FX FAX profile C */ +#define FAXPROFILE_L 5 /* !TIFF/FX FAX profile L */ +#define FAXPROFILE_M 6 /* !TIFF/FX FAX profile LM */ +#define TIFFTAG_CODINGMETHODS 403 /* !TIFF/FX coding methods */ +#define CODINGMETHODS_T4_1D (1 << 1) /* !T.4 1D */ +#define CODINGMETHODS_T4_2D (1 << 2) /* !T.4 2D */ +#define CODINGMETHODS_T6 (1 << 3) /* !T.6 */ +#define CODINGMETHODS_T85 (1 << 4) /* !T.85 JBIG */ +#define CODINGMETHODS_T42 (1 << 5) /* !T.42 JPEG */ +#define CODINGMETHODS_T43 (1 << 6) /* !T.43 colour by layered JBIG */ +#define TIFFTAG_VERSIONYEAR 404 /* !TIFF/FX version year */ +#define TIFFTAG_MODENUMBER 405 /* !TIFF/FX mode number */ +#define TIFFTAG_DECODE 433 /* !TIFF/FX decode */ +#define TIFFTAG_IMAGEBASECOLOR 434 /* !TIFF/FX image base colour */ +#define TIFFTAG_T82OPTIONS 435 /* !TIFF/FX T.82 options */ +/* + * Tags 512-521 are obsoleted by Technical Note #2 which specifies a + * revised JPEG-in-TIFF scheme. + */ +#define TIFFTAG_JPEGPROC 512 /* !JPEG processing algorithm */ +#define JPEGPROC_BASELINE 1 /* !baseline sequential */ +#define JPEGPROC_LOSSLESS 14 /* !Huffman coded lossless */ +#define TIFFTAG_JPEGIFOFFSET 513 /* !pointer to SOI marker */ +#define TIFFTAG_JPEGIFBYTECOUNT 514 /* !JFIF stream length */ +#define TIFFTAG_JPEGRESTARTINTERVAL 515 /* !restart interval length */ +#define TIFFTAG_JPEGLOSSLESSPREDICTORS 517 /* !lossless proc predictor */ +#define TIFFTAG_JPEGPOINTTRANSFORM 518 /* !lossless point transform */ +#define TIFFTAG_JPEGQTABLES 519 /* !Q matrix offsets */ +#define TIFFTAG_JPEGDCTABLES 520 /* !DCT table offsets */ +#define TIFFTAG_JPEGACTABLES 521 /* !AC coefficient offsets */ +#define TIFFTAG_YCBCRCOEFFICIENTS 529 /* !RGB -> YCbCr transform */ +#define TIFFTAG_YCBCRSUBSAMPLING 530 /* !YCbCr subsampling factors */ +#define TIFFTAG_YCBCRPOSITIONING 531 /* !subsample positioning */ +#define YCBCRPOSITION_CENTERED 1 /* !as in PostScript Level 2 */ +#define YCBCRPOSITION_COSITED 2 /* !as in CCIR 601-1 */ +#define TIFFTAG_REFERENCEBLACKWHITE 532 /* !colorimetry info */ +#define TIFFTAG_STRIPROWCOUNTS 559 /* !TIFF/FX strip row counts */ +#define TIFFTAG_XMLPACKET 700 /* %XML packet + [Adobe XMP Specification, + January 2004 */ +#define TIFFTAG_OPIIMAGEID 32781 /* %OPI ImageID + [Adobe TIFF technote] */ +#define TIFFTAG_TIFFANNOTATIONDATA 32932 /* http://web.archive.org/web/20050309141348/http://www.kofile.com/support%20pro/faqs/annospec.htm */ +/* tags 32952-32956 are private tags registered to Island Graphics */ +#define TIFFTAG_REFPTS 32953 /* image reference points */ +#define TIFFTAG_REGIONTACKPOINT 32954 /* region-xform tack point */ +#define TIFFTAG_REGIONWARPCORNERS 32955 /* warp quadrilateral */ +#define TIFFTAG_REGIONAFFINE 32956 /* affine transformation mat */ +/* tags 32995-32999 are private tags registered to SGI */ +#define TIFFTAG_MATTEING 32995 /* $use ExtraSamples */ +#define TIFFTAG_DATATYPE 32996 /* $use SampleFormat */ +#define TIFFTAG_IMAGEDEPTH 32997 /* z depth of image */ +#define TIFFTAG_TILEDEPTH 32998 /* z depth/data tile */ +/* tags 33300-33309 are private tags registered to Pixar */ +/* + * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH + * are set when an image has been cropped out of a larger image. + * They reflect the size of the original uncropped image. + * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used + * to determine the position of the smaller image in the larger one. + */ +#define TIFFTAG_PIXAR_IMAGEFULLWIDTH 33300 /* full image size in x */ +#define TIFFTAG_PIXAR_IMAGEFULLLENGTH 33301 /* full image size in y */ + /* Tags 33302-33306 are used to identify special image modes and data + * used by Pixar's texture formats. + */ +#define TIFFTAG_PIXAR_TEXTUREFORMAT 33302 /* texture map format */ +#define TIFFTAG_PIXAR_WRAPMODES 33303 /* s & t wrap modes */ +#define TIFFTAG_PIXAR_FOVCOT 33304 /* cotan(fov) for env. maps */ +#define TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN 33305 +#define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306 +/* tag 33405 is a private tag registered to Eastman Kodak */ +#define TIFFTAG_WRITERSERIALNUMBER 33405 /* device serial number */ +#define TIFFTAG_CFAREPEATPATTERNDIM 33421 /* dimensions of CFA pattern */ +#define TIFFTAG_CFAPATTERN 33422 /* color filter array pattern */ +/* tag 33432 is listed in the 6.0 spec w/ unknown ownership */ +#define TIFFTAG_COPYRIGHT 33432 /* copyright string */ +/* Tags 33445-33452 are used for GEL fileformat, see + * http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf + */ +#define TIFFTAG_MD_FILETAG 33445 /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */ +#define TIFFTAG_MD_SCALEPIXEL 33446 /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */ +#define TIFFTAG_MD_COLORTABLE 33447 /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */ +#define TIFFTAG_MD_LABNAME 33448 /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */ +#define TIFFTAG_MD_SAMPLEINFO 33449 /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */ +#define TIFFTAG_MD_PREPDATE 33450 /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */ +#define TIFFTAG_MD_PREPTIME 33451 /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */ +#define TIFFTAG_MD_FILEUNITS 33452 /* http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf */ +/* IPTC TAG from RichTIFF specifications */ +#define TIFFTAG_RICHTIFFIPTC 33723 +#define TIFFTAG_INGR_PACKET_DATA_TAG 33918 /* Intergraph Application specific storage. */ +#define TIFFTAG_INGR_FLAG_REGISTERS 33919 /* Intergraph Application specific flags. */ +#define TIFFTAG_IRASB_TRANSORMATION_MATRIX 33920 /* Originally part of Intergraph's GeoTIFF tags, but likely understood by IrasB only. */ +#define TIFFTAG_MODELTIEPOINTTAG 33922 /* GeoTIFF */ +/* 34016-34029 are reserved for ANSI IT8 TIFF/IT */ +#define TIFFTAG_STONITS 37439 /* Sample value to Nits */ +/* tag 34929 is a private tag registered to FedEx */ +#define TIFFTAG_FEDEX_EDR 34929 /* unknown use */ +#define TIFFTAG_IMAGESOURCEDATA 37724 /* http://justsolve.archiveteam.org/wiki/PSD, http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */ +#define TIFFTAG_INTEROPERABILITYIFD 40965 /* Pointer to Interoperability private directory */ +#define TIFFTAG_GDAL_METADATA 42112 /* Used by the GDAL library */ +#define TIFFTAG_GDAL_NODATA 42113 /* Used by the GDAL library */ +#define TIFFTAG_OCE_SCANJOB_DESCRIPTION 50215 /* Used in the Oce scanning process */ +#define TIFFTAG_OCE_APPLICATION_SELECTOR 50216 /* Used in the Oce scanning process. */ +#define TIFFTAG_OCE_IDENTIFICATION_NUMBER 50217 +#define TIFFTAG_OCE_IMAGELOGIC_CHARACTERISTICS 50218 + +/* tags 50674 to 50677 are reserved for ESRI */ +#define TIFFTAG_LERC_PARAMETERS 50674 /* Stores LERC version and additional compression method */ +/* Adobe Digital Negative (DNG) format tags */ +#define TIFFTAG_DNGVERSION 50706 /* &DNG version number */ +#define TIFFTAG_DNGBACKWARDVERSION 50707 /* &DNG compatibility version */ +#define TIFFTAG_UNIQUECAMERAMODEL 50708 /* &name for the camera model */ +#define TIFFTAG_LOCALIZEDCAMERAMODEL 50709 /* &localized camera model + name */ +#define TIFFTAG_CFAPLANECOLOR 50710 /* &CFAPattern->LinearRaw space + mapping */ +#define TIFFTAG_CFALAYOUT 50711 /* &spatial layout of the CFA */ +#define TIFFTAG_LINEARIZATIONTABLE 50712 /* &lookup table description */ +#define TIFFTAG_BLACKLEVELREPEATDIM 50713 /* &repeat pattern size for + the BlackLevel tag */ +#define TIFFTAG_BLACKLEVEL 50714 /* &zero light encoding level */ +#define TIFFTAG_BLACKLEVELDELTAH 50715 /* &zero light encoding level + differences (columns) */ +#define TIFFTAG_BLACKLEVELDELTAV 50716 /* &zero light encoding level + differences (rows) */ +#define TIFFTAG_WHITELEVEL 50717 /* &fully saturated encoding + level */ +#define TIFFTAG_DEFAULTSCALE 50718 /* &default scale factors */ +#define TIFFTAG_DEFAULTCROPORIGIN 50719 /* &origin of the final image + area */ +#define TIFFTAG_DEFAULTCROPSIZE 50720 /* &size of the final image + area */ +#define TIFFTAG_COLORMATRIX1 50721 /* &XYZ->reference color space + transformation matrix 1 */ +#define TIFFTAG_COLORMATRIX2 50722 /* &XYZ->reference color space + transformation matrix 2 */ +#define TIFFTAG_CAMERACALIBRATION1 50723 /* &calibration matrix 1 */ +#define TIFFTAG_CAMERACALIBRATION2 50724 /* &calibration matrix 2 */ +#define TIFFTAG_REDUCTIONMATRIX1 50725 /* &dimensionality reduction + matrix 1 */ +#define TIFFTAG_REDUCTIONMATRIX2 50726 /* &dimensionality reduction + matrix 2 */ +#define TIFFTAG_ANALOGBALANCE 50727 /* &gain applied the stored raw + values*/ +#define TIFFTAG_ASSHOTNEUTRAL 50728 /* &selected white balance in + linear reference space */ +#define TIFFTAG_ASSHOTWHITEXY 50729 /* &selected white balance in + x-y chromaticity + coordinates */ +#define TIFFTAG_BASELINEEXPOSURE 50730 /* &how much to move the zero + point */ +#define TIFFTAG_BASELINENOISE 50731 /* &relative noise level */ +#define TIFFTAG_BASELINESHARPNESS 50732 /* &relative amount of + sharpening */ +#define TIFFTAG_BAYERGREENSPLIT 50733 /* &how closely the values of + the green pixels in the + blue/green rows track the + values of the green pixels + in the red/green rows */ +#define TIFFTAG_LINEARRESPONSELIMIT 50734 /* &non-linear encoding range */ +#define TIFFTAG_CAMERASERIALNUMBER 50735 /* &camera's serial number */ +#define TIFFTAG_LENSINFO 50736 /* info about the lens */ +#define TIFFTAG_CHROMABLURRADIUS 50737 /* &chroma blur radius */ +#define TIFFTAG_ANTIALIASSTRENGTH 50738 /* &relative strength of the + camera's anti-alias filter */ +#define TIFFTAG_SHADOWSCALE 50739 /* &used by Adobe Camera Raw */ +#define TIFFTAG_DNGPRIVATEDATA 50740 /* &manufacturer's private data */ +#define TIFFTAG_MAKERNOTESAFETY 50741 /* &whether the EXIF MakerNote + tag is safe to preserve + along with the rest of the + EXIF data */ +#define TIFFTAG_CALIBRATIONILLUMINANT1 50778 /* &illuminant 1 */ +#define TIFFTAG_CALIBRATIONILLUMINANT2 50779 /* &illuminant 2 */ +#define TIFFTAG_BESTQUALITYSCALE 50780 /* &best quality multiplier */ +#define TIFFTAG_RAWDATAUNIQUEID 50781 /* &unique identifier for + the raw image data */ +#define TIFFTAG_ORIGINALRAWFILENAME 50827 /* &file name of the original + raw file */ +#define TIFFTAG_ORIGINALRAWFILEDATA 50828 /* &contents of the original + raw file */ +#define TIFFTAG_ACTIVEAREA 50829 /* &active (non-masked) pixels + of the sensor */ +#define TIFFTAG_MASKEDAREAS 50830 /* &list of coordinates + of fully masked pixels */ +#define TIFFTAG_ASSHOTICCPROFILE 50831 /* &these two tags used to */ +#define TIFFTAG_ASSHOTPREPROFILEMATRIX 50832 /* map cameras's color space + into ICC profile space */ +#define TIFFTAG_CURRENTICCPROFILE 50833 /* & */ +#define TIFFTAG_CURRENTPREPROFILEMATRIX 50834 /* & */ + +#define TIFFTAG_RPCCOEFFICIENT 50844 /* Define by GDAL for geospatial georeferencing through RPC: http://geotiff.maptools.org/rpc_prop.html */ + +#define TIFFTAG_ALIAS_LAYER_METADATA 50784 /* Alias Sketchbook Pro layer usage description. */ + +/* GeoTIFF DGIWG */ +#define TIFFTAG_TIFF_RSID 50908 /* https://www.awaresystems.be/imaging/tiff/tifftags/tiff_rsid.html */ +#define TIFFTAG_GEO_METADATA 50909 /* https://www.awaresystems.be/imaging/tiff/tifftags/geo_metadata.html */ + +#define TIFFTAG_EXTRACAMERAPROFILES 50933 /* http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf */ + +/* tag 65535 is an undefined tag used by Eastman Kodak */ +#define TIFFTAG_DCSHUESHIFTVALUES 65535 /* hue shift correction data */ + +/* + * The following are ``pseudo tags'' that can be used to control + * codec-specific functionality. These tags are not written to file. + * Note that these values start at 0xffff+1 so that they'll never + * collide with Aldus-assigned tags. + * + * If you want your private pseudo tags ``registered'' (i.e. added to + * this file), please post a bug report via the tracking system at + * http://www.remotesensing.org/libtiff/bugs.html with the appropriate + * C definitions to add. + */ +#define TIFFTAG_FAXMODE 65536 /* Group 3/4 format control */ +#define FAXMODE_CLASSIC 0x0000 /* default, include RTC */ +#define FAXMODE_NORTC 0x0001 /* no RTC at end of data */ +#define FAXMODE_NOEOL 0x0002 /* no EOL code at end of row */ +#define FAXMODE_BYTEALIGN 0x0004 /* byte align row */ +#define FAXMODE_WORDALIGN 0x0008 /* word align row */ +#define FAXMODE_CLASSF FAXMODE_NORTC /* TIFF Class F */ +#define TIFFTAG_JPEGQUALITY 65537 /* Compression quality level */ +/* Note: quality level is on the IJG 0-100 scale. Default value is 75 */ +#define TIFFTAG_JPEGCOLORMODE 65538 /* Auto RGB<=>YCbCr convert? */ +#define JPEGCOLORMODE_RAW 0x0000 /* no conversion (default) */ +#define JPEGCOLORMODE_RGB 0x0001 /* do auto conversion */ +#define TIFFTAG_JPEGTABLESMODE 65539 /* What to put in JPEGTables */ +#define JPEGTABLESMODE_QUANT 0x0001 /* include quantization tbls */ +#define JPEGTABLESMODE_HUFF 0x0002 /* include Huffman tbls */ +/* Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF */ +#define TIFFTAG_FAXFILLFUNC 65540 /* G3/G4 fill function */ +#define TIFFTAG_PIXARLOGDATAFMT 65549 /* PixarLogCodec I/O data sz */ +#define PIXARLOGDATAFMT_8BIT 0 /* regular u_char samples */ +#define PIXARLOGDATAFMT_8BITABGR 1 /* ABGR-order u_chars */ +#define PIXARLOGDATAFMT_11BITLOG 2 /* 11-bit log-encoded (raw) */ +#define PIXARLOGDATAFMT_12BITPICIO 3 /* as per PICIO (1.0==2048) */ +#define PIXARLOGDATAFMT_16BIT 4 /* signed short samples */ +#define PIXARLOGDATAFMT_FLOAT 5 /* IEEE float samples */ +/* 65550-65556 are allocated to Oceana Matrix */ +#define TIFFTAG_DCSIMAGERTYPE 65550 /* imager model & filter */ +#define DCSIMAGERMODEL_M3 0 /* M3 chip (1280 x 1024) */ +#define DCSIMAGERMODEL_M5 1 /* M5 chip (1536 x 1024) */ +#define DCSIMAGERMODEL_M6 2 /* M6 chip (3072 x 2048) */ +#define DCSIMAGERFILTER_IR 0 /* infrared filter */ +#define DCSIMAGERFILTER_MONO 1 /* monochrome filter */ +#define DCSIMAGERFILTER_CFA 2 /* color filter array */ +#define DCSIMAGERFILTER_OTHER 3 /* other filter */ +#define TIFFTAG_DCSINTERPMODE 65551 /* interpolation mode */ +#define DCSINTERPMODE_NORMAL 0x0 /* whole image, default */ +#define DCSINTERPMODE_PREVIEW 0x1 /* preview of image (384x256) */ +#define TIFFTAG_DCSBALANCEARRAY 65552 /* color balance values */ +#define TIFFTAG_DCSCORRECTMATRIX 65553 /* color correction values */ +#define TIFFTAG_DCSGAMMA 65554 /* gamma value */ +#define TIFFTAG_DCSTOESHOULDERPTS 65555 /* toe & shoulder points */ +#define TIFFTAG_DCSCALIBRATIONFD 65556 /* calibration file desc */ +/* Note: quality level is on the ZLIB 1-9 scale. Default value is -1 */ +#define TIFFTAG_ZIPQUALITY 65557 /* compression quality level */ +#define TIFFTAG_PIXARLOGQUALITY 65558 /* PixarLog uses same scale */ +/* 65559 is allocated to Oceana Matrix */ +#define TIFFTAG_DCSCLIPRECTANGLE 65559 /* area of image to acquire */ +#define TIFFTAG_SGILOGDATAFMT 65560 /* SGILog user data format */ +#define SGILOGDATAFMT_FLOAT 0 /* IEEE float samples */ +#define SGILOGDATAFMT_16BIT 1 /* 16-bit samples */ +#define SGILOGDATAFMT_RAW 2 /* uninterpreted data */ +#define SGILOGDATAFMT_8BIT 3 /* 8-bit RGB monitor values */ +#define TIFFTAG_SGILOGENCODE 65561 /* SGILog data encoding control*/ +#define SGILOGENCODE_NODITHER 0 /* do not dither encoded values*/ +#define SGILOGENCODE_RANDITHER 1 /* randomly dither encd values */ +#define TIFFTAG_LZMAPRESET 65562 /* LZMA2 preset (compression level) */ +#define TIFFTAG_PERSAMPLE 65563 /* interface for per sample tags */ +#define PERSAMPLE_MERGED 0 /* present as a single value */ +#define PERSAMPLE_MULTI 1 /* present as multiple values */ +#define TIFFTAG_ZSTD_LEVEL 65564 /* ZSTD compression level */ +#define TIFFTAG_LERC_VERSION 65565 /* LERC version */ +#define LERC_VERSION_2_4 4 +#define TIFFTAG_LERC_ADD_COMPRESSION 65566 /* LERC additional compression */ +#define LERC_ADD_COMPRESSION_NONE 0 +#define LERC_ADD_COMPRESSION_DEFLATE 1 +#define LERC_ADD_COMPRESSION_ZSTD 2 +#define TIFFTAG_LERC_MAXZERROR 65567 /* LERC maximum error */ +#define TIFFTAG_WEBP_LEVEL 65568 /* WebP compression level */ +#define TIFFTAG_WEBP_LOSSLESS 65569 /* WebP lossless/lossy */ +#define TIFFTAG_DEFLATE_SUBCODEC 65570 /* ZIP codec: to get/set the sub-codec to use. Will default to libdeflate when available */ +#define DEFLATE_SUBCODEC_ZLIB 0 +#define DEFLATE_SUBCODEC_LIBDEFLATE 1 + +/* + * EXIF tags + */ +#define EXIFTAG_EXPOSURETIME 33434 /* Exposure time */ +#define EXIFTAG_FNUMBER 33437 /* F number */ +#define EXIFTAG_EXPOSUREPROGRAM 34850 /* Exposure program */ +#define EXIFTAG_SPECTRALSENSITIVITY 34852 /* Spectral sensitivity */ +#define EXIFTAG_ISOSPEEDRATINGS 34855 /* ISO speed rating */ +#define EXIFTAG_PHOTOGRAPHICSENSITIVITY 34855 /* Photographic Sensitivity (new name for tag 34855) */ +#define EXIFTAG_OECF 34856 /* Optoelectric conversion factor */ +#define EXIFTAG_EXIFVERSION 36864 /* Exif version */ +#define EXIFTAG_DATETIMEORIGINAL 36867 /* Date and time of original + data generation */ +#define EXIFTAG_DATETIMEDIGITIZED 36868 /* Date and time of digital + data generation */ +#define EXIFTAG_COMPONENTSCONFIGURATION 37121 /* Meaning of each component */ +#define EXIFTAG_COMPRESSEDBITSPERPIXEL 37122 /* Image compression mode */ +#define EXIFTAG_SHUTTERSPEEDVALUE 37377 /* Shutter speed */ +#define EXIFTAG_APERTUREVALUE 37378 /* Aperture */ +#define EXIFTAG_BRIGHTNESSVALUE 37379 /* Brightness */ +#define EXIFTAG_EXPOSUREBIASVALUE 37380 /* Exposure bias */ +#define EXIFTAG_MAXAPERTUREVALUE 37381 /* Maximum lens aperture */ +#define EXIFTAG_SUBJECTDISTANCE 37382 /* Subject distance */ +#define EXIFTAG_METERINGMODE 37383 /* Metering mode */ +#define EXIFTAG_LIGHTSOURCE 37384 /* Light source */ +#define EXIFTAG_FLASH 37385 /* Flash */ +#define EXIFTAG_FOCALLENGTH 37386 /* Lens focal length */ +#define EXIFTAG_SUBJECTAREA 37396 /* Subject area */ +#define EXIFTAG_MAKERNOTE 37500 /* Manufacturer notes */ +#define EXIFTAG_USERCOMMENT 37510 /* User comments */ +#define EXIFTAG_SUBSECTIME 37520 /* DateTime subseconds */ +#define EXIFTAG_SUBSECTIMEORIGINAL 37521 /* DateTimeOriginal subseconds */ +#define EXIFTAG_SUBSECTIMEDIGITIZED 37522 /* DateTimeDigitized subseconds */ +#define EXIFTAG_FLASHPIXVERSION 40960 /* Supported Flashpix version */ +#define EXIFTAG_COLORSPACE 40961 /* Color space information */ +#define EXIFTAG_PIXELXDIMENSION 40962 /* Valid image width */ +#define EXIFTAG_PIXELYDIMENSION 40963 /* Valid image height */ +#define EXIFTAG_RELATEDSOUNDFILE 40964 /* Related audio file */ +#define EXIFTAG_FLASHENERGY 41483 /* Flash energy */ +#define EXIFTAG_SPATIALFREQUENCYRESPONSE 41484 /* Spatial frequency response */ +#define EXIFTAG_FOCALPLANEXRESOLUTION 41486 /* Focal plane X resolution */ +#define EXIFTAG_FOCALPLANEYRESOLUTION 41487 /* Focal plane Y resolution */ +#define EXIFTAG_FOCALPLANERESOLUTIONUNIT 41488 /* Focal plane resolution unit */ +#define EXIFTAG_SUBJECTLOCATION 41492 /* Subject location */ +#define EXIFTAG_EXPOSUREINDEX 41493 /* Exposure index */ +#define EXIFTAG_SENSINGMETHOD 41495 /* Sensing method */ +#define EXIFTAG_FILESOURCE 41728 /* File source */ +#define EXIFTAG_SCENETYPE 41729 /* Scene type */ +#define EXIFTAG_CFAPATTERN 41730 /* CFA pattern */ +#define EXIFTAG_CUSTOMRENDERED 41985 /* Custom image processing */ +#define EXIFTAG_EXPOSUREMODE 41986 /* Exposure mode */ +#define EXIFTAG_WHITEBALANCE 41987 /* White balance */ +#define EXIFTAG_DIGITALZOOMRATIO 41988 /* Digital zoom ratio */ +#define EXIFTAG_FOCALLENGTHIN35MMFILM 41989 /* Focal length in 35 mm film */ +#define EXIFTAG_SCENECAPTURETYPE 41990 /* Scene capture type */ +#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ +#define EXIFTAG_CONTRAST 41992 /* Contrast */ +#define EXIFTAG_SATURATION 41993 /* Saturation */ +#define EXIFTAG_SHARPNESS 41994 /* Sharpness */ +#define EXIFTAG_DEVICESETTINGDESCRIPTION 41995 /* Device settings description */ +#define EXIFTAG_SUBJECTDISTANCERANGE 41996 /* Subject distance range */ +#define EXIFTAG_IMAGEUNIQUEID 42016 /* Unique image ID */ + +/*--: New for EXIF-Version 2.32, May 2019 ... */ +#define EXIFTAG_SENSITIVITYTYPE 34864 /* The SensitivityType tag indicates which one of the parameters of ISO12232 is the PhotographicSensitivity tag. */ +#define EXIFTAG_STANDARDOUTPUTSENSITIVITY 34865 /* This tag indicates the standard output sensitivity value of a camera or input device defined in ISO 12232. */ +#define EXIFTAG_RECOMMENDEDEXPOSUREINDEX 34866 /* recommended exposure index */ +#define EXIFTAG_ISOSPEED 34867 /* ISO speed value */ +#define EXIFTAG_ISOSPEEDLATITUDEYYY 34868 /* ISO speed latitude yyy */ +#define EXIFTAG_ISOSPEEDLATITUDEZZZ 34869 /* ISO speed latitude zzz */ +#define EXIFTAG_OFFSETTIME 36880 /* offset from UTC of the time of DateTime tag. */ +#define EXIFTAG_OFFSETTIMEORIGINAL 36881 /* offset from UTC of the time of DateTimeOriginal tag. */ +#define EXIFTAG_OFFSETTIMEDIGITIZED 36882 /* offset from UTC of the time of DateTimeDigitized tag. */ +#define EXIFTAG_TEMPERATURE 37888 /* Temperature as the ambient situation at the shot in dergee Celsius */ +#define EXIFTAG_HUMIDITY 37889 /* Humidity as the ambient situation at the shot in percent */ +#define EXIFTAG_PRESSURE 37890 /* Pressure as the ambient situation at the shot hecto-Pascal (hPa) */ +#define EXIFTAG_WATERDEPTH 37891 /* WaterDepth as the ambient situation at the shot in meter (m) */ +#define EXIFTAG_ACCELERATION 37892 /* Acceleration (a scalar regardless of direction) as the ambient situation at the shot in units of mGal (10-5 m/s^2) */ +#define EXIFTAG_CAMERAELEVATIONANGLE 37893 /* Elevation/depression. angle of the orientation of the camera(imaging optical axis) as the ambient situation at the shot in degree from -180deg to +180deg. */ +#define EXIFTAG_CAMERAOWNERNAME 42032 /* owner of a camera */ +#define EXIFTAG_BODYSERIALNUMBER 42033 /* serial number of the body of the camera */ +#define EXIFTAG_LENSSPECIFICATION 42034 /* minimum focal length (in mm), maximum focal length (in mm), minimum F number in the minimum focal length, and minimum F number in the maximum focal length, */ +#define EXIFTAG_LENSMAKE 42035 /* the lens manufacturer */ +#define EXIFTAG_LENSMODEL 42036 /* the lens model name and model number */ +#define EXIFTAG_LENSSERIALNUMBER 42037 /* the serial number of the interchangeable lens */ +#define EXIFTAG_GAMMA 42240 /* value of coefficient gamma */ +#define EXIFTAG_COMPOSITEIMAGE 42080 /* composite image */ +#define EXIFTAG_SOURCEIMAGENUMBEROFCOMPOSITEIMAGE 42081 /* source image number of composite image */ +#define EXIFTAG_SOURCEEXPOSURETIMESOFCOMPOSITEIMAGE 42082 /* source exposure times of composite image */ + +/* + * EXIF-GPS tags (Version 2.31, July 2016) + */ +#define GPSTAG_VERSIONID 0 /* Indicates the version of GPSInfoIFD. */ +#define GPSTAG_LATITUDEREF 1 /* Indicates whether the latitude is north or south latitude. */ +#define GPSTAG_LATITUDE 2 /* Indicates the latitude. */ +#define GPSTAG_LONGITUDEREF 3 /* Indicates whether the longitude is east or west longitude. */ +#define GPSTAG_LONGITUDE 4 /* Indicates the longitude. */ +#define GPSTAG_ALTITUDEREF 5 /* Indicates the altitude used as the reference altitude. */ +#define GPSTAG_ALTITUDE 6 /* Indicates the altitude based on the reference in GPSAltitudeRef. */ +#define GPSTAG_TIMESTAMP 7 /* Indicates the time as UTC (Coordinated Universal Time). */ +#define GPSTAG_SATELLITES 8 /* Indicates the GPS satellites used for measurements. */ +#define GPSTAG_STATUS 9 /* Indicates the status of the GPS receiver when the image is recorded. */ +#define GPSTAG_MEASUREMODE 10 /* Indicates the GPS measurement mode. */ +#define GPSTAG_DOP 11 /* Indicates the GPS DOP (data degree of precision). */ +#define GPSTAG_SPEEDREF 12 /* Indicates the unit used to express the GPS receiver speed of movement. */ +#define GPSTAG_SPEED 13 /* Indicates the speed of GPS receiver movement. */ +#define GPSTAG_TRACKREF 14 /* Indicates the reference for giving the direction of GPS receiver movement. */ +#define GPSTAG_TRACK 15 /* Indicates the direction of GPS receiver movement. */ +#define GPSTAG_IMGDIRECTIONREF 16 /* Indicates the reference for giving the direction of the image when it is captured. */ +#define GPSTAG_IMGDIRECTION 17 /* Indicates the direction of the image when it was captured. */ +#define GPSTAG_MAPDATUM 18 /* Indicates the geodetic survey data used by the GPS receiver. (e.g. WGS-84) */ +#define GPSTAG_DESTLATITUDEREF 19 /* Indicates whether the latitude of the destination point is north or south latitude. */ +#define GPSTAG_DESTLATITUDE 20 /* Indicates the latitude of the destination point. */ +#define GPSTAG_DESTLONGITUDEREF 21 /* Indicates whether the longitude of the destination point is east or west longitude. */ +#define GPSTAG_DESTLONGITUDE 22 /* Indicates the longitude of the destination point. */ +#define GPSTAG_DESTBEARINGREF 23 /* Indicates the reference used for giving the bearing to the destination point. */ +#define GPSTAG_DESTBEARING 24 /* Indicates the bearing to the destination point. */ +#define GPSTAG_DESTDISTANCEREF 25 /* Indicates the unit used to express the distance to the destination point. */ +#define GPSTAG_DESTDISTANCE 26 /* Indicates the distance to the destination point. */ +#define GPSTAG_PROCESSINGMETHOD 27 /* A character string recording the name of the method used for location finding. */ +#define GPSTAG_AREAINFORMATION 28 /* A character string recording the name of the GPS area. */ +#define GPSTAG_DATESTAMP 29 /* A character string recording date and time information relative to UTC (Coordinated Universal Time). */ +#define GPSTAG_DIFFERENTIAL 30 /* Indicates whether differential correction is applied to the GPS receiver. */ +#define GPSTAG_GPSHPOSITIONINGERROR 31 /* Indicates horizontal positioning errors in meters. */ + +#endif /* _TIFF_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tiffconf.h b/libs/tiff/libtiff/tiffconf.h new file mode 100644 index 00000000000..0934be39686 --- /dev/null +++ b/libs/tiff/libtiff/tiffconf.h @@ -0,0 +1,128 @@ +/* libtiff/tiffconf.h. Generated from tiffconf.h.in by configure. */ +/* + Configuration defines for installed libtiff. + This file maintained for backward compatibility. Do not use definitions + from this file in your programs. +*/ + +#ifndef _TIFFCONF_ +#define _TIFFCONF_ + + +#include +#include +#include + + +/* Signed 16-bit type */ +/* #undef TIFF_INT16_T */ + +/* Signed 32-bit type */ +/* #undef TIFF_INT32_T */ + +/* Signed 64-bit type */ +/* #undef TIFF_INT64_T */ + +/* Signed 8-bit type */ +/* #undef TIFF_INT8_T */ + +/* Unsigned 16-bit type */ +/* #undef TIFF_UINT16_T */ + +/* Unsigned 32-bit type */ +/* #undef TIFF_UINT32_T */ + +/* Unsigned 64-bit type */ +/* #undef TIFF_UINT64_T */ + +/* Unsigned 8-bit type */ +/* #undef TIFF_UINT8_T */ + +/* Signed size type */ +#define TIFF_SSIZE_T ssize_t + +/* Compatibility stuff. */ + +/* Define as 0 or 1 according to the floating point format supported by the + machine */ +#define HAVE_IEEEFP 1 + +/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */ +#define HOST_FILLORDER FILLORDER_LSB2MSB + +/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian + (Intel) */ +#define HOST_BIGENDIAN 0 + +/* Support CCITT Group 3 & 4 algorithms */ +#define CCITT_SUPPORT 1 + +/* Support JPEG compression (requires IJG JPEG library) */ +#define JPEG_SUPPORT 1 + +/* Support JBIG compression (requires JBIG-KIT library) */ +/* #undef JBIG_SUPPORT */ + +/* Support LERC compression */ +/* #undef LERC_SUPPORT */ + +/* Support LogLuv high dynamic range encoding */ +#define LOGLUV_SUPPORT 1 + +/* Support LZW algorithm */ +#define LZW_SUPPORT 1 + +/* Support NeXT 2-bit RLE algorithm */ +#define NEXT_SUPPORT 1 + +/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation + fails with unpatched IJG JPEG library) */ +/* #undef OJPEG_SUPPORT */ + +/* Support Macintosh PackBits algorithm */ +#define PACKBITS_SUPPORT 1 + +/* Support Pixar log-format algorithm (requires Zlib) */ +#define PIXARLOG_SUPPORT 1 + +/* Support ThunderScan 4-bit RLE algorithm */ +#define THUNDER_SUPPORT 1 + +/* Support Deflate compression */ +#define ZIP_SUPPORT 1 + +/* Support libdeflate enhanced compression */ +/* #undef LIBDEFLATE_SUPPORT */ + +/* Support strip chopping (whether or not to convert single-strip uncompressed + images to multiple strips of ~8Kb to reduce memory usage) */ +#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP + +/* Enable SubIFD tag (330) support */ +#define SUBIFD_SUPPORT 1 + +/* Treat extra sample as alpha (default enabled). The RGBA interface will + treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many + packages produce RGBA files but don't mark the alpha properly. */ +#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1 + +/* Pick up YCbCr subsampling info from the JPEG data stream to support files + lacking the tag (default enabled). */ +#define CHECK_JPEG_YCBCR_SUBSAMPLING 1 + +/* Support MS MDI magic number files as TIFF */ +#define MDI_SUPPORT 1 + +/* + * Feature support definitions. + * XXX: These macros are obsoleted. Don't use them in your apps! + * Macros stays here for backward compatibility and should be always defined. + */ +#define COLORIMETRY_SUPPORT +#define YCBCR_SUPPORT +#define CMYK_SUPPORT +#define ICC_SUPPORT +#define PHOTOSHOP_SUPPORT +#define IPTC_SUPPORT + +#endif /* _TIFFCONF_ */ diff --git a/libs/tiff/libtiff/tiffio.h b/libs/tiff/libtiff/tiffio.h new file mode 100644 index 00000000000..0212968b0c2 --- /dev/null +++ b/libs/tiff/libtiff/tiffio.h @@ -0,0 +1,574 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIO_ +#define _TIFFIO_ + +/* + * TIFF I/O Library Definitions. + */ +#include "tiff.h" +#include "tiffvers.h" + +/* + * TIFF is defined as an incomplete type to hide the + * library's internal data structures from clients. + */ +typedef struct tiff TIFF; + +/* + * The following typedefs define the intrinsic size of + * data types used in the *exported* interfaces. These + * definitions depend on the proper definition of types + * in tiff.h. Note also that the varargs interface used + * to pass tag types and values uses the types defined in + * tiff.h directly. + * + * NB: ttag_t is unsigned int and not unsigned short because + * ANSI C requires that the type before the ellipsis be a + * promoted type (i.e. one of int, unsigned int, pointer, + * or double) and because we defined pseudo-tags that are + * outside the range of legal Aldus-assigned tags. + * NB: tsize_t is signed and not unsigned because some functions + * return -1. + * NB: toff_t is not off_t for many reasons; TIFFs max out at + * 32-bit file offsets, and BigTIFF maxes out at 64-bit + * offsets being the most important, and to ensure use of + * a consistently unsigned type across architectures. + * Prior to libtiff 4.0, this was an unsigned 32 bit type. + */ +/* + * this is the machine addressing size type, only it's signed, so make it + * int32_t on 32bit machines, int64_t on 64bit machines + */ +typedef TIFF_SSIZE_T tmsize_t; +#define TIFF_TMSIZE_T_MAX (tmsize_t)(SIZE_MAX >> 1) + +typedef uint64_t toff_t; /* file offset */ +/* the following are deprecated and should be replaced by their defining + counterparts */ +typedef uint32_t ttag_t; /* directory tag */ +typedef uint16_t tdir_t; /* directory index */ +typedef uint16_t tsample_t; /* sample number */ +typedef uint32_t tstrile_t; /* strip or tile number */ +typedef tstrile_t tstrip_t; /* strip number */ +typedef tstrile_t ttile_t; /* tile number */ +typedef tmsize_t tsize_t; /* i/o size in bytes */ +typedef void* tdata_t; /* image data ref */ + +#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32)) +#define __WIN32__ +#endif + +/* + * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c + * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c). + * + * By default tif_unix.c is assumed. + */ + +#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) +# if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILEIO) +# define AVOID_WIN32_FILEIO +# endif +#endif + +#if defined(USE_WIN32_FILEIO) +# define VC_EXTRALEAN +# include +# ifdef __WIN32__ +DECLARE_HANDLE(thandle_t); /* Win32 file handle */ +# else +typedef HFILE thandle_t; /* client data handle */ +# endif /* __WIN32__ */ +#else +typedef void* thandle_t; /* client data handle */ +#endif /* USE_WIN32_FILEIO */ + +/* + * Flags to pass to TIFFPrintDirectory to control + * printing of data structures that are potentially + * very large. Bit-or these flags to enable printing + * multiple items. + */ +#define TIFFPRINT_NONE 0x0 /* no extra info */ +#define TIFFPRINT_STRIPS 0x1 /* strips/tiles info */ +#define TIFFPRINT_CURVES 0x2 /* color/gray response curves */ +#define TIFFPRINT_COLORMAP 0x4 /* colormap */ +#define TIFFPRINT_JPEGQTABLES 0x100 /* JPEG Q matrices */ +#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */ +#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */ + +/* + * Colour conversion stuff + */ + +/* reference white */ +#define D65_X0 (95.0470F) +#define D65_Y0 (100.0F) +#define D65_Z0 (108.8827F) + +#define D50_X0 (96.4250F) +#define D50_Y0 (100.0F) +#define D50_Z0 (82.4680F) + +/* Structure for holding information about a display device. */ + +typedef unsigned char TIFFRGBValue; /* 8-bit samples */ + +typedef struct { + float d_mat[3][3]; /* XYZ -> luminance matrix */ + float d_YCR; /* Light o/p for reference white */ + float d_YCG; + float d_YCB; + uint32_t d_Vrwr; /* Pixel values for ref. white */ + uint32_t d_Vrwg; + uint32_t d_Vrwb; + float d_Y0R; /* Residual light for black pixel */ + float d_Y0G; + float d_Y0B; + float d_gammaR; /* Gamma values for the three guns */ + float d_gammaG; + float d_gammaB; +} TIFFDisplay; + +typedef struct { /* YCbCr->RGB support */ + TIFFRGBValue* clamptab; /* range clamping table */ + int* Cr_r_tab; + int* Cb_b_tab; + int32_t* Cr_g_tab; + int32_t* Cb_g_tab; + int32_t* Y_tab; +} TIFFYCbCrToRGB; + +typedef struct { /* CIE Lab 1976->RGB support */ + int range; /* Size of conversion table */ +#define CIELABTORGB_TABLE_RANGE 1500 + float rstep, gstep, bstep; + float X0, Y0, Z0; /* Reference white point */ + TIFFDisplay display; + float Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr to r */ + float Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg to g */ + float Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb to b */ +} TIFFCIELabToRGB; + +/* + * RGBA-style image support. + */ +typedef struct _TIFFRGBAImage TIFFRGBAImage; +/* + * The image reading and conversion routines invoke + * ``put routines'' to copy/image/whatever tiles of + * raw image data. A default set of routines are + * provided to convert/copy raw image data to 8-bit + * packed ABGR format rasters. Applications can supply + * alternate routines that unpack the data into a + * different format or, for example, unpack the data + * and draw the unpacked raster on the display. + */ +typedef void (*tileContigRoutine) + (TIFFRGBAImage*, uint32_t*, uint32_t, uint32_t, uint32_t, uint32_t, int32_t, int32_t, + unsigned char*); +typedef void (*tileSeparateRoutine) + (TIFFRGBAImage*, uint32_t*, uint32_t, uint32_t, uint32_t, uint32_t, int32_t, int32_t, + unsigned char*, unsigned char*, unsigned char*, unsigned char*); +/* + * RGBA-reader state. + */ +struct _TIFFRGBAImage { + TIFF* tif; /* image handle */ + int stoponerr; /* stop on read error */ + int isContig; /* data is packed/separate */ + int alpha; /* type of alpha data present */ + uint32_t width; /* image width */ + uint32_t height; /* image height */ + uint16_t bitspersample; /* image bits/sample */ + uint16_t samplesperpixel; /* image samples/pixel */ + uint16_t orientation; /* image orientation */ + uint16_t req_orientation; /* requested orientation */ + uint16_t photometric; /* image photometric interp */ + uint16_t* redcmap; /* colormap palette */ + uint16_t* greencmap; + uint16_t* bluecmap; + /* get image data routine */ + int (*get)(TIFFRGBAImage*, uint32_t*, uint32_t, uint32_t); + /* put decoded strip/tile */ + union { + void (*any)(TIFFRGBAImage*); + tileContigRoutine contig; + tileSeparateRoutine separate; + } put; + TIFFRGBValue* Map; /* sample mapping array */ + uint32_t** BWmap; /* black&white map */ + uint32_t** PALmap; /* palette image map */ + TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */ + TIFFCIELabToRGB* cielab; /* CIE L*a*b conversion state */ + + uint8_t* UaToAa; /* Unassociated alpha to associated alpha conversion LUT */ + uint8_t* Bitdepth16To8; /* LUT for conversion from 16bit to 8bit values */ + + int row_offset; + int col_offset; +}; + +/* + * Macros for extracting components from the + * packed ABGR form returned by TIFFReadRGBAImage. + */ +#define TIFFGetR(abgr) ((abgr) & 0xff) +#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff) +#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff) +#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff) + +/* + * A CODEC is a software package that implements decoding, + * encoding, or decoding+encoding of a compression algorithm. + * The library provides a collection of builtin codecs. + * More codecs may be registered through calls to the library + * and/or the builtin implementations may be overridden. + */ +typedef int (*TIFFInitMethod)(TIFF*, int); +typedef struct { + char* name; + uint16_t scheme; + TIFFInitMethod init; +} TIFFCodec; + +#include +#include + +/* share internal LogLuv conversion routines? */ +#ifndef LOGLUV_PUBLIC +#define LOGLUV_PUBLIC 1 +#endif + +#if defined(__GNUC__) || defined(__attribute__) +# define TIFF_ATTRIBUTE(x) __attribute__(x) +#else +# define TIFF_ATTRIBUTE(x) /*nothing*/ +#endif + +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif +typedef void (*TIFFErrorHandler)(const char*, const char*, va_list); +typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list); +typedef tmsize_t (*TIFFReadWriteProc)(thandle_t, void*, tmsize_t); +typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int); +typedef int (*TIFFCloseProc)(thandle_t); +typedef toff_t (*TIFFSizeProc)(thandle_t); +typedef int (*TIFFMapFileProc)(thandle_t, void** base, toff_t* size); +typedef void (*TIFFUnmapFileProc)(thandle_t, void* base, toff_t size); +typedef void (*TIFFExtendProc)(TIFF*); + +extern const char* TIFFGetVersion(void); + +extern const TIFFCodec* TIFFFindCODEC(uint16_t); +extern TIFFCodec* TIFFRegisterCODEC(uint16_t, const char*, TIFFInitMethod); +extern void TIFFUnRegisterCODEC(TIFFCodec*); +extern int TIFFIsCODECConfigured(uint16_t); +extern TIFFCodec* TIFFGetConfiguredCODECs(void); + +/* + * Auxiliary functions. + */ + +extern void* _TIFFmalloc(tmsize_t s); +extern void* _TIFFcalloc(tmsize_t nmemb, tmsize_t siz); +extern void* _TIFFrealloc(void* p, tmsize_t s); +extern void _TIFFmemset(void* p, int v, tmsize_t c); +extern void _TIFFmemcpy(void* d, const void* s, tmsize_t c); +extern int _TIFFmemcmp(const void* p1, const void* p2, tmsize_t c); +extern void _TIFFfree(void* p); + +/* +** Stuff, related to tag handling and creating custom tags. +*/ +extern int TIFFGetTagListCount( TIFF * ); +extern uint32_t TIFFGetTagListEntry(TIFF *, int tag_index ); + +#define TIFF_ANY TIFF_NOTYPE /* for field descriptor searching */ +#define TIFF_VARIABLE -1 /* marker for variable length tags */ +#define TIFF_SPP -2 /* marker for SamplesPerPixel tags */ +#define TIFF_VARIABLE2 -3 /* marker for uint32_t var-length tags */ + +#define FIELD_CUSTOM 65 + +typedef struct _TIFFField TIFFField; +typedef struct _TIFFFieldArray TIFFFieldArray; + +extern const TIFFField* TIFFFindField(TIFF *, uint32_t, TIFFDataType); +extern const TIFFField* TIFFFieldWithTag(TIFF*, uint32_t); +extern const TIFFField* TIFFFieldWithName(TIFF*, const char *); + +extern uint32_t TIFFFieldTag(const TIFFField*); +extern const char* TIFFFieldName(const TIFFField*); +extern TIFFDataType TIFFFieldDataType(const TIFFField*); +extern int TIFFFieldPassCount(const TIFFField*); +extern int TIFFFieldReadCount(const TIFFField*); +extern int TIFFFieldWriteCount(const TIFFField*); + +typedef int (*TIFFVSetMethod)(TIFF*, uint32_t, va_list); +typedef int (*TIFFVGetMethod)(TIFF*, uint32_t, va_list); +typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long); + +typedef struct { + TIFFVSetMethod vsetfield; /* tag set routine */ + TIFFVGetMethod vgetfield; /* tag get routine */ + TIFFPrintMethod printdir; /* directory print routine */ +} TIFFTagMethods; + +extern TIFFTagMethods *TIFFAccessTagMethods(TIFF *); +extern void *TIFFGetClientInfo(TIFF *, const char *); +extern void TIFFSetClientInfo(TIFF *, void *, const char *); + +extern void TIFFCleanup(TIFF* tif); +extern void TIFFClose(TIFF* tif); +extern int TIFFFlush(TIFF* tif); +extern int TIFFFlushData(TIFF* tif); +extern int WINAPIV TIFFGetField(TIFF* tif, uint32_t tag, ...); +extern int TIFFVGetField(TIFF* tif, uint32_t tag, va_list ap); +extern int WINAPIV TIFFGetFieldDefaulted(TIFF* tif, uint32_t tag, ...); +extern int TIFFVGetFieldDefaulted(TIFF* tif, uint32_t tag, va_list ap); +extern int TIFFReadDirectory(TIFF* tif); +extern int TIFFReadCustomDirectory(TIFF* tif, toff_t diroff, const TIFFFieldArray* infoarray); +extern int TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff); +extern int TIFFReadGPSDirectory(TIFF* tif, toff_t diroff); +extern uint64_t TIFFScanlineSize64(TIFF* tif); +extern tmsize_t TIFFScanlineSize(TIFF* tif); +extern uint64_t TIFFRasterScanlineSize64(TIFF* tif); +extern tmsize_t TIFFRasterScanlineSize(TIFF* tif); +extern uint64_t TIFFStripSize64(TIFF* tif); +extern tmsize_t TIFFStripSize(TIFF* tif); +extern uint64_t TIFFRawStripSize64(TIFF* tif, uint32_t strip); +extern tmsize_t TIFFRawStripSize(TIFF* tif, uint32_t strip); +extern uint64_t TIFFVStripSize64(TIFF* tif, uint32_t nrows); +extern tmsize_t TIFFVStripSize(TIFF* tif, uint32_t nrows); +extern uint64_t TIFFTileRowSize64(TIFF* tif); +extern tmsize_t TIFFTileRowSize(TIFF* tif); +extern uint64_t TIFFTileSize64(TIFF* tif); +extern tmsize_t TIFFTileSize(TIFF* tif); +extern uint64_t TIFFVTileSize64(TIFF* tif, uint32_t nrows); +extern tmsize_t TIFFVTileSize(TIFF* tif, uint32_t nrows); +extern uint32_t TIFFDefaultStripSize(TIFF* tif, uint32_t request); +extern void TIFFDefaultTileSize(TIFF*, uint32_t*, uint32_t*); +extern int TIFFFileno(TIFF*); +extern int TIFFSetFileno(TIFF*, int); +extern thandle_t TIFFClientdata(TIFF*); +extern thandle_t TIFFSetClientdata(TIFF*, thandle_t); +extern int TIFFGetMode(TIFF*); +extern int TIFFSetMode(TIFF*, int); +extern int TIFFIsTiled(TIFF*); +extern int TIFFIsByteSwapped(TIFF*); +extern int TIFFIsUpSampled(TIFF*); +extern int TIFFIsMSB2LSB(TIFF*); +extern int TIFFIsBigEndian(TIFF*); +extern TIFFReadWriteProc TIFFGetReadProc(TIFF*); +extern TIFFReadWriteProc TIFFGetWriteProc(TIFF*); +extern TIFFSeekProc TIFFGetSeekProc(TIFF*); +extern TIFFCloseProc TIFFGetCloseProc(TIFF*); +extern TIFFSizeProc TIFFGetSizeProc(TIFF*); +extern TIFFMapFileProc TIFFGetMapFileProc(TIFF*); +extern TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF*); +extern uint32_t TIFFCurrentRow(TIFF*); +extern uint16_t TIFFCurrentDirectory(TIFF*); +extern uint16_t TIFFNumberOfDirectories(TIFF*); +extern uint64_t TIFFCurrentDirOffset(TIFF*); +extern uint32_t TIFFCurrentStrip(TIFF*); +extern uint32_t TIFFCurrentTile(TIFF* tif); +extern int TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size); +extern int TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size); +extern int TIFFSetupStrips(TIFF *); +extern int TIFFWriteCheck(TIFF*, int, const char *); +extern void TIFFFreeDirectory(TIFF*); +extern int TIFFCreateDirectory(TIFF*); +extern int TIFFCreateCustomDirectory(TIFF*,const TIFFFieldArray*); +extern int TIFFCreateEXIFDirectory(TIFF*); +extern int TIFFCreateGPSDirectory(TIFF*); +extern int TIFFLastDirectory(TIFF*); +extern int TIFFSetDirectory(TIFF*, uint16_t); +extern int TIFFSetSubDirectory(TIFF*, uint64_t); +extern int TIFFUnlinkDirectory(TIFF*, uint16_t); +extern int WINAPIV TIFFSetField(TIFF*, uint32_t, ...); +extern int TIFFVSetField(TIFF*, uint32_t, va_list); +extern int TIFFUnsetField(TIFF*, uint32_t); +extern int TIFFWriteDirectory(TIFF *); +extern int TIFFWriteCustomDirectory(TIFF *, uint64_t *); +extern int TIFFCheckpointDirectory(TIFF *); +extern int TIFFRewriteDirectory(TIFF *); +extern int TIFFDeferStrileArrayWriting(TIFF *); +extern int TIFFForceStrileArrayWriting(TIFF* ); + +#if defined(c_plusplus) || defined(__cplusplus) +extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0); +extern int TIFFReadScanline(TIFF* tif, void* buf, uint32_t row, uint16_t sample = 0); +extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32_t row, uint16_t sample = 0); +extern int TIFFReadRGBAImage(TIFF*, uint32_t, uint32_t, uint32_t*, int = 0); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32_t, uint32_t, uint32_t*, + int = ORIENTATION_BOTLEFT, int = 0); +#else +extern void TIFFPrintDirectory(TIFF*, FILE*, long); +extern int TIFFReadScanline(TIFF* tif, void* buf, uint32_t row, uint16_t sample); +extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32_t row, uint16_t sample); +extern int TIFFReadRGBAImage(TIFF*, uint32_t, uint32_t, uint32_t*, int); +extern int TIFFReadRGBAImageOriented(TIFF*, uint32_t, uint32_t, uint32_t*, int, int); +#endif + +extern int TIFFReadRGBAStrip(TIFF*, uint32_t, uint32_t * ); +extern int TIFFReadRGBATile(TIFF*, uint32_t, uint32_t, uint32_t * ); +extern int TIFFReadRGBAStripExt(TIFF*, uint32_t, uint32_t *, int stop_on_error ); +extern int TIFFReadRGBATileExt(TIFF*, uint32_t, uint32_t, uint32_t *, int stop_on_error ); +extern int TIFFRGBAImageOK(TIFF*, char [1024]); +extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]); +extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32_t*, uint32_t, uint32_t); +extern void TIFFRGBAImageEnd(TIFFRGBAImage*); +extern TIFF* TIFFOpen(const char*, const char*); +# ifdef __WIN32__ +extern TIFF* TIFFOpenW(const wchar_t*, const char*); +# endif /* __WIN32__ */ +extern TIFF* TIFFFdOpen(int, const char*, const char*); +extern TIFF* TIFFClientOpen(const char*, const char*, + thandle_t, + TIFFReadWriteProc, TIFFReadWriteProc, + TIFFSeekProc, TIFFCloseProc, + TIFFSizeProc, + TIFFMapFileProc, TIFFUnmapFileProc); +extern const char* TIFFFileName(TIFF*); +extern const char* TIFFSetFileName(TIFF*, const char *); +extern void WINAPIV TIFFError(const char*, const char*, ...) TIFF_ATTRIBUTE((__format__ (__printf__,2,3))); +extern void WINAPIV TIFFErrorExt(thandle_t, const char*, const char*, ...) TIFF_ATTRIBUTE((__format__ (__printf__,3,4))); +extern void WINAPIV TIFFWarning(const char*, const char*, ...) TIFF_ATTRIBUTE((__format__ (__printf__,2,3))); +extern void WINAPIV TIFFWarningExt(thandle_t, const char*, const char*, ...) TIFF_ATTRIBUTE((__format__ (__printf__,3,4))); +extern TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetErrorHandlerExt(TIFFErrorHandlerExt); +extern TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler); +extern TIFFErrorHandlerExt TIFFSetWarningHandlerExt(TIFFErrorHandlerExt); +extern TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc); +extern uint32_t TIFFComputeTile(TIFF* tif, uint32_t x, uint32_t y, uint32_t z, uint16_t s); +extern int TIFFCheckTile(TIFF* tif, uint32_t x, uint32_t y, uint32_t z, uint16_t s); +extern uint32_t TIFFNumberOfTiles(TIFF*); +extern tmsize_t TIFFReadTile(TIFF* tif, void* buf, uint32_t x, uint32_t y, uint32_t z, uint16_t s); +extern tmsize_t TIFFWriteTile(TIFF* tif, void* buf, uint32_t x, uint32_t y, uint32_t z, uint16_t s); +extern uint32_t TIFFComputeStrip(TIFF*, uint32_t, uint16_t); +extern uint32_t TIFFNumberOfStrips(TIFF*); +extern tmsize_t TIFFReadEncodedStrip(TIFF* tif, uint32_t strip, void* buf, tmsize_t size); +extern tmsize_t TIFFReadRawStrip(TIFF* tif, uint32_t strip, void* buf, tmsize_t size); +extern tmsize_t TIFFReadEncodedTile(TIFF* tif, uint32_t tile, void* buf, tmsize_t size); +extern tmsize_t TIFFReadRawTile(TIFF* tif, uint32_t tile, void* buf, tmsize_t size); +extern int TIFFReadFromUserBuffer(TIFF* tif, uint32_t strile, + void* inbuf, tmsize_t insize, + void* outbuf, tmsize_t outsize); +extern tmsize_t TIFFWriteEncodedStrip(TIFF* tif, uint32_t strip, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteRawStrip(TIFF* tif, uint32_t strip, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteEncodedTile(TIFF* tif, uint32_t tile, void* data, tmsize_t cc); +extern tmsize_t TIFFWriteRawTile(TIFF* tif, uint32_t tile, void* data, tmsize_t cc); +extern int TIFFDataWidth(TIFFDataType); /* table of tag datatype widths */ +extern void TIFFSetWriteOffset(TIFF* tif, toff_t off); +extern void TIFFSwabShort(uint16_t*); +extern void TIFFSwabLong(uint32_t*); +extern void TIFFSwabLong8(uint64_t*); +extern void TIFFSwabFloat(float*); +extern void TIFFSwabDouble(double*); +extern void TIFFSwabArrayOfShort(uint16_t* wp, tmsize_t n); +extern void TIFFSwabArrayOfTriples(uint8_t* tp, tmsize_t n); +extern void TIFFSwabArrayOfLong(uint32_t* lp, tmsize_t n); +extern void TIFFSwabArrayOfLong8(uint64_t* lp, tmsize_t n); +extern void TIFFSwabArrayOfFloat(float* fp, tmsize_t n); +extern void TIFFSwabArrayOfDouble(double* dp, tmsize_t n); +extern void TIFFReverseBits(uint8_t* cp, tmsize_t n); +extern const unsigned char* TIFFGetBitRevTable(int); + +extern uint64_t TIFFGetStrileOffset(TIFF *tif, uint32_t strile); +extern uint64_t TIFFGetStrileByteCount(TIFF *tif, uint32_t strile); +extern uint64_t TIFFGetStrileOffsetWithErr(TIFF *tif, uint32_t strile, int *pbErr); +extern uint64_t TIFFGetStrileByteCountWithErr(TIFF *tif, uint32_t strile, int *pbErr); + +#ifdef LOGLUV_PUBLIC +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. +extern double LogL16toY(int); +extern double LogL10toY(int); +extern void XYZtoRGB24(float*, uint8_t*); +extern int uv_decode(double*, double*, int); +extern void LogLuv24toXYZ(uint32_t, float*); +extern void LogLuv32toXYZ(uint32_t, float*); +#if defined(c_plusplus) || defined(__cplusplus) +extern int LogL16fromY(double, int = SGILOGENCODE_NODITHER); +extern int LogL10fromY(double, int = SGILOGENCODE_NODITHER); +extern int uv_encode(double, double, int = SGILOGENCODE_NODITHER); +extern uint32_t LogLuv24fromXYZ(float*, int = SGILOGENCODE_NODITHER); +extern uint32_t LogLuv32fromXYZ(float*, int = SGILOGENCODE_NODITHER); +#else +extern int LogL16fromY(double, int); +extern int LogL10fromY(double, int); +extern int uv_encode(double, double, int); +extern uint32_t LogLuv24fromXYZ(float*, int); +extern uint32_t LogLuv32fromXYZ(float*, int); +#endif +#endif /* LOGLUV_PUBLIC */ + +extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, const TIFFDisplay *, float*); +extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32_t, int32_t, int32_t, + float *, float *, float *); +extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float, + uint32_t *, uint32_t *, uint32_t *); + +extern int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float*, float*); +extern void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *, uint32_t, int32_t, int32_t, + uint32_t *, uint32_t *, uint32_t *); + +/**************************************************************************** + * O B S O L E T E D I N T E R F A C E S + * + * Don't use this stuff in your applications, it may be removed in the future + * libtiff versions. + ****************************************************************************/ +typedef struct { + ttag_t field_tag; /* field's tag */ + short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ + short field_writecount; /* write count/TIFF_VARIABLE */ + TIFFDataType field_type; /* type of associated data */ + unsigned short field_bit; /* bit in fieldsset bit vector */ + unsigned char field_oktochange; /* if true, can change while writing */ + unsigned char field_passcount; /* if true, pass dir count on set */ + char *field_name; /* ASCII name */ +} TIFFFieldInfo; + +extern int TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], uint32_t); + +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif + +#endif /* _TIFFIO_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tiffiop.h b/libs/tiff/libtiff/tiffiop.h new file mode 100644 index 00000000000..f1151f513a6 --- /dev/null +++ b/libs/tiff/libtiff/tiffiop.h @@ -0,0 +1,448 @@ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIOP_ +#define _TIFFIOP_ +/* + * ``Library-private'' definitions. + */ + +#include "tif_config.h" + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#include + +#ifdef HAVE_ASSERT_H +# include +#else +# define assert(x) +#endif + +#include "tiffio.h" + +#include "tif_dir.h" + +#ifndef STRIP_SIZE_DEFAULT +# define STRIP_SIZE_DEFAULT 8192 +#endif + +#define streq(a,b) (strcmp(a,b) == 0) +#define strneq(a,b,n) (strncmp(a,b,n) == 0) + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +typedef struct client_info { + struct client_info *next; + void *data; + char *name; +} TIFFClientInfoLink; + +/* + * Typedefs for ``method pointers'' used internally. + * these are deprecated and provided only for backwards compatibility. + */ +typedef unsigned char tidataval_t; /* internal image data value type */ +typedef tidataval_t* tidata_t; /* reference to internal image data */ + +typedef void (*TIFFVoidMethod)(TIFF*); +typedef int (*TIFFBoolMethod)(TIFF*); +typedef int (*TIFFPreMethod)(TIFF*, uint16_t); +typedef int (*TIFFCodeMethod)(TIFF* tif, uint8_t* buf, tmsize_t size, uint16_t sample); +typedef int (*TIFFSeekMethod)(TIFF*, uint32_t); +typedef void (*TIFFPostMethod)(TIFF* tif, uint8_t* buf, tmsize_t size); +typedef uint32_t (*TIFFStripMethod)(TIFF*, uint32_t); +typedef void (*TIFFTileMethod)(TIFF*, uint32_t*, uint32_t*); + +struct tiff { + char* tif_name; /* name of open file */ + int tif_fd; /* open file descriptor */ + int tif_mode; /* open mode (O_*) */ + uint32_t tif_flags; + #define TIFF_FILLORDER 0x00003U /* natural bit fill order for machine */ + #define TIFF_DIRTYHEADER 0x00004U /* header must be written on close */ + #define TIFF_DIRTYDIRECT 0x00008U /* current directory must be written */ + #define TIFF_BUFFERSETUP 0x00010U /* data buffers setup */ + #define TIFF_CODERSETUP 0x00020U /* encoder/decoder setup done */ + #define TIFF_BEENWRITING 0x00040U /* written 1+ scanlines to file */ + #define TIFF_SWAB 0x00080U /* byte swap file information */ + #define TIFF_NOBITREV 0x00100U /* inhibit bit reversal logic */ + #define TIFF_MYBUFFER 0x00200U /* my raw data buffer; free on close */ + #define TIFF_ISTILED 0x00400U /* file is tile, not strip- based */ + #define TIFF_MAPPED 0x00800U /* file is mapped into memory */ + #define TIFF_POSTENCODE 0x01000U /* need call to postencode routine */ + #define TIFF_INSUBIFD 0x02000U /* currently writing a subifd */ + #define TIFF_UPSAMPLED 0x04000U /* library is doing data up-sampling */ + #define TIFF_STRIPCHOP 0x08000U /* enable strip chopping support */ + #define TIFF_HEADERONLY 0x10000U /* read header only, do not process the first directory */ + #define TIFF_NOREADRAW 0x20000U /* skip reading of raw uncompressed image data */ + #define TIFF_INCUSTOMIFD 0x40000U /* currently writing a custom IFD */ + #define TIFF_BIGTIFF 0x80000U /* read/write bigtiff */ + #define TIFF_BUF4WRITE 0x100000U /* rawcc bytes are for writing */ + #define TIFF_DIRTYSTRIP 0x200000U /* stripoffsets/stripbytecount dirty*/ + #define TIFF_PERSAMPLE 0x400000U /* get/set per sample tags as arrays */ + #define TIFF_BUFFERMMAP 0x800000U /* read buffer (tif_rawdata) points into mmap() memory */ + #define TIFF_DEFERSTRILELOAD 0x1000000U /* defer strip/tile offset/bytecount array loading. */ + #define TIFF_LAZYSTRILELOAD 0x2000000U /* lazy/ondemand loading of strip/tile offset/bytecount values. Only used if TIFF_DEFERSTRILELOAD is set and in read-only mode */ + #define TIFF_CHOPPEDUPARRAYS 0x4000000U /* set when allocChoppedUpStripArrays() has modified strip array */ + uint64_t tif_diroff; /* file offset of current directory */ + uint64_t tif_nextdiroff; /* file offset of following directory */ + uint64_t* tif_dirlist; /* list of offsets to already seen directories to prevent IFD looping */ + uint16_t tif_dirlistsize; /* number of entries in offset list */ + uint16_t tif_dirnumber; /* number of already seen directories */ + TIFFDirectory tif_dir; /* internal rep of current directory */ + TIFFDirectory tif_customdir; /* custom IFDs are separated from the main ones */ + union { + TIFFHeaderCommon common; + TIFFHeaderClassic classic; + TIFFHeaderBig big; + } tif_header; + uint16_t tif_header_size; /* file's header block and its length */ + uint32_t tif_row; /* current scanline */ + uint16_t tif_curdir; /* current directory (index) */ + uint32_t tif_curstrip; /* current strip for read/write */ + uint64_t tif_curoff; /* current offset for read/write */ + uint64_t tif_dataoff; /* current offset for writing dir */ + /* SubIFD support */ + uint16_t tif_nsubifd; /* remaining subifds to write */ + uint64_t tif_subifdoff; /* offset for patching SubIFD link */ + /* tiling support */ + uint32_t tif_col; /* current column (offset by row too) */ + uint32_t tif_curtile; /* current tile for read/write */ + tmsize_t tif_tilesize; /* # of bytes in a tile */ + /* compression scheme hooks */ + int tif_decodestatus; + TIFFBoolMethod tif_fixuptags; /* called in TIFFReadDirectory */ + TIFFBoolMethod tif_setupdecode; /* called once before predecode */ + TIFFPreMethod tif_predecode; /* pre- row/strip/tile decoding */ + TIFFBoolMethod tif_setupencode; /* called once before preencode */ + int tif_encodestatus; + TIFFPreMethod tif_preencode; /* pre- row/strip/tile encoding */ + TIFFBoolMethod tif_postencode; /* post- row/strip/tile encoding */ + TIFFCodeMethod tif_decoderow; /* scanline decoding routine */ + TIFFCodeMethod tif_encoderow; /* scanline encoding routine */ + TIFFCodeMethod tif_decodestrip; /* strip decoding routine */ + TIFFCodeMethod tif_encodestrip; /* strip encoding routine */ + TIFFCodeMethod tif_decodetile; /* tile decoding routine */ + TIFFCodeMethod tif_encodetile; /* tile encoding routine */ + TIFFVoidMethod tif_close; /* cleanup-on-close routine */ + TIFFSeekMethod tif_seek; /* position within a strip routine */ + TIFFVoidMethod tif_cleanup; /* cleanup state routine */ + TIFFStripMethod tif_defstripsize; /* calculate/constrain strip size */ + TIFFTileMethod tif_deftilesize; /* calculate/constrain tile size */ + uint8_t* tif_data; /* compression scheme private data */ + /* input/output buffering */ + tmsize_t tif_scanlinesize; /* # of bytes in a scanline */ + tmsize_t tif_scanlineskew; /* scanline skew for reading strips */ + uint8_t* tif_rawdata; /* raw data buffer */ + tmsize_t tif_rawdatasize; /* # of bytes in raw data buffer */ + tmsize_t tif_rawdataoff; /* rawdata offset within strip */ + tmsize_t tif_rawdataloaded;/* amount of data in rawdata */ + uint8_t* tif_rawcp; /* current spot in raw buffer */ + tmsize_t tif_rawcc; /* bytes unread from raw buffer */ + /* memory-mapped file support */ + uint8_t* tif_base; /* base of mapped file */ + tmsize_t tif_size; /* size of mapped file region (bytes, thus tmsize_t) */ + TIFFMapFileProc tif_mapproc; /* map file method */ + TIFFUnmapFileProc tif_unmapproc; /* unmap file method */ + /* input/output callback methods */ + thandle_t tif_clientdata; /* callback parameter */ + TIFFReadWriteProc tif_readproc; /* read method */ + TIFFReadWriteProc tif_writeproc; /* write method */ + TIFFSeekProc tif_seekproc; /* lseek method */ + TIFFCloseProc tif_closeproc; /* close method */ + TIFFSizeProc tif_sizeproc; /* filesize method */ + /* post-decoding support */ + TIFFPostMethod tif_postdecode; /* post decoding routine */ + /* tag support */ + TIFFField** tif_fields; /* sorted table of registered tags */ + size_t tif_nfields; /* # entries in registered tag table */ + const TIFFField* tif_foundfield; /* cached pointer to already found tag */ + TIFFTagMethods tif_tagmethods; /* tag get/set/print routines */ + TIFFClientInfoLink* tif_clientinfo; /* extra client information. */ + /* Backward compatibility stuff. We need these two fields for + * setting up an old tag extension scheme. */ + TIFFFieldArray* tif_fieldscompat; + size_t tif_nfieldscompat; +}; + +#define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */ + +#define isTiled(tif) (((tif)->tif_flags & TIFF_ISTILED) != 0) +#define isMapped(tif) (((tif)->tif_flags & TIFF_MAPPED) != 0) +#define isFillOrder(tif, o) (((tif)->tif_flags & (o)) != 0) +#define isUpSampled(tif) (((tif)->tif_flags & TIFF_UPSAMPLED) != 0) +#define TIFFReadFile(tif, buf, size) \ + ((*(tif)->tif_readproc)((tif)->tif_clientdata,(buf),(size))) +#define TIFFWriteFile(tif, buf, size) \ + ((*(tif)->tif_writeproc)((tif)->tif_clientdata,(buf),(size))) +#define TIFFSeekFile(tif, off, whence) \ + ((*(tif)->tif_seekproc)((tif)->tif_clientdata,(off),(whence))) +#define TIFFCloseFile(tif) \ + ((*(tif)->tif_closeproc)((tif)->tif_clientdata)) +#define TIFFGetFileSize(tif) \ + ((*(tif)->tif_sizeproc)((tif)->tif_clientdata)) +#define TIFFMapFileContents(tif, paddr, psize) \ + ((*(tif)->tif_mapproc)((tif)->tif_clientdata,(paddr),(psize))) +#define TIFFUnmapFileContents(tif, addr, size) \ + ((*(tif)->tif_unmapproc)((tif)->tif_clientdata,(addr),(size))) + +/* + * Default Read/Seek/Write definitions. + */ +#ifndef ReadOK +#define ReadOK(tif, buf, size) \ + (TIFFReadFile((tif),(buf),(size))==(size)) +#endif +#ifndef SeekOK +#define SeekOK(tif, off) _TIFFSeekOK(tif, off) +#endif +#ifndef WriteOK +#define WriteOK(tif, buf, size) \ + (TIFFWriteFile((tif),(buf),(size))==(size)) +#endif + +/* NB: the uint32_t casts are to silence certain ANSI-C compilers */ +#define TIFFhowmany_32(x, y) (((uint32_t)x < (0xffffffff - (uint32_t)(y-1))) ? \ + ((((uint32_t)(x))+(((uint32_t)(y))-1))/((uint32_t)(y))) : \ + 0U) +/* Variant of TIFFhowmany_32() that doesn't return 0 if x close to MAXUINT. */ +/* Caution: TIFFhowmany_32_maxuint_compat(x,y)*y might overflow */ +#define TIFFhowmany_32_maxuint_compat(x, y) \ + (((uint32_t)(x) / (uint32_t)(y)) + ((((uint32_t)(x) % (uint32_t)(y)) != 0) ? 1 : 0)) +#define TIFFhowmany8_32(x) (((x)&0x07)?((uint32_t)(x)>>3)+1:(uint32_t)(x)>>3) +#define TIFFroundup_32(x, y) (TIFFhowmany_32(x,y)*(y)) +#define TIFFhowmany_64(x, y) ((((uint64_t)(x))+(((uint64_t)(y))-1))/((uint64_t)(y))) +#define TIFFhowmany8_64(x) (((x)&0x07)?((uint64_t)(x)>>3)+1:(uint64_t)(x)>>3) +#define TIFFroundup_64(x, y) (TIFFhowmany_64(x,y)*(y)) + +/* Safe multiply which returns zero if there is an *unsigned* integer overflow. This macro is not safe for *signed* integer types */ +#define TIFFSafeMultiply(t,v,m) ((((t)(m) != (t)0) && (((t)(((v)*(m))/(m))) == (t)(v))) ? (t)((v)*(m)) : (t)0) + +#define TIFFmax(A,B) ((A)>(B)?(A):(B)) +#define TIFFmin(A,B) ((A)<(B)?(A):(B)) + +#define TIFFArrayCount(a) (sizeof (a) / sizeof ((a)[0])) + +/* + Support for large files. + + Windows read/write APIs support only 'unsigned int' rather than 'size_t'. + Windows off_t is only 32-bit, even in 64-bit builds. +*/ +#if defined(HAVE_FSEEKO) +/* + Use fseeko() and ftello() if they are available since they use + 'off_t' rather than 'long'. It is wrong to use fseeko() and + ftello() only on systems with special LFS support since some systems + (e.g. FreeBSD) support a 64-bit off_t by default. + + For MinGW, __MSVCRT_VERSION__ must be at least 0x800 to expose these + interfaces. The MinGW compiler must support the requested version. MinGW + does not distribute the CRT (it is supplied by Microsoft) so the correct CRT + must be available on the target computer in order for the program to run. +*/ +#if defined(HAVE_FSEEKO) +# define fseek(stream,offset,whence) fseeko(stream,offset,whence) +# define ftell(stream,offset,whence) ftello(stream,offset,whence) +#endif +#endif +#if defined(__WIN32__) && \ + !(defined(_MSC_VER) && _MSC_VER < 1400) && \ + !(defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x800) +typedef unsigned int TIFFIOSize_t; +#define _TIFF_lseek_f(fildes,offset,whence) _lseeki64(fildes,/* __int64 */ offset,whence) +/* #define _TIFF_tell_f(fildes) /\* __int64 *\/ _telli64(fildes) */ +#define _TIFF_fseek_f(stream,offset,whence) _fseeki64(stream,/* __int64 */ offset,whence) +#define _TIFF_fstat_f(fildes,stat_buff) _fstati64(fildes,/* struct _stati64 */ stat_buff) +/* #define _TIFF_ftell_f(stream) /\* __int64 *\/ _ftelli64(stream) */ +/* #define _TIFF_stat_f(path,stat_buff) _stati64(path,/\* struct _stati64 *\/ stat_buff) */ +#define _TIFF_stat_s struct _stati64 +#define _TIFF_off_t __int64 +#else +typedef size_t TIFFIOSize_t; +#define _TIFF_lseek_f(fildes,offset,whence) lseek(fildes,offset,whence) +/* #define _TIFF_tell_f(fildes) (_TIFF_lseek_f(fildes,0,SEEK_CUR)) */ +#define _TIFF_fseek_f(stream,offset,whence) fseek(stream,offset,whence) +#define _TIFF_fstat_f(fildes,stat_buff) fstat(fildes,stat_buff) +/* #define _TIFF_ftell_f(stream) ftell(stream) */ +/* #define _TIFF_stat_f(path,stat_buff) stat(path,stat_buff) */ +#define _TIFF_stat_s struct stat +#define _TIFF_off_t off_t +#endif + +#if defined(__has_attribute) && defined(__clang__) +#if __has_attribute(no_sanitize) +#define TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow"))) +#else +#define TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +#endif +#else +#define TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +#endif + + +#if defined(__cplusplus) +extern "C" { +#endif +extern int _TIFFgetMode(const char* mode, const char* module); +extern int _TIFFNoRowEncode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s); +extern int _TIFFNoStripEncode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s); +extern int _TIFFNoTileEncode(TIFF*, uint8_t* pp, tmsize_t cc, uint16_t s); +extern int _TIFFNoRowDecode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s); +extern int _TIFFNoStripDecode(TIFF* tif, uint8_t* pp, tmsize_t cc, uint16_t s); +extern int _TIFFNoTileDecode(TIFF*, uint8_t* pp, tmsize_t cc, uint16_t s); +extern void _TIFFNoPostDecode(TIFF* tif, uint8_t* buf, tmsize_t cc); +extern int _TIFFNoPreCode(TIFF* tif, uint16_t s); +extern int _TIFFNoSeek(TIFF* tif, uint32_t off); +extern void _TIFFSwab16BitData(TIFF* tif, uint8_t* buf, tmsize_t cc); +extern void _TIFFSwab24BitData(TIFF* tif, uint8_t* buf, tmsize_t cc); +extern void _TIFFSwab32BitData(TIFF* tif, uint8_t* buf, tmsize_t cc); +extern void _TIFFSwab64BitData(TIFF* tif, uint8_t* buf, tmsize_t cc); +extern int TIFFFlushData1(TIFF* tif); +extern int TIFFDefaultDirectory(TIFF* tif); +extern void _TIFFSetDefaultCompressionState(TIFF* tif); +extern int _TIFFRewriteField(TIFF *, uint16_t, TIFFDataType, tmsize_t, void *); +extern int TIFFSetCompressionScheme(TIFF* tif, int scheme); +extern int TIFFSetDefaultCompressionState(TIFF* tif); +extern uint32_t _TIFFDefaultStripSize(TIFF* tif, uint32_t s); +extern void _TIFFDefaultTileSize(TIFF* tif, uint32_t* tw, uint32_t* th); +extern int _TIFFDataSize(TIFFDataType type); + +/*--: Rational2Double: Return size of TIFFSetGetFieldType in bytes. */ +extern int _TIFFSetGetFieldSize(TIFFSetGetFieldType setgettype); + +extern void _TIFFsetByteArray(void**, void*, uint32_t); +extern void _TIFFsetString(char**, char*); +extern void _TIFFsetShortArray(uint16_t**, uint16_t*, uint32_t); +extern void _TIFFsetLongArray(uint32_t**, uint32_t*, uint32_t); +extern void _TIFFsetFloatArray(float**, float*, uint32_t); +extern void _TIFFsetDoubleArray(double**, double*, uint32_t); + +extern void _TIFFprintAscii(FILE*, const char*); +extern void _TIFFprintAsciiTag(FILE*, const char*, const char*); + +extern TIFFErrorHandler _TIFFwarningHandler; +extern TIFFErrorHandler _TIFFerrorHandler; +extern TIFFErrorHandlerExt _TIFFwarningHandlerExt; +extern TIFFErrorHandlerExt _TIFFerrorHandlerExt; + +extern uint32_t _TIFFMultiply32(TIFF*, uint32_t, uint32_t, const char*); +extern uint64_t _TIFFMultiply64(TIFF*, uint64_t, uint64_t, const char*); +extern tmsize_t _TIFFMultiplySSize(TIFF*, tmsize_t, tmsize_t, const char*); +extern tmsize_t _TIFFCastUInt64ToSSize(TIFF*, uint64_t, const char*); +extern void* _TIFFCheckMalloc(TIFF*, tmsize_t, tmsize_t, const char*); +extern void* _TIFFCheckRealloc(TIFF*, void*, tmsize_t, tmsize_t, const char*); + +extern double _TIFFUInt64ToDouble(uint64_t); +extern float _TIFFUInt64ToFloat(uint64_t); + +extern float _TIFFClampDoubleToFloat(double); + +extern tmsize_t +_TIFFReadEncodedStripAndAllocBuffer(TIFF* tif, uint32_t strip, + void **buf, tmsize_t bufsizetoalloc, + tmsize_t size_to_read); +extern tmsize_t +_TIFFReadEncodedTileAndAllocBuffer(TIFF* tif, uint32_t tile, + void **buf, tmsize_t bufsizetoalloc, + tmsize_t size_to_read); +extern tmsize_t +_TIFFReadTileAndAllocBuffer(TIFF* tif, + void **buf, tmsize_t bufsizetoalloc, + uint32_t x, uint32_t y, uint32_t z, uint16_t s); +extern int _TIFFSeekOK(TIFF* tif, toff_t off); + +extern int TIFFInitDumpMode(TIFF*, int); +#ifdef PACKBITS_SUPPORT +extern int TIFFInitPackBits(TIFF*, int); +#endif +#ifdef CCITT_SUPPORT +extern int TIFFInitCCITTRLE(TIFF*, int), TIFFInitCCITTRLEW(TIFF*, int); +extern int TIFFInitCCITTFax3(TIFF*, int), TIFFInitCCITTFax4(TIFF*, int); +#endif +#ifdef THUNDER_SUPPORT +extern int TIFFInitThunderScan(TIFF*, int); +#endif +#ifdef NEXT_SUPPORT +extern int TIFFInitNeXT(TIFF*, int); +#endif +#ifdef LZW_SUPPORT +extern int TIFFInitLZW(TIFF*, int); +#endif +#ifdef OJPEG_SUPPORT +extern int TIFFInitOJPEG(TIFF*, int); +#endif +#ifdef JPEG_SUPPORT +extern int TIFFInitJPEG(TIFF*, int); +extern int TIFFJPEGIsFullStripRequired(TIFF*); +#endif +#ifdef JBIG_SUPPORT +extern int TIFFInitJBIG(TIFF*, int); +#endif +#ifdef ZIP_SUPPORT +extern int TIFFInitZIP(TIFF*, int); +#endif +#ifdef PIXARLOG_SUPPORT +extern int TIFFInitPixarLog(TIFF*, int); +#endif +#ifdef LOGLUV_SUPPORT +extern int TIFFInitSGILog(TIFF*, int); +#endif +#ifdef LERC_SUPPORT +extern int TIFFInitLERC(TIFF* tif, int); +#endif +#ifdef LZMA_SUPPORT +extern int TIFFInitLZMA(TIFF*, int); +#endif +#ifdef ZSTD_SUPPORT +extern int TIFFInitZSTD(TIFF*, int); +#endif +#ifdef WEBP_SUPPORT +extern int TIFFInitWebP(TIFF*, int); +#endif +extern const TIFFCodec _TIFFBuiltinCODECS[]; + +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFIOP_ */ + +/* vim: set ts=8 sts=8 sw=8 noet: */ +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */ diff --git a/libs/tiff/libtiff/tiffvers.h b/libs/tiff/libtiff/tiffvers.h new file mode 100644 index 00000000000..dbe559617db --- /dev/null +++ b/libs/tiff/libtiff/tiffvers.h @@ -0,0 +1,9 @@ +#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.3.0\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." +/* + * This define can be used in code that requires + * compilation-related definitions specific to a + * version or versions of the library. Runtime + * version checking should be done based on the + * string returned by TIFFGetVersion. + */ +#define TIFFLIB_VERSION 20210416 diff --git a/libs/tiff/libtiff/uvcode.h b/libs/tiff/libtiff/uvcode.h new file mode 100644 index 00000000000..6286cfbb0c1 --- /dev/null +++ b/libs/tiff/libtiff/uvcode.h @@ -0,0 +1,180 @@ +/* Version 1.0 generated April 7, 1997 by Greg Ward Larson, SGI */ +#define UV_SQSIZ (float)0.003500 +#define UV_NDIVS 16289 +#define UV_VSTART (float)0.016940 +#define UV_NVS 163 +static const struct { + float ustart; + short nus, ncum; +} uv_row[UV_NVS] = { + { (float)0.247663, 4, 0 }, + { (float)0.243779, 6, 4 }, + { (float)0.241684, 7, 10 }, + { (float)0.237874, 9, 17 }, + { (float)0.235906, 10, 26 }, + { (float)0.232153, 12, 36 }, + { (float)0.228352, 14, 48 }, + { (float)0.226259, 15, 62 }, + { (float)0.222371, 17, 77 }, + { (float)0.220410, 18, 94 }, + { (float)0.214710, 21, 112 }, + { (float)0.212714, 22, 133 }, + { (float)0.210721, 23, 155 }, + { (float)0.204976, 26, 178 }, + { (float)0.202986, 27, 204 }, + { (float)0.199245, 29, 231 }, + { (float)0.195525, 31, 260 }, + { (float)0.193560, 32, 291 }, + { (float)0.189878, 34, 323 }, + { (float)0.186216, 36, 357 }, + { (float)0.186216, 36, 393 }, + { (float)0.182592, 38, 429 }, + { (float)0.179003, 40, 467 }, + { (float)0.175466, 42, 507 }, + { (float)0.172001, 44, 549 }, + { (float)0.172001, 44, 593 }, + { (float)0.168612, 46, 637 }, + { (float)0.168612, 46, 683 }, + { (float)0.163575, 49, 729 }, + { (float)0.158642, 52, 778 }, + { (float)0.158642, 52, 830 }, + { (float)0.158642, 52, 882 }, + { (float)0.153815, 55, 934 }, + { (float)0.153815, 55, 989 }, + { (float)0.149097, 58, 1044 }, + { (float)0.149097, 58, 1102 }, + { (float)0.142746, 62, 1160 }, + { (float)0.142746, 62, 1222 }, + { (float)0.142746, 62, 1284 }, + { (float)0.138270, 65, 1346 }, + { (float)0.138270, 65, 1411 }, + { (float)0.138270, 65, 1476 }, + { (float)0.132166, 69, 1541 }, + { (float)0.132166, 69, 1610 }, + { (float)0.126204, 73, 1679 }, + { (float)0.126204, 73, 1752 }, + { (float)0.126204, 73, 1825 }, + { (float)0.120381, 77, 1898 }, + { (float)0.120381, 77, 1975 }, + { (float)0.120381, 77, 2052 }, + { (float)0.120381, 77, 2129 }, + { (float)0.112962, 82, 2206 }, + { (float)0.112962, 82, 2288 }, + { (float)0.112962, 82, 2370 }, + { (float)0.107450, 86, 2452 }, + { (float)0.107450, 86, 2538 }, + { (float)0.107450, 86, 2624 }, + { (float)0.107450, 86, 2710 }, + { (float)0.100343, 91, 2796 }, + { (float)0.100343, 91, 2887 }, + { (float)0.100343, 91, 2978 }, + { (float)0.095126, 95, 3069 }, + { (float)0.095126, 95, 3164 }, + { (float)0.095126, 95, 3259 }, + { (float)0.095126, 95, 3354 }, + { (float)0.088276, 100, 3449 }, + { (float)0.088276, 100, 3549 }, + { (float)0.088276, 100, 3649 }, + { (float)0.088276, 100, 3749 }, + { (float)0.081523, 105, 3849 }, + { (float)0.081523, 105, 3954 }, + { (float)0.081523, 105, 4059 }, + { (float)0.081523, 105, 4164 }, + { (float)0.074861, 110, 4269 }, + { (float)0.074861, 110, 4379 }, + { (float)0.074861, 110, 4489 }, + { (float)0.074861, 110, 4599 }, + { (float)0.068290, 115, 4709 }, + { (float)0.068290, 115, 4824 }, + { (float)0.068290, 115, 4939 }, + { (float)0.068290, 115, 5054 }, + { (float)0.063573, 119, 5169 }, + { (float)0.063573, 119, 5288 }, + { (float)0.063573, 119, 5407 }, + { (float)0.063573, 119, 5526 }, + { (float)0.057219, 124, 5645 }, + { (float)0.057219, 124, 5769 }, + { (float)0.057219, 124, 5893 }, + { (float)0.057219, 124, 6017 }, + { (float)0.050985, 129, 6141 }, + { (float)0.050985, 129, 6270 }, + { (float)0.050985, 129, 6399 }, + { (float)0.050985, 129, 6528 }, + { (float)0.050985, 129, 6657 }, + { (float)0.044859, 134, 6786 }, + { (float)0.044859, 134, 6920 }, + { (float)0.044859, 134, 7054 }, + { (float)0.044859, 134, 7188 }, + { (float)0.040571, 138, 7322 }, + { (float)0.040571, 138, 7460 }, + { (float)0.040571, 138, 7598 }, + { (float)0.040571, 138, 7736 }, + { (float)0.036339, 142, 7874 }, + { (float)0.036339, 142, 8016 }, + { (float)0.036339, 142, 8158 }, + { (float)0.036339, 142, 8300 }, + { (float)0.032139, 146, 8442 }, + { (float)0.032139, 146, 8588 }, + { (float)0.032139, 146, 8734 }, + { (float)0.032139, 146, 8880 }, + { (float)0.027947, 150, 9026 }, + { (float)0.027947, 150, 9176 }, + { (float)0.027947, 150, 9326 }, + { (float)0.023739, 154, 9476 }, + { (float)0.023739, 154, 9630 }, + { (float)0.023739, 154, 9784 }, + { (float)0.023739, 154, 9938 }, + { (float)0.019504, 158, 10092 }, + { (float)0.019504, 158, 10250 }, + { (float)0.019504, 158, 10408 }, + { (float)0.016976, 161, 10566 }, + { (float)0.016976, 161, 10727 }, + { (float)0.016976, 161, 10888 }, + { (float)0.016976, 161, 11049 }, + { (float)0.012639, 165, 11210 }, + { (float)0.012639, 165, 11375 }, + { (float)0.012639, 165, 11540 }, + { (float)0.009991, 168, 11705 }, + { (float)0.009991, 168, 11873 }, + { (float)0.009991, 168, 12041 }, + { (float)0.009016, 170, 12209 }, + { (float)0.009016, 170, 12379 }, + { (float)0.009016, 170, 12549 }, + { (float)0.006217, 173, 12719 }, + { (float)0.006217, 173, 12892 }, + { (float)0.005097, 175, 13065 }, + { (float)0.005097, 175, 13240 }, + { (float)0.005097, 175, 13415 }, + { (float)0.003909, 177, 13590 }, + { (float)0.003909, 177, 13767 }, + { (float)0.002340, 177, 13944 }, + { (float)0.002389, 170, 14121 }, + { (float)0.001068, 164, 14291 }, + { (float)0.001653, 157, 14455 }, + { (float)0.000717, 150, 14612 }, + { (float)0.001614, 143, 14762 }, + { (float)0.000270, 136, 14905 }, + { (float)0.000484, 129, 15041 }, + { (float)0.001103, 123, 15170 }, + { (float)0.001242, 115, 15293 }, + { (float)0.001188, 109, 15408 }, + { (float)0.001011, 103, 15517 }, + { (float)0.000709, 97, 15620 }, + { (float)0.000301, 89, 15717 }, + { (float)0.002416, 82, 15806 }, + { (float)0.003251, 76, 15888 }, + { (float)0.003246, 69, 15964 }, + { (float)0.004141, 62, 16033 }, + { (float)0.005963, 55, 16095 }, + { (float)0.008839, 47, 16150 }, + { (float)0.010490, 40, 16197 }, + { (float)0.016994, 31, 16237 }, + { (float)0.023659, 21, 16268 }, +}; +/* + * Local Variables: + * mode: c + * c-basic-offset: 8 + * fill-column: 78 + * End: + */