From 333d31d37c606f97aba7028401608ce8660d2e23 Mon Sep 17 00:00:00 2001 From: gal kahana Date: Sun, 15 Oct 2023 21:18:49 +0300 Subject: [PATCH] Draft: feat: upgrade bundled libtiff to 4.6 (#227) * feat: upgrade bundled libtiff to 4.6 * feat: upgrade bundled libtiff to 4.6 * put back the way it was, lets try having clients that need C++ do independent imports * lets put back cmake version too, so we don't even break this part * update binding gyp as well for node --------- Co-authored-by: Gal Kahana --- LibTiff/CMakeLists.txt | 11 + LibTiff/binding.gyp | 14 +- LibTiff/mkg3states.c | 272 + LibTiff/t4.h | 486 +- LibTiff/tif_aux.c | 632 ++- LibTiff/tif_close.c | 184 +- LibTiff/tif_codec.c | 189 +- LibTiff/tif_color.c | 426 +- LibTiff/tif_compress.c | 425 +- LibTiff/tif_config.h | 102 +- LibTiff/tif_dir.c | 3139 ++++++---- LibTiff/tif_dir.h | 451 +- LibTiff/tif_dirinfo.c | 2051 ++++--- LibTiff/tif_dirread.c | 9789 +++++++++++++++++++++++++------- LibTiff/tif_dirwrite.c | 4788 +++++++++++----- LibTiff/tif_dumpmode.c | 152 +- LibTiff/tif_error.c | 142 +- LibTiff/tif_extension.c | 84 +- LibTiff/tif_fax3.c | 2767 ++++----- LibTiff/tif_fax3.h | 874 +-- LibTiff/tif_fax3sm.c | 1 + LibTiff/tif_flush.c | 161 +- LibTiff/tif_getimage.c | 4700 ++++++++------- LibTiff/tif_hash_set.c | 603 ++ LibTiff/tif_hash_set.h | 100 + LibTiff/tif_jbig.c | 468 +- LibTiff/tif_jpeg.c | 4109 ++++++++------ LibTiff/tif_jpeg_12.c | 63 + LibTiff/tif_lerc.c | 1206 ++++ LibTiff/tif_luv.c | 2667 +++++---- LibTiff/tif_lzma.c | 520 ++ LibTiff/tif_lzw.c | 2189 ++++--- LibTiff/tif_next.c | 276 +- LibTiff/tif_ojpeg.c | 4733 ++++++++------- LibTiff/tif_open.c | 1159 ++-- LibTiff/tif_packbits.c | 507 +- LibTiff/tif_pixarlog.c | 2533 +++++---- LibTiff/tif_predict.c | 1538 +++-- LibTiff/tif_predict.h | 79 +- LibTiff/tif_print.c | 1287 +++-- LibTiff/tif_read.c | 2096 +++++-- LibTiff/tif_stream.cxx | 611 +- LibTiff/tif_strip.c | 538 +- LibTiff/tif_swab.c | 427 +- LibTiff/tif_thunder.c | 263 +- LibTiff/tif_tile.c | 414 +- LibTiff/tif_unix.c | 434 +- LibTiff/tif_version.c | 30 +- LibTiff/tif_warning.c | 116 +- LibTiff/tif_webp.c | 881 +++ LibTiff/tif_win32.c | 442 ++ LibTiff/tif_write.c | 1394 +++-- LibTiff/tif_zip.c | 934 ++- LibTiff/tif_zstd.c | 436 ++ LibTiff/tiff.h | 1301 +++-- LibTiff/tiffconf.h | 70 +- LibTiff/tiffio.h | 873 +-- LibTiff/tiffio.hxx | 36 +- LibTiff/tiffiop.h | 679 ++- LibTiff/tiffvers.h | 31 +- LibTiff/uvcode.h | 269 +- PDFWriter/TIFFImageHandler.cpp | 214 +- PDFWriter/TIFFImageHandler.h | 34 +- 63 files changed, 44240 insertions(+), 24160 deletions(-) create mode 100644 LibTiff/mkg3states.c create mode 100644 LibTiff/tif_hash_set.c create mode 100644 LibTiff/tif_hash_set.h create mode 100644 LibTiff/tif_jpeg_12.c create mode 100644 LibTiff/tif_lerc.c create mode 100644 LibTiff/tif_lzma.c create mode 100644 LibTiff/tif_webp.c create mode 100644 LibTiff/tif_win32.c create mode 100644 LibTiff/tif_zstd.c diff --git a/LibTiff/CMakeLists.txt b/LibTiff/CMakeLists.txt index f2825f9b..ec449ef9 100644 --- a/LibTiff/CMakeLists.txt +++ b/LibTiff/CMakeLists.txt @@ -16,6 +16,7 @@ tif_fax3.c tif_fax3sm.c tif_flush.c tif_getimage.c +tif_hash_set.c tif_jbig.c tif_jpeg.c tif_luv.c @@ -51,6 +52,7 @@ tiffvers.h tif_config.h tif_dir.h tif_fax3.h +tif_hash_set.h tif_predict.h uvcode.h @@ -66,6 +68,15 @@ target_include_directories(LibTiff $ ) +# +# Check for unistd.h +# +include(CheckIncludeFile) +check_include_file(unistd.h T_HAVE_UNISTD_H) +if(T_HAVE_UNISTD_H) + target_compile_definitions(LibTiff PUBLIC HAVE_UNISTD_H=1) +endif(T_HAVE_UNISTD_H) + target_compile_definitions(LibTiff PUBLIC _CRT_SECURE_NO_DEPRECATE=1 AVOID_WIN32_FILEIO=1 diff --git a/LibTiff/binding.gyp b/LibTiff/binding.gyp index fe02906c..6ca80d3d 100644 --- a/LibTiff/binding.gyp +++ b/LibTiff/binding.gyp @@ -5,7 +5,7 @@ 'type': 'static_library', 'dependencies': [ '<(module_root_dir)/src/deps/Zlib/binding.gyp:zlib' - ], + ], 'defines': [ '_CRT_SECURE_NO_DEPRECATE=1', 'AVOID_WIN32_FILEIO=1', @@ -24,7 +24,15 @@ 'TIF_PLATFORM_CONSOLE=1', 'FILLODER_LSB2MSB=1' ], - 'include_dirs': [ + 'conditions': [ + ['OS == "win"', { + }, { + "defines": [ + 'HAVE_UNISTD_H=1' + ] + }] + ], + 'include_dirs': [ '<(module_root_dir)/src/deps/Zlib', ], 'sources': [ @@ -44,6 +52,7 @@ 'tif_fax3sm.c', 'tif_flush.c', 'tif_getimage.c', + 'tif_hash_set.c', 'tif_jbig.c', 'tif_jpeg.c', 'tif_luv.c', @@ -76,6 +85,7 @@ 'tif_config.h', 'tif_dir.h', 'tif_fax3.h', + 'tif_hash_set.h', 'tif_predict.h', 'uvcode.h' ] diff --git a/LibTiff/mkg3states.c b/LibTiff/mkg3states.c new file mode 100644 index 00000000..f32113a3 --- /dev/null +++ b/LibTiff/mkg3states.c @@ -0,0 +1,272 @@ +/* + * 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. + */ + +/* Initialise fax decoder tables + * Decoder support is derived, with permission, from the code + * in Frank Cringle's viewfax program; + * Copyright (C) 1990, 1995 Frank D. Cringle. + */ +#include "libport.h" +#include "tif_config.h" + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "tif_fax3.h" + +#define streq(a, b) (strcmp(a, b) == 0) + +/* NB: can't use names in tif_fax3.h 'cuz they are declared const */ +TIFFFaxTabEnt MainTable[128]; +TIFFFaxTabEnt WhiteTable[4096]; +TIFFFaxTabEnt BlackTable[8192]; + +struct proto +{ + uint16_t code; /* right justified, lsb-first, zero filled */ + uint16_t val; /* (pixel count)<<4 + code width */ +}; + +static struct proto Pass[] = {{0x0008, 4}, {0, 0}}; + +static struct proto Horiz[] = {{0x0004, 3}, {0, 0}}; + +static struct proto V0[] = {{0x0001, 1}, {0, 0}}; + +static struct proto VR[] = {{0x0006, (1 << 4) + 3}, + {0x0030, (2 << 4) + 6}, + {0x0060, (3 << 4) + 7}, + {0, 0}}; + +static struct proto VL[] = {{0x0002, (1 << 4) + 3}, + {0x0010, (2 << 4) + 6}, + {0x0020, (3 << 4) + 7}, + {0, 0}}; + +static struct proto Ext[] = {{0x0040, 7}, {0, 0}}; + +static struct proto EOLV[] = {{0x0000, 7}, {0, 0}}; + +static struct proto MakeUpW[] = { + {0x001b, 1029}, {0x0009, 2053}, {0x003a, 3078}, {0x0076, 4103}, + {0x006c, 5128}, {0x00ec, 6152}, {0x0026, 7176}, {0x00a6, 8200}, + {0x0016, 9224}, {0x00e6, 10248}, {0x0066, 11273}, {0x0166, 12297}, + {0x0096, 13321}, {0x0196, 14345}, {0x0056, 15369}, {0x0156, 16393}, + {0x00d6, 17417}, {0x01d6, 18441}, {0x0036, 19465}, {0x0136, 20489}, + {0x00b6, 21513}, {0x01b6, 22537}, {0x0032, 23561}, {0x0132, 24585}, + {0x00b2, 25609}, {0x0006, 26630}, {0x01b2, 27657}, {0, 0}}; + +static struct proto MakeUpB[] = { + {0x03c0, 1034}, {0x0130, 2060}, {0x0930, 3084}, {0x0da0, 4108}, + {0x0cc0, 5132}, {0x02c0, 6156}, {0x0ac0, 7180}, {0x06c0, 8205}, + {0x16c0, 9229}, {0x0a40, 10253}, {0x1a40, 11277}, {0x0640, 12301}, + {0x1640, 13325}, {0x09c0, 14349}, {0x19c0, 15373}, {0x05c0, 16397}, + {0x15c0, 17421}, {0x0dc0, 18445}, {0x1dc0, 19469}, {0x0940, 20493}, + {0x1940, 21517}, {0x0540, 22541}, {0x1540, 23565}, {0x0b40, 24589}, + {0x1b40, 25613}, {0x04c0, 26637}, {0x14c0, 27661}, {0, 0}}; + +static struct proto MakeUp[] = { + {0x0080, 28683}, {0x0180, 29707}, {0x0580, 30731}, {0x0480, 31756}, + {0x0c80, 32780}, {0x0280, 33804}, {0x0a80, 34828}, {0x0680, 35852}, + {0x0e80, 36876}, {0x0380, 37900}, {0x0b80, 38924}, {0x0780, 39948}, + {0x0f80, 40972}, {0, 0}}; + +static struct proto TermW[] = { + {0x00ac, 8}, {0x0038, 22}, {0x000e, 36}, {0x0001, 52}, {0x000d, 68}, + {0x0003, 84}, {0x0007, 100}, {0x000f, 116}, {0x0019, 133}, {0x0005, 149}, + {0x001c, 165}, {0x0002, 181}, {0x0004, 198}, {0x0030, 214}, {0x000b, 230}, + {0x002b, 246}, {0x0015, 262}, {0x0035, 278}, {0x0072, 295}, {0x0018, 311}, + {0x0008, 327}, {0x0074, 343}, {0x0060, 359}, {0x0010, 375}, {0x000a, 391}, + {0x006a, 407}, {0x0064, 423}, {0x0012, 439}, {0x000c, 455}, {0x0040, 472}, + {0x00c0, 488}, {0x0058, 504}, {0x00d8, 520}, {0x0048, 536}, {0x00c8, 552}, + {0x0028, 568}, {0x00a8, 584}, {0x0068, 600}, {0x00e8, 616}, {0x0014, 632}, + {0x0094, 648}, {0x0054, 664}, {0x00d4, 680}, {0x0034, 696}, {0x00b4, 712}, + {0x0020, 728}, {0x00a0, 744}, {0x0050, 760}, {0x00d0, 776}, {0x004a, 792}, + {0x00ca, 808}, {0x002a, 824}, {0x00aa, 840}, {0x0024, 856}, {0x00a4, 872}, + {0x001a, 888}, {0x009a, 904}, {0x005a, 920}, {0x00da, 936}, {0x0052, 952}, + {0x00d2, 968}, {0x004c, 984}, {0x00cc, 1000}, {0x002c, 1016}, {0, 0}}; + +static struct proto TermB[] = { + {0x03b0, 10}, {0x0002, 19}, {0x0003, 34}, {0x0001, 50}, {0x0006, 67}, + {0x000c, 84}, {0x0004, 100}, {0x0018, 117}, {0x0028, 134}, {0x0008, 150}, + {0x0010, 167}, {0x0050, 183}, {0x0070, 199}, {0x0020, 216}, {0x00e0, 232}, + {0x0030, 249}, {0x03a0, 266}, {0x0060, 282}, {0x0040, 298}, {0x0730, 315}, + {0x00b0, 331}, {0x01b0, 347}, {0x0760, 363}, {0x00a0, 379}, {0x0740, 395}, + {0x00c0, 411}, {0x0530, 428}, {0x0d30, 444}, {0x0330, 460}, {0x0b30, 476}, + {0x0160, 492}, {0x0960, 508}, {0x0560, 524}, {0x0d60, 540}, {0x04b0, 556}, + {0x0cb0, 572}, {0x02b0, 588}, {0x0ab0, 604}, {0x06b0, 620}, {0x0eb0, 636}, + {0x0360, 652}, {0x0b60, 668}, {0x05b0, 684}, {0x0db0, 700}, {0x02a0, 716}, + {0x0aa0, 732}, {0x06a0, 748}, {0x0ea0, 764}, {0x0260, 780}, {0x0a60, 796}, + {0x04a0, 812}, {0x0ca0, 828}, {0x0240, 844}, {0x0ec0, 860}, {0x01c0, 876}, + {0x0e40, 892}, {0x0140, 908}, {0x01a0, 924}, {0x09a0, 940}, {0x0d40, 956}, + {0x0340, 972}, {0x05a0, 988}, {0x0660, 1004}, {0x0e60, 1020}, {0, 0}}; + +static struct proto EOLH[] = {{0x0000, 11}, {0, 0}}; + +static void FillTable(TIFFFaxTabEnt *T, int Size, struct proto *P, int State) +{ + int limit = 1 << Size; + + while (P->val) + { + int width = P->val & 15; + int param = P->val >> 4; + int incr = 1 << width; + int code; + for (code = P->code; code < limit; code += incr) + { + TIFFFaxTabEnt *E = T + code; + E->State = State; + E->Width = width; + E->Param = param; + } + P++; + } +} + +static char *storage_class = ""; +static char *const_class = ""; +static int packoutput = 1; +static char *prebrace = ""; +static char *postbrace = ""; + +void WriteTable(FILE *fd, const TIFFFaxTabEnt *T, int Size, const char *name) +{ + int i; + char *sep; + + fprintf(fd, "%s %s TIFFFaxTabEnt %s[%d] = {", storage_class, const_class, + name, Size); + if (packoutput) + { + sep = "\n"; + for (i = 0; i < Size; i++) + { + fprintf(fd, "%s%s%d,%d,%d%s", sep, prebrace, T->State, T->Width, + (int)T->Param, postbrace); + if (((i + 1) % 10) == 0) + sep = ",\n"; + else + sep = ","; + T++; + } + } + else + { + sep = "\n "; + for (i = 0; i < Size; i++) + { + fprintf(fd, "%s%s%3d,%3d,%4d%s", sep, prebrace, T->State, T->Width, + (int)T->Param, postbrace); + if (((i + 1) % 6) == 0) + sep = ",\n "; + else + sep = ","; + T++; + } + } + fprintf(fd, "\n};\n"); +} + +/* initialise the huffman code tables */ +int main(int argc, char *argv[]) +{ + FILE *fd; + char *outputfile; + int c; + +#if !HAVE_DECL_OPTARG + extern int optind; + extern char *optarg; +#endif + + while ((c = getopt(argc, argv, "c:s:bp")) != -1) + switch (c) + { + case 'c': + const_class = optarg; + break; + case 's': + storage_class = optarg; + break; + case 'p': + packoutput = 0; + break; + case 'b': + prebrace = "{"; + postbrace = "}"; + break; + case '?': + fprintf(stderr, + "usage: %s [-c const] [-s storage] [-p] [-b] file\n", + argv[0]); + return (-1); + } + outputfile = optind < argc ? argv[optind] : "g3states.h"; + fd = fopen(outputfile, "w"); + if (fd == NULL) + { + fprintf(stderr, "%s: %s: Cannot create output file.\n", argv[0], + outputfile); + return (-2); + } + FillTable(MainTable, 7, Pass, S_Pass); + FillTable(MainTable, 7, Horiz, S_Horiz); + FillTable(MainTable, 7, V0, S_V0); + FillTable(MainTable, 7, VR, S_VR); + FillTable(MainTable, 7, VL, S_VL); + FillTable(MainTable, 7, Ext, S_Ext); + FillTable(MainTable, 7, EOLV, S_EOL); + FillTable(WhiteTable, 12, MakeUpW, S_MakeUpW); + FillTable(WhiteTable, 12, MakeUp, S_MakeUp); + FillTable(WhiteTable, 12, TermW, S_TermW); + FillTable(WhiteTable, 12, EOLH, S_EOL); + FillTable(BlackTable, 13, MakeUpB, S_MakeUpB); + FillTable(BlackTable, 13, MakeUp, S_MakeUp); + FillTable(BlackTable, 13, TermB, S_TermB); + FillTable(BlackTable, 13, EOLH, S_EOL); + + fprintf(fd, "/* WARNING, this file was automatically generated by the\n"); + fprintf(fd, " mkg3states program */\n"); + fprintf(fd, "#include \n"); + fprintf(fd, "#include \"tiff.h\"\n"); + fprintf(fd, "#include \"tif_fax3.h\"\n"); + WriteTable(fd, MainTable, 128, "TIFFFaxMainTable"); + WriteTable(fd, WhiteTable, 4096, "TIFFFaxWhiteTable"); + WriteTable(fd, BlackTable, 8192, "TIFFFaxBlackTable"); + fprintf(fd, "/*\n" + " * Local Variables:\n" + " * mode: c\n" + " * c-basic-offset: 8\n" + " * fill-column: 78\n" + " * End:\n" + " */\n"); + fclose(fd); + return (0); +} diff --git a/LibTiff/t4.h b/LibTiff/t4.h index 870704ff..f933d4a3 100644 --- a/LibTiff/t4.h +++ b/LibTiff/t4.h @@ -1,50 +1,49 @@ -/* $Id: t4.h,v 1.1.1.1.2.1 2010-06-08 18:50:41 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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_ +#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 */ +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 */ +#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 */ +#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 @@ -56,237 +55,230 @@ typedef struct tableentry { */ #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 */ + {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 */ + {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[]; +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/LibTiff/tif_aux.c b/LibTiff/tif_aux.c index 272f0d9b..49855bb0 100644 --- a/LibTiff/tif_aux.c +++ b/LibTiff/tif_aux.c @@ -1,26 +1,24 @@ -/* $Id: tif_aux.c,v 1.20.2.3 2010-06-09 21:15:27 bfriesen Exp $ */ - /* * Copyright (c) 1991-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -29,106 +27,180 @@ * * Auxiliary Support Routines. */ -#include "tiffiop.h" #include "tif_predict.h" +#include "tiffiop.h" +#include #include -tdata_t -_TIFFCheckRealloc(TIFF* tif, tdata_t buffer, - size_t nmemb, size_t elem_size, const char* what) +uint32_t _TIFFMultiply32(TIFF *tif, uint32_t first, uint32_t second, + const char *where) +{ + if (second && first > UINT32_MAX / second) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) { - tdata_t cp = NULL; - tsize_t bytes = nmemb * elem_size; - - /* - * XXX: Check for integer overflow. - */ - if (nmemb && elem_size && bytes / elem_size == nmemb) - cp = _TIFFrealloc(buffer, bytes); - - if (cp == NULL) - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Failed to allocate memory for %s " - "(%ld elements of %ld bytes each)", - what,(long) nmemb, (long) elem_size); - - return cp; + if (first <= 0 || second <= 0) + { + if (tif != NULL && where != NULL) + { + TIFFErrorExtR(tif, where, + "Invalid argument to _TIFFMultiplySSize() in %s", + where); + } + return 0; + } + + if (first > TIFF_TMSIZE_T_MAX / second) + { + if (tif != NULL && where != NULL) + { + TIFFErrorExtR(tif, where, "Integer overflow in %s", where); + } + return 0; + } + return first * second; } -tdata_t -_TIFFCheckMalloc(TIFF* tif, size_t nmemb, size_t elem_size, const char* what) +tmsize_t _TIFFCastUInt64ToSSize(TIFF *tif, uint64_t val, const char *module) { - return _TIFFCheckRealloc(tif, NULL, nmemb, elem_size, what); + if (val > (uint64_t)TIFF_TMSIZE_T_MAX) + { + if (tif != NULL && module != NULL) + { + TIFFErrorExtR(tif, module, "Integer overflow"); + } + return 0; + } + return (tmsize_t)val; } -static int -TIFFDefaultTransferFunction(TIFFDirectory* td) +void *_TIFFCheckRealloc(TIFF *tif, void *buffer, tmsize_t nmemb, + tmsize_t elem_size, const char *what) { - uint16 **tf = td->td_transferfunction; - tsize_t i, n, nbytes; - - tf[0] = tf[1] = tf[2] = 0; - if (td->td_bitspersample >= sizeof(tsize_t) * 8 - 2) - return 0; - - n = 1<td_bitspersample; - nbytes = n * sizeof (uint16); - if (!(tf[0] = (uint16 *)_TIFFmalloc(nbytes))) - return 0; - tf[0][0] = 0; - for (i = 1; i < n; i++) { - double t = (double)i/((double) n-1.); - tf[0][i] = (uint16)floor(65535.*pow(t, 2.2) + .5); - } - - if (td->td_samplesperpixel - td->td_extrasamples > 1) { - if (!(tf[1] = (uint16 *)_TIFFmalloc(nbytes))) - goto bad; - _TIFFmemcpy(tf[1], tf[0], nbytes); - if (!(tf[2] = (uint16 *)_TIFFmalloc(nbytes))) - goto bad; - _TIFFmemcpy(tf[2], tf[0], nbytes); - } - return 1; + void *cp = NULL; + tmsize_t count = _TIFFMultiplySSize(tif, nmemb, elem_size, NULL); + /* + * Check for integer overflow. + */ + if (count != 0) + { + cp = _TIFFreallocExt(tif, buffer, count); + } + + if (cp == NULL) + { + TIFFErrorExtR(tif, 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(TIFF *tif, 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->td_bitspersample; + nbytes = n * sizeof(uint16_t); + tf[0] = (uint16_t *)_TIFFmallocExt(tif, 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 *)_TIFFmallocExt(tif, nbytes); + if (tf[1] == NULL) + goto bad; + _TIFFmemcpy(tf[1], tf[0], nbytes); + tf[2] = (uint16_t *)_TIFFmallocExt(tif, 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; + if (tf[0]) + _TIFFfreeExt(tif, tf[0]); + if (tf[1]) + _TIFFfreeExt(tif, tf[1]); + if (tf[2]) + _TIFFfreeExt(tif, tf[2]); + tf[0] = tf[1] = tf[2] = 0; + return 0; } -static int -TIFFDefaultRefBlackWhite(TIFFDirectory* td) +static int TIFFDefaultRefBlackWhite(TIFF *tif, TIFFDirectory *td) { - int i; - - if (!(td->td_refblackwhite = (float *)_TIFFmalloc(6*sizeof (float)))) - 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; + int i; + + td->td_refblackwhite = (float *)_TIFFmallocExt(tif, 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->td_bitspersample) - 1L); + } + } + return 1; } /* @@ -136,155 +208,251 @@ TIFFDefaultRefBlackWhite(TIFFDirectory* td) * value if the tag is not present in the directory. * * NB: We use the value in the directory, rather than - * explcit values so that defaults exist only one + * explicit values so that defaults exist only one * place in the library -- in TIFFDefaultDirectory. */ -int -TIFFVGetFieldDefaulted(TIFF* tif, ttag_t tag, va_list ap) +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 *) = td->td_subfiletype; - return (1); - case TIFFTAG_BITSPERSAMPLE: - *va_arg(ap, uint16 *) = td->td_bitspersample; - return (1); - case TIFFTAG_THRESHHOLDING: - *va_arg(ap, uint16 *) = td->td_threshholding; - return (1); - case TIFFTAG_FILLORDER: - *va_arg(ap, uint16 *) = td->td_fillorder; - return (1); - case TIFFTAG_ORIENTATION: - *va_arg(ap, uint16 *) = td->td_orientation; - return (1); - case TIFFTAG_SAMPLESPERPIXEL: - *va_arg(ap, uint16 *) = td->td_samplesperpixel; - return (1); - case TIFFTAG_ROWSPERSTRIP: - *va_arg(ap, uint32 *) = td->td_rowsperstrip; - return (1); - case TIFFTAG_MINSAMPLEVALUE: - *va_arg(ap, uint16 *) = td->td_minsamplevalue; - return (1); - case TIFFTAG_MAXSAMPLEVALUE: - *va_arg(ap, uint16 *) = td->td_maxsamplevalue; - return (1); - case TIFFTAG_PLANARCONFIG: - *va_arg(ap, uint16 *) = td->td_planarconfig; - return (1); - case TIFFTAG_RESOLUTIONUNIT: - *va_arg(ap, uint16 *) = td->td_resolutionunit; - return (1); - case TIFFTAG_PREDICTOR: + 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: + { + uint16_t maxsamplevalue; + /* td_bitspersample=1 is always set in TIFFDefaultDirectory(). + * Therefore, td_maxsamplevalue has to be re-calculated in + * TIFFGetFieldDefaulted(). */ + if (td->td_bitspersample > 0) + { + /* This shift operation into a uint16_t limits the value to + * 65535 even if td_bitspersamle is > 16 */ + if (td->td_bitspersample <= 16) + { + maxsamplevalue = (1 << td->td_bitspersample) - + 1; /* 2**(BitsPerSample) - 1 */ + } + else { - TIFFPredictorState* sp = (TIFFPredictorState*) tif->tif_data; - *va_arg(ap, uint16*) = (uint16) sp->predictor; - return 1; + maxsamplevalue = 65535; } - case TIFFTAG_DOTRANGE: - *va_arg(ap, uint16 *) = 0; - *va_arg(ap, uint16 *) = (1<td_bitspersample)-1; - return (1); - case TIFFTAG_INKSET: - *va_arg(ap, uint16 *) = INKSET_CMYK; - return 1; - case TIFFTAG_NUMBEROFINKS: - *va_arg(ap, uint16 *) = 4; - return (1); - case TIFFTAG_EXTRASAMPLES: - *va_arg(ap, uint16 *) = td->td_extrasamples; - *va_arg(ap, uint16 **) = td->td_sampleinfo; - return (1); - case TIFFTAG_MATTEING: - *va_arg(ap, uint16 *) = - (td->td_extrasamples == 1 && - td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA); - return (1); - case TIFFTAG_TILEDEPTH: - *va_arg(ap, uint32 *) = td->td_tiledepth; - return (1); - case TIFFTAG_DATATYPE: - *va_arg(ap, uint16 *) = td->td_sampleformat-1; - return (1); - case TIFFTAG_SAMPLEFORMAT: - *va_arg(ap, uint16 *) = td->td_sampleformat; - return(1); - case TIFFTAG_IMAGEDEPTH: - *va_arg(ap, uint32 *) = td->td_imagedepth; - return (1); - case TIFFTAG_YCBCRCOEFFICIENTS: - { - /* defaults are from CCIR Recommendation 601-1 */ - static float ycbcrcoeffs[] = { 0.299f, 0.587f, 0.114f }; - *va_arg(ap, float **) = ycbcrcoeffs; - return 1; - } - case TIFFTAG_YCBCRSUBSAMPLING: - *va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[0]; - *va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[1]; - return (1); - case TIFFTAG_YCBCRPOSITIONING: - *va_arg(ap, uint16 *) = td->td_ycbcrpositioning; - return (1); - case TIFFTAG_WHITEPOINT: - { - static float whitepoint[2]; - - /* 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. */ - whitepoint[0] = D50_X0 / (D50_X0 + D50_Y0 + D50_Z0); - whitepoint[1] = D50_Y0 / (D50_X0 + D50_Y0 + D50_Z0); - *va_arg(ap, 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, uint16 **) = td->td_transferfunction[0]; - if (td->td_samplesperpixel - td->td_extrasamples > 1) { - *va_arg(ap, uint16 **) = td->td_transferfunction[1]; - *va_arg(ap, uint16 **) = td->td_transferfunction[2]; - } - return (1); - case TIFFTAG_REFERENCEBLACKWHITE: - if (!td->td_refblackwhite && !TIFFDefaultRefBlackWhite(td)) - return (0); - *va_arg(ap, float **) = td->td_refblackwhite; - return (1); - } - return 0; + } + else + { + maxsamplevalue = 0; + } + *va_arg(ap, uint16_t *) = 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) + { + TIFFErrorExtR( + tif, 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(tif, td)) + { + TIFFErrorExtR(tif, 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(tif, 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 -TIFFGetFieldDefaulted(TIFF* tif, ttag_t tag, ...) +int TIFFGetFieldDefaulted(TIFF *tif, uint32_t tag, ...) { - int ok; - va_list ap; + int ok; + va_list ap; - va_start(ap, tag); - ok = TIFFVGetFieldDefaulted(tif, tag, ap); - va_end(ap); - return (ok); + va_start(ap, tag); + ok = TIFFVGetFieldDefaulted(tif, tag, ap); + va_end(ap); + return (ok); } -/* vim: set ts=8 sts=8 sw=8 noet: */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ +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; +} + +uint32_t _TIFFClampDoubleToUInt32(double val) +{ + if (val < 0) + return 0; + if (val > 0xFFFFFFFFU || val != val) + return 0xFFFFFFFFU; + return (uint32_t)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; +} diff --git a/LibTiff/tif_close.c b/LibTiff/tif_close.c index 02591ba9..907d7f13 100644 --- a/LibTiff/tif_close.c +++ b/LibTiff/tif_close.c @@ -1,26 +1,24 @@ -/* $Id: tif_close.c,v 1.10.2.1 2010-06-08 18:50:41 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -28,6 +26,7 @@ * TIFF Library. */ #include "tiffiop.h" +#include /************************************************************************/ /* TIFFCleanup() */ @@ -35,62 +34,101 @@ /** * Auxiliary function to free the TIFF structure. Given structure will be - * completetly freed, so you should save opened file handle and pointer + * 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) +void TIFFCleanup(TIFF *tif) { - if (tif->tif_mode != O_RDONLY) - /* - * Flush buffered data and directory (if dirty). - */ - 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 *link = tif->tif_clientinfo; - - tif->tif_clientinfo = link->next; - _TIFFfree( link->name ); - _TIFFfree( link ); - } - - if (tif->tif_rawdata && (tif->tif_flags&TIFF_MYBUFFER)) - _TIFFfree(tif->tif_rawdata); - if (isMapped(tif)) - TIFFUnmapFileContents(tif, tif->tif_base, tif->tif_size); - - /* Clean up custom fields */ - if (tif->tif_nfields > 0) - { - size_t i; - - for (i = 0; i < tif->tif_nfields; i++) - { - TIFFFieldInfo *fld = tif->tif_fieldinfo[i]; - if (fld->field_bit == FIELD_CUSTOM && - strncmp("Tag ", fld->field_name, 4) == 0) - { - _TIFFfree(fld->field_name); - _TIFFfree(fld); - } - } - - _TIFFfree(tif->tif_fieldinfo); - } - - _TIFFfree(tif); + /* + * Flush buffered data and directory (if dirty). + */ + if (tif->tif_mode != O_RDONLY) + TIFFFlush(tif); + (*tif->tif_cleanup)(tif); + TIFFFreeDirectory(tif); + + _TIFFCleanupIFDOffsetAndNumberMaps(tif); + + /* + * Clean up client info links. + */ + while (tif->tif_clientinfo) + { + TIFFClientInfoLink *psLink = tif->tif_clientinfo; + + tif->tif_clientinfo = psLink->next; + _TIFFfreeExt(tif, psLink->name); + _TIFFfreeExt(tif, psLink); + } + + if (tif->tif_rawdata && (tif->tif_flags & TIFF_MYBUFFER)) + _TIFFfreeExt(tif, 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_name != NULL) + { + if (fld->field_bit == FIELD_CUSTOM && + /* caution: tif_fields[i] must not be the beginning of a + * fields-array. Otherwise the following tags are also freed + * with the first free(). + */ + TIFFFieldIsAnonymous(fld)) + { + _TIFFfreeExt(tif, fld->field_name); + _TIFFfreeExt(tif, fld); + } + } + } + + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, tif->tif_fieldscompat[i].fields); + } + _TIFFfreeExt(tif, tif->tif_fieldscompat); + } + + _TIFFfreeExt(NULL, tif); +} + +/************************************************************************/ +/* _TIFFCleanupIFDOffsetAndNumberMaps() */ +/************************************************************************/ + +void _TIFFCleanupIFDOffsetAndNumberMaps(TIFF *tif) +{ + if (tif->tif_map_dir_offset_to_number) + { + TIFFHashSetDestroy(tif->tif_map_dir_offset_to_number); + tif->tif_map_dir_offset_to_number = NULL; + } + if (tif->tif_map_dir_number_to_offset) + { + TIFFHashSetDestroy(tif->tif_map_dir_number_to_offset); + tif->tif_map_dir_number_to_offset = NULL; + } } /************************************************************************/ @@ -103,24 +141,18 @@ TIFFCleanup(TIFF* tif) * 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) +void TIFFClose(TIFF *tif) { - TIFFCloseProc closeproc = tif->tif_closeproc; - thandle_t fd = tif->tif_clientdata; - - TIFFCleanup(tif); - (void) (*closeproc)(fd); + if (tif != NULL) + { + TIFFCloseProc closeproc = tif->tif_closeproc; + thandle_t fd = tif->tif_clientdata; + + TIFFCleanup(tif); + (void)(*closeproc)(fd); + } } - -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ diff --git a/LibTiff/tif_codec.c b/LibTiff/tif_codec.c index d5c6fd11..d499b63a 100644 --- a/LibTiff/tif_codec.c +++ b/LibTiff/tif_codec.c @@ -1,26 +1,24 @@ -/* $Id: tif_codec.c,v 1.10.2.2 2010-06-08 18:50:41 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,91 +29,102 @@ */ #include "tiffiop.h" -static int NotConfigured(TIFF*, int); +static int NotConfigured(TIFF *, int); -#ifndef LZW_SUPPORT -#define TIFFInitLZW NotConfigured +#ifndef LZW_SUPPORT +#define TIFFInitLZW NotConfigured #endif -#ifndef PACKBITS_SUPPORT -#define TIFFInitPackBits NotConfigured +#ifndef PACKBITS_SUPPORT +#define TIFFInitPackBits NotConfigured #endif -#ifndef THUNDER_SUPPORT -#define TIFFInitThunderScan NotConfigured +#ifndef THUNDER_SUPPORT +#define TIFFInitThunderScan NotConfigured #endif -#ifndef NEXT_SUPPORT -#define TIFFInitNeXT NotConfigured +#ifndef NEXT_SUPPORT +#define TIFFInitNeXT NotConfigured #endif -#ifndef JPEG_SUPPORT -#define TIFFInitJPEG NotConfigured +#ifndef JPEG_SUPPORT +#define TIFFInitJPEG NotConfigured #endif -#ifndef OJPEG_SUPPORT -#define TIFFInitOJPEG NotConfigured +#ifndef OJPEG_SUPPORT +#define TIFFInitOJPEG NotConfigured #endif -#ifndef CCITT_SUPPORT -#define TIFFInitCCITTRLE NotConfigured -#define TIFFInitCCITTRLEW NotConfigured -#define TIFFInitCCITTFax3 NotConfigured -#define TIFFInitCCITTFax4 NotConfigured +#ifndef CCITT_SUPPORT +#define TIFFInitCCITTRLE NotConfigured +#define TIFFInitCCITTRLEW NotConfigured +#define TIFFInitCCITTFax3 NotConfigured +#define TIFFInitCCITTFax4 NotConfigured #endif #ifndef JBIG_SUPPORT -#define TIFFInitJBIG NotConfigured +#define TIFFInitJBIG NotConfigured #endif -#ifndef ZIP_SUPPORT -#define TIFFInitZIP NotConfigured +#ifndef ZIP_SUPPORT +#define TIFFInitZIP NotConfigured #endif -#ifndef PIXARLOG_SUPPORT -#define TIFFInitPixarLog NotConfigured +#ifndef PIXARLOG_SUPPORT +#define TIFFInitPixarLog NotConfigured #endif #ifndef LOGLUV_SUPPORT -#define TIFFInitSGILog NotConfigured +#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. */ -#ifdef VMS const TIFFCodec _TIFFBuiltinCODECS[] = { -#else -TIFFCodec _TIFFBuiltinCODECS[] = { -#endif - { "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 }, - { NULL, 0, NULL } -}; + {"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) +static int _notConfigured(TIFF *tif) { - const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); - char compression_code[20]; - - sprintf( compression_code, "%d", 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); + const TIFFCodec *c = TIFFFindCODEC(tif->tif_dir.td_compression); + char compression_code[20]; + + snprintf(compression_code, sizeof(compression_code), "%" PRIu16, + tif->tif_dir.td_compression); + TIFFErrorExtR(tif, tif->tif_name, + "%s compression support is not configured", + c ? c->name : compression_code); + return (0); } -static int -NotConfigured(TIFF* tif, int scheme) +static int NotConfigured(TIFF *tif, int scheme) { - (void) scheme; - + (void)scheme; + + tif->tif_fixuptags = _notConfigured; tif->tif_decodestatus = FALSE; tif->tif_setupdecode = _notConfigured; tif->tif_encodestatus = FALSE; @@ -129,32 +138,26 @@ NotConfigured(TIFF* tif, int scheme) /** * 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 scheme) +int TIFFIsCODECConfigured(uint16_t scheme) { - const TIFFCodec* codec = TIFFFindCODEC(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; + 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/LibTiff/tif_color.c b/LibTiff/tif_color.c index 02eb346b..2d7dcac6 100644 --- a/LibTiff/tif_color.c +++ b/LibTiff/tif_color.c @@ -1,26 +1,24 @@ -/* $Id: tif_color.c,v 1.12.2.1 2010-06-08 18:50:41 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -42,154 +40,196 @@ /* * Convert color value from the CIE L*a*b* 1976 space to CIE XYZ. */ -void -TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32 l, int32 a, int32 b, - float *X, float *Y, float *Z) +void TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32_t l, int32_t a, int32_t b, + float *X, float *Y, float *Z) { - float L = (float)l * 100.0F / 255.0F; - float cby, tmp; - - if( L < 8.856F ) { - *Y = (L * cielab->Y0) / 903.292F; - cby = 7.787F * (*Y / cielab->Y0) + 16.0F / 116.0F; - } else { - cby = (L + 16.0F) / 116.0F; - *Y = cielab->Y0 * cby * cby * cby; - } - - tmp = (float)a / 500.0F + cby; - if( tmp < 0.2069F ) - *X = cielab->X0 * (tmp - 0.13793F) / 7.787F; - else - *X = cielab->X0 * tmp * tmp * tmp; - - tmp = cby - (float)b / 200.0F; - if( tmp < 0.2069F ) - *Z = cielab->Z0 * (tmp - 0.13793F) / 7.787F; - else - *Z = cielab->Z0 * tmp * tmp * tmp; + TIFFCIELab16ToXYZ(cielab, l * 257, a * 256, b * 256, X, Y, Z); +} + +/* + * For CIELab encoded in 16 bits, L is an unsigned integer range [0,65535]. + * The a* and b* components are signed integers range [-32768,32767]. The 16 + * bit chrominance values are encoded as 256 times the 1976 CIE a* and b* + * values + */ +void TIFFCIELab16ToXYZ(TIFFCIELabToRGB *cielab, uint32_t l, int32_t a, + int32_t b, float *X, float *Y, float *Z) +{ + float L = (float)l * 100.0F / 65535.0F; + float cby, tmp; + + if (L < 8.856F) + { + *Y = (L * cielab->Y0) / 903.292F; + cby = 7.787F * (*Y / cielab->Y0) + 16.0F / 116.0F; + } + else + { + cby = (L + 16.0F) / 116.0F; + *Y = cielab->Y0 * cby * cby * cby; + } + + tmp = (float)a / 256.0F / 500.0F + cby; + if (tmp < 0.2069F) + *X = cielab->X0 * (tmp - 0.13793F) / 7.787F; + else + *X = cielab->X0 * tmp * tmp * tmp; + + tmp = cby - (float)b / 256.0F / 200.0F; + if (tmp < 0.2069F) + *Z = cielab->Z0 * (tmp - 0.13793F) / 7.787F; + else + *Z = cielab->Z0 * tmp * tmp * tmp; } -#define RINT(R) ((uint32)((R)>0?((R)+0.5):((R)-0.5))) +#define RINT(R) ((uint32_t)((R) > 0 ? ((R) + 0.5) : ((R)-0.5))) /* * Convert color value from the XYZ space to RGB. */ -void -TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z, - uint32 *r, uint32 *g, uint32 *b) +void TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z, + uint32_t *r, uint32_t *g, uint32_t *b) { - int i; - float Yr, Yg, Yb; - float *matrix = &cielab->display.d_mat[0][0]; - - /* Multiply through the matrix to get luminosity values. */ - Yr = matrix[0] * X + matrix[1] * Y + matrix[2] * Z; - Yg = matrix[3] * X + matrix[4] * Y + matrix[5] * Z; - Yb = matrix[6] * X + matrix[7] * Y + matrix[8] * Z; - - /* Clip input */ - Yr = TIFFmax(Yr, cielab->display.d_Y0R); - Yg = TIFFmax(Yg, cielab->display.d_Y0G); - Yb = TIFFmax(Yb, cielab->display.d_Y0B); - - /* Avoid overflow in case of wrong input values */ - Yr = TIFFmin(Yr, cielab->display.d_YCR); - Yg = TIFFmin(Yg, cielab->display.d_YCG); - Yb = TIFFmin(Yb, cielab->display.d_YCB); - - /* Turn luminosity to colour value. */ - i = (int)((Yr - cielab->display.d_Y0R) / cielab->rstep); - i = TIFFmin(cielab->range, i); - *r = RINT(cielab->Yr2r[i]); - - i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep); - i = TIFFmin(cielab->range, i); - *g = RINT(cielab->Yg2g[i]); - - i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep); - i = TIFFmin(cielab->range, i); - *b = RINT(cielab->Yb2b[i]); - - /* Clip output. */ - *r = TIFFmin(*r, cielab->display.d_Vrwr); - *g = TIFFmin(*g, cielab->display.d_Vrwg); - *b = TIFFmin(*b, cielab->display.d_Vrwb); + int i; + float Yr, Yg, Yb; + float *matrix = &cielab->display.d_mat[0][0]; + + /* Multiply through the matrix to get luminosity values. */ + Yr = matrix[0] * X + matrix[1] * Y + matrix[2] * Z; + Yg = matrix[3] * X + matrix[4] * Y + matrix[5] * Z; + Yb = matrix[6] * X + matrix[7] * Y + matrix[8] * Z; + + /* Clip input */ + Yr = TIFFmax(Yr, cielab->display.d_Y0R); + Yg = TIFFmax(Yg, cielab->display.d_Y0G); + Yb = TIFFmax(Yb, cielab->display.d_Y0B); + + /* Avoid overflow in case of wrong input values */ + Yr = TIFFmin(Yr, cielab->display.d_YCR); + Yg = TIFFmin(Yg, cielab->display.d_YCG); + Yb = TIFFmin(Yb, cielab->display.d_YCB); + + /* Turn luminosity to colour value. */ + i = (int)((Yr - cielab->display.d_Y0R) / cielab->rstep); + i = TIFFmin(cielab->range, i); + *r = RINT(cielab->Yr2r[i]); + + i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep); + i = TIFFmin(cielab->range, i); + *g = RINT(cielab->Yg2g[i]); + + i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep); + i = TIFFmin(cielab->range, i); + *b = RINT(cielab->Yb2b[i]); + + /* Clip output. */ + *r = TIFFmin(*r, cielab->display.d_Vrwr); + *g = TIFFmin(*g, cielab->display.d_Vrwg); + *b = TIFFmin(*b, cielab->display.d_Vrwb); } #undef RINT -/* +/* * Allocate conversion state structures and make look_up tables for * the Yr,Yb,Yg <=> r,g,b conversions. */ -int -TIFFCIELabToRGBInit(TIFFCIELabToRGB* cielab, - TIFFDisplay *display, float *refWhite) +int TIFFCIELabToRGBInit(TIFFCIELabToRGB *cielab, const TIFFDisplay *display, + float *refWhite) { - int i; - double gamma; - - cielab->range = CIELABTORGB_TABLE_RANGE; - - _TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay)); - - /* Red */ - gamma = 1.0 / cielab->display.d_gammaR ; - cielab->rstep = - (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; - for(i = 0; i <= cielab->range; i++) { - cielab->Yr2r[i] = cielab->display.d_Vrwr - * ((float)pow((double)i / cielab->range, gamma)); - } - - /* Green */ - gamma = 1.0 / cielab->display.d_gammaG ; - cielab->gstep = - (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; - for(i = 0; i <= cielab->range; i++) { - cielab->Yg2g[i] = cielab->display.d_Vrwg - * ((float)pow((double)i / cielab->range, gamma)); - } - - /* Blue */ - gamma = 1.0 / cielab->display.d_gammaB ; - cielab->bstep = - (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; - for(i = 0; i <= cielab->range; i++) { - cielab->Yb2b[i] = cielab->display.d_Vrwb - * ((float)pow((double)i / cielab->range, gamma)); - } - - /* Init reference white point */ - cielab->X0 = refWhite[0]; - cielab->Y0 = refWhite[1]; - cielab->Z0 = refWhite[2]; - - return 0; + int i; + double dfGamma; + + cielab->range = CIELABTORGB_TABLE_RANGE; + + _TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay)); + + /* Red */ + dfGamma = 1.0 / cielab->display.d_gammaR; + cielab->rstep = + (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; + for (i = 0; i <= cielab->range; i++) + { + cielab->Yr2r[i] = cielab->display.d_Vrwr * + ((float)pow((double)i / cielab->range, dfGamma)); + } + + /* Green */ + dfGamma = 1.0 / cielab->display.d_gammaG; + cielab->gstep = + (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; + for (i = 0; i <= cielab->range; i++) + { + cielab->Yg2g[i] = cielab->display.d_Vrwg * + ((float)pow((double)i / cielab->range, dfGamma)); + } + + /* Blue */ + dfGamma = 1.0 / cielab->display.d_gammaB; + cielab->bstep = + (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; + for (i = 0; i <= cielab->range; i++) + { + cielab->Yb2b[i] = cielab->display.d_Vrwb * + ((float)pow((double)i / cielab->range, dfGamma)); + } + + /* Init reference white point */ + cielab->X0 = refWhite[0]; + cielab->Y0 = refWhite[1]; + cielab->Z0 = refWhite[2]; + + return 0; } -/* - * Convert color value from the YCbCr space to CIE XYZ. +/* + * Convert color value from the YCbCr space to RGB. * The colorspace conversion algorithm comes from the IJG v5a code; * see below for more information on how it works. */ -#define SHIFT 16 -#define FIX(x) ((int32)((x) * (1L<(max)?(max):(f)) -#define HICLAMP(f,max) ((f)>(max)?(max):(f)) - -void -TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32 Y, int32 Cb, int32 Cr, - uint32 *r, uint32 *g, uint32 *b) +#define SHIFT 16 +#define FIX(x) ((int32_t)((x) * (1L << SHIFT) + 0.5)) +#define ONE_HALF ((int32_t)(1 << (SHIFT - 1))) +#define Code2V(c, RB, RW, CR) \ + ((((c) - (int32_t)(RB)) * (float)(CR)) / \ + (float)(((RW) - (RB) != 0) ? ((RW) - (RB)) : 1)) +/* !((f)>=(min)) written that way to deal with NaN */ +#define CLAMP(f, min, max) \ + ((!((f) >= (min))) ? (min) : (f) > (max) ? (max) : (f)) +#define HICLAMP(f, max) ((f) > (max) ? (max) : (f)) + +void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32_t Y, int32_t Cb, int32_t Cr, + uint32_t *r, uint32_t *g, uint32_t *b) { - /* XXX: Only 8-bit YCbCr input supported for now */ - Y = HICLAMP(Y, 255), Cb = CLAMP(Cb, 0, 255), Cr = CLAMP(Cr, 0, 255); + int32_t i; + + /* XXX: Only 8-bit YCbCr input supported for now */ + Y = HICLAMP(Y, 255); + Cb = CLAMP(Cb, 0, 255); + Cr = CLAMP(Cr, 0, 255); + + i = ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr]; + *r = CLAMP(i, 0, 255); + i = ycbcr->Y_tab[Y] + + (int)((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT); + *g = CLAMP(i, 0, 255); + i = ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb]; + *b = CLAMP(i, 0, 255); +} - *r = ycbcr->clamptab[ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr]]; - *g = ycbcr->clamptab[ycbcr->Y_tab[Y] - + (int)((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT)]; - *b = ycbcr->clamptab[ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb]]; +/* Clamp function for sanitization purposes. Normally clamping should not */ +/* occur for well behaved chroma and refBlackWhite coefficients */ +static float CLAMPw(float v, float vmin, float vmax) +{ + if (v < vmin) + { + /* printf("%f clamped to %f\n", v, vmin); */ + return vmin; + } + if (v > vmax) + { + /* printf("%f clamped to %f\n", v, vmax); */ + return vmax; + } + return v; } /* @@ -208,75 +248,75 @@ TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32 Y, int32 Cb, int32 Cr, * pre-calculating possible values indexed by Cb and Cr (this code * assumes conversion is being done for 8-bit samples). */ -int -TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, float *luma, float *refBlackWhite) +int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB *ycbcr, float *luma, float *refBlackWhite) { - TIFFRGBValue* clamptab; + TIFFRGBValue *clamptab; int i; - -#define LumaRed luma[0] -#define LumaGreen luma[1] -#define LumaBlue luma[2] - - clamptab = (TIFFRGBValue*)( - (tidata_t) ycbcr+TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long))); - _TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */ + +#define LumaRed luma[0] +#define LumaGreen luma[1] +#define LumaBlue luma[2] + + clamptab = + (TIFFRGBValue *)((uint8_t *)ycbcr + + TIFFroundup_32(sizeof(TIFFYCbCrToRGB), sizeof(long))); + _TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */ ycbcr->clamptab = (clamptab += 256); for (i = 0; i < 256; i++) - clamptab[i] = (TIFFRGBValue) i; - _TIFFmemset(clamptab+256, 255, 2*256); /* v > 255 => 255 */ - ycbcr->Cr_r_tab = (int*) (clamptab + 3*256); + clamptab[i] = (TIFFRGBValue)i; + _TIFFmemset(clamptab + 256, 255, 2 * 256); /* v > 255 => 255 */ + ycbcr->Cr_r_tab = (int *)(clamptab + 3 * 256); ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256; - ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256); + ycbcr->Cr_g_tab = (int32_t *)(ycbcr->Cb_b_tab + 256); ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256; ycbcr->Y_tab = ycbcr->Cb_g_tab + 256; - { float f1 = 2-2*LumaRed; int32 D1 = FIX(f1); - float f2 = LumaRed*f1/LumaGreen; int32 D2 = -FIX(f2); - float f3 = 2-2*LumaBlue; int32 D3 = FIX(f3); - float f4 = LumaBlue*f3/LumaGreen; int32 D4 = -FIX(f4); - int x; + { + float f1 = 2 - 2 * LumaRed; + int32_t D1 = FIX(CLAMP(f1, 0.0F, 2.0F)); + float f2 = LumaRed * f1 / LumaGreen; + int32_t D2 = -FIX(CLAMP(f2, 0.0F, 2.0F)); + float f3 = 2 - 2 * LumaBlue; + int32_t D3 = FIX(CLAMP(f3, 0.0F, 2.0F)); + float f4 = LumaBlue * f3 / LumaGreen; + int32_t D4 = -FIX(CLAMP(f4, 0.0F, 2.0F)); + int x; #undef LumaBlue #undef LumaGreen #undef LumaRed - - /* - * i is the actual input pixel value in the range 0..255 - * Cb and Cr values are in the range -128..127 (actually - * they are in a range defined by the ReferenceBlackWhite - * tag) so there is some range shifting to do here when - * constructing tables indexed by the raw pixel data. - */ - for (i = 0, x = -128; i < 256; i++, x++) { - int32 Cr = (int32)Code2V(x, refBlackWhite[4] - 128.0F, - refBlackWhite[5] - 128.0F, 127); - int32 Cb = (int32)Code2V(x, refBlackWhite[2] - 128.0F, - refBlackWhite[3] - 128.0F, 127); - - ycbcr->Cr_r_tab[i] = (int32)((D1*Cr + ONE_HALF)>>SHIFT); - ycbcr->Cb_b_tab[i] = (int32)((D3*Cb + ONE_HALF)>>SHIFT); - ycbcr->Cr_g_tab[i] = D2*Cr; - ycbcr->Cb_g_tab[i] = D4*Cb + ONE_HALF; - ycbcr->Y_tab[i] = - (int32)Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255); - } + + /* + * i is the actual input pixel value in the range 0..255 + * Cb and Cr values are in the range -128..127 (actually + * they are in a range defined by the ReferenceBlackWhite + * tag) so there is some range shifting to do here when + * constructing tables indexed by the raw pixel data. + */ + for (i = 0, x = -128; i < 256; i++, x++) + { + int32_t Cr = (int32_t)CLAMPw(Code2V(x, refBlackWhite[4] - 128.0F, + refBlackWhite[5] - 128.0F, 127), + -128.0F * 32, 128.0F * 32); + int32_t Cb = (int32_t)CLAMPw(Code2V(x, refBlackWhite[2] - 128.0F, + refBlackWhite[3] - 128.0F, 127), + -128.0F * 32, 128.0F * 32); + + ycbcr->Cr_r_tab[i] = (int32_t)((D1 * Cr + ONE_HALF) >> SHIFT); + ycbcr->Cb_b_tab[i] = (int32_t)((D3 * Cb + ONE_HALF) >> SHIFT); + ycbcr->Cr_g_tab[i] = D2 * Cr; + ycbcr->Cb_g_tab[i] = D4 * Cb + ONE_HALF; + ycbcr->Y_tab[i] = (int32_t)CLAMPw( + Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255), + -128.0F * 32, 128.0F * 32); + } } return 0; } -#undef HICLAMP -#undef CLAMP -#undef Code2V -#undef SHIFT -#undef ONE_HALF -#undef FIX - -/* vim: set ts=8 sts=8 sw=8 noet: */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ +#undef HICLAMP +#undef CLAMP +#undef Code2V +#undef SHIFT +#undef ONE_HALF +#undef FIX diff --git a/LibTiff/tif_compress.c b/LibTiff/tif_compress.c index 0ce509b0..c6e17d3e 100644 --- a/LibTiff/tif_compress.c +++ b/LibTiff/tif_compress.c @@ -1,26 +1,24 @@ -/* $Id: tif_compress.c,v 1.13.2.1 2010-06-08 18:50:41 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,137 +29,152 @@ */ #include "tiffiop.h" -static int -TIFFNoEncode(TIFF* tif, const char* method) +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 %u %s encoding is not implemented", - tif->tif_dir.td_compression, method); - } - return (-1); + const TIFFCodec *c = TIFFFindCODEC(tif->tif_dir.td_compression); + + if (c) + { + TIFFErrorExtR(tif, tif->tif_name, "%s %s encoding is not implemented", + c->name, method); + } + else + { + TIFFErrorExtR(tif, tif->tif_name, + "Compression scheme %" PRIu16 + " %s encoding is not implemented", + tif->tif_dir.td_compression, method); + } + return (-1); } -int -_TIFFNoRowEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +int _TIFFNoRowEncode(TIFF *tif, uint8_t *pp, tmsize_t cc, uint16_t s) { - (void) pp; (void) cc; (void) s; - return (TIFFNoEncode(tif, "scanline")); + (void)pp; + (void)cc; + (void)s; + return (TIFFNoEncode(tif, "scanline")); } -int -_TIFFNoStripEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +int _TIFFNoStripEncode(TIFF *tif, uint8_t *pp, tmsize_t cc, uint16_t s) { - (void) pp; (void) cc; (void) s; - return (TIFFNoEncode(tif, "strip")); + (void)pp; + (void)cc; + (void)s; + return (TIFFNoEncode(tif, "strip")); } -int -_TIFFNoTileEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +int _TIFFNoTileEncode(TIFF *tif, uint8_t *pp, tmsize_t cc, uint16_t s) { - (void) pp; (void) cc; (void) s; - return (TIFFNoEncode(tif, "tile")); + (void)pp; + (void)cc; + (void)s; + return (TIFFNoEncode(tif, "tile")); } -static int -TIFFNoDecode(TIFF* tif, const char* method) +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 %u %s decoding is not implemented", - tif->tif_dir.td_compression, method); - return (-1); + const TIFFCodec *c = TIFFFindCODEC(tif->tif_dir.td_compression); + + if (c) + TIFFErrorExtR(tif, tif->tif_name, "%s %s decoding is not implemented", + c->name, method); + else + TIFFErrorExtR(tif, tif->tif_name, + "Compression scheme %" PRIu16 + " %s decoding is not implemented", + tif->tif_dir.td_compression, method); + return (0); } -int -_TIFFNoRowDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +static int _TIFFNoFixupTags(TIFF *tif) { - (void) pp; (void) cc; (void) s; - return (TIFFNoDecode(tif, "scanline")); + (void)tif; + return (1); } -int -_TIFFNoStripDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +int _TIFFNoRowDecode(TIFF *tif, uint8_t *pp, tmsize_t cc, uint16_t s) { - (void) pp; (void) cc; (void) s; - return (TIFFNoDecode(tif, "strip")); + (void)pp; + (void)cc; + (void)s; + return (TIFFNoDecode(tif, "scanline")); } -int -_TIFFNoTileDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +int _TIFFNoStripDecode(TIFF *tif, uint8_t *pp, tmsize_t cc, uint16_t s) { - (void) pp; (void) cc; (void) s; - return (TIFFNoDecode(tif, "tile")); + (void)pp; + (void)cc; + (void)s; + return (TIFFNoDecode(tif, "strip")); } -int -_TIFFNoSeek(TIFF* tif, uint32 off) +int _TIFFNoTileDecode(TIFF *tif, uint8_t *pp, tmsize_t cc, uint16_t s) { - (void) off; - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Compression algorithm does not support random access"); - return (0); + (void)pp; + (void)cc; + (void)s; + return (TIFFNoDecode(tif, "tile")); } -int -_TIFFNoPreCode(TIFF* tif, tsample_t s) +int _TIFFNoSeek(TIFF *tif, uint32_t off) { - (void) tif; (void) s; - return (1); + (void)off; + TIFFErrorExtR(tif, tif->tif_name, + "Compression algorithm does not support random access"); + return (0); } -static int _TIFFtrue(TIFF* tif) { (void) tif; return (1); } -static void _TIFFvoid(TIFF* tif) { (void) tif; } +int _TIFFNoPreCode(TIFF *tif, uint16_t s) +{ + (void)tif; + (void)s; + return (1); +} -void -_TIFFSetDefaultCompressionState(TIFF* tif) +static int _TIFFtrue(TIFF *tif) { - 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); + (void)tif; + return (1); } +static void _TIFFvoid(TIFF *tif) { (void)tif; } -int -TIFFSetCompressionScheme(TIFF* tif, int scheme) +void _TIFFSetDefaultCompressionState(TIFF *tif) { - const TIFFCodec *c = TIFFFindCODEC((uint16) scheme); + 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); +} - _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); +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); } /* @@ -169,64 +182,68 @@ TIFFSetCompressionScheme(TIFF* tif, int scheme) * schemes can also override the builtin versions provided * by this library. */ -typedef struct _codec { - struct _codec* next; - TIFFCodec* info; +typedef struct _codec +{ + struct _codec *next; + TIFFCodec *info; } codec_t; -static codec_t* registeredCODECS = NULL; +static codec_t *registeredCODECS = NULL; -const TIFFCodec* -TIFFFindCODEC(uint16 scheme) +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); + 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 scheme, const char* name, TIFFInitMethod init) +TIFFCodec *TIFFRegisterCODEC(uint16_t scheme, const char *name, + TIFFInitMethod init) { - codec_t* cd = (codec_t*) - _TIFFmalloc(sizeof (codec_t) + sizeof (TIFFCodec) + strlen(name)+1); - - if (cd != NULL) { - cd->info = (TIFFCodec*) ((tidata_t) cd + sizeof (codec_t)); - cd->info->name = (char*) - ((tidata_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); + codec_t *cd = (codec_t *)_TIFFmallocExt( + NULL, + (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) +void TIFFUnRegisterCODEC(TIFFCodec *c) { - codec_t* cd; - codec_t** pcd; - - for (pcd = ®isteredCODECS; (cd = *pcd); 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); + codec_t *cd; + codec_t **pcd; + + for (pcd = ®isteredCODECS; (cd = *pcd) != NULL; pcd = &cd->next) + if (cd->info == c) + { + *pcd = cd->next; + _TIFFfreeExt(NULL, cd); + return; + } + TIFFErrorExt(0, "TIFFUnRegisterCODEC", + "Cannot remove compression scheme %s; not registered", + c->name); } /************************************************************************/ @@ -236,60 +253,58 @@ TIFFUnRegisterCODEC(TIFFCodec* c) /** * 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() +TIFFCodec *TIFFGetConfiguredCODECs() { - int i = 1; - codec_t *cd; - const TIFFCodec *c; - TIFFCodec *codecs = NULL, *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, 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 tdata_t)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; + 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 *)_TIFFreallocExt(NULL, codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) + { + _TIFFfreeExt(NULL, 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 *)_TIFFreallocExt(NULL, codecs, + i * sizeof(TIFFCodec)); + if (!new_codecs) + { + _TIFFfreeExt(NULL, codecs); + return NULL; + } + codecs = new_codecs; + _TIFFmemcpy(codecs + i - 1, (const void *)c, sizeof(TIFFCodec)); + i++; + } + } + + new_codecs = + (TIFFCodec *)_TIFFreallocExt(NULL, codecs, i * sizeof(TIFFCodec)); + if (!new_codecs) + { + _TIFFfreeExt(NULL, 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/LibTiff/tif_config.h b/LibTiff/tif_config.h index 9e3880fb..544e0236 100644 --- a/LibTiff/tif_config.h +++ b/LibTiff/tif_config.h @@ -1,19 +1,22 @@ -/* Define to 1 if you have the header file. */ -#define HAVE_ASSERT_H 1 +/* clang-format off */ +/* clang-format disabled because CMake scripts are very sensitive to the + * formatting of this file. configure_file variables of type "" are + * modified by clang-format and won't be substituted. + */ -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 +/* libtiff/tif_config.h.cmake.in. Not generated, but originated from autoheader. */ +/* This file must be kept up-to-date with needed substitutions from libtiff/tif_config.h.in. */ -/* Define as 0 or 1 according to the floating point format suported by the - machine */ -#define HAVE_IEEEFP 1 +#include "tiffconf.h" -/* Define to 1 if you have the `jbg_newlen' function. */ -#define HAVE_JBG_NEWLEN 1 +/* Support C++ stream API (requires C++ compiler) */ +#define CXX_SUPPORT 1 -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 @@ -22,46 +25,61 @@ #define HAVE_IO_H 1 #endif -/* Define to 1 if you have the header file. */ -#define HAVE_SEARCH_H 1 -/* Define to 1 if you have the `setmode' function. */ -#define HAVE_SETMODE 1 -/* The size of a `int', as computed by sizeof. */ -#define SIZEOF_INT 4 +/* 12bit libjpeg primary include file with path */ +#define LIBJPEG_12_PATH "" -/* The size of a `long', as computed by sizeof. */ -#define SIZEOF_LONG 4 +/* Name of package */ +#define PACKAGE "LibTIFF Software" -/* Signed 64-bit type */ -//#define TIFF_INT64_T signed long long +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "tiff@lists.osgeo.org" -/* Unsigned 64-bit type */ -//#define TIFF_UINT64_T unsigned long long +/* Define to the full name of this package. */ +#define PACKAGE_NAME "LibTIFF Software" -/* Set the native cpu bit order */ -#define HOST_FILLORDER FILLORDER_LSB2MSB +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "tiff" -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ +/* Define to the home page for this package. */ +#define PACKAGE_URL "" -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -# ifndef inline -# define inline __inline +/* Size of size_t */ +#define SIZEOF_SIZE_T 8 + + +/** Maximum number of TIFF IFDs that libtiff can iterate through in a file. */ +#define TIFF_MAX_DIR_COUNT 1048576 + + +/* 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 -#if (defined(_WIN32) || defined(WIN32)) -#define lfind _lfind +#if !defined(__MINGW32__) +# define TIFF_SIZE_FORMAT "zu" #endif -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ +#if SIZEOF_SIZE_T == 8 +# define TIFF_SSIZE_FORMAT PRId64 +# if defined(__MINGW32__) +# define TIFF_SIZE_FORMAT PRIu64 +# endif +#elif SIZEOF_SIZE_T == 4 +# define TIFF_SSIZE_FORMAT PRId32 +# if defined(__MINGW32__) +# define TIFF_SIZE_FORMAT PRIu32 +# endif +#else +# error "Unsupported size_t size; please submit a bug report" +#endif + +/* clang-format on */ diff --git a/LibTiff/tif_dir.c b/LibTiff/tif_dir.c index ac44b381..85006218 100644 --- a/LibTiff/tif_dir.c +++ b/LibTiff/tif_dir.c @@ -1,26 +1,24 @@ -/* $Id: tif_dir.c,v 1.75.2.5 2010-06-09 21:15:27 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,423 +29,715 @@ * (and also some miscellaneous stuff) */ #include "tiffiop.h" +#include /*--: for Rational2Double */ +#include /* * 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 */ +#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(TIFF *tif, void **vpp, const void *vp, size_t nmemb, + size_t elem_size) +{ + if (*vpp) + { + _TIFFfreeExt(tif, *vpp); + *vpp = 0; + } + if (vp) + { + tmsize_t bytes = _TIFFMultiplySSize(NULL, nmemb, elem_size, NULL); + if (bytes) + *vpp = (void *)_TIFFmallocExt(tif, bytes); + if (*vpp) + _TIFFmemcpy(*vpp, vp, bytes); + } +} +void _TIFFsetByteArray(void **vpp, const void *vp, uint32_t n) +{ + setByteArray(NULL, vpp, vp, n, 1); +} +void _TIFFsetByteArrayExt(TIFF *tif, void **vpp, const void *vp, uint32_t n) +{ + setByteArray(tif, vpp, vp, n, 1); +} + +static void _TIFFsetNString(TIFF *tif, char **cpp, const char *cp, uint32_t n) +{ + setByteArray(tif, (void **)cpp, cp, n, 1); +} + +void _TIFFsetShortArray(uint16_t **wpp, const uint16_t *wp, uint32_t n) +{ + setByteArray(NULL, (void **)wpp, wp, n, sizeof(uint16_t)); +} +void _TIFFsetShortArrayExt(TIFF *tif, uint16_t **wpp, const uint16_t *wp, + uint32_t n) +{ + setByteArray(tif, (void **)wpp, wp, n, sizeof(uint16_t)); +} + +void _TIFFsetLongArray(uint32_t **lpp, const uint32_t *lp, uint32_t n) +{ + setByteArray(NULL, (void **)lpp, lp, n, sizeof(uint32_t)); +} +void _TIFFsetLongArrayExt(TIFF *tif, uint32_t **lpp, const uint32_t *lp, + uint32_t n) +{ + setByteArray(tif, (void **)lpp, lp, n, sizeof(uint32_t)); +} -static void -setByteArray(void** vpp, void* vp, size_t nmemb, size_t elem_size) +static void _TIFFsetLong8Array(TIFF *tif, uint64_t **lpp, const uint64_t *lp, + uint32_t n) { - if (*vpp) - _TIFFfree(*vpp), *vpp = 0; - if (vp) { - tsize_t bytes = nmemb * elem_size; - if (elem_size && bytes / elem_size == nmemb) - *vpp = (void*) _TIFFmalloc(bytes); - if (*vpp) - _TIFFmemcpy(*vpp, vp, bytes); - } + setByteArray(tif, (void **)lpp, lp, n, sizeof(uint64_t)); +} + +void _TIFFsetFloatArray(float **fpp, const float *fp, uint32_t n) +{ + setByteArray(NULL, (void **)fpp, fp, n, sizeof(float)); +} +void _TIFFsetFloatArrayExt(TIFF *tif, float **fpp, const float *fp, uint32_t n) +{ + setByteArray(tif, (void **)fpp, fp, n, sizeof(float)); +} + +void _TIFFsetDoubleArray(double **dpp, const double *dp, uint32_t n) +{ + setByteArray(NULL, (void **)dpp, dp, n, sizeof(double)); +} +void _TIFFsetDoubleArrayExt(TIFF *tif, double **dpp, const double *dp, + uint32_t n) +{ + setByteArray(tif, (void **)dpp, dp, n, sizeof(double)); +} + +static void setDoubleArrayOneValue(TIFF *tif, double **vpp, double value, + size_t nmemb) +{ + if (*vpp) + _TIFFfreeExt(tif, *vpp); + *vpp = _TIFFmallocExt(tif, nmemb * sizeof(double)); + if (*vpp) + { + while (nmemb--) + ((double *)*vpp)[nmemb] = value; + } } -void _TIFFsetByteArray(void** vpp, void* vp, uint32 n) - { setByteArray(vpp, vp, n, 1); } -void _TIFFsetString(char** cpp, char* cp) - { setByteArray((void**) cpp, (void*) cp, strlen(cp)+1, 1); } -void _TIFFsetNString(char** cpp, char* cp, uint32 n) - { setByteArray((void**) cpp, (void*) cp, n, 1); } -void _TIFFsetShortArray(uint16** wpp, uint16* wp, uint32 n) - { setByteArray((void**) wpp, (void*) wp, n, sizeof (uint16)); } -void _TIFFsetLongArray(uint32** lpp, uint32* lp, uint32 n) - { setByteArray((void**) lpp, (void*) lp, n, sizeof (uint32)); } -void _TIFFsetFloatArray(float** fpp, float* fp, uint32 n) - { setByteArray((void**) fpp, (void*) fp, n, sizeof (float)); } -void _TIFFsetDoubleArray(double** dpp, double* dp, uint32 n) - { setByteArray((void**) dpp, (void*) dp, n, sizeof (double)); } /* * Install extra samples information. */ -static int -setExtraSamples(TIFFDirectory* td, va_list ap, uint32* v) +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* va; - uint32 i; - - *v = va_arg(ap, uint32); - if ((uint16) *v > td->td_samplesperpixel) - return 0; - va = va_arg(ap, uint16*); - 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; - } - } - td->td_extrasamples = (uint16) *v; - _TIFFsetShortArray(&td->td_sampleinfo, va, td->td_extrasamples); - return 1; +#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)) + { + TIFFWarningExtR(tif, module, + "ExtraSamples tag value is changing, " + "but TransferFunction was read with a different value. " + "Canceling it"); + TIFFClrFieldBit(tif, FIELD_TRANSFERFUNCTION); + _TIFFfreeExt(tif, td->td_transferfunction[0]); + td->td_transferfunction[0] = NULL; + } + + td->td_extrasamples = (uint16_t)*v; + _TIFFsetShortArrayExt(tif, &td->td_sampleinfo, va, td->td_extrasamples); + return 1; #undef EXTRASAMPLE_COREL_UNASSALPHA } -static uint32 -checkInkNamesString(TIFF* tif, uint32 slen, const char* s) +/* + * Count ink names separated by \0. Returns + * zero if the ink names are not as expected. + */ +static uint16_t countInkNamesString(TIFF *tif, uint32_t slen, const char *s) { - TIFFDirectory* td = &tif->tif_dir; - uint16 i = td->td_samplesperpixel; - - if (slen > 0) { - const char* ep = s+slen; - const char* cp = s; - for (; i > 0; i--) { - for (; *cp != '\0'; cp++) - if (cp >= ep) - goto bad; - cp++; /* skip \0 */ - } - return (cp-s); - } + uint16_t i = 0; + + if (slen > 0) + { + const char *ep = s + slen; + const char *cp = s; + do + { + for (; cp < ep && *cp != '\0'; cp++) + { + } + if (cp >= ep) + goto bad; + cp++; /* skip \0 */ + i++; + } while (cp < ep); + return (i); + } bad: - TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", - "%s: Invalid InkNames value; expecting %d names, found %d", - tif->tif_name, - td->td_samplesperpixel, - td->td_samplesperpixel-i); - return (0); + TIFFErrorExtR(tif, "TIFFSetField", + "%s: Invalid InkNames value; no NUL at given buffer end " + "location %" PRIu32 ", after %" PRIu16 " ink", + tif->tif_name, slen, i); + return (0); } -static int -_TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap) +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 v32, i, v; - char* s; - - switch (tag) { - case TIFFTAG_SUBFILETYPE: - td->td_subfiletype = va_arg(ap, uint32); - break; - case TIFFTAG_IMAGEWIDTH: - td->td_imagewidth = va_arg(ap, uint32); - break; - case TIFFTAG_IMAGELENGTH: - td->td_imagelength = va_arg(ap, uint32); - break; - case TIFFTAG_BITSPERSAMPLE: - td->td_bitspersample = (uint16) va_arg(ap, int); - /* - * 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 behaviour - * 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 == 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 = va_arg(ap, uint32) & 0xffff; - /* - * 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 (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) v; - else - status = 0; - break; - case TIFFTAG_PHOTOMETRIC: - td->td_photometric = (uint16) va_arg(ap, int); - break; - case TIFFTAG_THRESHHOLDING: - td->td_threshholding = (uint16) va_arg(ap, int); - break; - case TIFFTAG_FILLORDER: - v = va_arg(ap, uint32); - if (v != FILLORDER_LSB2MSB && v != FILLORDER_MSB2LSB) - goto badvalue; - td->td_fillorder = (uint16) v; - break; - case TIFFTAG_ORIENTATION: - v = va_arg(ap, uint32); - if (v < ORIENTATION_TOPLEFT || ORIENTATION_LEFTBOT < v) - goto badvalue; - else - td->td_orientation = (uint16) v; - break; - case TIFFTAG_SAMPLESPERPIXEL: - /* XXX should cross check -- e.g. if pallette, then 1 */ - v = va_arg(ap, uint32); - if (v == 0) - goto badvalue; - td->td_samplesperpixel = (uint16) v; - break; - case TIFFTAG_ROWSPERSTRIP: - v32 = va_arg(ap, uint32); - 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) va_arg(ap, int); - break; - case TIFFTAG_MAXSAMPLEVALUE: - td->td_maxsamplevalue = (uint16) va_arg(ap, int); - break; - case TIFFTAG_SMINSAMPLEVALUE: - td->td_sminsamplevalue = va_arg(ap, double); - break; - case TIFFTAG_SMAXSAMPLEVALUE: - td->td_smaxsamplevalue = va_arg(ap, double); - break; - case TIFFTAG_XRESOLUTION: - td->td_xresolution = (float) va_arg(ap, double); - break; - case TIFFTAG_YRESOLUTION: - td->td_yresolution = (float) va_arg(ap, double); - break; - case TIFFTAG_PLANARCONFIG: - v = va_arg(ap, uint32); - if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE) - goto badvalue; - td->td_planarconfig = (uint16) v; - break; - case TIFFTAG_XPOSITION: - td->td_xposition = (float) va_arg(ap, double); - break; - case TIFFTAG_YPOSITION: - td->td_yposition = (float) va_arg(ap, double); - break; - case TIFFTAG_RESOLUTIONUNIT: - v = va_arg(ap, uint32); - if (v < RESUNIT_NONE || RESUNIT_CENTIMETER < v) - goto badvalue; - td->td_resolutionunit = (uint16) v; - break; - case TIFFTAG_PAGENUMBER: - td->td_pagenumber[0] = (uint16) va_arg(ap, int); - td->td_pagenumber[1] = (uint16) va_arg(ap, int); - break; - case TIFFTAG_HALFTONEHINTS: - td->td_halftonehints[0] = (uint16) va_arg(ap, int); - td->td_halftonehints[1] = (uint16) va_arg(ap, int); - break; - case TIFFTAG_COLORMAP: - v32 = (uint32)(1L<td_bitspersample); - _TIFFsetShortArray(&td->td_colormap[0], va_arg(ap, uint16*), v32); - _TIFFsetShortArray(&td->td_colormap[1], va_arg(ap, uint16*), v32); - _TIFFsetShortArray(&td->td_colormap[2], va_arg(ap, uint16*), v32); - break; - case TIFFTAG_EXTRASAMPLES: - if (!setExtraSamples(td, ap, &v)) - goto badvalue; - break; - case TIFFTAG_MATTEING: - td->td_extrasamples = (uint16) (va_arg(ap, int) != 0); - if (td->td_extrasamples) { - uint16 sv = EXTRASAMPLE_ASSOCALPHA; - _TIFFsetShortArray(&td->td_sampleinfo, &sv, 1); - } - break; - case TIFFTAG_TILEWIDTH: - v32 = va_arg(ap, uint32); - if (v32 % 16) { - if (tif->tif_mode != O_RDONLY) - goto badvalue32; - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, - "Nonstandard tile width %d, convert file", v32); - } - td->td_tilewidth = v32; - tif->tif_flags |= TIFF_ISTILED; - break; - case TIFFTAG_TILELENGTH: - v32 = va_arg(ap, uint32); - if (v32 % 16) { - if (tif->tif_mode != O_RDONLY) - goto badvalue32; - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, - "Nonstandard tile length %d, convert file", v32); - } - td->td_tilelength = v32; - tif->tif_flags |= TIFF_ISTILED; - break; - case TIFFTAG_TILEDEPTH: - v32 = va_arg(ap, uint32); - if (v32 == 0) - goto badvalue32; - td->td_tiledepth = v32; - break; - case TIFFTAG_DATATYPE: - v = va_arg(ap, uint32); - 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) v; - break; - case TIFFTAG_SAMPLEFORMAT: - v = va_arg(ap, uint32); - if (v < SAMPLEFORMAT_UINT || SAMPLEFORMAT_COMPLEXIEEEFP < v) - goto badvalue; - td->td_sampleformat = (uint16) 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 ) + static const char module[] = "_TIFFVSetField"; + + TIFFDirectory *td = &tif->tif_dir; + int status = 1; + uint32_t v32, 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_sampleformat == SAMPLEFORMAT_COMPLEXINT - || td->td_sampleformat == SAMPLEFORMAT_COMPLEXIEEEFP) - && td->td_bitspersample == 64 - && tif->tif_postdecode == _TIFFSwab64BitData ) + else if (td->td_bitspersample == 24) + tif->tif_postdecode = _TIFFSwab24BitData; + else if (td->td_bitspersample == 32) tif->tif_postdecode = _TIFFSwab32BitData; - break; - case TIFFTAG_IMAGEDEPTH: - td->td_imagedepth = va_arg(ap, uint32); - break; - case TIFFTAG_SUBIFD: - if ((tif->tif_flags & TIFF_INSUBIFD) == 0) { - td->td_nsubifd = (uint16) va_arg(ap, int); - _TIFFsetLongArray(&td->td_subifd, va_arg(ap, uint32*), - (long) 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) va_arg(ap, int); - break; - case TIFFTAG_YCBCRSUBSAMPLING: - td->td_ycbcrsubsampling[0] = (uint16) va_arg(ap, int); - td->td_ycbcrsubsampling[1] = (uint16) va_arg(ap, int); - 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*), 1L<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 = va_arg(ap, uint32); - 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; - default: { + 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, 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) + { + TIFFWarningExtR(tif, module, + "SamplesPerPixel tag value is changing, " + "but SMinSampleValue tag was read with a " + "different value. Canceling it"); + TIFFClrFieldBit(tif, FIELD_SMINSAMPLEVALUE); + _TIFFfreeExt(tif, td->td_sminsamplevalue); + td->td_sminsamplevalue = NULL; + } + if (td->td_smaxsamplevalue != NULL) + { + TIFFWarningExtR(tif, module, + "SamplesPerPixel tag value is changing, " + "but SMaxSampleValue tag was read with a " + "different value. Canceling it"); + TIFFClrFieldBit(tif, FIELD_SMAXSAMPLEVALUE); + _TIFFfreeExt(tif, 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)) + { + TIFFWarningExtR(tif, module, + "SamplesPerPixel tag value is changing, " + "but TransferFunction was read with a " + "different value. Canceling it"); + TIFFClrFieldBit(tif, FIELD_TRANSFERFUNCTION); + _TIFFfreeExt(tif, 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) + _TIFFsetDoubleArrayExt(tif, &td->td_sminsamplevalue, + va_arg(ap, double *), + td->td_samplesperpixel); + else + setDoubleArrayOneValue(tif, &td->td_sminsamplevalue, + va_arg(ap, double), + td->td_samplesperpixel); + break; + case TIFFTAG_SMAXSAMPLEVALUE: + if (tif->tif_flags & TIFF_PERSAMPLE) + _TIFFsetDoubleArrayExt(tif, &td->td_smaxsamplevalue, + va_arg(ap, double *), + td->td_samplesperpixel); + else + setDoubleArrayOneValue(tif, &td->td_smaxsamplevalue, + va_arg(ap, double), + td->td_samplesperpixel); + break; + case TIFFTAG_XRESOLUTION: + dblval = va_arg(ap, double); + if (dblval != dblval || dblval < 0) + goto badvaluedouble; + td->td_xresolution = _TIFFClampDoubleToFloat(dblval); + break; + case TIFFTAG_YRESOLUTION: + dblval = va_arg(ap, double); + if (dblval != dblval || 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); + _TIFFsetShortArrayExt(tif, &td->td_colormap[0], + va_arg(ap, uint16_t *), v32); + _TIFFsetShortArrayExt(tif, &td->td_colormap[1], + va_arg(ap, uint16_t *), v32); + _TIFFsetShortArrayExt(tif, &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; + _TIFFsetShortArrayExt(tif, &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; + TIFFWarningExtR( + tif, 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; + TIFFWarningExtR( + tif, 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(tif, &td->td_subifd, + (uint64_t *)va_arg(ap, uint64_t *), + (uint32_t)td->td_nsubifd); + } + else + { + TIFFErrorExtR(tif, 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: + { + uint32_t i; + v = (td->td_samplesperpixel - td->td_extrasamples) > 1 ? 3 : 1; + for (i = 0; i < v; i++) + _TIFFsetShortArrayExt(tif, &td->td_transferfunction[i], + va_arg(ap, uint16_t *), + 1U << td->td_bitspersample); + break; + } + case TIFFTAG_REFERENCEBLACKWHITE: + /* XXX should check for null range */ + _TIFFsetFloatArrayExt(tif, &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 *); + uint16_t ninksinstring; + ninksinstring = countInkNamesString(tif, v, s); + status = ninksinstring > 0; + if (ninksinstring > 0) + { + _TIFFsetNString(tif, &td->td_inknames, s, v); + td->td_inknameslen = v; + /* Set NumberOfInks to the value ninksinstring */ + if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS)) + { + if (td->td_numberofinks != ninksinstring) + { + TIFFErrorExtR( + tif, module, + "Warning %s; Tag %s:\n Value %" PRIu16 + " of NumberOfInks is different from the number of " + "inks %" PRIu16 + ".\n -> NumberOfInks value adapted to %" PRIu16 "", + tif->tif_name, fip->field_name, td->td_numberofinks, + ninksinstring, ninksinstring); + td->td_numberofinks = ninksinstring; + } + } + else + { + td->td_numberofinks = ninksinstring; + TIFFSetFieldBit(tif, FIELD_NUMBEROFINKS); + } + if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL)) + { + if (td->td_numberofinks != td->td_samplesperpixel) + { + TIFFErrorExtR(tif, module, + "Warning %s; Tag %s:\n Value %" PRIu16 + " of NumberOfInks is different from the " + "SamplesPerPixel value %" PRIu16 "", + tif->tif_name, fip->field_name, + td->td_numberofinks, + td->td_samplesperpixel); + } + } + } + } + break; + case TIFFTAG_NUMBEROFINKS: + v = (uint16_t)va_arg(ap, uint16_vap); + /* If InkNames already set also NumberOfInks is set accordingly and + * should be equal */ + if (TIFFFieldSet(tif, FIELD_INKNAMES)) + { + if (v != td->td_numberofinks) + { + TIFFErrorExtR( + tif, module, + "Error %s; Tag %s:\n It is not possible to set the " + "value %" PRIu32 + " for NumberOfInks\n which is different from the " + "number of inks in the InkNames tag (%" PRIu16 ")", + tif->tif_name, fip->field_name, v, td->td_numberofinks); + /* Do not set / overwrite number of inks already set by + * InkNames case accordingly. */ + status = 0; + } + } + else + { + td->td_numberofinks = (uint16_t)v; + if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL)) + { + if (td->td_numberofinks != td->td_samplesperpixel) + { + TIFFErrorExtR(tif, module, + "Warning %s; Tag %s:\n Value %" PRIu32 + " of NumberOfInks is different from the " + "SamplesPerPixel value %" PRIu16 "", + tif->tif_name, fip->field_name, v, + td->td_samplesperpixel); + } + } + } + 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; - const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); /* - * 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. + * 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. + * + * This also happens when a FIELD_IGNORE tag is written. */ - if(fip == NULL || 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 ? fip->field_name : "Unknown"); - status = 0; - break; + if (fip->field_bit == FIELD_IGNORE) + { + TIFFErrorExtR( + tif, module, + "%s: Ignored %stag \"%s\" (not supported by libtiff)", + tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", + fip->field_name); + status = 0; + break; + } + if (fip->field_bit != FIELD_CUSTOM) + { + TIFFErrorExtR( + tif, 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; - } + 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) + { + _TIFFfreeExt(tif, 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; + if (tv == NULL) + { + TIFFTagValue *new_customValues; + + td->td_customValueCount++; + new_customValues = (TIFFTagValue *)_TIFFreallocExt( + tif, td->td_customValues, + sizeof(TIFFTagValue) * td->td_customValueCount); + if (!new_customValues) + { + TIFFErrorExtR(tif, 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; @@ -458,151 +748,358 @@ _TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap) /* * Set custom value ... save a copy of the custom tag value. */ - tv_size = _TIFFDataSize(fip->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_passcount) { - if (fip->field_writecount == TIFF_VARIABLE2) - tv->count = (uint32) va_arg(ap, uint32); - 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 (fip->field_type == TIFF_ASCII) - _TIFFsetString((char **)&tv->value, va_arg(ap, char *)); - else { - tv->value = _TIFFCheckMalloc(tif, tv_size, tv->count, - "Tag Value"); - if (!tv->value) { - status = 0; - goto end; - } - - if ((fip->field_passcount - || fip->field_writecount == TIFF_VARIABLE - || fip->field_writecount == TIFF_VARIABLE2 - || fip->field_writecount == TIFF_SPP - || tv->count > 1) - && fip->field_tag != TIFFTAG_PAGENUMBER - && fip->field_tag != TIFFTAG_HALFTONEHINTS - && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING - && fip->field_tag != TIFFTAG_DOTRANGE) { + /*--: Rational2Double: For Rationals evaluate "set_field_type" to + * determine internal storage size. */ + tv_size = TIFFFieldSetGetSize(fip); + if (tv_size == 0) + { + status = 0; + TIFFErrorExtR(tif, 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; + const char *mb; + if (fip->field_passcount) + { + assert(fip->field_writecount == TIFF_VARIABLE2); + ma = (uint32_t)va_arg(ap, uint32_t); + mb = (const char *)va_arg(ap, const char *); + } + else + { + mb = (const char *)va_arg(ap, const char *); + size_t len = strlen(mb) + 1; + if (len >= 0x80000000U) + { + status = 0; + TIFFErrorExtR(tif, module, + "%s: Too long string value for \"%s\". " + "Maximum supported is 2147483647 bytes", + tif->tif_name, fip->field_name); + goto end; + } + ma = (uint32_t)len; + } + tv->count = ma; + setByteArray(tif, &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; + TIFFErrorExtR(tif, 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 { - /* - * XXX: The following loop required to handle - * TIFFTAG_PAGENUMBER, TIFFTAG_HALFTONEHINTS, - * TIFFTAG_YCBCRSUBSAMPLING and TIFFTAG_DOTRANGE tags. - * These tags are actually arrays and should be passed as - * array pointers to TIFFSetField() function, but actually - * passed as a list of separate values. This behaviour - * must be changed in the future! - */ - int i; - char *val = (char *)tv->value; - - for (i = 0; i < tv->count; i++, val += tv_size) { - switch (fip->field_type) { - case TIFF_BYTE: - case TIFF_UNDEFINED: - { - uint8 v = (uint8)va_arg(ap, int); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_SBYTE: - { - int8 v = (int8)va_arg(ap, int); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_SHORT: - { - uint16 v = (uint16)va_arg(ap, int); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_SSHORT: - { - int16 v = (int16)va_arg(ap, int); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_LONG: - case TIFF_IFD: - { - uint32 v = va_arg(ap, uint32); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_SLONG: - { - int32 v = va_arg(ap, int32); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_RATIONAL: - case TIFF_SRATIONAL: - case TIFF_FLOAT: - { - float v = (float)va_arg(ap, double); - _TIFFmemcpy(val, &v, tv_size); - } - break; - case TIFF_DOUBLE: - { - double v = va_arg(ap, double); - _TIFFmemcpy(val, &v, tv_size); - } - break; - default: - _TIFFmemset(val, 0, tv_size); - status = 0; - break; - } - } - } - } - } - } - if (status) { - TIFFSetFieldBit(tif, _TIFFFieldWithTag(tif, tag)->field_bit); - tif->tif_flags |= TIFF_DIRTYDIRECT; - } + tv->count * tv_size); + /* Test here for too big values for LONG8, SLONG8 in + * ClassicTIFF and delete custom field from custom list */ + if (!(tif->tif_flags & TIFF_BIGTIFF)) + { + if (tv->info->field_type == TIFF_LONG8) + { + uint64_t *pui64 = (uint64_t *)tv->value; + for (int i = 0; i < tv->count; i++) + { + if (pui64[i] > 0xffffffffu) + { + TIFFErrorExtR( + tif, module, + "%s: Bad LONG8 value %" PRIu64 + " at %d. array position for \"%s\" tag " + "%d in ClassicTIFF. Tag won't be " + "written to file", + tif->tif_name, pui64[i], i, + fip->field_name, tag); + goto badvalueifd8long8; + } + } + } + else if (tv->info->field_type == TIFF_SLONG8) + { + int64_t *pi64 = (int64_t *)tv->value; + for (int i = 0; i < tv->count; i++) + { + if (pi64[i] > 2147483647 || + pi64[i] < (-2147483647 - 1)) + { + TIFFErrorExtR( + tif, module, + "%s: Bad SLONG8 value %" PRIi64 + " at %d. array position for \"%s\" tag " + "%d in ClassicTIFF. Tag won't be " + "written to file", + tif->tif_name, pi64[i], i, + fip->field_name, tag); + goto badvalueifd8long8; + } + } + } + } + } + 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); + /* Test here for too big values for ClassicTIFF and + * delete custom field from custom list */ + if (!(tif->tif_flags & TIFF_BIGTIFF) && + (v2 > 0xffffffffu)) + { + TIFFErrorExtR( + tif, module, + "%s: Bad LONG8 or IFD8 value %" PRIu64 + " for \"%s\" tag %d in ClassicTIFF. Tag " + "won't be written to file", + tif->tif_name, v2, fip->field_name, tag); + goto badvalueifd8long8; + } + } + break; + case TIFF_SLONG8: + { + int64_t v2 = va_arg(ap, int64_t); + _TIFFmemcpy(val, &v2, tv_size); + /* Test here for too big values for ClassicTIFF and + * delete custom field from custom list */ + if (!(tif->tif_flags & TIFF_BIGTIFF) && + ((v2 > 2147483647) || (v2 < (-2147483647 - 1)))) + { + TIFFErrorExtR( + tif, module, + "%s: Bad SLONG8 value %" PRIi64 + " for \"%s\" tag %d in ClassicTIFF. Tag " + "won't be written to file", + tif->tif_name, v2, fip->field_name, tag); + goto badvalueifd8long8; + } + } + 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) + { + TIFFErrorExtR( + tif, module, + "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); + va_end(ap); + return (status); badvalue: - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Bad value %d for \"%s\" tag", - tif->tif_name, v, - _TIFFFieldWithTag(tif, tag)->field_name); - va_end(ap); - return (0); +{ + const TIFFField *fip2 = TIFFFieldWithTag(tif, tag); + TIFFErrorExtR(tif, module, "%s: Bad value %" PRIu32 " for \"%s\" tag", + tif->tif_name, v, fip2 ? fip2->field_name : "Unknown"); + va_end(ap); +} + return (0); badvalue32: - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Bad value %u for \"%s\" tag", - tif->tif_name, v32, - _TIFFFieldWithTag(tif, tag)->field_name); - va_end(ap); - return (0); +{ + const TIFFField *fip2 = TIFFFieldWithTag(tif, tag); + TIFFErrorExtR(tif, 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); + TIFFErrorExtR(tif, module, "%s: Bad value %f for \"%s\" tag", tif->tif_name, + dblval, fip2 ? fip2->field_name : "Unknown"); + va_end(ap); } + return (0); +badvalueifd8long8: +{ + /* Error message issued already above. */ + TIFFTagValue *tv2 = NULL; + int iCustom2, iC2; + /* Find the existing entry for this custom value. */ + for (iCustom2 = 0; iCustom2 < td->td_customValueCount; iCustom2++) + { + if (td->td_customValues[iCustom2].info->field_tag == tag) + { + tv2 = td->td_customValues + (iCustom2); + break; + } + } + if (tv2 != NULL) + { + /* Remove custom field from custom list */ + if (tv2->value != NULL) + { + _TIFFfreeExt(tif, tv2->value); + tv2->value = NULL; + } + /* Shorten list and close gap in customValues list. + * Re-allocation of td_customValues not necessary here. */ + td->td_customValueCount--; + for (iC2 = iCustom2; iC2 < td->td_customValueCount; iC2++) + { + td->td_customValues[iC2] = td->td_customValues[iC2 + 1]; + } + } + else + { + assert(0); + } + va_end(ap); +} + return (0); +} /*-- _TIFFVSetField() --*/ /* * Return 1/0 according to whether or not @@ -613,29 +1110,30 @@ _TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap) * has commenced, unless its value has no effect * on the format of the data that is written. */ -static int -OkToChangeTag(TIFF* tif, ttag_t tag) +static int OkToChangeTag(TIFF *tif, uint32_t tag) { - const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); - if (!fip) { /* unknown tag */ - TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", "%s: Unknown %stag %u", - 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); + const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY); + if (!fip) + { /* unknown tag */ + TIFFErrorExtR(tif, "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. + */ + TIFFErrorExtR(tif, "TIFFSetField", + "%s: Cannot modify tag \"%s\" while writing", + tif->tif_name, fip->field_name); + return (0); + } + return (1); } /* @@ -645,16 +1143,57 @@ OkToChangeTag(TIFF* tif, ttag_t tag) * when/if the directory structure is * updated. */ -int -TIFFSetField(TIFF* tif, ttag_t tag, ...) +int TIFFSetField(TIFF *tif, uint32_t tag, ...) { - va_list ap; - int status; + va_list ap; + int status; - va_start(ap, tag); - status = TIFFVSetField(tif, tag, ap); - va_end(ap); - return (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) + { + _TIFFfreeExt(tif, 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); } /* @@ -663,300 +1202,392 @@ TIFFSetField(TIFF* tif, ttag_t tag, ...) * for building higher-level interfaces on * top of the library. */ -int -TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap) +int TIFFVSetField(TIFF *tif, uint32_t tag, va_list ap) { - return OkToChangeTag(tif, tag) ? - (*tif->tif_tagmethods.vsetfield)(tif, tag, ap) : 0; + return OkToChangeTag(tif, tag) + ? (*tif->tif_tagmethods.vsetfield)(tif, tag, ap) + : 0; } -static int -_TIFFVGetField(TIFF* tif, ttag_t tag, va_list ap) +static int _TIFFVGetField(TIFF *tif, uint32_t tag, va_list ap) { - TIFFDirectory* td = &tif->tif_dir; - int ret_val = 1; + 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; + } - switch (tag) { - case TIFFTAG_SUBFILETYPE: - *va_arg(ap, uint32*) = td->td_subfiletype; + switch (standard_tag) + { + case TIFFTAG_SUBFILETYPE: + *va_arg(ap, uint32_t *) = td->td_subfiletype; break; - case TIFFTAG_IMAGEWIDTH: - *va_arg(ap, uint32*) = td->td_imagewidth; + case TIFFTAG_IMAGEWIDTH: + *va_arg(ap, uint32_t *) = td->td_imagewidth; break; - case TIFFTAG_IMAGELENGTH: - *va_arg(ap, uint32*) = td->td_imagelength; + case TIFFTAG_IMAGELENGTH: + *va_arg(ap, uint32_t *) = td->td_imagelength; break; - case TIFFTAG_BITSPERSAMPLE: - *va_arg(ap, uint16*) = td->td_bitspersample; + case TIFFTAG_BITSPERSAMPLE: + *va_arg(ap, uint16_t *) = td->td_bitspersample; break; - case TIFFTAG_COMPRESSION: - *va_arg(ap, uint16*) = td->td_compression; + case TIFFTAG_COMPRESSION: + *va_arg(ap, uint16_t *) = td->td_compression; break; - case TIFFTAG_PHOTOMETRIC: - *va_arg(ap, uint16*) = td->td_photometric; + case TIFFTAG_PHOTOMETRIC: + *va_arg(ap, uint16_t *) = td->td_photometric; break; - case TIFFTAG_THRESHHOLDING: - *va_arg(ap, uint16*) = td->td_threshholding; + case TIFFTAG_THRESHHOLDING: + *va_arg(ap, uint16_t *) = td->td_threshholding; break; - case TIFFTAG_FILLORDER: - *va_arg(ap, uint16*) = td->td_fillorder; + case TIFFTAG_FILLORDER: + *va_arg(ap, uint16_t *) = td->td_fillorder; break; - case TIFFTAG_ORIENTATION: - *va_arg(ap, uint16*) = td->td_orientation; + case TIFFTAG_ORIENTATION: + *va_arg(ap, uint16_t *) = td->td_orientation; break; - case TIFFTAG_SAMPLESPERPIXEL: - *va_arg(ap, uint16*) = td->td_samplesperpixel; + case TIFFTAG_SAMPLESPERPIXEL: + *va_arg(ap, uint16_t *) = td->td_samplesperpixel; break; - case TIFFTAG_ROWSPERSTRIP: - *va_arg(ap, uint32*) = td->td_rowsperstrip; + case TIFFTAG_ROWSPERSTRIP: + *va_arg(ap, uint32_t *) = td->td_rowsperstrip; break; - case TIFFTAG_MINSAMPLEVALUE: - *va_arg(ap, uint16*) = td->td_minsamplevalue; + case TIFFTAG_MINSAMPLEVALUE: + *va_arg(ap, uint16_t *) = td->td_minsamplevalue; break; - case TIFFTAG_MAXSAMPLEVALUE: - *va_arg(ap, uint16*) = td->td_maxsamplevalue; + case TIFFTAG_MAXSAMPLEVALUE: + *va_arg(ap, uint16_t *) = td->td_maxsamplevalue; break; - case TIFFTAG_SMINSAMPLEVALUE: - *va_arg(ap, double*) = td->td_sminsamplevalue; + 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: - *va_arg(ap, double*) = td->td_smaxsamplevalue; + 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; + case TIFFTAG_XRESOLUTION: + *va_arg(ap, float *) = td->td_xresolution; break; - case TIFFTAG_YRESOLUTION: - *va_arg(ap, float*) = td->td_yresolution; + case TIFFTAG_YRESOLUTION: + *va_arg(ap, float *) = td->td_yresolution; break; - case TIFFTAG_PLANARCONFIG: - *va_arg(ap, uint16*) = td->td_planarconfig; + case TIFFTAG_PLANARCONFIG: + *va_arg(ap, uint16_t *) = td->td_planarconfig; break; - case TIFFTAG_XPOSITION: - *va_arg(ap, float*) = td->td_xposition; + case TIFFTAG_XPOSITION: + *va_arg(ap, float *) = td->td_xposition; break; - case TIFFTAG_YPOSITION: - *va_arg(ap, float*) = td->td_yposition; + case TIFFTAG_YPOSITION: + *va_arg(ap, float *) = td->td_yposition; break; - case TIFFTAG_RESOLUTIONUNIT: - *va_arg(ap, uint16*) = td->td_resolutionunit; + case TIFFTAG_RESOLUTIONUNIT: + *va_arg(ap, uint16_t *) = td->td_resolutionunit; break; - case TIFFTAG_PAGENUMBER: - *va_arg(ap, uint16*) = td->td_pagenumber[0]; - *va_arg(ap, uint16*) = td->td_pagenumber[1]; + 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*) = td->td_halftonehints[0]; - *va_arg(ap, uint16*) = td->td_halftonehints[1]; + 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, uint16**) = td->td_colormap[0]; - *va_arg(ap, uint16**) = td->td_colormap[1]; - *va_arg(ap, uint16**) = td->td_colormap[2]; + 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: - *va_arg(ap, uint32**) = td->td_stripoffset; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_TILEOFFSETS: + _TIFFFillStriles(tif); + *va_arg(ap, const uint64_t **) = td->td_stripoffset_p; + if (td->td_stripoffset_p == NULL) + ret_val = 0; break; - case TIFFTAG_STRIPBYTECOUNTS: - case TIFFTAG_TILEBYTECOUNTS: - *va_arg(ap, uint32**) = td->td_stripbytecount; + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEBYTECOUNTS: + _TIFFFillStriles(tif); + *va_arg(ap, const uint64_t **) = td->td_stripbytecount_p; + if (td->td_stripbytecount_p == NULL) + ret_val = 0; break; - case TIFFTAG_MATTEING: - *va_arg(ap, uint16*) = + 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*) = td->td_extrasamples; - *va_arg(ap, uint16**) = td->td_sampleinfo; + 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*) = td->td_tilewidth; + case TIFFTAG_TILEWIDTH: + *va_arg(ap, uint32_t *) = td->td_tilewidth; break; - case TIFFTAG_TILELENGTH: - *va_arg(ap, uint32*) = td->td_tilelength; + case TIFFTAG_TILELENGTH: + *va_arg(ap, uint32_t *) = td->td_tilelength; break; - case TIFFTAG_TILEDEPTH: - *va_arg(ap, uint32*) = td->td_tiledepth; + 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*) = DATATYPE_UINT; + 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*) = DATATYPE_INT; + case SAMPLEFORMAT_INT: + *va_arg(ap, uint16_t *) = DATATYPE_INT; break; - case SAMPLEFORMAT_IEEEFP: - *va_arg(ap, uint16*) = DATATYPE_IEEEFP; + case SAMPLEFORMAT_IEEEFP: + *va_arg(ap, uint16_t *) = DATATYPE_IEEEFP; break; - case SAMPLEFORMAT_VOID: - *va_arg(ap, uint16*) = DATATYPE_VOID; + case SAMPLEFORMAT_VOID: + *va_arg(ap, uint16_t *) = DATATYPE_VOID; break; } break; - case TIFFTAG_SAMPLEFORMAT: - *va_arg(ap, uint16*) = td->td_sampleformat; + case TIFFTAG_SAMPLEFORMAT: + *va_arg(ap, uint16_t *) = td->td_sampleformat; break; - case TIFFTAG_IMAGEDEPTH: - *va_arg(ap, uint32*) = td->td_imagedepth; + case TIFFTAG_IMAGEDEPTH: + *va_arg(ap, uint32_t *) = td->td_imagedepth; break; - case TIFFTAG_SUBIFD: - *va_arg(ap, uint16*) = td->td_nsubifd; - *va_arg(ap, uint32**) = td->td_subifd; + 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*) = td->td_ycbcrpositioning; + case TIFFTAG_YCBCRPOSITIONING: + *va_arg(ap, uint16_t *) = td->td_ycbcrpositioning; break; - case TIFFTAG_YCBCRSUBSAMPLING: - *va_arg(ap, uint16*) = td->td_ycbcrsubsampling[0]; - *va_arg(ap, uint16*) = td->td_ycbcrsubsampling[1]; + 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, uint16**) = td->td_transferfunction[0]; - if (td->td_samplesperpixel - td->td_extrasamples > 1) { - *va_arg(ap, uint16**) = td->td_transferfunction[1]; - *va_arg(ap, uint16**) = td->td_transferfunction[2]; + 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_REFERENCEBLACKWHITE: - *va_arg(ap, float**) = td->td_refblackwhite; - break; - case TIFFTAG_INKNAMES: - *va_arg(ap, char**) = td->td_inknames; + case TIFFTAG_INKNAMES: + *va_arg(ap, const char **) = td->td_inknames; + break; + case TIFFTAG_NUMBEROFINKS: + *va_arg(ap, uint16_t *) = td->td_numberofinks; break; default: { - const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); - int i; - + 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. + * 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 == NULL || fip->field_bit != FIELD_CUSTOM ) + 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 ? fip->field_name : "Unknown"); - ret_val = 0; - break; + TIFFErrorExtR(tif, "_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? - */ + * 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*) = (uint32)tv->count; - else /* Assume TIFF_VARIABLE */ - *va_arg(ap, uint16*) = (uint16)tv->count; - *va_arg(ap, void **) = tv->value; - 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) - && fip->field_tag != TIFFTAG_PAGENUMBER - && fip->field_tag != TIFFTAG_HALFTONEHINTS - && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING - && fip->field_tag != TIFFTAG_DOTRANGE) { - *va_arg(ap, void **) = tv->value; - ret_val = 1; - } else { - int j; - char *val = (char *)tv->value; - - for (j = 0; j < tv->count; - j++, val += _TIFFDataSize(tv->info->field_type)) { - switch (fip->field_type) { - case TIFF_BYTE: - case TIFF_UNDEFINED: - *va_arg(ap, uint8*) = - *(uint8 *)val; - ret_val = 1; - break; - case TIFF_SBYTE: - *va_arg(ap, int8*) = - *(int8 *)val; - ret_val = 1; - break; - case TIFF_SHORT: - *va_arg(ap, uint16*) = - *(uint16 *)val; - ret_val = 1; - break; - case TIFF_SSHORT: - *va_arg(ap, int16*) = - *(int16 *)val; - ret_val = 1; - break; - case TIFF_LONG: - case TIFF_IFD: - *va_arg(ap, uint32*) = - *(uint32 *)val; - ret_val = 1; - break; - case TIFF_SLONG: - *va_arg(ap, int32*) = - *(int32 *)val; - ret_val = 1; - break; - case TIFF_RATIONAL: - case TIFF_SRATIONAL: - 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; - } - } - } + 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; } - break; + 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 = TIFFFieldSetGetSize(fip); + 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) + { + TIFFErrorExtR( + tif, "_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 (ret_val); } /* * Return the value of a field in the * internal directory structure. */ -int -TIFFGetField(TIFF* tif, ttag_t tag, ...) +int TIFFGetField(TIFF *tif, uint32_t tag, ...) { - int status; - va_list ap; + int status; + va_list ap; - va_start(ap, tag); - status = TIFFVGetField(tif, tag, ap); - va_end(ap); - return (status); + va_start(ap, tag); + status = TIFFVGetField(tif, tag, ap); + va_end(ap); + return (status); } /* @@ -965,68 +1596,75 @@ TIFFGetField(TIFF* tif, ttag_t tag, ...) * for building higher-level interfaces on * top of the library. */ -int -TIFFVGetField(TIFF* tif, ttag_t tag, va_list ap) +int TIFFVGetField(TIFF *tif, uint32_t tag, va_list ap) { - const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); - return (fip && (isPseudoTag(tag) || TIFFFieldSet(tif, fip->field_bit)) ? - (*tif->tif_tagmethods.vgetfield)(tif, tag, ap) : 0); + 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; \ - } \ -} +#define CleanupField(member) \ + { \ + if (td->member) \ + { \ + _TIFFfreeExt(tif, td->member); \ + td->member = 0; \ + } \ + } /* * Release storage associated with a directory. */ -void -TIFFFreeDirectory(TIFF* tif) +void TIFFFreeDirectory(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - int i; - - _TIFFmemset(td->td_fieldsset, 0, FIELD_SETLONGS); - 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); - CleanupField(td_stripbytecount); - 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); + TIFFDirectory *td = &tif->tif_dir; + int i; + + _TIFFmemset(td->td_fieldsset, 0, sizeof(td->td_fieldsset)); + 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) + _TIFFfreeExt(tif, 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; +static TIFFExtendProc _TIFFextender = (TIFFExtendProc)NULL; -TIFFExtendProc -TIFFSetTagExtender(TIFFExtendProc extender) +TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc extender) { - TIFFExtendProc prev = _TIFFextender; - _TIFFextender = extender; - return (prev); + TIFFExtendProc prev = _TIFFextender; + _TIFFextender = extender; + return (prev); } /* @@ -1036,155 +1674,350 @@ TIFFSetTagExtender(TIFFExtendProc extender) * The newly created directory will not exist on the file till * TIFFWriteDirectory(), TIFFFlush() or TIFFClose() is called. */ -int -TIFFCreateDirectory(TIFF* tif) +int TIFFCreateDirectory(TIFF *tif) { TIFFDefaultDirectory(tif); tif->tif_diroff = 0; tif->tif_nextdiroff = 0; tif->tif_curoff = 0; - tif->tif_row = (uint32) -1; - tif->tif_curstrip = (tstrip_t) -1; + 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; + /* invalidate directory index */ + tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; + /* invalidate IFD loop lists */ + _TIFFCleanupIFDOffsetAndNumberMaps(tif); + /* To be able to return from SubIFD or custom-IFD to main-IFD */ + tif->tif_setdirectory_force_absolute = TRUE; + + 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) +int TIFFDefaultDirectory(TIFF *tif) { - register TIFFDirectory* td = &tif->tif_dir; - - size_t tiffFieldInfoCount; - const TIFFFieldInfo *tiffFieldInfo = - _TIFFGetFieldInfo(&tiffFieldInfoCount); - _TIFFSetupFieldInfo(tif, tiffFieldInfo, tiffFieldInfoCount); - - _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) -1; - td->td_tilewidth = 0; - td->td_tilelength = 0; - td->td_tiledepth = 1; - td->td_stripbytecountsorted = 1; /* Our own arrays always sorted. */ - 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. - */ - 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; - /* - * Clear other directory-specific fields. - */ - tif->tif_tilesize = -1; - tif->tif_scanlinesize = -1; + 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; + /* additional default values */ + td->td_planarconfig = PLANARCONFIG_CONTIG; + td->td_compression = COMPRESSION_NONE; + td->td_subfiletype = 0; + td->td_minsamplevalue = 0; + /* td_bitspersample=1 is always set in TIFFDefaultDirectory(). + * Therefore, td_maxsamplevalue has to be re-calculated in + * TIFFGetFieldDefaulted(). */ + td->td_maxsamplevalue = 1; /* Default for td_bitspersample=1 */ + td->td_extrasamples = 0; + td->td_sampleinfo = 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; - return (1); + for (i = 0; i < tif->tif_nfieldscompat; i++) + { + if (tif->tif_fieldscompat[i].allocated_size) + _TIFFfreeExt(tif, tif->tif_fieldscompat[i].fields); + } + _TIFFfreeExt(tif, 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, uint32* nextdir, toff_t* off) +static int TIFFAdvanceDirectory(TIFF *tif, uint64_t *nextdiroff, uint64_t *off, + tdir_t *nextdirnum) { - static const char module[] = "TIFFAdvanceDirectory"; - uint16 dircount; - if (isMapped(tif)) - { - toff_t poff=*nextdir; - if (poff+sizeof(uint16) > tif->tif_size) - { - TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count", - tif->tif_name); - return (0); - } - _TIFFmemcpy(&dircount, tif->tif_base+poff, sizeof (uint16)); - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabShort(&dircount); - poff+=sizeof (uint16)+dircount*sizeof (TIFFDirEntry); - if (off != NULL) - *off = poff; - if (((toff_t) (poff+sizeof (uint32))) > tif->tif_size) - { - TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link", - tif->tif_name); - return (0); - } - _TIFFmemcpy(nextdir, tif->tif_base+poff, sizeof (uint32)); - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabLong(nextdir); - return (1); - } - else - { - if (!SeekOK(tif, *nextdir) || - !ReadOK(tif, &dircount, sizeof (uint16))) { - 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*sizeof (TIFFDirEntry), SEEK_CUR); - else - (void) TIFFSeekFile(tif, - dircount*sizeof (TIFFDirEntry), SEEK_CUR); - if (!ReadOK(tif, nextdir, sizeof (uint32))) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link", - tif->tif_name); - return (0); - } - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabLong(nextdir); - return (1); - } + static const char module[] = "TIFFAdvanceDirectory"; + + /* Add this directory to the directory list, if not already in. */ + if (!_TIFFCheckDirNumberAndOffset(tif, *nextdirnum, *nextdiroff)) + { + TIFFErrorExtR(tif, module, + "Starting directory %u at offset 0x%" PRIx64 " (%" PRIu64 + ") might cause an IFD loop", + *nextdirnum, *nextdiroff, *nextdiroff); + *nextdiroff = 0; + *nextdirnum = 0; + return (0); + } + + if (isMapped(tif)) + { + uint64_t poff = *nextdiroff; + 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)) + { + TIFFErrorExtR(tif, module, "Error fetching directory count"); + *nextdiroff = 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 < poffb) || (poffc < dircount * 12) || (poffd < poffc) || + (poffd < (tmsize_t)sizeof(uint32_t)) || (poffd > tif->tif_size)) + { + TIFFErrorExtR(tif, 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); + *nextdiroff = nextdir32; + } + else + { + tmsize_t poffa, poffb, poffc, poffd; + uint64_t dircount64; + uint16_t dircount16; + if (poff > (uint64_t)TIFF_TMSIZE_T_MAX - sizeof(uint64_t)) + { + TIFFErrorExtR(tif, module, "Error fetching directory count"); + return (0); + } + poffa = (tmsize_t)poff; + poffb = poffa + sizeof(uint64_t); + if (poffb > tif->tif_size) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, + "Sanity check on directory count failed"); + return (0); + } + dircount16 = (uint16_t)dircount64; + if (poffb > TIFF_TMSIZE_T_MAX - (tmsize_t)(dircount16 * 20) - + (tmsize_t)sizeof(uint64_t)) + { + TIFFErrorExtR(tif, module, "Error fetching directory link"); + return (0); + } + poffc = poffb + dircount16 * 20; + poffd = poffc + sizeof(uint64_t); + if (poffd > tif->tif_size) + { + TIFFErrorExtR(tif, module, "Error fetching directory link"); + return (0); + } + if (off != NULL) + *off = (uint64_t)poffc; + _TIFFmemcpy(nextdiroff, tif->tif_base + poffc, sizeof(uint64_t)); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(nextdiroff); + } + } + else + { + if (!(tif->tif_flags & TIFF_BIGTIFF)) + { + uint16_t dircount; + uint32_t nextdir32; + if (!SeekOK(tif, *nextdiroff) || + !ReadOK(tif, &dircount, sizeof(uint16_t))) + { + TIFFErrorExtR(tif, 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))) + { + TIFFErrorExtR(tif, module, "%s: Error fetching directory link", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdir32); + *nextdiroff = nextdir32; + } + else + { + uint64_t dircount64; + uint16_t dircount16; + if (!SeekOK(tif, *nextdiroff) || + !ReadOK(tif, &dircount64, sizeof(uint64_t))) + { + TIFFErrorExtR(tif, module, "%s: Error fetching directory count", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64 > 0xFFFF) + { + TIFFErrorExtR(tif, 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, nextdiroff, sizeof(uint64_t))) + { + TIFFErrorExtR(tif, module, "%s: Error fetching directory link", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(nextdiroff); + } + } + if (*nextdiroff != 0) + { + (*nextdirnum)++; + /* Check next directory for IFD looping and if so, set it as last + * directory. */ + if (!_TIFFCheckDirNumberAndOffset(tif, *nextdirnum, *nextdiroff)) + { + TIFFWarningExtR( + tif, module, + "the next directory %u at offset 0x%" PRIx64 " (%" PRIu64 + ") might be an IFD loop. Treating directory %d as " + "last directory", + *nextdirnum, *nextdiroff, *nextdiroff, (int)(*nextdirnum) - 1); + *nextdiroff = 0; + (*nextdirnum)--; + } + } + return (1); } /* * Count the number of directories in a file. */ -tdir_t -TIFFNumberOfDirectories(TIFF* tif) +tdir_t TIFFNumberOfDirectories(TIFF *tif) { - toff_t nextdir = tif->tif_header.tiff_diroff; - tdir_t n = 0; - - while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL)) - n++; + uint64_t nextdiroff; + tdir_t nextdirnum; + tdir_t n; + if (!(tif->tif_flags & TIFF_BIGTIFF)) + nextdiroff = tif->tif_header.classic.tiff_diroff; + else + nextdiroff = tif->tif_header.big.tiff_diroff; + nextdirnum = 0; + n = 0; + while (nextdiroff != 0 && + TIFFAdvanceDirectory(tif, &nextdiroff, NULL, &nextdirnum)) + { + ++n; + } return (n); } @@ -1192,29 +2025,82 @@ TIFFNumberOfDirectories(TIFF* tif) * Set the n-th directory as the current directory. * NB: Directories are numbered starting at 0. */ -int -TIFFSetDirectory(TIFF* tif, tdir_t dirn) +int TIFFSetDirectory(TIFF *tif, tdir_t dirn) { - toff_t nextdir; - tdir_t n; - - nextdir = tif->tif_header.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)); + uint64_t nextdiroff; + tdir_t nextdirnum = 0; + tdir_t n; + + if (tif->tif_setdirectory_force_absolute) + { + /* tif_setdirectory_force_absolute=1 will force parsing the main IFD + * chain from the beginning, thus IFD directory list needs to be cleared + * from possible SubIFD offsets. + */ + _TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */ + } + + /* Even faster path, if offset is available within IFD loop hash list. */ + if (!tif->tif_setdirectory_force_absolute && + _TIFFGetOffsetFromDirNumber(tif, dirn, &nextdiroff)) + { + /* Set parameters for following TIFFReadDirectory() below. */ + tif->tif_nextdiroff = nextdiroff; + tif->tif_curdir = dirn; + /* Reset to relative stepping */ + tif->tif_setdirectory_force_absolute = FALSE; + } + else + { + + /* Fast path when we just advance relative to the current directory: + * start at the current dir offset and continue to seek from there. + * Check special cases when relative is not allowed: + * - jump back from SubIFD or custom directory + * - right after TIFFWriteDirectory() jump back to that directory + * using TIFFSetDirectory() */ + const int relative = (dirn >= tif->tif_curdir) && + (tif->tif_diroff != 0) && + !tif->tif_setdirectory_force_absolute; + + if (relative) + { + nextdiroff = tif->tif_diroff; + dirn -= tif->tif_curdir; + nextdirnum = tif->tif_curdir; + } + else if (!(tif->tif_flags & TIFF_BIGTIFF)) + nextdiroff = tif->tif_header.classic.tiff_diroff; + else + nextdiroff = tif->tif_header.big.tiff_diroff; + + /* Reset to relative stepping */ + tif->tif_setdirectory_force_absolute = FALSE; + + for (n = dirn; n > 0 && nextdiroff != 0; n--) + if (!TIFFAdvanceDirectory(tif, &nextdiroff, NULL, &nextdirnum)) + return (0); + /* If the n-th directory could not be reached (does not exist), + * return here without touching anything further. */ + if (nextdiroff == 0 || n > 0) + return (0); + + tif->tif_nextdiroff = nextdiroff; + + /* Set curdir to the actual directory index. */ + if (relative) + tif->tif_curdir += dirn - n; + else + tif->tif_curdir = dirn - n; + } + + /* The -1 decrement is because TIFFReadDirectory will increment + * tif_curdir after successfully reading the directory. */ + if (tif->tif_curdir == 0) + tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; + else + tif->tif_curdir--; + return (TIFFReadDirectory(tif)); } /* @@ -1223,167 +2109,200 @@ TIFFSetDirectory(TIFF* tif, tdir_t dirn) * is used mainly to access directories linked with * the SubIFD tag (e.g. thumbnail images). */ -int -TIFFSetSubDirectory(TIFF* tif, uint32 diroff) +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)); + /* Match nextdiroff and curdir for consistent IFD-loop checking. + * Only with TIFFSetSubDirectory() the IFD list can be corrupted with + * invalid offsets within the main IFD tree. In the case of several subIFDs + * of a main image, there are two possibilities that are not even mutually + * exclusive. a.) The subIFD tag contains an array with all offsets of the + * subIFDs. b.) The SubIFDs are concatenated with their NextIFD parameters. + * (refer to + * https://www.awaresystems.be/imaging/tiff/specification/TIFFPM6.pdf.) + */ + int retval; + uint32_t curdir = 0; + int8_t probablySubIFD = 0; + if (diroff == 0) + { + /* Special case to invalidate the tif_lastdiroff member. */ + tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; + } + else + { + if (!_TIFFGetDirNumberFromOffset(tif, diroff, &curdir)) + { + /* Non-existing offsets might point to a SubIFD or invalid IFD.*/ + probablySubIFD = 1; + } + /* -1 because TIFFReadDirectory() will increment tif_curdir. */ + tif->tif_curdir = + curdir == 0 ? TIFF_NON_EXISTENT_DIR_NUMBER : curdir - 1; + } + + tif->tif_nextdiroff = diroff; + retval = TIFFReadDirectory(tif); + /* If failed, curdir was not incremented in TIFFReadDirectory(), so set it + * back, but leave it for diroff==0. */ + if (!retval && diroff != 0) + { + if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER) + tif->tif_curdir = 0; + else + tif->tif_curdir++; + } + if (retval && probablySubIFD) + { + /* Reset IFD list to start new one for SubIFD chain and also start + * SubIFD chain with tif_curdir=0. */ + _TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */ + tif->tif_curdir = 0; /* first directory of new chain */ + /* add this offset to new IFD list */ + _TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff); + /* To be able to return from SubIFD or custom-IFD to main-IFD */ + tif->tif_setdirectory_force_absolute = TRUE; + } + return (retval); } /* * Return file offset of the current directory. */ -uint32 -TIFFCurrentDirOffset(TIFF* tif) -{ - return (tif->tif_diroff); -} +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); -} +int TIFFLastDirectory(TIFF *tif) { return (tif->tif_nextdiroff == 0); } /* * Unlink the specified directory from the directory chain. + * Note: First directory starts with number dirn=1. + * This is different to TIFFSetDirectory() where the first directory starts with + * zero. */ -int -TIFFUnlinkDirectory(TIFF* tif, tdir_t dirn) +int TIFFUnlinkDirectory(TIFF *tif, tdir_t dirn) { - static const char module[] = "TIFFUnlinkDirectory"; - toff_t nextdir; - toff_t off; - tdir_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. - */ - nextdir = tif->tif_header.tiff_diroff; - off = sizeof (uint16) + sizeof (uint16); - for (n = dirn-1; n > 0; n--) { - if (nextdir == 0) { - TIFFErrorExt(tif->tif_clientdata, module, "Directory %d 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_SWAB) - TIFFSwabLong(&nextdir); - if (!WriteOK(tif, &nextdir, sizeof (uint32))) { - 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_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP|TIFF_POSTENCODE); - 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) -1; - tif->tif_curstrip = (tstrip_t) -1; - return (1); -} + static const char module[] = "TIFFUnlinkDirectory"; + uint64_t nextdir; + tdir_t nextdirnum; + uint64_t off; + tdir_t n; -/* [BFC] - * - * Author: Bruce Cameron - * - * Set a table of tags that are to be replaced during directory process by the - * 'IGNORE' state - or return TRUE/FALSE for the requested tag such that - * 'ReadDirectory' can use the stored information. - * - * FIXME: this is never used properly. Should be removed in the future. - */ -int -TIFFReassignTagToIgnore (enum TIFFIgnoreSense task, int TIFFtagID) -{ - static int TIFFignoretags [FIELD_LAST]; - static int tagcount = 0 ; - int i; /* Loop index */ - int j; /* Loop index */ + if (tif->tif_mode == O_RDONLY) + { + TIFFErrorExtR(tif, module, + "Can not unlink directory in read-only file"); + return (0); + } + if (dirn == 0) + { + TIFFErrorExtR(tif, module, + "For TIFFUnlinkDirectory() first directory starts with " + "number 1 and not 0"); + 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; + } + nextdirnum = 0; /* First directory is dirn=0 */ - switch (task) + for (n = dirn - 1; n > 0; n--) { - case TIS_STORE: - if ( tagcount < (FIELD_LAST - 1) ) + if (nextdir == 0) { - for ( j = 0 ; j < tagcount ; ++j ) - { /* Do not add duplicate tag */ - if ( TIFFignoretags [j] == TIFFtagID ) - return (TRUE) ; - } - TIFFignoretags [tagcount++] = TIFFtagID ; - return (TRUE) ; + TIFFErrorExtR(tif, module, "Directory %u does not exist", dirn); + return (0); } - break ; - - case TIS_EXTRACT: - for ( i = 0 ; i < tagcount ; ++i ) + if (!TIFFAdvanceDirectory(tif, &nextdir, &off, &nextdirnum)) + return (0); + } + /* + * Advance to the directory to be unlinked and fetch + * the offset of the directory that follows. + */ + if (!TIFFAdvanceDirectory(tif, &nextdir, NULL, &nextdirnum)) + 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))) { - if ( TIFFignoretags [i] == TIFFtagID ) - return (TRUE) ; + TIFFErrorExtR(tif, module, "Error writing directory link"); + return (0); + } + } + else + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&nextdir); + if (!WriteOK(tif, &nextdir, sizeof(uint64_t))) + { + TIFFErrorExtR(tif, module, "Error writing directory link"); + return (0); } - break; - - case TIS_EMPTY: - tagcount = 0 ; /* Clear the list */ - return (TRUE) ; - - default: - break; } - - return (FALSE); -} -/* vim: set ts=8 sts=8 sw=8 noet: */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ + /* For dirn=1 (first directory) also update the libtiff internal + * base offset variables. */ + if (dirn == 1) + { + if (!(tif->tif_flags & TIFF_BIGTIFF)) + tif->tif_header.classic.tiff_diroff = (uint32_t)nextdir; + else + tif->tif_header.big.tiff_diroff = nextdir; + } + + /* + * 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) + { + _TIFFfreeExt(tif, 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_lastdiroff = 0; /* will be updated on next link */ + tif->tif_curoff = 0; + tif->tif_row = (uint32_t)-1; + tif->tif_curstrip = (uint32_t)-1; + tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; + _TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */ + return (1); +} diff --git a/LibTiff/tif_dir.h b/LibTiff/tif_dir.h index 515af199..9eaf22f8 100644 --- a/LibTiff/tif_dir.h +++ b/LibTiff/tif_dir.h @@ -1,211 +1,340 @@ -/* $Id: tif_dir.h,v 1.30.2.3 2010-06-09 21:15:27 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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_ +#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 td_imagewidth, td_imagelength, td_imagedepth; - uint32 td_tilewidth, td_tilelength, td_tiledepth; - uint32 td_subfiletype; - uint16 td_bitspersample; - uint16 td_sampleformat; - uint16 td_compression; - uint16 td_photometric; - uint16 td_threshholding; - uint16 td_fillorder; - uint16 td_orientation; - uint16 td_samplesperpixel; - uint32 td_rowsperstrip; - uint16 td_minsamplevalue, td_maxsamplevalue; - double td_sminsamplevalue, td_smaxsamplevalue; - float td_xresolution, td_yresolution; - uint16 td_resolutionunit; - uint16 td_planarconfig; - float td_xposition, td_yposition; - uint16 td_pagenumber[2]; - uint16* td_colormap[3]; - uint16 td_halftonehints[2]; - uint16 td_extrasamples; - uint16* 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 */ - tstrile_t td_stripsperimage; - tstrile_t td_nstrips; /* size of offset & bytecount arrays */ - toff_t* td_stripoffset; - toff_t* td_stripbytecount; /* FIXME: it should be tsize_t array */ - int td_stripbytecountsorted; /* is the bytecount array sorted ascending? */ - uint16 td_nsubifd; - uint32* td_subifd; - /* YCbCr parameters */ - uint16 td_ycbcrsubsampling[2]; - uint16 td_ycbcrpositioning; - /* Colorimetry parameters */ - float* td_refblackwhite; - uint16* td_transferfunction[3]; - /* CMYK parameters */ - int td_inknameslen; - char* td_inknames; - - int td_customValueCount; - TIFFTagValue *td_customValues; +typedef struct +{ +#define FIELDSET_ITEMS 4 + /* bit vector of fields that are set */ + uint32_t td_fieldsset[FIELDSET_ITEMS]; + + 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; + uint16_t td_numberofinks; /* number of inks in InkNames string */ + + 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 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 + * 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 +#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 */ +#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 +#define FIELD_NUMBEROFINKS 50 +/* 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 */ - +#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. + * 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 FIELD_PSEUDO 0 -#define TIFFExtractData(tif, type, v) \ - ((uint32) ((tif)->tif_header.tiff_magic == TIFF_BIGENDIAN ? \ - ((v) >> (tif)->tif_typeshift[type]) & (tif)->tif_typemask[type] : \ - (v) & (tif)->tif_typemask[type])) -#define TIFFInsertData(tif, type, v) \ - ((uint32) ((tif)->tif_header.tiff_magic == TIFF_BIGENDIAN ? \ - ((v) & (tif)->tif_typemask[type]) << (tif)->tif_typeshift[type] : \ - (v) & (tif)->tif_typemask[type])) +#define FIELD_LAST (32 * FIELDSET_ITEMS - 1) +#define BITn(n) (((uint32_t)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 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)) -#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" { +extern "C" +{ #endif -extern const TIFFFieldInfo *_TIFFGetFieldInfo(size_t *); -extern const TIFFFieldInfo *_TIFFGetExifFieldInfo(size_t *); -extern void _TIFFSetupFieldInfo(TIFF*, const TIFFFieldInfo[], size_t); -extern int _TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], int); -extern void _TIFFPrintFieldInfo(TIFF*, FILE*); -extern TIFFDataType _TIFFSampleToTagType(TIFF*); -extern const TIFFFieldInfo* _TIFFFindOrRegisterFieldInfo( TIFF *tif, - ttag_t tag, - TIFFDataType dt ); -extern TIFFFieldInfo* _TIFFCreateAnonFieldInfo( TIFF *tif, ttag_t tag, - TIFFDataType dt ); - -#define _TIFFFindFieldInfo TIFFFindFieldInfo -#define _TIFFFindFieldInfoByName TIFFFindFieldInfoByName -#define _TIFFFieldWithTag TIFFFieldWithTag -#define _TIFFFieldWithName TIFFFieldWithName + + 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 + field_anonymous; /* if true, this is a unknown / anonymous tag */ + 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); + extern int _TIFFCheckDirNumberAndOffset(TIFF *tif, tdir_t dirn, + uint64_t diroff); + extern int _TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, + tdir_t *dirn); + extern int _TIFFGetOffsetFromDirNumber(TIFF *tif, tdir_t dirn, + uint64_t *diroff); + extern int _TIFFRemoveEntryFromDirectoryListByOffset(TIFF *tif, + uint64_t diroff); #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/LibTiff/tif_dirinfo.c b/LibTiff/tif_dirinfo.c index 0a77c971..0e705e81 100644 --- a/LibTiff/tif_dirinfo.c +++ b/LibTiff/tif_dirinfo.c @@ -1,26 +1,24 @@ -/* $Id: tif_dirinfo.c,v 1.65.2.9 2010-06-09 21:15:27 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,858 +29,1323 @@ */ #include "tiffiop.h" #include -#include /* - * NB: NB: THIS ARRAY IS ASSUMED TO BE SORTED BY TAG. - * If a tag can have both LONG and SHORT types then the LONG must be - * placed before the SHORT for writing to work properly. + * 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 TIFFTAG_SPP (-2). The macros should be used but would throw off - * the formatting of the code, so please interprete the -1, -2 and -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. */ -static const TIFFFieldInfo -tiffFieldInfo[] = { - { TIFFTAG_SUBFILETYPE, 1, 1, TIFF_LONG, FIELD_SUBFILETYPE, - 1, 0, "SubfileType" }, -/* XXX SHORT for compatibility w/ old versions of the library */ - { TIFFTAG_SUBFILETYPE, 1, 1, TIFF_SHORT, FIELD_SUBFILETYPE, - 1, 0, "SubfileType" }, - { TIFFTAG_OSUBFILETYPE, 1, 1, TIFF_SHORT, FIELD_SUBFILETYPE, - 1, 0, "OldSubfileType" }, - { TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_LONG, FIELD_IMAGEDIMENSIONS, - 0, 0, "ImageWidth" }, - { TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDIMENSIONS, - 0, 0, "ImageWidth" }, - { TIFFTAG_IMAGELENGTH, 1, 1, TIFF_LONG, FIELD_IMAGEDIMENSIONS, - 1, 0, "ImageLength" }, - { TIFFTAG_IMAGELENGTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDIMENSIONS, - 1, 0, "ImageLength" }, - { TIFFTAG_BITSPERSAMPLE, -1,-1, TIFF_SHORT, FIELD_BITSPERSAMPLE, - 0, 0, "BitsPerSample" }, -/* XXX LONG for compatibility with some broken TIFF writers */ - { TIFFTAG_BITSPERSAMPLE, -1,-1, TIFF_LONG, FIELD_BITSPERSAMPLE, - 0, 0, "BitsPerSample" }, - { TIFFTAG_COMPRESSION, -1, 1, TIFF_SHORT, FIELD_COMPRESSION, - 0, 0, "Compression" }, -/* XXX LONG for compatibility with some broken TIFF writers */ - { TIFFTAG_COMPRESSION, -1, 1, TIFF_LONG, FIELD_COMPRESSION, - 0, 0, "Compression" }, - { TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_SHORT, FIELD_PHOTOMETRIC, - 0, 0, "PhotometricInterpretation" }, -/* XXX LONG for compatibility with some broken TIFF writers */ - { TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_LONG, FIELD_PHOTOMETRIC, - 0, 0, "PhotometricInterpretation" }, - { TIFFTAG_THRESHHOLDING, 1, 1, TIFF_SHORT, FIELD_THRESHHOLDING, - 1, 0, "Threshholding" }, - { TIFFTAG_CELLWIDTH, 1, 1, TIFF_SHORT, FIELD_IGNORE, - 1, 0, "CellWidth" }, - { TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, FIELD_IGNORE, - 1, 0, "CellLength" }, - { TIFFTAG_FILLORDER, 1, 1, TIFF_SHORT, FIELD_FILLORDER, - 0, 0, "FillOrder" }, - { TIFFTAG_DOCUMENTNAME, -1,-1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "DocumentName" }, - { TIFFTAG_IMAGEDESCRIPTION, -1,-1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "ImageDescription" }, - { TIFFTAG_MAKE, -1,-1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "Make" }, - { TIFFTAG_MODEL, -1,-1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "Model" }, - { TIFFTAG_STRIPOFFSETS, -1,-1, TIFF_LONG, FIELD_STRIPOFFSETS, - 0, 0, "StripOffsets" }, - { TIFFTAG_STRIPOFFSETS, -1,-1, TIFF_SHORT, FIELD_STRIPOFFSETS, - 0, 0, "StripOffsets" }, - { TIFFTAG_ORIENTATION, 1, 1, TIFF_SHORT, FIELD_ORIENTATION, - 0, 0, "Orientation" }, - { TIFFTAG_SAMPLESPERPIXEL, 1, 1, TIFF_SHORT, FIELD_SAMPLESPERPIXEL, - 0, 0, "SamplesPerPixel" }, - { TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_LONG, FIELD_ROWSPERSTRIP, - 0, 0, "RowsPerStrip" }, - { TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_SHORT, FIELD_ROWSPERSTRIP, - 0, 0, "RowsPerStrip" }, - { TIFFTAG_STRIPBYTECOUNTS, -1,-1, TIFF_LONG, FIELD_STRIPBYTECOUNTS, - 0, 0, "StripByteCounts" }, - { TIFFTAG_STRIPBYTECOUNTS, -1,-1, TIFF_SHORT, FIELD_STRIPBYTECOUNTS, - 0, 0, "StripByteCounts" }, - { TIFFTAG_MINSAMPLEVALUE, -2,-1, TIFF_SHORT, FIELD_MINSAMPLEVALUE, - 1, 0, "MinSampleValue" }, - { TIFFTAG_MAXSAMPLEVALUE, -2,-1, TIFF_SHORT, FIELD_MAXSAMPLEVALUE, - 1, 0, "MaxSampleValue" }, - { TIFFTAG_XRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_RESOLUTION, - 1, 0, "XResolution" }, - { TIFFTAG_YRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_RESOLUTION, - 1, 0, "YResolution" }, - { TIFFTAG_PLANARCONFIG, 1, 1, TIFF_SHORT, FIELD_PLANARCONFIG, - 0, 0, "PlanarConfiguration" }, - { TIFFTAG_PAGENAME, -1,-1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "PageName" }, - { TIFFTAG_XPOSITION, 1, 1, TIFF_RATIONAL, FIELD_POSITION, - 1, 0, "XPosition" }, - { TIFFTAG_YPOSITION, 1, 1, TIFF_RATIONAL, FIELD_POSITION, - 1, 0, "YPosition" }, - { TIFFTAG_FREEOFFSETS, -1,-1, TIFF_LONG, FIELD_IGNORE, - 0, 0, "FreeOffsets" }, - { TIFFTAG_FREEBYTECOUNTS, -1,-1, TIFF_LONG, FIELD_IGNORE, - 0, 0, "FreeByteCounts" }, - { TIFFTAG_GRAYRESPONSEUNIT, 1, 1, TIFF_SHORT, FIELD_IGNORE, - 1, 0, "GrayResponseUnit" }, - { TIFFTAG_GRAYRESPONSECURVE,-1,-1, TIFF_SHORT, FIELD_IGNORE, - 1, 0, "GrayResponseCurve" }, - { TIFFTAG_RESOLUTIONUNIT, 1, 1, TIFF_SHORT, FIELD_RESOLUTIONUNIT, - 1, 0, "ResolutionUnit" }, - { TIFFTAG_PAGENUMBER, 2, 2, TIFF_SHORT, FIELD_PAGENUMBER, - 1, 0, "PageNumber" }, - { TIFFTAG_COLORRESPONSEUNIT, 1, 1, TIFF_SHORT, FIELD_IGNORE, - 1, 0, "ColorResponseUnit" }, - { TIFFTAG_TRANSFERFUNCTION, -1,-1, TIFF_SHORT, FIELD_TRANSFERFUNCTION, - 1, 0, "TransferFunction" }, - { TIFFTAG_SOFTWARE, -1,-1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "Software" }, - { TIFFTAG_DATETIME, 20,20, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "DateTime" }, - { TIFFTAG_ARTIST, -1,-1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "Artist" }, - { TIFFTAG_HOSTCOMPUTER, -1,-1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "HostComputer" }, - { TIFFTAG_WHITEPOINT, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "WhitePoint" }, - { TIFFTAG_PRIMARYCHROMATICITIES,6,6,TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "PrimaryChromaticities" }, - { TIFFTAG_COLORMAP, -1,-1, TIFF_SHORT, FIELD_COLORMAP, - 1, 0, "ColorMap" }, - { TIFFTAG_HALFTONEHINTS, 2, 2, TIFF_SHORT, FIELD_HALFTONEHINTS, - 1, 0, "HalftoneHints" }, - { TIFFTAG_TILEWIDTH, 1, 1, TIFF_LONG, FIELD_TILEDIMENSIONS, - 0, 0, "TileWidth" }, - { TIFFTAG_TILEWIDTH, 1, 1, TIFF_SHORT, FIELD_TILEDIMENSIONS, - 0, 0, "TileWidth" }, - { TIFFTAG_TILELENGTH, 1, 1, TIFF_LONG, FIELD_TILEDIMENSIONS, - 0, 0, "TileLength" }, - { TIFFTAG_TILELENGTH, 1, 1, TIFF_SHORT, FIELD_TILEDIMENSIONS, - 0, 0, "TileLength" }, - { TIFFTAG_TILEOFFSETS, -1, 1, TIFF_LONG, FIELD_STRIPOFFSETS, - 0, 0, "TileOffsets" }, - { TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_LONG, FIELD_STRIPBYTECOUNTS, - 0, 0, "TileByteCounts" }, - { TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_SHORT, FIELD_STRIPBYTECOUNTS, - 0, 0, "TileByteCounts" }, - { TIFFTAG_SUBIFD, -1,-1, TIFF_IFD, FIELD_SUBIFD, - 1, 1, "SubIFD" }, - { TIFFTAG_SUBIFD, -1,-1, TIFF_LONG, FIELD_SUBIFD, - 1, 1, "SubIFD" }, - { TIFFTAG_INKSET, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "InkSet" }, - { TIFFTAG_INKNAMES, -1,-1, TIFF_ASCII, FIELD_INKNAMES, - 1, 1, "InkNames" }, - { TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "NumberOfInks" }, - { TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "DotRange" }, - { TIFFTAG_DOTRANGE, 2, 2, TIFF_BYTE, FIELD_CUSTOM, - 0, 0, "DotRange" }, - { TIFFTAG_TARGETPRINTER, -1,-1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "TargetPrinter" }, - { TIFFTAG_EXTRASAMPLES, -1,-1, TIFF_SHORT, FIELD_EXTRASAMPLES, - 0, 1, "ExtraSamples" }, -/* XXX for bogus Adobe Photoshop v2.5 files */ - { TIFFTAG_EXTRASAMPLES, -1,-1, TIFF_BYTE, FIELD_EXTRASAMPLES, - 0, 1, "ExtraSamples" }, - { TIFFTAG_SAMPLEFORMAT, -1,-1, TIFF_SHORT, FIELD_SAMPLEFORMAT, - 0, 0, "SampleFormat" }, - { TIFFTAG_SMINSAMPLEVALUE, -2,-1, TIFF_ANY, FIELD_SMINSAMPLEVALUE, - 1, 0, "SMinSampleValue" }, - { TIFFTAG_SMAXSAMPLEVALUE, -2,-1, TIFF_ANY, FIELD_SMAXSAMPLEVALUE, - 1, 0, "SMaxSampleValue" }, - { TIFFTAG_CLIPPATH, -1, -3, TIFF_BYTE, FIELD_CUSTOM, - 0, 1, "ClipPath" }, - { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SLONG, FIELD_CUSTOM, - 0, 0, "XClipPathUnits" }, - { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SSHORT, FIELD_CUSTOM, - 0, 0, "XClipPathUnits" }, - { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SBYTE, FIELD_CUSTOM, - 0, 0, "XClipPathUnits" }, - { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SLONG, FIELD_CUSTOM, - 0, 0, "YClipPathUnits" }, - { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SSHORT, FIELD_CUSTOM, - 0, 0, "YClipPathUnits" }, - { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SBYTE, FIELD_CUSTOM, - 0, 0, "YClipPathUnits" }, - { TIFFTAG_YCBCRCOEFFICIENTS, 3, 3, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "YCbCrCoefficients" }, - { TIFFTAG_YCBCRSUBSAMPLING, 2, 2, TIFF_SHORT, FIELD_YCBCRSUBSAMPLING, - 0, 0, "YCbCrSubsampling" }, - { TIFFTAG_YCBCRPOSITIONING, 1, 1, TIFF_SHORT, FIELD_YCBCRPOSITIONING, - 0, 0, "YCbCrPositioning" }, - { TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_RATIONAL, FIELD_REFBLACKWHITE, - 1, 0, "ReferenceBlackWhite" }, -/* XXX temporarily accept LONG for backwards compatibility */ - { TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_LONG, FIELD_REFBLACKWHITE, - 1, 0, "ReferenceBlackWhite" }, - { TIFFTAG_XMLPACKET, -3,-3, TIFF_BYTE, FIELD_CUSTOM, - 0, 1, "XMLPacket" }, -/* begin SGI tags */ - { TIFFTAG_MATTEING, 1, 1, TIFF_SHORT, FIELD_EXTRASAMPLES, - 0, 0, "Matteing" }, - { TIFFTAG_DATATYPE, -2,-1, TIFF_SHORT, FIELD_SAMPLEFORMAT, - 0, 0, "DataType" }, - { TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_LONG, FIELD_IMAGEDEPTH, - 0, 0, "ImageDepth" }, - { TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDEPTH, - 0, 0, "ImageDepth" }, - { TIFFTAG_TILEDEPTH, 1, 1, TIFF_LONG, FIELD_TILEDEPTH, - 0, 0, "TileDepth" }, - { TIFFTAG_TILEDEPTH, 1, 1, TIFF_SHORT, FIELD_TILEDEPTH, - 0, 0, "TileDepth" }, -/* end SGI tags */ -/* begin Pixar tags */ - { TIFFTAG_PIXAR_IMAGEFULLWIDTH, 1, 1, TIFF_LONG, FIELD_CUSTOM, - 1, 0, "ImageFullWidth" }, - { TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG, FIELD_CUSTOM, - 1, 0, "ImageFullLength" }, - { TIFFTAG_PIXAR_TEXTUREFORMAT, -1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "TextureFormat" }, - { TIFFTAG_PIXAR_WRAPMODES, -1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "TextureWrapModes" }, - { TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, FIELD_CUSTOM, - 1, 0, "FieldOfViewCotangent" }, - { TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16,16, TIFF_FLOAT, - FIELD_CUSTOM, 1, 0, "MatrixWorldToScreen" }, - { TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16,16, TIFF_FLOAT, - FIELD_CUSTOM, 1, 0, "MatrixWorldToCamera" }, - { TIFFTAG_COPYRIGHT, -1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "Copyright" }, -/* end Pixar tags */ - { TIFFTAG_RICHTIFFIPTC, -3, -3, TIFF_LONG, FIELD_CUSTOM, - 0, 1, "RichTIFFIPTC" }, - { TIFFTAG_PHOTOSHOP, -3, -3, TIFF_BYTE, FIELD_CUSTOM, - 0, 1, "Photoshop" }, - { TIFFTAG_EXIFIFD, 1, 1, TIFF_LONG, FIELD_CUSTOM, - 0, 0, "EXIFIFDOffset" }, - { TIFFTAG_ICCPROFILE, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, - 0, 1, "ICC Profile" }, - { TIFFTAG_GPSIFD, 1, 1, TIFF_LONG, FIELD_CUSTOM, - 0, 0, "GPSIFDOffset" }, - { TIFFTAG_STONITS, 1, 1, TIFF_DOUBLE, FIELD_CUSTOM, - 0, 0, "StoNits" }, - { TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_LONG, FIELD_CUSTOM, - 0, 0, "InteroperabilityIFDOffset" }, -/* begin DNG tags */ - { TIFFTAG_DNGVERSION, 4, 4, TIFF_BYTE, FIELD_CUSTOM, - 0, 0, "DNGVersion" }, - { TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, FIELD_CUSTOM, - 0, 0, "DNGBackwardVersion" }, - { TIFFTAG_UNIQUECAMERAMODEL, -1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "UniqueCameraModel" }, - { TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "LocalizedCameraModel" }, - { TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, FIELD_CUSTOM, - 1, 1, "LocalizedCameraModel" }, - { TIFFTAG_CFAPLANECOLOR, -1, -1, TIFF_BYTE, FIELD_CUSTOM, - 0, 1, "CFAPlaneColor" }, - { TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "CFALayout" }, - { TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, FIELD_CUSTOM, - 0, 1, "LinearizationTable" }, - { TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "BlackLevelRepeatDim" }, - { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_LONG, FIELD_CUSTOM, - 0, 1, "BlackLevel" }, - { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_SHORT, FIELD_CUSTOM, - 0, 1, "BlackLevel" }, - { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 1, "BlackLevel" }, - { TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 1, "BlackLevelDeltaH" }, - { TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 1, "BlackLevelDeltaV" }, - { TIFFTAG_WHITELEVEL, -2, -2, TIFF_LONG, FIELD_CUSTOM, - 0, 0, "WhiteLevel" }, - { TIFFTAG_WHITELEVEL, -2, -2, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "WhiteLevel" }, - { TIFFTAG_DEFAULTSCALE, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "DefaultScale" }, - { TIFFTAG_BESTQUALITYSCALE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "BestQualityScale" }, - { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_LONG, FIELD_CUSTOM, - 0, 0, "DefaultCropOrigin" }, - { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "DefaultCropOrigin" }, - { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "DefaultCropOrigin" }, - { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_LONG, FIELD_CUSTOM, - 0, 0, "DefaultCropSize" }, - { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "DefaultCropSize" }, - { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "DefaultCropSize" }, - { TIFFTAG_COLORMATRIX1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 1, "ColorMatrix1" }, - { TIFFTAG_COLORMATRIX2, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 1, "ColorMatrix2" }, - { TIFFTAG_CAMERACALIBRATION1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 1, "CameraCalibration1" }, - { TIFFTAG_CAMERACALIBRATION2, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 1, "CameraCalibration2" }, - { TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 1, "ReductionMatrix1" }, - { TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 1, "ReductionMatrix2" }, - { TIFFTAG_ANALOGBALANCE, -1, -1, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 1, "AnalogBalance" }, - { TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_SHORT, FIELD_CUSTOM, - 0, 1, "AsShotNeutral" }, - { TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 1, "AsShotNeutral" }, - { TIFFTAG_ASSHOTWHITEXY, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "AsShotWhiteXY" }, - { TIFFTAG_BASELINEEXPOSURE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 0, "BaselineExposure" }, - { TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "BaselineNoise" }, - { TIFFTAG_BASELINESHARPNESS, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "BaselineSharpness" }, - { TIFFTAG_BAYERGREENSPLIT, 1, 1, TIFF_LONG, FIELD_CUSTOM, - 0, 0, "BayerGreenSplit" }, - { TIFFTAG_LINEARRESPONSELIMIT, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "LinearResponseLimit" }, - { TIFFTAG_CAMERASERIALNUMBER, -1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "CameraSerialNumber" }, - { TIFFTAG_LENSINFO, 4, 4, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "LensInfo" }, - { TIFFTAG_CHROMABLURRADIUS, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "ChromaBlurRadius" }, - { TIFFTAG_ANTIALIASSTRENGTH, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "AntiAliasStrength" }, - { TIFFTAG_SHADOWSCALE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 0, 0, "ShadowScale" }, - { TIFFTAG_DNGPRIVATEDATA, -1, -1, TIFF_BYTE, FIELD_CUSTOM, - 0, 1, "DNGPrivateData" }, - { TIFFTAG_MAKERNOTESAFETY, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "MakerNoteSafety" }, - { TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "CalibrationIlluminant1" }, - { TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "CalibrationIlluminant2" }, - { TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, FIELD_CUSTOM, - 0, 0, "RawDataUniqueID" }, - { TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "OriginalRawFileName" }, - { TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, FIELD_CUSTOM, - 1, 1, "OriginalRawFileName" }, - { TIFFTAG_ORIGINALRAWFILEDATA, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, - 0, 1, "OriginalRawFileData" }, - { TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, FIELD_CUSTOM, - 0, 0, "ActiveArea" }, - { TIFFTAG_ACTIVEAREA, 4, 4, TIFF_SHORT, FIELD_CUSTOM, - 0, 0, "ActiveArea" }, - { TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, FIELD_CUSTOM, - 0, 1, "MaskedAreas" }, - { TIFFTAG_ASSHOTICCPROFILE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, - 0, 1, "AsShotICCProfile" }, - { TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 1, "AsShotPreProfileMatrix" }, - { TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, - 0, 1, "CurrentICCProfile" }, - { TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, - 0, 1, "CurrentPreProfileMatrix" }, -/* end DNG tags */ -}; -static const TIFFFieldInfo -exifFieldInfo[] = { - { EXIFTAG_EXPOSURETIME, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "ExposureTime" }, - { EXIFTAG_FNUMBER, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "FNumber" }, - { EXIFTAG_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "ExposureProgram" }, - { EXIFTAG_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "SpectralSensitivity" }, - { EXIFTAG_ISOSPEEDRATINGS, -1, -1, TIFF_SHORT, FIELD_CUSTOM, - 1, 1, "ISOSpeedRatings" }, - { EXIFTAG_OECF, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 1, "OptoelectricConversionFactor" }, - { EXIFTAG_EXIFVERSION, 4, 4, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 0, "ExifVersion" }, - { EXIFTAG_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "DateTimeOriginal" }, - { EXIFTAG_DATETIMEDIGITIZED, 20, 20, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "DateTimeDigitized" }, - { EXIFTAG_COMPONENTSCONFIGURATION, 4, 4, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 0, "ComponentsConfiguration" }, - { EXIFTAG_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "CompressedBitsPerPixel" }, - { EXIFTAG_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM, - 1, 0, "ShutterSpeedValue" }, - { EXIFTAG_APERTUREVALUE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "ApertureValue" }, - { EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM, - 1, 0, "BrightnessValue" }, - { EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM, - 1, 0, "ExposureBiasValue" }, - { EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "MaxApertureValue" }, - { EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "SubjectDistance" }, - { EXIFTAG_METERINGMODE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "MeteringMode" }, - { EXIFTAG_LIGHTSOURCE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "LightSource" }, - { EXIFTAG_FLASH, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "Flash" }, - { EXIFTAG_FOCALLENGTH, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "FocalLength" }, - { EXIFTAG_SUBJECTAREA, -1, -1, TIFF_SHORT, FIELD_CUSTOM, - 1, 1, "SubjectArea" }, - { EXIFTAG_MAKERNOTE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 1, "MakerNote" }, - { EXIFTAG_USERCOMMENT, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 1, "UserComment" }, - { EXIFTAG_SUBSECTIME, -1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "SubSecTime" }, - { EXIFTAG_SUBSECTIMEORIGINAL, -1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "SubSecTimeOriginal" }, - { EXIFTAG_SUBSECTIMEDIGITIZED,-1, -1, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "SubSecTimeDigitized" }, - { EXIFTAG_FLASHPIXVERSION, 4, 4, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 0, "FlashpixVersion" }, - { EXIFTAG_COLORSPACE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "ColorSpace" }, - { EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_LONG, FIELD_CUSTOM, - 1, 0, "PixelXDimension" }, - { EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "PixelXDimension" }, - { EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_LONG, FIELD_CUSTOM, - 1, 0, "PixelYDimension" }, - { EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "PixelYDimension" }, - { EXIFTAG_RELATEDSOUNDFILE, 13, 13, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "RelatedSoundFile" }, - { EXIFTAG_FLASHENERGY, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "FlashEnergy" }, - { EXIFTAG_SPATIALFREQUENCYRESPONSE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 1, "SpatialFrequencyResponse" }, - { EXIFTAG_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "FocalPlaneXResolution" }, - { EXIFTAG_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "FocalPlaneYResolution" }, - { EXIFTAG_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "FocalPlaneResolutionUnit" }, - { EXIFTAG_SUBJECTLOCATION, 2, 2, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "SubjectLocation" }, - { EXIFTAG_EXPOSUREINDEX, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "ExposureIndex" }, - { EXIFTAG_SENSINGMETHOD, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "SensingMethod" }, - { EXIFTAG_FILESOURCE, 1, 1, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 0, "FileSource" }, - { EXIFTAG_SCENETYPE, 1, 1, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 0, "SceneType" }, - { EXIFTAG_CFAPATTERN, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 1, "CFAPattern" }, - { EXIFTAG_CUSTOMRENDERED, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "CustomRendered" }, - { EXIFTAG_EXPOSUREMODE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "ExposureMode" }, - { EXIFTAG_WHITEBALANCE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "WhiteBalance" }, - { EXIFTAG_DIGITALZOOMRATIO, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "DigitalZoomRatio" }, - { EXIFTAG_FOCALLENGTHIN35MMFILM, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "FocalLengthIn35mmFilm" }, - { EXIFTAG_SCENECAPTURETYPE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "SceneCaptureType" }, - { EXIFTAG_GAINCONTROL, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM, - 1, 0, "GainControl" }, - { EXIFTAG_CONTRAST, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "Contrast" }, - { EXIFTAG_SATURATION, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "Saturation" }, - { EXIFTAG_SHARPNESS, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "Sharpness" }, - { EXIFTAG_DEVICESETTINGDESCRIPTION, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM, - 1, 1, "DeviceSettingDescription" }, - { EXIFTAG_SUBJECTDISTANCERANGE, 1, 1, TIFF_SHORT, FIELD_CUSTOM, - 1, 0, "SubjectDistanceRange" }, - { EXIFTAG_IMAGEUNIQUEID, 33, 33, TIFF_ASCII, FIELD_CUSTOM, - 1, 0, "ImageUniqueID" } +/* 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. + * + */ + +/* clang-format off */ /* for better readability of tag comments */ +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_IGNORE, 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_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CellWidth", NULL}, + {TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 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_NUMBEROFINKS, 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, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ClipPath", NULL}, + {TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL}, + {TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, 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, 1, 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_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, 1, 1, "RichTIFFIPTC", NULL}, + {TIFFTAG_PHOTOSHOP, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 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, 1, 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_IMAGESOURCEDATA, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "Adobe Photoshop Document Data Block", NULL}, + {TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, 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, 1, 0, "DNGVersion", NULL}, + {TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 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, 1, 1, "CFAPlaneColor", NULL}, + {TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CFALayout", NULL}, + {TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "LinearizationTable", NULL}, + {TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BlackLevelRepeatDim", NULL}, + {TIFFTAG_BLACKLEVEL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "BlackLevel", NULL}, + {TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "BlackLevelDeltaH", NULL}, + {TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "BlackLevelDeltaV", NULL}, + {TIFFTAG_WHITELEVEL, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "WhiteLevel", NULL}, + {TIFFTAG_DEFAULTSCALE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultScale", NULL}, + {TIFFTAG_BESTQUALITYSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BestQualityScale", NULL}, + {TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultCropOrigin", NULL}, + {TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultCropSize", NULL}, + {TIFFTAG_COLORMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ColorMatrix1", NULL}, + {TIFFTAG_COLORMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ColorMatrix2", NULL}, + {TIFFTAG_CAMERACALIBRATION1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibration1", NULL}, + {TIFFTAG_CAMERACALIBRATION2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibration2", NULL}, + {TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ReductionMatrix1", NULL}, + {TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ReductionMatrix2", NULL}, + {TIFFTAG_ANALOGBALANCE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AnalogBalance", NULL}, + {TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AsShotNeutral", NULL}, + {TIFFTAG_ASSHOTWHITEXY, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "AsShotWhiteXY", NULL}, + {TIFFTAG_BASELINEEXPOSURE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BaselineExposure", NULL}, + {TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BaselineNoise", NULL}, + {TIFFTAG_BASELINESHARPNESS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BaselineSharpness", NULL}, + {TIFFTAG_BAYERGREENSPLIT, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BayerGreenSplit", NULL}, + {TIFFTAG_LINEARRESPONSELIMIT, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 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, 1, 0, "LensInfo", NULL}, + {TIFFTAG_CHROMABLURRADIUS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ChromaBlurRadius", NULL}, + {TIFFTAG_ANTIALIASSTRENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "AntiAliasStrength", NULL}, + {TIFFTAG_SHADOWSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ShadowScale", NULL}, + {TIFFTAG_DNGPRIVATEDATA, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "DNGPrivateData", NULL}, + {TIFFTAG_MAKERNOTESAFETY, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MakerNoteSafety", NULL}, + {TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant1", NULL}, + {TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant2", NULL}, + {TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 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, 1, 1, "OriginalRawFileData", NULL}, + {TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ActiveArea", NULL}, + {TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "MaskedAreas", NULL}, + {TIFFTAG_ASSHOTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AsShotICCProfile", NULL}, + {TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AsShotPreProfileMatrix", NULL}, + {TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CurrentICCProfile", NULL}, + {TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CurrentPreProfileMatrix", NULL}, + {TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL}, +#if 0 + /* TODO: revert above #if 0 for TIFF 4.6.0 */ + + /* begin DNG 1.2.0.0 tags */ + {TIFFTAG_COLORIMETRICREFERENCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorimetricReference", NULL}, + {TIFFTAG_CAMERACALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibrationSignature", NULL}, + {TIFFTAG_PROFILECALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileCalibrationSignature", NULL}, + {TIFFTAG_EXTRACAMERAPROFILES, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ExtraCameraProfiles", NULL}, + {TIFFTAG_ASSHOTPROFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "AsShotProfileName", NULL}, + {TIFFTAG_NOISEREDUCTIONAPPLIED, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NoiseReductionApplied", NULL}, + {TIFFTAG_PROFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileName", NULL}, + {TIFFTAG_PROFILEHUESATMAPDIMS, 3, 3, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileHueSatMapDims", NULL}, + {TIFFTAG_PROFILEHUESATMAPDATA1, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData1", NULL}, + {TIFFTAG_PROFILEHUESATMAPDATA2, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData2", NULL}, + {TIFFTAG_PROFILETONECURVE, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileToneCurve", NULL}, + {TIFFTAG_PROFILEEMBEDPOLICY, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileEmbedPolicy", NULL}, + {TIFFTAG_PROFILECOPYRIGHT, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileCopyright", NULL}, + {TIFFTAG_FORWARDMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ForwardMatrix1", NULL}, + {TIFFTAG_FORWARDMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ForwardMatrix2", NULL}, + {TIFFTAG_PREVIEWAPPLICATIONNAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "PreviewApplicationName", NULL}, + {TIFFTAG_PREVIEWAPPLICATIONVERSION, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "PreviewApplicationVersion", NULL}, + {TIFFTAG_PREVIEWSETTINGSNAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "PreviewSettingsName", NULL}, + {TIFFTAG_PREVIEWSETTINGSDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewSettingsDigest", NULL}, + {TIFFTAG_PREVIEWCOLORSPACE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewColorSpace", NULL}, + {TIFFTAG_PREVIEWDATETIME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "PreviewDateTime", NULL}, + {TIFFTAG_RAWIMAGEDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RawImageDigest", NULL}, + {TIFFTAG_ORIGINALRAWFILEDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OriginalRawFileDigest", NULL}, + {TIFFTAG_SUBTILEBLOCKSIZE, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubTileBlockSize", NULL}, + {TIFFTAG_ROWINTERLEAVEFACTOR, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RowInterleaveFactor", NULL}, + {TIFFTAG_PROFILELOOKTABLEDIMS, 3, 3, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileLookTableDims", NULL}, + {TIFFTAG_PROFILELOOKTABLEDATA, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileLookTableData", NULL}, + /* begin DNG 1.3.0.0 tags */ + {TIFFTAG_OPCODELIST1, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList1", NULL}, + {TIFFTAG_OPCODELIST2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList2", NULL}, + {TIFFTAG_OPCODELIST3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OpcodeList3", NULL}, + {TIFFTAG_NOISEPROFILE, -1, -1, TIFF_DOUBLE, 0, TIFF_SETGET_C16_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "NoiseProfile", NULL}, + /* begin DNG 1.4.0.0 tags */ + {TIFFTAG_DEFAULTUSERCROP, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultUserCrop", NULL}, + {TIFFTAG_DEFAULTBLACKRENDER, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DefaultBlackRender", NULL}, + {TIFFTAG_BASELINEEXPOSUREOFFSET, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BaselineExposureOffset", NULL}, + {TIFFTAG_PROFILELOOKTABLEENCODING, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileLookTableEncoding", NULL}, + {TIFFTAG_PROFILEHUESATMAPENCODING, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileHueSatMapEncoding", NULL}, + {TIFFTAG_ORIGINALDEFAULTFINALSIZE, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OriginalDefaultFinalSize", NULL}, + {TIFFTAG_ORIGINALBESTQUALITYFINALSIZE, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OriginalBestQualityFinalSize", NULL}, + {TIFFTAG_ORIGINALDEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "OriginalDefaultCropSize", NULL}, /* could also be rational */ + {TIFFTAG_NEWRAWIMAGEDIGEST, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NewRawImageDigest", NULL}, + {TIFFTAG_RAWTOPREVIEWGAIN, 1, 1, TIFF_DOUBLE, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "RawToPreviewGain", NULL}, + /* begin DNG 1.5.0.0 tags */ + {TIFFTAG_DEPTHFORMAT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthFormat", NULL}, + {TIFFTAG_DEPTHNEAR, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthNear", NULL}, + {TIFFTAG_DEPTHFAR, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthFar", NULL}, + {TIFFTAG_DEPTHUNITS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthUnits", NULL}, + {TIFFTAG_DEPTHMEASURETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DepthMeasureType", NULL}, + {TIFFTAG_ENHANCEPARAMS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EnhanceParams", NULL}, + /* begin DNG 1.6.0.0 tags */ + {TIFFTAG_PROFILEGAINTABLEMAP, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileGainTableMap", NULL}, + {TIFFTAG_SEMANTICNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SemanticName", NULL}, + {TIFFTAG_SEMANTICINSTANCEID, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SemanticInstanceID", NULL}, + {TIFFTAG_MASKSUBAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaskSubArea", NULL}, + {TIFFTAG_RGBTABLES, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "RGBTables", NULL}, + {TIFFTAG_CALIBRATIONILLUMINANT3, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CalibrationIlluminant3", NULL}, + {TIFFTAG_COLORMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ColorMatrix3", NULL}, + {TIFFTAG_CAMERACALIBRATION3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibration3", NULL}, + {TIFFTAG_REDUCTIONMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ReductionMatrix3", NULL}, + {TIFFTAG_PROFILEHUESATMAPDATA3, -1, -1, TIFF_FLOAT, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ProfileHueSatMapData3", NULL}, + {TIFFTAG_FORWARDMATRIX3, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ForwardMatrix3", NULL}, + {TIFFTAG_ILLUMINANTDATA1, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData1", NULL}, + {TIFFTAG_ILLUMINANTDATA2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData2", NULL}, + {TIFFTAG_ILLUMINANTDATA3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData3", NULL}, + /* end DNG tags */ + /* begin TIFF/EP tags */ + {TIFFTAG_EP_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP CFARepeatPatternDim", NULL}, + {TIFFTAG_EP_CFAPATTERN, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP CFAPattern", NULL}, + /* TIFFTAG_EP_BATTERYLEVEL can be RATIONAL or ASCII. + * LibTiff defines it as ASCII and converts RATIONAL to an ASCII string. */ + {TIFFTAG_EP_BATTERYLEVEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP BatteryLevel", NULL}, + {TIFFTAG_EP_INTERLACE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP Interlace", NULL}, + /* TIFFTAG_EP_IPTC_NAA and TIFFTAG_RICHTIFFIPTC share the same tag number (33723) + * LibTIFF type is UNDEFINED or BYTE, but often times incorrectly specified as LONG, because TIFF/EP (ISO/DIS 12234-2) specifies type LONG or ASCII. */ + {TIFFTAG_EP_TIMEZONEOFFSET, -1, -1, TIFF_SSHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP TimeZoneOffset", NULL}, + {TIFFTAG_EP_SELFTIMERMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SelfTimerMode", NULL}, + {TIFFTAG_EP_FLASHENERGY, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP FlashEnergy", NULL}, + {TIFFTAG_EP_SPATIALFREQUENCYRESPONSE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP SpatialFrequencyResponse", NULL}, + {TIFFTAG_EP_NOISE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP Noise", NULL}, + {TIFFTAG_EP_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP FocalPlaneXResolution", NULL}, + {TIFFTAG_EP_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP FocalPlaneYResolution", NULL}, + {TIFFTAG_EP_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP FocalPlaneResolutionUnit", NULL}, + {TIFFTAG_EP_IMAGENUMBER, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ImageNumber", NULL}, /* or SHORT */ + {TIFFTAG_EP_SECURITYCLASSIFICATION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SecurityClassification", NULL}, + {TIFFTAG_EP_IMAGEHISTORY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ImageHistory", NULL}, + {TIFFTAG_EP_EXPOSUREINDEX, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP ExposureIndex", NULL}, + {TIFFTAG_EP_STANDARDID, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP StandardId", NULL}, + {TIFFTAG_EP_SENSINGMETHOD, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SensingMethod", NULL}, + /* TIFF/EP tags equivalent to EXIF tags, sometimes defined differently. */ + {TIFFTAG_EP_EXPOSURETIME, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP ExposureTime", NULL}, /*N=1 or 2 */ + {TIFFTAG_EP_FNUMBER, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP FNumber", NULL}, + {TIFFTAG_EP_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ExposureProgram", NULL}, + {TIFFTAG_EP_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP SpectralSensitivity", NULL}, + {TIFFTAG_EP_ISOSPEEDRATINGS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ISOSpeedRatings", NULL}, + {TIFFTAG_EP_OECF, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP OptoelectricConversionFactor", NULL}, + {TIFFTAG_EP_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP DateTimeOriginal", NULL}, + {TIFFTAG_EP_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP CompressedBitsPerPixel", NULL}, + {TIFFTAG_EP_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ShutterSpeedValue", NULL}, + {TIFFTAG_EP_APERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP ApertureValue", NULL}, + {TIFFTAG_EP_BRIGHTNESSVALUE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP BrightnessValue", NULL}, + {TIFFTAG_EP_EXPOSUREBIASVALUE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP ExposureBiasValue", NULL}, /*N=1 or 2 */ + {TIFFTAG_EP_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP MaxApertureValue", NULL}, + {TIFFTAG_EP_SUBJECTDISTANCE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP SubjectDistance", NULL}, + {TIFFTAG_EP_METERINGMODE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP MeteringMode", NULL}, + {TIFFTAG_EP_LIGHTSOURCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP LightSource", NULL}, + {TIFFTAG_EP_FLASH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP Flash", NULL}, + {TIFFTAG_EP_FOCALLENGTH, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP FocalLength", NULL}, + {TIFFTAG_EP_SUBJECTLOCATION, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP SubjectLocation", NULL}, + /* end TIFF/EP tags */ +#endif + /* begin TIFF/FX tags */ + {TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Indexed", NULL}, + {TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "GlobalParametersIFD", NULL}, + {TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ProfileType", NULL}, + {TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FaxProfile", NULL}, + {TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CodingMethods", NULL}, + {TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "VersionYear", NULL}, + {TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ModeNumber", NULL}, + {TIFFTAG_DECODE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "Decode", NULL}, + {TIFFTAG_IMAGEBASECOLOR, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ImageBaseColor", NULL}, + {TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "T82Options", NULL}, + {TIFFTAG_STRIPROWCOUNTS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "StripRowCounts", NULL}, + {TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageLayer", NULL}, + /* end TIFF/FX tags */ + /* begin pseudo tags */ }; -const TIFFFieldInfo * -_TIFFGetFieldInfo(size_t *size) -{ - *size = TIFFArrayCount(tiffFieldInfo); - return tiffFieldInfo; -} +/* + * 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}, + /* After EXIF 2.2.1 ISOSpeedRatings is named PhotographicSensitivity. In addition, while "Count=Any", only 1 count should be used. */ + {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) + */ -const TIFFFieldInfo * -_TIFFGetExifFieldInfo(size_t *size) -{ - *size = TIFFArrayCount(exifFieldInfo); - return exifFieldInfo; -} +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}}; +/* clang-format on */ /* was off for better readability of tag comments */ + +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}; -void -_TIFFSetupFieldInfo(TIFF* tif, const TIFFFieldInfo info[], size_t n) +/* + * 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 *)) { - if (tif->tif_fieldinfo) { - size_t i; - - for (i = 0; i < tif->tif_nfields; i++) - { - TIFFFieldInfo *fld = tif->tif_fieldinfo[i]; - if (fld->field_bit == FIELD_CUSTOM && - strncmp("Tag ", fld->field_name, 4) == 0) { - _TIFFfree(fld->field_name); - _TIFFfree(fld); - } - } - - _TIFFfree(tif->tif_fieldinfo); - tif->tif_nfields = 0; - } - if (!_TIFFMergeFieldInfo(tif, info, n)) - { - TIFFErrorExt(tif->tif_clientdata, "_TIFFSetupFieldInfo", - "Setting up field info failed"); - } + 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; } -static int -tagCompare(const void* a, const void* b) +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) { - const TIFFFieldInfo* ta = *(const TIFFFieldInfo**) a; - const TIFFFieldInfo* tb = *(const TIFFFieldInfo**) 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); + 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_name != NULL) + { + if (fld->field_bit == FIELD_CUSTOM && TIFFFieldIsAnonymous(fld)) + { + _TIFFfreeExt(tif, fld->field_name); + /* caution: tif_fields[i] must not be the beginning of a + * fields-array. Otherwise the following tags are also freed + * with the first free(). + */ + _TIFFfreeExt(tif, fld); + } + } + } + + _TIFFfreeExt(tif, tif->tif_fields); + tif->tif_fields = NULL; + tif->tif_nfields = 0; + } + if (!_TIFFMergeFields(tif, fieldarray->fields, fieldarray->count)) + { + TIFFErrorExtR(tif, "_TIFFSetupFields", "Setting up field info failed"); + } } -static int -tagNameCompare(const void* a, const void* b) +static int tagCompare(const void *a, const void *b) { - const TIFFFieldInfo* ta = *(const TIFFFieldInfo**) a; - const TIFFFieldInfo* tb = *(const TIFFFieldInfo**) 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); + 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); } -void -TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], int n) +static int tagNameCompare(const void *a, const void *b) { - if (_TIFFMergeFieldInfo(tif, info, n) < 0) - { - TIFFErrorExt(tif->tif_clientdata, "TIFFMergeFieldInfo", - "Merging block of %d fields failed", n); - } + 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 -_TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], int n) +int _TIFFMergeFields(TIFF *tif, const TIFFField info[], uint32_t n) { - static const char module[] = "_TIFFMergeFieldInfo"; - static const char reason[] = "for field info array"; - TIFFFieldInfo** tp; - int i; - - tif->tif_foundfield = NULL; - - if (tif->tif_nfields > 0) { - tif->tif_fieldinfo = (TIFFFieldInfo**) - _TIFFCheckRealloc(tif, tif->tif_fieldinfo, - (tif->tif_nfields + n), - sizeof (TIFFFieldInfo*), reason); - } else { - tif->tif_fieldinfo = (TIFFFieldInfo**) - _TIFFCheckMalloc(tif, n, sizeof (TIFFFieldInfo*), - reason); - } - if (!tif->tif_fieldinfo) { - TIFFErrorExt(tif->tif_clientdata, module, - "Failed to allocate field info array"); - return 0; - } - tp = tif->tif_fieldinfo + tif->tif_nfields; - for (i = 0; i < n; i++) - { - const TIFFFieldInfo *fip = - _TIFFFindFieldInfo(tif, info[i].field_tag, info[i].field_type); + static const char module[] = "_TIFFMergeFields"; + static const char reason[] = "for fields array"; + /* TIFFField** tp; */ + uint32_t i; - /* only add definitions that aren't already present */ - if (!fip) { - *tp++ = (TIFFFieldInfo*) (info + i); - tif->tif_nfields++; - } + 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) + { + TIFFErrorExtR(tif, 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_fieldinfo, tif->tif_nfields, - sizeof (TIFFFieldInfo*), tagCompare); + /* Sort the field info by tag number */ + qsort(tif->tif_fields, tif->tif_nfields, sizeof(TIFFField *), tagCompare); - return n; + return n; } -void -_TIFFPrintFieldInfo(TIFF* tif, FILE* fd) +void _TIFFPrintFieldInfo(TIFF *tif, FILE *fd) { - size_t i; - - fprintf(fd, "%s: \n", tif->tif_name); - for (i = 0; i < tif->tif_nfields; i++) { - const TIFFFieldInfo* fip = tif->tif_fieldinfo[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 - ); - } + 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 + * Return size of TIFFDataType within TIFF-file in bytes */ -int -TIFFDataWidth(TIFFDataType type) +int TIFFDataWidth(TIFFDataType type) { - switch(type) - { - case 0: /* nothing */ - case 1: /* TIFF_BYTE */ - case 2: /* TIFF_ASCII */ - case 6: /* TIFF_SBYTE */ - case 7: /* TIFF_UNDEFINED */ - return 1; - case 3: /* TIFF_SHORT */ - case 8: /* TIFF_SSHORT */ - return 2; - case 4: /* TIFF_LONG */ - case 9: /* TIFF_SLONG */ - case 11: /* TIFF_FLOAT */ - case 13: /* TIFF_IFD */ - return 4; - case 5: /* TIFF_RATIONAL */ - case 10: /* TIFF_SRATIONAL */ - case 12: /* TIFF_DOUBLE */ - return 8; - default: - return 0; /* will return 0 for unknown types */ - } + 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. + * Return internal storage size of TIFFSetGetFieldType in bytes. + * TIFFSetField() and TIFFGetField() have to provide the parameter accordingly. + * Replaces internal functions _TIFFDataSize() and _TIFFSetGetFieldSize() + * with now extern available function TIFFFieldSetGetSize(). */ -int -_TIFFDataSize(TIFFDataType type) +int TIFFFieldSetGetSize(const TIFFField *fip) { - 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: - return 8; - default: - return 0; - } -} + /* + * TIFFSetField() and TIFFGetField() must provide the parameter accordingly + * to the definition of "set_field_type" of the tag definition in + * dir_info.c. This function returns the data size for that purpose. + * + * Furthermore, this data size is also used for the internal storage, + * even for TIFF_RATIONAL values for FIELD_CUSTOM, which are stored + * internally as 4-byte float, but some of them should be stored internally + * as 8-byte double, depending on the "set_field_type" _FLOAT_ or _DOUBLE_. + */ + if (fip == NULL) + return 0; + + switch (fip->set_field_type) + { + 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 1; + 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; + } +} /*-- TIFFFieldSetGetSize() --- */ /* - * Return nearest TIFFDataType to the sample type of an image. + * Return size of count parameter of TIFFSetField() and TIFFGetField() + * and also if it is required: 0=none, 2=uint16_t, 4=uint32_t */ -TIFFDataType -_TIFFSampleToTagType(TIFF* tif) +int TIFFFieldSetGetCountSize(const TIFFField *fip) { - uint32 bps = TIFFhowmany8(tif->tif_dir.td_bitspersample); - - switch (tif->tif_dir.td_sampleformat) { - case SAMPLEFORMAT_IEEEFP: - return (bps == 4 ? TIFF_FLOAT : TIFF_DOUBLE); - case SAMPLEFORMAT_INT: - return (bps <= 1 ? TIFF_SBYTE : - bps <= 2 ? TIFF_SSHORT : TIFF_SLONG); - case SAMPLEFORMAT_UINT: - return (bps <= 1 ? TIFF_BYTE : - bps <= 2 ? TIFF_SHORT : TIFF_LONG); - case SAMPLEFORMAT_VOID: - return (TIFF_UNDEFINED); - } - /*NOTREACHED*/ - return (TIFF_UNDEFINED); -} + if (fip == NULL) + return 0; + + switch (fip->set_field_type) + { + case TIFF_SETGET_C16_ASCII: + case TIFF_SETGET_C16_UINT8: + case TIFF_SETGET_C16_SINT8: + case TIFF_SETGET_C16_UINT16: + case TIFF_SETGET_C16_SINT16: + case TIFF_SETGET_C16_UINT32: + case TIFF_SETGET_C16_SINT32: + case TIFF_SETGET_C16_FLOAT: + case TIFF_SETGET_C16_UINT64: + case TIFF_SETGET_C16_SINT64: + case TIFF_SETGET_C16_DOUBLE: + case TIFF_SETGET_C16_IFD8: + return 2; + case TIFF_SETGET_C32_ASCII: + case TIFF_SETGET_C32_UINT8: + case TIFF_SETGET_C32_SINT8: + case TIFF_SETGET_C32_UINT16: + case TIFF_SETGET_C32_SINT16: + case TIFF_SETGET_C32_UINT32: + case TIFF_SETGET_C32_SINT32: + case TIFF_SETGET_C32_FLOAT: + case TIFF_SETGET_C32_UINT64: + case TIFF_SETGET_C32_SINT64: + case TIFF_SETGET_C32_DOUBLE: + case TIFF_SETGET_C32_IFD8: + return 4; + default: + return 0; + } +} /*-- TIFFFieldSetGetCountSize() --- */ -const TIFFFieldInfo* -_TIFFFindFieldInfo(TIFF* tif, ttag_t tag, TIFFDataType dt) +const TIFFField *TIFFFindField(TIFF *tif, uint32_t tag, TIFFDataType dt) { - TIFFFieldInfo key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0}; - TIFFFieldInfo* pkey = &key; - const TIFFFieldInfo **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_fieldinfo ) { - return NULL; - } - - /* NB: use sorted search (e.g. binary search) */ - key.field_tag = tag; - key.field_type = dt; - - ret = (const TIFFFieldInfo **) bsearch(&pkey, - tif->tif_fieldinfo, - tif->tif_nfields, - sizeof(TIFFFieldInfo *), - tagCompare); - return tif->tif_foundfield = (ret ? *ret : NULL); + 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); } -const TIFFFieldInfo* -_TIFFFindFieldInfoByName(TIFF* tif, const char *field_name, TIFFDataType dt) +static const TIFFField *_TIFFFindFieldByName(TIFF *tif, const char *field_name, + TIFFDataType dt) { - TIFFFieldInfo key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0}; - TIFFFieldInfo* pkey = &key; - const TIFFFieldInfo **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_fieldinfo ) { - return NULL; - } - - /* NB: use sorted search (e.g. binary search) */ - key.field_name = (char *)field_name; - key.field_type = dt; - - ret = (const TIFFFieldInfo **) lfind(&pkey, - tif->tif_fieldinfo, - &tif->tif_nfields, - sizeof(TIFFFieldInfo *), - tagNameCompare); - return tif->tif_foundfield = (ret ? *ret : NULL); + 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 TIFFFieldInfo* -_TIFFFieldWithTag(TIFF* tif, ttag_t tag) +const TIFFField *TIFFFieldWithTag(TIFF *tif, uint32_t tag) { - const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); - if (!fip) { - TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithTag", - "Internal error, unknown tag 0x%x", - (unsigned int) tag); - assert(fip != NULL); - /*NOTREACHED*/ - } - return (fip); + const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY); + if (!fip) + { + TIFFWarningExtR(tif, "TIFFFieldWithTag", "Warning, unknown tag 0x%x", + (unsigned int)tag); + } + return (fip); } -const TIFFFieldInfo* -_TIFFFieldWithName(TIFF* tif, const char *field_name) +const TIFFField *TIFFFieldWithName(TIFF *tif, const char *field_name) { - const TIFFFieldInfo* fip = - _TIFFFindFieldInfoByName(tif, field_name, TIFF_ANY); - if (!fip) { - TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithName", - "Internal error, unknown tag %s", field_name); - assert(fip != NULL); - /*NOTREACHED*/ - } - return (fip); + const TIFFField *fip = _TIFFFindFieldByName(tif, field_name, TIFF_ANY); + if (!fip) + { + TIFFWarningExtR(tif, "TIFFFieldWithName", "Warning, unknown tag %s", + field_name); + } + return (fip); } -const TIFFFieldInfo* -_TIFFFindOrRegisterFieldInfo( TIFF *tif, ttag_t tag, TIFFDataType dt ) +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; } + +int TIFFFieldIsAnonymous(const TIFFField *fip) { return fip->field_anonymous; } + +const TIFFField *_TIFFFindOrRegisterField(TIFF *tif, uint32_t tag, + TIFFDataType dt) { - const TIFFFieldInfo *fld; + const TIFFField *fld; - fld = _TIFFFindFieldInfo( tif, tag, dt ); - if( fld == NULL ) + fld = TIFFFindField(tif, tag, dt); + if (fld == NULL) { - fld = _TIFFCreateAnonFieldInfo( tif, tag, dt ); - if (!_TIFFMergeFieldInfo(tif, fld, 1)) - return NULL; + fld = _TIFFCreateAnonField(tif, tag, dt); + if (!_TIFFMergeFields(tif, fld, 1)) + return NULL; } return fld; } -TIFFFieldInfo* -_TIFFCreateAnonFieldInfo(TIFF *tif, ttag_t tag, TIFFDataType field_type) +TIFFField *_TIFFCreateAnonField(TIFF *tif, uint32_t tag, + TIFFDataType field_type) { - TIFFFieldInfo *fld; - (void) tif; - - fld = (TIFFFieldInfo *) _TIFFmalloc(sizeof (TIFFFieldInfo)); - if (fld == NULL) - return NULL; - _TIFFmemset( fld, 0, sizeof(TIFFFieldInfo) ); - - fld->field_tag = tag; - fld->field_readcount = TIFF_VARIABLE2; - fld->field_writecount = TIFF_VARIABLE2; - fld->field_type = field_type; - 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; - } - - /* - * note that this name is a special sign to TIFFClose() and - * _TIFFSetupFieldInfo() to free the field - */ - sprintf(fld->field_name, "Tag %d", (int) tag); - - return fld; + TIFFField *fld; + (void)tif; + + fld = (TIFFField *)_TIFFmallocExt(tif, 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->field_anonymous = + 1; /* indicate that this is an anonymous / unknown tag */ + 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 *)_TIFFmallocExt(tif, 32); + if (fld->field_name == NULL) + { + _TIFFfreeExt(tif, fld); + return NULL; + } + fld->field_subfields = NULL; + + /* + * note that this name is a special sign to TIFFClose() and + * _TIFFSetupFields() to free the field + * Update: + * This special sign is replaced by fld->field_anonymous flag. + */ + (void)snprintf(fld->field_name, 32, "Tag %d", (int)tag); + + return fld; } -/* vim: set ts=8 sts=8 sw=8 noet: */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ +/**************************************************************************** + * 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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->field_anonymous = 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; + if (info[i].field_name == NULL) + { + TIFFErrorExtR(tif, module, + "Field_name of %d.th allocation tag %d is NULL", i, + info[i].field_tag); + return -1; + } + tp->field_name = info[i].field_name; + tp->field_subfields = NULL; + tp++; + } + + if (!_TIFFMergeFields(tif, tif->tif_fieldscompat[nfields].fields, n)) + { + TIFFErrorExtR(tif, 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; + } + if (!TIFFIsCODECConfigured(tif->tif_dir.td_compression)) + { + return 0; + } + /* 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; +} diff --git a/LibTiff/tif_dirread.c b/LibTiff/tif_dirread.c index 907b5318..2c49dc6a 100644 --- a/LibTiff/tif_dirread.c +++ b/LibTiff/tif_dirread.c @@ -1,26 +1,24 @@ -/* $Id: tif_dirread.c,v 1.92.2.9 2010-06-14 00:21:46 fwarmerdam Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -29,2053 +27,7872 @@ * * 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 +#include +#include -#define IGNORE 0 /* tag placeholder used below */ +#define FAILED_FII ((uint32_t)-1) #ifdef HAVE_IEEEFP -# define TIFFCvtIEEEFloatToNative(tif, n, fp) -# define TIFFCvtIEEEDoubleToNative(tif, n, dp) +#define TIFFCvtIEEEFloatToNative(tif, n, fp) +#define TIFFCvtIEEEDoubleToNative(tif, n, dp) #else -extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*); -extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, double*); +extern void TIFFCvtIEEEFloatToNative(TIFF *, uint32_t, float *); +extern void TIFFCvtIEEEDoubleToNative(TIFF *, uint32_t, double *); #endif -static TIFFDirEntry* TIFFReadDirectoryFind(TIFFDirEntry* dir, - uint16 dircount, uint16 tagid); -static int EstimateStripByteCounts(TIFF*, TIFFDirEntry*, uint16); -static void MissingRequired(TIFF*, const char*); -static int TIFFCheckDirOffset(TIFF*, toff_t); -static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32); -static uint16 TIFFFetchDirectory(TIFF*, toff_t, TIFFDirEntry**, toff_t *); -static tsize_t TIFFFetchData(TIFF*, TIFFDirEntry*, char*); -static tsize_t TIFFFetchString(TIFF*, TIFFDirEntry*, char*); -static float TIFFFetchRational(TIFF*, TIFFDirEntry*); -static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*); -static int TIFFFetchPerSampleShorts(TIFF*, TIFFDirEntry*, uint16*); -static int TIFFFetchPerSampleLongs(TIFF*, TIFFDirEntry*, uint32*); -static int TIFFFetchPerSampleAnys(TIFF*, TIFFDirEntry*, double*); -static int TIFFFetchShortArray(TIFF*, TIFFDirEntry*, uint16*); -static int TIFFFetchStripThing(TIFF*, TIFFDirEntry*, long, uint32**); -static int TIFFFetchRefBlackWhite(TIFF*, TIFFDirEntry*); -static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*); -static float TIFFFetchFloat(TIFF*, TIFFDirEntry*); -static int TIFFFetchFloatArray(TIFF*, TIFFDirEntry*, float*); -static int TIFFFetchDoubleArray(TIFF*, TIFFDirEntry*, double*); -static int TIFFFetchAnyArray(TIFF*, TIFFDirEntry*, double*); -static int TIFFFetchShortPair(TIFF*, TIFFDirEntry*); -static void ChopUpSingleUncompressedStrip(TIFF*); - -/* - * 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"; - - int n; - TIFFDirectory* td; - TIFFDirEntry *dp, *dir = NULL; - uint16 iv; - uint32 v; - const TIFFFieldInfo* fip; - size_t fix; - uint16 dircount; - int diroutoforderwarning = 0, compressionknown = 0; - int haveunknowntags = 0; - - tif->tif_diroff = tif->tif_nextdiroff; - /* - * Check whether we have the last offset or bad offset (IFD looping). - */ - if (!TIFFCheckDirOffset(tif, tif->tif_nextdiroff)) - return 0; - /* - * Cleanup any previous compression state. - */ - (*tif->tif_cleanup)(tif); - tif->tif_curdir++; - dircount = TIFFFetchDirectory(tif, tif->tif_nextdiroff, - &dir, &tif->tif_nextdiroff); - if (!dircount) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Failed to read directory at offset %u", - tif->tif_name, tif->tif_nextdiroff); - return 0; - } - - tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ - /* - * 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 everthing not taken in the first pass. - */ - td = &tif->tif_dir; - /* 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); - - /* - * Sigh, we must make a separate pass through the - * directory for the following reason: - * - * We must process the Compression tag in the first pass - * 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 permited 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). - * - * It sure would have been nice if Aldus had really thought - * this stuff through carefully. - */ - for (dp = dir, n = dircount; n > 0; n--, dp++) { - if (tif->tif_flags & TIFF_SWAB) { - TIFFSwabArrayOfShort(&dp->tdir_tag, 2); - TIFFSwabArrayOfLong(&dp->tdir_count, 2); - } - if (dp->tdir_tag == TIFFTAG_SAMPLESPERPIXEL) { - if (!TIFFFetchNormalTag(tif, dp)) - goto bad; - dp->tdir_tag = IGNORE; - } - } - /* - * First real pass over the directory. - */ - fix = 0; - for (dp = dir, n = dircount; n > 0; n--, dp++) { - - if (dp->tdir_tag == IGNORE) - continue; - if (fix >= tif->tif_nfields) - fix = 0; - - /* - * Silicon Beach (at least) writes unordered - * directory tags (violating the spec). Handle - * it here, but be obnoxious (maybe they'll fix it?). - */ - if (dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) { - if (!diroutoforderwarning) { - TIFFWarningExt(tif->tif_clientdata, module, - "%s: invalid TIFF directory; tags are not sorted in ascending order", - tif->tif_name); - diroutoforderwarning = 1; - } - fix = 0; /* O(n^2) */ - } - while (fix < tif->tif_nfields && - tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) - fix++; - if (fix >= tif->tif_nfields || - tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) { - /* Unknown tag ... we'll deal with it below */ - haveunknowntags = 1; - continue; - } - /* - * Null out old tags that we ignore. - */ - if (tif->tif_fieldinfo[fix]->field_bit == FIELD_IGNORE) { - ignore: - dp->tdir_tag = IGNORE; - continue; - } - /* - * Check data type. - */ - fip = tif->tif_fieldinfo[fix]; - while (dp->tdir_type != (unsigned short) fip->field_type - && fix < tif->tif_nfields) { - if (fip->field_type == TIFF_ANY) /* wildcard */ - break; - fip = tif->tif_fieldinfo[++fix]; - if (fix >= tif->tif_nfields || - fip->field_tag != dp->tdir_tag) { - TIFFWarningExt(tif->tif_clientdata, module, - "%s: wrong data type %d for \"%s\"; tag ignored", - tif->tif_name, dp->tdir_type, - tif->tif_fieldinfo[fix-1]->field_name); - goto ignore; - } - } - /* - * Check count if known in advance. - */ - if (fip->field_readcount != TIFF_VARIABLE - && fip->field_readcount != TIFF_VARIABLE2) { - uint32 expected = (fip->field_readcount == TIFF_SPP) ? - (uint32) td->td_samplesperpixel : - (uint32) fip->field_readcount; - if (!CheckDirCount(tif, dp, expected)) - goto ignore; - } - - switch (dp->tdir_tag) { - case TIFFTAG_COMPRESSION: - /* - * 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. - */ - if (dp->tdir_count == 1) { - v = TIFFExtractData(tif, - dp->tdir_type, dp->tdir_offset); - if (!TIFFSetField(tif, dp->tdir_tag, (uint16)v)) - goto bad; - else - compressionknown = 1; - break; - /* XXX: workaround for broken TIFFs */ - } else if (dp->tdir_type == TIFF_LONG) { - if (!TIFFFetchPerSampleLongs(tif, dp, &v) || - !TIFFSetField(tif, dp->tdir_tag, (uint16)v)) - goto bad; - } else { - if (!TIFFFetchPerSampleShorts(tif, dp, &iv) - || !TIFFSetField(tif, dp->tdir_tag, iv)) - goto bad; - } - dp->tdir_tag = IGNORE; - break; - 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)) - goto bad; - dp->tdir_tag = IGNORE; - break; - } - } - - /* - * If we saw any unknown tags, make an extra pass over the directory - * to deal with them. This must be done separately because the tags - * could have become known when we registered a codec after finding - * the Compression tag. In a correctly-sorted directory there's - * no problem because Compression will come before any codec-private - * tags, but if the sorting is wrong that might not hold. - */ - if (haveunknowntags) { - fix = 0; - for (dp = dir, n = dircount; n > 0; n--, dp++) { - if (dp->tdir_tag == IGNORE) - continue; - if (fix >= tif->tif_nfields || - dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) - fix = 0; /* O(n^2) */ - while (fix < tif->tif_nfields && - tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) - fix++; - if (fix >= tif->tif_nfields || - tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) { - - TIFFWarningExt(tif->tif_clientdata, - module, - "%s: unknown field with tag %d (0x%x) encountered", - tif->tif_name, - dp->tdir_tag, - dp->tdir_tag); - - if (!_TIFFMergeFieldInfo(tif, - _TIFFCreateAnonFieldInfo(tif, - dp->tdir_tag, - (TIFFDataType) dp->tdir_type), - 1)) - { - TIFFWarningExt(tif->tif_clientdata, - module, - "Registering anonymous field with tag %d (0x%x) failed", - dp->tdir_tag, - dp->tdir_tag); - dp->tdir_tag = IGNORE; - continue; - } - fix = 0; - while (fix < tif->tif_nfields && - tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) - fix++; - } - /* - * Check data type. - */ - fip = tif->tif_fieldinfo[fix]; - while (dp->tdir_type != (unsigned short) fip->field_type - && fix < tif->tif_nfields) { - if (fip->field_type == TIFF_ANY) /* wildcard */ - break; - fip = tif->tif_fieldinfo[++fix]; - if (fix >= tif->tif_nfields || - fip->field_tag != dp->tdir_tag) { - TIFFWarningExt(tif->tif_clientdata, module, - "%s: wrong data type %d for \"%s\"; tag ignored", - tif->tif_name, dp->tdir_type, - tif->tif_fieldinfo[fix-1]->field_name); - dp->tdir_tag = IGNORE; - 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 ((td->td_compression==COMPRESSION_OJPEG) && - (td->td_planarconfig==PLANARCONFIG_SEPARATE)) { - dp = TIFFReadDirectoryFind(dir,dircount,TIFFTAG_STRIPOFFSETS); - if ((dp!=0) && (dp->tdir_count==1)) { - dp = TIFFReadDirectoryFind(dir, dircount, - TIFFTAG_STRIPBYTECOUNTS); - if ((dp!=0) && (dp->tdir_count==1)) { - td->td_planarconfig=PLANARCONFIG_CONTIG; - TIFFWarningExt(tif->tif_clientdata, - "TIFFReadDirectory", - "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)) { - td->td_nstrips = TIFFNumberOfStrips(tif); - td->td_tilewidth = td->td_imagewidth; - td->td_tilelength = td->td_rowsperstrip; - td->td_tiledepth = td->td_imagedepth; - tif->tif_flags &= ~TIFF_ISTILED; - } else { - td->td_nstrips = TIFFNumberOfTiles(tif); - tif->tif_flags |= TIFF_ISTILED; - } - if (!td->td_nstrips) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: cannot handle zero number of %s", - tif->tif_name, isTiled(tif) ? "tiles" : "strips"); - goto bad; - } - td->td_stripsperimage = td->td_nstrips; - if (td->td_planarconfig == PLANARCONFIG_SEPARATE) - td->td_stripsperimage /= td->td_samplesperpixel; - if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) { - if ((td->td_compression==COMPRESSION_OJPEG) && - (isTiled(tif)==0) && - (td->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 { - MissingRequired(tif, - isTiled(tif) ? "TileOffsets" : "StripOffsets"); - goto bad; - } - } - - /* - * Second pass: extract other information. - */ - for (dp = dir, n = dircount; n > 0; n--, dp++) { - if (dp->tdir_tag == IGNORE) - continue; - switch (dp->tdir_tag) { - case TIFFTAG_MINSAMPLEVALUE: - case TIFFTAG_MAXSAMPLEVALUE: - case TIFFTAG_BITSPERSAMPLE: - case TIFFTAG_DATATYPE: - case TIFFTAG_SAMPLEFORMAT: - /* - * 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. - * - * 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 (yech). Other vendors write correct - * value for NumberOfSamples, but incorrect one for - * BitsPerSample and friends, and we will read this - * too. - */ - if (dp->tdir_count == 1) { - v = TIFFExtractData(tif, - dp->tdir_type, dp->tdir_offset); - if (!TIFFSetField(tif, dp->tdir_tag, (uint16)v)) - goto bad; - /* XXX: workaround for broken TIFFs */ - } else if (dp->tdir_tag == TIFFTAG_BITSPERSAMPLE - && dp->tdir_type == TIFF_LONG) { - if (!TIFFFetchPerSampleLongs(tif, dp, &v) || - !TIFFSetField(tif, dp->tdir_tag, (uint16)v)) - goto bad; - } else { - if (!TIFFFetchPerSampleShorts(tif, dp, &iv) || - !TIFFSetField(tif, dp->tdir_tag, iv)) - goto bad; - } - break; - case TIFFTAG_SMINSAMPLEVALUE: - case TIFFTAG_SMAXSAMPLEVALUE: - { - double dv = 0.0; - if (!TIFFFetchPerSampleAnys(tif, dp, &dv) || - !TIFFSetField(tif, dp->tdir_tag, dv)) - goto bad; - } - break; - case TIFFTAG_STRIPOFFSETS: - case TIFFTAG_TILEOFFSETS: - if (!TIFFFetchStripThing(tif, dp, - td->td_nstrips, &td->td_stripoffset)) - goto bad; - break; - case TIFFTAG_STRIPBYTECOUNTS: - case TIFFTAG_TILEBYTECOUNTS: - if (!TIFFFetchStripThing(tif, dp, - td->td_nstrips, &td->td_stripbytecount)) - goto bad; - break; - case TIFFTAG_COLORMAP: - case TIFFTAG_TRANSFERFUNCTION: - { - char* cp; - /* - * TransferFunction can have either 1x or 3x - * data values; Colormap can have only 3x - * items. - */ - v = 1L<td_bitspersample; - if (dp->tdir_tag == TIFFTAG_COLORMAP || - dp->tdir_count != v) { - if (!CheckDirCount(tif, dp, 3 * v)) - break; - } - v *= sizeof(uint16); - cp = (char *)_TIFFCheckMalloc(tif, - dp->tdir_count, - sizeof (uint16), - "to read \"TransferFunction\" tag"); - if (cp != NULL) { - if (TIFFFetchData(tif, dp, cp)) { - /* - * This deals with there being - * only one array to apply to - * all samples. - */ - uint32 c = 1L << td->td_bitspersample; - if (dp->tdir_count == c) - v = 0L; - TIFFSetField(tif, dp->tdir_tag, - cp, cp+v, cp+2*v); - } - _TIFFfree(cp); - } - break; - } - case TIFFTAG_PAGENUMBER: - case TIFFTAG_HALFTONEHINTS: - case TIFFTAG_YCBCRSUBSAMPLING: - case TIFFTAG_DOTRANGE: - (void) TIFFFetchShortPair(tif, dp); - break; - case TIFFTAG_REFERENCEBLACKWHITE: - (void) TIFFFetchRefBlackWhite(tif, dp); - break; -/* BEGIN REV 4.0 COMPATIBILITY */ - case TIFFTAG_OSUBFILETYPE: - v = 0L; - switch (TIFFExtractData(tif, dp->tdir_type, - dp->tdir_offset)) { - case OFILETYPE_REDUCEDIMAGE: - v = FILETYPE_REDUCEDIMAGE; - break; - case OFILETYPE_PAGE: - v = FILETYPE_PAGE; - break; - } - if (v) - TIFFSetField(tif, TIFFTAG_SUBFILETYPE, v); - break; -/* END REV 4.0 COMPATIBILITY */ - default: - (void) TIFFFetchNormalTag(tif, dp); - break; - } - } - /* - * 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 (td->td_compression==COMPRESSION_OJPEG) - { - if (!TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) - { - TIFFWarningExt(tif->tif_clientdata, "TIFFReadDirectory", - "Photometric tag is missing, assuming data is YCbCr"); - if (!TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_YCBCR)) - goto bad; - } - else if (td->td_photometric==PHOTOMETRIC_RGB) - { - td->td_photometric=PHOTOMETRIC_YCBCR; - TIFFWarningExt(tif->tif_clientdata, "TIFFReadDirectory", - "Photometric tag value assumed incorrect, " - "assuming data is YCbCr instead of RGB"); - } - if (!TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) - { - TIFFWarningExt(tif->tif_clientdata,"TIFFReadDirectory", - "BitsPerSample tag is missing, assuming 8 bits per sample"); - if (!TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,8)) - goto bad; - } - if (!TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) - { - if ((td->td_photometric==PHOTOMETRIC_RGB) - || (td->td_photometric==PHOTOMETRIC_YCBCR)) - { - TIFFWarningExt(tif->tif_clientdata, - "TIFFReadDirectory", - "SamplesPerPixel tag is missing, " - "assuming correct SamplesPerPixel value is 3"); - if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3)) - goto bad; - } - else if ((td->td_photometric==PHOTOMETRIC_MINISWHITE) - || (td->td_photometric==PHOTOMETRIC_MINISBLACK)) - { - TIFFWarningExt(tif->tif_clientdata, - "TIFFReadDirectory", - "SamplesPerPixel tag is missing, " - "assuming correct SamplesPerPixel value is 1"); - if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,1)) - goto bad; - } - } - } - /* - * Verify Palette image has a Colormap. - */ - if (td->td_photometric == PHOTOMETRIC_PALETTE && - !TIFFFieldSet(tif, FIELD_COLORMAP)) { - MissingRequired(tif, "Colormap"); - goto bad; - } - /* - * OJPEG hack: - * We do no further messing with strip/tile offsets/bytecounts in OJPEG - * TIFFs - */ - if (td->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 ((td->td_planarconfig == PLANARCONFIG_CONTIG && - td->td_nstrips > 1) || - (td->td_planarconfig == PLANARCONFIG_SEPARATE && - td->td_nstrips != td->td_samplesperpixel)) { - MissingRequired(tif, "StripByteCounts"); - goto bad; - } - TIFFWarningExt(tif->tif_clientdata, module, - "%s: TIFF directory is missing required " - "\"%s\" field, calculating from imagelength", - tif->tif_name, - _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); - if (EstimateStripByteCounts(tif, dir, dircount) < 0) - goto bad; - /* - * 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. - */ - #define BYTECOUNTLOOKSBAD \ - ( (td->td_stripbytecount[0] == 0 && td->td_stripoffset[0] != 0) || \ - (td->td_compression == COMPRESSION_NONE && \ - td->td_stripbytecount[0] > TIFFGetFileSize(tif) - td->td_stripoffset[0]) || \ - (tif->tif_mode == O_RDONLY && \ - td->td_compression == COMPRESSION_NONE && \ - td->td_stripbytecount[0] < TIFFScanlineSize(tif) * td->td_imagelength) ) - - } else if (td->td_nstrips == 1 - && td->td_stripoffset[0] != 0 - && BYTECOUNTLOOKSBAD) { - /* - * 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, - "%s: Bogus \"%s\" field, ignoring and calculating from imagelength", - tif->tif_name, - _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); - if(EstimateStripByteCounts(tif, dir, dircount) < 0) - goto bad; - } else if (td->td_planarconfig == PLANARCONFIG_CONTIG - && td->td_nstrips > 2 - && td->td_compression == COMPRESSION_NONE - && td->td_stripbytecount[0] != td->td_stripbytecount[1] - && td->td_stripbytecount[0] != 0 - && td->td_stripbytecount[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. - */ - TIFFWarningExt(tif->tif_clientdata, module, - "%s: Wrong \"%s\" field, ignoring and calculating from imagelength", - tif->tif_name, - _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); - if (EstimateStripByteCounts(tif, dir, dircount) < 0) - goto bad; - } - } - if (dir) { - _TIFFfree((char *)dir); - dir = NULL; - } - if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE)) - td->td_maxsamplevalue = (uint16)((1L<td_bitspersample)-1); - /* - * Setup default compression scheme. - */ - - /* - * 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 (td->td_nstrips > 1) { - tstrip_t strip; - - td->td_stripbytecountsorted = 1; - for (strip = 1; strip < td->td_nstrips; strip++) { - if (td->td_stripoffset[strip - 1] > - td->td_stripoffset[strip]) { - td->td_stripbytecountsorted = 0; - break; - } - } - } - - if (!TIFFFieldSet(tif, FIELD_COMPRESSION)) - TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); - /* - * 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 (td->td_nstrips == 1 && td->td_compression == COMPRESSION_NONE && - (tif->tif_flags & (TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP) - ChopUpSingleUncompressedStrip(tif); - - /* - * Reinitialize i/o since we are starting on a new directory. - */ - tif->tif_row = (uint32) -1; - tif->tif_curstrip = (tstrip_t) -1; - tif->tif_col = (uint32) -1; - tif->tif_curtile = (ttile_t) -1; - tif->tif_tilesize = (tsize_t) -1; - - tif->tif_scanlinesize = TIFFScanlineSize(tif); - if (!tif->tif_scanlinesize) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: cannot handle zero scanline size", - tif->tif_name); - return (0); - } - - if (isTiled(tif)) { - tif->tif_tilesize = TIFFTileSize(tif); - if (!tif->tif_tilesize) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: cannot handle zero tile size", - tif->tif_name); - return (0); - } - } else { - if (!TIFFStripSize(tif)) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: cannot handle zero strip size", - tif->tif_name); - return (0); - } - } - return (1); -bad: - if (dir) - _TIFFfree(dir); - return (0); -} - -static TIFFDirEntry* -TIFFReadDirectoryFind(TIFFDirEntry* dir, uint16 dircount, uint16 tagid) -{ - TIFFDirEntry* m; - uint16 n; - for (m=dir, n=0; ntdir_tag==tagid) - return(m); - } - return(0); -} - -/* - * Read custom directory from the arbitarry offset. - * The code is very similar to TIFFReadDirectory(). - */ -int -TIFFReadCustomDirectory(TIFF* tif, toff_t diroff, - const TIFFFieldInfo info[], size_t n) -{ - static const char module[] = "TIFFReadCustomDirectory"; - - TIFFDirectory* td = &tif->tif_dir; - TIFFDirEntry *dp, *dir = NULL; - const TIFFFieldInfo* fip; - size_t fix; - uint16 i, dircount; - - _TIFFSetupFieldInfo(tif, info, n); - - dircount = TIFFFetchDirectory(tif, diroff, &dir, NULL); - if (!dircount) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Failed to read custom directory at offset %u", - tif->tif_name, diroff); - return 0; - } - - TIFFFreeDirectory(tif); - _TIFFmemset(&tif->tif_dir, 0, sizeof(TIFFDirectory)); - - fix = 0; - for (dp = dir, i = dircount; i > 0; i--, dp++) { - if (tif->tif_flags & TIFF_SWAB) { - TIFFSwabArrayOfShort(&dp->tdir_tag, 2); - TIFFSwabArrayOfLong(&dp->tdir_count, 2); - } - - if (fix >= tif->tif_nfields || dp->tdir_tag == IGNORE) - continue; - - while (fix < tif->tif_nfields && - tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) - fix++; - - if (fix >= tif->tif_nfields || - tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) { - - TIFFWarningExt(tif->tif_clientdata, module, - "%s: unknown field with tag %d (0x%x) encountered", - tif->tif_name, dp->tdir_tag, dp->tdir_tag); - if (!_TIFFMergeFieldInfo(tif, - _TIFFCreateAnonFieldInfo(tif, - dp->tdir_tag, - (TIFFDataType) dp->tdir_type), - 1)) - { - TIFFWarningExt(tif->tif_clientdata, module, - "Registering anonymous field with tag %d (0x%x) failed", - dp->tdir_tag, dp->tdir_tag); - goto ignore; - } - - fix = 0; - while (fix < tif->tif_nfields && - tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) - fix++; - } - /* - * Null out old tags that we ignore. - */ - if (tif->tif_fieldinfo[fix]->field_bit == FIELD_IGNORE) { - ignore: - dp->tdir_tag = IGNORE; - continue; - } - /* - * Check data type. - */ - fip = tif->tif_fieldinfo[fix]; - while (dp->tdir_type != (unsigned short) fip->field_type - && fix < tif->tif_nfields) { - if (fip->field_type == TIFF_ANY) /* wildcard */ - break; - fip = tif->tif_fieldinfo[++fix]; - if (fix >= tif->tif_nfields || - fip->field_tag != dp->tdir_tag) { - TIFFWarningExt(tif->tif_clientdata, module, - "%s: wrong data type %d for \"%s\"; tag ignored", - tif->tif_name, dp->tdir_type, - tif->tif_fieldinfo[fix-1]->field_name); - goto ignore; - } - } - /* - * Check count if known in advance. - */ - if (fip->field_readcount != TIFF_VARIABLE - && fip->field_readcount != TIFF_VARIABLE2) { - uint32 expected = (fip->field_readcount == TIFF_SPP) ? - (uint32) td->td_samplesperpixel : - (uint32) fip->field_readcount; - if (!CheckDirCount(tif, dp, expected)) - goto ignore; - } - - /* - * EXIF tags which need to be specifically processed. - */ - switch (dp->tdir_tag) { - case EXIFTAG_SUBJECTDISTANCE: - (void) TIFFFetchSubjectDistance(tif, dp); - break; - default: - (void) TIFFFetchNormalTag(tif, dp); - break; - } - } - - 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) +enum TIFFReadDirEntryErr { - size_t exifFieldInfoCount; - const TIFFFieldInfo *exifFieldInfo = - _TIFFGetExifFieldInfo(&exifFieldInfoCount); - return TIFFReadCustomDirectory(tif, diroff, exifFieldInfo, - exifFieldInfoCount); -} + TIFFReadDirEntryErrOk = 0, + TIFFReadDirEntryErrCount = 1, + TIFFReadDirEntryErrType = 2, + TIFFReadDirEntryErrIo = 3, + TIFFReadDirEntryErrRange = 4, + TIFFReadDirEntryErrPsdif = 5, + TIFFReadDirEntryErrSizesan = 6, + TIFFReadDirEntryErrAlloc = 7, +}; -static int -EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount) -{ - static const char module[] = "EstimateStripByteCounts"; +static enum TIFFReadDirEntryErr +TIFFReadDirEntryByte(TIFF *tif, TIFFDirEntry *direntry, uint8_t *value); +static enum TIFFReadDirEntryErr +TIFFReadDirEntrySbyte(TIFF *tif, TIFFDirEntry *direntry, int8_t *value); +static enum TIFFReadDirEntryErr +TIFFReadDirEntryShort(TIFF *tif, TIFFDirEntry *direntry, uint16_t *value); +static enum TIFFReadDirEntryErr +TIFFReadDirEntrySshort(TIFF *tif, TIFFDirEntry *direntry, int16_t *value); +static enum TIFFReadDirEntryErr +TIFFReadDirEntryLong(TIFF *tif, TIFFDirEntry *direntry, uint32_t *value); +static enum TIFFReadDirEntryErr +TIFFReadDirEntrySlong(TIFF *tif, TIFFDirEntry *direntry, int32_t *value); +static enum TIFFReadDirEntryErr +TIFFReadDirEntryLong8(TIFF *tif, TIFFDirEntry *direntry, uint64_t *value); +static enum TIFFReadDirEntryErr +TIFFReadDirEntrySlong8(TIFF *tif, TIFFDirEntry *direntry, int64_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); - TIFFDirEntry *dp; - TIFFDirectory *td = &tif->tif_dir; - uint32 strip; +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); - if (td->td_stripbytecount) - _TIFFfree(td->td_stripbytecount); - td->td_stripbytecount = (uint32*) - _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint32), - "for \"StripByteCounts\" array"); - if( td->td_stripbytecount == NULL ) - return -1; +static enum TIFFReadDirEntryErr +TIFFReadDirEntryPersampleShort(TIFF *tif, TIFFDirEntry *direntry, + uint16_t *value); - if (td->td_compression != COMPRESSION_NONE) { - uint32 space = (uint32)(sizeof (TIFFHeader) - + sizeof (uint16) - + (dircount * sizeof (TIFFDirEntry)) - + sizeof (uint32)); - toff_t filesize = TIFFGetFileSize(tif); - uint16 n; - - /* calculate amount of space used by indirect values */ - for (dp = dir, n = dircount; n > 0; n--, dp++) - { - uint32 cc = TIFFDataWidth((TIFFDataType) dp->tdir_type); - if (cc == 0) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Cannot determine size of unknown tag type %d", - tif->tif_name, dp->tdir_type); - return -1; - } - cc = cc * dp->tdir_count; - if (cc > sizeof (uint32)) - space += cc; - } - space = filesize - space; - if (td->td_planarconfig == PLANARCONFIG_SEPARATE) - space /= td->td_samplesperpixel; - for (strip = 0; strip < td->td_nstrips; strip++) - td->td_stripbytecount[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 (((toff_t)(td->td_stripoffset[strip]+ - td->td_stripbytecount[strip])) > filesize) - td->td_stripbytecount[strip] = - filesize - td->td_stripoffset[strip]; - } else if (isTiled(tif)) { - uint32 bytespertile = TIFFTileSize(tif); - - for (strip = 0; strip < td->td_nstrips; strip++) - td->td_stripbytecount[strip] = bytespertile; - } else { - uint32 rowbytes = TIFFScanlineSize(tif); - uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage; - for (strip = 0; strip < td->td_nstrips; strip++) - td->td_stripbytecount[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, - "%s: TIFF directory is missing required \"%s\" field", - tif->tif_name, tagname); -} +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); +#if 0 +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckedRationalDirect(TIFF *tif, TIFFDirEntry *direntry, + TIFFRational_t *value); +#endif +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); -/* - * 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, toff_t diroff) -{ - uint16 n; +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); - if (diroff == 0) /* no more directories */ - return 0; +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); - for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) { - if (tif->tif_dirlist[n] == diroff) - return 0; - } +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); - tif->tif_dirnumber++; +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); - if (tif->tif_dirnumber > tif->tif_dirlistsize) { - toff_t* new_dirlist; +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlongLong(uint32_t value); +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlongLong8(uint64_t value); +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlongSlong8(int64_t value); - /* - * XXX: Reduce memory allocation granularity of the dirlist - * array. - */ - new_dirlist = (toff_t *)_TIFFCheckRealloc(tif, - tif->tif_dirlist, - tif->tif_dirnumber, - 2 * sizeof(toff_t), - "for IFD list"); - if (!new_dirlist) - return 0; - tif->tif_dirlistsize = 2 * tif->tif_dirnumber; - tif->tif_dirlist = new_dirlist; - } +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); - tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff; +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckRangeSlong8Long8(uint64_t value); - return 1; -} +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); -/* - * 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 count) -{ - if (count > dir->tdir_count) { - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, - "incorrect count for field \"%s\" (%u, expecting %u); tag ignored", - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, - dir->tdir_count, count); - return (0); - } else if (count < dir->tdir_count) { - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, - "incorrect count for field \"%s\" (%u, expecting %u); tag trimmed", - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, - dir->tdir_count, count); - return (1); - } - return (1); -} +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); -/* - * 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 -TIFFFetchDirectory(TIFF* tif, toff_t diroff, TIFFDirEntry **pdir, - toff_t *nextdiroff) -{ - static const char module[] = "TIFFFetchDirectory"; - - TIFFDirEntry *dir; - uint16 dircount; - - 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 (!ReadOK(tif, &dircount, sizeof (uint16))) { - 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); - dir = (TIFFDirEntry *)_TIFFCheckMalloc(tif, dircount, - sizeof (TIFFDirEntry), - "to read TIFF directory"); - if (dir == NULL) - return 0; - if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) { - TIFFErrorExt(tif->tif_clientdata, module, - "%.100s: Can not read TIFF directory", - tif->tif_name); - _TIFFfree(dir); - return 0; - } - /* - * Read offset to next directory for sequential scans if - * needed. - */ - if (nextdiroff) - (void) ReadOK(tif, nextdiroff, sizeof(uint32)); - } else { - toff_t off = 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) > tif->tif_size - * - * to avoid overflow. - */ - if (tif->tif_size < sizeof (uint16) || - off > tif->tif_size - sizeof(uint16)) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Can not read TIFF directory count", - tif->tif_name); - return 0; - } else { - _TIFFmemcpy(&dircount, tif->tif_base + off, - sizeof(uint16)); - } - off += sizeof (uint16); - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabShort(&dircount); - dir = (TIFFDirEntry *)_TIFFCheckMalloc(tif, dircount, - sizeof(TIFFDirEntry), - "to read TIFF directory"); - if (dir == NULL) - return 0; - if (off + dircount * sizeof (TIFFDirEntry) > tif->tif_size) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Can not read TIFF directory", - tif->tif_name); - _TIFFfree(dir); - return 0; - } else { - _TIFFmemcpy(dir, tif->tif_base + off, - dircount * sizeof(TIFFDirEntry)); - } - if (nextdiroff) { - off += dircount * sizeof (TIFFDirEntry); - if (off + sizeof (uint32) <= tif->tif_size) { - _TIFFmemcpy(nextdiroff, tif->tif_base + off, - sizeof (uint32)); - } - } - } - if (nextdiroff && tif->tif_flags & TIFF_SWAB) - TIFFSwabLong(nextdiroff); - *pdir = dir; - return dircount; -} +static int EstimateStripByteCounts(TIFF *tif, TIFFDirEntry *dir, + uint16_t dircount); +static void MissingRequired(TIFF *, const char *); +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); -/* - * Fetch a contiguous directory item. - */ -static tsize_t -TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp) -{ - uint32 w = TIFFDataWidth((TIFFDataType) dir->tdir_type); - /* - * FIXME: butecount should have tsize_t type, but for now libtiff - * defines tsize_t as a signed 32-bit integer and we are losing - * ability to read arrays larger than 2^31 bytes. So we are using - * uint32 instead of tsize_t here. - */ - uint32 cc = dir->tdir_count * w; - - /* Check for overflow. */ - if (!dir->tdir_count || !w || cc / w != dir->tdir_count) - goto bad; - - if (!isMapped(tif)) { - if (!SeekOK(tif, dir->tdir_offset)) - goto bad; - if (!ReadOK(tif, cp, cc)) - goto bad; - } else { - /* Check for overflow. */ - if (dir->tdir_offset + cc < dir->tdir_offset - || dir->tdir_offset + cc < cc - || dir->tdir_offset + cc > tif->tif_size) - goto bad; - _TIFFmemcpy(cp, tif->tif_base + dir->tdir_offset, cc); - } - if (tif->tif_flags & TIFF_SWAB) { - switch (dir->tdir_type) { - case TIFF_SHORT: - case TIFF_SSHORT: - TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count); - break; - case TIFF_LONG: - case TIFF_SLONG: - case TIFF_FLOAT: - TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count); - break; - case TIFF_RATIONAL: - case TIFF_SRATIONAL: - TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count); - break; - case TIFF_DOUBLE: - TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count); - break; - } - } - return (cc); -bad: - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Error fetching data for field \"%s\"", - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); - return (tsize_t) 0; -} +static int _TIFFFillStrilesInternal(TIFF *tif, int loadStripByteCount); -/* - * Fetch an ASCII item from the file. - */ -static tsize_t -TIFFFetchString(TIFF* tif, TIFFDirEntry* dir, char* cp) +typedef union _UInt64Aligned_t { - if (dir->tdir_count <= 4) { - uint32 l = dir->tdir_offset; - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabLong(&l); - _TIFFmemcpy(cp, &l, dir->tdir_count); - return (1); - } - return (TIFFFetchData(tif, dir, cp)); -} - -/* - * Convert numerator+denominator to float. - */ -static int -cvtRational(TIFF* tif, TIFFDirEntry* dir, uint32 num, uint32 denom, float* rv) -{ - if (denom == 0) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%s: Rational with zero denominator (num = %u)", - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, num); - return (0); - } else { - if (dir->tdir_type == TIFF_RATIONAL) - *rv = ((float)num / (float)denom); - else - *rv = ((float)(int32)num / (float)(int32)denom); - return (1); - } -} + double d; + uint64_t l; + uint32_t i[2]; + uint16_t s[4]; + uint8_t c[8]; +} UInt64Aligned_t; /* - * Fetch a rational item from the file at offset off and return the value as a - * floating point number. - */ -static float -TIFFFetchRational(TIFF* tif, TIFFDirEntry* dir) + Unaligned safe copy of a uint64_t value from an octet array. +*/ +static uint64_t TIFFReadUInt64(const uint8_t *value) { - uint32 l[2]; - float v; + UInt64Aligned_t result; - return (!TIFFFetchData(tif, dir, (char *)l) || - !cvtRational(tif, dir, l[0], l[1], &v) ? 1.0f : v); -} + 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]; -/* - * Fetch a single floating point value from the offset field and return it as - * a native float. - */ -static float -TIFFFetchFloat(TIFF* tif, TIFFDirEntry* dir) -{ - float v; - int32 l = TIFFExtractData(tif, dir->tdir_type, dir->tdir_offset); - _TIFFmemcpy(&v, &l, sizeof(float)); - TIFFCvtIEEEFloatToNative(tif, 1, &v); - return (v); + return result.l; } -/* - * Fetch an array of BYTE or SBYTE values. - */ -static int -TIFFFetchByteArray(TIFF* tif, TIFFDirEntry* dir, uint8* v) +static enum TIFFReadDirEntryErr +TIFFReadDirEntryByte(TIFF *tif, TIFFDirEntry *direntry, uint8_t *value) { - if (dir->tdir_count <= 4) { - /* - * Extract data from offset field. - */ - if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { - if (dir->tdir_type == TIFF_SBYTE) - switch (dir->tdir_count) { - case 4: v[3] = dir->tdir_offset & 0xff; - case 3: v[2] = (dir->tdir_offset >> 8) & 0xff; - case 2: v[1] = (dir->tdir_offset >> 16) & 0xff; - case 1: v[0] = dir->tdir_offset >> 24; - } - else - switch (dir->tdir_count) { - case 4: v[3] = dir->tdir_offset & 0xff; - case 3: v[2] = (dir->tdir_offset >> 8) & 0xff; - case 2: v[1] = (dir->tdir_offset >> 16) & 0xff; - case 1: v[0] = dir->tdir_offset >> 24; - } - } else { - if (dir->tdir_type == TIFF_SBYTE) - switch (dir->tdir_count) { - case 4: v[3] = dir->tdir_offset >> 24; - case 3: v[2] = (dir->tdir_offset >> 16) & 0xff; - case 2: v[1] = (dir->tdir_offset >> 8) & 0xff; - case 1: v[0] = dir->tdir_offset & 0xff; - } - else - switch (dir->tdir_count) { - case 4: v[3] = dir->tdir_offset >> 24; - case 3: v[2] = (dir->tdir_offset >> 16) & 0xff; - case 2: v[1] = (dir->tdir_offset >> 8) & 0xff; - case 1: v[0] = dir->tdir_offset & 0xff; - } - } - return (1); - } else - return (TIFFFetchData(tif, dir, (char*) v) != 0); /* XXX */ -} - -/* - * Fetch an array of SHORT or SSHORT values. - */ -static int -TIFFFetchShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v) -{ - if (dir->tdir_count <= 2) { - if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { - switch (dir->tdir_count) { - case 2: v[1] = (uint16) (dir->tdir_offset & 0xffff); - case 1: v[0] = (uint16) (dir->tdir_offset >> 16); - } - } else { - switch (dir->tdir_count) { - case 2: v[1] = (uint16) (dir->tdir_offset >> 16); - case 1: v[0] = (uint16) (dir->tdir_offset & 0xffff); - } - } - return (1); - } else - return (TIFFFetchData(tif, dir, (char *)v) != 0); -} - -/* - * Fetch a pair of SHORT or BYTE values. Some tags may have either BYTE - * or SHORT type and this function works with both ones. - */ -static int -TIFFFetchShortPair(TIFF* tif, TIFFDirEntry* dir) -{ - /* - * Prevent overflowing the v stack arrays below by performing a sanity - * check on tdir_count, this should never be greater than two. - */ - if (dir->tdir_count > 2) { - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, - "unexpected count for field \"%s\", %u, expected 2; ignored", - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, - dir->tdir_count); - return 0; - } - - switch (dir->tdir_type) { - case TIFF_BYTE: - case TIFF_SBYTE: - { - uint8 v[4]; - return TIFFFetchByteArray(tif, dir, v) - && TIFFSetField(tif, dir->tdir_tag, v[0], v[1]); - } - case TIFF_SHORT: - case TIFF_SSHORT: - { - uint16 v[2]; - return TIFFFetchShortArray(tif, dir, v) - && TIFFSetField(tif, dir->tdir_tag, v[0], v[1]); - } - default: - return 0; - } + 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); + } } -/* - * Fetch an array of LONG or SLONG values. - */ -static int -TIFFFetchLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v) +static enum TIFFReadDirEntryErr +TIFFReadDirEntrySbyte(TIFF *tif, TIFFDirEntry *direntry, int8_t *value) { - if (dir->tdir_count == 1) { - v[0] = dir->tdir_offset; - return (1); - } else - return (TIFFFetchData(tif, dir, (char*) v) != 0); -} + 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 */ + { + uint8_t m; + TIFFReadDirEntryCheckedByte(tif, direntry, &m); + err = TIFFReadDirEntryCheckRangeSbyteByte(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int8_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + TIFFReadDirEntryCheckedSbyte(tif, direntry, value); + return (TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16_t m; + TIFFReadDirEntryCheckedShort(tif, direntry, &m); + err = TIFFReadDirEntryCheckRangeSbyteShort(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int8_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16_t m; + TIFFReadDirEntryCheckedSshort(tif, direntry, &m); + err = TIFFReadDirEntryCheckRangeSbyteSshort(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int8_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32_t m; + TIFFReadDirEntryCheckedLong(tif, direntry, &m); + err = TIFFReadDirEntryCheckRangeSbyteLong(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int8_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32_t m; + TIFFReadDirEntryCheckedSlong(tif, direntry, &m); + err = TIFFReadDirEntryCheckRangeSbyteSlong(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int8_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64_t m; + err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); + if (err != TIFFReadDirEntryErrOk) + return (err); + err = TIFFReadDirEntryCheckRangeSbyteLong8(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int8_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64_t m; + err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); + if (err != TIFFReadDirEntryErrOk) + return (err); + err = TIFFReadDirEntryCheckRangeSbyteSlong8(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int8_t)m; + return (TIFFReadDirEntryErrOk); + } + default: + return (TIFFReadDirEntryErrType); + } +} /*-- TIFFReadDirEntrySbyte() --*/ -/* - * Fetch an array of RATIONAL or SRATIONAL values. - */ -static int -TIFFFetchRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v) -{ - int ok = 0; - uint32* l; - - l = (uint32*)_TIFFCheckMalloc(tif, - dir->tdir_count, TIFFDataWidth((TIFFDataType) dir->tdir_type), - "to fetch array of rationals"); - if (l) { - if (TIFFFetchData(tif, dir, (char *)l)) { - uint32 i; - for (i = 0; i < dir->tdir_count; i++) { - ok = cvtRational(tif, dir, - l[2*i+0], l[2*i+1], &v[i]); - if (!ok) - break; - } - } - _TIFFfree((char *)l); - } - return (ok); -} +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); + } +} /*-- TIFFReadDirEntryShort() --*/ -/* - * Fetch an array of FLOAT values. - */ -static int -TIFFFetchFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v) +static enum TIFFReadDirEntryErr +TIFFReadDirEntrySshort(TIFF *tif, TIFFDirEntry *direntry, int16_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 = (int16_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8_t m; + TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); + *value = (int16_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16_t m; + TIFFReadDirEntryCheckedShort(tif, direntry, &m); + err = TIFFReadDirEntryCheckRangeSshortShort(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (uint16_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + TIFFReadDirEntryCheckedSshort(tif, direntry, value); + return (TIFFReadDirEntryErrOk); + case TIFF_LONG: + { + uint32_t m; + TIFFReadDirEntryCheckedLong(tif, direntry, &m); + err = TIFFReadDirEntryCheckRangeSshortLong(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int16_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32_t m; + TIFFReadDirEntryCheckedSlong(tif, direntry, &m); + err = TIFFReadDirEntryCheckRangeSshortSlong(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int16_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64_t m; + err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); + if (err != TIFFReadDirEntryErrOk) + return (err); + err = TIFFReadDirEntryCheckRangeSshortLong8(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int16_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64_t m; + err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); + if (err != TIFFReadDirEntryErrOk) + return (err); + err = TIFFReadDirEntryCheckRangeSshortSlong8(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int16_t)m; + return (TIFFReadDirEntryErrOk); + } + default: + return (TIFFReadDirEntryErrType); + } +} /*-- TIFFReadDirEntrySshort() --*/ - if (dir->tdir_count == 1) { - union - { - float f; - uint32 i; - } float_union; +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); + } +} /*-- TIFFReadDirEntryLong() --*/ - float_union.i=dir->tdir_offset; - v[0]=float_union.f; - TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v); - return (1); - } else if (TIFFFetchData(tif, dir, (char*) v)) { - TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v); - return (1); - } else - return (0); -} +static enum TIFFReadDirEntryErr +TIFFReadDirEntrySlong(TIFF *tif, TIFFDirEntry *direntry, int32_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 = (int32_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8_t m; + TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); + *value = (int32_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16_t m; + TIFFReadDirEntryCheckedShort(tif, direntry, &m); + *value = (int32_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16_t m; + TIFFReadDirEntryCheckedSshort(tif, direntry, &m); + *value = (int32_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32_t m; + TIFFReadDirEntryCheckedLong(tif, direntry, &m); + err = TIFFReadDirEntryCheckRangeSlongLong(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int32_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + TIFFReadDirEntryCheckedSlong(tif, direntry, value); + return (TIFFReadDirEntryErrOk); + case TIFF_LONG8: + { + uint64_t m; + err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); + if (err != TIFFReadDirEntryErrOk) + return (err); + err = TIFFReadDirEntryCheckRangeSlongLong8(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int32_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + { + int64_t m; + err = TIFFReadDirEntryCheckedSlong8(tif, direntry, &m); + if (err != TIFFReadDirEntryErrOk) + return (err); + err = TIFFReadDirEntryCheckRangeSlongSlong8(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int32_t)m; + return (TIFFReadDirEntryErrOk); + } + default: + return (TIFFReadDirEntryErrType); + } +} /*-- TIFFReadDirEntrySlong() --*/ -/* - * Fetch an array of DOUBLE values. - */ -static int -TIFFFetchDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v) +static enum TIFFReadDirEntryErr +TIFFReadDirEntryLong8(TIFF *tif, TIFFDirEntry *direntry, uint64_t *value) { - if (TIFFFetchData(tif, dir, (char*) v)) { - TIFFCvtIEEEDoubleToNative(tif, dir->tdir_count, v); - return (1); - } else - return (0); -} + 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); + } +} /*-- TIFFReadDirEntryLong8() --*/ -/* - * Fetch an array of ANY values. The actual values are returned as doubles - * which should be able hold all the types. Yes, there really should be an - * tany_t to avoid this potential non-portability ... Note in particular that - * we assume that the double return value vector is large enough to read in - * any fundamental type. We use that vector as a buffer to read in the base - * type vector and then convert it in place to double (from end to front of - * course). - */ -static int -TIFFFetchAnyArray(TIFF* tif, TIFFDirEntry* dir, double* v) -{ - int i; - - switch (dir->tdir_type) { - case TIFF_BYTE: - case TIFF_SBYTE: - if (!TIFFFetchByteArray(tif, dir, (uint8*) v)) - return (0); - if (dir->tdir_type == TIFF_BYTE) { - uint8* vp = (uint8*) v; - for (i = dir->tdir_count-1; i >= 0; i--) - v[i] = vp[i]; - } else { - int8* vp = (int8*) v; - for (i = dir->tdir_count-1; i >= 0; i--) - v[i] = vp[i]; - } - break; - case TIFF_SHORT: - case TIFF_SSHORT: - if (!TIFFFetchShortArray(tif, dir, (uint16*) v)) - return (0); - if (dir->tdir_type == TIFF_SHORT) { - uint16* vp = (uint16*) v; - for (i = dir->tdir_count-1; i >= 0; i--) - v[i] = vp[i]; - } else { - int16* vp = (int16*) v; - for (i = dir->tdir_count-1; i >= 0; i--) - v[i] = vp[i]; - } - break; - case TIFF_LONG: - case TIFF_SLONG: - if (!TIFFFetchLongArray(tif, dir, (uint32*) v)) - return (0); - if (dir->tdir_type == TIFF_LONG) { - uint32* vp = (uint32*) v; - for (i = dir->tdir_count-1; i >= 0; i--) - v[i] = vp[i]; - } else { - int32* vp = (int32*) v; - for (i = dir->tdir_count-1; i >= 0; i--) - v[i] = vp[i]; - } - break; - case TIFF_RATIONAL: - case TIFF_SRATIONAL: - if (!TIFFFetchRationalArray(tif, dir, (float*) v)) - return (0); - { float* vp = (float*) v; - for (i = dir->tdir_count-1; i >= 0; i--) - v[i] = vp[i]; - } - break; - case TIFF_FLOAT: - if (!TIFFFetchFloatArray(tif, dir, (float*) v)) - return (0); - { float* vp = (float*) v; - for (i = dir->tdir_count-1; i >= 0; i--) - v[i] = vp[i]; - } - break; - case TIFF_DOUBLE: - return (TIFFFetchDoubleArray(tif, dir, (double*) v)); - default: - /* TIFF_NOTYPE */ - /* TIFF_ASCII */ - /* TIFF_UNDEFINED */ - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "cannot read TIFF_ANY type %d for field \"%s\"", - dir->tdir_type, - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); - return (0); - } - return (1); -} +static enum TIFFReadDirEntryErr +TIFFReadDirEntrySlong8(TIFF *tif, TIFFDirEntry *direntry, int64_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 = (int64_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + { + int8_t m; + TIFFReadDirEntryCheckedSbyte(tif, direntry, &m); + *value = (int64_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SHORT: + { + uint16_t m; + TIFFReadDirEntryCheckedShort(tif, direntry, &m); + *value = (int64_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SSHORT: + { + int16_t m; + TIFFReadDirEntryCheckedSshort(tif, direntry, &m); + *value = (int64_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_LONG: + { + uint32_t m; + TIFFReadDirEntryCheckedLong(tif, direntry, &m); + *value = (int64_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SLONG: + { + int32_t m; + TIFFReadDirEntryCheckedSlong(tif, direntry, &m); + *value = (int64_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_LONG8: + { + uint64_t m; + err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); + if (err != TIFFReadDirEntryErrOk) + return (err); + err = TIFFReadDirEntryCheckRangeSlong8Long8(m); + if (err != TIFFReadDirEntryErrOk) + return (err); + *value = (int64_t)m; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SLONG8: + err = TIFFReadDirEntryCheckedSlong8(tif, direntry, value); + return (err); + default: + return (TIFFReadDirEntryErrType); + } +} /*-- TIFFReadDirEntrySlong8() --*/ -/* - * Fetch a tag that is not handled by special case code. - */ -static int -TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp) -{ - static const char mesg[] = "to fetch tag value"; - int ok = 0; - const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, dp->tdir_tag); - - if (dp->tdir_count > 1) { /* array of values */ - char* cp = NULL; - - switch (dp->tdir_type) { - case TIFF_BYTE: - case TIFF_SBYTE: - cp = (char *)_TIFFCheckMalloc(tif, - dp->tdir_count, sizeof (uint8), mesg); - ok = cp && TIFFFetchByteArray(tif, dp, (uint8*) cp); - break; - case TIFF_SHORT: - case TIFF_SSHORT: - cp = (char *)_TIFFCheckMalloc(tif, - dp->tdir_count, sizeof (uint16), mesg); - ok = cp && TIFFFetchShortArray(tif, dp, (uint16*) cp); - break; - case TIFF_LONG: - case TIFF_SLONG: - cp = (char *)_TIFFCheckMalloc(tif, - dp->tdir_count, sizeof (uint32), mesg); - ok = cp && TIFFFetchLongArray(tif, dp, (uint32*) cp); - break; - case TIFF_RATIONAL: - case TIFF_SRATIONAL: - cp = (char *)_TIFFCheckMalloc(tif, - dp->tdir_count, sizeof (float), mesg); - ok = cp && TIFFFetchRationalArray(tif, dp, (float*) cp); - break; - case TIFF_FLOAT: - cp = (char *)_TIFFCheckMalloc(tif, - dp->tdir_count, sizeof (float), mesg); - ok = cp && TIFFFetchFloatArray(tif, dp, (float*) cp); - break; - case TIFF_DOUBLE: - cp = (char *)_TIFFCheckMalloc(tif, - dp->tdir_count, sizeof (double), mesg); - ok = cp && TIFFFetchDoubleArray(tif, dp, (double*) cp); - break; - case TIFF_ASCII: - case TIFF_UNDEFINED: /* bit of a cheat... */ - /* - * Some vendors write strings w/o the trailing - * NULL byte, so always append one just in case. - */ - cp = (char *)_TIFFCheckMalloc(tif, dp->tdir_count + 1, - 1, mesg); - if( (ok = (cp && TIFFFetchString(tif, dp, cp))) != 0 ) - cp[dp->tdir_count] = '\0'; /* XXX */ - break; - } - if (ok) { - ok = (fip->field_passcount ? - TIFFSetField(tif, dp->tdir_tag, dp->tdir_count, cp) - : TIFFSetField(tif, dp->tdir_tag, cp)); - } - if (cp != NULL) - _TIFFfree(cp); - } else if (CheckDirCount(tif, dp, 1)) { /* singleton value */ - switch (dp->tdir_type) { - case TIFF_BYTE: - case TIFF_SBYTE: - case TIFF_SHORT: - case TIFF_SSHORT: - /* - * If the tag is also acceptable as a LONG or SLONG - * then TIFFSetField will expect an uint32 parameter - * passed to it (through varargs). Thus, for machines - * where sizeof (int) != sizeof (uint32) we must do - * a careful check here. It's hard to say if this - * is worth optimizing. - * - * NB: We use TIFFFieldWithTag here knowing that - * it returns us the first entry in the table - * for the tag and that that entry is for the - * widest potential data type the tag may have. - */ - { TIFFDataType type = fip->field_type; - if (type != TIFF_LONG && type != TIFF_SLONG) { - uint16 v = (uint16) - TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); - ok = (fip->field_passcount ? - TIFFSetField(tif, dp->tdir_tag, 1, &v) - : TIFFSetField(tif, dp->tdir_tag, v)); - break; - } - } - /* fall thru... */ - case TIFF_LONG: - case TIFF_SLONG: - { uint32 v32 = - TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); - ok = (fip->field_passcount ? - TIFFSetField(tif, dp->tdir_tag, 1, &v32) - : TIFFSetField(tif, dp->tdir_tag, v32)); - } - break; - case TIFF_RATIONAL: - case TIFF_SRATIONAL: - case TIFF_FLOAT: - { float v = (dp->tdir_type == TIFF_FLOAT ? - TIFFFetchFloat(tif, dp) - : TIFFFetchRational(tif, dp)); - ok = (fip->field_passcount ? - TIFFSetField(tif, dp->tdir_tag, 1, &v) - : TIFFSetField(tif, dp->tdir_tag, v)); - } - break; - case TIFF_DOUBLE: - { double v; - ok = (TIFFFetchDoubleArray(tif, dp, &v) && - (fip->field_passcount ? - TIFFSetField(tif, dp->tdir_tag, 1, &v) - : TIFFSetField(tif, dp->tdir_tag, v)) - ); - } - break; - case TIFF_ASCII: - case TIFF_UNDEFINED: /* bit of a cheat... */ - { char c[2]; - if( (ok = (TIFFFetchString(tif, dp, c) != 0)) != 0 ) { - c[1] = '\0'; /* XXX paranoid */ - ok = (fip->field_passcount ? - TIFFSetField(tif, dp->tdir_tag, 1, c) - : TIFFSetField(tif, dp->tdir_tag, c)); - } - } - break; - } - } - return (ok); -} - -#define NITEMS(x) (sizeof (x) / sizeof (x[0])) -/* - * Fetch samples/pixel short values for - * the specified tag and verify that - * all values are the same. - */ -static int -TIFFFetchPerSampleShorts(TIFF* tif, TIFFDirEntry* dir, uint16* pl) -{ - uint16 samples = tif->tif_dir.td_samplesperpixel; - int status = 0; - - if (CheckDirCount(tif, dir, (uint32) samples)) { - uint16 buf[10]; - uint16* v = buf; - - if (dir->tdir_count > NITEMS(buf)) - v = (uint16*) _TIFFCheckMalloc(tif, dir->tdir_count, sizeof(uint16), - "to fetch per-sample values"); - if (v && TIFFFetchShortArray(tif, dir, v)) { - uint16 i; - int check_count = dir->tdir_count; - if( samples < check_count ) - check_count = samples; - - for (i = 1; i < check_count; i++) - if (v[i] != v[0]) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Cannot handle different per-sample values for field \"%s\"", - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); - goto bad; - } - *pl = v[0]; - status = 1; +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); } - bad: - if (v && v != buf) - _TIFFfree(v); + 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); } - return (status); } -/* - * Fetch samples/pixel long values for - * the specified tag and verify that - * all values are the same. - */ -static int -TIFFFetchPerSampleLongs(TIFF* tif, TIFFDirEntry* dir, uint32* pl) -{ - uint16 samples = tif->tif_dir.td_samplesperpixel; - int status = 0; - - if (CheckDirCount(tif, dir, (uint32) samples)) { - uint32 buf[10]; - uint32* v = buf; - - if (dir->tdir_count > NITEMS(buf)) - v = (uint32*) _TIFFCheckMalloc(tif, dir->tdir_count, sizeof(uint32), - "to fetch per-sample values"); - if (v && TIFFFetchLongArray(tif, dir, v)) { - uint16 i; - int check_count = dir->tdir_count; - - if( samples < check_count ) - check_count = samples; - for (i = 1; i < check_count; i++) - if (v[i] != v[0]) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Cannot handle different per-sample values for field \"%s\"", - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); - goto bad; - } - *pl = v[0]; - status = 1; +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); } - bad: - if (v && v != buf) - _TIFFfree(v); + case TIFF_DOUBLE: + err = TIFFReadDirEntryCheckedDouble(tif, direntry, value); + return (err); + default: + return (TIFFReadDirEntryErrType); } - return (status); } -/* - * Fetch samples/pixel ANY values for the specified tag and verify that all - * values are the same. - */ -static int -TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* pl) -{ - uint16 samples = tif->tif_dir.td_samplesperpixel; - int status = 0; - - if (CheckDirCount(tif, dir, (uint32) samples)) { - double buf[10]; - double* v = buf; - - if (dir->tdir_count > NITEMS(buf)) - v = (double*) _TIFFCheckMalloc(tif, dir->tdir_count, sizeof (double), - "to fetch per-sample values"); - if (v && TIFFFetchAnyArray(tif, dir, v)) { - uint16 i; - int check_count = dir->tdir_count; - if( samples < check_count ) - check_count = samples; - - for (i = 1; i < check_count; i++) - if (v[i] != v[0]) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Cannot handle different per-sample values for field \"%s\"", - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); - goto bad; - } - *pl = v[0]; - status = 1; +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); } - bad: - if (v && v != buf) - _TIFFfree(v); + case TIFF_LONG8: + case TIFF_IFD8: + err = TIFFReadDirEntryCheckedLong8(tif, direntry, value); + return (err); + default: + return (TIFFReadDirEntryErrType); } - return (status); } -#undef NITEMS -/* - * 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, long nstrips, uint32** lpp) -{ - register uint32* lp; - int status; - - CheckDirCount(tif, dir, (uint32) nstrips); - - /* - * Allocate space for strip information. - */ - if (*lpp == NULL && - (*lpp = (uint32 *)_TIFFCheckMalloc(tif, - nstrips, sizeof (uint32), "for strip array")) == NULL) - return (0); - lp = *lpp; - _TIFFmemset( lp, 0, sizeof(uint32) * nstrips ); - - if (dir->tdir_type == (int)TIFF_SHORT) { - /* - * Handle uint16->uint32 expansion. - */ - uint16* dp = (uint16*) _TIFFCheckMalloc(tif, - dir->tdir_count, sizeof (uint16), "to fetch strip tag"); - if (dp == NULL) - return (0); - if( (status = TIFFFetchShortArray(tif, dir, dp)) != 0 ) { - int i; - - for( i = 0; i < nstrips && i < (int) dir->tdir_count; i++ ) - { - lp[i] = dp[i]; - } - } - _TIFFfree((char*) dp); +#define INITIAL_THRESHOLD (1024 * 1024) +#define THRESHOLD_MULTIPLIER 10 +#define MAX_THRESHOLD \ + (THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * \ + INITIAL_THRESHOLD) - } else if( nstrips != (int) dir->tdir_count ) { - /* Special case to correct length */ +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; - uint32* dp = (uint32*) _TIFFCheckMalloc(tif, - dir->tdir_count, sizeof (uint32), "to fetch strip tag"); - if (dp == NULL) - return (0); + assert(!isMapped(tif)); - status = TIFFFetchLongArray(tif, dir, dp); - if( status != 0 ) { - int i; + if (!SeekOK(tif, offset)) + return (TIFFReadDirEntryErrIo); - for( i = 0; i < nstrips && i < (int) dir->tdir_count; i++ ) - { - lp[i] = dp[i]; - } - } + /* 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 - _TIFFfree( (char *) dp ); - } else - status = TIFFFetchLongArray(tif, dir, lp); - - return (status); -} + new_dest = + (uint8_t *)_TIFFreallocExt(tif, *pdest, already_read + to_read); + if (new_dest == NULL) + { + TIFFErrorExtR(tif, 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; -/* - * Fetch and set the RefBlackWhite tag. - */ -static int -TIFFFetchRefBlackWhite(TIFF* tif, TIFFDirEntry* dir) -{ - static const char mesg[] = "for \"ReferenceBlackWhite\" array"; - char* cp; - int ok; - - if (dir->tdir_type == TIFF_RATIONAL) - return (TIFFFetchNormalTag(tif, dir)); - /* - * Handle LONG's for backward compatibility. - */ - cp = (char *)_TIFFCheckMalloc(tif, dir->tdir_count, - sizeof (uint32), mesg); - if( (ok = (cp && TIFFFetchLongArray(tif, dir, (uint32*) cp))) != 0) { - float* fp = (float*) - _TIFFCheckMalloc(tif, dir->tdir_count, sizeof (float), mesg); - if( (ok = (fp != NULL)) != 0 ) { - uint32 i; - for (i = 0; i < dir->tdir_count; i++) - fp[i] = (float)((uint32*) cp)[i]; - ok = TIFFSetField(tif, dir->tdir_tag, fp); - _TIFFfree((char*) fp); - } - } - if (cp) - _TIFFfree(cp); - return (ok); + bytes_read = TIFFReadFile(tif, (char *)*pdest + already_read, to_read); + already_read += bytes_read; + if (bytes_read != to_read) + { + return TIFFReadDirEntryErrIo; + } + } + return TIFFReadDirEntryErrOk; } -/* - * Fetch and set the SubjectDistance EXIF tag. - */ -static int -TIFFFetchSubjectDistance(TIFF* tif, TIFFDirEntry* dir) +/* Caution: if raising that value, make sure int32 / uint32 overflows can't + * occur elsewhere */ +#define MAX_SIZE_TAG_DATA 2147483647U + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryArrayWithLimit(TIFF *tif, TIFFDirEntry *direntry, + uint32_t *count, uint32_t desttypesize, + void **value, uint64_t maxcount) { - uint32 l[2]; - float v; - int ok = 0; + int typesize; + uint32_t datasize; + void *data; + uint64_t target_count64; + int original_datasize_clamped; + typesize = TIFFDataWidth(direntry->tdir_type); - if( dir->tdir_count != 1 || dir->tdir_type != TIFF_RATIONAL ) + target_count64 = + (direntry->tdir_count > maxcount) ? maxcount : direntry->tdir_count; + + if ((target_count64 == 0) || (typesize == 0)) { - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, - "incorrect count or type for SubjectDistance, tag ignored" ); - return (0); + *value = 0; + return (TIFFReadDirEntryErrOk); } + (void)desttypesize; - if (TIFFFetchData(tif, dir, (char *)l) - && cvtRational(tif, dir, l[0], l[1], &v)) { - /* - * XXX: Numerator 0xFFFFFFFF means that we have infinite - * distance. Indicate that with a negative floating point - * SubjectDistance value. - */ - ok = TIFFSetField(tif, dir->tdir_tag, - (l[0] != 0xFFFFFFFF) ? v : -v); - } + /* 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; - return ok; -} + /* + * 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)(MAX_SIZE_TAG_DATA / typesize) < target_count64) + return (TIFFReadDirEntryErrSizesan); + if ((uint64_t)(MAX_SIZE_TAG_DATA / desttypesize) < target_count64) + return (TIFFReadDirEntryErrSizesan); -/* - * 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; - uint32 bytecount = td->td_stripbytecount[0]; - uint32 offset = td->td_stripoffset[0]; - tsize_t rowbytes = TIFFVTileSize(tif, 1), stripbytes; - tstrip_t strip, nstrips, rowsperstrip; - uint32* newcounts; - uint32* newoffsets; - - /* - * Make the rows hold at least one scanline, but fill specified amount - * of data if possible. - */ - if (rowbytes > STRIP_SIZE_DEFAULT) { - stripbytes = rowbytes; - rowsperstrip = 1; - } else if (rowbytes > 0 ) { - rowsperstrip = STRIP_SIZE_DEFAULT / rowbytes; - stripbytes = rowbytes * rowsperstrip; - } - else - return; + *count = (uint32_t)target_count64; + datasize = (*count) * typesize; + assert((tmsize_t)datasize > 0); - /* - * never increase the number of strips in an image - */ - if (rowsperstrip >= td->td_rowsperstrip) - return; - nstrips = (tstrip_t) TIFFhowmany(bytecount, stripbytes); - if( nstrips == 0 ) /* something is wonky, do nothing. */ - return; + if (isMapped(tif) && datasize > (uint64_t)tif->tif_size) + return TIFFReadDirEntryErrIo; - newcounts = (uint32*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint32), - "for chopped \"StripByteCounts\" array"); - newoffsets = (uint32*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint32), - "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 (strip = 0; strip < nstrips; strip++) { - if ((uint32)stripbytes > bytecount) - stripbytes = bytecount; - newcounts[strip] = stripbytes; - newoffsets[strip] = offset; - 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); - _TIFFfree(td->td_stripoffset); - td->td_stripbytecount = newcounts; - td->td_stripoffset = newoffsets; - td->td_stripbytecountsorted = 1; -} - -/* vim: set ts=8 sts=8 sw=8 noet: */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ + 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) + { + _TIFFfreeExt(tif, 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) + { + _TIFFfreeExt(tif, 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; n < count; n++) + { + err = TIFFReadDirEntryCheckRangeByteSbyte(*m); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, origdata); + return (err); + } + m++; + } + *value = (uint8_t *)origdata; + return (TIFFReadDirEntryErrOk); + } + } + data = (uint8_t *)_TIFFmallocExt(tif, count); + if (data == 0) + { + _TIFFfreeExt(tif, origdata); + return (TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_SHORT: + { + uint16_t *ma; + uint8_t *mb; + uint32_t n; + ma = (uint16_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8((uint64_t *)ma); + err = TIFFReadDirEntryCheckRangeByteSlong8(*ma); + if (err != TIFFReadDirEntryErrOk) + break; + *mb++ = (uint8_t)(*ma++); + } + } + break; + } + _TIFFfreeExt(tif, origdata); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, 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; n < count; n++) + { + err = TIFFReadDirEntryCheckRangeSbyteByte(*m); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, origdata); + return (err); + } + m++; + } + *value = (int8_t *)origdata; + return (TIFFReadDirEntryErrOk); + } + case TIFF_SBYTE: + *value = (int8_t *)origdata; + return (TIFFReadDirEntryErrOk); + } + data = (int8_t *)_TIFFmallocExt(tif, count); + if (data == 0) + { + _TIFFfreeExt(tif, origdata); + return (TIFFReadDirEntryErrAlloc); + } + switch (direntry->tdir_type) + { + case TIFF_SHORT: + { + uint16_t *ma; + int8_t *mb; + uint32_t n; + ma = (uint16_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8((uint64_t *)ma); + err = TIFFReadDirEntryCheckRangeSbyteSlong8(*ma); + if (err != TIFFReadDirEntryErrOk) + break; + *mb++ = (int8_t)(*ma++); + } + } + break; + } + _TIFFfreeExt(tif, origdata); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, 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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort((uint16_t *)m); + err = TIFFReadDirEntryCheckRangeShortSshort(*m); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, origdata); + return (err); + } + m++; + } + *value = (uint16_t *)origdata; + return (TIFFReadDirEntryErrOk); + } + } + data = (uint16_t *)_TIFFmallocExt(tif, count * 2); + if (data == 0) + { + _TIFFfreeExt(tif, 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; n < count; n++) + *mb++ = (uint16_t)(*ma++); + } + break; + case TIFF_SBYTE: + { + int8_t *ma; + uint16_t *mb; + uint32_t n; + ma = (int8_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + err = TIFFReadDirEntryCheckRangeShortSbyte(*ma); + if (err != TIFFReadDirEntryErrOk) + break; + *mb++ = (uint16_t)(*ma++); + } + } + break; + case TIFF_LONG: + { + uint32_t *ma; + uint16_t *mb; + uint32_t n; + ma = (uint32_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8((uint64_t *)ma); + err = TIFFReadDirEntryCheckRangeShortSlong8(*ma); + if (err != TIFFReadDirEntryErrOk) + break; + *mb++ = (uint16_t)(*ma++); + } + } + break; + } + _TIFFfreeExt(tif, origdata); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, 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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(m); + err = TIFFReadDirEntryCheckRangeSshortShort(*m); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, 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 *)_TIFFmallocExt(tif, count * 2); + if (data == 0) + { + _TIFFfreeExt(tif, 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; n < count; n++) + *mb++ = (int16_t)(*ma++); + } + break; + case TIFF_SBYTE: + { + int8_t *ma; + int16_t *mb; + uint32_t n; + ma = (int8_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + *mb++ = (int16_t)(*ma++); + } + break; + case TIFF_LONG: + { + uint32_t *ma; + int16_t *mb; + uint32_t n; + ma = (uint32_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8((uint64_t *)ma); + err = TIFFReadDirEntryCheckRangeSshortSlong8(*ma); + if (err != TIFFReadDirEntryErrOk) + break; + *mb++ = (int16_t)(*ma++); + } + } + break; + } + _TIFFfreeExt(tif, origdata); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, 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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong((uint32_t *)m); + err = TIFFReadDirEntryCheckRangeLongSlong(*m); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, origdata); + return (err); + } + m++; + } + *value = (uint32_t *)origdata; + return (TIFFReadDirEntryErrOk); + } + } + data = (uint32_t *)_TIFFmallocExt(tif, count * 4); + if (data == 0) + { + _TIFFfreeExt(tif, 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; n < count; n++) + *mb++ = (uint32_t)(*ma++); + } + break; + case TIFF_SBYTE: + { + int8_t *ma; + uint32_t *mb; + uint32_t n; + ma = (int8_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + err = TIFFReadDirEntryCheckRangeLongSbyte(*ma); + if (err != TIFFReadDirEntryErrOk) + break; + *mb++ = (uint32_t)(*ma++); + } + } + break; + case TIFF_SHORT: + { + uint16_t *ma; + uint32_t *mb; + uint32_t n; + ma = (uint16_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8((uint64_t *)ma); + err = TIFFReadDirEntryCheckRangeLongSlong8(*ma); + if (err != TIFFReadDirEntryErrOk) + break; + *mb++ = (uint32_t)(*ma++); + } + } + break; + } + _TIFFfreeExt(tif, origdata); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, 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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong((uint32_t *)m); + err = TIFFReadDirEntryCheckRangeSlongLong(*m); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, 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 *)_TIFFmallocExt(tif, count * 4); + if (data == 0) + { + _TIFFfreeExt(tif, 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; n < count; n++) + *mb++ = (int32_t)(*ma++); + } + break; + case TIFF_SBYTE: + { + int8_t *ma; + int32_t *mb; + uint32_t n; + ma = (int8_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + *mb++ = (int32_t)(*ma++); + } + break; + case TIFF_SHORT: + { + uint16_t *ma; + int32_t *mb; + uint32_t n; + ma = (uint16_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8((uint64_t *)ma); + err = TIFFReadDirEntryCheckRangeSlongSlong8(*ma); + if (err != TIFFReadDirEntryErrOk) + break; + *mb++ = (int32_t)(*ma++); + } + } + break; + } + _TIFFfreeExt(tif, origdata); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, 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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8((uint64_t *)m); + err = TIFFReadDirEntryCheckRangeLong8Slong8(*m); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, origdata); + return (err); + } + m++; + } + *value = (uint64_t *)origdata; + return (TIFFReadDirEntryErrOk); + } + } + data = (uint64_t *)_TIFFmallocExt(tif, count * 8); + if (data == 0) + { + _TIFFfreeExt(tif, 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; n < count; n++) + *mb++ = (uint64_t)(*ma++); + } + break; + case TIFF_SBYTE: + { + int8_t *ma; + uint64_t *mb; + uint32_t n; + ma = (int8_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + err = TIFFReadDirEntryCheckRangeLong8Sbyte(*ma); + if (err != TIFFReadDirEntryErrOk) + break; + *mb++ = (uint64_t)(*ma++); + } + } + break; + case TIFF_SHORT: + { + uint16_t *ma; + uint64_t *mb; + uint32_t n; + ma = (uint16_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong((uint32_t *)ma); + err = TIFFReadDirEntryCheckRangeLong8Slong(*ma); + if (err != TIFFReadDirEntryErrOk) + break; + *mb++ = (uint64_t)(*ma++); + } + } + break; + } + _TIFFfreeExt(tif, origdata); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, 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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(m); + err = TIFFReadDirEntryCheckRangeSlong8Long8(*m); + if (err != TIFFReadDirEntryErrOk) + { + _TIFFfreeExt(tif, 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 *)_TIFFmallocExt(tif, count * 8); + if (data == 0) + { + _TIFFfreeExt(tif, 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; n < count; n++) + *mb++ = (int64_t)(*ma++); + } + break; + case TIFF_SBYTE: + { + int8_t *ma; + int64_t *mb; + uint32_t n; + ma = (int8_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + *mb++ = (int64_t)(*ma++); + } + break; + case TIFF_SHORT: + { + uint16_t *ma; + int64_t *mb; + uint32_t n; + ma = (uint16_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong((uint32_t *)ma); + *mb++ = (int64_t)(*ma++); + } + } + break; + } + _TIFFfreeExt(tif, 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 *)_TIFFmallocExt(tif, count * sizeof(float)); + if (data == 0) + { + _TIFFfreeExt(tif, 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; n < count; n++) + *mb++ = (float)(*ma++); + } + break; + case TIFF_SBYTE: + { + int8_t *ma; + float *mb; + uint32_t n; + ma = (int8_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + *mb++ = (float)(*ma++); + } + break; + case TIFF_SHORT: + { + uint16_t *ma; + float *mb; + uint32_t n; + ma = (uint16_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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 < count; n++) + { + double val = *ma++; + if (val > FLT_MAX) + val = FLT_MAX; + else if (val < -FLT_MAX) + val = -FLT_MAX; + *mb++ = (float)val; + } + } + break; + } + _TIFFfreeExt(tif, 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 *)_TIFFmallocExt(tif, count * sizeof(double)); + if (data == 0) + { + _TIFFfreeExt(tif, 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; n < count; n++) + *mb++ = (double)(*ma++); + } + break; + case TIFF_SBYTE: + { + int8_t *ma; + double *mb; + uint32_t n; + ma = (int8_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + *mb++ = (double)(*ma++); + } + break; + case TIFF_SHORT: + { + uint16_t *ma; + double *mb; + uint32_t n; + ma = (uint16_t *)origdata; + mb = data; + for (n = 0; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + { + if (tif->tif_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; n < count; n++) + *mb++ = (double)(*ma++); + } + break; + } + _TIFFfreeExt(tif, origdata); + *value = data; + return (TIFFReadDirEntryErrOk); +} + +static enum TIFFReadDirEntryErr +TIFFReadDirEntryIfd8Array(TIFF *tif, TIFFDirEntry *direntry, uint64_t **value) +{ + enum TIFFReadDirEntryErr err; + uint32_t count; + void *origdata; + uint64_t *data; + switch (direntry->tdir_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 *)_TIFFmallocExt(tif, count * 8); + if (data == 0) + { + _TIFFfreeExt(tif, 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; n < count; n++) + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(ma); + *mb++ = (uint64_t)(*ma++); + } + } + break; + } + _TIFFfreeExt(tif, 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--; + } + _TIFFfreeExt(tif, m); + return (err); +} + +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); +} + +#if 0 +static enum TIFFReadDirEntryErr +TIFFReadDirEntryCheckedRationalDirect(TIFF *tif, TIFFDirEntry *direntry, + TIFFRational_t *value) +{ /*--: SetGetRATIONAL_directly:_CustomTag: Read rational (and signed rationals) + directly --*/ + UInt64Aligned_t m; + + assert(sizeof(double) == 8); + assert(sizeof(uint64_t) == 8); + assert(sizeof(uint32_t) == 4); + + if (direntry->tdir_count != 1) + return (TIFFReadDirEntryErrCount); + + if (direntry->tdir_type != TIFF_RATIONAL && + direntry->tdir_type != TIFF_SRATIONAL) + return (TIFFReadDirEntryErrType); + + 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); + + value->uNum = m.i[0]; + value->uDenom = m.i[1]; + return (TIFFReadDirEntryErrOk); +} /*-- TIFFReadDirEntryCheckedRationalDirect() --*/ +#endif + +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: + TIFFErrorExtR(tif, module, "Incorrect count for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrType: + TIFFErrorExtR(tif, module, "Incompatible type for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrIo: + TIFFErrorExtR(tif, module, "IO error during reading of \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrRange: + TIFFErrorExtR(tif, module, "Incorrect value for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrPsdif: + TIFFErrorExtR( + tif, module, + "Cannot handle different values per sample for \"%s\"", + tagname); + break; + case TIFFReadDirEntryErrSizesan: + TIFFErrorExtR(tif, module, + "Sanity check on size of \"%s\" value failed", + tagname); + break; + case TIFFReadDirEntryErrAlloc: + TIFFErrorExtR(tif, module, "Out of memory reading of \"%s\"", + tagname); + break; + default: + assert(0); /* we should never get here */ + break; + } + } + else + { + switch (err) + { + case TIFFReadDirEntryErrCount: + TIFFWarningExtR(tif, module, + "Incorrect count for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrType: + TIFFWarningExtR(tif, module, + "Incompatible type for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrIo: + TIFFWarningExtR( + tif, module, + "IO error during reading of \"%s\"; tag ignored", tagname); + break; + case TIFFReadDirEntryErrRange: + TIFFWarningExtR(tif, module, + "Incorrect value for \"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrPsdif: + TIFFWarningExtR(tif, module, + "Cannot handle different values per sample for " + "\"%s\"; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrSizesan: + TIFFWarningExtR( + tif, module, + "Sanity check on size of \"%s\" value failed; tag ignored", + tagname); + break; + case TIFFReadDirEntryErrAlloc: + TIFFWarningExtR(tif, 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; + + if (tif->tif_nextdiroff == 0) + { + /* In this special case, tif_diroff needs also to be set to 0. + * This is behind the last IFD, thus no checking or reading necessary. + */ + tif->tif_diroff = tif->tif_nextdiroff; + return 0; + } + + nextdiroff = tif->tif_nextdiroff; + /* tif_curdir++ and tif_nextdiroff should only be updated after SUCCESSFUL + * reading of the directory. Otherwise, invalid IFD offsets could corrupt + * the IFD list. */ + if (!_TIFFCheckDirNumberAndOffset(tif, + tif->tif_curdir == + TIFF_NON_EXISTENT_DIR_NUMBER + ? 0 + : tif->tif_curdir + 1, + nextdiroff)) + { + return 0; /* bad offset (IFD looping or more than TIFF_MAX_DIR_COUNT + IFDs) */ + } + dircount = TIFFFetchDirectory(tif, nextdiroff, &dir, &tif->tif_nextdiroff); + if (!dircount) + { + TIFFErrorExtR(tif, module, + "Failed to read directory at offset %" PRIu64, + nextdiroff); + return 0; + } + /* Set global values after a valid directory has been fetched. + * tif_diroff is already set to nextdiroff in TIFFFetchDirectory() in the + * beginning. */ + if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER) + tif->tif_curdir = 0; + else + tif->tif_curdir++; + (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ + + 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; mb < dircount; ma++, mb++) + { + TIFFDirEntry *na; + uint16_t nb; + for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++) + { + if (ma->tdir_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. + * After PlanarConfiguration is preset in TIFFDefaultDirectory() + * the following setting is not needed, but does not harm either. + */ + 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; di < dircount; di++, dp++) + { + if (!dp->tdir_ignore) + { + TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); + if (fii == FAILED_FII) + { + TIFFWarningExtR(tif, 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)) + { + TIFFWarningExtR( + tif, 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; + TIFFWarningExtR(tif, 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; + } + + /* + * Second pass: extract other information. + */ + for (di = 0, dp = dir; di < dircount; di++, dp++) + { + if (!dp->tdir_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; + _TIFFfreeExt(tif, 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); + TIFFWarningExtR( + tif, 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); + TIFFWarningExtR( + tif, 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); + TIFFWarningExtR( + tif, 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); + TIFFWarningExtR( + tif, module, + "Ignoring %s because BitsPerSample=%" PRIu16 ">24", + fip ? fip->field_name : "unknown tagname", + tif->tif_dir.td_bitspersample); + continue; + } + countpersample = (1U << tif->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); + _TIFFfreeExt(tif, 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 */ +#if 0 + case TIFFTAG_EP_BATTERYLEVEL: + /* TIFFTAG_EP_BATTERYLEVEL can be RATIONAL or ASCII. + * LibTiff defines it as ASCII and converts RATIONAL to an + * ASCII string. */ + switch (dp->tdir_type) + { + case TIFF_RATIONAL: + { + /* Read rational and convert to ASCII*/ + enum TIFFReadDirEntryErr err; + TIFFRational_t rValue; + err = TIFFReadDirEntryCheckedRationalDirect( + tif, dp, &rValue); + if (err != TIFFReadDirEntryErrOk) + { + fip = TIFFFieldWithTag(tif, dp->tdir_tag); + TIFFReadDirEntryOutputErr( + tif, err, module, + fip ? fip->field_name : "unknown tagname", + 1); + } + else + { + char szAux[32]; + snprintf(szAux, sizeof(szAux) - 1, "%d/%d", + rValue.uNum, rValue.uDenom); + TIFFSetField(tif, dp->tdir_tag, szAux); + } + } + break; + case TIFF_ASCII: + (void)TIFFFetchNormalTag(tif, dp, TRUE); + break; + default: + fip = TIFFFieldWithTag(tif, dp->tdir_tag); + TIFFWarningExtR(tif, module, + "Invalid data type for tag %s. " + "ASCII or RATIONAL expected", + fip ? fip->field_name + : "unknown tagname"); + break; + } + break; +#endif + default: + (void)TIFFFetchNormalTag(tif, dp, TRUE); + break; + } + } /* -- if (!dp->tdir_ignore) */ + } /* -- for-loop -- */ + + /* + * 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)) + { + TIFFWarningExtR( + tif, 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; + TIFFWarningExtR(tif, module, + "Photometric tag value assumed incorrect, " + "assuming data is YCbCr instead of RGB"); + } + if (!TIFFFieldSet(tif, FIELD_BITSPERSAMPLE)) + { + TIFFWarningExtR( + tif, 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) + { + TIFFWarningExtR(tif, 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) + { + TIFFWarningExtR(tif, 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; + } + } + } + + /* + * Setup appropriate structures (by strip or by tile) + * We do that only after the above OJPEG hack which alters SamplesPerPixel + * and thus influences the number of strips in the separate planarconfig. + */ + 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) + { + TIFFErrorExtR(tif, 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; + } + } + + 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; + } + } + } + + /* + * 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; + + TIFFWarningExtR( + tif, 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 *)_TIFFcallocExt( + tif, tif->tif_dir.td_extrasamples, sizeof(uint16_t)); + if (!new_sampleinfo) + { + TIFFErrorExtR(tif, module, + "Failed to allocate memory for " + "temporary new sampleinfo array " + "(%" PRIu16 " 16 bit elements)", + tif->tif_dir.td_extrasamples); + goto bad; + } + + if (old_extrasamples > 0) + memcpy(new_sampleinfo, tif->tif_dir.td_sampleinfo, + old_extrasamples * sizeof(uint16_t)); + _TIFFsetShortArrayExt(tif, &tif->tif_dir.td_sampleinfo, new_sampleinfo, + tif->tif_dir.td_extrasamples); + _TIFFfreeExt(tif, 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; + } + TIFFWarningExtR( + tif, 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. + */ + TIFFWarningExtR(tif, 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. + */ + TIFFWarningExtR(tif, module, + "Wrong \"StripByteCounts\" field, ignoring and " + "calculating from imagelength"); + if (EstimateStripByteCounts(tif, dir, dircount) < 0) + goto bad; + } + } + if (dir) + { + _TIFFfreeExt(tif, 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) + { + TIFFErrorExtR(tif, module, "Cannot handle zero scanline size"); + return (0); + } + + if (isTiled(tif)) + { + tif->tif_tilesize = TIFFTileSize(tif); + if (!tif->tif_tilesize) + { + TIFFErrorExtR(tif, module, "Cannot handle zero tile size"); + return (0); + } + } + else + { + if (!TIFFStripSize(tif)) + { + TIFFErrorExtR(tif, module, "Cannot handle zero strip size"); + return (0); + } + } + return (1); +bad: + if (dir) + _TIFFfreeExt(tif, dir); + return (0); +} + +static void TIFFReadDirectoryCheckOrder(TIFF *tif, TIFFDirEntry *dir, + uint16_t dircount) +{ + static const char module[] = "TIFFReadDirectoryCheckOrder"; + uint32_t m; + uint16_t n; + TIFFDirEntry *o; + m = 0; + for (n = 0, o = dir; n < dircount; n++, o++) + { + if (o->tdir_tag < m) + { + TIFFWarningExtR(tif, 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; n < dircount; m++, n++) + { + if (m->tdir_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) + { + TIFFErrorExtR(tif, 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; di < dircount; di++, dp++) + { + TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); + if (fii == FAILED_FII) + { + TIFFWarningExtR(tif, 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)) + { + TIFFWarningExtR(tif, 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) + { + TIFFWarningExtR(tif, 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: + if (!TIFFFieldIsAnonymous(fip)) + { + /* should only be called on a Exif directory */ + /* when exifFields[] is active */ + (void)TIFFFetchSubjectDistance(tif, dp); + } + else + { + (void)TIFFFetchNormalTag(tif, dp, TRUE); + } + break; + default: + (void)TIFFFetchNormalTag(tif, dp, TRUE); + break; + } + } /*-- if (!dp->tdir_ignore) */ + } + } + /* To be able to return from SubIFD or custom-IFD to main-IFD */ + tif->tif_setdirectory_force_absolute = TRUE; + if (dir) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + { + TIFFErrorExtR( + tif, 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"; + + TIFFErrorExtR(tif, module, + "TIFF directory is missing required \"%s\" field", tagname); +} + +static unsigned long hashFuncOffsetToNumber(const void *elt) +{ + const TIFFOffsetAndDirNumber *offsetAndDirNumber = + (const TIFFOffsetAndDirNumber *)elt; + const uint32_t hash = (uint32_t)(offsetAndDirNumber->offset >> 32) ^ + ((uint32_t)offsetAndDirNumber->offset & 0xFFFFFFFFU); + return hash; +} + +static bool equalFuncOffsetToNumber(const void *elt1, const void *elt2) +{ + const TIFFOffsetAndDirNumber *offsetAndDirNumber1 = + (const TIFFOffsetAndDirNumber *)elt1; + const TIFFOffsetAndDirNumber *offsetAndDirNumber2 = + (const TIFFOffsetAndDirNumber *)elt2; + return offsetAndDirNumber1->offset == offsetAndDirNumber2->offset; +} + +static unsigned long hashFuncNumberToOffset(const void *elt) +{ + const TIFFOffsetAndDirNumber *offsetAndDirNumber = + (const TIFFOffsetAndDirNumber *)elt; + return offsetAndDirNumber->dirNumber; +} + +static bool equalFuncNumberToOffset(const void *elt1, const void *elt2) +{ + const TIFFOffsetAndDirNumber *offsetAndDirNumber1 = + (const TIFFOffsetAndDirNumber *)elt1; + const TIFFOffsetAndDirNumber *offsetAndDirNumber2 = + (const TIFFOffsetAndDirNumber *)elt2; + return offsetAndDirNumber1->dirNumber == offsetAndDirNumber2->dirNumber; +} + +/* + * Check the directory number and offset against the list of already seen + * directory numbers and 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 + * and its IFD number against that list. However, the offset of an IFD number + * can change - e.g. when writing updates to file. + * Returns 1 if all is ok; 0 if last directory or IFD loop is encountered, + * or an error has occurred. + */ +int _TIFFCheckDirNumberAndOffset(TIFF *tif, tdir_t dirn, uint64_t diroff) +{ + if (diroff == 0) /* no more directories */ + return 0; + + if (tif->tif_map_dir_offset_to_number == NULL) + { + tif->tif_map_dir_offset_to_number = TIFFHashSetNew( + hashFuncOffsetToNumber, equalFuncOffsetToNumber, free); + if (tif->tif_map_dir_offset_to_number == NULL) + { + TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", + "Not enough memory"); + return 1; + } + } + + if (tif->tif_map_dir_number_to_offset == NULL) + { + /* No free callback for this map, as it shares the same items as + * tif->tif_map_dir_offset_to_number. */ + tif->tif_map_dir_number_to_offset = TIFFHashSetNew( + hashFuncNumberToOffset, equalFuncNumberToOffset, NULL); + if (tif->tif_map_dir_number_to_offset == NULL) + { + TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", + "Not enough memory"); + return 1; + } + } + + /* Check if offset is already in the list: + * - yes: check, if offset is at the same IFD number - if not, it is an IFD + * loop + * - no: add to list or update offset at that IFD number + */ + TIFFOffsetAndDirNumber entry; + entry.offset = diroff; + entry.dirNumber = dirn; + + TIFFOffsetAndDirNumber *foundEntry = + (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( + tif->tif_map_dir_offset_to_number, &entry); + if (foundEntry) + { + if (foundEntry->dirNumber == dirn) + { + return 1; + } + else + { + TIFFWarningExtR(tif, "_TIFFCheckDirNumberAndOffset", + "TIFF directory %d has IFD looping to directory %u " + "at offset 0x%" PRIx64 " (%" PRIu64 ")", + (int)dirn - 1, foundEntry->dirNumber, diroff, + diroff); + return 0; + } + } + + /* Check if offset of an IFD has been changed and update offset of that IFD + * number. */ + foundEntry = (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( + tif->tif_map_dir_number_to_offset, &entry); + if (foundEntry) + { + if (foundEntry->offset != diroff) + { + TIFFOffsetAndDirNumber entryOld; + entryOld.offset = foundEntry->offset; + entryOld.dirNumber = dirn; + /* We must remove first from tif_map_dir_number_to_offset as the */ + /* entry is owned (and thus freed) by */ + /* tif_map_dir_offset_to_number */ + TIFFOffsetAndDirNumber *foundEntryOld = + (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( + tif->tif_map_dir_number_to_offset, &entryOld); + if (foundEntryOld) + { + TIFFHashSetRemove(tif->tif_map_dir_number_to_offset, + foundEntryOld); + } + foundEntryOld = (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( + tif->tif_map_dir_offset_to_number, &entryOld); + if (foundEntryOld) + { + TIFFHashSetRemove(tif->tif_map_dir_offset_to_number, + foundEntryOld); + } + + TIFFOffsetAndDirNumber *entryPtr = (TIFFOffsetAndDirNumber *)malloc( + sizeof(TIFFOffsetAndDirNumber)); + if (entryPtr == NULL) + { + return 0; + } + + /* Add IFD offset and dirn to IFD directory list */ + *entryPtr = entry; + + if (!TIFFHashSetInsert(tif->tif_map_dir_offset_to_number, entryPtr)) + { + TIFFErrorExtR( + tif, "_TIFFCheckDirNumberAndOffset", + "Insertion in tif_map_dir_offset_to_number failed"); + return 0; + } + if (!TIFFHashSetInsert(tif->tif_map_dir_number_to_offset, entryPtr)) + { + TIFFErrorExtR( + tif, "_TIFFCheckDirNumberAndOffset", + "Insertion in tif_map_dir_number_to_offset failed"); + return 0; + } + } + return 1; + } + + /* Arbitrary (hopefully big enough) limit */ + if (TIFFHashSetSize(tif->tif_map_dir_offset_to_number) >= + TIFF_MAX_DIR_COUNT) + { + TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", + "Cannot handle more than %u TIFF directories", + TIFF_MAX_DIR_COUNT); + return 0; + } + + TIFFOffsetAndDirNumber *entryPtr = + (TIFFOffsetAndDirNumber *)malloc(sizeof(TIFFOffsetAndDirNumber)); + if (entryPtr == NULL) + { + TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", + "malloc(sizeof(TIFFOffsetAndDirNumber)) failed"); + return 0; + } + + /* Add IFD offset and dirn to IFD directory list */ + *entryPtr = entry; + + if (!TIFFHashSetInsert(tif->tif_map_dir_offset_to_number, entryPtr)) + { + TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", + "Insertion in tif_map_dir_offset_to_number failed"); + return 0; + } + if (!TIFFHashSetInsert(tif->tif_map_dir_number_to_offset, entryPtr)) + { + TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset", + "Insertion in tif_map_dir_number_to_offset failed"); + return 0; + } + + return 1; +} /* --- _TIFFCheckDirNumberAndOffset() ---*/ + +/* + * Retrieve the matching IFD directory number of a given IFD offset + * from the list of directories already seen. + * Returns 1 if the offset was in the list and the directory number + * can be returned. + * Otherwise returns 0 or if an error occurred. + */ +int _TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, tdir_t *dirn) +{ + if (diroff == 0) /* no more directories */ + return 0; + + /* Check if offset is already in the list and return matching directory + * number. Otherwise update IFD list using TIFFNumberOfDirectories() and + * search again in IFD list. + */ + if (tif->tif_map_dir_offset_to_number == NULL) + return 0; + TIFFOffsetAndDirNumber entry; + entry.offset = diroff; + entry.dirNumber = 0; /* not used */ + + TIFFOffsetAndDirNumber *foundEntry = + (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( + tif->tif_map_dir_offset_to_number, &entry); + if (foundEntry) + { + *dirn = foundEntry->dirNumber; + return 1; + } + + /* This updates the directory list for all main-IFDs in the file. */ + TIFFNumberOfDirectories(tif); + + foundEntry = (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( + tif->tif_map_dir_offset_to_number, &entry); + if (foundEntry) + { + *dirn = foundEntry->dirNumber; + return 1; + } + + return 0; +} /*--- _TIFFGetDirNumberFromOffset() ---*/ + +/* + * Retrieve the matching IFD directory offset of a given IFD number + * from the list of directories already seen. + * Returns 1 if the offset was in the list of already seen IFDs and the + * directory offset can be returned. The directory list is not updated. + * Otherwise returns 0 or if an error occurred. + */ +int _TIFFGetOffsetFromDirNumber(TIFF *tif, tdir_t dirn, uint64_t *diroff) +{ + + if (tif->tif_map_dir_number_to_offset == NULL) + return 0; + TIFFOffsetAndDirNumber entry; + entry.offset = 0; /* not used */ + entry.dirNumber = dirn; + + TIFFOffsetAndDirNumber *foundEntry = + (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( + tif->tif_map_dir_number_to_offset, &entry); + if (foundEntry) + { + *diroff = foundEntry->offset; + return 1; + } + + return 0; +} /*--- _TIFFGetOffsetFromDirNumber() ---*/ + +/* + * Remove an entry from the directory list of already seen directories + * by directory offset. + * If an entry is to be removed from the list, it is also okay if the entry + * is not in the list or the list does not exist. + */ +int _TIFFRemoveEntryFromDirectoryListByOffset(TIFF *tif, uint64_t diroff) +{ + if (tif->tif_map_dir_offset_to_number == NULL) + return 1; + + TIFFOffsetAndDirNumber entryOld; + entryOld.offset = diroff; + entryOld.dirNumber = 0; + /* We must remove first from tif_map_dir_number_to_offset as the + * entry is owned (and thus freed) by tif_map_dir_offset_to_number. + * However, we need firstly to find the directory number from offset. */ + + TIFFOffsetAndDirNumber *foundEntryOldOff = + (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( + tif->tif_map_dir_offset_to_number, &entryOld); + if (foundEntryOldOff) + { + entryOld.dirNumber = foundEntryOldOff->dirNumber; + if (tif->tif_map_dir_number_to_offset != NULL) + { + TIFFOffsetAndDirNumber *foundEntryOldDir = + (TIFFOffsetAndDirNumber *)TIFFHashSetLookup( + tif->tif_map_dir_number_to_offset, &entryOld); + if (foundEntryOldDir) + { + TIFFHashSetRemove(tif->tif_map_dir_number_to_offset, + foundEntryOldDir); + TIFFHashSetRemove(tif->tif_map_dir_offset_to_number, + foundEntryOldOff); + return 1; + } + } + else + { + TIFFErrorExtR(tif, "_TIFFRemoveEntryFromDirectoryListByOffset", + "Unexpectedly tif_map_dir_number_to_offset is " + "missing but tif_map_dir_offset_to_number exists."); + return 0; + } + } + return 1; +} /*--- _TIFFRemoveEntryFromDirectoryListByOffset() ---*/ + +/* + * 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); + TIFFWarningExtR(tif, 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); + TIFFWarningExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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))) + { + TIFFErrorExtR(tif, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount16); + if (dircount16 > 4096) + { + TIFFErrorExtR(tif, 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))) + { + TIFFErrorExtR(tif, module, + "%s: Can not read TIFF directory count", + tif->tif_name); + return 0; + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64 > 4096) + { + TIFFErrorExtR(tif, 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))) + { + TIFFErrorExtR(tif, module, "%.100s: Can not read TIFF directory", + tif->tif_name); + _TIFFfreeExt(tif, 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) + { + TIFFErrorExtR(tif, 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 < off) || (m < (tmsize_t)sizeof(uint16_t)) || + (m > tif->tif_size)) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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 < off) || (m < (tmsize_t)sizeof(uint64_t)) || + (m > tif->tif_size)) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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 ((m < off) || (m < (tmsize_t)(dircount16 * dirsize)) || + (m > tif->tif_size)) + { + TIFFErrorExtR(tif, module, "Can not read TIFF directory"); + _TIFFfreeExt(tif, 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 < off) || (m < (tmsize_t)sizeof(uint32_t)) || + (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 < off) || (m < (tmsize_t)sizeof(uint64_t)) || + (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) + { + _TIFFfreeExt(tif, origdir); + return 0; + } + ma = (uint8_t *)origdir; + mb = dir; + for (n = 0; n < dircount16; n++) + { + mb->tdir_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++; + } + _TIFFfreeExt(tif, 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) + { + TIFFErrorExtR(tif, "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: + TIFFErrorExtR( + tif, "TIFFFetchNormalTag", + "Defined set_field_type of custom tag %u (%s) is " + "TIFF_SETGET_UNDEFINED and thus tag is not read from file", + fip->field_tag, fip->field_name); + break; + case TIFF_SETGET_ASCII: + { + uint8_t *data; + assert(fip->field_passcount == 0); + err = TIFFReadDirEntryByteArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + size_t mb = 0; + int n; + if (data != NULL) + { + if (dp->tdir_count > 0 && data[dp->tdir_count - 1] == 0) + { + /* optimization: if data is known to be 0 terminated, we + * can use strlen() */ + mb = strlen((const char *)data); + } + else + { + /* general case. equivalent to non-portable */ + /* mb = strnlen((const char*)data, + * (uint32_t)dp->tdir_count); */ + 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) + TIFFWarningExtR( + tif, 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; + TIFFWarningExtR( + tif, module, + "ASCII value for tag \"%s\" does not end in null byte", + fip->field_name); + /* TIFFReadDirEntryArrayWithLimit() ensures this can't be + * larger than MAX_SIZE_TAG_DATA */ + assert((uint32_t)dp->tdir_count + 1 == dp->tdir_count + 1); + o = _TIFFmallocExt(tif, (uint32_t)dp->tdir_count + 1); + if (o == NULL) + { + if (data != NULL) + _TIFFfreeExt(tif, data); + return (0); + } + if (dp->tdir_count > 0) + { + _TIFFmemcpy(o, data, (uint32_t)dp->tdir_count); + } + o[(uint32_t)dp->tdir_count] = 0; + if (data != 0) + _TIFFfreeExt(tif, data); + data = o; + } + n = TIFFSetField(tif, dp->tdir_tag, data); + if (data != 0) + _TIFFfreeExt(tif, 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_SINT8: + { + int8_t data = 0; + assert(fip->field_readcount == 1); + assert(fip->field_passcount == 0); + err = TIFFReadDirEntrySbyte(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_SINT16: + { + int16_t data; + assert(fip->field_readcount == 1); + assert(fip->field_passcount == 0); + err = TIFFReadDirEntrySshort(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_SINT32: + { + int32_t data; + assert(fip->field_readcount == 1); + assert(fip->field_passcount == 0); + err = TIFFReadDirEntrySlong(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_SINT64: + { + int64_t data; + assert(fip->field_readcount == 1); + assert(fip->field_passcount == 0); + err = TIFFReadDirEntrySlong8(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) + { + TIFFWarningExtR(tif, 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]); + _TIFFfreeExt(tif, 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) + { + TIFFWarningExtR(tif, 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) + _TIFFfreeExt(tif, data); + if (!m) + return (0); + } + } + } + break; + case TIFF_SETGET_C0_SINT8: + { + int8_t *data; + assert(fip->field_readcount >= 1); + assert(fip->field_passcount == 0); + if (dp->tdir_count != (uint64_t)fip->field_readcount) + { + TIFFWarningExtR(tif, module, + "incorrect count for field \"%s\", expected " + "%d, got %" PRIu64, + fip->field_name, (int)fip->field_readcount, + dp->tdir_count); + return (0); + } + else + { + err = TIFFReadDirEntrySbyteArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, data); + if (data != 0) + _TIFFfreeExt(tif, 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) + { + TIFFWarningExtR(tif, module, + "incorrect count for field \"%s\", expected " + "%d, got %" PRIu64, + fip->field_name, (int)fip->field_readcount, + dp->tdir_count); + return (0); + } + else + { + err = TIFFReadDirEntryShortArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, data); + if (data != 0) + _TIFFfreeExt(tif, data); + if (!m) + return (0); + } + } + } + break; + case TIFF_SETGET_C0_SINT16: + { + int16_t *data; + assert(fip->field_readcount >= 1); + assert(fip->field_passcount == 0); + if (dp->tdir_count != (uint64_t)fip->field_readcount) + { + TIFFWarningExtR(tif, module, + "incorrect count for field \"%s\", expected " + "%d, got %" PRIu64, + fip->field_name, (int)fip->field_readcount, + dp->tdir_count); + return (0); + } + else + { + err = TIFFReadDirEntrySshortArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, data); + if (data != 0) + _TIFFfreeExt(tif, 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) + { + TIFFWarningExtR(tif, module, + "incorrect count for field \"%s\", expected " + "%d, got %" PRIu64, + fip->field_name, (int)fip->field_readcount, + dp->tdir_count); + return (0); + } + else + { + err = TIFFReadDirEntryLongArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, data); + if (data != 0) + _TIFFfreeExt(tif, data); + if (!m) + return (0); + } + } + } + break; + case TIFF_SETGET_C0_SINT32: + { + int32_t *data; + assert(fip->field_readcount >= 1); + assert(fip->field_passcount == 0); + if (dp->tdir_count != (uint64_t)fip->field_readcount) + { + TIFFWarningExtR(tif, module, + "incorrect count for field \"%s\", expected " + "%d, got %" PRIu64, + fip->field_name, (int)fip->field_readcount, + dp->tdir_count); + return (0); + } + else + { + err = TIFFReadDirEntrySlongArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, data); + if (data != 0) + _TIFFfreeExt(tif, data); + if (!m) + return (0); + } + } + } + break; + case TIFF_SETGET_C0_UINT64: + { + uint64_t *data; + assert(fip->field_readcount >= 1); + assert(fip->field_passcount == 0); + if (dp->tdir_count != (uint64_t)fip->field_readcount) + { + TIFFWarningExtR(tif, module, + "incorrect count for field \"%s\", expected " + "%d, got %" PRIu64, + fip->field_name, (int)fip->field_readcount, + dp->tdir_count); + return (0); + } + else + { + err = TIFFReadDirEntryLong8Array(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, data); + if (data != 0) + _TIFFfreeExt(tif, data); + if (!m) + return (0); + } + } + } + break; + case TIFF_SETGET_C0_SINT64: + { + int64_t *data; + assert(fip->field_readcount >= 1); + assert(fip->field_passcount == 0); + if (dp->tdir_count != (uint64_t)fip->field_readcount) + { + TIFFWarningExtR(tif, module, + "incorrect count for field \"%s\", expected " + "%d, got %" PRIu64, + fip->field_name, (int)fip->field_readcount, + dp->tdir_count); + return (0); + } + else + { + err = TIFFReadDirEntrySlong8Array(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, data); + if (data != 0) + _TIFFfreeExt(tif, 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) + { + TIFFWarningExtR(tif, module, + "incorrect count for field \"%s\", expected " + "%d, got %" PRIu64, + fip->field_name, (int)fip->field_readcount, + dp->tdir_count); + return (0); + } + else + { + err = TIFFReadDirEntryFloatArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, data); + if (data != 0) + _TIFFfreeExt(tif, 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) + { + TIFFWarningExtR(tif, module, + "incorrect count for field \"%s\", expected " + "%d, got %" PRIu64, + fip->field_name, (int)fip->field_readcount, + dp->tdir_count); + return (0); + } + else + { + err = TIFFReadDirEntryDoubleArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, data); + if (data != 0) + _TIFFfreeExt(tif, 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') + { + TIFFWarningExtR( + tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, data); + if (!m) + return (0); + } + } + } + break; + case TIFF_SETGET_C16_SINT8: + { + int8_t *data; + assert(fip->field_readcount == TIFF_VARIABLE); + assert(fip->field_passcount == 1); + if (dp->tdir_count > 0xFFFF) + err = TIFFReadDirEntryErrCount; + else + { + err = TIFFReadDirEntrySbyteArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, + (uint16_t)(dp->tdir_count), data); + if (data != 0) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, data); + if (!m) + return (0); + } + } + } + break; + case TIFF_SETGET_C16_SINT16: + { + int16_t *data; + assert(fip->field_readcount == TIFF_VARIABLE); + assert(fip->field_passcount == 1); + if (dp->tdir_count > 0xFFFF) + err = TIFFReadDirEntryErrCount; + else + { + err = TIFFReadDirEntrySshortArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, + (uint16_t)(dp->tdir_count), data); + if (data != 0) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, data); + if (!m) + return (0); + } + } + } + break; + case TIFF_SETGET_C16_SINT32: + { + int32_t *data; + assert(fip->field_readcount == TIFF_VARIABLE); + assert(fip->field_passcount == 1); + if (dp->tdir_count > 0xFFFF) + err = TIFFReadDirEntryErrCount; + else + { + err = TIFFReadDirEntrySlongArray(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, + (uint16_t)(dp->tdir_count), data); + if (data != 0) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, data); + if (!m) + return (0); + } + } + } + break; + case TIFF_SETGET_C16_SINT64: + { + int64_t *data; + assert(fip->field_readcount == TIFF_VARIABLE); + assert(fip->field_passcount == 1); + if (dp->tdir_count > 0xFFFF) + err = TIFFReadDirEntryErrCount; + else + { + err = TIFFReadDirEntrySlong8Array(tif, dp, &data); + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, + (uint16_t)(dp->tdir_count), data); + if (data != 0) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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') + { + TIFFWarningExtR(tif, 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) + _TIFFfreeExt(tif, data); + if (!m) + return (0); + } + } + break; + case TIFF_SETGET_C32_UINT8: + { + uint8_t *data; + uint32_t count = 0; + assert(fip->field_readcount == TIFF_VARIABLE2); + assert(fip->field_passcount == 1); + if (fip->field_tag == TIFFTAG_RICHTIFFIPTC && + dp->tdir_type == TIFF_LONG) + { + /* Adobe's software (wrongly) writes RichTIFFIPTC tag with + * data type LONG instead of UNDEFINED. Work around this + * frequently found issue */ + void *origdata; + err = TIFFReadDirEntryArray(tif, dp, &count, 4, &origdata); + if ((err != TIFFReadDirEntryErrOk) || (origdata == 0)) + { + data = NULL; + } + else + { + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabArrayOfLong((uint32_t *)origdata, count); + data = (uint8_t *)origdata; + count = (uint32_t)(count * 4); + } + } + else + { + err = TIFFReadDirEntryByteArray(tif, dp, &data); + count = (uint32_t)(dp->tdir_count); + } + if (err == TIFFReadDirEntryErrOk) + { + int m; + m = TIFFSetField(tif, dp->tdir_tag, count, data); + if (data != 0) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, 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) + { + _TIFFfreeExt(tif, data); + return (0); + } + + resizeddata = (uint64_t *)_TIFFCheckMalloc( + tif, nstrips, sizeof(uint64_t), "for strip array"); + if (resizeddata == 0) + { + _TIFFfreeExt(tif, data); + return (0); + } + if (dir->tdir_count) + _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)); + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, newcounts); + if (newoffsets != NULL) + _TIFFfreeExt(tif, 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); + + _TIFFfreeExt(tif, td->td_stripbytecount_p); + _TIFFfreeExt(tif, 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 + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, + "Cannot allocate strip offset and bytecount arrays"); + return 0; + } +#endif + offsetArray = (uint64_t *)(_TIFFreallocExt(tif, td->td_stripoffset_p, + nArraySize)); + bytecountArray = (uint64_t *)(_TIFFreallocExt( + tif, 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 */ + /* coverity[overrun-buffer-arg] */ + memset(td->td_stripoffset_p + nStripArrayAllocBefore, 0xFF, + (td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * + sizeof(uint64_t)); + /* coverity[overrun-buffer-arg] */ + memset(td->td_stripbytecount_p + nStripArrayAllocBefore, 0xFF, + (td->td_stripoffsetbyteallocsize - nStripArrayAllocBefore) * + sizeof(uint64_t)); + } + else + { + TIFFErrorExtR(tif, module, + "Cannot allocate strip offset and bytecount arrays"); + _TIFFfreeExt(tif, td->td_stripoffset_p); + td->td_stripoffset_p = NULL; + _TIFFfreeExt(tif, 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 */ + _TIFFfreeExt(tif, td->td_stripoffset_p); + _TIFFfreeExt(tif, 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; +} diff --git a/LibTiff/tif_dirwrite.c b/LibTiff/tif_dirwrite.c index 8d308c42..d8844bbd 100644 --- a/LibTiff/tif_dirwrite.c +++ b/LibTiff/tif_dirwrite.c @@ -1,26 +1,24 @@ -/* $Id: tif_dirwrite.c,v 1.37.2.7 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -30,46 +28,203 @@ * 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) +#define TIFFCvtNativeToIEEEFloat(tif, n, fp) +#define TIFFCvtNativeToIEEEDouble(tif, n, dp) #else -extern void TIFFCvtNativeToIEEEFloat(TIFF*, uint32, float*); -extern void TIFFCvtNativeToIEEEDouble(TIFF*, uint32, double*); +extern void TIFFCvtNativeToIEEEFloat(TIFF *tif, uint32_t n, float *fp); +extern void TIFFCvtNativeToIEEEDouble(TIFF *tif, uint32_t n, double *dp); #endif -static int TIFFWriteNormalTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*); -static void TIFFSetupShortLong(TIFF*, ttag_t, TIFFDirEntry*, uint32); -static void TIFFSetupShort(TIFF*, ttag_t, TIFFDirEntry*, uint16); -static int TIFFSetupShortPair(TIFF*, ttag_t, TIFFDirEntry*); -static int TIFFWritePerSampleShorts(TIFF*, ttag_t, TIFFDirEntry*); -static int TIFFWritePerSampleAnys(TIFF*, TIFFDataType, ttag_t, TIFFDirEntry*); -static int TIFFWriteShortTable(TIFF*, ttag_t, TIFFDirEntry*, uint32, uint16**); -static int TIFFWriteShortArray(TIFF*, TIFFDirEntry*, uint16*); -static int TIFFWriteLongArray(TIFF *, TIFFDirEntry*, uint32*); -static int TIFFWriteRationalArray(TIFF *, TIFFDirEntry*, float*); -static int TIFFWriteFloatArray(TIFF *, TIFFDirEntry*, float*); -static int TIFFWriteDoubleArray(TIFF *, TIFFDirEntry*, double*); -static int TIFFWriteByteArray(TIFF*, TIFFDirEntry*, char*); -static int TIFFWriteAnyArray(TIFF*, - TIFFDataType, ttag_t, TIFFDirEntry*, uint32, double*); -static int TIFFWriteTransferFunction(TIFF*, TIFFDirEntry*); -static int TIFFWriteInkNames(TIFF*, TIFFDirEntry*); -static int TIFFWriteData(TIFF*, TIFFDirEntry*, char*); -static int TIFFLinkDirectory(TIFF*); - -#define WriteRationalPair(type, tag1, v1, tag2, v2) { \ - TIFFWriteRational((tif), (type), (tag1), (dir), (v1)) \ - TIFFWriteRational((tif), (type), (tag2), (dir)+1, (v2)) \ - (dir)++; \ -} -#define TIFFWriteRational(tif, type, tag, dir, v) \ - (dir)->tdir_tag = (tag); \ - (dir)->tdir_type = (type); \ - (dir)->tdir_count = 1; \ - if (!TIFFWriteRationalArray((tif), (dir), &(v))) \ - goto bad; +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); + +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); +static int TIFFWriteDirectoryTagByteArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, uint8_t *value); +static int TIFFWriteDirectoryTagSbyteArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, int8_t *value); +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); +static int TIFFWriteDirectoryTagSshortArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, int16_t *value); +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); +static int TIFFWriteDirectoryTagSlongArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, int32_t *value); +static int TIFFWriteDirectoryTagLong8Array(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, uint64_t *value); +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); +static int TIFFWriteDirectoryTagFloatArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, float *value); +static int TIFFWriteDirectoryTagDoubleArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, double *value); +static int TIFFWriteDirectoryTagIfdArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, uint32_t *value); +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); +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); +static int TIFFWriteDirectoryTagCheckedByteArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, + uint16_t tag, uint32_t count, + uint8_t *value); +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); +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); +static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, + uint16_t tag, uint32_t count, + int32_t *value); +static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, + uint16_t tag, uint32_t count, + uint64_t *value); +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); + +static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, + uint16_t tag, uint32_t count, + float *value); +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 @@ -77,343 +232,52 @@ static int TIFFLinkDirectory(TIFF*); * handle overwriting a directory with auxiliary * storage that's been changed. */ -static int -_TIFFWriteDirectory(TIFF* tif, int done) -{ - uint16 dircount; - toff_t diroff; - ttag_t tag; - uint32 nfields; - tsize_t dirsize; - char* data; - TIFFDirEntry* dir; - TIFFDirectory* td; - unsigned long b, fields[FIELD_SETLONGS]; - int fi, nfi; - - if (tif->tif_mode == O_RDONLY) - return (1); - /* - * Clear write state so that subsequent images with - * different characteristics get the right buffers - * setup for them. - */ - if (done) - { - if (tif->tif_flags & TIFF_POSTENCODE) { - tif->tif_flags &= ~TIFF_POSTENCODE; - if (!(*tif->tif_postencode)(tif)) { - TIFFErrorExt(tif->tif_clientdata, - tif->tif_name, - "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. - */ - if (tif->tif_rawcc > 0 - && (tif->tif_flags & TIFF_BEENWRITING) != 0 - && !TIFFFlushData1(tif)) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "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_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP); - } - - td = &tif->tif_dir; - /* - * Size the directory so that we can calculate - * offsets for the data items that aren't kept - * in-place in each field. - */ - nfields = 0; - for (b = 0; b <= FIELD_LAST; b++) - if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM) - nfields += (b < FIELD_SUBFILETYPE ? 2 : 1); - nfields += td->td_customValueCount; - dirsize = nfields * sizeof (TIFFDirEntry); - data = (char*) _TIFFmalloc(dirsize); - if (data == NULL) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Cannot write directory, out of space"); - return (0); - } - /* - * Directory hasn't been placed yet, put - * it at the end of the file and link it - * into the existing directory structure. - */ - if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif)) - goto bad; - tif->tif_dataoff = (toff_t)( - tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t)); - if (tif->tif_dataoff & 1) - tif->tif_dataoff++; - (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET); - tif->tif_curdir++; - dir = (TIFFDirEntry*) data; - /* - * Setup external form of directory - * entries and write data items. - */ - _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields)); - /* - * Write out ExtraSamples tag only if - * extra samples are present in the data. - */ - if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) { - ResetFieldBit(fields, FIELD_EXTRASAMPLES); - nfields--; - dirsize -= sizeof (TIFFDirEntry); - } /*XXX*/ - for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) { - const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi]; - - /* - * For custom fields, we test to see if the custom field - * is set or not. For normal fields, we just use the - * FieldSet test. - */ - if( fip->field_bit == FIELD_CUSTOM ) - { - int ci, is_set = FALSE; - - for( ci = 0; ci < td->td_customValueCount; ci++ ) - is_set |= (td->td_customValues[ci].info == fip); - - if( !is_set ) - continue; - } - else if (!FieldSet(fields, fip->field_bit)) - continue; - - /* - * Handle other fields. - */ - switch (fip->field_bit) - { - case FIELD_STRIPOFFSETS: - /* - * We use one field bit for both strip and tile - - * offsets, and so must be careful in selecting - * the appropriate field descriptor (so that tags - * are written in sorted order). - */ - tag = isTiled(tif) ? - TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS; - if (tag != fip->field_tag) - continue; - - dir->tdir_tag = (uint16) tag; - dir->tdir_type = (uint16) TIFF_LONG; - dir->tdir_count = (uint32) td->td_nstrips; - if (!TIFFWriteLongArray(tif, dir, td->td_stripoffset)) - goto bad; - break; - case FIELD_STRIPBYTECOUNTS: - /* - * We use one field bit for both strip and tile - * byte counts, and so must be careful in selecting - * the appropriate field descriptor (so that tags - * are written in sorted order). - */ - tag = isTiled(tif) ? - TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS; - if (tag != fip->field_tag) - continue; - - dir->tdir_tag = (uint16) tag; - dir->tdir_type = (uint16) TIFF_LONG; - dir->tdir_count = (uint32) td->td_nstrips; - if (!TIFFWriteLongArray(tif, dir, td->td_stripbytecount)) - goto bad; - break; - case FIELD_ROWSPERSTRIP: - TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP, - dir, td->td_rowsperstrip); - break; - case FIELD_COLORMAP: - if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir, - 3, td->td_colormap)) - goto bad; - break; - case FIELD_IMAGEDIMENSIONS: - TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH, - dir++, td->td_imagewidth); - TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH, - dir, td->td_imagelength); - break; - case FIELD_TILEDIMENSIONS: - TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH, - dir++, td->td_tilewidth); - TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH, - dir, td->td_tilelength); - break; - case FIELD_COMPRESSION: - TIFFSetupShort(tif, TIFFTAG_COMPRESSION, - dir, td->td_compression); - break; - case FIELD_PHOTOMETRIC: - TIFFSetupShort(tif, TIFFTAG_PHOTOMETRIC, - dir, td->td_photometric); - break; - case FIELD_POSITION: - WriteRationalPair(TIFF_RATIONAL, - TIFFTAG_XPOSITION, td->td_xposition, - TIFFTAG_YPOSITION, td->td_yposition); - break; - case FIELD_RESOLUTION: - WriteRationalPair(TIFF_RATIONAL, - TIFFTAG_XRESOLUTION, td->td_xresolution, - TIFFTAG_YRESOLUTION, td->td_yresolution); - break; - case FIELD_BITSPERSAMPLE: - case FIELD_MINSAMPLEVALUE: - case FIELD_MAXSAMPLEVALUE: - case FIELD_SAMPLEFORMAT: - if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir)) - goto bad; - break; - case FIELD_SMINSAMPLEVALUE: - case FIELD_SMAXSAMPLEVALUE: - if (!TIFFWritePerSampleAnys(tif, - _TIFFSampleToTagType(tif), fip->field_tag, dir)) - goto bad; - break; - case FIELD_PAGENUMBER: - case FIELD_HALFTONEHINTS: - case FIELD_YCBCRSUBSAMPLING: - if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) - goto bad; - break; - case FIELD_INKNAMES: - if (!TIFFWriteInkNames(tif, dir)) - goto bad; - break; - case FIELD_TRANSFERFUNCTION: - if (!TIFFWriteTransferFunction(tif, dir)) - goto bad; - break; - case FIELD_SUBIFD: - /* - * XXX: Always write this field using LONG type - * for backward compatibility. - */ - dir->tdir_tag = (uint16) fip->field_tag; - dir->tdir_type = (uint16) TIFF_LONG; - dir->tdir_count = (uint32) td->td_nsubifd; - if (!TIFFWriteLongArray(tif, dir, td->td_subifd)) - goto bad; - /* - * 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. - */ - if (dir->tdir_count > 0) { - tif->tif_flags |= TIFF_INSUBIFD; - tif->tif_nsubifd = (uint16) dir->tdir_count; - if (dir->tdir_count > 1) - tif->tif_subifdoff = dir->tdir_offset; - else - tif->tif_subifdoff = (uint32)( - tif->tif_diroff - + sizeof (uint16) - + ((char*)&dir->tdir_offset-data)); - } - break; - default: - /* XXX: Should be fixed and removed. */ - if (fip->field_tag == TIFFTAG_DOTRANGE) { - if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) - goto bad; - } - else if (!TIFFWriteNormalTag(tif, dir, fip)) - goto bad; - break; - } - dir++; - - if( fip->field_bit != FIELD_CUSTOM ) - ResetFieldBit(fields, fip->field_bit); - } - - /* - * Write directory. - */ - dircount = (uint16) nfields; - diroff = (uint32) tif->tif_nextdiroff; - if (tif->tif_flags & TIFF_SWAB) { - /* - * The file's byte order is opposite to the - * native machine architecture. We overwrite - * the directory information with impunity - * because it'll be released below after we - * write it to the file. Note that all the - * other tag construction routines assume that - * we do this byte-swapping; i.e. they only - * byte-swap indirect data. - */ - for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) { - TIFFSwabArrayOfShort(&dir->tdir_tag, 2); - TIFFSwabArrayOfLong(&dir->tdir_count, 2); - } - dircount = (uint16) nfields; - TIFFSwabShort(&dircount); - TIFFSwabLong(&diroff); - } - (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET); - if (!WriteOK(tif, &dircount, sizeof (dircount))) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Error writing directory count"); - goto bad; - } - if (!WriteOK(tif, data, dirsize)) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Error writing directory contents"); - goto bad; - } - if (!WriteOK(tif, &diroff, sizeof (uint32))) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Error writing directory link"); - goto bad; - } - if (done) { - TIFFFreeDirectory(tif); - tif->tif_flags &= ~TIFF_DIRTYDIRECT; - (*tif->tif_cleanup)(tif); - - /* - * Reset directory-related state for subsequent - * directories. - */ - TIFFCreateDirectory(tif); - } - _TIFFfree(data); - return (1); -bad: - _TIFFfree(data); - return (0); +int TIFFWriteDirectory(TIFF *tif) +{ + return TIFFWriteDirectorySec(tif, TRUE, TRUE, NULL); } -#undef WriteRationalPair -int -TIFFWriteDirectory(TIFF* tif) +/* + * 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) { - return _TIFFWriteDirectory(tif, TRUE); + static const char module[] = "TIFFDeferStrileArrayWriting"; + if (tif->tif_mode == O_RDONLY) + { + TIFFErrorExtR(tif, tif->tif_name, "File opened in read-only mode"); + return 0; + } + if (tif->tif_diroff != 0) + { + TIFFErrorExtR(tif, module, "Directory has already been written"); + return 0; + } + + tif->tif_dir.td_deferstrilearraywriting = TRUE; + return 1; } /* @@ -421,994 +285,3336 @@ TIFFWriteDirectory(TIFF* tif) * 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 TIFFCheckpointDirectory(TIFF *tif) { - int rc; - /* Setup the strips arrays, if they haven't already been. */ - if (tif->tif_dir.td_stripoffset == NULL) - (void) TIFFSetupStrips(tif); - rc = _TIFFWriteDirectory(tif, FALSE); - (void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END)); - return rc; -} - -static int -_TIFFWriteCustomDirectory(TIFF* tif, toff_t *pdiroff) -{ - uint16 dircount; - uint32 nfields; - tsize_t dirsize; - char* data; - TIFFDirEntry* dir; - TIFFDirectory* td; - unsigned long b, fields[FIELD_SETLONGS]; - int fi, nfi; - - if (tif->tif_mode == O_RDONLY) - return (1); - - td = &tif->tif_dir; - /* - * Size the directory so that we can calculate - * offsets for the data items that aren't kept - * in-place in each field. - */ - nfields = 0; - for (b = 0; b <= FIELD_LAST; b++) - if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM) - nfields += (b < FIELD_SUBFILETYPE ? 2 : 1); - nfields += td->td_customValueCount; - dirsize = nfields * sizeof (TIFFDirEntry); - data = (char*) _TIFFmalloc(dirsize); - if (data == NULL) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Cannot write directory, out of space"); - return (0); - } - /* - * Put the directory at the end of the file. - */ - tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1; - tif->tif_dataoff = (toff_t)( - tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t)); - if (tif->tif_dataoff & 1) - tif->tif_dataoff++; - (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET); - dir = (TIFFDirEntry*) data; - /* - * Setup external form of directory - * entries and write data items. - */ - _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields)); - - for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) { - const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi]; - - /* - * For custom fields, we test to see if the custom field - * is set or not. For normal fields, we just use the - * FieldSet test. - */ - if( fip->field_bit == FIELD_CUSTOM ) - { - int ci, is_set = FALSE; - - for( ci = 0; ci < td->td_customValueCount; ci++ ) - is_set |= (td->td_customValues[ci].info == fip); - - if( !is_set ) - continue; - } - else if (!FieldSet(fields, fip->field_bit)) - continue; - - if( fip->field_bit != FIELD_CUSTOM ) - ResetFieldBit(fields, fip->field_bit); - } - - /* - * Write directory. - */ - dircount = (uint16) nfields; - *pdiroff = (uint32) tif->tif_nextdiroff; - if (tif->tif_flags & TIFF_SWAB) { - /* - * The file's byte order is opposite to the - * native machine architecture. We overwrite - * the directory information with impunity - * because it'll be released below after we - * write it to the file. Note that all the - * other tag construction routines assume that - * we do this byte-swapping; i.e. they only - * byte-swap indirect data. - */ - for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) { - TIFFSwabArrayOfShort(&dir->tdir_tag, 2); - TIFFSwabArrayOfLong(&dir->tdir_count, 2); - } - dircount = (uint16) nfields; - TIFFSwabShort(&dircount); - TIFFSwabLong(pdiroff); - } - (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET); - if (!WriteOK(tif, &dircount, sizeof (dircount))) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Error writing directory count"); - goto bad; - } - if (!WriteOK(tif, data, dirsize)) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Error writing directory contents"); - goto bad; - } - if (!WriteOK(tif, pdiroff, sizeof (uint32))) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Error writing directory link"); - goto bad; - } - _TIFFfree(data); - return (1); -bad: - _TIFFfree(data); - return (0); + 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, toff_t *pdiroff) +int TIFFWriteCustomDirectory(TIFF *tif, uint64_t *pdiroff) { - return _TIFFWriteCustomDirectory(tif, pdiroff); + return TIFFWriteDirectorySec(tif, FALSE, FALSE, pdiroff); } /* - * Process tags that are not special cased. + * 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. */ -static int -TIFFWriteNormalTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip) -{ - uint16 wc = (uint16) fip->field_writecount; - uint32 wc2; - - dir->tdir_tag = (uint16) fip->field_tag; - dir->tdir_type = (uint16) fip->field_type; - dir->tdir_count = wc; - - switch (fip->field_type) { - case TIFF_SHORT: - case TIFF_SSHORT: - if (fip->field_passcount) { - uint16* wp; - if (wc == (uint16) TIFF_VARIABLE2) { - TIFFGetField(tif, fip->field_tag, &wc2, &wp); - dir->tdir_count = wc2; - } else { /* Assume TIFF_VARIABLE */ - TIFFGetField(tif, fip->field_tag, &wc, &wp); - dir->tdir_count = wc; - } - if (!TIFFWriteShortArray(tif, dir, wp)) - return 0; - } else { - if (wc == 1) { - uint16 sv; - TIFFGetField(tif, fip->field_tag, &sv); - dir->tdir_offset = - TIFFInsertData(tif, dir->tdir_type, sv); - } else { - uint16* wp; - TIFFGetField(tif, fip->field_tag, &wp); - if (!TIFFWriteShortArray(tif, dir, wp)) - return 0; - } - } - break; - case TIFF_LONG: - case TIFF_SLONG: - case TIFF_IFD: - if (fip->field_passcount) { - uint32* lp; - if (wc == (uint16) TIFF_VARIABLE2) { - TIFFGetField(tif, fip->field_tag, &wc2, &lp); - dir->tdir_count = wc2; - } else { /* Assume TIFF_VARIABLE */ - TIFFGetField(tif, fip->field_tag, &wc, &lp); - dir->tdir_count = wc; - } - if (!TIFFWriteLongArray(tif, dir, lp)) - return 0; - } else { - if (wc == 1) { - /* XXX handle LONG->SHORT conversion */ - TIFFGetField(tif, fip->field_tag, - &dir->tdir_offset); - } else { - uint32* lp; - TIFFGetField(tif, fip->field_tag, &lp); - if (!TIFFWriteLongArray(tif, dir, lp)) - return 0; - } - } - break; - case TIFF_RATIONAL: - case TIFF_SRATIONAL: - if (fip->field_passcount) { - float* fp; - if (wc == (uint16) TIFF_VARIABLE2) { - TIFFGetField(tif, fip->field_tag, &wc2, &fp); - dir->tdir_count = wc2; - } else { /* Assume TIFF_VARIABLE */ - TIFFGetField(tif, fip->field_tag, &wc, &fp); - dir->tdir_count = wc; - } - if (!TIFFWriteRationalArray(tif, dir, fp)) - return 0; - } else { - if (wc == 1) { - float fv; - TIFFGetField(tif, fip->field_tag, &fv); - if (!TIFFWriteRationalArray(tif, dir, &fv)) - return 0; - } else { - float* fp; - TIFFGetField(tif, fip->field_tag, &fp); - if (!TIFFWriteRationalArray(tif, dir, fp)) - return 0; - } - } - break; - case TIFF_FLOAT: - if (fip->field_passcount) { - float* fp; - if (wc == (uint16) TIFF_VARIABLE2) { - TIFFGetField(tif, fip->field_tag, &wc2, &fp); - dir->tdir_count = wc2; - } else { /* Assume TIFF_VARIABLE */ - TIFFGetField(tif, fip->field_tag, &wc, &fp); - dir->tdir_count = wc; - } - if (!TIFFWriteFloatArray(tif, dir, fp)) - return 0; - } else { - if (wc == 1) { - float fv; - TIFFGetField(tif, fip->field_tag, &fv); - if (!TIFFWriteFloatArray(tif, dir, &fv)) - return 0; - } else { - float* fp; - TIFFGetField(tif, fip->field_tag, &fp); - if (!TIFFWriteFloatArray(tif, dir, fp)) - return 0; - } - } - break; - case TIFF_DOUBLE: - if (fip->field_passcount) { - double* dp; - if (wc == (uint16) TIFF_VARIABLE2) { - TIFFGetField(tif, fip->field_tag, &wc2, &dp); - dir->tdir_count = wc2; - } else { /* Assume TIFF_VARIABLE */ - TIFFGetField(tif, fip->field_tag, &wc, &dp); - dir->tdir_count = wc; - } - if (!TIFFWriteDoubleArray(tif, dir, dp)) - return 0; - } else { - if (wc == 1) { - double dv; - TIFFGetField(tif, fip->field_tag, &dv); - if (!TIFFWriteDoubleArray(tif, dir, &dv)) - return 0; - } else { - double* dp; - TIFFGetField(tif, fip->field_tag, &dp); - if (!TIFFWriteDoubleArray(tif, dir, dp)) - return 0; - } - } - break; - case TIFF_ASCII: - { - char* cp; - if (fip->field_passcount) +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. + */ + uint64_t torewritediroff = tif->tif_diroff; + + 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)) + { + TIFFErrorExtR(tif, tif->tif_name, "Error updating TIFF header"); + return (0); + } + } + else if (tif->tif_diroff > 0xFFFFFFFFU) + { + TIFFErrorExtR(tif, module, + "tif->tif_diroff exceeds 32 bit range allowed for " + "Classic TIFF"); + 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)) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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)) { - if( wc == (uint16) TIFF_VARIABLE2 ) - TIFFGetField(tif, fip->field_tag, &wc2, &cp); - else - TIFFGetField(tif, fip->field_tag, &wc, &cp); + TIFFErrorExtR(tif, module, + "Error writing directory link"); + return (0); } - else - TIFFGetField(tif, fip->field_tag, &cp); - - dir->tdir_count = (uint32) (strlen(cp) + 1); - if (!TIFFWriteByteArray(tif, dir, cp)) + tif->tif_diroff = 0; + /* Force a full-traversal to reach the zeroed pointer */ + tif->tif_lastdiroff = 0; + break; + } + nextdir = nextnextdir; + } + } + /* Remove skipped offset from IFD loop directory list. */ + _TIFFRemoveEntryFromDirectoryListByOffset(tif, torewritediroff); + } + 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)) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, module, + "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64 > 0xFFFF) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, module, + "Error writing directory link"); return (0); - } - break; - - case TIFF_BYTE: - case TIFF_SBYTE: - if (fip->field_passcount) { - char* cp; - if (wc == (uint16) TIFF_VARIABLE2) { - TIFFGetField(tif, fip->field_tag, &wc2, &cp); - dir->tdir_count = wc2; - } else { /* Assume TIFF_VARIABLE */ - TIFFGetField(tif, fip->field_tag, &wc, &cp); - dir->tdir_count = wc; - } - if (!TIFFWriteByteArray(tif, dir, cp)) - return 0; - } else { - if (wc == 1) { - char cv; - TIFFGetField(tif, fip->field_tag, &cv); - if (!TIFFWriteByteArray(tif, dir, &cv)) - return 0; - } else { - char* cp; - TIFFGetField(tif, fip->field_tag, &cp); - if (!TIFFWriteByteArray(tif, dir, cp)) - return 0; - } - } - break; + } + tif->tif_diroff = 0; + /* Force a full-traversal to reach the zeroed pointer */ + tif->tif_lastdiroff = 0; + break; + } + nextdir = nextnextdir; + } + } + /* Remove skipped offset from IFD loop directory list. */ + _TIFFRemoveEntryFromDirectoryListByOffset(tif, torewritediroff); + } - case TIFF_UNDEFINED: - { char* cp; - if (wc == (unsigned short) TIFF_VARIABLE) { - TIFFGetField(tif, fip->field_tag, &wc, &cp); - dir->tdir_count = wc; - } else if (wc == (unsigned short) TIFF_VARIABLE2) { - TIFFGetField(tif, fip->field_tag, &wc2, &cp); - dir->tdir_count = wc2; - } else - TIFFGetField(tif, fip->field_tag, &cp); - if (!TIFFWriteByteArray(tif, dir, cp)) - return (0); - } - break; - - case TIFF_NOTYPE: - break; - } - return (1); + /* + * Now use TIFFWriteDirectory() normally. + */ + + return TIFFWriteDirectory(tif); } -/* - * Setup a directory entry with either a SHORT - * or LONG type according to the value. - */ -static void -TIFFSetupShortLong(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint32 v) +static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, + uint64_t *pdiroff) { - dir->tdir_tag = (uint16) tag; - dir->tdir_count = 1; - if (v > 0xffffL) { - dir->tdir_type = (short) TIFF_LONG; - dir->tdir_offset = v; - } else { - dir->tdir_type = (short) TIFF_SHORT; - dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v); - } + 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)) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, module, + "Error flushing data before directory write"); + return (0); + } + } + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) + { + _TIFFfreeExt(tif, 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); + } + + if (TIFFFieldSet(tif, FIELD_COMPRESSION) && + (tif->tif_dir.td_compression == COMPRESSION_DEFLATE)) + { + TIFFWarningExtR(tif, module, + "Creating TIFF with legacy Deflate codec identifier, " + "COMPRESSION_ADOBE_DEFLATE is more widely supported"); + } + 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_NUMBEROFINKS)) + { + if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir, + TIFFTAG_NUMBEROFINKS, + tif->tif_dir.td_numberofinks)) + goto bad; + } + if (TIFFFieldSet(tif, FIELD_SUBIFD)) + { + if (!TIFFWriteDirectoryTagSubifd(tif, &ndir, dir)) + goto bad; + } + { + uint32_t n; + for (n = 0; n < tif->tif_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: + TIFFErrorExtR( + tif, 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 = TIFFFieldSetGetSize( + tif->tif_dir.td_customValues[m].info); + 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) + { + TIFFErrorExtR(tif, + "TIFFLib: _TIFFWriteDirectorySec()", + "Rational2Double: .set_field_type is " + "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 = TIFFFieldSetGetSize( + tif->tif_dir.td_customValues[m].info); + 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) + { + TIFFErrorExtR(tif, + "TIFFLib: _TIFFWriteDirectorySec()", + "Rational2Double: .set_field_type is " + "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 = _TIFFmallocExt(tif, ndir * sizeof(TIFFDirEntry)); + if (dir == NULL) + { + TIFFErrorExtR(tif, 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_dataoff < tif->tif_diroff) || + (tif->tif_dataoff < (uint64_t)dirsize)) + { + TIFFErrorExtR(tif, module, "Maximum TIFF file size exceeded"); + goto bad; + } + if (tif->tif_dataoff & 1) + tif->tif_dataoff++; + if (isimage) + { + if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER) + tif->tif_curdir = 0; + else + 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) + { + TIFFErrorExtR(tif, 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 = _TIFFmallocExt(tif, dirsize); + if (dirmem == NULL) + { + TIFFErrorExtR(tif, 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; m < ndir; m++) + { + *(uint16_t *)n = o->tdir_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; m < ndir; m++) + { + *(uint16_t *)n = o->tdir_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); + } + _TIFFfreeExt(tif, dir); + dir = NULL; + if (!SeekOK(tif, tif->tif_diroff)) + { + TIFFErrorExtR(tif, module, "IO error writing directory"); + goto bad; + } + if (!WriteOK(tif, dirmem, (tmsize_t)dirsize)) + { + TIFFErrorExtR(tif, module, "IO error writing directory"); + goto bad; + } + _TIFFfreeExt(tif, 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) + _TIFFfreeExt(tif, dir); + if (dirmem != NULL) + _TIFFfreeExt(tif, dirmem); + return (0); } -/* - * Setup a SHORT directory entry - */ -static void -TIFFSetupShort(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint16 v) +static int8_t TIFFClampDoubleToInt8(double val) { - dir->tdir_tag = (uint16) tag; - dir->tdir_count = 1; - dir->tdir_type = (short) TIFF_SHORT; - dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v); + if (val > 127) + return 127; + if (val < -128 || val != val) + return -128; + return (int8_t)val; } -#undef MakeShortDirent -#define NITEMS(x) (sizeof (x) / sizeof (x[0])) -/* - * Setup a directory entry that references a - * samples/pixel array of SHORT values and - * (potentially) write the associated indirect - * values. - */ -static int -TIFFWritePerSampleShorts(TIFF* tif, ttag_t tag, TIFFDirEntry* dir) -{ - uint16 buf[10], v; - uint16* w = buf; - uint16 i, samples = tif->tif_dir.td_samplesperpixel; - int status; - - if (samples > NITEMS(buf)) { - w = (uint16*) _TIFFmalloc(samples * sizeof (uint16)); - if (w == NULL) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "No space to write per-sample shorts"); - return (0); - } - } - TIFFGetField(tif, tag, &v); - for (i = 0; i < samples; i++) - w[i] = v; - - dir->tdir_tag = (uint16) tag; - dir->tdir_type = (uint16) TIFF_SHORT; - dir->tdir_count = samples; - status = TIFFWriteShortArray(tif, dir, w); - if (w != buf) - _TIFFfree((char*) w); - return (status); +static int16_t TIFFClampDoubleToInt16(double val) +{ + if (val > 32767) + return 32767; + if (val < -32768 || val != val) + return -32768; + return (int16_t)val; } -/* - * Setup a directory entry that references a samples/pixel array of ``type'' - * values and (potentially) write the associated indirect values. The source - * data from TIFFGetField() for the specified tag must be returned as double. - */ -static int -TIFFWritePerSampleAnys(TIFF* tif, - TIFFDataType type, ttag_t tag, TIFFDirEntry* dir) -{ - double buf[10], v; - double* w = buf; - uint16 i, samples = tif->tif_dir.td_samplesperpixel; - int status; - - if (samples > NITEMS(buf)) { - w = (double*) _TIFFmalloc(samples * sizeof (double)); - if (w == NULL) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "No space to write per-sample values"); - return (0); - } - } - TIFFGetField(tif, tag, &v); - for (i = 0; i < samples; i++) - w[i] = v; - status = TIFFWriteAnyArray(tif, type, tag, dir, samples, w); - if (w != buf) - _TIFFfree(w); - return (status); -} -#undef NITEMS +static int32_t TIFFClampDoubleToInt32(double val) +{ + if (val > 0x7FFFFFFF) + return 0x7FFFFFFF; + if (val < -0x7FFFFFFF - 1 || val != val) + return -0x7FFFFFFF - 1; + return (int32_t)val; +} -/* - * Setup a pair of shorts that are returned by - * value, rather than as a reference to an array. - */ -static int -TIFFSetupShortPair(TIFF* tif, ttag_t tag, TIFFDirEntry* dir) +static uint8_t TIFFClampDoubleToUInt8(double val) { - uint16 v[2]; + if (val < 0) + return 0; + if (val > 255 || val != val) + return 255; + return (uint8_t)val; +} - TIFFGetField(tif, tag, &v[0], &v[1]); +static uint16_t TIFFClampDoubleToUInt16(double val) +{ + if (val < 0) + return 0; + if (val > 65535 || val != val) + return 65535; + return (uint16_t)val; +} - dir->tdir_tag = (uint16) tag; - dir->tdir_type = (uint16) TIFF_SHORT; - dir->tdir_count = 2; - return (TIFFWriteShortArray(tif, dir, v)); +static uint32_t TIFFClampDoubleToUInt32(double val) +{ + if (val < 0) + return 0; + if (val > 0xFFFFFFFFU || val != val) + return 0xFFFFFFFFU; + return (uint32_t)val; } -/* - * Setup a directory entry for an NxM table of shorts, - * where M is known to be 2**bitspersample, and write - * the associated indirect data. - */ -static int -TIFFWriteShortTable(TIFF* tif, - ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16** table) +static int TIFFWriteDirectoryTagSampleformatArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, + uint16_t tag, uint32_t count, + double *value) { - uint32 i, off; + static const char module[] = "TIFFWriteDirectoryTagSampleformatArray"; + void *conv; + uint32_t i; + int ok; + conv = _TIFFmallocExt(tif, count * sizeof(double)); + if (conv == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } - dir->tdir_tag = (uint16) tag; - dir->tdir_type = (short) TIFF_SHORT; - /* XXX -- yech, fool TIFFWriteData */ - dir->tdir_count = (uint32) (1L<tif_dir.td_bitspersample); - off = tif->tif_dataoff; - for (i = 0; i < n; i++) - if (!TIFFWriteData(tif, dir, (char *)table[i])) - return (0); - dir->tdir_count *= n; - dir->tdir_offset = off; - return (1); -} + 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; + } -/* - * Write/copy data associated with an ASCII or opaque tag value. - */ -static int -TIFFWriteByteArray(TIFF* tif, TIFFDirEntry* dir, char* cp) -{ - if (dir->tdir_count <= 4) { - if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { - dir->tdir_offset = (uint32)cp[0] << 24; - if (dir->tdir_count >= 2) - dir->tdir_offset |= (uint32)cp[1] << 16; - if (dir->tdir_count >= 3) - dir->tdir_offset |= (uint32)cp[2] << 8; - if (dir->tdir_count == 4) - dir->tdir_offset |= cp[3]; - } else { - dir->tdir_offset = cp[0]; - if (dir->tdir_count >= 2) - dir->tdir_offset |= (uint32) cp[1] << 8; - if (dir->tdir_count >= 3) - dir->tdir_offset |= (uint32) cp[2] << 16; - if (dir->tdir_count == 4) - dir->tdir_offset |= (uint32) cp[3] << 24; - } - return 1; - } else - return TIFFWriteData(tif, dir, cp); + _TIFFfreeExt(tif, conv); + return (ok); } -/* - * Setup a directory entry of an array of SHORT - * or SSHORT and write the associated indirect values. - */ -static int -TIFFWriteShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v) -{ - if (dir->tdir_count <= 2) { - if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { - dir->tdir_offset = (uint32) v[0] << 16; - if (dir->tdir_count == 2) - dir->tdir_offset |= v[1] & 0xffff; - } else { - dir->tdir_offset = v[0] & 0xffff; - if (dir->tdir_count == 2) - dir->tdir_offset |= (uint32) v[1] << 16; - } - return (1); - } else - return (TIFFWriteData(tif, dir, (char*) v)); +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)); } -/* - * Setup a directory entry of an array of LONG - * or SLONG and write the associated indirect values. - */ -static int -TIFFWriteLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v) +static int TIFFWriteDirectoryTagUndefinedArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, uint8_t *value) { - if (dir->tdir_count == 1) { - dir->tdir_offset = v[0]; - return (1); - } else - return (TIFFWriteData(tif, dir, (char*) v)); + if (dir == NULL) + { + (*ndir)++; + return (1); + } + return (TIFFWriteDirectoryTagCheckedUndefinedArray(tif, ndir, dir, tag, + count, value)); } -/* - * Setup a directory entry of an array of RATIONAL - * or SRATIONAL and write the associated indirect values. - */ -static int -TIFFWriteRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v) -{ - uint32 i; - uint32* t; - int status; - - t = (uint32*) _TIFFmalloc(2 * dir->tdir_count * sizeof (uint32)); - if (t == NULL) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "No space to write RATIONAL array"); - return (0); - } - for (i = 0; i < dir->tdir_count; i++) { - float fv = v[i]; - int sign = 1; - uint32 den; - - if (fv < 0) { - if (dir->tdir_type == TIFF_RATIONAL) { - TIFFWarningExt(tif->tif_clientdata, - tif->tif_name, - "\"%s\": Information lost writing value (%g) as (unsigned) RATIONAL", - _TIFFFieldWithTag(tif,dir->tdir_tag)->field_name, - fv); - fv = 0; - } else - fv = -fv, sign = -1; - } - den = 1L; - if (fv > 0) { - while (fv < 1L<<(31-3) && den < 1L<<(31-3)) - fv *= 1<<3, den *= 1L<<3; - } - t[2*i+0] = (uint32) (sign * (fv + 0.5)); - t[2*i+1] = den; - } - status = TIFFWriteData(tif, dir, (char *)t); - _TIFFfree((char*) t); - return (status); +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)); } -static int -TIFFWriteFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v) +static int TIFFWriteDirectoryTagSbyteArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, int8_t *value) { - TIFFCvtNativeToIEEEFloat(tif, dir->tdir_count, v); - if (dir->tdir_count == 1) { - dir->tdir_offset = *(uint32*) &v[0]; - return (1); - } else - return (TIFFWriteData(tif, dir, (char*) v)); + if (dir == NULL) + { + (*ndir)++; + return (1); + } + return (TIFFWriteDirectoryTagCheckedSbyteArray(tif, ndir, dir, tag, count, + value)); } -static int -TIFFWriteDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v) +static int TIFFWriteDirectoryTagShort(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint16_t value) { - TIFFCvtNativeToIEEEDouble(tif, dir->tdir_count, v); - return (TIFFWriteData(tif, dir, (char*) v)); + if (dir == NULL) + { + (*ndir)++; + return (1); + } + return (TIFFWriteDirectoryTagCheckedShort(tif, ndir, dir, tag, value)); } -/* - * Write an array of ``type'' values for a specified tag (i.e. this is a tag - * which is allowed to have different types, e.g. SMaxSampleType). - * Internally the data values are represented as double since a double can - * hold any of the TIFF tag types (yes, this should really be an abstract - * type tany_t for portability). The data is converted into the specified - * type in a temporary buffer and then handed off to the appropriate array - * writer. - */ -static int -TIFFWriteAnyArray(TIFF* tif, - TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v) -{ - char buf[10 * sizeof(double)]; - char* w = buf; - int i, status = 0; - - if (n * TIFFDataWidth(type) > sizeof buf) { - w = (char*) _TIFFmalloc(n * TIFFDataWidth(type)); - if (w == NULL) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "No space to write array"); - return (0); - } - } - - dir->tdir_tag = (uint16) tag; - dir->tdir_type = (uint16) type; - dir->tdir_count = n; - - switch (type) { - case TIFF_BYTE: - { - uint8* bp = (uint8*) w; - for (i = 0; i < (int) n; i++) - bp[i] = (uint8) v[i]; - if (!TIFFWriteByteArray(tif, dir, (char*) bp)) - goto out; - } - break; - case TIFF_SBYTE: - { - int8* bp = (int8*) w; - for (i = 0; i < (int) n; i++) - bp[i] = (int8) v[i]; - if (!TIFFWriteByteArray(tif, dir, (char*) bp)) - goto out; - } - break; - case TIFF_SHORT: - { - uint16* bp = (uint16*) w; - for (i = 0; i < (int) n; i++) - bp[i] = (uint16) v[i]; - if (!TIFFWriteShortArray(tif, dir, (uint16*)bp)) - goto out; - } - break; - case TIFF_SSHORT: - { - int16* bp = (int16*) w; - for (i = 0; i < (int) n; i++) - bp[i] = (int16) v[i]; - if (!TIFFWriteShortArray(tif, dir, (uint16*)bp)) - goto out; - } - break; - case TIFF_LONG: - { - uint32* bp = (uint32*) w; - for (i = 0; i < (int) n; i++) - bp[i] = (uint32) v[i]; - if (!TIFFWriteLongArray(tif, dir, bp)) - goto out; - } - break; - case TIFF_SLONG: - { - int32* bp = (int32*) w; - for (i = 0; i < (int) n; i++) - bp[i] = (int32) v[i]; - if (!TIFFWriteLongArray(tif, dir, (uint32*) bp)) - goto out; - } - break; - case TIFF_FLOAT: - { - float* bp = (float*) w; - for (i = 0; i < (int) n; i++) - bp[i] = (float) v[i]; - if (!TIFFWriteFloatArray(tif, dir, bp)) - goto out; - } - break; - case TIFF_DOUBLE: - { - if( !TIFFWriteDoubleArray(tif, dir, v)) - goto out; - } - break; - default: - /* TIFF_NOTYPE */ - /* TIFF_ASCII */ - /* TIFF_UNDEFINED */ - /* TIFF_RATIONAL */ - /* TIFF_SRATIONAL */ - goto out; - } - status = 1; - out: - if (w != buf) - _TIFFfree(w); - return (status); +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 -TIFFWriteTransferFunction(TIFF* tif, TIFFDirEntry* dir) -{ - TIFFDirectory* td = &tif->tif_dir; - tsize_t n = (1L<td_bitspersample) * sizeof (uint16); - uint16** tf = td->td_transferfunction; - int ncols; - - /* - * 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. - */ - switch (td->td_samplesperpixel - td->td_extrasamples) { - default: if (_TIFFmemcmp(tf[0], tf[2], n)) { ncols = 3; break; } - case 2: if (_TIFFmemcmp(tf[0], tf[1], n)) { ncols = 3; break; } - case 1: case 0: ncols = 1; - } - return (TIFFWriteShortTable(tif, - TIFFTAG_TRANSFERFUNCTION, dir, ncols, tf)); +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 = _TIFFmallocExt(tif, tif->tif_dir.td_samplesperpixel * sizeof(uint16_t)); + if (m == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + for (na = m, nb = 0; nb < tif->tif_dir.td_samplesperpixel; na++, nb++) + *na = value; + o = TIFFWriteDirectoryTagCheckedShortArray( + tif, ndir, dir, tag, tif->tif_dir.td_samplesperpixel, m); + _TIFFfreeExt(tif, m); + return (o); } -static int -TIFFWriteInkNames(TIFF* tif, TIFFDirEntry* dir) +static int TIFFWriteDirectoryTagSshortArray(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, int16_t *value) { - TIFFDirectory* td = &tif->tif_dir; + if (dir == NULL) + { + (*ndir)++; + return (1); + } + return (TIFFWriteDirectoryTagCheckedSshortArray(tif, ndir, dir, tag, count, + value)); +} - dir->tdir_tag = TIFFTAG_INKNAMES; - dir->tdir_type = (short) TIFF_ASCII; - dir->tdir_count = td->td_inknameslen; - return (TIFFWriteByteArray(tif, dir, td->td_inknames)); +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)); } -/* - * Write a contiguous directory item. - */ -static int -TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp) -{ - tsize_t cc; - - if (tif->tif_flags & TIFF_SWAB) { - switch (dir->tdir_type) { - case TIFF_SHORT: - case TIFF_SSHORT: - TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count); - break; - case TIFF_LONG: - case TIFF_SLONG: - case TIFF_FLOAT: - TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count); - break; - case TIFF_RATIONAL: - case TIFF_SRATIONAL: - TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count); - break; - case TIFF_DOUBLE: - TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count); - break; - } - } - dir->tdir_offset = tif->tif_dataoff; - cc = dir->tdir_count * TIFFDataWidth((TIFFDataType) dir->tdir_type); - if (SeekOK(tif, dir->tdir_offset) && - WriteOK(tif, cp, cc)) { - tif->tif_dataoff += (cc + 1) & ~1; - return (1); - } - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Error writing data for field \"%s\"", - _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); - return (0); +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)); } -/* - * 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. - */ +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)); +} -int -TIFFRewriteDirectory( TIFF *tif ) +/************************************************************************/ +/* TIFFWriteDirectoryTagLong8Array() */ +/* */ +/* Write either Long8 or Long array depending on file type. */ +/************************************************************************/ +static int TIFFWriteDirectoryTagLong8Array(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, uint64_t *value) { - static const char module[] = "TIFFRewriteDirectory"; + static const char module[] = "TIFFWriteDirectoryTagLong8Array"; + 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 don't need to do anything special if it hasn't been written. */ - if( tif->tif_diroff == 0 ) - return TIFFWriteDirectory( tif ); + /* We always write Long8 for BigTIFF, no checking needed. */ + if (tif->tif_flags & TIFF_BIGTIFF) + return (TIFFWriteDirectoryTagCheckedLong8Array(tif, ndir, dir, tag, + count, value)); /* - ** Find and zero the pointer to this directory, so that TIFFLinkDirectory - ** will cause it to be added after this directories current pre-link. + ** For classic tiff we want to verify everything is in range for long + ** and convert to long format. */ - - /* Is it the first directory in the file? */ - if (tif->tif_header.tiff_diroff == tif->tif_diroff) + p = _TIFFmallocExt(tif, count * sizeof(uint32_t)); + if (p == NULL) { - tif->tif_header.tiff_diroff = 0; - tif->tif_diroff = 0; + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } - TIFFSeekFile(tif, (toff_t)(TIFF_MAGIC_SIZE+TIFF_VERSION_SIZE), - SEEK_SET); - if (!WriteOK(tif, &(tif->tif_header.tiff_diroff), - sizeof (tif->tif_diroff))) + for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++) + { + if (*ma > 0xFFFFFFFF) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Error updating TIFF header"); + TIFFErrorExtR(tif, module, + "Attempt to write unsigned long value %" PRIu64 + " larger than 0xFFFFFFFF for tag %d in Classic TIFF " + "file. TIFF file writing aborted", + *ma, tag); + _TIFFfreeExt(tif, p); return (0); } + *q = (uint32_t)(*ma); } - else + + o = TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count, p); + _TIFFfreeExt(tif, p); + + return (o); +} + +/************************************************************************/ +/* TIFFWriteDirectoryTagSlong8Array() */ +/* */ +/* Write either SLong8 or SLong array depending on file type. */ +/************************************************************************/ +static int TIFFWriteDirectoryTagSlong8Array(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir, uint16_t tag, + uint32_t count, int64_t *value) +{ + static const char module[] = "TIFFWriteDirectoryTagSlong8Array"; + int64_t *ma; + uint32_t mb; + int32_t *p; + int32_t *q; + int o; + + /* is this just a counting pass? */ + if (dir == NULL) { - toff_t nextdir, off; - - nextdir = tif->tif_header.tiff_diroff; - do { - uint16 dircount; - - if (!SeekOK(tif, nextdir) || - !ReadOK(tif, &dircount, sizeof (dircount))) { - TIFFErrorExt(tif->tif_clientdata, module, - "Error fetching directory count"); - return (0); - } - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabShort(&dircount); - (void) TIFFSeekFile(tif, - dircount * sizeof (TIFFDirEntry), SEEK_CUR); - if (!ReadOK(tif, &nextdir, sizeof (nextdir))) { - TIFFErrorExt(tif->tif_clientdata, module, - "Error fetching directory link"); - return (0); - } - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabLong(&nextdir); - } while (nextdir != tif->tif_diroff && nextdir != 0); - off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */ - (void) TIFFSeekFile(tif, off - (toff_t)sizeof(nextdir), SEEK_SET); - tif->tif_diroff = 0; - if (!WriteOK(tif, &(tif->tif_diroff), sizeof (nextdir))) { - TIFFErrorExt(tif->tif_clientdata, module, - "Error writing directory link"); - return (0); - } + (*ndir)++; + return (1); } + /* We always write SLong8 for BigTIFF, no checking needed. */ + if (tif->tif_flags & TIFF_BIGTIFF) + return (TIFFWriteDirectoryTagCheckedSlong8Array(tif, ndir, dir, tag, + count, value)); /* - ** Now use TIFFWriteDirectory() normally. + ** For classic tiff we want to verify everything is in range for signed-long + ** and convert to signed-long format. */ + p = _TIFFmallocExt(tif, count * sizeof(uint32_t)); + if (p == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } - return TIFFWriteDirectory( tif ); -} + for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++) + { + if (*ma > (2147483647)) + { + TIFFErrorExtR(tif, module, + "Attempt to write signed long value %" PRIi64 + " larger than 0x7FFFFFFF (2147483647) for tag %d in " + "Classic TIFF file. TIFF writing to file aborted", + *ma, tag); + _TIFFfreeExt(tif, p); + return (0); + } + else if (*ma < (-2147483647 - 1)) + { + TIFFErrorExtR(tif, module, + "Attempt to write signed long value %" PRIi64 + " smaller than 0x80000000 (-2147483648) for tag %d " + "in Classic TIFF file. TIFF writing to file aborted", + *ma, tag); + _TIFFfreeExt(tif, p); + return (0); + } + *q = (int32_t)(*ma); + } + + o = TIFFWriteDirectoryTagCheckedSlongArray(tif, ndir, dir, tag, count, p); + _TIFFfreeExt(tif, p); + + return (o); +} + +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)); +} + +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)); +} + +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)); +} + +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)); +} + +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_DEFLATE || + compression == COMPRESSION_LZMA || + compression == COMPRESSION_LERC || + compression == COMPRESSION_ZSTD || + compression == COMPRESSION_WEBP || compression == COMPRESSION_JXL) + { + /* 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 = _TIFFmallocExt(tif, count * sizeof(uint32_t)); + uint32_t *q; + uint64_t *ma; + uint32_t mb; + + if (p == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + + for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++) + { + if (*ma > 0xFFFFFFFF) + { + TIFFErrorExtR(tif, module, + "Attempt to write value larger than 0xFFFFFFFF " + "in LONG array."); + _TIFFfreeExt(tif, p); + return (0); + } + *q = (uint32_t)(*ma); + } + + o = TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count, + p); + _TIFFfreeExt(tif, p); + } + else + { + uint16_t *p = _TIFFmallocExt(tif, count * sizeof(uint16_t)); + uint16_t *q; + uint64_t *ma; + uint32_t mb; + + if (p == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + + for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++) + { + if (*ma > 0xFFFF) + { + /* Should not happen normally given the check we did before */ + TIFFErrorExtR(tif, module, + "Attempt to write value larger than 0xFFFF in " + "SHORT array."); + _TIFFfreeExt(tif, p); + return (0); + } + *q = (uint16_t)(*ma); + } + + o = TIFFWriteDirectoryTagCheckedShortArray(tif, ndir, dir, tag, count, + p); + _TIFFfreeExt(tif, 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 = _TIFFmallocExt(tif, count * sizeof(uint32_t)); + if (p == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + + for (q = p, ma = value, mb = 0; mb < count; ma++, mb++, q++) + { + if (*ma > 0xFFFFFFFF) + { + TIFFErrorExtR(tif, module, + "Attempt to write value larger than 0xFFFFFFFF in " + "Classic TIFF file."); + _TIFFfreeExt(tif, p); + return (0); + } + *q = (uint32_t)(*ma); + } + + o = TIFFWriteDirectoryTagCheckedIfdArray(tif, ndir, dir, tag, count, p); + _TIFFfreeExt(tif, p); + + return (o); +} + +static int TIFFWriteDirectoryTagColormap(TIFF *tif, uint32_t *ndir, + TIFFDirEntry *dir) +{ + static const char module[] = "TIFFWriteDirectoryTagColormap"; + uint32_t m; + uint16_t *n; + int o; + if (dir == NULL) + { + (*ndir)++; + return (1); + } + m = (1 << tif->tif_dir.td_bitspersample); + n = _TIFFmallocExt(tif, 3 * m * sizeof(uint16_t)); + if (n == NULL) + { + TIFFErrorExtR(tif, 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); + _TIFFfreeExt(tif, 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); + } + /* TIFFTAG_TRANSFERFUNCTION expects (1 or 3) pointer to arrays with + * (1 << BitsPerSample) * uint16_t values. + */ + m = (1 << tif->tif_dir.td_bitspersample); + /* clang-format off */ + n = (tif->tif_dir.td_samplesperpixel - tif->tif_dir.td_extrasamples) > 1 ? 3 : 1; + /* clang-format on */ + + /* Check for proper number of transferfunctions */ + for (int i = 0; i < n; i++) + { + if (tif->tif_dir.td_transferfunction[i] == NULL) + { + TIFFWarningExtR( + tif, module, + "Too few TransferFunctions provided. Tag not written to file"); + return (1); /* Not an error; only tag is not written. */ + } + } + /* + * 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) + { + if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0], + tif->tif_dir.td_transferfunction[2], + m * sizeof(uint16_t)) && + !_TIFFmemcmp(tif->tif_dir.td_transferfunction[0], + tif->tif_dir.td_transferfunction[1], + m * sizeof(uint16_t))) + n = 1; + } + o = _TIFFmallocExt(tif, n * m * sizeof(uint16_t)); + if (o == NULL) + { + TIFFErrorExtR(tif, 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); + _TIFFfreeExt(tif, 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 = _TIFFmallocExt(tif, tif->tif_dir.td_nsubifd * sizeof(uint32_t)); + if (o == NULL) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, "Illegal value for SubIFD tag"); + _TIFFfreeExt(tif, o); + return (0); + } + *pb++ = (uint32_t)(*pa++); + } + n = TIFFWriteDirectoryTagCheckedIfdArray(tif, ndir, dir, TIFFTAG_SUBIFD, + tif->tif_dir.td_nsubifd, o); + _TIFFfreeExt(tif, 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)); +} + +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)); +} + +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)); +} + +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)); +} + +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)); +} + +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)) + { + TIFFErrorExtR(tif, "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)); +} + +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)) + { + TIFFErrorExtR(tif, "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) + { + TIFFErrorExtR(tif, module, "Negative value is illegal"); + return 0; + } + else if (value != value) + { + TIFFErrorExtR(tif, module, "Not-a-number value is illegal"); + return 0; + } + /*--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]); + } + + 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 = _TIFFmallocExt(tif, count * 2 * sizeof(uint32_t)); + if (m == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++) + { + DoubleToRational(*na, &nb[0], &nb[1]); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabArrayOfLong(m, count * 2); + o = TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_RATIONAL, count, + count * 8, &m[0]); + _TIFFfreeExt(tif, 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 = _TIFFmallocExt(tif, count * 2 * sizeof(int32_t)); + if (m == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++) + { + DoubleToSrational(*na, &nb[0], &nb[1]); + } + 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]); + _TIFFfreeExt(tif, 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 = _TIFFmallocExt(tif, count * 2 * sizeof(uint32_t)); + if (m == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++) + { + DoubleToRational(*na, &nb[0], &nb[1]); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabArrayOfLong(m, count * 2); + o = TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_RATIONAL, count, + count * 8, &m[0]); + _TIFFfreeExt(tif, 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 = _TIFFmallocExt(tif, count * 2 * sizeof(int32_t)); + if (m == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + for (na = value, nb = m, nc = 0; nc < count; na++, nb += 2, nc++) + { + DoubleToSrational(*na, &nb[0], &nb[1]); + } + 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]); + _TIFFfreeExt(tif, m); + return (o); +} /*--- TIFFWriteDirectoryTagCheckedSrationalDoubleArray() -------- */ + +/** ----- 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() --------------*/ + +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)); +} + +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 ((nb < na) || (nb < datalength)) + { + TIFFErrorExtR(tif, module, "Maximum TIFF file size exceeded"); + return (0); + } + if (!SeekOK(tif, na)) + { + TIFFErrorExtR(tif, module, "IO error writing tag data"); + return (0); + } + if (datalength >= 0x80000000UL) + { + TIFFErrorExtR(tif, module, + "libtiff does not allow writing more than 2147483647 " + "bytes in a tag"); + return (0); + } + if (!WriteOK(tif, data, (tmsize_t)datalength)) + { + TIFFErrorExtR(tif, 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"; - toff_t nextdir; - toff_t diroff, off; - - tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1; - diroff = tif->tif_diroff; - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabLong(&diroff); - - /* - * Handle SubIFDs - */ - if (tif->tif_flags & TIFF_INSUBIFD) { - (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); - if (!WriteOK(tif, &diroff, sizeof (diroff))) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Error writing SubIFD directory link", - tif->tif_name); - 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 += sizeof (diroff); - else - tif->tif_flags &= ~TIFF_INSUBIFD; - return (1); - } - - if (tif->tif_header.tiff_diroff == 0) { - /* - * First directory, overwrite offset in header. - */ - tif->tif_header.tiff_diroff = tif->tif_diroff; - (void) TIFFSeekFile(tif, - (toff_t)(TIFF_MAGIC_SIZE+TIFF_VERSION_SIZE), - SEEK_SET); - if (!WriteOK(tif, &diroff, sizeof (diroff))) { - 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.tiff_diroff; - do { - uint16 dircount; - - if (!SeekOK(tif, nextdir) || - !ReadOK(tif, &dircount, sizeof (dircount))) { - TIFFErrorExt(tif->tif_clientdata, module, - "Error fetching directory count"); - return (0); - } - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabShort(&dircount); - (void) TIFFSeekFile(tif, - dircount * sizeof (TIFFDirEntry), SEEK_CUR); - if (!ReadOK(tif, &nextdir, sizeof (nextdir))) { - TIFFErrorExt(tif->tif_clientdata, module, - "Error fetching directory link"); - return (0); - } - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabLong(&nextdir); - } while (nextdir != 0); - off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */ - (void) TIFFSeekFile(tif, off - (toff_t)sizeof(nextdir), SEEK_SET); - if (!WriteOK(tif, &diroff, sizeof (diroff))) { - TIFFErrorExt(tif->tif_clientdata, module, - "Error writing directory link"); - 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: - */ +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)) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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; + tif->tif_lastdiroff = tif->tif_diroff; + (void)TIFFSeekFile(tif, 4, SEEK_SET); + if (!WriteOK(tif, &m, 4)) + { + TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header"); + return (0); + } + return (1); + } + /* + * Not the first directory, search to the last and append. + */ + if (tif->tif_lastdiroff != 0) + { + nextdir = (uint32_t)tif->tif_lastdiroff; + } + else + { + nextdir = tif->tif_header.classic.tiff_diroff; + } + + while (1) + { + uint16_t dircount; + uint32_t nextnextdir; + + if (!SeekOK(tif, nextdir) || !ReadOK(tif, &dircount, 2)) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, module, "Error writing directory link"); + return (0); + } + tif->tif_lastdiroff = tif->tif_diroff; + 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; + tif->tif_lastdiroff = tif->tif_diroff; + (void)TIFFSeekFile(tif, 8, SEEK_SET); + if (!WriteOK(tif, &m, 8)) + { + TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header"); + return (0); + } + return (1); + } + /* + * Not the first directory, search to the last and append. + */ + if (tif->tif_lastdiroff != 0) + { + nextdir = tif->tif_lastdiroff; + } + else + { + 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)) + { + TIFFErrorExtR(tif, module, "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8(&dircount64); + if (dircount64 > 0xFFFF) + { + TIFFErrorExtR( + tif, 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)) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, module, "Error writing directory link"); + return (0); + } + tif->tif_lastdiroff = tif->tif_diroff; + 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)) + { + TIFFErrorExtR( + tif, module, + "Memory mapped files not currently supported for this operation."); + return 0; + } + + if (tif->tif_diroff == 0) + { + TIFFErrorExtR( + tif, module, + "Attempt to reset field on directory not already on disk."); + return 0; + } + + /* -------------------------------------------------------------------- */ + /* Read the directory entry count. */ + /* -------------------------------------------------------------------- */ + if (!SeekOK(tif, tif->tif_diroff)) + { + TIFFErrorExtR(tif, 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))) + { + TIFFErrorExtR(tif, 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))) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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]) + { + _TIFFfreeExt(tif, buf_to_write); + TIFFErrorExtR(tif, 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]) + { + _TIFFfreeExt(tif, buf_to_write); + TIFFErrorExtR(tif, 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]) + { + _TIFFfreeExt(tif, buf_to_write); + TIFFErrorExtR(tif, module, + "Value exceeds 16bit range of output type."); + return 0; + } + } + } + else + { + TIFFErrorExtR(tif, 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)) + { + _TIFFfreeExt(tif, buf_to_write); + TIFFErrorExtR(tif, module, + "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + if (!WriteOK(tif, buf_to_write, count * TIFFDataWidth(datatype))) + { + _TIFFfreeExt(tif, buf_to_write); + TIFFErrorExtR(tif, module, "Error writing directory link"); + return (0); + } + + _TIFFfreeExt(tif, 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))) + { + _TIFFfreeExt(tif, buf_to_write); + TIFFErrorExtR(tif, module, "Error writing directory link"); + return (0); + } + } + else + { + if (count * TIFFDataWidth(datatype) == 4) + { + uint32_t value; + memcpy(&value, buf_to_write, count * TIFFDataWidth(datatype)); + entry_offset = value; + } + else + { + memcpy(&entry_offset, buf_to_write, + count * TIFFDataWidth(datatype)); + } + } + + _TIFFfreeExt(tif, 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)) + { + TIFFErrorExtR(tif, module, "%s: Seek error accessing TIFF directory", + tif->tif_name); + return 0; + } + + if (!WriteOK(tif, direntry_raw, dirsize)) + { + TIFFErrorExtR(tif, module, "%s: Can not write TIFF directory entry.", + tif->tif_name); + return 0; + } + + return 1; +} diff --git a/LibTiff/tif_dumpmode.c b/LibTiff/tif_dumpmode.c index da861503..267d5d2d 100644 --- a/LibTiff/tif_dumpmode.c +++ b/LibTiff/tif_dumpmode.c @@ -1,26 +1,24 @@ -/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_dumpmode.c,v 1.5.2.2 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,96 +29,94 @@ */ #include "tiffiop.h" +static int DumpFixupTags(TIFF *tif) +{ + (void)tif; + return (1); +} + /* * Encode a hunk of pixels. */ -static int -DumpModeEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +static int DumpModeEncode(TIFF *tif, uint8_t *pp, tmsize_t cc, uint16_t s) { - (void) s; - while (cc > 0) { - tsize_t n; + (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; - n = cc; - if (tif->tif_rawcc + n > tif->tif_rawdatasize) - n = tif->tif_rawdatasize - tif->tif_rawcc; + assert(n > 0); - 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 (-1); - } - return (1); + /* + * 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, tidata_t buf, tsize_t cc, tsample_t s) +static int DumpModeDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s) { - (void) s; -/* fprintf(stderr,"DumpModeDecode: scanline %ld, expected %ld bytes, got %ld bytes\n", */ -/* (long) tif->tif_row, (long) tif->tif_rawcc, (long) cc); */ - if (tif->tif_rawcc < cc) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "DumpModeDecode: Not enough data for scanline %d", - tif->tif_row); - 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); + static const char module[] = "DumpModeDecode"; + (void)s; + if (tif->tif_rawcc < cc) + { + TIFFErrorExtR(tif, 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 nrows) +static int DumpModeSeek(TIFF *tif, uint32_t nrows) { - tif->tif_rawcp += nrows * tif->tif_scanlinesize; - tif->tif_rawcc -= nrows * tif->tif_scanlinesize; - return (1); + 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) +int TIFFInitDumpMode(TIFF *tif, int scheme) { - (void) scheme; - 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); + (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/LibTiff/tif_error.c b/LibTiff/tif_error.c index 2377abda..ac0b9c37 100644 --- a/LibTiff/tif_error.c +++ b/LibTiff/tif_error.c @@ -1,26 +1,24 @@ -/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_error.c,v 1.4.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,50 +29,104 @@ TIFFErrorHandlerExt _TIFFerrorHandlerExt = NULL; -TIFFErrorHandler -TIFFSetErrorHandler(TIFFErrorHandler handler) +TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler handler) { - TIFFErrorHandler prev = _TIFFerrorHandler; - _TIFFerrorHandler = handler; - return (prev); + TIFFErrorHandler prev = _TIFFerrorHandler; + _TIFFerrorHandler = handler; + return (prev); } -TIFFErrorHandlerExt -TIFFSetErrorHandlerExt(TIFFErrorHandlerExt handler) +TIFFErrorHandlerExt TIFFSetErrorHandlerExt(TIFFErrorHandlerExt handler) { - TIFFErrorHandlerExt prev = _TIFFerrorHandlerExt; - _TIFFerrorHandlerExt = handler; - return (prev); + TIFFErrorHandlerExt prev = _TIFFerrorHandlerExt; + _TIFFerrorHandlerExt = handler; + return (prev); } -void -TIFFError(const char* module, const char* fmt, ...) +void TIFFError(const char *module, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - if (_TIFFerrorHandler) - (*_TIFFerrorHandler)(module, fmt, ap); - if (_TIFFerrorHandlerExt) - (*_TIFFerrorHandlerExt)(0, module, fmt, ap); - va_end(ap); + 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 -TIFFErrorExt(thandle_t fd, const char* module, const char* fmt, ...) +void TIFFErrorExt(thandle_t fd, const char *module, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - if (_TIFFerrorHandler) - (*_TIFFerrorHandler)(module, fmt, ap); - if (_TIFFerrorHandlerExt) - (*_TIFFerrorHandlerExt)(fd, module, fmt, ap); - va_end(ap); + 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: - */ +void _TIFFErrorEarly(TIFFOpenOptions *opts, thandle_t clientdata, + const char *module, const char *fmt, ...) +{ + va_list ap; + if (opts && opts->errorhandler) + { + va_start(ap, fmt); + int stop = opts->errorhandler(NULL, opts->errorhandler_user_data, + module, fmt, ap); + va_end(ap); + if (stop) + return; + } + if (_TIFFerrorHandler) + { + va_start(ap, fmt); + (*_TIFFerrorHandler)(module, fmt, ap); + va_end(ap); + } + if (_TIFFerrorHandlerExt) + { + va_start(ap, fmt); + (*_TIFFerrorHandlerExt)(clientdata, module, fmt, ap); + va_end(ap); + } +} + +void TIFFErrorExtR(TIFF *tif, const char *module, const char *fmt, ...) +{ + va_list ap; + if (tif && tif->tif_errorhandler) + { + va_start(ap, fmt); + int stop = (*tif->tif_errorhandler)( + tif, tif->tif_errorhandler_user_data, module, fmt, ap); + va_end(ap); + if (stop) + return; + } + if (_TIFFerrorHandler) + { + va_start(ap, fmt); + (*_TIFFerrorHandler)(module, fmt, ap); + va_end(ap); + } + if (_TIFFerrorHandlerExt) + { + va_start(ap, fmt); + (*_TIFFerrorHandlerExt)(tif ? tif->tif_clientdata : NULL, module, fmt, + ap); + va_end(ap); + } +} diff --git a/LibTiff/tif_extension.c b/LibTiff/tif_extension.c index b67c0f00..1a09e987 100644 --- a/LibTiff/tif_extension.c +++ b/LibTiff/tif_extension.c @@ -1,26 +1,24 @@ -/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_extension.c,v 1.4.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -28,26 +26,26 @@ * TIFF Library. * * Various routines support external extension of the tag set, and other - * application extension capabilities. + * application extension capabilities. */ #include "tiffiop.h" -int TIFFGetTagListCount( TIFF *tif ) +int TIFFGetTagListCount(TIFF *tif) { - TIFFDirectory* td = &tif->tif_dir; - + TIFFDirectory *td = &tif->tif_dir; + return td->td_customValueCount; } -ttag_t TIFFGetTagListEntry( TIFF *tif, int tag_index ) +uint32_t TIFFGetTagListEntry(TIFF *tif, int tag_index) { - TIFFDirectory* td = &tif->tif_dir; + TIFFDirectory *td = &tif->tif_dir; - if( tag_index < 0 || tag_index >= td->td_customValueCount ) - return (ttag_t) -1; + if (tag_index < 0 || tag_index >= td->td_customValueCount) + return (uint32_t)(-1); else return td->td_customValues[tag_index].info->field_tag; } @@ -57,41 +55,41 @@ ttag_t TIFFGetTagListEntry( TIFF *tif, int tag_index ) ** structure to application code without giving access to the private ** TIFF structure. */ -TIFFTagMethods *TIFFAccessTagMethods( TIFF *tif ) +TIFFTagMethods *TIFFAccessTagMethods(TIFF *tif) { return &(tif->tif_tagmethods); } -void *TIFFGetClientInfo( TIFF *tif, const char *name ) +void *TIFFGetClientInfo(TIFF *tif, const char *name) { - TIFFClientInfoLink *link = tif->tif_clientinfo; + TIFFClientInfoLink *psLink = tif->tif_clientinfo; - while( link != NULL && strcmp(link->name,name) != 0 ) - link = link->next; + while (psLink != NULL && strcmp(psLink->name, name) != 0) + psLink = psLink->next; - if( link != NULL ) - return link->data; + if (psLink != NULL) + return psLink->data; else return NULL; } -void TIFFSetClientInfo( TIFF *tif, void *data, const char *name ) +void TIFFSetClientInfo(TIFF *tif, void *data, const char *name) { - TIFFClientInfoLink *link = tif->tif_clientinfo; + TIFFClientInfoLink *psLink = tif->tif_clientinfo; /* ** Do we have an existing link with this name? If so, just ** set it. */ - while( link != NULL && strcmp(link->name,name) != 0 ) - link = link->next; + while (psLink != NULL && strcmp(psLink->name, name) != 0) + psLink = psLink->next; - if( link != NULL ) + if (psLink != NULL) { - link->data = data; + psLink->data = data; return; } @@ -99,20 +97,14 @@ void TIFFSetClientInfo( TIFF *tif, void *data, const char *name ) ** Create a new link. */ - link = (TIFFClientInfoLink *) _TIFFmalloc(sizeof(TIFFClientInfoLink)); - assert (link != NULL); - link->next = tif->tif_clientinfo; - link->name = (char *) _TIFFmalloc(strlen(name)+1); - assert (link->name != NULL); - strcpy(link->name, name); - link->data = data; + psLink = + (TIFFClientInfoLink *)_TIFFmallocExt(tif, sizeof(TIFFClientInfoLink)); + assert(psLink != NULL); + psLink->next = tif->tif_clientinfo; + psLink->name = (char *)_TIFFmallocExt(tif, (tmsize_t)(strlen(name) + 1)); + assert(psLink->name != NULL); + strcpy(psLink->name, name); + psLink->data = data; - tif->tif_clientinfo = link; + tif->tif_clientinfo = psLink; } -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ diff --git a/LibTiff/tif_fax3.c b/LibTiff/tif_fax3.c index 9eec4ab7..a3c645cb 100644 --- a/LibTiff/tif_fax3.c +++ b/LibTiff/tif_fax3.c @@ -1,26 +1,24 @@ -/* $Id: tif_fax3.c,v 1.43.2.10 2010-06-09 17:16:58 bfriesen Exp $ */ - /* * Copyright (c) 1990-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -39,7 +37,7 @@ * Copyright (C) 1990, 1995 Frank D. Cringle. */ #include "tif_fax3.h" -#define G3CODES +#define G3CODES #include "t4.h" #include @@ -47,54 +45,57 @@ * 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 */ - uint32 rowbytes; /* bytes in a decoded scanline */ - uint32 rowpixels; /* pixels in a scanline */ - - uint16 cleanfaxdata; /* CleanFaxData tag */ - uint32 badfaxrun; /* BadFaxRun tag */ - uint32 badfaxlines; /* BadFaxLines tag */ - uint32 groupoptions; /* Group 3/4 options tag */ - uint32 recvparams; /* encoded Class 2 session params */ - char* subaddress; /* subaddress string */ - uint32 recvtime; /* time spent receiving (secs) */ - char* faxdcs; /* Table 2/T.30 encoded session params */ - TIFFVGetMethod vgetparent; /* super-class method */ - TIFFVSetMethod vsetparent; /* super-class method */ - TIFFPrintMethod printdir; /* super-class method */ +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 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* runs; /* b&w runs for current/previous row */ - uint32* refruns; /* runs for reference line */ - uint32* 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; +#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 DecoderState(tif) ((Fax3CodecState *)Fax3State(tif)) +#define EncoderState(tif) ((Fax3CodecState *)Fax3State(tif)) -#define is2DEncoding(sp) \ - (sp->b.groupoptions & GROUP3OPT_2DENCODING) -#define isAligned(p,t) ((((unsigned long)(p)) & (sizeof (t)-1)) == 0) +#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. @@ -104,74 +105,81 @@ typedef struct { * 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 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* pa; /* place to stuff next run */ \ - uint32* 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* 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) +#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 -= (tidata_t) cp - tif->tif_rawcp; \ - tif->tif_rawcp = (tidata_t) cp; \ -} while (0) +#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, tsample_t s) +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); - if (sp->refruns) { /* init reference line to white */ - sp->refruns[0] = (uint32) sp->b.rowpixels; - sp->refruns[1] = 0; - } - sp->line = 0; - return (1); + 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); } /* @@ -180,277 +188,296 @@ Fax3PreDecode(TIFF* tif, tsample_t s) * overriding the definitions used by the decoder. */ -static void -Fax3Unexpected(const char* module, TIFF* tif, uint32 line, uint32 a0) +static void Fax3Unexpected(const char *module, TIFF *tif, uint32_t line, + uint32_t a0) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: Bad code word at line %u of %s %u (x %u)", - tif->tif_name, line, isTiled(tif) ? "tile" : "strip", - (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), - a0); + TIFFErrorExtR(tif, 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) +#define unexpected(table, a0) Fax3Unexpected(module, tif, sp->line, a0) -static void -Fax3Extension(const char* module, TIFF* tif, uint32 line, uint32 a0) +static void Fax3Extension(const char *module, TIFF *tif, uint32_t line, + uint32_t a0) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Uncompressed data (not supported) at line %u of %s %u (x %u)", - tif->tif_name, line, isTiled(tif) ? "tile" : "strip", - (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), - a0); + TIFFErrorExtR(tif, 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) +#define extension(a0) Fax3Extension(module, tif, sp->line, a0) -static void -Fax3BadLength(const char* module, TIFF* tif, uint32 line, uint32 a0, uint32 lastx) +static void Fax3BadLength(const char *module, TIFF *tif, uint32_t line, + uint32_t a0, uint32_t lastx) { - TIFFWarningExt(tif->tif_clientdata, module, "%s: %s at line %u of %s %u (got %u, expected %u)", - tif->tif_name, - a0 < lastx ? "Premature EOL" : "Line length mismatch", - line, isTiled(tif) ? "tile" : "strip", - (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), - a0, lastx); + TIFFWarningExtR(tif, 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) +#define badlength(a0, lastx) Fax3BadLength(module, tif, sp->line, a0, lastx) -static void -Fax3PrematureEOF(const char* module, TIFF* tif, uint32 line, uint32 a0) +static void Fax3PrematureEOF(const char *module, TIFF *tif, uint32_t line, + uint32_t a0) { - TIFFWarningExt(tif->tif_clientdata, module, "%s: Premature EOF at line %u of %s %u (x %u)", - tif->tif_name, - line, isTiled(tif) ? "tile" : "strip", - (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), - a0); + TIFFWarningExtR(tif, 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 prematureEOF(a0) Fax3PrematureEOF(module, tif, sp->line, a0) -#define Nop +#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, tidata_t buf, tsize_t occ, tsample_t s) +static int Fax3Decode1D(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s) { - DECLARE_STATE(tif, sp, "Fax3Decode1D"); - - (void) s; - CACHE_STATE(tif, sp); - thisrun = sp->curruns; - while ((long)occ > 0) { - a0 = 0; - RunLength = 0; - pa = thisrun; + DECLARE_STATE(tif, sp, "Fax3Decode1D"); + (void)s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExtR(tif, 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=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); - printf("-------------------- %d\n", tif->tif_row); - fflush(stdout); + 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); + 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; } +#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, tidata_t buf, tsize_t occ, tsample_t s) +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; - CACHE_STATE(tif, sp); - while ((long)occ > 0) { - a0 = 0; - RunLength = 0; - pa = thisrun = sp->curruns; + DECLARE_STATE_2D(tif, sp, "Fax3Decode2D"); + int is1D; /* current line is 1d/2d-encoded */ + (void)s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExtR(tif, 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=%08X, BitsAvail = %d EOLcnt = %d", - BitAcc, BitsAvail, EOLcnt); + 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); + SYNC_EOL(EOF2D); + NeedBits8(1, EOF2D); + is1D = GetBits(1); /* 1D/2D-encoding tag bit */ + ClrBits(1); #ifdef FAX3_DEBUG - printf(" %s\n-------------------- %d\n", - is1D ? "1D" : "2D", tif->tif_row); - fflush(stdout); + 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); - SETVALUE(0); /* imaginary change for reference */ - SWAP(uint32*, 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); + 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 -/* - * The ZERO & FILL macros must handle spans < 2*sizeof(long) bytes. - * For machines with 64-bit longs this is <16 bytes; otherwise - * this is <8 bytes. We optimize the code here to reflect the - * machine characteristics. - */ -#if SIZEOF_LONG == 8 -# define FILL(n, cp) \ - switch (n) { \ - case 15:(cp)[14] = 0xff; case 14:(cp)[13] = 0xff; case 13: (cp)[12] = 0xff;\ - case 12:(cp)[11] = 0xff; case 11:(cp)[10] = 0xff; case 10: (cp)[9] = 0xff;\ - case 9: (cp)[8] = 0xff; case 8: (cp)[7] = 0xff; case 7: (cp)[6] = 0xff;\ - case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; case 4: (cp)[3] = 0xff;\ - case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \ - case 1: (cp)[0] = 0xff; (cp) += (n); case 0: ; \ - } -# define ZERO(n, cp) \ - switch (n) { \ - case 15:(cp)[14] = 0; case 14:(cp)[13] = 0; case 13: (cp)[12] = 0; \ - case 12:(cp)[11] = 0; case 11:(cp)[10] = 0; case 10: (cp)[9] = 0; \ - case 9: (cp)[8] = 0; case 8: (cp)[7] = 0; case 7: (cp)[6] = 0; \ - case 6: (cp)[5] = 0; case 5: (cp)[4] = 0; case 4: (cp)[3] = 0; \ - case 3: (cp)[2] = 0; case 2: (cp)[1] = 0; \ - case 1: (cp)[0] = 0; (cp) += (n); case 0: ; \ - } -#else -# define FILL(n, cp) \ - switch (n) { \ - case 7: (cp)[6] = 0xff; case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; \ - case 4: (cp)[3] = 0xff; case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \ - case 1: (cp)[0] = 0xff; (cp) += (n); case 0: ; \ - } -# define ZERO(n, cp) \ - switch (n) { \ - case 7: (cp)[6] = 0; case 6: (cp)[5] = 0; case 5: (cp)[4] = 0; \ - case 4: (cp)[3] = 0; case 3: (cp)[2] = 0; case 2: (cp)[1] = 0; \ - case 1: (cp)[0] = 0; (cp) += (n); case 0: ; \ - } -#endif +#define FILL(n, cp) \ + for (int32_t ifill = 0; ifill < (n); ++ifill) \ + { \ + (cp)[ifill] = 0xff; \ + } \ + (cp) += (n); + +#define ZERO(n, cp) \ + for (int32_t izero = 0; izero < (n); ++izero) \ + { \ + (cp)[izero] = 0; \ + } \ + (cp) += (n); /* * Bit-fill a row according to the white/black * runs generated during G3/G4 decoding. */ -void -_TIFFFax3fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx) +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 x, bx, run; - int32 n, nw; - long* lp; - - 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) (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 */ - if ((n/sizeof (long)) > 1) { - /* - * Align to longword boundary and fill. - */ - for (; n && !isAligned(cp, long); n--) - *cp++ = 0x00; - lp = (long*) cp; - nw = (int32)(n / sizeof (long)); - n -= nw * sizeof (long); - do { - *lp++ = 0L; - } while (--nw); - cp = (unsigned char*) lp; - } - ZERO(n, cp); - 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 */ - if ((n/sizeof (long)) > 1) { - /* - * Align to longword boundary and fill. - */ - for (; n && !isAligned(cp, long); n--) - *cp++ = 0xff; - lp = (long*) cp; - nw = (int32)(n / sizeof (long)); - n -= nw * sizeof (long); - do { - *lp++ = -1L; - } while (--nw); - cp = (unsigned char*) lp; - } - FILL(n, cp); - run &= 7; - } - if (run) - cp[0] |= 0xff00 >> run; - } else - cp[0] |= _fillmasks[run]>>bx; - x += runs[1]; - } - } - assert(x == 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, nw; + int64_t *lp; + + 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 */ + if ((n / sizeof(int64_t)) > 1) + { + /* + * Align to int64_tword boundary and fill. + */ + for (; n && !isAligned(cp, int64_t); n--) + *cp++ = 0x00; + lp = (int64_t *)cp; + nw = (int32_t)(n / sizeof(int64_t)); + n -= nw * sizeof(int64_t); + do + { + *lp++ = 0L; + } while (--nw); + cp = (unsigned char *)lp; + } + ZERO(n, cp); + 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 */ + if ((n / sizeof(int64_t)) > 1) + { + /* + * Align to int64_t boundary and fill. + */ + for (; n && !isAligned(cp, int64_t); n--) + *cp++ = 0xff; + lp = (int64_t *)cp; + nw = (int32_t)(n / sizeof(int64_t)); + n -= nw * sizeof(int64_t); + do + { + *lp++ = -1L; + } while (--nw); + cp = (unsigned char *)lp; + } + FILL(n, cp); + 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); } -#undef ZERO -#undef FILL /* * Setup G3/G4-related compression/decompression state @@ -459,160 +486,188 @@ _TIFFFax3fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx) * or not decoding or encoding is being done and whether * 1D- or 2D-encoded data is involved. */ -static int -Fax3SetupState(TIFF* tif) +static int Fax3SetupState(TIFF *tif) { - TIFFDirectory* td = &tif->tif_dir; - Fax3BaseState* sp = Fax3State(tif); - int needsRefLine; - Fax3CodecState* dsp = (Fax3CodecState*) Fax3State(tif); - uint32 rowbytes, rowpixels, nruns; - - if (td->td_bitspersample != 1) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "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; - } - sp->rowbytes = (uint32) rowbytes; - sp->rowpixels = (uint32) 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*) NULL; - nruns = TIFFroundup(rowpixels,32); - if (needsRefLine) { - nruns = TIFFSafeMultiply(uint32,nruns,2); - } - if ((nruns == 0) || (TIFFSafeMultiply(uint32,nruns,2) == 0)) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Row pixels integer overflow (rowpixels %u)", - rowpixels); - return (0); - } - dsp->runs = (uint32*) _TIFFCheckMalloc(tif, - TIFFSafeMultiply(uint32,nruns,2), - sizeof (uint32), - "for Group 3/4 run arrays"); - if (dsp->runs == NULL) - return (0); - dsp->curruns = dsp->runs; - if (needsRefLine) - dsp->refruns = dsp->runs + 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, "Fax3SetupState", - "%s: No space for Group 3/4 reference line", - tif->tif_name); - return (0); - } - } else /* 1d encoding */ - EncoderState(tif)->refline = NULL; - - return (1); + 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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 + 1, 32); + if (needsRefLine) + { + dsp->nruns = TIFFSafeMultiply(uint32_t, dsp->nruns, 2); + } + if ((dsp->nruns == 0) || (TIFFSafeMultiply(uint32_t, dsp->nruns, 2) == 0)) + { + TIFFErrorExtR(tif, 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 *)_TIFFmallocExt(tif, rowbytes); + if (esp->refline == NULL) + { + TIFFErrorExtR(tif, 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) \ - (void) TIFFFlushData1(tif); \ - *(tif)->tif_rawcp++ = (tidataval_t) (sp)->data; \ - (tif)->tif_rawcc++; \ - (sp)->data = 0, (sp)->bit = 8; \ -} -#define _FlushBits(tif) { \ - if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \ - (void) TIFFFlushData1(tif); \ - *(tif)->tif_rawcp++ = (tidataval_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); \ - } \ - data |= (bits & _msbmask[length]) << (bit - length); \ - bit -= length; \ - if (bit == 0) \ - _FlushBits(tif); \ -} - +#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 void -Fax3PutBits(TIFF* tif, unsigned int bits, unsigned int length) +static int Fax3PutBits(TIFF *tif, unsigned int bits, unsigned int length) { - Fax3CodecState* sp = EncoderState(tif); - unsigned int bit = sp->bit; - int data = sp->data; + Fax3CodecState *sp = EncoderState(tif); + unsigned int bit = sp->bit; + int data = sp->data; - _PutBits(tif, bits, length); + _PutBits(tif, bits, length); - sp->data = data; - sp->bit = bit; + 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) +#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("%08X/%-2d: %s%5d\t", data, bit, DEBUG_COLOR(what), len); \ - for (t = length-1; t >= 0; t--) \ - putchar(code & (1<= 0; t--) \ + putchar(code & (1 << t) ? '1' : '0'); \ + putchar('\n'); \ + } #endif /* @@ -621,41 +676,47 @@ Fax3PutBits(TIFF* tif, unsigned int bits, unsigned int length) * appropriate table that holds the make-up and * terminating codes is supplied. */ -static void -putspan(TIFF* tif, int32 span, const tableentry* tab) +static int putspan(TIFF *tif, int32_t span, const tableentry *tab) { - Fax3CodecState* sp = EncoderState(tif); - unsigned int bit = sp->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; + Fax3CodecState *sp = EncoderState(tif); + unsigned int bit = sp->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); + 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; + _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); + DEBUG_PRINT("MakeUp", te->runlen); #endif - _PutBits(tif, code, length); - span -= te->runlen; - } - code = tab[span].code, length = tab[span].length; + _PutBits(tif, code, length); + span -= te->runlen; + } + code = tab[span].code; + length = tab[span].length; #ifdef FAX3_DEBUG - DEBUG_PRINT(" Term", tab[span].runlen); + DEBUG_PRINT(" Term", tab[span].runlen); #endif - _PutBits(tif, code, length); + _PutBits(tif, code, length); + + sp->data = data; + sp->bit = bit; - sp->data = data; - sp->bit = bit; + return 1; } /* @@ -664,250 +725,266 @@ putspan(TIFF* tif, int32 span, const tableentry* tab) * here. We also handle writing the tag bit for the next * scanline when doing 2d encoding. */ -static void -Fax3PutEOL(TIFF* tif) +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; - code = 0; - 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; + 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, tsample_t s) +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); + 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 */ + 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 */ + 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 */ }; -/* - * On certain systems it pays to inline - * the routines that find pixel spans. - */ -#ifdef VAXC -static int32 find0span(unsigned char*, int32, int32); -static int32 find1span(unsigned char*, int32, int32); -#pragma inline(find0span,find1span) -#endif - /* * 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 int32 -find0span(unsigned char* bp, int32 bs, int32 be) +static inline int32_t find0span(unsigned char *bp, int32_t bs, int32_t be) { - int32 bits = be - bs; - int32 n, span; - - bp += bs>>3; - /* - * Check partial byte on lhs. - */ - if (bits > 0 && (n = (bs & 7))) { - 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)(2 * 8 * sizeof(long))) { - long* lp; - /* - * Align to longword boundary and check longwords. - */ - while (!isAligned(bp, long)) { - if (*bp != 0x00) - return (span + zeroruns[*bp]); - span += 8, bits -= 8; - bp++; - } - lp = (long*) bp; - while ((bits >= (int32)(8 * sizeof(long))) && (0 == *lp)) { - span += 8*sizeof (long), bits -= 8*sizeof (long); - 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); + 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 int32 -find1span(unsigned char* bp, int32 bs, int32 be) +static inline int32_t find1span(unsigned char *bp, int32_t bs, int32_t be) { - int32 bits = be - bs; - int32 n, span; - - bp += bs>>3; - /* - * Check partial byte on lhs. - */ - if (bits > 0 && (n = (bs & 7))) { - 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)(2 * 8 * sizeof(long))) { - long* lp; - /* - * Align to longword boundary and check longwords. - */ - while (!isAligned(bp, long)) { - if (*bp != 0xff) - return (span + oneruns[*bp]); - span += 8, bits -= 8; - bp++; - } - lp = (long*) bp; - while ((bits >= (int32)(8 * sizeof(long))) && (~0 == *lp)) { - span += 8*sizeof (long), bits -= 8*sizeof (long); - 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); + 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); } /* @@ -916,501 +993,501 @@ find1span(unsigned char* bp, int32 bs, int32 be) * 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))) +#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) +#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 bits) +static int Fax3Encode1DRow(TIFF *tif, unsigned char *bp, uint32_t bits) { - Fax3CodecState* sp = EncoderState(tif); - int32 span; - uint32 bs = 0; - - for (;;) { - span = find0span(bp, bs, bits); /* white span */ - putspan(tif, span, TIFFFaxWhiteCodes); - bs += span; - if (bs >= bits) - break; - span = find1span(bp, bs, bits); /* black span */ - putspan(tif, span, TIFFFaxBlackCodes); - 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)) - Fax3FlushBits(tif, sp); - } - return (1); + 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 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 */ + {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 bits) +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 a0 = 0; - uint32 a1 = (PIXEL(bp, 0) != 0 ? 0 : finddiff(bp, 0, bits, 0)); - uint32 b1 = (PIXEL(rp, 0) != 0 ? 0 : finddiff(rp, 0, bits, 0)); - uint32 a2, b2; - - for (;;) { - b2 = finddiff2(rp, b1, bits, PIXEL(rp,b1)); - if (b2 >= a1) { - int32 d = b1 - a1; - if (!(-3 <= d && d <= 3)) { /* horizontal mode */ - a2 = finddiff2(bp, a1, bits, PIXEL(bp,a1)); - putcode(tif, &horizcode); - if (a0+a1 == 0 || PIXEL(bp, a0) == 0) { - putspan(tif, a1-a0, TIFFFaxWhiteCodes); - putspan(tif, a2-a1, TIFFFaxBlackCodes); - } else { - putspan(tif, a1-a0, TIFFFaxBlackCodes); - putspan(tif, a2-a1, TIFFFaxWhiteCodes); - } - a0 = a2; - } else { /* vertical mode */ - putcode(tif, &vcodes[d+3]); - a0 = a1; - } - } else { /* pass mode */ - putcode(tif, &passcode); - 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); +#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, tidata_t bp, tsize_t cc, tsample_t s) +static int Fax3Encode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - Fax3CodecState* sp = EncoderState(tif); - - (void) s; - while ((long)cc > 0) { - if ((sp->b.mode & FAXMODE_NOEOL) == 0) - Fax3PutEOL(tif); - 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 const char module[] = "Fax3Encode"; + Fax3CodecState *sp = EncoderState(tif); + (void)s; + if (cc % sp->b.rowbytes) + { + TIFFErrorExtR(tif, 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) +static int Fax3PostEncode(TIFF *tif) { - Fax3CodecState* sp = EncoderState(tif); + Fax3CodecState *sp = EncoderState(tif); - if (sp->bit != 8) - Fax3FlushBits(tif, sp); - return (1); + if (sp->bit != 8) + Fax3FlushBits(tif, sp); + return (1); } -static void -Fax3Close(TIFF* tif) +static int _Fax3Close(TIFF *tif) { - if ((Fax3State(tif)->mode & FAXMODE_NORTC) == 0) { - 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); - } + 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 -Fax3Cleanup(TIFF* tif) +static void Fax3Close(TIFF *tif) { _Fax3Close(tif); } + +static void Fax3Cleanup(TIFF *tif) { - Fax3CodecState* sp = DecoderState(tif); - - assert(sp != 0); + Fax3CodecState *sp = DecoderState(tif); - tif->tif_tagmethods.vgetfield = sp->b.vgetparent; - tif->tif_tagmethods.vsetfield = sp->b.vsetparent; - tif->tif_tagmethods.printdir = sp->b.printdir; + assert(sp != 0); - if (sp->runs) - _TIFFfree(sp->runs); - if (sp->refline) - _TIFFfree(sp->refline); + tif->tif_tagmethods.vgetfield = sp->b.vgetparent; + tif->tif_tagmethods.vsetfield = sp->b.vsetparent; + tif->tif_tagmethods.printdir = sp->b.printdir; - if (Fax3State(tif)->subaddress) - _TIFFfree(Fax3State(tif)->subaddress); - if (Fax3State(tif)->faxdcs) - _TIFFfree(Fax3State(tif)->faxdcs); + if (sp->runs) + _TIFFfreeExt(tif, sp->runs); + if (sp->refline) + _TIFFfreeExt(tif, sp->refline); - _TIFFfree(tif->tif_data); - tif->tif_data = NULL; + _TIFFfreeExt(tif, tif->tif_data); + tif->tif_data = NULL; - _TIFFSetDefaultCompressionState(tif); + _TIFFSetDefaultCompressionState(tif); } -#define FIELD_BADFAXLINES (FIELD_CODEC+0) -#define FIELD_CLEANFAXDATA (FIELD_CODEC+1) -#define FIELD_BADFAXRUN (FIELD_CODEC+2) -#define FIELD_RECVPARAMS (FIELD_CODEC+3) -#define FIELD_SUBADDRESS (FIELD_CODEC+4) -#define FIELD_RECVTIME (FIELD_CODEC+5) -#define FIELD_FAXDCS (FIELD_CODEC+6) - -#define FIELD_OPTIONS (FIELD_CODEC+7) - -static const TIFFFieldInfo faxFieldInfo[] = { - { TIFFTAG_FAXMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO, - FALSE, FALSE, "FaxMode" }, - { TIFFTAG_FAXFILLFUNC, 0, 0, TIFF_ANY, FIELD_PSEUDO, - FALSE, FALSE, "FaxFillFunc" }, - { TIFFTAG_BADFAXLINES, 1, 1, TIFF_LONG, FIELD_BADFAXLINES, - TRUE, FALSE, "BadFaxLines" }, - { TIFFTAG_BADFAXLINES, 1, 1, TIFF_SHORT, FIELD_BADFAXLINES, - TRUE, FALSE, "BadFaxLines" }, - { TIFFTAG_CLEANFAXDATA, 1, 1, TIFF_SHORT, FIELD_CLEANFAXDATA, - TRUE, FALSE, "CleanFaxData" }, - { TIFFTAG_CONSECUTIVEBADFAXLINES,1,1, TIFF_LONG, FIELD_BADFAXRUN, - TRUE, FALSE, "ConsecutiveBadFaxLines" }, - { TIFFTAG_CONSECUTIVEBADFAXLINES,1,1, TIFF_SHORT, FIELD_BADFAXRUN, - TRUE, FALSE, "ConsecutiveBadFaxLines" }, - { TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, FIELD_RECVPARAMS, - TRUE, FALSE, "FaxRecvParams" }, - { TIFFTAG_FAXSUBADDRESS, -1,-1, TIFF_ASCII, FIELD_SUBADDRESS, - TRUE, FALSE, "FaxSubAddress" }, - { TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, FIELD_RECVTIME, - TRUE, FALSE, "FaxRecvTime" }, - { TIFFTAG_FAXDCS, -1,-1, TIFF_ASCII, FIELD_FAXDCS, - TRUE, FALSE, "FaxDcs" }, -}; -static const TIFFFieldInfo fax3FieldInfo[] = { - { TIFFTAG_GROUP3OPTIONS, 1, 1, TIFF_LONG, FIELD_OPTIONS, - FALSE, FALSE, "Group3Options" }, +#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 TIFFFieldInfo fax4FieldInfo[] = { - { TIFFTAG_GROUP4OPTIONS, 1, 1, TIFF_LONG, FIELD_OPTIONS, - FALSE, FALSE, "Group4Options" }, +static const TIFFField fax4Fields[] = { + {TIFFTAG_GROUP4OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, + TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group4Options", NULL}, }; -#define N(a) (sizeof (a) / sizeof (a[0])) -static int -Fax3VSetField(TIFF* tif, ttag_t tag, va_list ap) +static int Fax3VSetField(TIFF *tif, uint32_t tag, va_list ap) { - Fax3BaseState* sp = Fax3State(tif); - const TIFFFieldInfo* fip; - - assert(sp != 0); - assert(sp->vsetparent != 0); - - switch (tag) { - case TIFFTAG_FAXMODE: - sp->mode = 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 = va_arg(ap, uint32); - break; - case TIFFTAG_GROUP4OPTIONS: - /* XXX: avoid reading options if compression mismatches. */ - if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) - sp->groupoptions = va_arg(ap, uint32); - break; - case TIFFTAG_BADFAXLINES: - sp->badfaxlines = va_arg(ap, uint32); - break; - case TIFFTAG_CLEANFAXDATA: - sp->cleanfaxdata = (uint16) va_arg(ap, int); - break; - case TIFFTAG_CONSECUTIVEBADFAXLINES: - sp->badfaxrun = va_arg(ap, uint32); - break; - case TIFFTAG_FAXRECVPARAMS: - sp->recvparams = va_arg(ap, uint32); - break; - case TIFFTAG_FAXSUBADDRESS: - _TIFFsetString(&sp->subaddress, va_arg(ap, char*)); - break; - case TIFFTAG_FAXRECVTIME: - sp->recvtime = va_arg(ap, uint32); - break; - case TIFFTAG_FAXDCS: - _TIFFsetString(&sp->faxdcs, va_arg(ap, char*)); - break; - default: - return (*sp->vsetparent)(tif, tag, ap); - } - - if ((fip = _TIFFFieldWithTag(tif, tag))) - TIFFSetFieldBit(tif, fip->field_bit); - else - return 0; - - tif->tif_flags |= TIFF_DIRTYDIRECT; - return 1; + 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, ttag_t tag, va_list ap) +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*) = sp->groupoptions; - break; - case TIFFTAG_BADFAXLINES: - *va_arg(ap, uint32*) = sp->badfaxlines; - break; - case TIFFTAG_CLEANFAXDATA: - *va_arg(ap, uint16*) = sp->cleanfaxdata; - break; - case TIFFTAG_CONSECUTIVEBADFAXLINES: - *va_arg(ap, uint32*) = sp->badfaxrun; - break; - case TIFFTAG_FAXRECVPARAMS: - *va_arg(ap, uint32*) = sp->recvparams; - break; - case TIFFTAG_FAXSUBADDRESS: - *va_arg(ap, char**) = sp->subaddress; - break; - case TIFFTAG_FAXRECVTIME: - *va_arg(ap, uint32*) = sp->recvtime; - break; - case TIFFTAG_FAXDCS: - *va_arg(ap, char**) = sp->faxdcs; - break; - default: - return (*sp->vgetparent)(tif, tag, ap); - } - return (1); + 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) +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, " (%lu = 0x%lx)\n", - (unsigned long) sp->groupoptions, - (unsigned long) 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, " (%u = 0x%x)\n", - sp->cleanfaxdata, sp->cleanfaxdata); - } - if (TIFFFieldSet(tif,FIELD_BADFAXLINES)) - fprintf(fd, " Bad Fax Lines: %lu\n", - (unsigned long) sp->badfaxlines); - if (TIFFFieldSet(tif,FIELD_BADFAXRUN)) - fprintf(fd, " Consecutive Bad Fax Lines: %lu\n", - (unsigned long) sp->badfaxrun); - if (TIFFFieldSet(tif,FIELD_RECVPARAMS)) - fprintf(fd, " Fax Receive Parameters: %08lx\n", - (unsigned long) sp->recvparams); - if (TIFFFieldSet(tif,FIELD_SUBADDRESS)) - fprintf(fd, " Fax SubAddress: %s\n", sp->subaddress); - if (TIFFFieldSet(tif,FIELD_RECVTIME)) - fprintf(fd, " Fax Receive Time: %lu secs\n", - (unsigned long) sp->recvtime); - if (TIFFFieldSet(tif,FIELD_FAXDCS)) - fprintf(fd, " Fax DCS: %s\n", sp->faxdcs); + 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 int InitCCITTFax3(TIFF *tif) { - Fax3BaseState* sp; - - /* - * Merge codec-specific tag information. - */ - if (!_TIFFMergeFieldInfo(tif, faxFieldInfo, N(faxFieldInfo))) { - 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 = (tidata_t) - _TIFFmalloc(sizeof (Fax3CodecState)); - - if (tif->tif_data == NULL) { - TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax3", - "%s: No space for state block", tif->tif_name); - return (0); - } - - 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; - sp->recvparams = 0; - sp->subaddress = NULL; - sp->faxdcs = NULL; - - 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_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); + static const char module[] = "InitCCITTFax3"; + Fax3BaseState *sp; + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, faxFields, TIFFArrayCount(faxFields))) + { + TIFFErrorExtR(tif, "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 *)_TIFFmallocExt(tif, sizeof(Fax3CodecState)); + + if (tif->tif_data == NULL) + { + TIFFErrorExtR(tif, 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) +int TIFFInitCCITTFax3(TIFF *tif, int scheme) { - (void) scheme; - if (InitCCITTFax3(tif)) { - /* - * Merge codec-specific tag information. - */ - if (!_TIFFMergeFieldInfo(tif, fax3FieldInfo, N(fax3FieldInfo))) { - 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; + (void)scheme; + if (InitCCITTFax3(tif)) + { + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, fax3Fields, TIFFArrayCount(fax3Fields))) + { + TIFFErrorExtR(tif, "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; } /* @@ -1418,114 +1495,146 @@ TIFFInitCCITTFax3(TIFF* tif, int scheme) * Compression Scheme Support. */ -#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; } +#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, tidata_t buf, tsize_t occ, tsample_t s) +static int Fax4Decode(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s) { - DECLARE_STATE_2D(tif, sp, "Fax4Decode"); - - (void) s; - CACHE_STATE(tif, sp); - while ((long)occ > 0) { - a0 = 0; - RunLength = 0; - pa = thisrun = sp->curruns; - pb = sp->refruns; - b1 = *pb++; + DECLARE_STATE_2D(tif, sp, "Fax4Decode"); + (void)s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExtR(tif, 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=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); - printf("-------------------- %d\n", tif->tif_row); - fflush(stdout); + printf("\nBitAcc=%08" PRIX32 ", BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); #endif - EXPAND2D(EOFG4); - if (EOLcnt) - goto EOFG4; - (*sp->fill)(buf, thisrun, pa, lastx); - SETVALUE(0); /* imaginary change for reference */ - SWAP(uint32*, sp->curruns, sp->refruns); - buf += sp->b.rowbytes; - occ -= sp->b.rowbytes; - sp->line++; - continue; - EOFG4: - NeedBits16( 13, BADG4 ); - BADG4: + EXPAND2D(EOFG4); + if (EOLcnt) + goto EOFG4; + if (((lastx + 7) >> 3) > (int)occ) /* check for buffer overrun */ + { + TIFFErrorExtR(tif, 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 ); - (*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); + if (GetBits(13) != 0x1001) + fputs("Bad EOFB\n", stderr); +#endif + ClrBits(13); + if (((lastx + 7) >> 3) > (int)occ) /* check for buffer overrun */ + { + TIFFErrorExtR(tif, 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 +#undef SWAP /* * Encode the requested amount of data. */ -static int -Fax4Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +static int Fax4Encode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - Fax3CodecState *sp = EncoderState(tif); - - (void) s; - while ((long)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 const char module[] = "Fax4Encode"; + Fax3CodecState *sp = EncoderState(tif); + (void)s; + if (cc % sp->b.rowbytes) + { + TIFFErrorExtR(tif, 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) +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); + 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) +int TIFFInitCCITTFax4(TIFF *tif, int scheme) { - (void) scheme; - if (InitCCITTFax3(tif)) { /* reuse G3 support */ - /* - * Merge codec-specific tag information. - */ - if (!_TIFFMergeFieldInfo(tif, fax4FieldInfo, N(fax4FieldInfo))) { - 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); + (void)scheme; + if (InitCCITTFax3(tif)) + { /* reuse G3 support */ + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, fax4Fields, TIFFArrayCount(fax4Fields))) + { + TIFFErrorExtR(tif, "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); } /* @@ -1536,91 +1645,91 @@ TIFFInitCCITTFax4(TIFF* tif, int scheme) /* * Decode the requested amount of RLE-encoded data. */ -static int -Fax3DecodeRLE(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +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; - CACHE_STATE(tif, sp); - thisrun = sp->curruns; - while ((long)occ > 0) { - a0 = 0; - RunLength = 0; - pa = thisrun; + DECLARE_STATE(tif, sp, "Fax3DecodeRLE"); + int mode = sp->b.mode; + (void)s; + if (occ % sp->b.rowbytes) + { + TIFFErrorExtR(tif, 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=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); - printf("-------------------- %d\n", tif->tif_row); - fflush(stdout); + 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)) - 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); + 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) +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); + (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) +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); + (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/LibTiff/tif_fax3.h b/LibTiff/tif_fax3.h index 40718bcf..e095009b 100644 --- a/LibTiff/tif_fax3.h +++ b/LibTiff/tif_fax3.h @@ -1,31 +1,29 @@ -/* $Id: tif_fax3.h,v 1.5.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1990-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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_ +#define _FAX3_ /* * TIFF Library. * @@ -39,11 +37,11 @@ /* * To override the default routine used to image decoded - * spans one can use the pseduo tag TIFFTAG_FAXFILLFUNC. + * 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* runs, uint32* erun, uint32 lastx) + * 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 @@ -52,44 +50,52 @@ * 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*, uint32*, uint32); +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" { +extern "C" +{ #endif -extern void _TIFFFax3fillruns(unsigned char*, uint32*, uint32*, uint32); + 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 +#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 -typedef struct { /* state table entry */ - unsigned char State; /* see above */ - unsigned char Width; /* width of code in bits */ - uint32 Param; /* unsigned 32-bit run length in bits */ +/* 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[]; +extern const TIFFFaxTabEnt TIFFFaxMainTable[]; +extern const TIFFFaxTabEnt TIFFFaxWhiteTable[]; +extern const TIFFFaxTabEnt TIFFFaxBlackTable[]; /* * The following macros define the majority of the G3/G4 decoder @@ -108,7 +114,7 @@ extern const TIFFFaxTabEnt TIFFFaxBlackTable[]; */ #ifndef EndOfData -#define EndOfData() (cp >= ep) +#define EndOfData() (cp >= ep) #endif /* * Need <=8 or <=16 bits of input data. Unlike viewfax we @@ -134,116 +140,143 @@ extern const TIFFFaxTabEnt TIFFFaxBlackTable[]; * 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) bitmap[*cp++])<>= (n); \ -} while (0) +#define GetBits(n) (BitAcc & ((1 << (n)) - 1)) +#define ClrBits(n) \ + do \ + { \ + BitsAvail -= (n); \ + BitAcc >>= (n); \ + } while (0) #ifdef FAX3_DEBUG -static const char* StateNames[] = { - "Null ", - "Pass ", - "Horiz ", - "V0 ", - "VR ", - "VL ", - "Ext ", - "TermW ", - "TermB ", - "MakeUpW", - "MakeUpB", - "MakeUp ", - "EOL ", +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 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) +#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) +#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 { \ - *pa++ = RunLength + (x); \ - a0 += (x); \ - RunLength = 0; \ -} while (0) +#define SETVALUE(x) \ + do \ + { \ + if (pa >= thisrun + sp->nruns) \ + { \ + TIFFErrorExtR(tif, 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 /* @@ -256,51 +289,62 @@ static const char* StateNames[] = { * 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) +#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) +#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. @@ -314,219 +358,291 @@ static const char* StateNames[] = { * 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) +#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) { \ - b1 += pb[0] + pb[1]; \ - pb += 2; \ - } \ -} while (0) +#define CHECK_b1 \ + do \ + { \ + if (pa != thisrun) \ + while (b1 <= a0 && b1 < lastx) \ + { \ + if (pb + 1 >= sp->refruns + sp->nruns) \ + { \ + TIFFErrorExtR( \ + tif, 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) { \ - LOOKUP8(7, TIFFFaxMainTable, eof2d); \ - switch (TabEnt->State) { \ - case S_Pass: \ - CHECK_b1; \ - 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); \ - b1 += *pb++; \ - break; \ - case S_VR: \ - CHECK_b1; \ - SETVALUE(b1 - a0 + TabEnt->Param); \ - b1 += *pb++; \ - break; \ - case S_VL: \ - CHECK_b1; \ - 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) +#define EXPAND2D(eoflab) \ + do \ + { \ + while (a0 < lastx) \ + { \ + if (pa >= thisrun + sp->nruns) \ + { \ + TIFFErrorExtR( \ + tif, 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) \ + { \ + TIFFErrorExtR(tif, 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) \ + { \ + TIFFErrorExtR(tif, 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) \ + { \ + TIFFErrorExtR(tif, 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_ */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ diff --git a/LibTiff/tif_fax3sm.c b/LibTiff/tif_fax3sm.c index 822191ec..ba2fc532 100644 --- a/LibTiff/tif_fax3sm.c +++ b/LibTiff/tif_fax3sm.c @@ -1,5 +1,6 @@ /* WARNING, this file was automatically generated by the mkg3states program */ +#include #include "tiff.h" #include "tif_fax3.h" const TIFFFaxTabEnt TIFFFaxMainTable[128] = { diff --git a/LibTiff/tif_flush.c b/LibTiff/tif_flush.c index 7ecc4d83..ff9c1e24 100644 --- a/LibTiff/tif_flush.c +++ b/LibTiff/tif_flush.c @@ -1,26 +1,24 @@ -/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_flush.c,v 1.3.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -29,18 +27,111 @@ */ #include "tiffiop.h" -int -TIFFFlush(TIFF* tif) +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) + { + TIFFErrorExtR(tif, tif->tif_name, "File opened in read-only mode"); + return 0; + } + if (tif->tif_diroff == 0) + { + TIFFErrorExtR(tif, module, "Directory has not yet been written"); + return 0; + } + if ((tif->tif_flags & TIFF_DIRTYDIRECT) != 0) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, module, + "Function not called together with " + "TIFFDeferStrileArrayWriting()"); + return 0; + } - if (tif->tif_mode != O_RDONLY) { - if (!TIFFFlushData(tif)) - return (0); - if ((tif->tif_flags & TIFF_DIRTYDIRECT) && - !TIFFWriteDirectory(tif)) - return (0); - } - return (1); + 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; } /* @@ -50,25 +141,17 @@ TIFFFlush(TIFF* tif) * 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. + * problems for other people. */ -int -TIFFFlushData(TIFF* tif) +int TIFFFlushData(TIFF *tif) { - if ((tif->tif_flags & TIFF_BEENWRITING) == 0) - return (0); - if (tif->tif_flags & TIFF_POSTENCODE) { - tif->tif_flags &= ~TIFF_POSTENCODE; - if (!(*tif->tif_postencode)(tif)) - return (0); - } - return (TIFFFlushData1(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)); } - -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ diff --git a/LibTiff/tif_getimage.c b/LibTiff/tif_getimage.c index 38455fbc..41f7dfd7 100644 --- a/LibTiff/tif_getimage.c +++ b/LibTiff/tif_getimage.c @@ -1,26 +1,24 @@ -/* $Id: tif_getimage.c,v 1.63.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1991-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -30,36 +28,50 @@ * Read and return a packed RGBA image. */ #include "tiffiop.h" +#include #include -static int gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32); -static int gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); -static int gtStripContig(TIFFRGBAImage*, uint32*, uint32, uint32); -static int gtStripSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); -static int PickContigCase(TIFFRGBAImage*); -static int PickSeparateCase(TIFFRGBAImage*); +static int gtTileContig(TIFFRGBAImage *, uint32_t *, uint32_t, uint32_t); +static int gtTileSeparate(TIFFRGBAImage *, uint32_t *, uint32_t, uint32_t); +static int gtStripContig(TIFFRGBAImage *, uint32_t *, uint32_t, uint32_t); +static int gtStripSeparate(TIFFRGBAImage *, uint32_t *, uint32_t, uint32_t); +static int PickContigCase(TIFFRGBAImage *); +static int PickSeparateCase(TIFFRGBAImage *); + +static int BuildMapUaToAa(TIFFRGBAImage *img); +static int BuildMapBitdepth16To8(TIFFRGBAImage *img); + static const char photoTag[] = "PhotometricInterpretation"; -/* +/* * Helper constants used in Orientation tag handling */ #define FLIP_VERTICALLY 0x01 #define FLIP_HORIZONTALLY 0x02 +#define EMSG_BUF_SIZE 1024 + /* * Color conversion constants. We will define display types here. */ -TIFFDisplay display_sRGB = { - { /* XYZ -> luminance matrix */ - { 3.2410F, -1.5374F, -0.4986F }, - { -0.9692F, 1.8760F, 0.0416F }, - { 0.0556F, -0.2040F, 1.0570F } - }, - 100.0F, 100.0F, 100.0F, /* Light o/p for reference white */ - 255, 255, 255, /* Pixel values for ref. white */ - 1.0F, 1.0F, 1.0F, /* Residual light o/p for black pixel */ - 2.4F, 2.4F, 2.4F, /* Gamma values for the three guns */ +static const TIFFDisplay display_sRGB = { + {/* XYZ -> luminance matrix */ + {3.2410F, -1.5374F, -0.4986F}, + {-0.9692F, 1.8760F, 0.0416F}, + {0.0556F, -0.2040F, 1.0570F}}, + 100.0F, + 100.0F, + 100.0F, /* Light o/p for reference white */ + 255, + 255, + 255, /* Pixel values for ref. white */ + 1.0F, + 1.0F, + 1.0F, /* Residual light o/p for black pixel */ + 2.4F, + 2.4F, + 2.4F, /* Gamma values for the three guns */ }; /* @@ -68,395 +80,525 @@ TIFFDisplay display_sRGB = { * be handled. If 0 is returned, emsg contains the reason * why it is being rejected. */ -int -TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) -{ - TIFFDirectory* td = &tif->tif_dir; - uint16 photometric; - int colorchannels; - - if (!tif->tif_decodestatus) { - sprintf(emsg, "Sorry, requested compression method is not configured"); - return (0); - } - switch (td->td_bitspersample) { - case 1: - case 2: - case 4: - case 8: - case 16: - break; - default: - sprintf(emsg, "Sorry, can not handle images with %d-bit samples", - td->td_bitspersample); - return (0); - } - colorchannels = td->td_samplesperpixel - td->td_extrasamples; - if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) { - switch (colorchannels) { - case 1: - photometric = PHOTOMETRIC_MINISBLACK; - break; - case 3: - photometric = PHOTOMETRIC_RGB; - break; - default: - sprintf(emsg, "Missing needed %s tag", photoTag); - return (0); - } - } - switch (photometric) { - case PHOTOMETRIC_MINISWHITE: - case PHOTOMETRIC_MINISBLACK: - case PHOTOMETRIC_PALETTE: - if (td->td_planarconfig == PLANARCONFIG_CONTIG - && td->td_samplesperpixel != 1 - && td->td_bitspersample < 8 ) { - sprintf(emsg, - "Sorry, can not handle contiguous data with %s=%d, " - "and %s=%d and Bits/Sample=%d", - photoTag, photometric, - "Samples/pixel", td->td_samplesperpixel, - td->td_bitspersample); - return (0); - } - /* - * We should likely validate that any extra samples are either - * to be ignored, or are alpha, and if alpha we should try to use - * them. But for now we won't bother with this. - */ - break; - case PHOTOMETRIC_YCBCR: - /* - * TODO: if at all meaningful and useful, make more complete - * support check here, or better still, refactor to let supporting - * code decide whether there is support and what meaningfull - * error to return - */ - break; - case PHOTOMETRIC_RGB: - if (colorchannels < 3) { - sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", - "Color channels", colorchannels); - return (0); - } - break; - case PHOTOMETRIC_SEPARATED: - { - uint16 inkset; - TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); - if (inkset != INKSET_CMYK) { - sprintf(emsg, - "Sorry, can not handle separated image with %s=%d", - "InkSet", inkset); - return 0; - } - if (td->td_samplesperpixel < 4) { - sprintf(emsg, - "Sorry, can not handle separated image with %s=%d", - "Samples/pixel", td->td_samplesperpixel); - return 0; - } - break; - } - case PHOTOMETRIC_LOGL: - if (td->td_compression != COMPRESSION_SGILOG) { - sprintf(emsg, "Sorry, LogL data must have %s=%d", - "Compression", COMPRESSION_SGILOG); - return (0); - } - break; - case PHOTOMETRIC_LOGLUV: - if (td->td_compression != COMPRESSION_SGILOG && - td->td_compression != COMPRESSION_SGILOG24) { - sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", - "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); - return (0); - } - if (td->td_planarconfig != PLANARCONFIG_CONTIG) { - sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", - "Planarconfiguration", td->td_planarconfig); - return (0); - } - break; - case PHOTOMETRIC_CIELAB: - break; - default: - sprintf(emsg, "Sorry, can not handle image with %s=%d", - photoTag, photometric); - return (0); - } - return (1); -} - -void -TIFFRGBAImageEnd(TIFFRGBAImage* img) -{ - if (img->Map) - _TIFFfree(img->Map), img->Map = NULL; - if (img->BWmap) - _TIFFfree(img->BWmap), img->BWmap = NULL; - if (img->PALmap) - _TIFFfree(img->PALmap), img->PALmap = NULL; - if (img->ycbcr) - _TIFFfree(img->ycbcr), img->ycbcr = NULL; - if (img->cielab) - _TIFFfree(img->cielab), img->cielab = NULL; - if( img->redcmap ) { - _TIFFfree( img->redcmap ); - _TIFFfree( img->greencmap ); - _TIFFfree( img->bluecmap ); - } -} - -static int -isCCITTCompression(TIFF* tif) -{ - uint16 compress; +int TIFFRGBAImageOK(TIFF *tif, char emsg[EMSG_BUF_SIZE]) +{ + TIFFDirectory *td = &tif->tif_dir; + uint16_t photometric; + int colorchannels; + + if (!tif->tif_decodestatus) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, requested compression method is not configured"); + return (0); + } + switch (td->td_bitspersample) + { + case 1: + case 2: + case 4: + case 8: + case 16: + break; + default: + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle images with %" PRIu16 + "-bit samples", + td->td_bitspersample); + return (0); + } + if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP) + { + snprintf( + emsg, EMSG_BUF_SIZE, + "Sorry, can not handle images with IEEE floating-point samples"); + return (0); + } + colorchannels = td->td_samplesperpixel - td->td_extrasamples; + if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) + { + switch (colorchannels) + { + case 1: + photometric = PHOTOMETRIC_MINISBLACK; + break; + case 3: + photometric = PHOTOMETRIC_RGB; + break; + default: + snprintf(emsg, EMSG_BUF_SIZE, "Missing needed %s tag", + photoTag); + return (0); + } + } + switch (photometric) + { + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_PALETTE: + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + td->td_samplesperpixel != 1 && td->td_bitspersample < 8) + { + snprintf( + emsg, EMSG_BUF_SIZE, + "Sorry, can not handle contiguous data with %s=%" PRIu16 + ", " + "and %s=%" PRIu16 " and Bits/Sample=%" PRIu16 "", + photoTag, photometric, "Samples/pixel", + td->td_samplesperpixel, td->td_bitspersample); + return (0); + } + /* + * We should likely validate that any extra samples are either + * to be ignored, or are alpha, and if alpha we should try to use + * them. But for now we won't bother with this. + */ + break; + case PHOTOMETRIC_YCBCR: + /* + * TODO: if at all meaningful and useful, make more complete + * support check here, or better still, refactor to let supporting + * code decide whether there is support and what meaningful + * error to return + */ + break; + case PHOTOMETRIC_RGB: + if (colorchannels < 3) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle RGB image with %s=%d", + "Color channels", colorchannels); + return (0); + } + break; + case PHOTOMETRIC_SEPARATED: + { + uint16_t inkset; + TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); + if (inkset != INKSET_CMYK) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle separated image with %s=%d", + "InkSet", inkset); + return 0; + } + if (td->td_samplesperpixel < 4) + { + snprintf( + emsg, EMSG_BUF_SIZE, + "Sorry, can not handle separated image with %s=%" PRIu16, + "Samples/pixel", td->td_samplesperpixel); + return 0; + } + break; + } + case PHOTOMETRIC_LOGL: + if (td->td_compression != COMPRESSION_SGILOG) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, LogL data must have %s=%d", "Compression", + COMPRESSION_SGILOG); + return (0); + } + break; + case PHOTOMETRIC_LOGLUV: + if (td->td_compression != COMPRESSION_SGILOG && + td->td_compression != COMPRESSION_SGILOG24) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, LogLuv data must have %s=%d or %d", + "Compression", COMPRESSION_SGILOG, + COMPRESSION_SGILOG24); + return (0); + } + if (td->td_planarconfig != PLANARCONFIG_CONTIG) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle LogLuv images with %s=%" PRIu16, + "Planarconfiguration", td->td_planarconfig); + return (0); + } + if (td->td_samplesperpixel != 3 || colorchannels != 3) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle image with %s=%" PRIu16 + ", %s=%d", + "Samples/pixel", td->td_samplesperpixel, + "colorchannels", colorchannels); + return 0; + } + break; + case PHOTOMETRIC_CIELAB: + if (td->td_samplesperpixel != 3 || colorchannels != 3 || + (td->td_bitspersample != 8 && td->td_bitspersample != 16)) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle image with %s=%" PRIu16 + ", %s=%d and %s=%" PRIu16, + "Samples/pixel", td->td_samplesperpixel, + "colorchannels", colorchannels, "Bits/sample", + td->td_bitspersample); + return 0; + } + break; + default: + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle image with %s=%" PRIu16, photoTag, + photometric); + return (0); + } + return (1); +} + +void TIFFRGBAImageEnd(TIFFRGBAImage *img) +{ + if (img->Map) + { + _TIFFfreeExt(img->tif, img->Map); + img->Map = NULL; + } + if (img->BWmap) + { + _TIFFfreeExt(img->tif, img->BWmap); + img->BWmap = NULL; + } + if (img->PALmap) + { + _TIFFfreeExt(img->tif, img->PALmap); + img->PALmap = NULL; + } + if (img->ycbcr) + { + _TIFFfreeExt(img->tif, img->ycbcr); + img->ycbcr = NULL; + } + if (img->cielab) + { + _TIFFfreeExt(img->tif, img->cielab); + img->cielab = NULL; + } + if (img->UaToAa) + { + _TIFFfreeExt(img->tif, img->UaToAa); + img->UaToAa = NULL; + } + if (img->Bitdepth16To8) + { + _TIFFfreeExt(img->tif, img->Bitdepth16To8); + img->Bitdepth16To8 = NULL; + } + + if (img->redcmap) + { + _TIFFfreeExt(img->tif, img->redcmap); + _TIFFfreeExt(img->tif, img->greencmap); + _TIFFfreeExt(img->tif, img->bluecmap); + img->redcmap = img->greencmap = img->bluecmap = NULL; + } +} + +static int isCCITTCompression(TIFF *tif) +{ + uint16_t compress; TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress); return (compress == COMPRESSION_CCITTFAX3 || - compress == COMPRESSION_CCITTFAX4 || - compress == COMPRESSION_CCITTRLE || - compress == COMPRESSION_CCITTRLEW); -} - -int -TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) -{ - uint16* sampleinfo; - uint16 extrasamples; - uint16 planarconfig; - uint16 compress; - int colorchannels; - uint16 *red_orig, *green_orig, *blue_orig; - int n_color; - - /* Initialize to normal values */ - img->row_offset = 0; - img->col_offset = 0; - img->redcmap = NULL; - img->greencmap = NULL; - img->bluecmap = NULL; - img->req_orientation = ORIENTATION_BOTLEFT; /* It is the default */ - - img->tif = tif; - img->stoponerr = stop; - TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample); - switch (img->bitspersample) { - case 1: - case 2: - case 4: - case 8: - case 16: - break; - default: - sprintf(emsg, "Sorry, can not handle images with %d-bit samples", - img->bitspersample); - return (0); - } - img->alpha = 0; - TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel); - TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, - &extrasamples, &sampleinfo); - if (extrasamples >= 1) - { - switch (sampleinfo[0]) { - case EXTRASAMPLE_UNSPECIFIED: /* Workaround for some images without */ - if (img->samplesperpixel > 3) /* correct info about alpha channel */ - img->alpha = EXTRASAMPLE_ASSOCALPHA; - break; - case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */ - case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */ - img->alpha = sampleinfo[0]; - break; - } - } + compress == COMPRESSION_CCITTFAX4 || + compress == COMPRESSION_CCITTRLE || + compress == COMPRESSION_CCITTRLEW); +} + +int TIFFRGBAImageBegin(TIFFRGBAImage *img, TIFF *tif, int stop, + char emsg[EMSG_BUF_SIZE]) +{ + uint16_t *sampleinfo; + uint16_t extrasamples; + uint16_t planarconfig; + uint16_t compress; + int colorchannels; + uint16_t *red_orig, *green_orig, *blue_orig; + int n_color; + + if (!TIFFRGBAImageOK(tif, emsg)) + return 0; + + /* Initialize to normal values */ + img->row_offset = 0; + img->col_offset = 0; + img->redcmap = NULL; + img->greencmap = NULL; + img->bluecmap = NULL; + img->Map = NULL; + img->BWmap = NULL; + img->PALmap = NULL; + img->ycbcr = NULL; + img->cielab = NULL; + img->UaToAa = NULL; + img->Bitdepth16To8 = NULL; + img->req_orientation = ORIENTATION_BOTLEFT; /* It is the default */ + + img->tif = tif; + img->stoponerr = stop; + TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample); + switch (img->bitspersample) + { + case 1: + case 2: + case 4: + case 8: + case 16: + break; + default: + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle images with %" PRIu16 + "-bit samples", + img->bitspersample); + goto fail_return; + } + img->alpha = 0; + TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel); + TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, + &sampleinfo); + if (extrasamples >= 1) + { + switch (sampleinfo[0]) + { + case EXTRASAMPLE_UNSPECIFIED: /* Workaround for some images without + */ + if (img->samplesperpixel > + 3) /* correct info about alpha channel */ + img->alpha = EXTRASAMPLE_ASSOCALPHA; + break; + case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */ + case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */ + img->alpha = sampleinfo[0]; + break; + } + } #ifdef DEFAULT_EXTRASAMPLE_AS_ALPHA - if( !TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) - img->photometric = PHOTOMETRIC_MINISWHITE; - - if( extrasamples == 0 - && img->samplesperpixel == 4 - && img->photometric == PHOTOMETRIC_RGB ) - { - img->alpha = EXTRASAMPLE_ASSOCALPHA; - extrasamples = 1; - } + if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) + img->photometric = PHOTOMETRIC_MINISWHITE; + + if (extrasamples == 0 && img->samplesperpixel == 4 && + img->photometric == PHOTOMETRIC_RGB) + { + img->alpha = EXTRASAMPLE_ASSOCALPHA; + extrasamples = 1; + } #endif - colorchannels = img->samplesperpixel - extrasamples; - TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress); - TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); - if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) { - switch (colorchannels) { - case 1: - if (isCCITTCompression(tif)) - img->photometric = PHOTOMETRIC_MINISWHITE; - else - img->photometric = PHOTOMETRIC_MINISBLACK; - break; - case 3: - img->photometric = PHOTOMETRIC_RGB; - break; - default: - sprintf(emsg, "Missing needed %s tag", photoTag); - return (0); - } - } - switch (img->photometric) { - case PHOTOMETRIC_PALETTE: - if (!TIFFGetField(tif, TIFFTAG_COLORMAP, - &red_orig, &green_orig, &blue_orig)) { - sprintf(emsg, "Missing required \"Colormap\" tag"); - return (0); - } - - /* copy the colormaps so we can modify them */ - n_color = (1L << img->bitspersample); - img->redcmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); - img->greencmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); - img->bluecmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); - if( !img->redcmap || !img->greencmap || !img->bluecmap ) { - sprintf(emsg, "Out of memory for colormap copy"); - return (0); - } - - _TIFFmemcpy( img->redcmap, red_orig, n_color * 2 ); - _TIFFmemcpy( img->greencmap, green_orig, n_color * 2 ); - _TIFFmemcpy( img->bluecmap, blue_orig, n_color * 2 ); - - /* fall thru... */ - case PHOTOMETRIC_MINISWHITE: - case PHOTOMETRIC_MINISBLACK: - if (planarconfig == PLANARCONFIG_CONTIG - && img->samplesperpixel != 1 - && img->bitspersample < 8 ) { - sprintf(emsg, - "Sorry, can not handle contiguous data with %s=%d, " - "and %s=%d and Bits/Sample=%d", - photoTag, img->photometric, - "Samples/pixel", img->samplesperpixel, - img->bitspersample); - return (0); - } - break; - case PHOTOMETRIC_YCBCR: - /* It would probably be nice to have a reality check here. */ - if (planarconfig == PLANARCONFIG_CONTIG) - /* can rely on libjpeg to convert to RGB */ - /* XXX should restore current state on exit */ - switch (compress) { - case COMPRESSION_JPEG: - /* - * TODO: when complete tests verify complete desubsampling - * and YCbCr handling, remove use of TIFFTAG_JPEGCOLORMODE in - * favor of tif_getimage.c native handling - */ - TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); - img->photometric = PHOTOMETRIC_RGB; - break; - default: - /* do nothing */; - break; - } - /* - * TODO: if at all meaningful and useful, make more complete - * support check here, or better still, refactor to let supporting - * code decide whether there is support and what meaningfull - * error to return - */ - break; - case PHOTOMETRIC_RGB: - if (colorchannels < 3) { - sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", - "Color channels", colorchannels); - return (0); - } - break; - case PHOTOMETRIC_SEPARATED: - { - uint16 inkset; - TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); - if (inkset != INKSET_CMYK) { - sprintf(emsg, "Sorry, can not handle separated image with %s=%d", - "InkSet", inkset); - return (0); - } - if (img->samplesperpixel < 4) { - sprintf(emsg, "Sorry, can not handle separated image with %s=%d", - "Samples/pixel", img->samplesperpixel); - return (0); - } - } - break; - case PHOTOMETRIC_LOGL: - if (compress != COMPRESSION_SGILOG) { - sprintf(emsg, "Sorry, LogL data must have %s=%d", - "Compression", COMPRESSION_SGILOG); - return (0); - } - TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); - img->photometric = PHOTOMETRIC_MINISBLACK; /* little white lie */ - img->bitspersample = 8; - break; - case PHOTOMETRIC_LOGLUV: - if (compress != COMPRESSION_SGILOG && compress != COMPRESSION_SGILOG24) { - sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", - "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); - return (0); - } - if (planarconfig != PLANARCONFIG_CONTIG) { - sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", - "Planarconfiguration", planarconfig); - return (0); - } - TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); - img->photometric = PHOTOMETRIC_RGB; /* little white lie */ - img->bitspersample = 8; - break; - case PHOTOMETRIC_CIELAB: - break; - default: - sprintf(emsg, "Sorry, can not handle image with %s=%d", - photoTag, img->photometric); - return (0); - } - img->Map = NULL; - img->BWmap = NULL; - img->PALmap = NULL; - img->ycbcr = NULL; - img->cielab = NULL; - TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width); - TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height); - TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation); - img->isContig = - !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1); - if (img->isContig) { - if (!PickContigCase(img)) { - sprintf(emsg, "Sorry, can not handle image"); - return 0; - } - } else { - if (!PickSeparateCase(img)) { - sprintf(emsg, "Sorry, can not handle image"); - return 0; - } - } - return 1; -} - -int -TIFFRGBAImageGet(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) -{ - if (img->get == NULL) { - TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No \"get\" routine setup"); - return (0); - } - if (img->put.any == NULL) { - TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), - "No \"put\" routine setupl; probably can not handle image format"); - return (0); + colorchannels = img->samplesperpixel - extrasamples; + TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress); + TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); + if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) + { + switch (colorchannels) + { + case 1: + if (isCCITTCompression(tif)) + img->photometric = PHOTOMETRIC_MINISWHITE; + else + img->photometric = PHOTOMETRIC_MINISBLACK; + break; + case 3: + img->photometric = PHOTOMETRIC_RGB; + break; + default: + snprintf(emsg, EMSG_BUF_SIZE, "Missing needed %s tag", + photoTag); + goto fail_return; + } + } + switch (img->photometric) + { + case PHOTOMETRIC_PALETTE: + if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &red_orig, &green_orig, + &blue_orig)) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Missing required \"Colormap\" tag"); + goto fail_return; + } + + /* copy the colormaps so we can modify them */ + n_color = (1U << img->bitspersample); + img->redcmap = + (uint16_t *)_TIFFmallocExt(tif, sizeof(uint16_t) * n_color); + img->greencmap = + (uint16_t *)_TIFFmallocExt(tif, sizeof(uint16_t) * n_color); + img->bluecmap = + (uint16_t *)_TIFFmallocExt(tif, sizeof(uint16_t) * n_color); + if (!img->redcmap || !img->greencmap || !img->bluecmap) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Out of memory for colormap copy"); + goto fail_return; + } + + _TIFFmemcpy(img->redcmap, red_orig, n_color * 2); + _TIFFmemcpy(img->greencmap, green_orig, n_color * 2); + _TIFFmemcpy(img->bluecmap, blue_orig, n_color * 2); + + /* fall through... */ + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + if (planarconfig == PLANARCONFIG_CONTIG && + img->samplesperpixel != 1 && img->bitspersample < 8) + { + snprintf( + emsg, EMSG_BUF_SIZE, + "Sorry, can not handle contiguous data with %s=%" PRIu16 + ", " + "and %s=%" PRIu16 " and Bits/Sample=%" PRIu16, + photoTag, img->photometric, "Samples/pixel", + img->samplesperpixel, img->bitspersample); + goto fail_return; + } + break; + case PHOTOMETRIC_YCBCR: + /* It would probably be nice to have a reality check here. */ + if (planarconfig == PLANARCONFIG_CONTIG) + /* can rely on libjpeg to convert to RGB */ + /* XXX should restore current state on exit */ + switch (compress) + { + case COMPRESSION_JPEG: + /* + * TODO: when complete tests verify complete + * desubsampling and YCbCr handling, remove use of + * TIFFTAG_JPEGCOLORMODE in favor of tif_getimage.c + * native handling + */ + TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, + JPEGCOLORMODE_RGB); + img->photometric = PHOTOMETRIC_RGB; + break; + default: + /* do nothing */; + break; + } + /* + * TODO: if at all meaningful and useful, make more complete + * support check here, or better still, refactor to let supporting + * code decide whether there is support and what meaningful + * error to return + */ + break; + case PHOTOMETRIC_RGB: + if (colorchannels < 3) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle RGB image with %s=%d", + "Color channels", colorchannels); + goto fail_return; + } + break; + case PHOTOMETRIC_SEPARATED: + { + uint16_t inkset; + TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); + if (inkset != INKSET_CMYK) + { + snprintf( + emsg, EMSG_BUF_SIZE, + "Sorry, can not handle separated image with %s=%" PRIu16, + "InkSet", inkset); + goto fail_return; + } + if (img->samplesperpixel < 4) + { + snprintf( + emsg, EMSG_BUF_SIZE, + "Sorry, can not handle separated image with %s=%" PRIu16, + "Samples/pixel", img->samplesperpixel); + goto fail_return; + } + } + break; + case PHOTOMETRIC_LOGL: + if (compress != COMPRESSION_SGILOG) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, LogL data must have %s=%d", "Compression", + COMPRESSION_SGILOG); + goto fail_return; + } + TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); + img->photometric = PHOTOMETRIC_MINISBLACK; /* little white lie */ + img->bitspersample = 8; + break; + case PHOTOMETRIC_LOGLUV: + if (compress != COMPRESSION_SGILOG && + compress != COMPRESSION_SGILOG24) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, LogLuv data must have %s=%d or %d", + "Compression", COMPRESSION_SGILOG, + COMPRESSION_SGILOG24); + goto fail_return; + } + if (planarconfig != PLANARCONFIG_CONTIG) + { + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle LogLuv images with %s=%" PRIu16, + "Planarconfiguration", planarconfig); + return (0); + } + TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); + img->photometric = PHOTOMETRIC_RGB; /* little white lie */ + img->bitspersample = 8; + break; + case PHOTOMETRIC_CIELAB: + break; + default: + snprintf(emsg, EMSG_BUF_SIZE, + "Sorry, can not handle image with %s=%" PRIu16, photoTag, + img->photometric); + goto fail_return; + } + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height); + TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation); + img->isContig = + !(planarconfig == PLANARCONFIG_SEPARATE && img->samplesperpixel > 1); + if (img->isContig) + { + if (!PickContigCase(img)) + { + snprintf(emsg, EMSG_BUF_SIZE, "Sorry, can not handle image"); + goto fail_return; + } + } + else + { + if (!PickSeparateCase(img)) + { + snprintf(emsg, EMSG_BUF_SIZE, "Sorry, can not handle image"); + goto fail_return; + } + } + return 1; + +fail_return: + TIFFRGBAImageEnd(img); + return 0; +} + +int TIFFRGBAImageGet(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, + uint32_t h) +{ + if (img->get == NULL) + { + TIFFErrorExtR(img->tif, TIFFFileName(img->tif), + "No \"get\" routine setup"); + return (0); + } + if (img->put.any == NULL) + { + TIFFErrorExtR( + img->tif, TIFFFileName(img->tif), + "No \"put\" routine setupl; probably can not handle image format"); + return (0); } return (*img->get)(img, raster, w, h); } @@ -465,24 +607,25 @@ TIFFRGBAImageGet(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) * Read the specified image into an ABGR-format rastertaking in account * specified orientation. */ -int -TIFFReadRGBAImageOriented(TIFF* tif, - uint32 rwidth, uint32 rheight, uint32* raster, - int orientation, int stop) +int TIFFReadRGBAImageOriented(TIFF *tif, uint32_t rwidth, uint32_t rheight, + uint32_t *raster, int orientation, int stop) { - char emsg[1024] = ""; + char emsg[EMSG_BUF_SIZE] = ""; TIFFRGBAImage img; int ok; - if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, stop, emsg)) { - img.req_orientation = orientation; - /* XXX verify rwidth and rheight against width and height */ - ok = TIFFRGBAImageGet(&img, raster+(rheight-img.height)*rwidth, - rwidth, img.height); - TIFFRGBAImageEnd(&img); - } else { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); - ok = 0; + if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, stop, emsg)) + { + img.req_orientation = (uint16_t)orientation; + /* XXX verify rwidth and rheight against width and height */ + ok = TIFFRGBAImageGet(&img, raster + (rheight - img.height) * rwidth, + rwidth, img.height); + TIFFRGBAImageEnd(&img); + } + else + { + TIFFErrorExtR(tif, TIFFFileName(tif), "%s", emsg); + ok = 0; } return (ok); } @@ -491,73 +634,72 @@ TIFFReadRGBAImageOriented(TIFF* tif, * Read the specified image into an ABGR-format raster. Use bottom left * origin for raster by default. */ -int -TIFFReadRGBAImage(TIFF* tif, - uint32 rwidth, uint32 rheight, uint32* raster, int stop) -{ - return TIFFReadRGBAImageOriented(tif, rwidth, rheight, raster, - ORIENTATION_BOTLEFT, stop); -} - -static int -setorientation(TIFFRGBAImage* img) -{ - switch (img->orientation) { - case ORIENTATION_TOPLEFT: - case ORIENTATION_LEFTTOP: - if (img->req_orientation == ORIENTATION_TOPRIGHT || - img->req_orientation == ORIENTATION_RIGHTTOP) - return FLIP_HORIZONTALLY; - else if (img->req_orientation == ORIENTATION_BOTRIGHT || - img->req_orientation == ORIENTATION_RIGHTBOT) - return FLIP_HORIZONTALLY | FLIP_VERTICALLY; - else if (img->req_orientation == ORIENTATION_BOTLEFT || - img->req_orientation == ORIENTATION_LEFTBOT) - return FLIP_VERTICALLY; - else - return 0; - case ORIENTATION_TOPRIGHT: - case ORIENTATION_RIGHTTOP: - if (img->req_orientation == ORIENTATION_TOPLEFT || - img->req_orientation == ORIENTATION_LEFTTOP) - return FLIP_HORIZONTALLY; - else if (img->req_orientation == ORIENTATION_BOTRIGHT || - img->req_orientation == ORIENTATION_RIGHTBOT) - return FLIP_VERTICALLY; - else if (img->req_orientation == ORIENTATION_BOTLEFT || - img->req_orientation == ORIENTATION_LEFTBOT) - return FLIP_HORIZONTALLY | FLIP_VERTICALLY; - else - return 0; - case ORIENTATION_BOTRIGHT: - case ORIENTATION_RIGHTBOT: - if (img->req_orientation == ORIENTATION_TOPLEFT || - img->req_orientation == ORIENTATION_LEFTTOP) - return FLIP_HORIZONTALLY | FLIP_VERTICALLY; - else if (img->req_orientation == ORIENTATION_TOPRIGHT || - img->req_orientation == ORIENTATION_RIGHTTOP) - return FLIP_VERTICALLY; - else if (img->req_orientation == ORIENTATION_BOTLEFT || - img->req_orientation == ORIENTATION_LEFTBOT) - return FLIP_HORIZONTALLY; - else - return 0; - case ORIENTATION_BOTLEFT: - case ORIENTATION_LEFTBOT: - if (img->req_orientation == ORIENTATION_TOPLEFT || - img->req_orientation == ORIENTATION_LEFTTOP) - return FLIP_VERTICALLY; - else if (img->req_orientation == ORIENTATION_TOPRIGHT || - img->req_orientation == ORIENTATION_RIGHTTOP) - return FLIP_HORIZONTALLY | FLIP_VERTICALLY; - else if (img->req_orientation == ORIENTATION_BOTRIGHT || - img->req_orientation == ORIENTATION_RIGHTBOT) - return FLIP_HORIZONTALLY; - else - return 0; - default: /* NOTREACHED */ - return 0; - } +int TIFFReadRGBAImage(TIFF *tif, uint32_t rwidth, uint32_t rheight, + uint32_t *raster, int stop) +{ + return TIFFReadRGBAImageOriented(tif, rwidth, rheight, raster, + ORIENTATION_BOTLEFT, stop); +} + +static int setorientation(TIFFRGBAImage *img) +{ + switch (img->orientation) + { + case ORIENTATION_TOPLEFT: + case ORIENTATION_LEFTTOP: + if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_HORIZONTALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_VERTICALLY; + else + return 0; + case ORIENTATION_TOPRIGHT: + case ORIENTATION_RIGHTTOP: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_HORIZONTALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else + return 0; + case ORIENTATION_BOTRIGHT: + case ORIENTATION_RIGHTBOT: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_HORIZONTALLY; + else + return 0; + case ORIENTATION_BOTLEFT: + case ORIENTATION_LEFTBOT: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_HORIZONTALLY; + else + return 0; + default: /* NOTREACHED */ + return 0; + } } /* @@ -565,89 +707,131 @@ setorientation(TIFFRGBAImage* img) * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 - */ -static int -gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) + */ +static int gtTileContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, + uint32_t h) { - TIFF* tif = img->tif; + TIFF *tif = img->tif; tileContigRoutine put = img->put.contig; - uint32 col, row, y, rowstoread; - uint32 pos; - uint32 tw, th; - unsigned char* buf; - int32 fromskew, toskew; - uint32 nrow; + uint32_t col, row, y, rowstoread; + tmsize_t pos; + uint32_t tw, th; + unsigned char *buf = NULL; + int32_t fromskew, toskew; + uint32_t nrow; int ret = 1, flip; - - buf = (unsigned char*) _TIFFmalloc(TIFFTileSize(tif)); - if (buf == 0) { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); - return (0); + uint32_t this_tw, tocol; + int32_t this_toskew, leftmost_toskew; + int32_t leftmost_fromskew; + uint32_t leftmost_tw; + tmsize_t bufsize; + + bufsize = TIFFTileSize(tif); + if (bufsize == 0) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "%s", "No space for tile buffer"); + return (0); } - _TIFFmemset(buf, 0, TIFFTileSize(tif)); + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); flip = setorientation(img); - if (flip & FLIP_VERTICALLY) { - y = h - 1; - toskew = -(int32)(tw + w); + if (flip & FLIP_VERTICALLY) + { + if ((tw + w) > INT_MAX) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "%s", + "unsupported tile size (too wide)"); + return (0); + } + y = h - 1; + toskew = -(int32_t)(tw + w); } - else { - y = 0; - toskew = -(int32)(tw - w); + else + { + if (tw > (INT_MAX + w)) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "%s", + "unsupported tile size (too wide)"); + return (0); + } + y = 0; + toskew = -(int32_t)(tw - w); } - - for (row = 0; row < h; row += nrow) + + /* + * Leftmost tile is clipped on left side if col_offset > 0. + */ + leftmost_fromskew = img->col_offset % tw; + leftmost_tw = tw - leftmost_fromskew; + leftmost_toskew = toskew + leftmost_fromskew; + for (row = 0; ret != 0 && row < h; row += nrow) { rowstoread = th - (row + img->row_offset) % th; - nrow = (row + rowstoread > h ? h - row : rowstoread); - for (col = 0; col < w; col += tw) + nrow = (row + rowstoread > h ? h - row : rowstoread); + fromskew = leftmost_fromskew; + this_tw = leftmost_tw; + this_toskew = leftmost_toskew; + tocol = 0; + col = img->col_offset; + while (tocol < w) { - if (TIFFReadTile(tif, buf, col+img->col_offset, - row+img->row_offset, 0, 0) < 0 && img->stoponerr) + if (_TIFFReadTileAndAllocBuffer(tif, (void **)&buf, bufsize, col, + row + img->row_offset, 0, + 0) == (tmsize_t)(-1) && + (buf == NULL || img->stoponerr)) { ret = 0; break; } - - pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); - - if (col + tw > w) + pos = ((row + img->row_offset) % th) * TIFFTileRowSize(tif) + + ((tmsize_t)fromskew * img->samplesperpixel); + if (tocol + this_tw > w) { /* - * Tile is clipped horizontally. Calculate - * visible portion and skewing factors. + * Rightmost tile is clipped on right side. */ - uint32 npix = w - col; - fromskew = tw - npix; - (*put)(img, raster+y*w+col, col, y, - npix, nrow, fromskew, toskew + fromskew, buf + pos); - } - else - { - (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf + pos); + fromskew = tw - (w - tocol); + this_tw = tw - fromskew; + this_toskew = toskew + fromskew; } + tmsize_t roffset = (tmsize_t)y * w + tocol; + (*put)(img, raster + roffset, tocol, y, this_tw, nrow, fromskew, + this_toskew, buf + pos); + tocol += this_tw; + col += this_tw; + /* + * After the leftmost tile, tiles are no longer clipped on left + * side. + */ + fromskew = 0; + this_tw = tw; + this_toskew = toskew; } - y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); + y += ((flip & FLIP_VERTICALLY) ? -(int32_t)nrow : (int32_t)nrow); } - _TIFFfree(buf); + _TIFFfreeExt(img->tif, buf); - if (flip & FLIP_HORIZONTALLY) { - uint32 line; + if (flip & FLIP_HORIZONTALLY) + { + uint32_t line; - for (line = 0; line < h; line++) { - uint32 *left = raster + (line * w); - uint32 *right = left + w - 1; - - while ( left < right ) { - uint32 temp = *left; - *left = *right; - *right = temp; - left++, right--; - } - } + for (line = 0; line < h; line++) + { + uint32_t *left = raster + (line * w); + uint32_t *right = left + w - 1; + + while (left < right) + { + uint32_t temp = *left; + *left = *right; + *right = temp; + left++; + right--; + } + } } return (ret); @@ -658,124 +842,203 @@ gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) * SamplesPerPixel > 1 * PlanarConfiguration separated * We assume that all such images are RGB. - */ -static int -gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) -{ - TIFF* tif = img->tif; - tileSeparateRoutine put = img->put.separate; - uint32 col, row, y, rowstoread; - uint32 pos; - uint32 tw, th; - unsigned char* buf; - unsigned char* p0; - unsigned char* p1; - unsigned char* p2; - unsigned char* pa; - tsize_t tilesize; - int32 fromskew, toskew; - int alpha = img->alpha; - uint32 nrow; - int ret = 1, flip; - - tilesize = TIFFTileSize(tif); - buf = (unsigned char*) _TIFFmalloc((alpha?4:3)*tilesize); - if (buf == 0) { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); - return (0); - } - _TIFFmemset(buf, 0, (alpha?4:3)*tilesize); - p0 = buf; - p1 = p0 + tilesize; - p2 = p1 + tilesize; - pa = (alpha?(p2+tilesize):NULL); - TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); - TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); - - flip = setorientation(img); - if (flip & FLIP_VERTICALLY) { - y = h - 1; - toskew = -(int32)(tw + w); - } - else { - y = 0; - toskew = -(int32)(tw - w); - } - - for (row = 0; row < h; row += nrow) - { - rowstoread = th - (row + img->row_offset) % th; - nrow = (row + rowstoread > h ? h - row : rowstoread); - for (col = 0; col < w; col += tw) - { - if (TIFFReadTile(tif, p0, col+img->col_offset, - row+img->row_offset,0,0) < 0 && img->stoponerr) - { - ret = 0; - break; - } - if (TIFFReadTile(tif, p1, col+img->col_offset, - row+img->row_offset,0,1) < 0 && img->stoponerr) - { - ret = 0; - break; - } - if (TIFFReadTile(tif, p2, col+img->col_offset, - row+img->row_offset,0,2) < 0 && img->stoponerr) - { - ret = 0; - break; - } - if (alpha) - { - if (TIFFReadTile(tif,pa,col+img->col_offset, - row+img->row_offset,0,3) < 0 && img->stoponerr) - { - ret = 0; - break; - } - } - - pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); - - if (col + tw > w) - { - /* - * Tile is clipped horizontally. Calculate - * visible portion and skewing factors. - */ - uint32 npix = w - col; - fromskew = tw - npix; - (*put)(img, raster+y*w+col, col, y, - npix, nrow, fromskew, toskew + fromskew, - p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); - } else { - (*put)(img, raster+y*w+col, col, y, - tw, nrow, 0, toskew, p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL)); - } - } - - y += (flip & FLIP_VERTICALLY ?-(int32) nrow : (int32) nrow); - } - - if (flip & FLIP_HORIZONTALLY) { - uint32 line; - - for (line = 0; line < h; line++) { - uint32 *left = raster + (line * w); - uint32 *right = left + w - 1; - - while ( left < right ) { - uint32 temp = *left; - *left = *right; - *right = temp; - left++, right--; - } - } - } - - _TIFFfree(buf); - return (ret); + */ +static int gtTileSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, + uint32_t h) +{ + TIFF *tif = img->tif; + tileSeparateRoutine put = img->put.separate; + uint32_t col, row, y, rowstoread; + tmsize_t pos; + uint32_t tw, th; + unsigned char *buf = NULL; + unsigned char *p0 = NULL; + unsigned char *p1 = NULL; + unsigned char *p2 = NULL; + unsigned char *pa = NULL; + tmsize_t tilesize; + tmsize_t bufsize; + int32_t fromskew, toskew; + int alpha = img->alpha; + uint32_t nrow; + int ret = 1, flip; + uint16_t colorchannels; + uint32_t this_tw, tocol; + int32_t this_toskew, leftmost_toskew; + int32_t leftmost_fromskew; + uint32_t leftmost_tw; + + tilesize = TIFFTileSize(tif); + bufsize = + _TIFFMultiplySSize(tif, alpha ? 4 : 3, tilesize, "gtTileSeparate"); + if (bufsize == 0) + { + return (0); + } + + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); + TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) + { + if ((tw + w) > INT_MAX) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "%s", + "unsupported tile size (too wide)"); + return (0); + } + y = h - 1; + toskew = -(int32_t)(tw + w); + } + else + { + if (tw > (INT_MAX + w)) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "%s", + "unsupported tile size (too wide)"); + return (0); + } + y = 0; + toskew = -(int32_t)(tw - w); + } + + switch (img->photometric) + { + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_PALETTE: + colorchannels = 1; + break; + + default: + colorchannels = 3; + break; + } + + /* + * Leftmost tile is clipped on left side if col_offset > 0. + */ + leftmost_fromskew = img->col_offset % tw; + leftmost_tw = tw - leftmost_fromskew; + leftmost_toskew = toskew + leftmost_fromskew; + for (row = 0; ret != 0 && row < h; row += nrow) + { + rowstoread = th - (row + img->row_offset) % th; + nrow = (row + rowstoread > h ? h - row : rowstoread); + fromskew = leftmost_fromskew; + this_tw = leftmost_tw; + this_toskew = leftmost_toskew; + tocol = 0; + col = img->col_offset; + while (tocol < w) + { + if (buf == NULL) + { + if (_TIFFReadTileAndAllocBuffer(tif, (void **)&buf, bufsize, + col, row + img->row_offset, 0, + 0) == (tmsize_t)(-1) && + (buf == NULL || img->stoponerr)) + { + ret = 0; + break; + } + p0 = buf; + if (colorchannels == 1) + { + p2 = p1 = p0; + pa = (alpha ? (p0 + 3 * tilesize) : NULL); + } + else + { + p1 = p0 + tilesize; + p2 = p1 + tilesize; + pa = (alpha ? (p2 + tilesize) : NULL); + } + } + else if (TIFFReadTile(tif, p0, col, row + img->row_offset, 0, 0) == + (tmsize_t)(-1) && + img->stoponerr) + { + ret = 0; + break; + } + if (colorchannels > 1 && + TIFFReadTile(tif, p1, col, row + img->row_offset, 0, 1) == + (tmsize_t)(-1) && + img->stoponerr) + { + ret = 0; + break; + } + if (colorchannels > 1 && + TIFFReadTile(tif, p2, col, row + img->row_offset, 0, 2) == + (tmsize_t)(-1) && + img->stoponerr) + { + ret = 0; + break; + } + if (alpha && + TIFFReadTile(tif, pa, col, row + img->row_offset, 0, + colorchannels) == (tmsize_t)(-1) && + img->stoponerr) + { + ret = 0; + break; + } + + pos = ((row + img->row_offset) % th) * TIFFTileRowSize(tif) + + ((tmsize_t)fromskew * img->samplesperpixel); + if (tocol + this_tw > w) + { + /* + * Rightmost tile is clipped on right side. + */ + fromskew = tw - (w - tocol); + this_tw = tw - fromskew; + this_toskew = toskew + fromskew; + } + tmsize_t roffset = (tmsize_t)y * w + tocol; + (*put)(img, raster + roffset, tocol, y, this_tw, nrow, fromskew, + this_toskew, p0 + pos, p1 + pos, p2 + pos, + (alpha ? (pa + pos) : NULL)); + tocol += this_tw; + col += this_tw; + /* + * After the leftmost tile, tiles are no longer clipped on left + * side. + */ + fromskew = 0; + this_tw = tw; + this_toskew = toskew; + } + + y += ((flip & FLIP_VERTICALLY) ? -(int32_t)nrow : (int32_t)nrow); + } + + if (flip & FLIP_HORIZONTALLY) + { + uint32_t line; + + for (line = 0; line < h; line++) + { + uint32_t *left = raster + (line * w); + uint32_t *right = left + w - 1; + + while (left < right) + { + uint32_t temp = *left; + *left = *right; + *right = temp; + left++; + right--; + } + } + } + + _TIFFfreeExt(img->tif, buf); + return (ret); } /* @@ -783,82 +1046,110 @@ gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 - */ -static int -gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) -{ - TIFF* tif = img->tif; - tileContigRoutine put = img->put.contig; - uint32 row, y, nrow, nrowsub, rowstoread; - uint32 pos; - unsigned char* buf; - uint32 rowsperstrip; - uint16 subsamplinghor,subsamplingver; - uint32 imagewidth = img->width; - tsize_t scanline; - int32 fromskew, toskew; - int ret = 1, flip; - - buf = (unsigned char*) _TIFFmalloc(TIFFStripSize(tif)); - if (buf == 0) { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer"); - return (0); - } - _TIFFmemset(buf, 0, TIFFStripSize(tif)); - - flip = setorientation(img); - if (flip & FLIP_VERTICALLY) { - y = h - 1; - toskew = -(int32)(w + w); - } else { - y = 0; - toskew = -(int32)(w - w); - } - - TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); - TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver); - scanline = TIFFNewScanlineSize(tif); - fromskew = (w < imagewidth ? imagewidth - w : 0); - for (row = 0; row < h; row += nrow) - { - rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; - nrow = (row + rowstoread > h ? h - row : rowstoread); - nrowsub = nrow; - if ((nrowsub%subsamplingver)!=0) - nrowsub+=subsamplingver-nrowsub%subsamplingver; - if (TIFFReadEncodedStrip(tif, - TIFFComputeStrip(tif,row+img->row_offset, 0), - buf, - ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline) < 0 - && img->stoponerr) - { - ret = 0; - break; - } - - pos = ((row + img->row_offset) % rowsperstrip) * scanline; - (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf + pos); - y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); - } - - if (flip & FLIP_HORIZONTALLY) { - uint32 line; - - for (line = 0; line < h; line++) { - uint32 *left = raster + (line * w); - uint32 *right = left + w - 1; - - while ( left < right ) { - uint32 temp = *left; - *left = *right; - *right = temp; - left++, right--; - } - } - } - - _TIFFfree(buf); - return (ret); + */ +static int gtStripContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, + uint32_t h) +{ + TIFF *tif = img->tif; + tileContigRoutine put = img->put.contig; + uint32_t row, y, nrow, nrowsub, rowstoread; + tmsize_t pos; + unsigned char *buf = NULL; + uint32_t rowsperstrip; + uint16_t subsamplinghor, subsamplingver; + uint32_t imagewidth = img->width; + tmsize_t scanline; + int32_t fromskew, toskew; + int ret = 1, flip; + tmsize_t maxstripsize; + + TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, + &subsamplingver); + if (subsamplingver == 0) + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Invalid vertical YCbCr subsampling"); + return (0); + } + + maxstripsize = TIFFStripSize(tif); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) + { + if (w > INT_MAX) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "Width overflow"); + return (0); + } + y = h - 1; + toskew = -(int32_t)(w + w); + } + else + { + y = 0; + toskew = -(int32_t)(w - w); + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + + scanline = TIFFScanlineSize(tif); + fromskew = (w < imagewidth ? imagewidth - w : 0); + for (row = 0; row < h; row += nrow) + { + uint32_t temp; + rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; + nrow = (row + rowstoread > h ? h - row : rowstoread); + nrowsub = nrow; + if ((nrowsub % subsamplingver) != 0) + nrowsub += subsamplingver - nrowsub % subsamplingver; + temp = (row + img->row_offset) % rowsperstrip + nrowsub; + if (scanline > 0 && temp > (size_t)(TIFF_TMSIZE_T_MAX / scanline)) + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Integer overflow in gtStripContig"); + return 0; + } + if (_TIFFReadEncodedStripAndAllocBuffer( + tif, TIFFComputeStrip(tif, row + img->row_offset, 0), + (void **)(&buf), maxstripsize, + temp * scanline) == (tmsize_t)(-1) && + (buf == NULL || img->stoponerr)) + { + ret = 0; + break; + } + + pos = ((row + img->row_offset) % rowsperstrip) * scanline + + ((tmsize_t)img->col_offset * img->samplesperpixel); + tmsize_t roffset = (tmsize_t)y * w; + (*put)(img, raster + roffset, 0, y, w, nrow, fromskew, toskew, + buf + pos); + y += ((flip & FLIP_VERTICALLY) ? -(int32_t)nrow : (int32_t)nrow); + } + + if (flip & FLIP_HORIZONTALLY) + { + uint32_t line; + + for (line = 0; line < h; line++) + { + uint32_t *left = raster + (line * w); + uint32_t *right = left + w - 1; + + while (left < right) + { + uint32_t temp = *left; + *left = *right; + *right = temp; + left++; + right--; + } + } + } + + _TIFFfreeExt(img->tif, buf); + return (ret); } /* @@ -867,108 +1158,167 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) * PlanarConfiguration separated * We assume that all such images are RGB. */ -static int -gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) -{ - TIFF* tif = img->tif; - tileSeparateRoutine put = img->put.separate; - unsigned char *buf; - unsigned char *p0, *p1, *p2, *pa; - uint32 row, y, nrow, rowstoread; - uint32 pos; - tsize_t scanline; - uint32 rowsperstrip, offset_row; - uint32 imagewidth = img->width; - tsize_t stripsize; - int32 fromskew, toskew; - int alpha = img->alpha; - int ret = 1, flip; - - stripsize = TIFFStripSize(tif); - p0 = buf = (unsigned char *)_TIFFmalloc((alpha?4:3)*stripsize); - if (buf == 0) { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer"); - return (0); - } - _TIFFmemset(buf, 0, (alpha?4:3)*stripsize); - p1 = p0 + stripsize; - p2 = p1 + stripsize; - pa = (alpha?(p2+stripsize):NULL); - - flip = setorientation(img); - if (flip & FLIP_VERTICALLY) { - y = h - 1; - toskew = -(int32)(w + w); - } - else { - y = 0; - toskew = -(int32)(w - w); - } - - TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); - scanline = TIFFScanlineSize(tif); - fromskew = (w < imagewidth ? imagewidth - w : 0); - for (row = 0; row < h; row += nrow) - { - rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; - nrow = (row + rowstoread > h ? h - row : rowstoread); - offset_row = row + img->row_offset; - if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0), - p0, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 - && img->stoponerr) - { - ret = 0; - break; - } - if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1), - p1, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 - && img->stoponerr) - { - ret = 0; - break; - } - if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2), - p2, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 - && img->stoponerr) - { - ret = 0; - break; - } - if (alpha) - { - if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 3), - pa, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 - && img->stoponerr) - { - ret = 0; - break; - } - } - - pos = ((row + img->row_offset) % rowsperstrip) * scanline; - (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, p0 + pos, p1 + pos, - p2 + pos, (alpha?(pa+pos):NULL)); - y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); - } - - if (flip & FLIP_HORIZONTALLY) { - uint32 line; - - for (line = 0; line < h; line++) { - uint32 *left = raster + (line * w); - uint32 *right = left + w - 1; - - while ( left < right ) { - uint32 temp = *left; - *left = *right; - *right = temp; - left++, right--; - } - } - } - - _TIFFfree(buf); - return (ret); +static int gtStripSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w, + uint32_t h) +{ + TIFF *tif = img->tif; + tileSeparateRoutine put = img->put.separate; + unsigned char *buf = NULL; + unsigned char *p0 = NULL, *p1 = NULL, *p2 = NULL, *pa = NULL; + uint32_t row, y, nrow, rowstoread; + tmsize_t pos; + tmsize_t scanline; + uint32_t rowsperstrip, offset_row; + uint32_t imagewidth = img->width; + tmsize_t stripsize; + tmsize_t bufsize; + int32_t fromskew, toskew; + int alpha = img->alpha; + int ret = 1, flip; + uint16_t colorchannels; + + stripsize = TIFFStripSize(tif); + bufsize = + _TIFFMultiplySSize(tif, alpha ? 4 : 3, stripsize, "gtStripSeparate"); + if (bufsize == 0) + { + return (0); + } + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) + { + if (w > INT_MAX) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "Width overflow"); + return (0); + } + y = h - 1; + toskew = -(int32_t)(w + w); + } + else + { + y = 0; + toskew = -(int32_t)(w - w); + } + + switch (img->photometric) + { + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_PALETTE: + colorchannels = 1; + break; + + default: + colorchannels = 3; + break; + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + scanline = TIFFScanlineSize(tif); + fromskew = (w < imagewidth ? imagewidth - w : 0); + for (row = 0; row < h; row += nrow) + { + uint32_t temp; + rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; + nrow = (row + rowstoread > h ? h - row : rowstoread); + offset_row = row + img->row_offset; + temp = (row + img->row_offset) % rowsperstrip + nrow; + if (scanline > 0 && temp > (size_t)(TIFF_TMSIZE_T_MAX / scanline)) + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Integer overflow in gtStripSeparate"); + return 0; + } + if (buf == NULL) + { + if (_TIFFReadEncodedStripAndAllocBuffer( + tif, TIFFComputeStrip(tif, offset_row, 0), (void **)&buf, + bufsize, temp * scanline) == (tmsize_t)(-1) && + (buf == NULL || img->stoponerr)) + { + ret = 0; + break; + } + p0 = buf; + if (colorchannels == 1) + { + p2 = p1 = p0; + pa = (alpha ? (p0 + 3 * stripsize) : NULL); + } + else + { + p1 = p0 + stripsize; + p2 = p1 + stripsize; + pa = (alpha ? (p2 + stripsize) : NULL); + } + } + else if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0), + p0, temp * scanline) == (tmsize_t)(-1) && + img->stoponerr) + { + ret = 0; + break; + } + if (colorchannels > 1 && + TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1), p1, + temp * scanline) == (tmsize_t)(-1) && + img->stoponerr) + { + ret = 0; + break; + } + if (colorchannels > 1 && + TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2), p2, + temp * scanline) == (tmsize_t)(-1) && + img->stoponerr) + { + ret = 0; + break; + } + if (alpha) + { + if (TIFFReadEncodedStrip( + tif, TIFFComputeStrip(tif, offset_row, colorchannels), pa, + temp * scanline) == (tmsize_t)(-1) && + img->stoponerr) + { + ret = 0; + break; + } + } + + pos = ((row + img->row_offset) % rowsperstrip) * scanline + + ((tmsize_t)img->col_offset * img->samplesperpixel); + tmsize_t roffset = (tmsize_t)y * w; + (*put)(img, raster + roffset, 0, y, w, nrow, fromskew, toskew, p0 + pos, + p1 + pos, p2 + pos, (alpha ? (pa + pos) : NULL)); + y += ((flip & FLIP_VERTICALLY) ? -(int32_t)nrow : (int32_t)nrow); + } + + if (flip & FLIP_HORIZONTALLY) + { + uint32_t line; + + for (line = 0; line < h; line++) + { + uint32_t *left = raster + (line * w); + uint32_t *right = left + w - 1; + + while (left < right) + { + uint32_t temp = *left; + *left = *right; + *right = temp; + left++; + right--; + } + } + } + + _TIFFfreeExt(img->tif, buf); + return (ret); } /* @@ -981,93 +1331,139 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) * PickSeparateCase analyze the parameters and select * the appropriate "get" and "put" routine to use. */ -#define REPEAT8(op) REPEAT4(op); REPEAT4(op) -#define REPEAT4(op) REPEAT2(op); REPEAT2(op) -#define REPEAT2(op) op; op -#define CASE8(x,op) \ - switch (x) { \ - case 7: op; case 6: op; case 5: op; \ - case 4: op; case 3: op; case 2: op; \ - case 1: op; \ - } -#define CASE4(x,op) switch (x) { case 3: op; case 2: op; case 1: op; } -#define NOP - -#define UNROLL8(w, op1, op2) { \ - uint32 _x; \ - for (_x = w; _x >= 8; _x -= 8) { \ - op1; \ - REPEAT8(op2); \ - } \ - if (_x > 0) { \ - op1; \ - CASE8(_x,op2); \ - } \ -} -#define UNROLL4(w, op1, op2) { \ - uint32 _x; \ - for (_x = w; _x >= 4; _x -= 4) { \ - op1; \ - REPEAT4(op2); \ - } \ - if (_x > 0) { \ - op1; \ - CASE4(_x,op2); \ - } \ -} -#define UNROLL2(w, op1, op2) { \ - uint32 _x; \ - for (_x = w; _x >= 2; _x -= 2) { \ - op1; \ - REPEAT2(op2); \ - } \ - if (_x) { \ - op1; \ - op2; \ - } \ -} - -#define SKEW(r,g,b,skew) { r += skew; g += skew; b += skew; } -#define SKEW4(r,g,b,a,skew) { r += skew; g += skew; b += skew; a+= skew; } - -#define A1 (((uint32)0xffL)<<24) -#define PACK(r,g,b) \ - ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|A1) -#define PACK4(r,g,b,a) \ - ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|((uint32)(a)<<24)) -#define W2B(v) (((v)>>8)&0xff) -#define PACKW(r,g,b) \ - ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|A1) -#define PACKW4(r,g,b,a) \ - ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|((uint32)W2B(a)<<24)) - -#define DECLAREContigPutFunc(name) \ -static void name(\ - TIFFRGBAImage* img, \ - uint32* cp, \ - uint32 x, uint32 y, \ - uint32 w, uint32 h, \ - int32 fromskew, int32 toskew, \ - unsigned char* pp \ -) +#define REPEAT8(op) \ + REPEAT4(op); \ + REPEAT4(op) +#define REPEAT4(op) \ + REPEAT2(op); \ + REPEAT2(op) +#define REPEAT2(op) \ + op; \ + op +#define CASE8(x, op) \ + switch (x) \ + { \ + case 7: \ + op; /*-fallthrough*/ \ + case 6: \ + op; /*-fallthrough*/ \ + case 5: \ + op; /*-fallthrough*/ \ + case 4: \ + op; /*-fallthrough*/ \ + case 3: \ + op; /*-fallthrough*/ \ + case 2: \ + op; /*-fallthrough*/ \ + case 1: \ + op; \ + } +#define CASE4(x, op) \ + switch (x) \ + { \ + case 3: \ + op; /*-fallthrough*/ \ + case 2: \ + op; /*-fallthrough*/ \ + case 1: \ + op; \ + } +#define NOP + +#define UNROLL8(w, op1, op2) \ + { \ + uint32_t _x; \ + for (_x = w; _x >= 8; _x -= 8) \ + { \ + op1; \ + REPEAT8(op2); \ + } \ + if (_x > 0) \ + { \ + op1; \ + CASE8(_x, op2); \ + } \ + } +#define UNROLL4(w, op1, op2) \ + { \ + uint32_t _x; \ + for (_x = w; _x >= 4; _x -= 4) \ + { \ + op1; \ + REPEAT4(op2); \ + } \ + if (_x > 0) \ + { \ + op1; \ + CASE4(_x, op2); \ + } \ + } +#define UNROLL2(w, op1, op2) \ + { \ + uint32_t _x; \ + for (_x = w; _x >= 2; _x -= 2) \ + { \ + op1; \ + REPEAT2(op2); \ + } \ + if (_x) \ + { \ + op1; \ + op2; \ + } \ + } + +#define SKEW(r, g, b, skew) \ + { \ + r += skew; \ + g += skew; \ + b += skew; \ + } +#define SKEW4(r, g, b, a, skew) \ + { \ + r += skew; \ + g += skew; \ + b += skew; \ + a += skew; \ + } + +#define A1 (((uint32_t)0xffL) << 24) +#define PACK(r, g, b) \ + ((uint32_t)(r) | ((uint32_t)(g) << 8) | ((uint32_t)(b) << 16) | A1) +#define PACK4(r, g, b, a) \ + ((uint32_t)(r) | ((uint32_t)(g) << 8) | ((uint32_t)(b) << 16) | \ + ((uint32_t)(a) << 24)) +#define W2B(v) (((v) >> 8) & 0xff) +/* TODO: PACKW should have be made redundant in favor of Bitdepth16To8 LUT */ +#define PACKW(r, g, b) \ + ((uint32_t)W2B(r) | ((uint32_t)W2B(g) << 8) | ((uint32_t)W2B(b) << 16) | A1) +#define PACKW4(r, g, b, a) \ + ((uint32_t)W2B(r) | ((uint32_t)W2B(g) << 8) | ((uint32_t)W2B(b) << 16) | \ + ((uint32_t)W2B(a) << 24)) + +#define DECLAREContigPutFunc(name) \ + static void name(TIFFRGBAImage *img, uint32_t *cp, uint32_t x, uint32_t y, \ + uint32_t w, uint32_t h, int32_t fromskew, int32_t toskew, \ + unsigned char *pp) /* * 8-bit palette => colormap/RGB */ DECLAREContigPutFunc(put8bitcmaptile) { - uint32** PALmap = img->PALmap; + uint32_t **PALmap = img->PALmap; int samplesperpixel = img->samplesperpixel; - (void) y; - while (h-- > 0) { - for (x = w; x-- > 0;) + (void)y; + for (; h > 0; --h) + { + for (x = w; x > 0; --x) { - *cp++ = PALmap[*pp][0]; + *cp++ = PALmap[*pp][0]; pp += samplesperpixel; } - cp += toskew; - pp += fromskew; + cp += toskew; + pp += fromskew; } } @@ -1076,15 +1472,17 @@ DECLAREContigPutFunc(put8bitcmaptile) */ DECLAREContigPutFunc(put4bitcmaptile) { - uint32** PALmap = img->PALmap; + uint32_t **PALmap = img->PALmap; - (void) x; (void) y; + (void)x; + (void)y; fromskew /= 2; - while (h-- > 0) { - uint32* bw; - UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++); - cp += toskew; - pp += fromskew; + for (; h > 0; --h) + { + uint32_t *bw; + UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; } } @@ -1093,15 +1491,17 @@ DECLAREContigPutFunc(put4bitcmaptile) */ DECLAREContigPutFunc(put2bitcmaptile) { - uint32** PALmap = img->PALmap; + uint32_t **PALmap = img->PALmap; - (void) x; (void) y; + (void)x; + (void)y; fromskew /= 4; - while (h-- > 0) { - uint32* bw; - UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++); - cp += toskew; - pp += fromskew; + for (; h > 0; --h) + { + uint32_t *bw; + UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; } } @@ -1110,15 +1510,17 @@ DECLAREContigPutFunc(put2bitcmaptile) */ DECLAREContigPutFunc(put1bitcmaptile) { - uint32** PALmap = img->PALmap; + uint32_t **PALmap = img->PALmap; - (void) x; (void) y; + (void)x; + (void)y; fromskew /= 8; - while (h-- > 0) { - uint32* bw; - UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++); - cp += toskew; - pp += fromskew; + for (; h > 0; --h) + { + uint32_t *bw; + UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; } } @@ -1128,17 +1530,39 @@ DECLAREContigPutFunc(put1bitcmaptile) DECLAREContigPutFunc(putgreytile) { int samplesperpixel = img->samplesperpixel; - uint32** BWmap = img->BWmap; + uint32_t **BWmap = img->BWmap; - (void) y; - while (h-- > 0) { - for (x = w; x-- > 0;) + (void)y; + for (; h > 0; --h) + { + for (x = w; x > 0; --x) + { + *cp++ = BWmap[*pp][0]; + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit greyscale with associated alpha => colormap/RGBA + */ +DECLAREContigPutFunc(putagreytile) +{ + int samplesperpixel = img->samplesperpixel; + uint32_t **BWmap = img->BWmap; + + (void)y; + for (; h > 0; --h) + { + for (x = w; x > 0; --x) { - *cp++ = BWmap[*pp][0]; + *cp++ = BWmap[*pp][0] & ((uint32_t) * (pp + 1) << 24 | ~A1); pp += samplesperpixel; } - cp += toskew; - pp += fromskew; + cp += toskew; + pp += fromskew; } } @@ -1148,22 +1572,23 @@ DECLAREContigPutFunc(putgreytile) DECLAREContigPutFunc(put16bitbwtile) { int samplesperpixel = img->samplesperpixel; - uint32** BWmap = img->BWmap; + uint32_t **BWmap = img->BWmap; - (void) y; - while (h-- > 0) { - uint16 *wp = (uint16 *) pp; + (void)y; + for (; h > 0; --h) + { + uint16_t *wp = (uint16_t *)pp; - for (x = w; x-- > 0;) + for (x = w; x > 0; --x) { /* use high order byte of 16bit value */ - *cp++ = BWmap[*wp >> 8][0]; + *cp++ = BWmap[*wp >> 8][0]; pp += 2 * samplesperpixel; wp += samplesperpixel; } - cp += toskew; - pp += fromskew; + cp += toskew; + pp += fromskew; } } @@ -1172,15 +1597,17 @@ DECLAREContigPutFunc(put16bitbwtile) */ DECLAREContigPutFunc(put1bitbwtile) { - uint32** BWmap = img->BWmap; + uint32_t **BWmap = img->BWmap; - (void) x; (void) y; + (void)x; + (void)y; fromskew /= 8; - while (h-- > 0) { - uint32* bw; - UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++); - cp += toskew; - pp += fromskew; + for (; h > 0; --h) + { + uint32_t *bw; + UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; } } @@ -1189,15 +1616,17 @@ DECLAREContigPutFunc(put1bitbwtile) */ DECLAREContigPutFunc(put2bitbwtile) { - uint32** BWmap = img->BWmap; + uint32_t **BWmap = img->BWmap; - (void) x; (void) y; + (void)x; + (void)y; fromskew /= 4; - while (h-- > 0) { - uint32* bw; - UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++); - cp += toskew; - pp += fromskew; + for (; h > 0; --h) + { + uint32_t *bw; + UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; } } @@ -1206,15 +1635,17 @@ DECLAREContigPutFunc(put2bitbwtile) */ DECLAREContigPutFunc(put4bitbwtile) { - uint32** BWmap = img->BWmap; + uint32_t **BWmap = img->BWmap; - (void) x; (void) y; + (void)x; + (void)y; fromskew /= 2; - while (h-- > 0) { - uint32* bw; - UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++); - cp += toskew; - pp += fromskew; + for (; h > 0; --h) + { + uint32_t *bw; + UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; } } @@ -1225,14 +1656,15 @@ DECLAREContigPutFunc(putRGBcontig8bittile) { int samplesperpixel = img->samplesperpixel; - (void) x; (void) y; + (void)x; + (void)y; fromskew *= samplesperpixel; - while (h-- > 0) { - UNROLL8(w, NOP, - *cp++ = PACK(pp[0], pp[1], pp[2]); - pp += samplesperpixel); - cp += toskew; - pp += fromskew; + for (; h > 0; --h) + { + UNROLL8(w, NOP, *cp++ = PACK(pp[0], pp[1], pp[2]); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; } } @@ -1244,14 +1676,15 @@ DECLAREContigPutFunc(putRGBAAcontig8bittile) { int samplesperpixel = img->samplesperpixel; - (void) x; (void) y; + (void)x; + (void)y; fromskew *= samplesperpixel; - while (h-- > 0) { - UNROLL8(w, NOP, - *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]); - pp += samplesperpixel); - cp += toskew; - pp += fromskew; + for (; h > 0; --h) + { + UNROLL8(w, NOP, *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; } } @@ -1261,22 +1694,26 @@ DECLAREContigPutFunc(putRGBAAcontig8bittile) */ DECLAREContigPutFunc(putRGBUAcontig8bittile) { - int samplesperpixel = img->samplesperpixel; - (void) y; - fromskew *= samplesperpixel; - while (h-- > 0) { - uint32 r, g, b, a; - for (x = w; x-- > 0;) { - a = pp[3]; - r = (a*pp[0] + 127) / 255; - g = (a*pp[1] + 127) / 255; - b = (a*pp[2] + 127) / 255; - *cp++ = PACK4(r,g,b,a); - pp += samplesperpixel; - } - cp += toskew; - pp += fromskew; - } + int samplesperpixel = img->samplesperpixel; + (void)y; + fromskew *= samplesperpixel; + for (; h > 0; --h) + { + uint32_t r, g, b, a; + uint8_t *m; + for (x = w; x > 0; --x) + { + a = pp[3]; + m = img->UaToAa + ((size_t)a << 8); + r = m[pp[0]]; + g = m[pp[1]]; + b = m[pp[2]]; + *cp++ = PACK4(r, g, b, a); + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } } /* @@ -1284,18 +1721,21 @@ DECLAREContigPutFunc(putRGBUAcontig8bittile) */ DECLAREContigPutFunc(putRGBcontig16bittile) { - int samplesperpixel = img->samplesperpixel; - uint16 *wp = (uint16 *)pp; - (void) y; - fromskew *= samplesperpixel; - while (h-- > 0) { - for (x = w; x-- > 0;) { - *cp++ = PACKW(wp[0],wp[1],wp[2]); - wp += samplesperpixel; - } - cp += toskew; - wp += fromskew; - } + int samplesperpixel = img->samplesperpixel; + uint16_t *wp = (uint16_t *)pp; + (void)y; + fromskew *= samplesperpixel; + for (; h > 0; --h) + { + for (x = w; x > 0; --x) + { + *cp++ = PACK(img->Bitdepth16To8[wp[0]], img->Bitdepth16To8[wp[1]], + img->Bitdepth16To8[wp[2]]); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } } /* @@ -1304,18 +1744,21 @@ DECLAREContigPutFunc(putRGBcontig16bittile) */ DECLAREContigPutFunc(putRGBAAcontig16bittile) { - int samplesperpixel = img->samplesperpixel; - uint16 *wp = (uint16 *)pp; - (void) y; - fromskew *= samplesperpixel; - while (h-- > 0) { - for (x = w; x-- > 0;) { - *cp++ = PACKW4(wp[0],wp[1],wp[2],wp[3]); - wp += samplesperpixel; - } - cp += toskew; - wp += fromskew; - } + int samplesperpixel = img->samplesperpixel; + uint16_t *wp = (uint16_t *)pp; + (void)y; + fromskew *= samplesperpixel; + for (; h > 0; --h) + { + for (x = w; x > 0; --x) + { + *cp++ = PACK4(img->Bitdepth16To8[wp[0]], img->Bitdepth16To8[wp[1]], + img->Bitdepth16To8[wp[2]], img->Bitdepth16To8[wp[3]]); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } } /* @@ -1324,23 +1767,27 @@ DECLAREContigPutFunc(putRGBAAcontig16bittile) */ DECLAREContigPutFunc(putRGBUAcontig16bittile) { - int samplesperpixel = img->samplesperpixel; - uint16 *wp = (uint16 *)pp; - (void) y; - fromskew *= samplesperpixel; - while (h-- > 0) { - uint32 r,g,b,a; - for (x = w; x-- > 0;) { - a = W2B(wp[3]); - r = (a*W2B(wp[0]) + 127) / 255; - g = (a*W2B(wp[1]) + 127) / 255; - b = (a*W2B(wp[2]) + 127) / 255; - *cp++ = PACK4(r,g,b,a); - wp += samplesperpixel; - } - cp += toskew; - wp += fromskew; - } + int samplesperpixel = img->samplesperpixel; + uint16_t *wp = (uint16_t *)pp; + (void)y; + fromskew *= samplesperpixel; + for (; h > 0; --h) + { + uint32_t r, g, b, a; + uint8_t *m; + for (x = w; x > 0; --x) + { + a = img->Bitdepth16To8[wp[3]]; + m = img->UaToAa + ((size_t)a << 8); + r = m[img->Bitdepth16To8[wp[0]]]; + g = m[img->Bitdepth16To8[wp[1]]]; + b = m[img->Bitdepth16To8[wp[2]]]; + *cp++ = PACK4(r, g, b, a); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } } /* @@ -1351,20 +1798,18 @@ DECLAREContigPutFunc(putRGBUAcontig16bittile) DECLAREContigPutFunc(putRGBcontig8bitCMYKtile) { int samplesperpixel = img->samplesperpixel; - uint16 r, g, b, k; + uint16_t r, g, b, k; - (void) x; (void) y; + (void)x; + (void)y; fromskew *= samplesperpixel; - while (h-- > 0) { - UNROLL8(w, NOP, - k = 255 - pp[3]; - r = (k*(255-pp[0]))/255; - g = (k*(255-pp[1]))/255; - b = (k*(255-pp[2]))/255; - *cp++ = PACK(r, g, b); - pp += samplesperpixel); - cp += toskew; - pp += fromskew; + for (; h > 0; --h) + { + UNROLL8(w, NOP, k = 255 - pp[3]; r = (k * (255 - pp[0])) / 255; + g = (k * (255 - pp[1])) / 255; b = (k * (255 - pp[2])) / 255; + *cp++ = PACK(r, g, b); pp += samplesperpixel); + cp += toskew; + pp += fromskew; } } @@ -1376,59 +1821,87 @@ DECLAREContigPutFunc(putRGBcontig8bitCMYKtile) DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile) { int samplesperpixel = img->samplesperpixel; - TIFFRGBValue* Map = img->Map; - uint16 r, g, b, k; + TIFFRGBValue *Map = img->Map; + uint16_t r, g, b, k; - (void) y; + (void)y; fromskew *= samplesperpixel; - while (h-- > 0) { - for (x = w; x-- > 0;) { - k = 255 - pp[3]; - r = (k*(255-pp[0]))/255; - g = (k*(255-pp[1]))/255; - b = (k*(255-pp[2]))/255; - *cp++ = PACK(Map[r], Map[g], Map[b]); - pp += samplesperpixel; - } - pp += fromskew; - cp += toskew; - } -} - -#define DECLARESepPutFunc(name) \ -static void name(\ - TIFFRGBAImage* img,\ - uint32* cp,\ - uint32 x, uint32 y, \ - uint32 w, uint32 h,\ - int32 fromskew, int32 toskew,\ - unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a\ -) + for (; h > 0; --h) + { + for (x = w; x > 0; --x) + { + k = 255 - pp[3]; + r = (k * (255 - pp[0])) / 255; + g = (k * (255 - pp[1])) / 255; + b = (k * (255 - pp[2])) / 255; + *cp++ = PACK(Map[r], Map[g], Map[b]); + pp += samplesperpixel; + } + pp += fromskew; + cp += toskew; + } +} + +#define DECLARESepPutFunc(name) \ + static void name(TIFFRGBAImage *img, uint32_t *cp, uint32_t x, uint32_t y, \ + uint32_t w, uint32_t h, int32_t fromskew, int32_t toskew, \ + unsigned char *r, unsigned char *g, unsigned char *b, \ + unsigned char *a) /* * 8-bit unpacked samples => RGB */ -DECLARESepPutFunc(putRGBseparate8bittile) +DECLARESepPutFunc(putRGBseparate8bittile) +{ + (void)img; + (void)x; + (void)y; + (void)a; + for (; h > 0; --h) + { + UNROLL8(w, NOP, *cp++ = PACK(*r++, *g++, *b++)); + SKEW(r, g, b, fromskew); + cp += toskew; + } +} + +/* + * 8-bit unpacked samples => RGBA w/ associated alpha + */ +DECLARESepPutFunc(putRGBAAseparate8bittile) { - (void) img; (void) x; (void) y; (void) a; - while (h-- > 0) { - UNROLL8(w, NOP, *cp++ = PACK(*r++, *g++, *b++)); - SKEW(r, g, b, fromskew); - cp += toskew; + (void)img; + (void)x; + (void)y; + for (; h > 0; --h) + { + UNROLL8(w, NOP, *cp++ = PACK4(*r++, *g++, *b++, *a++)); + SKEW4(r, g, b, a, fromskew); + cp += toskew; } } /* - * 8-bit unpacked samples => RGBA w/ associated alpha + * 8-bit unpacked CMYK samples => RGBA */ -DECLARESepPutFunc(putRGBAAseparate8bittile) +DECLARESepPutFunc(putCMYKseparate8bittile) { - (void) img; (void) x; (void) y; - while (h-- > 0) { - UNROLL8(w, NOP, *cp++ = PACK4(*r++, *g++, *b++, *a++)); - SKEW4(r, g, b, a, fromskew); - cp += toskew; - } + (void)img; + (void)y; + for (; h > 0; --h) + { + uint32_t rv, gv, bv, kv; + for (x = w; x > 0; --x) + { + kv = 255 - *a++; + rv = (kv * (255 - *r++)) / 255; + gv = (kv * (255 - *g++)) / 255; + bv = (kv * (255 - *b++)) / 255; + *cp++ = PACK4(rv, gv, bv, 255); + } + SKEW4(r, g, b, a, fromskew); + cp += toskew; + } } /* @@ -1436,19 +1909,24 @@ DECLARESepPutFunc(putRGBAAseparate8bittile) */ DECLARESepPutFunc(putRGBUAseparate8bittile) { - (void) img; (void) y; - while (h-- > 0) { - uint32 rv, gv, bv, av; - for (x = w; x-- > 0;) { - av = *a++; - rv = (av* *r++ + 127) / 255; - gv = (av* *g++ + 127) / 255; - bv = (av* *b++ + 127) / 255; - *cp++ = PACK4(rv,gv,bv,av); - } - SKEW4(r, g, b, a, fromskew); - cp += toskew; - } + (void)img; + (void)y; + for (; h > 0; --h) + { + uint32_t rv, gv, bv, av; + uint8_t *m; + for (x = w; x > 0; --x) + { + av = *a++; + m = img->UaToAa + ((size_t)av << 8); + rv = m[*r++]; + gv = m[*g++]; + bv = m[*b++]; + *cp++ = PACK4(rv, gv, bv, av); + } + SKEW4(r, g, b, a, fromskew); + cp += toskew; + } } /* @@ -1456,16 +1934,20 @@ DECLARESepPutFunc(putRGBUAseparate8bittile) */ DECLARESepPutFunc(putRGBseparate16bittile) { - uint16 *wr = (uint16*) r; - uint16 *wg = (uint16*) g; - uint16 *wb = (uint16*) b; - (void) img; (void) y; (void) a; - while (h-- > 0) { - for (x = 0; x < w; x++) - *cp++ = PACKW(*wr++,*wg++,*wb++); - SKEW(wr, wg, wb, fromskew); - cp += toskew; - } + uint16_t *wr = (uint16_t *)r; + uint16_t *wg = (uint16_t *)g; + uint16_t *wb = (uint16_t *)b; + (void)img; + (void)y; + (void)a; + for (; h > 0; --h) + { + for (x = 0; x < w; x++) + *cp++ = PACK(img->Bitdepth16To8[*wr++], img->Bitdepth16To8[*wg++], + img->Bitdepth16To8[*wb++]); + SKEW(wr, wg, wb, fromskew); + cp += toskew; + } } /* @@ -1473,17 +1955,20 @@ DECLARESepPutFunc(putRGBseparate16bittile) */ DECLARESepPutFunc(putRGBAAseparate16bittile) { - uint16 *wr = (uint16*) r; - uint16 *wg = (uint16*) g; - uint16 *wb = (uint16*) b; - uint16 *wa = (uint16*) a; - (void) img; (void) y; - while (h-- > 0) { - for (x = 0; x < w; x++) - *cp++ = PACKW4(*wr++,*wg++,*wb++,*wa++); - SKEW4(wr, wg, wb, wa, fromskew); - cp += toskew; - } + uint16_t *wr = (uint16_t *)r; + uint16_t *wg = (uint16_t *)g; + uint16_t *wb = (uint16_t *)b; + uint16_t *wa = (uint16_t *)a; + (void)img; + (void)y; + for (; h > 0; --h) + { + for (x = 0; x < w; x++) + *cp++ = PACK4(img->Bitdepth16To8[*wr++], img->Bitdepth16To8[*wg++], + img->Bitdepth16To8[*wb++], img->Bitdepth16To8[*wa++]); + SKEW4(wr, wg, wb, wa, fromskew); + cp += toskew; + } } /* @@ -1491,166 +1976,123 @@ DECLARESepPutFunc(putRGBAAseparate16bittile) */ DECLARESepPutFunc(putRGBUAseparate16bittile) { - uint16 *wr = (uint16*) r; - uint16 *wg = (uint16*) g; - uint16 *wb = (uint16*) b; - uint16 *wa = (uint16*) a; - (void) img; (void) y; - while (h-- > 0) { - uint32 r,g,b,a; - for (x = w; x-- > 0;) { - a = W2B(*wa++); - r = (a*W2B(*wr++) + 127) / 255; - g = (a*W2B(*wg++) + 127) / 255; - b = (a*W2B(*wb++) + 127) / 255; - *cp++ = PACK4(r,g,b,a); - } - SKEW4(wr, wg, wb, wa, fromskew); - cp += toskew; - } + uint16_t *wr = (uint16_t *)r; + uint16_t *wg = (uint16_t *)g; + uint16_t *wb = (uint16_t *)b; + uint16_t *wa = (uint16_t *)a; + (void)img; + (void)y; + for (; h > 0; --h) + { + uint32_t r2, g2, b2, a2; + uint8_t *m; + for (x = w; x > 0; --x) + { + a2 = img->Bitdepth16To8[*wa++]; + m = img->UaToAa + ((size_t)a2 << 8); + r2 = m[img->Bitdepth16To8[*wr++]]; + g2 = m[img->Bitdepth16To8[*wg++]]; + b2 = m[img->Bitdepth16To8[*wb++]]; + *cp++ = PACK4(r2, g2, b2, a2); + } + SKEW4(wr, wg, wb, wa, fromskew); + cp += toskew; + } } /* * 8-bit packed CIE L*a*b 1976 samples => RGB */ -DECLAREContigPutFunc(putcontig8bitCIELab) -{ - float X, Y, Z; - uint32 r, g, b; - (void) y; - fromskew *= 3; - while (h-- > 0) { - for (x = w; x-- > 0;) { - TIFFCIELabToXYZ(img->cielab, - (unsigned char)pp[0], - (signed char)pp[1], - (signed char)pp[2], - &X, &Y, &Z); - TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b); - *cp++ = PACK(r, g, b); - pp += 3; - } - cp += toskew; - pp += fromskew; - } +DECLAREContigPutFunc(putcontig8bitCIELab8) +{ + float X, Y, Z; + uint32_t r, g, b; + (void)y; + fromskew *= 3; + for (; h > 0; --h) + { + for (x = w; x > 0; --x) + { + TIFFCIELabToXYZ(img->cielab, (unsigned char)pp[0], + (signed char)pp[1], (signed char)pp[2], &X, &Y, &Z); + TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b); + *cp++ = PACK(r, g, b); + pp += 3; + } + cp += toskew; + pp += fromskew; + } } /* - * YCbCr -> RGB conversion and packing routines. + * 16-bit packed CIE L*a*b 1976 samples => RGB */ - -#define YCbCrtoRGB(dst, Y) { \ - uint32 r, g, b; \ - TIFFYCbCrtoRGB(img->ycbcr, (Y), Cb, Cr, &r, &g, &b); \ - dst = PACK(r, g, b); \ +DECLAREContigPutFunc(putcontig8bitCIELab16) +{ + float X, Y, Z; + uint32_t r, g, b; + uint16_t *wp = (uint16_t *)pp; + (void)y; + fromskew *= 3; + for (; h > 0; --h) + { + for (x = w; x > 0; --x) + { + TIFFCIELab16ToXYZ(img->cielab, (uint16_t)wp[0], (int16_t)wp[1], + (int16_t)wp[2], &X, &Y, &Z); + TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b); + *cp++ = PACK(r, g, b); + wp += 3; + } + cp += toskew; + wp += fromskew; + } } /* - * 8-bit packed YCbCr samples => RGB - * This function is generic for different sampling sizes, - * and can handle blocks sizes that aren't multiples of the - * sampling size. However, it is substantially less optimized - * than the specific sampling cases. It is used as a fallback - * for difficult blocks. + * YCbCr -> RGB conversion and packing routines. */ -#ifdef notdef -static void putcontig8bitYCbCrGenericTile( - TIFFRGBAImage* img, - uint32* cp, - uint32 x, uint32 y, - uint32 w, uint32 h, - int32 fromskew, int32 toskew, - unsigned char* pp, - int h_group, - int v_group ) - -{ - uint32* cp1 = cp+w+toskew; - uint32* cp2 = cp1+w+toskew; - uint32* cp3 = cp2+w+toskew; - int32 incr = 3*w+4*toskew; - int32 Cb, Cr; - int group_size = v_group * h_group + 2; - - (void) y; - fromskew = (fromskew * group_size) / h_group; - - for( yy = 0; yy < h; yy++ ) - { - unsigned char *pp_line; - int y_line_group = yy / v_group; - int y_remainder = yy - y_line_group * v_group; - - pp_line = pp + v_line_group * - - - for( xx = 0; xx < w; xx++ ) - { - Cb = pp - } - } - for (; h >= 4; h -= 4) { - x = w>>2; - do { - Cb = pp[16]; - Cr = pp[17]; - - YCbCrtoRGB(cp [0], pp[ 0]); - YCbCrtoRGB(cp [1], pp[ 1]); - YCbCrtoRGB(cp [2], pp[ 2]); - YCbCrtoRGB(cp [3], pp[ 3]); - YCbCrtoRGB(cp1[0], pp[ 4]); - YCbCrtoRGB(cp1[1], pp[ 5]); - YCbCrtoRGB(cp1[2], pp[ 6]); - YCbCrtoRGB(cp1[3], pp[ 7]); - YCbCrtoRGB(cp2[0], pp[ 8]); - YCbCrtoRGB(cp2[1], pp[ 9]); - YCbCrtoRGB(cp2[2], pp[10]); - YCbCrtoRGB(cp2[3], pp[11]); - YCbCrtoRGB(cp3[0], pp[12]); - YCbCrtoRGB(cp3[1], pp[13]); - YCbCrtoRGB(cp3[2], pp[14]); - YCbCrtoRGB(cp3[3], pp[15]); - - cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; - pp += 18; - } while (--x); - cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; - pp += fromskew; + +#define YCbCrtoRGB(dst, Y) \ + { \ + uint32_t r, g, b; \ + TIFFYCbCrtoRGB(img->ycbcr, (Y), Cb, Cr, &r, &g, &b); \ + dst = PACK(r, g, b); \ } -} -#endif /* * 8-bit packed YCbCr samples w/ 4,4 subsampling => RGB */ DECLAREContigPutFunc(putcontig8bitYCbCr44tile) { - uint32* cp1 = cp+w+toskew; - uint32* cp2 = cp1+w+toskew; - uint32* cp3 = cp2+w+toskew; - int32 incr = 3*w+4*toskew; + uint32_t *cp1 = cp + w + toskew; + uint32_t *cp2 = cp1 + w + toskew; + uint32_t *cp3 = cp2 + w + toskew; + int32_t incr = 3 * w + 4 * toskew; - (void) y; + (void)y; /* adjust fromskew */ - fromskew = (fromskew * 18) / 4; - if ((h & 3) == 0 && (w & 3) == 0) { - for (; h >= 4; h -= 4) { - x = w>>2; - do { - int32 Cb = pp[16]; - int32 Cr = pp[17]; - - YCbCrtoRGB(cp [0], pp[ 0]); - YCbCrtoRGB(cp [1], pp[ 1]); - YCbCrtoRGB(cp [2], pp[ 2]); - YCbCrtoRGB(cp [3], pp[ 3]); - YCbCrtoRGB(cp1[0], pp[ 4]); - YCbCrtoRGB(cp1[1], pp[ 5]); - YCbCrtoRGB(cp1[2], pp[ 6]); - YCbCrtoRGB(cp1[3], pp[ 7]); - YCbCrtoRGB(cp2[0], pp[ 8]); - YCbCrtoRGB(cp2[1], pp[ 9]); + fromskew = (fromskew / 4) * (4 * 2 + 2); + if ((h & 3) == 0 && (w & 3) == 0) + { + for (; h >= 4; h -= 4) + { + x = w >> 2; + do + { + int32_t Cb = pp[16]; + int32_t Cr = pp[17]; + + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + YCbCrtoRGB(cp[2], pp[2]); + YCbCrtoRGB(cp[3], pp[3]); + YCbCrtoRGB(cp1[0], pp[4]); + YCbCrtoRGB(cp1[1], pp[5]); + YCbCrtoRGB(cp1[2], pp[6]); + YCbCrtoRGB(cp1[3], pp[7]); + YCbCrtoRGB(cp2[0], pp[8]); + YCbCrtoRGB(cp2[1], pp[9]); YCbCrtoRGB(cp2[2], pp[10]); YCbCrtoRGB(cp2[3], pp[11]); YCbCrtoRGB(cp3[0], pp[12]); @@ -1658,53 +2100,92 @@ DECLAREContigPutFunc(putcontig8bitYCbCr44tile) YCbCrtoRGB(cp3[2], pp[14]); YCbCrtoRGB(cp3[3], pp[15]); - cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; + cp += 4; + cp1 += 4; + cp2 += 4; + cp3 += 4; pp += 18; } while (--x); - cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + cp += incr; + cp1 += incr; + cp2 += incr; + cp3 += incr; pp += fromskew; } - } else { - while (h > 0) { - for (x = w; x > 0;) { - int32 Cb = pp[16]; - int32 Cr = pp[17]; - switch (x) { - default: - switch (h) { - default: YCbCrtoRGB(cp3[3], pp[15]); /* FALLTHROUGH */ - case 3: YCbCrtoRGB(cp2[3], pp[11]); /* FALLTHROUGH */ - case 2: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ - case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ - } /* FALLTHROUGH */ - case 3: - switch (h) { - default: YCbCrtoRGB(cp3[2], pp[14]); /* FALLTHROUGH */ - case 3: YCbCrtoRGB(cp2[2], pp[10]); /* FALLTHROUGH */ - case 2: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ - case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ - } /* FALLTHROUGH */ - case 2: - switch (h) { - default: YCbCrtoRGB(cp3[1], pp[13]); /* FALLTHROUGH */ - case 3: YCbCrtoRGB(cp2[1], pp[ 9]); /* FALLTHROUGH */ - case 2: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ - case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ - } /* FALLTHROUGH */ - case 1: - switch (h) { - default: YCbCrtoRGB(cp3[0], pp[12]); /* FALLTHROUGH */ - case 3: YCbCrtoRGB(cp2[0], pp[ 8]); /* FALLTHROUGH */ - case 2: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ - case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ - } /* FALLTHROUGH */ + } + else + { + while (h > 0) + { + for (x = w; x > 0;) + { + int32_t Cb = pp[16]; + int32_t Cr = pp[17]; + switch (x) + { + default: + switch (h) + { + default: + YCbCrtoRGB(cp3[3], pp[15]); /* FALLTHROUGH */ + case 3: + YCbCrtoRGB(cp2[3], pp[11]); /* FALLTHROUGH */ + case 2: + YCbCrtoRGB(cp1[3], pp[7]); /* FALLTHROUGH */ + case 1: + YCbCrtoRGB(cp[3], pp[3]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 3: + switch (h) + { + default: + YCbCrtoRGB(cp3[2], pp[14]); /* FALLTHROUGH */ + case 3: + YCbCrtoRGB(cp2[2], pp[10]); /* FALLTHROUGH */ + case 2: + YCbCrtoRGB(cp1[2], pp[6]); /* FALLTHROUGH */ + case 1: + YCbCrtoRGB(cp[2], pp[2]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 2: + switch (h) + { + default: + YCbCrtoRGB(cp3[1], pp[13]); /* FALLTHROUGH */ + case 3: + YCbCrtoRGB(cp2[1], pp[9]); /* FALLTHROUGH */ + case 2: + YCbCrtoRGB(cp1[1], pp[5]); /* FALLTHROUGH */ + case 1: + YCbCrtoRGB(cp[1], pp[1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) + { + default: + YCbCrtoRGB(cp3[0], pp[12]); /* FALLTHROUGH */ + case 3: + YCbCrtoRGB(cp2[0], pp[8]); /* FALLTHROUGH */ + case 2: + YCbCrtoRGB(cp1[0], pp[4]); /* FALLTHROUGH */ + case 1: + YCbCrtoRGB(cp[0], pp[0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ } - if (x < 4) { - cp += x; cp1 += x; cp2 += x; cp3 += x; + if (x < 4) + { + cp += x; + cp1 += x; + cp2 += x; + cp3 += x; x = 0; } - else { - cp += 4; cp1 += 4; cp2 += 4; cp3 += 4; + else + { + cp += 4; + cp1 += 4; + cp2 += 4; + cp3 += 4; x -= 4; } pp += 18; @@ -1712,7 +2193,10 @@ DECLAREContigPutFunc(putcontig8bitYCbCr44tile) if (h <= 4) break; h -= 4; - cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + cp += incr; + cp1 += incr; + cp2 += incr; + cp3 += incr; pp += fromskew; } } @@ -1723,66 +2207,92 @@ DECLAREContigPutFunc(putcontig8bitYCbCr44tile) */ DECLAREContigPutFunc(putcontig8bitYCbCr42tile) { - uint32* cp1 = cp+w+toskew; - int32 incr = 2*toskew+w; - - (void) y; - fromskew = (fromskew * 10) / 4; - if ((h & 3) == 0 && (w & 1) == 0) { - for (; h >= 2; h -= 2) { - x = w>>2; - do { - int32 Cb = pp[8]; - int32 Cr = pp[9]; - - YCbCrtoRGB(cp [0], pp[0]); - YCbCrtoRGB(cp [1], pp[1]); - YCbCrtoRGB(cp [2], pp[2]); - YCbCrtoRGB(cp [3], pp[3]); + uint32_t *cp1 = cp + w + toskew; + int32_t incr = 2 * toskew + w; + + (void)y; + fromskew = (fromskew / 4) * (4 * 2 + 2); + if ((w & 3) == 0 && (h & 1) == 0) + { + for (; h >= 2; h -= 2) + { + x = w >> 2; + do + { + int32_t Cb = pp[8]; + int32_t Cr = pp[9]; + + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + YCbCrtoRGB(cp[2], pp[2]); + YCbCrtoRGB(cp[3], pp[3]); YCbCrtoRGB(cp1[0], pp[4]); YCbCrtoRGB(cp1[1], pp[5]); YCbCrtoRGB(cp1[2], pp[6]); YCbCrtoRGB(cp1[3], pp[7]); - - cp += 4, cp1 += 4; + + cp += 4; + cp1 += 4; pp += 10; } while (--x); - cp += incr, cp1 += incr; + cp += incr; + cp1 += incr; pp += fromskew; } - } else { - while (h > 0) { - for (x = w; x > 0;) { - int32 Cb = pp[8]; - int32 Cr = pp[9]; - switch (x) { - default: - switch (h) { - default: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ - case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ - } /* FALLTHROUGH */ - case 3: - switch (h) { - default: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ - case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ - } /* FALLTHROUGH */ - case 2: - switch (h) { - default: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ - case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ - } /* FALLTHROUGH */ - case 1: - switch (h) { - default: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ - case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ - } /* FALLTHROUGH */ + } + else + { + while (h > 0) + { + for (x = w; x > 0;) + { + int32_t Cb = pp[8]; + int32_t Cr = pp[9]; + switch (x) + { + default: + switch (h) + { + default: + YCbCrtoRGB(cp1[3], pp[7]); /* FALLTHROUGH */ + case 1: + YCbCrtoRGB(cp[3], pp[3]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 3: + switch (h) + { + default: + YCbCrtoRGB(cp1[2], pp[6]); /* FALLTHROUGH */ + case 1: + YCbCrtoRGB(cp[2], pp[2]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 2: + switch (h) + { + default: + YCbCrtoRGB(cp1[1], pp[5]); /* FALLTHROUGH */ + case 1: + YCbCrtoRGB(cp[1], pp[1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) + { + default: + YCbCrtoRGB(cp1[0], pp[4]); /* FALLTHROUGH */ + case 1: + YCbCrtoRGB(cp[0], pp[0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ } - if (x < 4) { - cp += x; cp1 += x; + if (x < 4) + { + cp += x; + cp1 += x; x = 0; } - else { - cp += 4; cp1 += 4; + else + { + cp += 4; + cp1 += 4; x -= 4; } pp += 10; @@ -1790,7 +2300,8 @@ DECLAREContigPutFunc(putcontig8bitYCbCr42tile) if (h <= 2) break; h -= 2; - cp += incr, cp1 += incr; + cp += incr; + cp1 += incr; pp += fromskew; } } @@ -1801,43 +2312,50 @@ DECLAREContigPutFunc(putcontig8bitYCbCr42tile) */ DECLAREContigPutFunc(putcontig8bitYCbCr41tile) { - (void) y; - /* XXX adjust fromskew */ - do { - x = w>>2; - do { - int32 Cb = pp[4]; - int32 Cr = pp[5]; + (void)y; + fromskew = (fromskew / 4) * (4 * 1 + 2); + do + { + x = w >> 2; + while (x > 0) + { + int32_t Cb = pp[4]; + int32_t Cr = pp[5]; - YCbCrtoRGB(cp [0], pp[0]); - YCbCrtoRGB(cp [1], pp[1]); - YCbCrtoRGB(cp [2], pp[2]); - YCbCrtoRGB(cp [3], pp[3]); + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + YCbCrtoRGB(cp[2], pp[2]); + YCbCrtoRGB(cp[3], pp[3]); - cp += 4; - pp += 6; - } while (--x); + cp += 4; + pp += 6; + x--; + } - if( (w&3) != 0 ) + if ((w & 3) != 0) { - int32 Cb = pp[4]; - int32 Cr = pp[5]; - - switch( (w&3) ) { - case 3: YCbCrtoRGB(cp [2], pp[2]); - case 2: YCbCrtoRGB(cp [1], pp[1]); - case 1: YCbCrtoRGB(cp [0], pp[0]); - case 0: break; + int32_t Cb = pp[4]; + int32_t Cr = pp[5]; + + switch ((w & 3)) + { + case 3: + YCbCrtoRGB(cp[2], pp[2]); /*-fallthrough*/ + case 2: + YCbCrtoRGB(cp[1], pp[1]); /*-fallthrough*/ + case 1: + YCbCrtoRGB(cp[0], pp[0]); /*-fallthrough*/ + case 0: + break; } - cp += (w&3); + cp += (w & 3); pp += 6; } - cp += toskew; - pp += fromskew; + cp += toskew; + pp += fromskew; } while (--h); - } /* @@ -1845,56 +2363,63 @@ DECLAREContigPutFunc(putcontig8bitYCbCr41tile) */ DECLAREContigPutFunc(putcontig8bitYCbCr22tile) { - uint32* cp2; - (void) y; - fromskew = (fromskew / 2) * 6; - cp2 = cp+w+toskew; - while (h>=2) { - x = w; - while (x>=2) { - uint32 Cb = pp[4]; - uint32 Cr = pp[5]; - YCbCrtoRGB(cp[0], pp[0]); - YCbCrtoRGB(cp[1], pp[1]); - YCbCrtoRGB(cp2[0], pp[2]); - YCbCrtoRGB(cp2[1], pp[3]); - cp += 2; - cp2 += 2; - pp += 6; - x -= 2; - } - if (x==1) { - uint32 Cb = pp[4]; - uint32 Cr = pp[5]; - YCbCrtoRGB(cp[0], pp[0]); - YCbCrtoRGB(cp2[0], pp[2]); - cp ++ ; - cp2 ++ ; - pp += 6; - } - cp += toskew*2+w; - cp2 += toskew*2+w; - pp += fromskew; - h-=2; - } - if (h==1) { - x = w; - while (x>=2) { - uint32 Cb = pp[4]; - uint32 Cr = pp[5]; - YCbCrtoRGB(cp[0], pp[0]); - YCbCrtoRGB(cp[1], pp[1]); - cp += 2; - cp2 += 2; - pp += 6; - x -= 2; - } - if (x==1) { - uint32 Cb = pp[4]; - uint32 Cr = pp[5]; - YCbCrtoRGB(cp[0], pp[0]); - } - } + uint32_t *cp2; + int32_t incr = 2 * toskew + w; + (void)y; + fromskew = (fromskew / 2) * (2 * 2 + 2); + cp2 = cp + w + toskew; + while (h >= 2) + { + x = w; + while (x >= 2) + { + uint32_t Cb = pp[4]; + uint32_t Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + YCbCrtoRGB(cp2[0], pp[2]); + YCbCrtoRGB(cp2[1], pp[3]); + cp += 2; + cp2 += 2; + pp += 6; + x -= 2; + } + if (x == 1) + { + uint32_t Cb = pp[4]; + uint32_t Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp2[0], pp[2]); + cp++; + cp2++; + pp += 6; + } + cp += incr; + cp2 += incr; + pp += fromskew; + h -= 2; + } + if (h == 1) + { + x = w; + while (x >= 2) + { + uint32_t Cb = pp[4]; + uint32_t Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + cp += 2; + cp2 += 2; + pp += 6; + x -= 2; + } + if (x == 1) + { + uint32_t Cb = pp[4]; + uint32_t Cr = pp[5]; + YCbCrtoRGB(cp[0], pp[0]); + } + } } /* @@ -1902,35 +2427,38 @@ DECLAREContigPutFunc(putcontig8bitYCbCr22tile) */ DECLAREContigPutFunc(putcontig8bitYCbCr21tile) { - (void) y; - fromskew = (fromskew * 4) / 2; - do { - x = w>>1; - do { - int32 Cb = pp[2]; - int32 Cr = pp[3]; + (void)y; + fromskew = (fromskew / 2) * (2 * 1 + 2); + do + { + x = w >> 1; + while (x > 0) + { + int32_t Cb = pp[2]; + int32_t Cr = pp[3]; - YCbCrtoRGB(cp[0], pp[0]); - YCbCrtoRGB(cp[1], pp[1]); + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); - cp += 2; - pp += 4; - } while (--x); + cp += 2; + pp += 4; + x--; + } - if( (w&1) != 0 ) - { - int32 Cb = pp[2]; - int32 Cr = pp[3]; + if ((w & 1) != 0) + { + int32_t Cb = pp[2]; + int32_t Cr = pp[3]; - YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[0], pp[0]); - cp += 1; - pp += 4; - } + cp += 1; + pp += 4; + } - cp += toskew; - pp += fromskew; - } while (--h); + cp += toskew; + pp += fromskew; + } while (--h); } /* @@ -1938,36 +2466,41 @@ DECLAREContigPutFunc(putcontig8bitYCbCr21tile) */ DECLAREContigPutFunc(putcontig8bitYCbCr12tile) { - uint32* cp2; - (void) y; - fromskew = (fromskew / 2) * 4; - cp2 = cp+w+toskew; - while (h>=2) { - x = w; - do { - uint32 Cb = pp[2]; - uint32 Cr = pp[3]; - YCbCrtoRGB(cp[0], pp[0]); - YCbCrtoRGB(cp2[0], pp[1]); - cp ++; - cp2 ++; - pp += 4; - } while (--x); - cp += toskew*2+w; - cp2 += toskew*2+w; - pp += fromskew; - h-=2; - } - if (h==1) { - x = w; - do { - uint32 Cb = pp[2]; - uint32 Cr = pp[3]; - YCbCrtoRGB(cp[0], pp[0]); - cp ++; - pp += 4; - } while (--x); - } + uint32_t *cp2; + int32_t incr = 2 * toskew + w; + (void)y; + fromskew = (fromskew / 1) * (1 * 2 + 2); + cp2 = cp + w + toskew; + while (h >= 2) + { + x = w; + do + { + uint32_t Cb = pp[2]; + uint32_t Cr = pp[3]; + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp2[0], pp[1]); + cp++; + cp2++; + pp += 4; + } while (--x); + cp += incr; + cp2 += incr; + pp += fromskew; + h -= 2; + } + if (h == 1) + { + x = w; + do + { + uint32_t Cb = pp[2]; + uint32_t Cr = pp[3]; + YCbCrtoRGB(cp[0], pp[0]); + cp++; + pp += 4; + } while (--x); + } } /* @@ -1975,21 +2508,23 @@ DECLAREContigPutFunc(putcontig8bitYCbCr12tile) */ DECLAREContigPutFunc(putcontig8bitYCbCr11tile) { - (void) y; - fromskew *= 3; - do { - x = w; /* was x = w>>1; patched 2000/09/25 warmerda@home.com */ - do { - int32 Cb = pp[1]; - int32 Cr = pp[2]; + (void)y; + fromskew = (fromskew / 1) * (1 * 1 + 2); + do + { + x = w; /* was x = w>>1; patched 2000/09/25 warmerda@home.com */ + do + { + int32_t Cb = pp[1]; + int32_t Cr = pp[2]; - YCbCrtoRGB(*cp++, pp[0]); + YCbCrtoRGB(*cp++, pp[0]); - pp += 3; - } while (--x); - cp += toskew; - pp += fromskew; - } while (--h); + pp += 3; + } while (--x); + cp += toskew; + pp += fromskew; + } while (--h); } /* @@ -1997,82 +2532,124 @@ DECLAREContigPutFunc(putcontig8bitYCbCr11tile) */ DECLARESepPutFunc(putseparate8bitYCbCr11tile) { - (void) y; - (void) a; - /* TODO: naming of input vars is still off, change obfuscating declaration inside define, or resolve obfuscation */ - while (h-- > 0) { - x = w; - do { - uint32 dr, dg, db; - TIFFYCbCrtoRGB(img->ycbcr,*r++,*g++,*b++,&dr,&dg,&db); - *cp++ = PACK(dr,dg,db); - } while (--x); - SKEW(r, g, b, fromskew); - cp += toskew; - } + (void)y; + (void)a; + /* TODO: naming of input vars is still off, change obfuscating declaration + * inside define, or resolve obfuscation */ + for (; h > 0; --h) + { + x = w; + do + { + uint32_t dr, dg, db; + TIFFYCbCrtoRGB(img->ycbcr, *r++, *g++, *b++, &dr, &dg, &db); + *cp++ = PACK(dr, dg, db); + } while (--x); + SKEW(r, g, b, fromskew); + cp += toskew; + } } #undef YCbCrtoRGB -static int -initYCbCrConversion(TIFFRGBAImage* img) -{ - static char module[] = "initYCbCrConversion"; - - float *luma, *refBlackWhite; - - if (img->ycbcr == NULL) { - img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc( - TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)) - + 4*256*sizeof (TIFFRGBValue) - + 2*256*sizeof (int) - + 3*256*sizeof (int32) - ); - if (img->ycbcr == NULL) { - TIFFErrorExt(img->tif->tif_clientdata, module, - "No space for YCbCr->RGB conversion state"); - return (0); - } - } - - TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma); - TIFFGetFieldDefaulted(img->tif, TIFFTAG_REFERENCEBLACKWHITE, - &refBlackWhite); - if (TIFFYCbCrToRGBInit(img->ycbcr, luma, refBlackWhite) < 0) - return(0); - return (1); -} - -static tileContigRoutine -initCIELabConversion(TIFFRGBAImage* img) -{ - static char module[] = "initCIELabConversion"; - - float *whitePoint; - float refWhite[3]; - - if (!img->cielab) { - img->cielab = (TIFFCIELabToRGB *) - _TIFFmalloc(sizeof(TIFFCIELabToRGB)); - if (!img->cielab) { - TIFFErrorExt(img->tif->tif_clientdata, module, - "No space for CIE L*a*b*->RGB conversion state."); - return NULL; - } - } - - TIFFGetFieldDefaulted(img->tif, TIFFTAG_WHITEPOINT, &whitePoint); - refWhite[1] = 100.0F; - refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1]; - refWhite[2] = (1.0F - whitePoint[0] - whitePoint[1]) - / whitePoint[1] * refWhite[1]; - if (TIFFCIELabToRGBInit(img->cielab, &display_sRGB, refWhite) < 0) { - TIFFErrorExt(img->tif->tif_clientdata, module, - "Failed to initialize CIE L*a*b*->RGB conversion state."); - _TIFFfree(img->cielab); - return NULL; - } - - return putcontig8bitCIELab; +static int isInRefBlackWhiteRange(float f) +{ + return f > (float)(-0x7FFFFFFF + 128) && f < (float)0x7FFFFFFF; +} + +static int initYCbCrConversion(TIFFRGBAImage *img) +{ + static const char module[] = "initYCbCrConversion"; + + float *luma, *refBlackWhite; + + if (img->ycbcr == NULL) + { + img->ycbcr = (TIFFYCbCrToRGB *)_TIFFmallocExt( + img->tif, TIFFroundup_32(sizeof(TIFFYCbCrToRGB), sizeof(long)) + + 4 * 256 * sizeof(TIFFRGBValue) + + 2 * 256 * sizeof(int) + 3 * 256 * sizeof(int32_t)); + if (img->ycbcr == NULL) + { + TIFFErrorExtR(img->tif, module, + "No space for YCbCr->RGB conversion state"); + return (0); + } + } + + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma); + TIFFGetFieldDefaulted(img->tif, TIFFTAG_REFERENCEBLACKWHITE, + &refBlackWhite); + + /* Do some validation to avoid later issues. Detect NaN for now */ + /* and also if lumaGreen is zero since we divide by it later */ + if (luma[0] != luma[0] || luma[1] != luma[1] || luma[1] == 0.0 || + luma[2] != luma[2]) + { + TIFFErrorExtR(img->tif, module, + "Invalid values for YCbCrCoefficients tag"); + return (0); + } + + if (!isInRefBlackWhiteRange(refBlackWhite[0]) || + !isInRefBlackWhiteRange(refBlackWhite[1]) || + !isInRefBlackWhiteRange(refBlackWhite[2]) || + !isInRefBlackWhiteRange(refBlackWhite[3]) || + !isInRefBlackWhiteRange(refBlackWhite[4]) || + !isInRefBlackWhiteRange(refBlackWhite[5])) + { + TIFFErrorExtR(img->tif, module, + "Invalid values for ReferenceBlackWhite tag"); + return (0); + } + + if (TIFFYCbCrToRGBInit(img->ycbcr, luma, refBlackWhite) < 0) + return (0); + return (1); +} + +static tileContigRoutine initCIELabConversion(TIFFRGBAImage *img) +{ + static const char module[] = "initCIELabConversion"; + + float *whitePoint; + float refWhite[3]; + + TIFFGetFieldDefaulted(img->tif, TIFFTAG_WHITEPOINT, &whitePoint); + if (whitePoint[1] == 0.0f) + { + TIFFErrorExtR(img->tif, module, "Invalid value for WhitePoint tag."); + return NULL; + } + + if (!img->cielab) + { + img->cielab = (TIFFCIELabToRGB *)_TIFFmallocExt( + img->tif, sizeof(TIFFCIELabToRGB)); + if (!img->cielab) + { + TIFFErrorExtR(img->tif, module, + "No space for CIE L*a*b*->RGB conversion state."); + return NULL; + } + } + + refWhite[1] = 100.0F; + refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1]; + refWhite[2] = + (1.0F - whitePoint[0] - whitePoint[1]) / whitePoint[1] * refWhite[1]; + if (TIFFCIELabToRGBInit(img->cielab, &display_sRGB, refWhite) < 0) + { + TIFFErrorExtR(img->tif, module, + "Failed to initialize CIE L*a*b*->RGB conversion state."); + _TIFFfreeExt(img->tif, img->cielab); + return NULL; + } + + if (img->bitspersample == 8) + return putcontig8bitCIELab8; + else if (img->bitspersample == 16) + return putcontig8bitCIELab16; + return NULL; } /* @@ -2082,56 +2659,62 @@ initCIELabConversion(TIFFRGBAImage* img) * pixel values simply by indexing into the table with one * number. */ -static int -makebwmap(TIFFRGBAImage* img) +static int makebwmap(TIFFRGBAImage *img) { - TIFFRGBValue* Map = img->Map; + TIFFRGBValue *Map = img->Map; int bitspersample = img->bitspersample; int nsamples = 8 / bitspersample; int i; - uint32* p; + uint32_t *p; - if( nsamples == 0 ) + if (nsamples == 0) nsamples = 1; - img->BWmap = (uint32**) _TIFFmalloc( - 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); - if (img->BWmap == NULL) { - TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for B&W mapping table"); - return (0); - } - p = (uint32*)(img->BWmap + 256); - for (i = 0; i < 256; i++) { - TIFFRGBValue c; - img->BWmap[i] = p; - switch (bitspersample) { -#define GREY(x) c = Map[x]; *p++ = PACK(c,c,c); - case 1: - GREY(i>>7); - GREY((i>>6)&1); - GREY((i>>5)&1); - GREY((i>>4)&1); - GREY((i>>3)&1); - GREY((i>>2)&1); - GREY((i>>1)&1); - GREY(i&1); - break; - case 2: - GREY(i>>6); - GREY((i>>4)&3); - GREY((i>>2)&3); - GREY(i&3); - break; - case 4: - GREY(i>>4); - GREY(i&0xf); - break; - case 8: - case 16: - GREY(i); - break; - } -#undef GREY + img->BWmap = (uint32_t **)_TIFFmallocExt( + img->tif, + 256 * sizeof(uint32_t *) + (256 * nsamples * sizeof(uint32_t))); + if (img->BWmap == NULL) + { + TIFFErrorExtR(img->tif, TIFFFileName(img->tif), + "No space for B&W mapping table"); + return (0); + } + p = (uint32_t *)(img->BWmap + 256); + for (i = 0; i < 256; i++) + { + TIFFRGBValue c; + img->BWmap[i] = p; + switch (bitspersample) + { +#define GREY(x) \ + c = Map[x]; \ + *p++ = PACK(c, c, c); + case 1: + GREY(i >> 7); + GREY((i >> 6) & 1); + GREY((i >> 5) & 1); + GREY((i >> 4) & 1); + GREY((i >> 3) & 1); + GREY((i >> 2) & 1); + GREY((i >> 1) & 1); + GREY(i & 1); + break; + case 2: + GREY(i >> 6); + GREY((i >> 4) & 3); + GREY((i >> 2) & 3); + GREY(i & 3); + break; + case 4: + GREY(i >> 4); + GREY(i & 0xf); + break; + case 8: + case 16: + GREY(i); + break; + } +#undef GREY } return (1); } @@ -2140,74 +2723,79 @@ makebwmap(TIFFRGBAImage* img) * Construct a mapping table to convert from the range * of the data samples to [0,255] --for display. This * process also handles inverting B&W images when needed. - */ -static int -setupMap(TIFFRGBAImage* img) + */ +static int setupMap(TIFFRGBAImage *img) { - int32 x, range; + int32_t x, range; + + range = (int32_t)((1L << img->bitspersample) - 1); - range = (int32)((1L<bitspersample)-1); - /* treat 16 bit the same as eight bit */ - if( img->bitspersample == 16 ) - range = (int32) 255; - - img->Map = (TIFFRGBValue*) _TIFFmalloc((range+1) * sizeof (TIFFRGBValue)); - if (img->Map == NULL) { - TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), - "No space for photometric conversion table"); - return (0); - } - if (img->photometric == PHOTOMETRIC_MINISWHITE) { - for (x = 0; x <= range; x++) - img->Map[x] = (TIFFRGBValue) (((range - x) * 255) / range); - } else { - for (x = 0; x <= range; x++) - img->Map[x] = (TIFFRGBValue) ((x * 255) / range); + if (img->bitspersample == 16) + range = (int32_t)255; + + img->Map = (TIFFRGBValue *)_TIFFmallocExt( + img->tif, (range + 1) * sizeof(TIFFRGBValue)); + if (img->Map == NULL) + { + TIFFErrorExtR(img->tif, TIFFFileName(img->tif), + "No space for photometric conversion table"); + return (0); + } + if (img->photometric == PHOTOMETRIC_MINISWHITE) + { + for (x = 0; x <= range; x++) + img->Map[x] = (TIFFRGBValue)(((range - x) * 255) / range); + } + else + { + for (x = 0; x <= range; x++) + img->Map[x] = (TIFFRGBValue)((x * 255) / range); } if (img->bitspersample <= 16 && - (img->photometric == PHOTOMETRIC_MINISBLACK || - img->photometric == PHOTOMETRIC_MINISWHITE)) { - /* - * Use photometric mapping table to construct - * unpacking tables for samples <= 8 bits. - */ - if (!makebwmap(img)) - return (0); - /* no longer need Map, free it */ - _TIFFfree(img->Map), img->Map = NULL; + (img->photometric == PHOTOMETRIC_MINISBLACK || + img->photometric == PHOTOMETRIC_MINISWHITE)) + { + /* + * Use photometric mapping table to construct + * unpacking tables for samples <= 8 bits. + */ + if (!makebwmap(img)) + return (0); + /* no longer need Map, free it */ + _TIFFfreeExt(img->tif, img->Map); + img->Map = NULL; } return (1); } -static int -checkcmap(TIFFRGBAImage* img) +static int checkcmap(TIFFRGBAImage *img) { - uint16* r = img->redcmap; - uint16* g = img->greencmap; - uint16* b = img->bluecmap; - long n = 1L<bitspersample; + uint16_t *r = img->redcmap; + uint16_t *g = img->greencmap; + uint16_t *b = img->bluecmap; + long n = 1L << img->bitspersample; while (n-- > 0) - if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) - return (16); + if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) + return (16); return (8); } -static void -cvtcmap(TIFFRGBAImage* img) +static void cvtcmap(TIFFRGBAImage *img) { - uint16* r = img->redcmap; - uint16* g = img->greencmap; - uint16* b = img->bluecmap; + uint16_t *r = img->redcmap; + uint16_t *g = img->greencmap; + uint16_t *b = img->bluecmap; long i; - for (i = (1L<bitspersample)-1; i >= 0; i--) { -#define CVT(x) ((uint16)((x)>>8)) - r[i] = CVT(r[i]); - g[i] = CVT(g[i]); - b[i] = CVT(b[i]); -#undef CVT + for (i = (1L << img->bitspersample) - 1; i >= 0; i--) + { +#define CVT(x) ((uint16_t)((x) >> 8)) + r[i] = CVT(r[i]); + g[i] = CVT(g[i]); + b[i] = CVT(b[i]); +#undef CVT } } @@ -2218,93 +2806,100 @@ cvtcmap(TIFFRGBAImage* img) * pixel values simply by indexing into the table with one * number. */ -static int -makecmap(TIFFRGBAImage* img) +static int makecmap(TIFFRGBAImage *img) { int bitspersample = img->bitspersample; int nsamples = 8 / bitspersample; - uint16* r = img->redcmap; - uint16* g = img->greencmap; - uint16* b = img->bluecmap; - uint32 *p; + uint16_t *r = img->redcmap; + uint16_t *g = img->greencmap; + uint16_t *b = img->bluecmap; + uint32_t *p; int i; - img->PALmap = (uint32**) _TIFFmalloc( - 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); - if (img->PALmap == NULL) { - TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for Palette mapping table"); - return (0); - } - p = (uint32*)(img->PALmap + 256); - for (i = 0; i < 256; i++) { - TIFFRGBValue c; - img->PALmap[i] = p; -#define CMAP(x) c = (TIFFRGBValue) x; *p++ = PACK(r[c]&0xff, g[c]&0xff, b[c]&0xff); - switch (bitspersample) { - case 1: - CMAP(i>>7); - CMAP((i>>6)&1); - CMAP((i>>5)&1); - CMAP((i>>4)&1); - CMAP((i>>3)&1); - CMAP((i>>2)&1); - CMAP((i>>1)&1); - CMAP(i&1); - break; - case 2: - CMAP(i>>6); - CMAP((i>>4)&3); - CMAP((i>>2)&3); - CMAP(i&3); - break; - case 4: - CMAP(i>>4); - CMAP(i&0xf); - break; - case 8: - CMAP(i); - break; - } + img->PALmap = (uint32_t **)_TIFFmallocExt( + img->tif, + 256 * sizeof(uint32_t *) + (256 * nsamples * sizeof(uint32_t))); + if (img->PALmap == NULL) + { + TIFFErrorExtR(img->tif, TIFFFileName(img->tif), + "No space for Palette mapping table"); + return (0); + } + p = (uint32_t *)(img->PALmap + 256); + for (i = 0; i < 256; i++) + { + TIFFRGBValue c; + img->PALmap[i] = p; +#define CMAP(x) \ + c = (TIFFRGBValue)x; \ + *p++ = PACK(r[c] & 0xff, g[c] & 0xff, b[c] & 0xff); + switch (bitspersample) + { + case 1: + CMAP(i >> 7); + CMAP((i >> 6) & 1); + CMAP((i >> 5) & 1); + CMAP((i >> 4) & 1); + CMAP((i >> 3) & 1); + CMAP((i >> 2) & 1); + CMAP((i >> 1) & 1); + CMAP(i & 1); + break; + case 2: + CMAP(i >> 6); + CMAP((i >> 4) & 3); + CMAP((i >> 2) & 3); + CMAP(i & 3); + break; + case 4: + CMAP(i >> 4); + CMAP(i & 0xf); + break; + case 8: + CMAP(i); + break; + } #undef CMAP } return (1); } -/* +/* * Construct any mapping table used * by the associated put routine. */ -static int -buildMap(TIFFRGBAImage* img) -{ - switch (img->photometric) { - case PHOTOMETRIC_RGB: - case PHOTOMETRIC_YCBCR: - case PHOTOMETRIC_SEPARATED: - if (img->bitspersample == 8) - break; - /* fall thru... */ - case PHOTOMETRIC_MINISBLACK: - case PHOTOMETRIC_MINISWHITE: - if (!setupMap(img)) - return (0); - break; - case PHOTOMETRIC_PALETTE: - /* - * Convert 16-bit colormap to 8-bit (unless it looks - * like an old-style 8-bit colormap). - */ - if (checkcmap(img) == 16) - cvtcmap(img); - else - TIFFWarningExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "Assuming 8-bit colormap"); - /* - * Use mapping table and colormap to construct - * unpacking tables for samples < 8 bits. - */ - if (img->bitspersample <= 8 && !makecmap(img)) - return (0); - break; +static int buildMap(TIFFRGBAImage *img) +{ + switch (img->photometric) + { + case PHOTOMETRIC_RGB: + case PHOTOMETRIC_YCBCR: + case PHOTOMETRIC_SEPARATED: + if (img->bitspersample == 8) + break; + /* fall through... */ + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_MINISWHITE: + if (!setupMap(img)) + return (0); + break; + case PHOTOMETRIC_PALETTE: + /* + * Convert 16-bit colormap to 8-bit (unless it looks + * like an old-style 8-bit colormap). + */ + if (checkcmap(img) == 16) + cvtcmap(img); + else + TIFFWarningExtR(img->tif, TIFFFileName(img->tif), + "Assuming 8-bit colormap"); + /* + * Use mapping table and colormap to construct + * unpacking tables for samples < 8 bits. + */ + if (img->bitspersample <= 8 && !makecmap(img)) + return (0); + break; } return (1); } @@ -2312,141 +2907,162 @@ buildMap(TIFFRGBAImage* img) /* * Select the appropriate conversion routine for packed data. */ -static int -PickContigCase(TIFFRGBAImage* img) -{ - img->get = TIFFIsTiled(img->tif) ? gtTileContig : gtStripContig; - img->put.contig = NULL; - switch (img->photometric) { - case PHOTOMETRIC_RGB: - switch (img->bitspersample) { - case 8: - if (img->alpha == EXTRASAMPLE_ASSOCALPHA) - img->put.contig = putRGBAAcontig8bittile; - else if (img->alpha == EXTRASAMPLE_UNASSALPHA) - { - img->put.contig = putRGBUAcontig8bittile; - } - else - img->put.contig = putRGBcontig8bittile; - break; - case 16: - if (img->alpha == EXTRASAMPLE_ASSOCALPHA) - { - img->put.contig = putRGBAAcontig16bittile; - } - else if (img->alpha == EXTRASAMPLE_UNASSALPHA) - { - img->put.contig = putRGBUAcontig16bittile; - } - else - { - img->put.contig = putRGBcontig16bittile; - } - break; - } - break; - case PHOTOMETRIC_SEPARATED: - if (buildMap(img)) { - if (img->bitspersample == 8) { - if (!img->Map) - img->put.contig = putRGBcontig8bitCMYKtile; - else - img->put.contig = putRGBcontig8bitCMYKMaptile; - } - } - break; - case PHOTOMETRIC_PALETTE: - if (buildMap(img)) { - switch (img->bitspersample) { - case 8: - img->put.contig = put8bitcmaptile; - break; - case 4: - img->put.contig = put4bitcmaptile; - break; - case 2: - img->put.contig = put2bitcmaptile; - break; - case 1: - img->put.contig = put1bitcmaptile; - break; - } - } - break; - case PHOTOMETRIC_MINISWHITE: - case PHOTOMETRIC_MINISBLACK: - if (buildMap(img)) { - switch (img->bitspersample) { - case 16: - img->put.contig = put16bitbwtile; - break; - case 8: - img->put.contig = putgreytile; - break; - case 4: - img->put.contig = put4bitbwtile; - break; - case 2: - img->put.contig = put2bitbwtile; - break; - case 1: - img->put.contig = put1bitbwtile; - break; - } - } - break; - case PHOTOMETRIC_YCBCR: - if (img->bitspersample == 8) - { - if (initYCbCrConversion(img)!=0) - { - /* - * The 6.0 spec says that subsampling must be - * one of 1, 2, or 4, and that vertical subsampling - * must always be <= horizontal subsampling; so - * there are only a few possibilities and we just - * enumerate the cases. - * Joris: added support for the [1,2] case, nonetheless, to accomodate - * some OJPEG files - */ - uint16 SubsamplingHor; - uint16 SubsamplingVer; - TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &SubsamplingHor, &SubsamplingVer); - switch ((SubsamplingHor<<4)|SubsamplingVer) { - case 0x44: - img->put.contig = putcontig8bitYCbCr44tile; - break; - case 0x42: - img->put.contig = putcontig8bitYCbCr42tile; - break; - case 0x41: - img->put.contig = putcontig8bitYCbCr41tile; - break; - case 0x22: - img->put.contig = putcontig8bitYCbCr22tile; - break; - case 0x21: - img->put.contig = putcontig8bitYCbCr21tile; - break; - case 0x12: - img->put.contig = putcontig8bitYCbCr12tile; - break; - case 0x11: - img->put.contig = putcontig8bitYCbCr11tile; - break; - } - } - } - break; - case PHOTOMETRIC_CIELAB: - if (buildMap(img)) { - if (img->bitspersample == 8) - img->put.contig = initCIELabConversion(img); - break; - } - } - return ((img->get!=NULL) && (img->put.contig!=NULL)); +static int PickContigCase(TIFFRGBAImage *img) +{ + img->get = TIFFIsTiled(img->tif) ? gtTileContig : gtStripContig; + img->put.contig = NULL; + switch (img->photometric) + { + case PHOTOMETRIC_RGB: + switch (img->bitspersample) + { + case 8: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA && + img->samplesperpixel >= 4) + img->put.contig = putRGBAAcontig8bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA && + img->samplesperpixel >= 4) + { + if (BuildMapUaToAa(img)) + img->put.contig = putRGBUAcontig8bittile; + } + else if (img->samplesperpixel >= 3) + img->put.contig = putRGBcontig8bittile; + break; + case 16: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA && + img->samplesperpixel >= 4) + { + if (BuildMapBitdepth16To8(img)) + img->put.contig = putRGBAAcontig16bittile; + } + else if (img->alpha == EXTRASAMPLE_UNASSALPHA && + img->samplesperpixel >= 4) + { + if (BuildMapBitdepth16To8(img) && BuildMapUaToAa(img)) + img->put.contig = putRGBUAcontig16bittile; + } + else if (img->samplesperpixel >= 3) + { + if (BuildMapBitdepth16To8(img)) + img->put.contig = putRGBcontig16bittile; + } + break; + } + break; + case PHOTOMETRIC_SEPARATED: + if (img->samplesperpixel >= 4 && buildMap(img)) + { + if (img->bitspersample == 8) + { + if (!img->Map) + img->put.contig = putRGBcontig8bitCMYKtile; + else + img->put.contig = putRGBcontig8bitCMYKMaptile; + } + } + break; + case PHOTOMETRIC_PALETTE: + if (buildMap(img)) + { + switch (img->bitspersample) + { + case 8: + img->put.contig = put8bitcmaptile; + break; + case 4: + img->put.contig = put4bitcmaptile; + break; + case 2: + img->put.contig = put2bitcmaptile; + break; + case 1: + img->put.contig = put1bitcmaptile; + break; + } + } + break; + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + if (buildMap(img)) + { + switch (img->bitspersample) + { + case 16: + img->put.contig = put16bitbwtile; + break; + case 8: + if (img->alpha && img->samplesperpixel == 2) + img->put.contig = putagreytile; + else + img->put.contig = putgreytile; + break; + case 4: + img->put.contig = put4bitbwtile; + break; + case 2: + img->put.contig = put2bitbwtile; + break; + case 1: + img->put.contig = put1bitbwtile; + break; + } + } + break; + case PHOTOMETRIC_YCBCR: + if ((img->bitspersample == 8) && (img->samplesperpixel == 3)) + { + if (initYCbCrConversion(img) != 0) + { + /* + * The 6.0 spec says that subsampling must be + * one of 1, 2, or 4, and that vertical subsampling + * must always be <= horizontal subsampling; so + * there are only a few possibilities and we just + * enumerate the cases. + * Joris: added support for the [1,2] case, nonetheless, to + * accommodate some OJPEG files + */ + uint16_t SubsamplingHor; + uint16_t SubsamplingVer; + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, + &SubsamplingHor, &SubsamplingVer); + switch ((SubsamplingHor << 4) | SubsamplingVer) + { + case 0x44: + img->put.contig = putcontig8bitYCbCr44tile; + break; + case 0x42: + img->put.contig = putcontig8bitYCbCr42tile; + break; + case 0x41: + img->put.contig = putcontig8bitYCbCr41tile; + break; + case 0x22: + img->put.contig = putcontig8bitYCbCr22tile; + break; + case 0x21: + img->put.contig = putcontig8bitYCbCr21tile; + break; + case 0x12: + img->put.contig = putcontig8bitYCbCr12tile; + break; + case 0x11: + img->put.contig = putcontig8bitYCbCr11tile; + break; + } + } + } + break; + case PHOTOMETRIC_CIELAB: + if (img->samplesperpixel == 3 && buildMap(img)) + { + if (img->bitspersample == 8 || img->bitspersample == 16) + img->put.contig = initCIELabConversion(img); + break; + } + } + return ((img->get != NULL) && (img->put.contig != NULL)); } /* @@ -2455,58 +3071,116 @@ PickContigCase(TIFFRGBAImage* img) * NB: we assume that unpacked single channel data is directed * to the "packed routines. */ -static int -PickSeparateCase(TIFFRGBAImage* img) -{ - img->get = TIFFIsTiled(img->tif) ? gtTileSeparate : gtStripSeparate; - img->put.separate = NULL; - switch (img->photometric) { - case PHOTOMETRIC_RGB: - switch (img->bitspersample) { - case 8: - if (img->alpha == EXTRASAMPLE_ASSOCALPHA) - img->put.separate = putRGBAAseparate8bittile; - else if (img->alpha == EXTRASAMPLE_UNASSALPHA) - { - img->put.separate = putRGBUAseparate8bittile; - } - else - img->put.separate = putRGBseparate8bittile; - break; - case 16: - if (img->alpha == EXTRASAMPLE_ASSOCALPHA) - { - img->put.separate = putRGBAAseparate16bittile; - } - else if (img->alpha == EXTRASAMPLE_UNASSALPHA) - { - img->put.separate = putRGBUAseparate16bittile; - } - else - { - img->put.separate = putRGBseparate16bittile; - } - break; - } - break; - case PHOTOMETRIC_YCBCR: - if ((img->bitspersample==8) && (img->samplesperpixel==3)) - { - if (initYCbCrConversion(img)!=0) - { - uint16 hs, vs; - TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs); - switch ((hs<<4)|vs) { - case 0x11: - img->put.separate = putseparate8bitYCbCr11tile; - break; - /* TODO: add other cases here */ - } - } - } - break; - } - return ((img->get!=NULL) && (img->put.separate!=NULL)); +static int PickSeparateCase(TIFFRGBAImage *img) +{ + img->get = TIFFIsTiled(img->tif) ? gtTileSeparate : gtStripSeparate; + img->put.separate = NULL; + switch (img->photometric) + { + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + /* greyscale images processed pretty much as RGB by gtTileSeparate + */ + case PHOTOMETRIC_RGB: + switch (img->bitspersample) + { + case 8: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + img->put.separate = putRGBAAseparate8bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + if (BuildMapUaToAa(img)) + img->put.separate = putRGBUAseparate8bittile; + } + else + img->put.separate = putRGBseparate8bittile; + break; + case 16: + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + { + if (BuildMapBitdepth16To8(img)) + img->put.separate = putRGBAAseparate16bittile; + } + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + { + if (BuildMapBitdepth16To8(img) && BuildMapUaToAa(img)) + img->put.separate = putRGBUAseparate16bittile; + } + else + { + if (BuildMapBitdepth16To8(img)) + img->put.separate = putRGBseparate16bittile; + } + break; + } + break; + case PHOTOMETRIC_SEPARATED: + if (img->bitspersample == 8 && img->samplesperpixel == 4) + { + img->alpha = + 1; // Not alpha, but seems like the only way to get 4th band + img->put.separate = putCMYKseparate8bittile; + } + break; + case PHOTOMETRIC_YCBCR: + if ((img->bitspersample == 8) && (img->samplesperpixel == 3)) + { + if (initYCbCrConversion(img) != 0) + { + uint16_t hs, vs; + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, + &hs, &vs); + switch ((hs << 4) | vs) + { + case 0x11: + img->put.separate = putseparate8bitYCbCr11tile; + break; + /* TODO: add other cases here */ + } + } + } + break; + } + return ((img->get != NULL) && (img->put.separate != NULL)); +} + +static int BuildMapUaToAa(TIFFRGBAImage *img) +{ + static const char module[] = "BuildMapUaToAa"; + uint8_t *m; + uint16_t na, nv; + assert(img->UaToAa == NULL); + img->UaToAa = _TIFFmallocExt(img->tif, 65536); + if (img->UaToAa == NULL) + { + TIFFErrorExtR(img->tif, module, "Out of memory"); + return (0); + } + m = img->UaToAa; + for (na = 0; na < 256; na++) + { + for (nv = 0; nv < 256; nv++) + *m++ = (uint8_t)((nv * na + 127) / 255); + } + return (1); +} + +static int BuildMapBitdepth16To8(TIFFRGBAImage *img) +{ + static const char module[] = "BuildMapBitdepth16To8"; + uint8_t *m; + uint32_t n; + assert(img->Bitdepth16To8 == NULL); + img->Bitdepth16To8 = _TIFFmallocExt(img->tif, 65536); + if (img->Bitdepth16To8 == NULL) + { + TIFFErrorExtR(img->tif, module, "Out of memory"); + return (0); + } + m = img->Bitdepth16To8; + for (n = 0; n < 65536; n++) + *m++ = (uint8_t)((n + 128) / 257); + return (1); } /* @@ -2516,49 +3190,59 @@ PickSeparateCase(TIFFRGBAImage* img) * organized in bottom to top form. */ +int TIFFReadRGBAStrip(TIFF *tif, uint32_t row, uint32_t *raster) + +{ + return TIFFReadRGBAStripExt(tif, row, raster, 0); +} -int -TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster ) +int TIFFReadRGBAStripExt(TIFF *tif, uint32_t row, uint32_t *raster, + int stop_on_error) { - char emsg[1024] = ""; + char emsg[EMSG_BUF_SIZE] = ""; TIFFRGBAImage img; - int ok; - uint32 rowsperstrip, rows_to_read; + int ok; + uint32_t rowsperstrip, rows_to_read; - if( TIFFIsTiled( tif ) ) + if (TIFFIsTiled(tif)) { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), - "Can't use TIFFReadRGBAStrip() with tiled file."); - return (0); + TIFFErrorExtR(tif, TIFFFileName(tif), + "Can't use TIFFReadRGBAStrip() with tiled file."); + return (0); } - + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); - if( (row % rowsperstrip) != 0 ) + if ((row % rowsperstrip) != 0) { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), - "Row passed to TIFFReadRGBAStrip() must be first in a strip."); - return (0); + TIFFErrorExtR( + tif, TIFFFileName(tif), + "Row passed to TIFFReadRGBAStrip() must be first in a strip."); + return (0); } - if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, 0, emsg)) { + if (TIFFRGBAImageOK(tif, emsg) && + TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg)) + { img.row_offset = row; img.col_offset = 0; - if( row + rowsperstrip > img.height ) + if (row + rowsperstrip > img.height) rows_to_read = img.height - row; else rows_to_read = rowsperstrip; - - ok = TIFFRGBAImageGet(&img, raster, img.width, rows_to_read ); - - TIFFRGBAImageEnd(&img); - } else { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); - ok = 0; - } - + + ok = TIFFRGBAImageGet(&img, raster, img.width, rows_to_read); + + TIFFRGBAImageEnd(&img); + } + else + { + TIFFErrorExtR(tif, TIFFFileName(tif), "%s", emsg); + ok = 0; + } + return (ok); } @@ -2568,47 +3252,53 @@ TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster ) * and may include zeroed areas if the tile extends off the image. */ -int -TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) +int TIFFReadRGBATile(TIFF *tif, uint32_t col, uint32_t row, uint32_t *raster) { - char emsg[1024] = ""; + return TIFFReadRGBATileExt(tif, col, row, raster, 0); +} + +int TIFFReadRGBATileExt(TIFF *tif, uint32_t col, uint32_t row, uint32_t *raster, + int stop_on_error) +{ + char emsg[EMSG_BUF_SIZE] = ""; TIFFRGBAImage img; - int ok; - uint32 tile_xsize, tile_ysize; - uint32 read_xsize, read_ysize; - uint32 i_row; + int ok; + uint32_t tile_xsize, tile_ysize; + uint32_t read_xsize, read_ysize; + uint32_t i_row; /* * Verify that our request is legal - on a tile file, and on a * tile boundary. */ - - if( !TIFFIsTiled( tif ) ) + + if (!TIFFIsTiled(tif)) { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), - "Can't use TIFFReadRGBATile() with stripped file."); - return (0); + TIFFErrorExtR(tif, TIFFFileName(tif), + "Can't use TIFFReadRGBATile() with striped file."); + return (0); } - + TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize); TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize); - if( (col % tile_xsize) != 0 || (row % tile_ysize) != 0 ) + if ((col % tile_xsize) != 0 || (row % tile_ysize) != 0) { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), - "Row/col passed to TIFFReadRGBATile() must be top" - "left corner of a tile."); - return (0); + TIFFErrorExtR(tif, TIFFFileName(tif), + "Row/col passed to TIFFReadRGBATile() must be top" + "left corner of a tile."); + return (0); } /* * Setup the RGBA reader. */ - - if (!TIFFRGBAImageOK(tif, emsg) - || !TIFFRGBAImageBegin(&img, tif, 0, emsg)) { - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg); - return( 0 ); + + if (!TIFFRGBAImageOK(tif, emsg) || + !TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg)) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "%s", emsg); + return (0); } /* @@ -2618,12 +3308,12 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) * a full tile configuration afterwards. */ - if( row + tile_ysize > img.height ) + if (row + tile_ysize > img.height) read_ysize = img.height - row; else read_ysize = tile_ysize; - - if( col + tile_xsize > img.width ) + + if (col + tile_xsize > img.width) read_xsize = img.width - col; else read_xsize = tile_xsize; @@ -2631,12 +3321,12 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) /* * Read the chunk of imagery. */ - + img.row_offset = row; img.col_offset = col; - ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize ); - + ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize); + TIFFRGBAImageEnd(&img); /* @@ -2644,33 +3334,27 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) * shifting the data around as if a full tile of data is being returned. * * This is all the more complicated because the image is organized in - * bottom to top format. + * bottom to top format. */ - if( read_xsize == tile_xsize && read_ysize == tile_ysize ) - return( ok ); + if (read_xsize == tile_xsize && read_ysize == tile_ysize) + return (ok); - for( i_row = 0; i_row < read_ysize; i_row++ ) { - memmove( raster + (tile_ysize - i_row - 1) * tile_xsize, - raster + (read_ysize - i_row - 1) * read_xsize, - read_xsize * sizeof(uint32) ); - _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize+read_xsize, - 0, sizeof(uint32) * (tile_xsize - read_xsize) ); + for (i_row = 0; i_row < read_ysize; i_row++) + { + memmove(raster + (size_t)(tile_ysize - i_row - 1) * tile_xsize, + raster + (size_t)(read_ysize - i_row - 1) * read_xsize, + read_xsize * sizeof(uint32_t)); + _TIFFmemset(raster + (size_t)(tile_ysize - i_row - 1) * tile_xsize + + read_xsize, + 0, sizeof(uint32_t) * (tile_xsize - read_xsize)); } - for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) { - _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize, - 0, sizeof(uint32) * tile_xsize ); + for (i_row = read_ysize; i_row < tile_ysize; i_row++) + { + _TIFFmemset(raster + (size_t)(tile_ysize - i_row - 1) * tile_xsize, 0, + sizeof(uint32_t) * tile_xsize); } return (ok); } - -/* vim: set ts=8 sts=8 sw=8 noet: */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ diff --git a/LibTiff/tif_hash_set.c b/LibTiff/tif_hash_set.c new file mode 100644 index 00000000..9792c63f --- /dev/null +++ b/LibTiff/tif_hash_set.c @@ -0,0 +1,603 @@ +/********************************************************************** + * + * Name: tif_hash_set.c + * Purpose: Hash set functions. + * Author: Even Rouault, + * + ********************************************************************** + * Copyright (c) 2008-2009, Even Rouault + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "tif_config.h" + +#include "tif_hash_set.h" + +#include +#include +#include +#include +#include + +/** List element structure. */ +typedef struct _TIFFList TIFFList; + +/** List element structure. */ +struct _TIFFList +{ + /*! Pointer to the data object. Should be allocated and freed by the + * caller. + * */ + void *pData; + /*! Pointer to the next element in list. NULL, if current element is the + * last one. + */ + struct _TIFFList *psNext; +}; + +struct _TIFFHashSet +{ + TIFFHashSetHashFunc fnHashFunc; + TIFFHashSetEqualFunc fnEqualFunc; + TIFFHashSetFreeEltFunc fnFreeEltFunc; + TIFFList **tabList; + int nSize; + int nIndiceAllocatedSize; + int nAllocatedSize; + TIFFList *psRecyclingList; + int nRecyclingListSize; + bool bRehash; +#ifdef HASH_DEBUG + int nCollisions; +#endif +}; + +static const int anPrimes[] = { + 53, 97, 193, 389, 769, 1543, 3079, + 6151, 12289, 24593, 49157, 98317, 196613, 393241, + 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, + 100663319, 201326611, 402653189, 805306457, 1610612741}; + +/************************************************************************/ +/* TIFFHashSetHashPointer() */ +/************************************************************************/ + +/** + * Hash function for an arbitrary pointer + * + * @param elt the arbitrary pointer to hash + * + * @return the hash value of the pointer + */ + +static unsigned long TIFFHashSetHashPointer(const void *elt) +{ + return (unsigned long)(uintptr_t)((void *)(elt)); +} + +/************************************************************************/ +/* TIFFHashSetEqualPointer() */ +/************************************************************************/ + +/** + * Equality function for arbitrary pointers + * + * @param elt1 the first arbitrary pointer to compare + * @param elt2 the second arbitrary pointer to compare + * + * @return true if the pointers are equal + */ + +static bool TIFFHashSetEqualPointer(const void *elt1, const void *elt2) +{ + return elt1 == elt2; +} + +/************************************************************************/ +/* TIFFHashSetNew() */ +/************************************************************************/ + +/** + * Creates a new hash set + * + * The hash function must return a hash value for the elements to insert. + * If fnHashFunc is NULL, TIFFHashSetHashPointer will be used. + * + * The equal function must return if two elements are equal. + * If fnEqualFunc is NULL, TIFFHashSetEqualPointer will be used. + * + * The free function is used to free elements inserted in the hash set, + * when the hash set is destroyed, when elements are removed or replaced. + * If fnFreeEltFunc is NULL, elements inserted into the hash set will not be + * freed. + * + * @param fnHashFunc hash function. May be NULL. + * @param fnEqualFunc equal function. May be NULL. + * @param fnFreeEltFunc element free function. May be NULL. + * + * @return a new hash set + */ + +TIFFHashSet *TIFFHashSetNew(TIFFHashSetHashFunc fnHashFunc, + TIFFHashSetEqualFunc fnEqualFunc, + TIFFHashSetFreeEltFunc fnFreeEltFunc) +{ + TIFFHashSet *set = (TIFFHashSet *)malloc(sizeof(TIFFHashSet)); + if (set == NULL) + return NULL; + set->fnHashFunc = fnHashFunc ? fnHashFunc : TIFFHashSetHashPointer; + set->fnEqualFunc = fnEqualFunc ? fnEqualFunc : TIFFHashSetEqualPointer; + set->fnFreeEltFunc = fnFreeEltFunc; + set->nSize = 0; + set->tabList = (TIFFList **)(calloc(sizeof(TIFFList *), 53)); + if (set->tabList == NULL) + { + free(set); + return NULL; + } + set->nIndiceAllocatedSize = 0; + set->nAllocatedSize = 53; + set->psRecyclingList = NULL; + set->nRecyclingListSize = 0; + set->bRehash = false; +#ifdef HASH_DEBUG + set->nCollisions = 0; +#endif + return set; +} + +/************************************************************************/ +/* TIFFHashSetSize() */ +/************************************************************************/ + +/** + * Returns the number of elements inserted in the hash set + * + * Note: this is not the internal size of the hash set + * + * @param set the hash set + * + * @return the number of elements in the hash set + */ + +int TIFFHashSetSize(const TIFFHashSet *set) +{ + assert(set != NULL); + return set->nSize; +} + +/************************************************************************/ +/* TIFFHashSetGetNewListElt() */ +/************************************************************************/ + +static TIFFList *TIFFHashSetGetNewListElt(TIFFHashSet *set) +{ + if (set->psRecyclingList) + { + TIFFList *psRet = set->psRecyclingList; + psRet->pData = NULL; + set->nRecyclingListSize--; + set->psRecyclingList = psRet->psNext; + return psRet; + } + + return (TIFFList *)malloc(sizeof(TIFFList)); +} + +/************************************************************************/ +/* TIFFHashSetReturnListElt() */ +/************************************************************************/ + +static void TIFFHashSetReturnListElt(TIFFHashSet *set, TIFFList *psList) +{ + if (set->nRecyclingListSize < 128) + { + psList->psNext = set->psRecyclingList; + set->psRecyclingList = psList; + set->nRecyclingListSize++; + } + else + { + free(psList); + } +} + +/************************************************************************/ +/* TIFFHashSetClearInternal() */ +/************************************************************************/ + +static void TIFFHashSetClearInternal(TIFFHashSet *set, bool bFinalize) +{ + assert(set != NULL); + for (int i = 0; i < set->nAllocatedSize; i++) + { + TIFFList *cur = set->tabList[i]; + while (cur) + { + if (set->fnFreeEltFunc) + set->fnFreeEltFunc(cur->pData); + TIFFList *psNext = cur->psNext; + if (bFinalize) + free(cur); + else + TIFFHashSetReturnListElt(set, cur); + cur = psNext; + } + set->tabList[i] = NULL; + } + set->bRehash = false; +} + +/************************************************************************/ +/* TIFFListDestroy() */ +/************************************************************************/ + +/** + * Destroy a list. Caller responsible for freeing data objects contained in + * list elements. + * + * @param psList pointer to list head. + * + */ + +static void TIFFListDestroy(TIFFList *psList) +{ + TIFFList *psCurrent = psList; + + while (psCurrent) + { + TIFFList *const psNext = psCurrent->psNext; + free(psCurrent); + psCurrent = psNext; + } +} + +/************************************************************************/ +/* TIFFHashSetDestroy() */ +/************************************************************************/ + +/** + * Destroys an allocated hash set. + * + * This function also frees the elements if a free function was + * provided at the creation of the hash set. + * + * @param set the hash set + */ + +void TIFFHashSetDestroy(TIFFHashSet *set) +{ + if (set) + { + TIFFHashSetClearInternal(set, true); + free(set->tabList); + TIFFListDestroy(set->psRecyclingList); + free(set); + } +} + +#ifdef notused +/************************************************************************/ +/* TIFFHashSetClear() */ +/************************************************************************/ + +/** + * Clear all elements from a hash set. + * + * This function also frees the elements if a free function was + * provided at the creation of the hash set. + * + * @param set the hash set + */ + +void TIFFHashSetClear(TIFFHashSet *set) +{ + TIFFHashSetClearInternal(set, false); + set->nIndiceAllocatedSize = 0; + set->nAllocatedSize = 53; +#ifdef HASH_DEBUG + set->nCollisions = 0; +#endif + set->nSize = 0; +} + +/************************************************************************/ +/* TIFFHashSetForeach() */ +/************************************************************************/ + +/** + * Walk through the hash set and runs the provided function on all the + * elements + * + * This function is provided the user_data argument of TIFFHashSetForeach. + * It must return true to go on the walk through the hash set, or FALSE to + * make it stop. + * + * Note : the structure of the hash set must *NOT* be modified during the + * walk. + * + * @param set the hash set. + * @param fnIterFunc the function called on each element. + * @param user_data the user data provided to the function. + */ + +void TIFFHashSetForeach(TIFFHashSet *set, TIFFHashSetIterEltFunc fnIterFunc, + void *user_data) +{ + assert(set != NULL); + if (!fnIterFunc) + return; + + for (int i = 0; i < set->nAllocatedSize; i++) + { + TIFFList *cur = set->tabList[i]; + while (cur) + { + if (!fnIterFunc(cur->pData, user_data)) + return; + + cur = cur->psNext; + } + } +} +#endif + +/************************************************************************/ +/* TIFFHashSetRehash() */ +/************************************************************************/ + +static bool TIFFHashSetRehash(TIFFHashSet *set) +{ + int nNewAllocatedSize = anPrimes[set->nIndiceAllocatedSize]; + TIFFList **newTabList = + (TIFFList **)(calloc(sizeof(TIFFList *), nNewAllocatedSize)); + if (newTabList == NULL) + return false; +#ifdef HASH_DEBUG + TIFFDebug("TIFFHASH", + "hashSet=%p, nSize=%d, nCollisions=%d, " + "fCollisionRate=%.02f", + set, set->nSize, set->nCollisions, + set->nCollisions * 100.0 / set->nSize); + set->nCollisions = 0; +#endif + for (int i = 0; i < set->nAllocatedSize; i++) + { + TIFFList *cur = set->tabList[i]; + while (cur) + { + const unsigned long nNewHashVal = + set->fnHashFunc(cur->pData) % nNewAllocatedSize; +#ifdef HASH_DEBUG + if (newTabList[nNewHashVal]) + set->nCollisions++; +#endif + TIFFList *psNext = cur->psNext; + cur->psNext = newTabList[nNewHashVal]; + newTabList[nNewHashVal] = cur; + cur = psNext; + } + } + free(set->tabList); + set->tabList = newTabList; + set->nAllocatedSize = nNewAllocatedSize; + set->bRehash = false; + return true; +} + +/************************************************************************/ +/* TIFFHashSetFindPtr() */ +/************************************************************************/ + +static void **TIFFHashSetFindPtr(TIFFHashSet *set, const void *elt) +{ + const unsigned long nHashVal = set->fnHashFunc(elt) % set->nAllocatedSize; + TIFFList *cur = set->tabList[nHashVal]; + while (cur) + { + if (set->fnEqualFunc(cur->pData, elt)) + return &cur->pData; + cur = cur->psNext; + } + return NULL; +} + +/************************************************************************/ +/* TIFFHashSetInsert() */ +/************************************************************************/ + +/** + * Inserts an element into a hash set. + * + * If the element was already inserted in the hash set, the previous + * element is replaced by the new element. If a free function was provided, + * it is used to free the previously inserted element + * + * @param set the hash set + * @param elt the new element to insert in the hash set + * + * @return true if success. If false is returned, elt has not been inserted, + * but TIFFHashSetInsert() will have run the free function if provided. + */ + +bool TIFFHashSetInsert(TIFFHashSet *set, void *elt) +{ + assert(set != NULL); + void **pElt = TIFFHashSetFindPtr(set, elt); + if (pElt) + { + if (set->fnFreeEltFunc) + set->fnFreeEltFunc(*pElt); + + *pElt = elt; + return true; + } + + if (set->nSize >= 2 * set->nAllocatedSize / 3 || + (set->bRehash && set->nIndiceAllocatedSize > 0 && + set->nSize <= set->nAllocatedSize / 2)) + { + set->nIndiceAllocatedSize++; + if (!TIFFHashSetRehash(set)) + { + set->nIndiceAllocatedSize--; + if (set->fnFreeEltFunc) + set->fnFreeEltFunc(elt); + return false; + } + } + + const unsigned long nHashVal = set->fnHashFunc(elt) % set->nAllocatedSize; +#ifdef HASH_DEBUG + if (set->tabList[nHashVal]) + set->nCollisions++; +#endif + + TIFFList *new_elt = TIFFHashSetGetNewListElt(set); + if (new_elt == NULL) + { + if (set->fnFreeEltFunc) + set->fnFreeEltFunc(elt); + return false; + } + new_elt->pData = elt; + new_elt->psNext = set->tabList[nHashVal]; + set->tabList[nHashVal] = new_elt; + set->nSize++; + + return true; +} + +/************************************************************************/ +/* TIFFHashSetLookup() */ +/************************************************************************/ + +/** + * Returns the element found in the hash set corresponding to the element to + * look up The element must not be modified. + * + * @param set the hash set + * @param elt the element to look up in the hash set + * + * @return the element found in the hash set or NULL + */ + +void *TIFFHashSetLookup(TIFFHashSet *set, const void *elt) +{ + assert(set != NULL); + void **pElt = TIFFHashSetFindPtr(set, elt); + if (pElt) + return *pElt; + + return NULL; +} + +/************************************************************************/ +/* TIFFHashSetRemoveInternal() */ +/************************************************************************/ + +static bool TIFFHashSetRemoveInternal(TIFFHashSet *set, const void *elt, + bool bDeferRehash) +{ + assert(set != NULL); + if (set->nIndiceAllocatedSize > 0 && set->nSize <= set->nAllocatedSize / 2) + { + set->nIndiceAllocatedSize--; + if (bDeferRehash) + set->bRehash = true; + else + { + if (!TIFFHashSetRehash(set)) + { + set->nIndiceAllocatedSize++; + return false; + } + } + } + + int nHashVal = (int)(set->fnHashFunc(elt) % set->nAllocatedSize); + TIFFList *cur = set->tabList[nHashVal]; + TIFFList *prev = NULL; + while (cur) + { + if (set->fnEqualFunc(cur->pData, elt)) + { + if (prev) + prev->psNext = cur->psNext; + else + set->tabList[nHashVal] = cur->psNext; + + if (set->fnFreeEltFunc) + set->fnFreeEltFunc(cur->pData); + + TIFFHashSetReturnListElt(set, cur); +#ifdef HASH_DEBUG + if (set->tabList[nHashVal]) + set->nCollisions--; +#endif + set->nSize--; + return true; + } + prev = cur; + cur = cur->psNext; + } + return false; +} + +/************************************************************************/ +/* TIFFHashSetRemove() */ +/************************************************************************/ + +/** + * Removes an element from a hash set + * + * @param set the hash set + * @param elt the new element to remove from the hash set + * + * @return true if the element was in the hash set + */ + +bool TIFFHashSetRemove(TIFFHashSet *set, const void *elt) +{ + return TIFFHashSetRemoveInternal(set, elt, false); +} + +#ifdef notused +/************************************************************************/ +/* TIFFHashSetRemoveDeferRehash() */ +/************************************************************************/ + +/** + * Removes an element from a hash set. + * + * This will defer potential rehashing of the set to later calls to + * TIFFHashSetInsert() or TIFFHashSetRemove(). + * + * @param set the hash set + * @param elt the new element to remove from the hash set + * + * @return true if the element was in the hash set + */ + +bool TIFFHashSetRemoveDeferRehash(TIFFHashSet *set, const void *elt) +{ + return TIFFHashSetRemoveInternal(set, elt, true); +} +#endif diff --git a/LibTiff/tif_hash_set.h b/LibTiff/tif_hash_set.h new file mode 100644 index 00000000..f60e2c67 --- /dev/null +++ b/LibTiff/tif_hash_set.h @@ -0,0 +1,100 @@ +/********************************************************************** + * $Id$ + * + * Name: tif_hash_set.h + * Project: TIFF - Common Portability Library + * Purpose: Hash set functions. + * Author: Even Rouault, + * + ********************************************************************** + * Copyright (c) 2008-2009, Even Rouault + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#ifndef TIFF_HASH_SET_H_INCLUDED +#define TIFF_HASH_SET_H_INCLUDED + +#include + +/** + * \file tif_hash_set.h + * + * Hash set implementation. + * + * An hash set is a data structure that holds elements that are unique + * according to a comparison function. Operations on the hash set, such as + * insertion, removal or lookup, are supposed to be fast if an efficient + * "hash" function is provided. + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Types */ + + /** Opaque type for a hash set */ + typedef struct _TIFFHashSet TIFFHashSet; + + /** TIFFHashSetHashFunc */ + typedef unsigned long (*TIFFHashSetHashFunc)(const void *elt); + + /** TIFFHashSetEqualFunc */ + typedef bool (*TIFFHashSetEqualFunc)(const void *elt1, const void *elt2); + + /** TIFFHashSetFreeEltFunc */ + typedef void (*TIFFHashSetFreeEltFunc)(void *elt); + + /* Functions */ + + TIFFHashSet *TIFFHashSetNew(TIFFHashSetHashFunc fnHashFunc, + TIFFHashSetEqualFunc fnEqualFunc, + TIFFHashSetFreeEltFunc fnFreeEltFunc); + + void TIFFHashSetDestroy(TIFFHashSet *set); + + int TIFFHashSetSize(const TIFFHashSet *set); + +#ifdef notused + void TIFFHashSetClear(TIFFHashSet *set); + + /** TIFFHashSetIterEltFunc */ + typedef int (*TIFFHashSetIterEltFunc)(void *elt, void *user_data); + + void TIFFHashSetForeach(TIFFHashSet *set, TIFFHashSetIterEltFunc fnIterFunc, + void *user_data); +#endif + + bool TIFFHashSetInsert(TIFFHashSet *set, void *elt); + + void *TIFFHashSetLookup(TIFFHashSet *set, const void *elt); + + bool TIFFHashSetRemove(TIFFHashSet *set, const void *elt); + +#ifdef notused + bool TIFFHashSetRemoveDeferRehash(TIFFHashSet *set, const void *elt); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* TIFF_HASH_SET_H_INCLUDED */ diff --git a/LibTiff/tif_jbig.c b/LibTiff/tif_jbig.c index c92ee3de..7e455ad1 100644 --- a/LibTiff/tif_jbig.c +++ b/LibTiff/tif_jbig.c @@ -1,26 +1,24 @@ -/* $Id: tif_jbig.c,v 1.2.2.3 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -29,7 +27,7 @@ * * JBIG Compression Algorithm Support. * Contributed by Lee Howard - * + * */ #include "tiffiop.h" @@ -37,349 +35,197 @@ #ifdef JBIG_SUPPORT #include "jbig.h" -typedef struct -{ - uint32 recvparams; /* encoded Class 2 session params */ - char* subaddress; /* subaddress string */ - uint32 recvtime; /* time spend receiving in seconds */ - char* faxdcs; /* encoded fax parameters (DCS, Table 2/T.30) */ - - TIFFVGetMethod vgetparent; - TIFFVSetMethod vsetparent; -} JBIGState; - -#define GetJBIGState(tif) ((JBIGState*)(tif)->tif_data) - -#define FIELD_RECVPARAMS (FIELD_CODEC+0) -#define FIELD_SUBADDRESS (FIELD_CODEC+1) -#define FIELD_RECVTIME (FIELD_CODEC+2) -#define FIELD_FAXDCS (FIELD_CODEC+3) - -static const TIFFFieldInfo jbigFieldInfo[] = +static int JBIGSetupDecode(TIFF *tif) { - {TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, FIELD_RECVPARAMS, TRUE, FALSE, "FaxRecvParams"}, - {TIFFTAG_FAXSUBADDRESS, -1, -1, TIFF_ASCII, FIELD_SUBADDRESS, TRUE, FALSE, "FaxSubAddress"}, - {TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, FIELD_RECVTIME, TRUE, FALSE, "FaxRecvTime"}, - {TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, FIELD_FAXDCS, TRUE, FALSE, "FaxDcs"}, -}; - -static int JBIGSetupDecode(TIFF* tif) -{ - if (TIFFNumberOfStrips(tif) != 1) - { - TIFFError("JBIG", "Multistrip images not supported in decoder"); - return 0; - } - - return 1; + if (TIFFNumberOfStrips(tif) != 1) + { + TIFFErrorExtR(tif, "JBIG", + "Multistrip images not supported in decoder"); + return 0; + } + + return 1; } -static int JBIGDecode(TIFF* tif, tidata_t buffer, tsize_t size, tsample_t s) +static int JBIGDecode(TIFF *tif, uint8_t *buffer, tmsize_t size, uint16_t s) { - struct jbg_dec_state decoder; - int decodeStatus = 0; - unsigned char* pImage = NULL; - (void) size, (void) s; + struct jbg_dec_state decoder; + int decodeStatus = 0; + unsigned char *pImage = NULL; + unsigned long decodedSize; + (void)s; - if (isFillOrder(tif, tif->tif_dir.td_fillorder)) - { - TIFFReverseBits(tif->tif_rawdata, tif->tif_rawdatasize); - } + if (isFillOrder(tif, tif->tif_dir.td_fillorder)) + { + TIFFReverseBits(tif->tif_rawcp, tif->tif_rawcc); + } - jbg_dec_init(&decoder); + jbg_dec_init(&decoder); #if defined(HAVE_JBG_NEWLEN) - jbg_newlen(tif->tif_rawdata, tif->tif_rawdatasize); - /* - * I do not check the return status of jbg_newlen because even if this - * function fails it does not necessarily mean that decoding the image - * will fail. It is generally only needed for received fax images - * that do not contain the actual length of the image in the BIE - * header. I do not log when an error occurs because that will cause - * problems when converting JBIG encoded TIFF's to - * PostScript. As long as the actual image length is contained in the - * BIE header jbg_dec_in should succeed. - */ + jbg_newlen(tif->tif_rawcp, (size_t)tif->tif_rawcc); + /* + * I do not check the return status of jbg_newlen because even if this + * function fails it does not necessarily mean that decoding the image + * will fail. It is generally only needed for received fax images + * that do not contain the actual length of the image in the BIE + * header. I do not log when an error occurs because that will cause + * problems when converting JBIG encoded TIFF's to + * PostScript. As long as the actual image length is contained in the + * BIE header jbg_dec_in should succeed. + */ #endif /* HAVE_JBG_NEWLEN */ - decodeStatus = jbg_dec_in(&decoder, tif->tif_rawdata, - tif->tif_rawdatasize, NULL); - if (JBG_EOK != decodeStatus) - { - /* - * XXX: JBG_EN constant was defined in pre-2.0 releases of the - * JBIG-KIT. Since the 2.0 the error reporting functions were - * changed. We will handle both cases here. - */ - TIFFError("JBIG", "Error (%d) decoding: %s", decodeStatus, + decodeStatus = jbg_dec_in(&decoder, (unsigned char *)tif->tif_rawcp, + (size_t)tif->tif_rawcc, NULL); + if (JBG_EOK != decodeStatus) + { + /* + * XXX: JBG_EN constant was defined in pre-2.0 releases of the + * JBIG-KIT. Since the 2.0 the error reporting functions were + * changed. We will handle both cases here. + */ + TIFFErrorExtR(tif, "JBIG", "Error (%d) decoding: %s", decodeStatus, #if defined(JBG_EN) - jbg_strerror(decodeStatus, JBG_EN) + jbg_strerror(decodeStatus, JBG_EN) #else - jbg_strerror(decodeStatus) + jbg_strerror(decodeStatus) #endif - ); - return 0; - } - - pImage = jbg_dec_getimage(&decoder, 0); - _TIFFmemcpy(buffer, pImage, jbg_dec_getsize(&decoder)); + ); jbg_dec_free(&decoder); - return 1; -} - -static int JBIGSetupEncode(TIFF* tif) -{ - if (TIFFNumberOfStrips(tif) != 1) - { - TIFFError("JBIG", "Multistrip images not supported in encoder"); - return 0; - } - - return 1; -} - -static int JBIGCopyEncodedData(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) -{ - (void) s; - while (cc > 0) - { - tsize_t n = cc; - - if (tif->tif_rawcc + n > tif->tif_rawdatasize) - { - n = tif->tif_rawdatasize - tif->tif_rawcc; - } - - assert(n > 0); - _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 (-1); - } - } - - return (1); -} - -static void JBIGOutputBie(unsigned char* buffer, size_t len, void *userData) -{ - TIFF* tif = (TIFF*)userData; - - if (isFillOrder(tif, tif->tif_dir.td_fillorder)) - { - TIFFReverseBits(buffer, len); - } - - JBIGCopyEncodedData(tif, buffer, len, 0); -} + return 0; + } + + decodedSize = jbg_dec_getsize(&decoder); + if ((tmsize_t)decodedSize < size) + { + TIFFWarningExtR(tif, "JBIG", + "Only decoded %lu bytes, whereas %" TIFF_SSIZE_FORMAT + " requested", + decodedSize, size); + } + else if ((tmsize_t)decodedSize > size) + { + TIFFErrorExtR(tif, "JBIG", + "Decoded %lu bytes, whereas %" TIFF_SSIZE_FORMAT + " were requested", + decodedSize, size); + jbg_dec_free(&decoder); + return 0; + } + pImage = jbg_dec_getimage(&decoder, 0); + _TIFFmemcpy(buffer, pImage, decodedSize); + jbg_dec_free(&decoder); -static int JBIGEncode(TIFF* tif, tidata_t buffer, tsize_t size, tsample_t s) -{ - TIFFDirectory* dir = &tif->tif_dir; - struct jbg_enc_state encoder; - - (void) size, (void) s; - - jbg_enc_init(&encoder, - dir->td_imagewidth, - dir->td_imagelength, - 1, - &buffer, - JBIGOutputBie, - tif); - /* - * jbg_enc_out does the "real" encoding. As data is encoded, - * JBIGOutputBie is called, which writes the data to the directory. - */ - jbg_enc_out(&encoder); - jbg_enc_free(&encoder); + tif->tif_rawcp += tif->tif_rawcc; + tif->tif_rawcc = 0; - return 1; + return 1; } -static void JBIGCleanup(TIFF* tif) +static int JBIGSetupEncode(TIFF *tif) { - JBIGState *sp = GetJBIGState(tif); - - assert(sp != 0); - - tif->tif_tagmethods.vgetfield = sp->vgetparent; - tif->tif_tagmethods.vsetfield = sp->vsetparent; - - _TIFFfree(tif->tif_data); - tif->tif_data = NULL; - - _TIFFSetDefaultCompressionState(tif); + if (TIFFNumberOfStrips(tif) != 1) + { + TIFFErrorExtR(tif, "JBIG", + "Multistrip images not supported in encoder"); + return 0; + } + + return 1; } -static void JBIGPrintDir(TIFF* tif, FILE* fd, long flags) +static int JBIGCopyEncodedData(TIFF *tif, unsigned char *pp, size_t cc, + uint16_t s) { - JBIGState* codec = GetJBIGState(tif); - (void)flags; + (void)s; + while (cc > 0) + { + tmsize_t n = (tmsize_t)cc; - if (TIFFFieldSet(tif, FIELD_RECVPARAMS)) + if (tif->tif_rawcc + n > tif->tif_rawdatasize) { - fprintf(fd, - " Fax Receive Parameters: %08lx\n", - (unsigned long)codec->recvparams); + n = tif->tif_rawdatasize - tif->tif_rawcc; } - if (TIFFFieldSet(tif, FIELD_SUBADDRESS)) + assert(n > 0); + _TIFFmemcpy(tif->tif_rawcp, pp, n); + tif->tif_rawcp += n; + tif->tif_rawcc += n; + pp += n; + cc -= (size_t)n; + if (tif->tif_rawcc >= tif->tif_rawdatasize && !TIFFFlushData1(tif)) { - fprintf(fd, - " Fax SubAddress: %s\n", - codec->subaddress); + return (-1); } + } - if (TIFFFieldSet(tif, FIELD_RECVTIME)) - { - fprintf(fd, - " Fax Receive Time: %lu secs\n", - (unsigned long)codec->recvtime); - } - - if (TIFFFieldSet(tif, FIELD_FAXDCS)) - { - fprintf(fd, - " Fax DCS: %s\n", - codec->faxdcs); - } + return (1); } -static int JBIGVGetField(TIFF* tif, ttag_t tag, va_list ap) +static void JBIGOutputBie(unsigned char *buffer, size_t len, void *userData) { - JBIGState* codec = GetJBIGState(tif); + TIFF *tif = (TIFF *)userData; - switch (tag) - { - case TIFFTAG_FAXRECVPARAMS: - *va_arg(ap, uint32*) = codec->recvparams; - break; - - case TIFFTAG_FAXSUBADDRESS: - *va_arg(ap, char**) = codec->subaddress; - break; - - case TIFFTAG_FAXRECVTIME: - *va_arg(ap, uint32*) = codec->recvtime; - break; - - case TIFFTAG_FAXDCS: - *va_arg(ap, char**) = codec->faxdcs; - break; - - default: - return (*codec->vgetparent)(tif, tag, ap); - } + if (isFillOrder(tif, tif->tif_dir.td_fillorder)) + { + TIFFReverseBits(buffer, (tmsize_t)len); + } - return 1; + JBIGCopyEncodedData(tif, buffer, len, 0); } -static int JBIGVSetField(TIFF* tif, ttag_t tag, va_list ap) +static int JBIGEncode(TIFF *tif, uint8_t *buffer, tmsize_t size, uint16_t s) { - JBIGState* codec = GetJBIGState(tif); - - switch (tag) - { - case TIFFTAG_FAXRECVPARAMS: - codec->recvparams = va_arg(ap, uint32); - break; + TIFFDirectory *dir = &tif->tif_dir; + struct jbg_enc_state encoder; - case TIFFTAG_FAXSUBADDRESS: - _TIFFsetString(&codec->subaddress, va_arg(ap, char*)); - break; + (void)size, (void)s; - case TIFFTAG_FAXRECVTIME: - codec->recvtime = va_arg(ap, uint32); - break; + jbg_enc_init(&encoder, dir->td_imagewidth, dir->td_imagelength, 1, &buffer, + JBIGOutputBie, tif); + /* + * jbg_enc_out does the "real" encoding. As data is encoded, + * JBIGOutputBie is called, which writes the data to the directory. + */ + jbg_enc_out(&encoder); + jbg_enc_free(&encoder); - case TIFFTAG_FAXDCS: - _TIFFsetString(&codec->faxdcs, va_arg(ap, char*)); - break; - - default: - return (*codec->vsetparent)(tif, tag, ap); - } - - TIFFSetFieldBit(tif, _TIFFFieldWithTag(tif, tag)->field_bit); - tif->tif_flags |= TIFF_DIRTYDIRECT; - return 1; + return 1; } -int TIFFInitJBIG(TIFF* tif, int scheme) +int TIFFInitJBIG(TIFF *tif, int scheme) { - JBIGState* codec = NULL; - - assert(scheme == COMPRESSION_JBIG); - - /* - * Merge codec-specific tag information. - */ - if (!_TIFFMergeFieldInfo(tif, jbigFieldInfo, - TIFFArrayCount(jbigFieldInfo))) { - TIFFErrorExt(tif->tif_clientdata, "TIFFInitJBIG", - "Merging JBIG codec-specific tags failed"); - return 0; - } - - /* Allocate memory for the JBIGState structure.*/ - tif->tif_data = (tdata_t)_TIFFmalloc(sizeof(JBIGState)); - if (tif->tif_data == NULL) - { - TIFFError("TIFFInitJBIG", "Not enough memory for JBIGState"); - return 0; - } - _TIFFmemset(tif->tif_data, 0, sizeof(JBIGState)); - codec = GetJBIGState(tif); - - /* Initialize codec private fields */ - codec->recvparams = 0; - codec->subaddress = NULL; - codec->faxdcs = NULL; - codec->recvtime = 0; - - /* - * Override parent get/set field methods. - */ - codec->vgetparent = tif->tif_tagmethods.vgetfield; - codec->vsetparent = tif->tif_tagmethods.vsetfield; - tif->tif_tagmethods.vgetfield = JBIGVGetField; - tif->tif_tagmethods.vsetfield = JBIGVSetField; - tif->tif_tagmethods.printdir = JBIGPrintDir; - - /* - * These flags are set so the JBIG Codec can control when to reverse - * bits and when not to and to allow the jbig decoder and bit reverser - * to write to memory when necessary. - */ - tif->tif_flags |= TIFF_NOBITREV; - tif->tif_flags &= ~TIFF_MAPPED; - - /* Setup the function pointers for encode, decode, and cleanup. */ - tif->tif_setupdecode = JBIGSetupDecode; - tif->tif_decodestrip = JBIGDecode; - - tif->tif_setupencode = JBIGSetupEncode; - tif->tif_encodestrip = JBIGEncode; - - tif->tif_cleanup = JBIGCleanup; - - return 1; + (void)scheme; + assert(scheme == COMPRESSION_JBIG); + + /* + * These flags are set so the JBIG Codec can control when to reverse + * bits and when not to and to allow the jbig decoder and bit reverser + * to write to memory when necessary. + */ + tif->tif_flags |= TIFF_NOBITREV; + tif->tif_flags &= ~TIFF_MAPPED; + /* We may have read from a previous IFD and thus set TIFF_BUFFERMMAP and + * cleared TIFF_MYBUFFER. It is necessary to restore them to their initial + * value to be consistent with the state of a non-memory mapped file. + */ + if (tif->tif_flags & TIFF_BUFFERMMAP) + { + tif->tif_rawdata = NULL; + tif->tif_rawdatasize = 0; + tif->tif_flags &= ~TIFF_BUFFERMMAP; + tif->tif_flags |= TIFF_MYBUFFER; + } + + /* Setup the function pointers for encode, decode, and cleanup. */ + tif->tif_setupdecode = JBIGSetupDecode; + tif->tif_decodestrip = JBIGDecode; + + tif->tif_setupencode = JBIGSetupEncode; + tif->tif_encodestrip = JBIGEncode; + + return 1; } #endif /* JBIG_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/LibTiff/tif_jpeg.c b/LibTiff/tif_jpeg.c index a967827e..250144f2 100644 --- a/LibTiff/tif_jpeg.c +++ b/LibTiff/tif_jpeg.c @@ -1,26 +1,24 @@ -/* $Id: tif_jpeg.c,v 1.50.2.9 2010-06-14 02:47:16 fwarmerdam Exp $ */ - /* * Copyright (c) 1994-1997 Sam Leffler * Copyright (c) 1994-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -28,6 +26,8 @@ #define VC_EXTRALEAN #include "tiffiop.h" +#include + #ifdef JPEG_SUPPORT /* @@ -44,8 +44,34 @@ */ #include -int TIFFFillStrip(TIFF*, tstrip_t); -int TIFFFillTile(TIFF*, ttile_t); +/* Settings that are independent of libjpeg ABI. Used when reinitializing the */ +/* JPEGState from libjpegs 8 bit to libjpeg 12 bits, which have potentially */ +/* different ABI */ +typedef struct +{ + 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; + int has_warned_about_progressive_mode; +} JPEGOtherSettings; + +int TIFFFillStrip(TIFF *tif, uint32_t strip); +int TIFFFillTile(TIFF *tif, uint32_t tile); +int TIFFReInitJPEG_12(TIFF *tif, const JPEGOtherSettings *otherSettings, + int scheme, int is_encode); +int TIFFJPEGIsFullStripRequired_12(TIFF *tif); /* We undefine FAR to avoid conflict with JPEG definition */ @@ -57,10 +83,10 @@ int TIFFFillTile(TIFF*, ttile_t); 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 conficting typedef given the headers which are included. + a conflicting typedef given the headers which are included. */ #if defined(__BORLANDC__) || defined(__MINGW32__) -# define XMD_H 1 +#define XMD_H 1 #endif /* @@ -72,20 +98,70 @@ int TIFFFillTile(TIFF*, ttile_t); "JPEGLib: JPEG parameter struct mismatch: library thinks size is 432, caller expects 464" - For such users we wil fix the problem here. See install.doc file from + 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 */ +#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" +#include "jpeglib.h" + +/* Do optional compile-time version check */ +#if defined(EXPECTED_JPEG_LIB_VERSION) && !defined(LIBJPEG_12_PATH) +#if EXPECTED_JPEG_LIB_VERSION != JPEG_LIB_VERSION +#error EXPECTED_JPEG_LIB_VERSION != JPEG_LIB_VERSION +#endif +#endif + +/* + * Do we want to do special processing suitable for when JSAMPLE is a + * 16bit value? + */ + +/* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 2.2 which + * adds a dual-mode 8/12 bit API in the same library. + */ + +#if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) +#define JPEG_DUAL_MODE_8_12 +/* Start by undefining BITS_IN_JSAMPLE which is always set to 8 in libjpeg-turbo + * >= 2.2 Cf + * https://github.com/libjpeg-turbo/libjpeg-turbo/commit/8b9bc4b9635a2a047fb23ebe70c9acd728d3f99b + */ +#undef BITS_IN_JSAMPLE +/* libjpeg-turbo >= 2.2 adds J12xxxx datatypes for the 12-bit mode. */ +#if defined(FROM_TIF_JPEG_12) +#define BITS_IN_JSAMPLE 12 +#define TIFF_JSAMPLE J12SAMPLE +#define TIFF_JSAMPARRAY J12SAMPARRAY +#define TIFF_JSAMPIMAGE J12SAMPIMAGE +#define TIFF_JSAMPROW J12SAMPROW +#else +#define BITS_IN_JSAMPLE 8 +#define TIFF_JSAMPLE JSAMPLE +#define TIFF_JSAMPARRAY JSAMPARRAY +#define TIFF_JSAMPIMAGE JSAMPIMAGE +#define TIFF_JSAMPROW JSAMPROW +#endif +#else +#define TIFF_JSAMPLE JSAMPLE +#define TIFF_JSAMPARRAY JSAMPARRAY +#define TIFF_JSAMPIMAGE JSAMPIMAGE +#define TIFF_JSAMPROW JSAMPROW +#endif + +#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 @@ -102,13 +178,13 @@ int TIFFFillTile(TIFF*, ttile_t); * 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 +#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; +typedef struct jpeg_error_mgr jpeg_error_mgr; /* * State block for each open TIFF file using @@ -123,87 +199,60 @@ typedef struct jpeg_error_mgr jpeg_error_mgr; * 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 */ - /* - * 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 photometric; /* copy of PhotometricInterpretation */ - uint16 h_sampling; /* luminance sampling factors */ - uint16 v_sampling; - tsize_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 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; - uint32 recvparams; /* encoded Class 2 session params */ - char* subaddress; /* subaddress string */ - uint32 recvtime; /* time spent receiving (secs) */ - char* faxdcs; /* encoded fax parameters (DCS, Table 2/T.30) */ +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 */ + TIFF_JSAMPARRAY ds_buffer[MAX_COMPONENTS]; + int scancount; /* number of "scanlines" accumulated */ + int samplesperclump; + + JPEGOtherSettings otherSettings; } JPEGState; -#define JState(tif) ((JPEGState*)(tif)->tif_data) - -static int JPEGDecode(TIFF*, tidata_t, tsize_t, tsample_t); -static int JPEGDecodeRaw(TIFF*, tidata_t, tsize_t, tsample_t); -static int JPEGEncode(TIFF*, tidata_t, tsize_t, tsample_t); -static int JPEGEncodeRaw(TIFF*, tidata_t, tsize_t, tsample_t); -static int JPEGInitializeLibJPEG( TIFF * tif, - int force_encode, int force_decode ); - -#define FIELD_JPEGTABLES (FIELD_CODEC+0) -#define FIELD_RECVPARAMS (FIELD_CODEC+1) -#define FIELD_SUBADDRESS (FIELD_CODEC+2) -#define FIELD_RECVTIME (FIELD_CODEC+3) -#define FIELD_FAXDCS (FIELD_CODEC+4) - -static const TIFFFieldInfo jpegFieldInfo[] = { - { TIFFTAG_JPEGTABLES, -3,-3, TIFF_UNDEFINED, FIELD_JPEGTABLES, - FALSE, TRUE, "JPEGTables" }, - { TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, FIELD_PSEUDO, - TRUE, FALSE, "" }, - { TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO, - FALSE, FALSE, "" }, - { TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO, - FALSE, FALSE, "" }, - /* Specific for JPEG in faxes */ - { TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, FIELD_RECVPARAMS, - TRUE, FALSE, "FaxRecvParams" }, - { TIFFTAG_FAXSUBADDRESS, -1,-1, TIFF_ASCII, FIELD_SUBADDRESS, - TRUE, FALSE, "FaxSubAddress" }, - { TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, FIELD_RECVTIME, - TRUE, FALSE, "FaxRecvTime" }, - { TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, FIELD_FAXDCS, - TRUE, FALSE, "FaxDcs" }, -}; -#define N(a) (sizeof (a) / sizeof (a[0])) +#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. @@ -219,16 +268,16 @@ static const TIFFFieldInfo jpegFieldInfo[] = { * IJG routines from jerror.c). These are used for both * compression and decompression. */ -static void -TIFFjpeg_error_exit(j_common_ptr cinfo) +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 */ + JPEGState *sp = (JPEGState *)cinfo; /* NB: cinfo assumed first */ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message)(cinfo, buffer); + TIFFErrorExtR(sp->tif, "JPEGLib", "%s", + buffer); /* display the error message */ + jpeg_abort(cinfo); /* clean up libjpeg state */ + LONGJMP(sp->exit_jmpbuf, 1); /* return to libtiff caller */ } /* @@ -236,13 +285,39 @@ TIFFjpeg_error_exit(j_common_ptr cinfo) * since error_exit does its own thing and trace_level * is never set > 0. */ -static void -TIFFjpeg_output_message(j_common_ptr cinfo) +static void TIFFjpeg_output_message(j_common_ptr cinfo) { - char buffer[JMSG_LENGTH_MAX]; + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message)(cinfo, buffer); + TIFFWarningExtR(((JPEGState *)cinfo)->tif, "JPEGLib", "%s", buffer); +} - (*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->otherSettings.max_allowed_scan_number) + { + TIFFErrorExtR( + ((JPEGState *)cinfo)->tif, "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->otherSettings.max_allowed_scan_number); + + jpeg_abort(cinfo); /* clean up libjpeg state */ + LONGJMP(sp->exit_jmpbuf, 1); /* return to libtiff caller */ + } + } } /* @@ -251,140 +326,175 @@ TIFFjpeg_output_message(j_common_ptr cinfo) * 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)) +#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) +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; + /* 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; - return CALLVJPEG(sp, jpeg_create_compress(&sp->cinfo.c)); + /* 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) +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; + /* 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; - return CALLVJPEG(sp, jpeg_create_decompress(&sp->cinfo.d)); + /* 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) +static int TIFFjpeg_set_defaults(JPEGState *sp) { - return CALLVJPEG(sp, jpeg_set_defaults(&sp->cinfo.c)); + return CALLVJPEG(sp, jpeg_set_defaults(&sp->cinfo.c)); } -static int -TIFFjpeg_set_colorspace(JPEGState* sp, J_COLOR_SPACE colorspace) +static int TIFFjpeg_set_colorspace(JPEGState *sp, J_COLOR_SPACE colorspace) { - return CALLVJPEG(sp, jpeg_set_colorspace(&sp->cinfo.c, colorspace)); + return CALLVJPEG(sp, jpeg_set_colorspace(&sp->cinfo.c, colorspace)); } -static int -TIFFjpeg_set_quality(JPEGState* sp, int quality, boolean force_baseline) +static int TIFFjpeg_set_quality(JPEGState *sp, int quality, + boolean force_baseline) { - return CALLVJPEG(sp, - jpeg_set_quality(&sp->cinfo.c, quality, force_baseline)); + return CALLVJPEG(sp, + jpeg_set_quality(&sp->cinfo.c, quality, force_baseline)); } -static int -TIFFjpeg_suppress_tables(JPEGState* sp, boolean suppress) +static int TIFFjpeg_suppress_tables(JPEGState *sp, boolean suppress) { - return CALLVJPEG(sp, jpeg_suppress_tables(&sp->cinfo.c, suppress)); + return CALLVJPEG(sp, jpeg_suppress_tables(&sp->cinfo.c, suppress)); } -static int -TIFFjpeg_start_compress(JPEGState* sp, boolean write_all_tables) +static int TIFFjpeg_start_compress(JPEGState *sp, boolean write_all_tables) { - return CALLVJPEG(sp, - jpeg_start_compress(&sp->cinfo.c, 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) +static int TIFFjpeg_write_scanlines(JPEGState *sp, TIFF_JSAMPARRAY scanlines, + int num_lines) { - return CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c, - scanlines, (JDIMENSION) num_lines)); +#if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) && BITS_IN_JSAMPLE == 12 + return CALLJPEG(sp, -1, + (int)jpeg12_write_scanlines(&sp->cinfo.c, scanlines, + (JDIMENSION)num_lines)); +#else + return CALLJPEG(sp, -1, + (int)jpeg_write_scanlines(&sp->cinfo.c, scanlines, + (JDIMENSION)num_lines)); +#endif } -static int -TIFFjpeg_write_raw_data(JPEGState* sp, JSAMPIMAGE data, int num_lines) +static int TIFFjpeg_write_raw_data(JPEGState *sp, TIFF_JSAMPIMAGE data, + int num_lines) { - return CALLJPEG(sp, -1, (int) jpeg_write_raw_data(&sp->cinfo.c, - data, (JDIMENSION) num_lines)); +#if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) && BITS_IN_JSAMPLE == 12 + return CALLJPEG( + sp, -1, + (int)jpeg12_write_raw_data(&sp->cinfo.c, data, (JDIMENSION)num_lines)); +#else + return CALLJPEG( + sp, -1, + (int)jpeg_write_raw_data(&sp->cinfo.c, data, (JDIMENSION)num_lines)); +#endif } -static int -TIFFjpeg_finish_compress(JPEGState* sp) +static int TIFFjpeg_finish_compress(JPEGState *sp) { - return CALLVJPEG(sp, jpeg_finish_compress(&sp->cinfo.c)); + return CALLVJPEG(sp, jpeg_finish_compress(&sp->cinfo.c)); } -static int -TIFFjpeg_write_tables(JPEGState* sp) +static int TIFFjpeg_write_tables(JPEGState *sp) { - return CALLVJPEG(sp, jpeg_write_tables(&sp->cinfo.c)); + return CALLVJPEG(sp, jpeg_write_tables(&sp->cinfo.c)); } -static int -TIFFjpeg_read_header(JPEGState* sp, boolean require_image) +static int TIFFjpeg_read_header(JPEGState *sp, boolean require_image) { - return CALLJPEG(sp, -1, jpeg_read_header(&sp->cinfo.d, require_image)); + return CALLJPEG(sp, -1, jpeg_read_header(&sp->cinfo.d, require_image)); } -static int -TIFFjpeg_start_decompress(JPEGState* sp) +static int TIFFjpeg_has_multiple_scans(JPEGState *sp) { - return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d)); + return CALLJPEG(sp, 0, jpeg_has_multiple_scans(&sp->cinfo.d)); } -static int -TIFFjpeg_read_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int max_lines) +static int TIFFjpeg_start_decompress(JPEGState *sp) { - return CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d, - scanlines, (JDIMENSION) max_lines)); + const char *sz_max_allowed_scan_number; + /* progress monitor */ + sp->cinfo.d.progress = &sp->progress; + sp->progress.progress_monitor = TIFFjpeg_progress_monitor; + sp->otherSettings.max_allowed_scan_number = 100; + sz_max_allowed_scan_number = getenv("LIBTIFF_JPEG_MAX_ALLOWED_SCAN_NUMBER"); + if (sz_max_allowed_scan_number) + sp->otherSettings.max_allowed_scan_number = + atoi(sz_max_allowed_scan_number); + + return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d)); } -static int -TIFFjpeg_read_raw_data(JPEGState* sp, JSAMPIMAGE data, int max_lines) +static int TIFFjpeg_read_scanlines(JPEGState *sp, TIFF_JSAMPARRAY scanlines, + int max_lines) { - return CALLJPEG(sp, -1, (int) jpeg_read_raw_data(&sp->cinfo.d, - data, (JDIMENSION) max_lines)); +#if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) && BITS_IN_JSAMPLE == 12 + return CALLJPEG(sp, -1, + (int)jpeg12_read_scanlines(&sp->cinfo.d, scanlines, + (JDIMENSION)max_lines)); +#else + return CALLJPEG(sp, -1, + (int)jpeg_read_scanlines(&sp->cinfo.d, scanlines, + (JDIMENSION)max_lines)); +#endif } -static int -TIFFjpeg_finish_decompress(JPEGState* sp) +static int TIFFjpeg_read_raw_data(JPEGState *sp, TIFF_JSAMPIMAGE data, + int max_lines) { - return CALLJPEG(sp, -1, (int) jpeg_finish_decompress(&sp->cinfo.d)); +#if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) && BITS_IN_JSAMPLE == 12 + return CALLJPEG( + sp, -1, + (int)jpeg12_read_raw_data(&sp->cinfo.d, data, (JDIMENSION)max_lines)); +#else + return CALLJPEG( + sp, -1, + (int)jpeg_read_raw_data(&sp->cinfo.d, data, (JDIMENSION)max_lines)); +#endif } -static int -TIFFjpeg_abort(JPEGState* sp) +static int TIFFjpeg_finish_decompress(JPEGState *sp) { - return CALLVJPEG(sp, jpeg_abort(&sp->cinfo.comm)); + return CALLJPEG(sp, -1, (int)jpeg_finish_decompress(&sp->cinfo.d)); } -static int -TIFFjpeg_destroy(JPEGState* sp) +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)); + return CALLVJPEG(sp, jpeg_destroy(&sp->cinfo.comm)); } -static JSAMPARRAY -TIFFjpeg_alloc_sarray(JPEGState* sp, int pool_id, - JDIMENSION samplesperrow, JDIMENSION numrows) +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)); + return CALLJPEG(sp, (JSAMPARRAY)NULL, + (*sp->cinfo.comm.mem->alloc_sarray)( + &sp->cinfo.comm, pool_id, samplesperrow, numrows)); } /* @@ -393,116 +503,128 @@ TIFFjpeg_alloc_sarray(JPEGState* sp, int pool_id, * libtiff output buffer. */ -static void -std_init_destination(j_compress_ptr cinfo) +static void std_init_destination(j_compress_ptr cinfo) { - JPEGState* sp = (JPEGState*) cinfo; - TIFF* tif = sp->tif; + 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; + 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) +static boolean std_empty_output_buffer(j_compress_ptr cinfo) { - JPEGState* sp = (JPEGState*) cinfo; - TIFF* tif = sp->tif; + 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 - /* the entire buffer has been filled */ - tif->tif_rawcc = tif->tif_rawdatasize; - TIFFFlushData1(tif); - sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; - sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; + 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); + return (TRUE); } -static void -std_term_destination(j_compress_ptr cinfo) +static void std_term_destination(j_compress_ptr cinfo) { - JPEGState* sp = (JPEGState*) cinfo; - TIFF* tif = sp->tif; + JPEGState *sp = (JPEGState *)cinfo; + TIFF *tif = sp->tif; - tif->tif_rawcp = (tidata_t) sp->dest.next_output_byte; - tif->tif_rawcc = - tif->tif_rawdatasize - (tsize_t) sp->dest.free_in_buffer; - /* NB: libtiff does the final buffer flush */ + 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) +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; + (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) +static void tables_init_destination(j_compress_ptr cinfo) { - JPEGState* sp = (JPEGState*) 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; + /* while building, otherSettings.jpegtables_length is allocated buffer size + */ + sp->dest.next_output_byte = (JOCTET *)sp->otherSettings.jpegtables; + sp->dest.free_in_buffer = (size_t)sp->otherSettings.jpegtables_length; } -static boolean -tables_empty_output_buffer(j_compress_ptr cinfo) +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((tdata_t) sp->jpegtables, - (tsize_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); + JPEGState *sp = (JPEGState *)cinfo; + void *newbuf; + + /* the entire buffer has been filled; enlarge it by 1000 bytes */ + newbuf = + _TIFFreallocExt(sp->tif, (void *)sp->otherSettings.jpegtables, + (tmsize_t)(sp->otherSettings.jpegtables_length + 1000)); + if (newbuf == NULL) + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 100); + sp->dest.next_output_byte = + (JOCTET *)newbuf + sp->otherSettings.jpegtables_length; + sp->dest.free_in_buffer = (size_t)1000; + sp->otherSettings.jpegtables = newbuf; + sp->otherSettings.jpegtables_length += 1000; + return (TRUE); } -static void -tables_term_destination(j_compress_ptr cinfo) +static void tables_term_destination(j_compress_ptr cinfo) { - JPEGState* sp = (JPEGState*) cinfo; + JPEGState *sp = (JPEGState *)cinfo; - /* set tables length to number of bytes actually emitted */ - sp->jpegtables_length -= sp->dest.free_in_buffer; + /* set tables length to number of bytes actually emitted */ + sp->otherSettings.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((tsize_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); +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->otherSettings.jpegtables) + _TIFFfreeExt(tif, sp->otherSettings.jpegtables); + sp->otherSettings.jpegtables_length = 1000; + sp->otherSettings.jpegtables = (void *)_TIFFmallocExt( + tif, (tmsize_t)sp->otherSettings.jpegtables_length); + if (sp->otherSettings.jpegtables == NULL) + { + sp->otherSettings.jpegtables_length = 0; + TIFFErrorExtR(sp->tif, "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); } /* @@ -510,71 +632,86 @@ TIFFjpeg_tables_dest(JPEGState* sp, TIFF* tif) * These routines supply compressed data to libjpeg. */ -static void -std_init_source(j_decompress_ptr cinfo) +static void std_init_source(j_decompress_ptr cinfo) { - JPEGState* sp = (JPEGState*) cinfo; - TIFF* tif = sp->tif; + 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; + 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) +static boolean std_fill_input_buffer(j_decompress_ptr cinfo) { - JPEGState* sp = (JPEGState* ) cinfo; - static const JOCTET dummy_EOI[2] = { 0xFF, JPEG_EOI }; + 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 + */ - /* - * Should never get here since entire strip/tile is - * read into memory before the decompressor is called, - * and thus was supplied by init_source. - */ - 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); + 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) +static void std_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { - JPEGState* sp = (JPEGState*) cinfo; + JPEGState *sp = (JPEGState *)cinfo; - if (num_bytes > 0) { - if (num_bytes > (long) 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; - } - } + 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) +static void std_term_source(j_decompress_ptr cinfo) { - /* No work necessary here */ - /* Or must we update tif->tif_rawcp, tif->tif_rawcc ??? */ - /* (if so, need empty tables_term_source!) */ - (void) cinfo; + /* No work necessary here */ + (void)cinfo; } -static void -TIFFjpeg_data_src(JPEGState* sp, TIFF* tif) +static void TIFFjpeg_data_src(JPEGState *sp) { - (void) tif; - 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; + 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; } /* @@ -582,20 +719,18 @@ TIFFjpeg_data_src(JPEGState* sp, TIFF* tif) * We can share all the code except for the init routine. */ -static void -tables_init_source(j_decompress_ptr cinfo) +static void tables_init_source(j_decompress_ptr cinfo) { - JPEGState* sp = (JPEGState*) cinfo; + JPEGState *sp = (JPEGState *)cinfo; - sp->src.next_input_byte = (const JOCTET*) sp->jpegtables; - sp->src.bytes_in_buffer = (size_t) sp->jpegtables_length; + sp->src.next_input_byte = (const JOCTET *)sp->otherSettings.jpegtables; + sp->src.bytes_in_buffer = (size_t)sp->otherSettings.jpegtables_length; } -static void -TIFFjpeg_tables_src(JPEGState* sp, TIFF* tif) +static void TIFFjpeg_tables_src(JPEGState *sp) { - TIFFjpeg_data_src(sp, tif); - sp->src.init_source = tables_init_source; + TIFFjpeg_data_src(sp); + sp->src.init_source = tables_init_source; } /* @@ -605,1269 +740,1976 @@ TIFFjpeg_tables_src(JPEGState* sp, TIFF* tif) * 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); -} +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; + TIFF_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 = (TIFF_JSAMPARRAY)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. */ -static int -JPEGSetupDecode(TIFF* tif) -{ - JPEGState* sp = JState(tif); - TIFFDirectory *td = &tif->tif_dir; - - JPEGInitializeLibJPEG( tif, 0, 1 ); - - assert(sp != NULL); - assert(sp->cinfo.comm.is_decompressor); - - /* Read JPEGTables if it is present */ - if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) { - TIFFjpeg_tables_src(sp, tif); - 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->tif_postdecode = _TIFFNoPostDecode; /* override byte swapping */ - return (1); -} +#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING -/* - * Set up for decoding a strip or tile. - */ +#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 -JPEGPreDecode(TIFF* tif, tsample_t s) -{ - JPEGState *sp = JState(tif); - TIFFDirectory *td = &tif->tif_dir; - static const char module[] = "JPEGPreDecode"; - uint32 segment_width, segment_height; - int downsampled_output; - int ci; - - assert(sp != NULL); - 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); - /* - * Check image parameters and set decompression parameters. - */ - segment_width = td->td_imagewidth; - segment_height = td->td_imagelength - tif->tif_row; - if (isTiled(tif)) { - segment_width = td->td_tilewidth; - segment_height = td->td_tilelength; - sp->bytesperline = TIFFTileRowSize(tif); - } else { - if (segment_height > td->td_rowsperstrip) - segment_height = td->td_rowsperstrip; - sp->bytesperline = TIFFOldScanlineSize(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(segment_width, sp->h_sampling); - segment_height = TIFFhowmany(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 %dx%d, got %dx%d", - 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) { - /* - * 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 %dx%d, got %dx%d", - 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); - } +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 - 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) { - TIFFWarningExt(tif->tif_clientdata, module, - "Improper JPEG sampling factors %d,%d\n" - "Apparently should be %d,%d.", - sp->cinfo.d.comp_info[0].h_samp_factor, - sp->cinfo.d.comp_info[0].v_samp_factor, - sp->h_sampling, sp->v_sampling); - - /* - * There are potential security issues here - * for decoders that have already allocated - * buffers based on the expected sampling - * factors. Lets check the sampling factors - * dont exceed what we were expecting. - */ - 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, - "Cannot honour JPEG sampling factors" - " that exceed those specified."); - return (0); - } - - /* - * XXX: Files written by the Intergraph software - * has different sampling factors stored in the - * TIFF tags and in the JPEG structures. We will - * try to deduce Intergraph files by the presense - * of the tag 33918. - */ - if (!_TIFFFindFieldInfo(tif, 33918, TIFF_ANY)) { - TIFFWarningExt(tif->tif_clientdata, module, - "Decompressor will try reading with " - "sampling %d,%d.", - sp->cinfo.d.comp_info[0].h_samp_factor, - sp->cinfo.d.comp_info[0].v_samp_factor); - - sp->h_sampling = (uint16) - sp->cinfo.d.comp_info[0].h_samp_factor; - sp->v_sampling = (uint16) - sp->cinfo.d.comp_info[0].v_samp_factor; - } - } - /* 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; - tif->tif_decoderow = JPEGDecodeRaw; - 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. - */ -/*ARGSUSED*/ static int -JPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +static int JPEGFixupTags(TIFF *tif) { +#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING JPEGState *sp = JState(tif); - tsize_t nrows; - (void) s; + if ((tif->tif_dir.td_photometric == PHOTOMETRIC_YCBCR) && + (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG) && + (tif->tif_dir.td_samplesperpixel == 3) && + !sp->otherSettings.ycbcrsampling_fetched) + JPEGFixupTagsSubsampling(tif); +#endif - nrows = cc / sp->bytesperline; - if (cc % sp->bytesperline) - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline not read"); + return (1); +} - if( nrows > (int) sp->cinfo.d.image_height ) - nrows = sp->cinfo.d.image_height; +#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING - /* data is expected to be read in multiples of a scanline */ - if (nrows) +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) { - JSAMPROW line_work_buf = NULL; + /* 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; + } - /* - ** For 6B, only use temporary buffer for 12 bit imagery. - ** For Mk1 always use it. - */ -#if !defined(JPEG_LIB_MK1) - if( sp->cinfo.d.data_precision == 12 ) -#endif + m.tif = tif; + m.buffersize = 2048; + m.buffer = _TIFFmallocExt(tif, m.buffersize); + if (m.buffer == NULL) + { + TIFFWarningExtR(tif, 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)) + TIFFWarningExtR( + tif, module, + "Unable to auto-correct subsampling values, likely corrupt JPEG " + "compressed data in first strip/tile; auto-correcting skipped"); + _TIFFfreeExt(tif, m.buffer); +} + +static int +JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData *data) +{ + static const char module[] = "JPEGFixupTagsSubsamplingSec"; + uint8_t m; + while (1) + { + while (1) { - line_work_buf = (JSAMPROW) - _TIFFmalloc(sizeof(short) * sp->cinfo.d.output_width - * sp->cinfo.d.num_components ); + if (!JPEGFixupTagsSubsamplingReadByte(data, &m)) + return (0); + if (m == 255) + break; } - - do { - if( line_work_buf != NULL ) - { - /* - ** In the MK1 case, we aways 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 ) + 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 */ { - 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] = (in_ptr[0] & 0xff0) >> 4; - out_ptr[1] = ((in_ptr[0] & 0xf) << 4) - | ((in_ptr[1] & 0xf00) >> 8); - out_ptr[2] = ((in_ptr[1] & 0xff) >> 0); - } + uint16_t n; + if (!JPEGFixupTagsSubsamplingReadWord(data, &n)) + return (0); + if (n < 2) + return (0); + n -= 2; + if (n > 0) + JPEGFixupTagsSubsamplingSkip(data, n); } - else if( sp->cinfo.d.data_precision == 8 ) + 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 */ { - int value_count = (sp->cinfo.d.output_width - * sp->cinfo.d.num_components); - int iValue; - - for( iValue = 0; iValue < value_count; iValue++ ) + 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; o < data->tif->tif_dir.td_samplesperpixel; o++) { - ((unsigned char *) buf)[iValue] = - line_work_buf[iValue] & 0xff; + JPEGFixupTagsSubsamplingSkip(data, 1); + if (!JPEGFixupTagsSubsamplingReadByte(data, &p)) + return (0); + if (p != 0x11) + { + TIFFWarningExtR(data->tif, 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))) + { + TIFFWarningExtR(data->tif, 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])) + { + TIFFWarningExtR( + data->tif, 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; } } - } - else + 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) { - /* - ** In the libjpeg6b 8bit case. We read directly into the - ** TIFF buffer. - */ - JSAMPROW bufptr = (JSAMPROW)buf; - - if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1) - return (0); + return 0; } - - ++tif->tif_row; - buf += sp->bytesperline; - cc -= sp->bytesperline; - } while (--nrows > 0); - - if( line_work_buf != NULL ) - _TIFFfree( line_work_buf ); + 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; } - - /* 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); + *result = *data->buffercurrentbyte; + data->buffercurrentbyte++; + data->bufferbytesleft--; + return (1); } -/* - * Decode a chunk of pixels. - * Returned data is downsampled per sampling factors. - */ -/*ARGSUSED*/ static int -JPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +static int +JPEGFixupTagsSubsamplingReadWord(struct JPEGFixupTagsSubsamplingData *data, + uint16_t *result) { - JPEGState *sp = JState(tif); - tsize_t nrows; - (void) s; + uint8_t ma; + uint8_t mb; + if (!JPEGFixupTagsSubsamplingReadByte(data, &ma)) + return (0); + if (!JPEGFixupTagsSubsamplingReadByte(data, &mb)) + return (0); + *result = (ma << 8) | mb; + return (1); +} - /* data is expected to be read in multiples of a scanline */ - if ( (nrows = sp->cinfo.d.image_height) ) { - /* 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; +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; + } + } +} -#ifdef JPEG_LIB_MK1 - unsigned short* tmpbuf = _TIFFmalloc(sizeof(unsigned short) * - sp->cinfo.d.output_width * - sp->cinfo.d.num_components); #endif - do { - jpeg_component_info *compptr; - int ci, clumpoffset; - - /* 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]; -#ifdef JPEG_LIB_MK1 - JSAMPLE *outptr = (JSAMPLE*)tmpbuf + clumpoffset; -#else - JSAMPLE *outptr = (JSAMPLE*)buf + clumpoffset; -#endif - JDIMENSION nclump; - - 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; - } - } +static int JPEGSetupDecode(TIFF *tif) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; -#ifdef JPEG_LIB_MK1 - { - 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 = tmpbuf + iPair * 2; - out_ptr[0] = (in_ptr[0] & 0xff0) >> 4; - out_ptr[1] = ((in_ptr[0] & 0xf) << 4) - | ((in_ptr[1] & 0xf00) >> 8); - out_ptr[2] = ((in_ptr[1] & 0xff) >> 0); - } - } - } +#if defined(JPEG_DUAL_MODE_8_12) && !defined(FROM_TIF_JPEG_12) + if (tif->tif_dir.td_bitspersample == 12) + { + /* We pass a pointer to a copy of otherSettings, since */ + /* TIFFReInitJPEG_12() will clear sp */ + JPEGOtherSettings savedOtherSettings = sp->otherSettings; + return TIFFReInitJPEG_12(tif, &savedOtherSettings, COMPRESSION_JPEG, 0); + } #endif - sp->scancount ++; - tif->tif_row += sp->v_sampling; - /* increment/decrement of buf and cc is still incorrect, but should not matter - * TODO: resolve this */ - buf += sp->bytesperline; - cc -= sp->bytesperline; - nrows -= sp->v_sampling; - } while (nrows > 0); - -#ifdef JPEG_LIB_MK1 - _TIFFfree(tmpbuf); -#endif + JPEGInitializeLibJPEG(tif, TRUE); - } + assert(sp != NULL); + assert(sp->cinfo.comm.is_decompressor); - /* Close down the decompressor if done. */ - return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height - || TIFFjpeg_finish_decompress(sp); -} + /* 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) + { + TIFFErrorExtR(tif, "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(FROM_TIF_JPEG_12) + 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) + { + TIFFWarningExtR(tif, 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. */ + TIFFWarningExtR(tif, 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. + */ + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, module, "Improper JPEG component count"); + return (0); + } +#ifdef JPEG_LIB_MK1 + if (12 != td->td_bitspersample && 8 != td->td_bitspersample) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, "Improper JPEG data precision"); + return (0); + } +#endif + + if (sp->cinfo.d.progressive_mode && + !sp->otherSettings.has_warned_about_progressive_mode) + { + TIFFWarningExtR(tif, module, + "The JPEG strip/tile is encoded with progressive mode, " + "which is normally not legal for JPEG-in-TIFF.\n" + "libtiff should be able to decode it, but it might " + "cause compatibility issues with other readers"); + sp->otherSettings.has_warned_about_progressive_mode = TRUE; + } + + /* 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) + { + TIFFErrorExtR( + tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, "Improper JPEG sampling factors"); + return (0); + } + } + downsampled_output = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + sp->photometric == PHOTOMETRIC_YCBCR && + sp->otherSettings.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) + TIFFWarningExtR(tif, 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) + TIFFWarningExtR(tif, 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) + { + TIFF_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 = (TIFF_JSAMPROW)_TIFFmallocExt( + tif, 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; + TIFF_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) + _TIFFfreeExt(tif, 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; + + TIFFErrorExtR( + tif, "TIFFReadScanline", + "scanline oriented access is not supported for downsampled JPEG " + "compressed images, consider enabling TIFFTAG_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; + +#if defined(JPEG_LIB_MK1_OR_12BIT) + unsigned short *tmpbuf = NULL; +#endif + + /* 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) + tmpbuf = _TIFFmallocExt(tif, sizeof(unsigned short) * + sp->cinfo.d.output_width * + sp->cinfo.d.num_components); + if (tmpbuf == NULL) + { + TIFFErrorExtR(tif, "JPEGDecodeRaw", "Out of memory"); + return 0; + } +#endif + + do + { + jpeg_component_info *compptr; + int ci, clumpoffset; + + if (cc < sp->bytesperline) + { + TIFFErrorExtR( + tif, "JPEGDecodeRaw", + "application buffer not large enough for all data."); + goto error; + } + + /* 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) + goto error; + 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++) + { + TIFF_JSAMPLE *inptr = + sp->ds_buffer[ci][sp->scancount * vsamp + ypos]; + JDIMENSION nclump; +#if defined(JPEG_LIB_MK1_OR_12BIT) + TIFF_JSAMPLE *outptr = (TIFF_JSAMPLE *)tmpbuf + clumpoffset; +#else + TIFF_JSAMPLE *outptr = (TIFF_JSAMPLE *)buf + clumpoffset; + if (cc < (tmsize_t)(clumpoffset + + (tmsize_t)samples_per_clump * + (clumps_per_line - 1) + + hsamp)) + { + TIFFErrorExtR( + tif, "JPEGDecodeRaw", + "application buffer not large enough for all data, " + "possible subsampling issue"); + goto error; + } +#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; i < len; i++) + { + ((unsigned char *)buf)[i] = tmpbuf[i] & 0xff; + } + } + else + { /* 12-bit */ + 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 = (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) + _TIFFfreeExt(tif, tmpbuf); +#endif + } + + /* Close down the decompressor if done. */ + return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height || + TIFFjpeg_finish_decompress(sp); + +error: +#if defined(JPEG_LIB_MK1_OR_12BIT) + _TIFFfreeExt(tif, tmpbuf); +#endif + return 0; +} + +/* + * 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->otherSettings.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->otherSettings.jpegtablesmode & JPEGTABLESMODE_QUANT) + { + unsuppress_quant_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_quant_table(sp, 1); + } + if (sp->otherSettings.jpegtablesmode & JPEGTABLESMODE_HUFF) + { + unsuppress_huff_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_huff_table(sp, 1); + } + /* Direct libjpeg output into otherSettings.jpegtables */ + if (!TIFFjpeg_tables_dest(sp, tif)) + return (0); + /* Emit tables-only datastream */ + if (!TIFFjpeg_write_tables(sp)) + return (0); + + return (1); +} + +#if defined(JPEG_LIB_VERSION_MAJOR) && \ + (JPEG_LIB_VERSION_MAJOR > 9 || \ + (JPEG_LIB_VERSION_MAJOR == 9 && JPEG_LIB_VERSION_MINOR >= 4)) +/* This is a modified version of std_huff_tables() from jcparam.c + * in libjpeg-9d because it no longer initializes default Huffman + * tables in jpeg_set_defaults(). */ +static void TIFF_std_huff_tables(j_compress_ptr cinfo) +{ + + if (cinfo->dc_huff_tbl_ptrs[0] == NULL) + { + (void)jpeg_std_huff_table((j_common_ptr)cinfo, TRUE, 0); + } + if (cinfo->ac_huff_tbl_ptrs[0] == NULL) + { + (void)jpeg_std_huff_table((j_common_ptr)cinfo, FALSE, 0); + } + if (cinfo->dc_huff_tbl_ptrs[1] == NULL) + { + (void)jpeg_std_huff_table((j_common_ptr)cinfo, TRUE, 1); + } + if (cinfo->ac_huff_tbl_ptrs[1] == NULL) + { + (void)jpeg_std_huff_table((j_common_ptr)cinfo, FALSE, 1); + } +} +#endif + +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(FROM_TIF_JPEG_12) + if (tif->tif_dir.td_bitspersample == 12) + { + /* We pass a pointer to a copy of otherSettings, since */ + /* TIFFReInitJPEG_12() will clear sp */ + JPEGOtherSettings savedOtherSettings = sp->otherSettings; + return TIFFReInitJPEG_12(tif, &savedOtherSettings, 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->otherSettings.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); + + /* mozjpeg by default enables progressive JPEG, which is illegal in + * JPEG-in-TIFF */ + /* So explicitly disable it. */ + if (sp->cinfo.c.num_scans != 0 && + (sp->otherSettings.jpegtablesmode & JPEGTABLESMODE_HUFF) != 0) + { + /* it has been found that mozjpeg could create corrupt strips/tiles */ + /* in non optimize_coding mode. */ + TIFFWarningExtR( + tif, module, + "mozjpeg library likely detected. Disable emission of " + "Huffman tables in JpegTables tag, and use optimize_coding " + "to avoid potential issues"); + sp->otherSettings.jpegtablesmode &= ~JPEGTABLESMODE_HUFF; + } + sp->cinfo.c.num_scans = 0; + sp->cinfo.c.scan_info = NULL; + + /* 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) + { + TIFFErrorExtR(tif, module, + "Invalig horizontal/vertical sampling value"); + return (0); + } + if (td->td_bitspersample > 16) + { + TIFFErrorExtR(tif, 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: + TIFFErrorExtR(tif, 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 + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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->otherSettings.jpegtablesmode & + (JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF)) + { + if (sp->otherSettings.jpegtables == NULL || + memcmp(sp->otherSettings.jpegtables, "\0\0\0\0\0\0\0\0\0", 8) == 0) + { +#if defined(JPEG_LIB_VERSION_MAJOR) && \ + (JPEG_LIB_VERSION_MAJOR > 9 || \ + (JPEG_LIB_VERSION_MAJOR == 9 && JPEG_LIB_VERSION_MINOR >= 4)) + if ((sp->otherSettings.jpegtablesmode & JPEGTABLESMODE_HUFF) != 0 && + (sp->cinfo.c.dc_huff_tbl_ptrs[0] == NULL || + sp->cinfo.c.dc_huff_tbl_ptrs[1] == NULL || + sp->cinfo.c.ac_huff_tbl_ptrs[0] == NULL || + sp->cinfo.c.ac_huff_tbl_ptrs[1] == NULL)) + { + /* libjpeg-9d no longer initializes default Huffman tables in */ + /* jpeg_set_defaults() */ + TIFF_std_huff_tables(&sp->cinfo.c); + } +#endif + + 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) + { + TIFFErrorExtR(tif, 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->otherSettings.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->otherSettings.jpegquality, FALSE)) + return (0); + if (sp->otherSettings.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->otherSettings.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); +} /* - * JPEG Encoding. + * Encode a chunk of pixels. + * "Standard" case: incoming data is not downsampled. */ - -static void -unsuppress_quant_table (JPEGState* sp, int tblno) +static int JPEGEncode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s) { - JQUANT_TBL* qtbl; + JPEGState *sp = JState(tif); + tmsize_t nrows; + TIFF_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) + TIFFWarningExtR(tif, tif->tif_name, "fractional scanline discarded"); - if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL) - qtbl->sent_table = FALSE; -} + /* 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; -static void -unsuppress_huff_table (JPEGState* sp, int tblno) -{ - JHUFF_TBL* htbl; + if (sp->cinfo.c.data_precision == 12) + { + line16_count = (int)((sp->bytesperline * 2) / 3); + line16 = (short *)_TIFFmallocExt(tif, sizeof(short) * line16_count); + if (!line16) + { + TIFFErrorExtR(tif, "JPEGEncode", "Failed to allocate memory"); - 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; -} + return 0; + } + } -static int -prepare_JPEGTables(TIFF* tif) -{ - JPEGState* sp = JState(tif); - - JPEGInitializeLibJPEG( tif, 0, 0 ); - - /* 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); -} + while (nrows-- > 0) + { -static int -JPEGSetupEncode(TIFF* tif) -{ - JPEGState* sp = JState(tif); - TIFFDirectory *td = &tif->tif_dir; - static const char module[] = "JPEGSetupEncode"; - - JPEGInitializeLibJPEG( tif, 1, 0 ); - - assert(sp != NULL); - assert(!sp->cinfo.comm.is_decompressor); - - /* - * Initialize all JPEG parameters to default values. - * Note that jpeg_set_defaults needs legal values for - * in_color_space and input_components. - */ - sp->cinfo.c.in_color_space = JCS_UNKNOWN; - sp->cinfo.c.input_components = 1; - if (!TIFFjpeg_set_defaults(sp)) - return (0); - /* Set per-file parameters */ - 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]; - /* - * 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 %d not allowed for JPEG", - (int) 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 %d not allowed for JPEG", - (int) 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 %d", - 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 %d", - 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 %d for JPEG", - 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); - } + if (sp->cinfo.c.data_precision == 12) + { - /* Direct libjpeg output to libtiff's output buffer */ - TIFFjpeg_data_dest(sp, tif); + int value_pairs = line16_count / 2; + int iPair; - return (1); -} + bufptr[0] = (TIFF_JSAMPROW)line16; -/* - * Set encoding state at the start of a strip or tile. - */ -static int -JPEGPreEncode(TIFF* tif, tsample_t s) -{ - JPEGState *sp = JState(tif); - TIFFDirectory *td = &tif->tif_dir; - static const char module[] = "JPEGPreEncode"; - uint32 segment_width, segment_height; - int downsampled_input; - - assert(sp != NULL); - 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 = TIFFOldScanlineSize(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(segment_width, sp->h_sampling); - segment_height = TIFFhowmany(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) { - sp->cinfo.c.in_color_space = JCS_RGB; - } else { - sp->cinfo.c.in_color_space = JCS_YCbCr; - 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 { - sp->cinfo.c.in_color_space = JCS_UNKNOWN; - if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) - return (0); - /* jpeg_set_colorspace set all sampling factors to 1 */ - } - } else { - sp->cinfo.c.input_components = 1; - sp->cinfo.c.in_color_space = JCS_UNKNOWN; - 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 */ - if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) - return (0); - if (! (sp->jpegtablesmode & JPEGTABLESMODE_QUANT)) { - unsuppress_quant_table(sp, 0); - unsuppress_quant_table(sp, 1); - } - if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) - 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); -} + for (iPair = 0; iPair < value_pairs; iPair++) + { + unsigned char *in_ptr = ((unsigned char *)buf) + iPair * 3; + TIFF_JSAMPLE *out_ptr = (TIFF_JSAMPLE *)(line16 + iPair * 2); -/* - * Encode a chunk of pixels. - * "Standard" case: incoming data is not downsampled. - */ -static int -JPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) -{ - JPEGState *sp = JState(tif); - tsize_t nrows; - JSAMPROW bufptr[1]; - - (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; - - while (nrows-- > 0) { - bufptr[0] = (JSAMPROW) buf; - if (TIFFjpeg_write_scanlines(sp, bufptr, 1) != 1) - return (0); - if (nrows > 0) - tif->tif_row++; - buf += sp->bytesperline; - } - return (1); + 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] = (TIFF_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) + { + _TIFFfreeExt(tif, line16); + } + + return (1); } /* * Encode a chunk of pixels. * Incoming data is expected to be downsampled per sampling factors. */ -static int -JPEGEncodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) -{ - JPEGState *sp = JState(tif); - JSAMPLE* inptr; - JSAMPLE* outptr; - tsize_t nrows; - JDIMENSION clumps_per_line, nclump; - int clumpoffset, ci, xpos, ypos; - jpeg_component_info* compptr; - int samples_per_clump = sp->samplesperclump; - tsize_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 = (((sp->cinfo.c.image_width+sp->h_sampling-1)/sp->h_sampling) - *(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 += sp->bytesperline; - nrows -= sp->v_sampling; - } - return (1); +static int JPEGEncodeRaw(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s) +{ + JPEGState *sp = JState(tif); + TIFF_JSAMPLE *inptr; + TIFF_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) + TIFFWarningExtR(tif, 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 = ((TIFF_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; - tsize_t row_width = compptr->width_in_blocks * DCTSIZE - * sizeof(JSAMPLE); - for (ypos = sp->scancount * vsamp; - ypos < DCTSIZE * vsamp; ypos++) { - _TIFFmemcpy((tdata_t)sp->ds_buffer[ci][ypos], - (tdata_t)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) : (tsize_t) -1; +static int JPEGPostEncode(TIFF *tif) +{ + JPEGState *sp = JState(tif); - if(tif->tif_scanlinesize > 0 ) - tif->tif_scanlinesize = TIFFScanlineSize(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; -static int -JPEGVSetField(TIFF* tif, ttag_t tag, va_list ap) -{ - JPEGState* sp = JState(tif); - const TIFFFieldInfo* fip; - uint32 v32; - - assert(sp != NULL); - - switch (tag) { - case TIFFTAG_JPEGTABLES: - v32 = va_arg(ap, uint32); - if (v32 == 0) { - /* XXX */ - return (0); - } - _TIFFsetByteArray(&sp->jpegtables, va_arg(ap, void*), - (long) v32); - sp->jpegtables_length = v32; - TIFFSetFieldBit(tif, FIELD_JPEGTABLES); - break; - case TIFFTAG_JPEGQUALITY: - sp->jpegquality = va_arg(ap, int); - return (1); /* pseudo tag */ - case TIFFTAG_JPEGCOLORMODE: - sp->jpegcolormode = va_arg(ap, int); - JPEGResetUpsampled( tif ); - return (1); /* pseudo tag */ - case TIFFTAG_PHOTOMETRIC: + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; ci++, compptr++) { - int ret_value = (*sp->vsetparent)(tif, tag, ap); - JPEGResetUpsampled( tif ); - return ret_value; + 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); + } } - case TIFFTAG_JPEGTABLESMODE: - sp->jpegtablesmode = 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); - case TIFFTAG_FAXRECVPARAMS: - sp->recvparams = va_arg(ap, uint32); - break; - case TIFFTAG_FAXSUBADDRESS: - _TIFFsetString(&sp->subaddress, va_arg(ap, char*)); - break; - case TIFFTAG_FAXRECVTIME: - sp->recvtime = va_arg(ap, uint32); - break; - case TIFFTAG_FAXDCS: - _TIFFsetString(&sp->faxdcs, va_arg(ap, char*)); - break; - default: - return (*sp->vsetparent)(tif, tag, ap); - } - - if ((fip = _TIFFFieldWithTag(tif, tag))) { - TIFFSetFieldBit(tif, fip->field_bit); - } else { - return (0); - } - - tif->tif_flags |= TIFF_DIRTYDIRECT; - return (1); + 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))); } -/* - * 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 load the first strip in - * order to get the sampling values from the jpeg data stream. Various - * hacks are various places are done to ensure this function gets called - * before the td_ycbcrsubsampling values are used from the directory structure, - * including calling TIFFGetField() for the YCBCRSUBSAMPLING field from - * TIFFStripSize(), and the printing code in tif_print.c. - * - * 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. - * - * Problems: - * o This code will cause one whole strip/tile of compressed data to be - * loaded just to get the tags right, even if the imagery is never read. - * It would be more efficient to just load a bit of the header, and - * initialize things from that. - * - * See the bug in bugzilla for details: - * - * http://bugzilla.remotesensing.org/show_bug.cgi?id=168 - * - * Frank Warmerdam, July 2002 - */ +static void JPEGCleanup(TIFF *tif) +{ + JPEGState *sp = JState(tif); + + assert(sp != 0); -static void -JPEGFixupTestSubsampling( TIFF * tif ) + tif->tif_tagmethods.vgetfield = sp->otherSettings.vgetparent; + tif->tif_tagmethods.vsetfield = sp->otherSettings.vsetparent; + tif->tif_tagmethods.printdir = sp->otherSettings.printdir; + if (sp->cinfo_initialized) + TIFFjpeg_destroy(sp); /* release libjpeg resources */ + if (sp->otherSettings.jpegtables) /* tag value */ + _TIFFfreeExt(tif, sp->otherSettings.jpegtables); + _TIFFfreeExt(tif, tif->tif_data); /* release local state */ + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static void JPEGResetUpsampled(TIFF *tif) { -#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING JPEGState *sp = JState(tif); TIFFDirectory *td = &tif->tif_dir; - JPEGInitializeLibJPEG( tif, 0, 0 ); + /* + * 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->otherSettings.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 + } + } /* - * Some JPEG-in-TIFF files don't provide the ycbcrsampling tags, - * and use a sampling schema other than the default 2,2. To handle - * this we actually have to scan the header of a strip or tile of - * jpeg data to get the sampling. + * Must recalculate cached tile size in case sampling state changed. + * Should we really be doing this now if image size isn't set? */ - if( !sp->cinfo.comm.is_decompressor - || sp->ycbcrsampling_fetched - || td->td_photometric != PHOTOMETRIC_YCBCR ) - return; + 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); + } + _TIFFsetByteArrayExt(tif, &sp->otherSettings.jpegtables, + va_arg(ap, void *), v32); + sp->otherSettings.jpegtables_length = v32; + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + break; + case TIFFTAG_JPEGQUALITY: + sp->otherSettings.jpegquality = (int)va_arg(ap, int); + return (1); /* pseudo tag */ + case TIFFTAG_JPEGCOLORMODE: + sp->otherSettings.jpegcolormode = (int)va_arg(ap, int); + JPEGResetUpsampled(tif); + return (1); /* pseudo tag */ + case TIFFTAG_PHOTOMETRIC: + { + int ret_value = (*sp->otherSettings.vsetparent)(tif, tag, ap); + JPEGResetUpsampled(tif); + return ret_value; + } + case TIFFTAG_JPEGTABLESMODE: + sp->otherSettings.jpegtablesmode = (int)va_arg(ap, int); + return (1); /* pseudo tag */ + case TIFFTAG_YCBCRSUBSAMPLING: + /* mark the fact that we have a real ycbcrsubsampling! */ + sp->otherSettings.ycbcrsampling_fetched = 1; + /* should we be recomputing upsampling info here? */ + return (*sp->otherSettings.vsetparent)(tif, tag, ap); + default: + return (*sp->otherSettings.vsetparent)(tif, tag, ap); + } - sp->ycbcrsampling_fetched = 1; - if( TIFFIsTiled( tif ) ) + if ((fip = TIFFFieldWithTag(tif, tag)) != NULL) { - if( !TIFFFillTile( tif, 0 ) ) - return; + TIFFSetFieldBit(tif, fip->field_bit); } else { - if( !TIFFFillStrip( tif, 0 ) ) - return; + return (0); } - TIFFSetField( tif, TIFFTAG_YCBCRSUBSAMPLING, - (uint16) sp->h_sampling, (uint16) sp->v_sampling ); + tif->tif_flags |= TIFF_DIRTYDIRECT; + return (1); +} - /* - ** We want to clear the loaded strip so the application has time - ** to set JPEGCOLORMODE or other behavior modifiers. This essentially - ** undoes the JPEGPreDecode triggers by TIFFFileStrip(). (#1936) - */ - tif->tif_curstrip = -1; +static int JPEGVGetField(TIFF *tif, uint32_t tag, va_list ap) +{ + JPEGState *sp = JState(tif); -#endif /* CHECK_JPEG_YCBCR_SUBSAMPLING */ -} + assert(sp != NULL); -static int -JPEGVGetField(TIFF* tif, ttag_t tag, va_list ap) -{ - JPEGState* sp = JState(tif); - - assert(sp != NULL); - - switch (tag) { - case TIFFTAG_JPEGTABLES: - *va_arg(ap, uint32*) = sp->jpegtables_length; - *va_arg(ap, 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; - case TIFFTAG_YCBCRSUBSAMPLING: - JPEGFixupTestSubsampling( tif ); - return (*sp->vgetparent)(tif, tag, ap); - case TIFFTAG_FAXRECVPARAMS: - *va_arg(ap, uint32*) = sp->recvparams; - break; - case TIFFTAG_FAXSUBADDRESS: - *va_arg(ap, char**) = sp->subaddress; - break; - case TIFFTAG_FAXRECVTIME: - *va_arg(ap, uint32*) = sp->recvtime; - break; - case TIFFTAG_FAXDCS: - *va_arg(ap, char**) = sp->faxdcs; - break; - default: - return (*sp->vgetparent)(tif, tag, ap); - } - return (1); + switch (tag) + { + case TIFFTAG_JPEGTABLES: + *va_arg(ap, uint32_t *) = sp->otherSettings.jpegtables_length; + *va_arg(ap, const void **) = sp->otherSettings.jpegtables; + break; + case TIFFTAG_JPEGQUALITY: + *va_arg(ap, int *) = sp->otherSettings.jpegquality; + break; + case TIFFTAG_JPEGCOLORMODE: + *va_arg(ap, int *) = sp->otherSettings.jpegcolormode; + break; + case TIFFTAG_JPEGTABLESMODE: + *va_arg(ap, int *) = sp->otherSettings.jpegtablesmode; + break; + default: + return (*sp->otherSettings.vgetparent)(tif, tag, ap); + } + return (1); } -static void -JPEGPrintDir(TIFF* tif, FILE* fd, long flags) +static void JPEGPrintDir(TIFF *tif, FILE *fd, long flags) { - JPEGState* sp = JState(tif); + JPEGState *sp = JState(tif); - assert(sp != NULL); + assert(sp != NULL); + (void)flags; - (void) flags; - if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) - fprintf(fd, " JPEG Tables: (%lu bytes)\n", - (unsigned long) sp->jpegtables_length); - if (TIFFFieldSet(tif,FIELD_RECVPARAMS)) - fprintf(fd, " Fax Receive Parameters: %08lx\n", - (unsigned long) sp->recvparams); - if (TIFFFieldSet(tif,FIELD_SUBADDRESS)) - fprintf(fd, " Fax SubAddress: %s\n", sp->subaddress); - if (TIFFFieldSet(tif,FIELD_RECVTIME)) - fprintf(fd, " Fax Receive Time: %lu secs\n", - (unsigned long) sp->recvtime); - if (TIFFFieldSet(tif,FIELD_FAXDCS)) - fprintf(fd, " Fax DCS: %s\n", sp->faxdcs); + if (sp != NULL) + { + if (TIFFFieldSet(tif, FIELD_JPEGTABLES)) + fprintf(fd, " JPEG Tables: (%" PRIu32 " bytes)\n", + sp->otherSettings.jpegtables_length); + if (sp->otherSettings.printdir) + (*sp->otherSettings.printdir)(tif, fd, flags); + } } -static uint32 -JPEGDefaultStripSize(TIFF* tif, uint32 s) +static uint32_t JPEGDefaultStripSize(TIFF *tif, uint32_t s) { - JPEGState* sp = JState(tif); - TIFFDirectory *td = &tif->tif_dir; + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; - s = (*sp->defsparent)(tif, s); - if (s < td->td_imagelength) - s = TIFFroundup(s, td->td_ycbcrsubsampling[1] * DCTSIZE); - return (s); + s = (*sp->otherSettings.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* tw, uint32* th) +static void JPEGDefaultTileSize(TIFF *tif, uint32_t *tw, uint32_t *th) { - JPEGState* sp = JState(tif); - TIFFDirectory *td = &tif->tif_dir; + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; - (*sp->deftparent)(tif, tw, th); - *tw = TIFFroundup(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE); - *th = TIFFroundup(*th, td->td_ycbcrsubsampling[1] * DCTSIZE); + (*sp->otherSettings.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 + * 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. + * 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. + * 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) @@ -1877,20 +2719,16 @@ JPEGDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) * NFW, Feb 3rd, 2003. */ -static int JPEGInitializeLibJPEG( TIFF * tif, int force_encode, int force_decode ) +static int JPEGInitializeLibJPEG(TIFF *tif, int decompress) { - JPEGState* sp = JState(tif); - uint32 *byte_counts = NULL; - int data_is_empty = TRUE; - int decompress; - + JPEGState *sp = JState(tif); - if(sp->cinfo_initialized) + if (sp->cinfo_initialized) { - if( force_encode && sp->cinfo.comm.is_decompressor ) - TIFFjpeg_destroy( sp ); - else if( force_decode && !sp->cinfo.comm.is_decompressor ) - TIFFjpeg_destroy( sp ); + if (!decompress && sp->cinfo.comm.is_decompressor) + TIFFjpeg_destroy(sp); + else if (decompress && !sp->cinfo.comm.is_decompressor) + TIFFjpeg_destroy(sp); else return 1; @@ -1898,168 +2736,165 @@ static int JPEGInitializeLibJPEG( TIFF * tif, int force_encode, int force_decode } /* - * Do we have tile data already? Make sure we initialize the - * the state in decompressor mode if we have tile data, even if we - * are not in read-only file access mode. + * Initialize libjpeg. */ - if( TIFFIsTiled( tif ) - && TIFFGetField( tif, TIFFTAG_TILEBYTECOUNTS, &byte_counts ) - && byte_counts != NULL ) + if (decompress) { - data_is_empty = byte_counts[0] == 0; + if (!TIFFjpeg_create_decompress(sp)) + return (0); } - if( !TIFFIsTiled( tif ) - && TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &byte_counts) - && byte_counts != NULL ) + else { - data_is_empty = byte_counts[0] == 0; + 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; + } + } } - if( force_decode ) - decompress = 1; - else if( force_encode ) - decompress = 0; - else if( tif->tif_mode == O_RDONLY ) - decompress = 1; - else if( data_is_empty ) - decompress = 0; - else - decompress = 1; + sp->cinfo_initialized = TRUE; + + return 1; +} + +/* Common to tif_jpeg.c and tif_jpeg_12.c */ +static void TIFFInitJPEGCommon(TIFF *tif) +{ + JPEGState *sp; + + sp = JState(tif); + sp->tif = tif; /* back link */ + + /* Default values for codec-specific fields */ + sp->otherSettings.jpegtables = NULL; + sp->otherSettings.jpegtables_length = 0; + sp->otherSettings.jpegquality = 75; /* Default IJG quality */ + sp->otherSettings.jpegcolormode = JPEGCOLORMODE_RAW; + sp->otherSettings.jpegtablesmode = + JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF; + sp->otherSettings.ycbcrsampling_fetched = 0; + + tif->tif_tagmethods.vgetfield = JPEGVGetField; /* hook for codec tags */ + tif->tif_tagmethods.vsetfield = JPEGVSetField; /* hook for codec tags */ + tif->tif_tagmethods.printdir = JPEGPrintDir; /* hook for codec tags */ /* - * Initialize libjpeg. + * Install codec methods. */ - if ( decompress ) { - if (!TIFFjpeg_create_decompress(sp)) - return (0); + 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; + + tif->tif_defstripsize = JPEGDefaultStripSize; + tif->tif_deftilesize = JPEGDefaultTileSize; + tif->tif_flags |= TIFF_NOBITREV; /* no bit reversal, please */ + sp->cinfo_initialized = FALSE; +} - } else { - if (!TIFFjpeg_create_compress(sp)) - return (0); +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))) + { + TIFFErrorExtR(tif, "TIFFInitJPEG", + "Merging JPEG codec-specific tags failed"); + return 0; } - sp->cinfo_initialized = TRUE; + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(JPEGState)); - return 1; -} + if (tif->tif_data == NULL) + { + TIFFErrorExtR(tif, "TIFFInitJPEG", "No space for JPEG state block"); + return 0; + } + _TIFFmemset(tif->tif_data, 0, sizeof(JPEGState)); + + sp = JState(tif); + /* + * Override parent get/set field methods. + */ + sp->otherSettings.vgetparent = tif->tif_tagmethods.vgetfield; + sp->otherSettings.vsetparent = tif->tif_tagmethods.vsetfield; + sp->otherSettings.printdir = tif->tif_tagmethods.printdir; + + sp->otherSettings.defsparent = tif->tif_defstripsize; + sp->otherSettings.deftparent = tif->tif_deftilesize; + + TIFFInitJPEGCommon(tif); -int -TIFFInitJPEG(TIFF* tif, int scheme) -{ - JPEGState* sp; - - assert(scheme == COMPRESSION_JPEG); - - /* - * Merge codec-specific tag information. - */ - if (!_TIFFMergeFieldInfo(tif, jpegFieldInfo, N(jpegFieldInfo))) { - 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 = (tidata_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->recvparams = 0; - sp->subaddress = NULL; - sp->faxdcs = NULL; - - sp->ycbcrsampling_fetched = 0; - - /* - * Install codec methods. - */ - 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. + /* + ** 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); */ - if( tif->tif_diroff == 0 ) + sp->otherSettings.jpegtables_length = SIZE_OF_JPEGTABLES; + sp->otherSettings.jpegtables = + (void *)_TIFFmallocExt(tif, sp->otherSettings.jpegtables_length); + if (sp->otherSettings.jpegtables) { -#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); - _TIFFmemset(sp->jpegtables, 0, SIZE_OF_JPEGTABLES); -#undef SIZE_OF_JPEGTABLES + _TIFFmemset(sp->otherSettings.jpegtables, 0, SIZE_OF_JPEGTABLES); } - - /* - * Mark the TIFFTAG_YCBCRSAMPLES as present even if it is not - * see: JPEGFixupTestSubsampling(). - */ - TIFFSetFieldBit( tif, FIELD_YCBCRSUBSAMPLING ); - - return 1; + else + { + TIFFErrorExtR(tif, "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/LibTiff/tif_jpeg_12.c b/LibTiff/tif_jpeg_12.c new file mode 100644 index 00000000..406e1cfc --- /dev/null +++ b/LibTiff/tif_jpeg_12.c @@ -0,0 +1,63 @@ + +#include "tiffiop.h" + +#if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) +#define JPEG_DUAL_MODE_8_12 +#endif + +#if defined(JPEG_DUAL_MODE_8_12) + +#define FROM_TIF_JPEG_12 + +#ifdef TIFFInitJPEG +#undef TIFFInitJPEG +#endif +#define TIFFInitJPEG TIFFInitJPEG_12 + +#ifdef TIFFJPEGIsFullStripRequired +#undef TIFFJPEGIsFullStripRequired +#endif +#define TIFFJPEGIsFullStripRequired TIFFJPEGIsFullStripRequired_12 + +int TIFFInitJPEG_12(TIFF *tif, int scheme); + +#if !defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) +#include LIBJPEG_12_PATH +#endif + +#include "tif_jpeg.c" + +int TIFFReInitJPEG_12(TIFF *tif, const JPEGOtherSettings *otherSettings, + int scheme, int is_encode) +{ + JPEGState *sp; + uint8_t *new_tif_data; + + (void)scheme; + assert(scheme == COMPRESSION_JPEG); + + new_tif_data = + (uint8_t *)_TIFFreallocExt(tif, tif->tif_data, sizeof(JPEGState)); + + if (new_tif_data == NULL) + { + TIFFErrorExtR(tif, "TIFFReInitJPEG_12", + "No space for JPEG state block"); + return 0; + } + + tif->tif_data = new_tif_data; + _TIFFmemset(tif->tif_data, 0, sizeof(JPEGState)); + + TIFFInitJPEGCommon(tif); + + sp = JState(tif); + sp->otherSettings = *otherSettings; + + if (is_encode) + return JPEGSetupEncode(tif); + else + return JPEGSetupDecode(tif); +} + +#endif /* defined(JPEG_DUAL_MODE_8_12) */ diff --git a/LibTiff/tif_lerc.c b/LibTiff/tif_lerc.c new file mode 100644 index 00000000..4f357a60 --- /dev/null +++ b/LibTiff/tif_lerc.c @@ -0,0 +1,1206 @@ +/* + * Copyright (c) 2018, Even Rouault + * Author: + * + * 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 LERC_SUPPORT +/* + * TIFF Library. + * + * LERC Compression Support + * + */ + +#include "Lerc_c_api.h" +#include "zlib.h" +#ifdef ZSTD_SUPPORT +#include "zstd.h" +#endif + +#if LIBDEFLATE_SUPPORT +#include "libdeflate.h" +#endif +#define LIBDEFLATE_MAX_COMPRESSION_LEVEL 12 + +#include + +#define LSTATE_INIT_DECODE 0x01 +#define LSTATE_INIT_ENCODE 0x02 + +#ifndef LERC_AT_LEAST_VERSION +#define LERC_AT_LEAST_VERSION(maj, min, patch) 0 +#endif + +/* + * State block for each open TIFF file using LERC compression/decompression. + */ +typedef struct +{ + double maxzerror; /* max z error */ + int lerc_version; + int additional_compression; + int zstd_compress_level; /* zstd */ + int zipquality; /* deflate */ + int state; /* state flags */ + + uint32_t segment_width; + uint32_t segment_height; + + unsigned int uncompressed_size; + unsigned int uncompressed_alloc; + uint8_t *uncompressed_buffer; + unsigned int uncompressed_offset; + + unsigned int mask_size; + uint8_t *mask_buffer; + + unsigned int compressed_size; + void *compressed_buffer; + +#if LIBDEFLATE_SUPPORT + struct libdeflate_decompressor *libdeflate_dec; + struct libdeflate_compressor *libdeflate_enc; +#endif + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +} LERCState; + +#define LState(tif) ((LERCState *)(tif)->tif_data) +#define DecoderState(tif) LState(tif) +#define EncoderState(tif) LState(tif) + +static int LERCEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); +static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); + +static int LERCFixupTags(TIFF *tif) +{ + (void)tif; + return 1; +} + +static int LERCSetupDecode(TIFF *tif) +{ + LERCState *sp = DecoderState(tif); + + assert(sp != NULL); + + /* if we were last encoding, terminate this mode */ + if (sp->state & LSTATE_INIT_ENCODE) + { + sp->state = 0; + } + + sp->state |= LSTATE_INIT_DECODE; + return 1; +} + +static int GetLercDataType(TIFF *tif) +{ + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "GetLercDataType"; + + if (td->td_sampleformat == SAMPLEFORMAT_INT && td->td_bitspersample == 8) + { + return 0; + } + + if (td->td_sampleformat == SAMPLEFORMAT_UINT && td->td_bitspersample == 8) + { + return 1; + } + + if (td->td_sampleformat == SAMPLEFORMAT_INT && td->td_bitspersample == 16) + { + return 2; + } + + if (td->td_sampleformat == SAMPLEFORMAT_UINT && td->td_bitspersample == 16) + { + return 3; + } + + if (td->td_sampleformat == SAMPLEFORMAT_INT && td->td_bitspersample == 32) + { + return 4; + } + + if (td->td_sampleformat == SAMPLEFORMAT_UINT && td->td_bitspersample == 32) + { + return 5; + } + + if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP && + td->td_bitspersample == 32) + { + return 6; + } + + if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP && + td->td_bitspersample == 64) + { + return 7; + } + + TIFFErrorExtR( + tif, module, + "Unsupported combination of SampleFormat and td_bitspersample"); + return -1; +} + +static int SetupUncompressedBuffer(TIFF *tif, LERCState *sp, const char *module) +{ + TIFFDirectory *td = &tif->tif_dir; + uint64_t new_size_64; + uint64_t new_alloc_64; + unsigned int new_size; + unsigned int new_alloc; + + sp->uncompressed_offset = 0; + + if (isTiled(tif)) + { + sp->segment_width = td->td_tilewidth; + sp->segment_height = td->td_tilelength; + } + else + { + sp->segment_width = td->td_imagewidth; + sp->segment_height = td->td_imagelength - tif->tif_row; + if (sp->segment_height > td->td_rowsperstrip) + sp->segment_height = td->td_rowsperstrip; + } + + new_size_64 = (uint64_t)sp->segment_width * sp->segment_height * + (td->td_bitspersample / 8); + if (td->td_planarconfig == PLANARCONFIG_CONTIG) + { + new_size_64 *= td->td_samplesperpixel; + } + + new_size = (unsigned int)new_size_64; + sp->uncompressed_size = new_size; + + /* add some margin as we are going to use it also to store deflate/zstd + * compressed data */ + new_alloc_64 = 100 + new_size_64 + new_size_64 / 3; +#ifdef ZSTD_SUPPORT + { + size_t zstd_max = ZSTD_compressBound((size_t)new_size_64); + if (new_alloc_64 < zstd_max) + { + new_alloc_64 = zstd_max; + } + } +#endif + new_alloc = (unsigned int)new_alloc_64; + if (new_alloc != new_alloc_64) + { + TIFFErrorExtR(tif, module, "Too large uncompressed strip/tile"); + _TIFFfreeExt(tif, sp->uncompressed_buffer); + sp->uncompressed_buffer = 0; + sp->uncompressed_alloc = 0; + return 0; + } + + if (sp->uncompressed_alloc < new_alloc) + { + _TIFFfreeExt(tif, sp->uncompressed_buffer); + sp->uncompressed_buffer = _TIFFmallocExt(tif, new_alloc); + if (!sp->uncompressed_buffer) + { + TIFFErrorExtR(tif, module, "Cannot allocate buffer"); + _TIFFfreeExt(tif, sp->uncompressed_buffer); + sp->uncompressed_buffer = 0; + sp->uncompressed_alloc = 0; + return 0; + } + sp->uncompressed_alloc = new_alloc; + } + + if ((td->td_planarconfig == PLANARCONFIG_CONTIG && + td->td_extrasamples > 0 && + td->td_sampleinfo[td->td_extrasamples - 1] == EXTRASAMPLE_UNASSALPHA && + GetLercDataType(tif) == 1) || + (td->td_sampleformat == SAMPLEFORMAT_IEEEFP && + (td->td_planarconfig == PLANARCONFIG_SEPARATE || + td->td_samplesperpixel == 1) && + (td->td_bitspersample == 32 || td->td_bitspersample == 64))) + { + unsigned int mask_size = sp->segment_width * sp->segment_height; + if (sp->mask_size < mask_size) + { + void *mask_buffer = + _TIFFreallocExt(tif, sp->mask_buffer, mask_size); + if (mask_buffer == NULL) + { + TIFFErrorExtR(tif, module, "Cannot allocate buffer"); + sp->mask_size = 0; + _TIFFfreeExt(tif, sp->uncompressed_buffer); + sp->uncompressed_buffer = 0; + sp->uncompressed_alloc = 0; + return 0; + } + sp->mask_buffer = (uint8_t *)mask_buffer; + sp->mask_size = mask_size; + } + } + + return 1; +} + +/* + * Setup state for decoding a strip. + */ +static int LERCPreDecode(TIFF *tif, uint16_t s) +{ + static const char module[] = "LERCPreDecode"; + lerc_status lerc_ret; + TIFFDirectory *td = &tif->tif_dir; + LERCState *sp = DecoderState(tif); + int lerc_data_type; + unsigned int infoArray[8]; + unsigned nomask_bands = td->td_samplesperpixel; + int ndims; + int use_mask = 0; + uint8_t *lerc_data = tif->tif_rawcp; + unsigned int lerc_data_size = (unsigned int)tif->tif_rawcc; + + (void)s; + assert(sp != NULL); + if (sp->state != LSTATE_INIT_DECODE) + tif->tif_setupdecode(tif); + + lerc_data_type = GetLercDataType(tif); + if (lerc_data_type < 0) + return 0; + + if (!SetupUncompressedBuffer(tif, sp, module)) + return 0; + + if (sp->additional_compression != LERC_ADD_COMPRESSION_NONE) + { + if (sp->compressed_size < sp->uncompressed_alloc) + { + _TIFFfreeExt(tif, sp->compressed_buffer); + sp->compressed_buffer = _TIFFmallocExt(tif, sp->uncompressed_alloc); + if (!sp->compressed_buffer) + { + sp->compressed_size = 0; + return 0; + } + sp->compressed_size = sp->uncompressed_alloc; + } + } + + if (sp->additional_compression == LERC_ADD_COMPRESSION_DEFLATE) + { +#if LIBDEFLATE_SUPPORT + enum libdeflate_result res; + size_t lerc_data_sizet = 0; + if (sp->libdeflate_dec == NULL) + { + sp->libdeflate_dec = libdeflate_alloc_decompressor(); + if (sp->libdeflate_dec == NULL) + { + TIFFErrorExtR(tif, module, "Cannot allocate decompressor"); + return 0; + } + } + + res = libdeflate_zlib_decompress( + sp->libdeflate_dec, tif->tif_rawcp, (size_t)tif->tif_rawcc, + sp->compressed_buffer, sp->compressed_size, &lerc_data_sizet); + if (res != LIBDEFLATE_SUCCESS) + { + TIFFErrorExtR(tif, module, "Decoding error at scanline %lu", + (unsigned long)tif->tif_row); + return 0; + } + assert(lerc_data_sizet == (unsigned int)lerc_data_sizet); + lerc_data = sp->compressed_buffer; + lerc_data_size = (unsigned int)lerc_data_sizet; +#else + z_stream strm; + int zlib_ret; + + memset(&strm, 0, sizeof(strm)); + strm.zalloc = NULL; + strm.zfree = NULL; + strm.opaque = NULL; + zlib_ret = inflateInit(&strm); + if (zlib_ret != Z_OK) + { + TIFFErrorExtR(tif, module, "inflateInit() failed"); + inflateEnd(&strm); + return 0; + } + + strm.avail_in = (uInt)tif->tif_rawcc; + strm.next_in = tif->tif_rawcp; + strm.avail_out = sp->compressed_size; + strm.next_out = sp->compressed_buffer; + zlib_ret = inflate(&strm, Z_FINISH); + if (zlib_ret != Z_STREAM_END && zlib_ret != Z_OK) + { + TIFFErrorExtR(tif, module, "inflate() failed"); + inflateEnd(&strm); + return 0; + } + lerc_data = sp->compressed_buffer; + lerc_data_size = sp->compressed_size - strm.avail_out; + inflateEnd(&strm); +#endif + } + else if (sp->additional_compression == LERC_ADD_COMPRESSION_ZSTD) + { +#ifdef ZSTD_SUPPORT + size_t zstd_ret; + + zstd_ret = ZSTD_decompress(sp->compressed_buffer, sp->compressed_size, + tif->tif_rawcp, tif->tif_rawcc); + if (ZSTD_isError(zstd_ret)) + { + TIFFErrorExtR(tif, module, "Error in ZSTD_decompress(): %s", + ZSTD_getErrorName(zstd_ret)); + return 0; + } + + lerc_data = sp->compressed_buffer; + lerc_data_size = (unsigned int)zstd_ret; +#else + TIFFErrorExtR(tif, module, "ZSTD support missing"); + return 0; +#endif + } + else if (sp->additional_compression != LERC_ADD_COMPRESSION_NONE) + { + TIFFErrorExtR(tif, module, "Unhandled additional compression"); + return 0; + } + + lerc_ret = + lerc_getBlobInfo(lerc_data, lerc_data_size, infoArray, NULL, 8, 0); + if (lerc_ret != 0) + { + TIFFErrorExtR(tif, module, "lerc_getBlobInfo() failed"); + return 0; + } + + /* If the configuration is compatible of a LERC mask, and that the */ + /* LERC info has dim == samplesperpixel - 1, then there is a LERC */ + /* mask. */ + if (td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_extrasamples > 0 && + td->td_sampleinfo[td->td_extrasamples - 1] == EXTRASAMPLE_UNASSALPHA && + GetLercDataType(tif) == 1 && + infoArray[2] == td->td_samplesperpixel - 1U) + { + use_mask = 1; + nomask_bands--; + } + else if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP && + (td->td_planarconfig == PLANARCONFIG_SEPARATE || + td->td_samplesperpixel == 1) && + (td->td_bitspersample == 32 || td->td_bitspersample == 64)) + { + use_mask = 1; + } + + ndims = td->td_planarconfig == PLANARCONFIG_CONTIG ? nomask_bands : 1; + + /* Info returned in infoArray is { version, dataType, nDim, nCols, + nRows, nBands, nValidPixels, blobSize } */ + if (infoArray[0] != (unsigned)sp->lerc_version) + { + TIFFWarningExtR(tif, module, + "Unexpected version number: %d. Expected: %d", + infoArray[0], sp->lerc_version); + } + if (infoArray[1] != (unsigned)lerc_data_type) + { + TIFFErrorExtR(tif, module, "Unexpected dataType: %d. Expected: %d", + infoArray[1], lerc_data_type); + return 0; + } + if (infoArray[2] != (unsigned)ndims) + { + TIFFErrorExtR(tif, module, "Unexpected nDim: %d. Expected: %d", + infoArray[2], ndims); + return 0; + } + if (infoArray[3] != sp->segment_width) + { + TIFFErrorExtR(tif, module, "Unexpected nCols: %d. Expected: %du", + infoArray[3], sp->segment_width); + return 0; + } + if (infoArray[4] != sp->segment_height) + { + TIFFErrorExtR(tif, module, "Unexpected nRows: %d. Expected: %u", + infoArray[4], sp->segment_height); + return 0; + } + if (infoArray[5] != 1) + { + TIFFErrorExtR(tif, module, "Unexpected nBands: %d. Expected: %d", + infoArray[5], 1); + return 0; + } + if (infoArray[7] != lerc_data_size) + { + TIFFErrorExtR(tif, module, "Unexpected blobSize: %d. Expected: %u", + infoArray[7], lerc_data_size); + return 0; + } + + lerc_ret = lerc_decode(lerc_data, lerc_data_size, +#if LERC_AT_LEAST_VERSION(3, 0, 0) + use_mask ? 1 : 0, +#endif + use_mask ? sp->mask_buffer : NULL, ndims, + sp->segment_width, sp->segment_height, 1, + lerc_data_type, sp->uncompressed_buffer); + if (lerc_ret != 0) + { + TIFFErrorExtR(tif, module, "lerc_decode() failed"); + return 0; + } + + /* Interleave alpha mask with other samples. */ + if (use_mask && GetLercDataType(tif) == 1) + { + unsigned src_stride = + (td->td_samplesperpixel - 1) * (td->td_bitspersample / 8); + unsigned dst_stride = + td->td_samplesperpixel * (td->td_bitspersample / 8); + unsigned i = sp->segment_width * sp->segment_height; + /* Operate from end to begin to be able to move in place */ + while (i > 0 && i > nomask_bands) + { + i--; + sp->uncompressed_buffer[i * dst_stride + td->td_samplesperpixel - + 1] = 255 * sp->mask_buffer[i]; + memcpy(sp->uncompressed_buffer + i * dst_stride, + sp->uncompressed_buffer + i * src_stride, src_stride); + } + /* First pixels must use memmove due to overlapping areas */ + while (i > 0) + { + i--; + sp->uncompressed_buffer[i * dst_stride + td->td_samplesperpixel - + 1] = 255 * sp->mask_buffer[i]; + memmove(sp->uncompressed_buffer + i * dst_stride, + sp->uncompressed_buffer + i * src_stride, src_stride); + } + } + else if (use_mask && td->td_sampleformat == SAMPLEFORMAT_IEEEFP) + { + const unsigned nb_pixels = sp->segment_width * sp->segment_height; + unsigned i; +#if WORDS_BIGENDIAN + const unsigned char nan_bytes[] = {0x7f, 0xc0, 0, 0}; +#else + const unsigned char nan_bytes[] = {0, 0, 0xc0, 0x7f}; +#endif + float nan_float32; + memcpy(&nan_float32, nan_bytes, 4); + + if (td->td_bitspersample == 32) + { + for (i = 0; i < nb_pixels; i++) + { + if (sp->mask_buffer[i] == 0) + ((float *)sp->uncompressed_buffer)[i] = nan_float32; + } + } + else + { + const double nan_float64 = nan_float32; + for (i = 0; i < nb_pixels; i++) + { + if (sp->mask_buffer[i] == 0) + ((double *)sp->uncompressed_buffer)[i] = nan_float64; + } + } + } + + return 1; +} + +/* + * Decode a strip, tile or scanline. + */ +static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) +{ + static const char module[] = "LERCDecode"; + LERCState *sp = DecoderState(tif); + + (void)s; + assert(sp != NULL); + assert(sp->state == LSTATE_INIT_DECODE); + + if (sp->uncompressed_buffer == 0) + { + TIFFErrorExtR(tif, module, "Uncompressed buffer not allocated"); + return 0; + } + + if ((uint64_t)sp->uncompressed_offset + (uint64_t)occ > + sp->uncompressed_size) + { + TIFFErrorExtR(tif, module, "Too many bytes read"); + return 0; + } + + memcpy(op, sp->uncompressed_buffer + sp->uncompressed_offset, occ); + sp->uncompressed_offset += (unsigned)occ; + + return 1; +} + +static int LERCSetupEncode(TIFF *tif) +{ + LERCState *sp = EncoderState(tif); + + assert(sp != NULL); + if (sp->state & LSTATE_INIT_DECODE) + { + sp->state = 0; + } + + sp->state |= LSTATE_INIT_ENCODE; + + return 1; +} + +/* + * Reset encoding state at the start of a strip. + */ +static int LERCPreEncode(TIFF *tif, uint16_t s) +{ + static const char module[] = "LERCPreEncode"; + LERCState *sp = EncoderState(tif); + int lerc_data_type; + + (void)s; + assert(sp != NULL); + if (sp->state != LSTATE_INIT_ENCODE) + tif->tif_setupencode(tif); + + lerc_data_type = GetLercDataType(tif); + if (lerc_data_type < 0) + return 0; + + if (!SetupUncompressedBuffer(tif, sp, module)) + return 0; + + return 1; +} + +/* + * Encode a chunk of pixels. + */ +static int LERCEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "LERCEncode"; + LERCState *sp = EncoderState(tif); + + (void)s; + assert(sp != NULL); + assert(sp->state == LSTATE_INIT_ENCODE); + + if ((uint64_t)sp->uncompressed_offset + (uint64_t)cc > + sp->uncompressed_size) + { + TIFFErrorExtR(tif, module, "Too many bytes written"); + return 0; + } + + memcpy(sp->uncompressed_buffer + sp->uncompressed_offset, bp, cc); + sp->uncompressed_offset += (unsigned)cc; + + return 1; +} + +/* + * Finish off an encoded strip by flushing it. + */ +static int LERCPostEncode(TIFF *tif) +{ + lerc_status lerc_ret; + static const char module[] = "LERCPostEncode"; + LERCState *sp = EncoderState(tif); + unsigned int numBytes = 0; + unsigned int numBytesWritten = 0; + TIFFDirectory *td = &tif->tif_dir; + int use_mask = 0; + unsigned dst_nbands = td->td_samplesperpixel; + + if (sp->uncompressed_offset != sp->uncompressed_size) + { + TIFFErrorExtR(tif, module, "Unexpected number of bytes in the buffer"); + return 0; + } + + /* Extract alpha mask (if containing only 0 and 255 values, */ + /* and compact array of regular bands */ + if (td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_extrasamples > 0 && + td->td_sampleinfo[td->td_extrasamples - 1] == EXTRASAMPLE_UNASSALPHA && + GetLercDataType(tif) == 1) + { + const unsigned dst_stride = + (td->td_samplesperpixel - 1) * (td->td_bitspersample / 8); + const unsigned src_stride = + td->td_samplesperpixel * (td->td_bitspersample / 8); + unsigned i = 0; + const unsigned nb_pixels = sp->segment_width * sp->segment_height; + + use_mask = 1; + for (i = 0; i < nb_pixels; i++) + { + int v = sp->uncompressed_buffer[i * src_stride + + td->td_samplesperpixel - 1]; + if (v != 0 && v != 255) + { + use_mask = 0; + break; + } + } + + if (use_mask) + { + dst_nbands--; + /* First pixels must use memmove due to overlapping areas */ + for (i = 0; i < dst_nbands && i < nb_pixels; i++) + { + memmove(sp->uncompressed_buffer + i * dst_stride, + sp->uncompressed_buffer + i * src_stride, dst_stride); + sp->mask_buffer[i] = + sp->uncompressed_buffer[i * src_stride + + td->td_samplesperpixel - 1]; + } + for (; i < nb_pixels; i++) + { + memcpy(sp->uncompressed_buffer + i * dst_stride, + sp->uncompressed_buffer + i * src_stride, dst_stride); + sp->mask_buffer[i] = + sp->uncompressed_buffer[i * src_stride + + td->td_samplesperpixel - 1]; + } + } + } + else if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP && + (td->td_planarconfig == PLANARCONFIG_SEPARATE || + dst_nbands == 1) && + (td->td_bitspersample == 32 || td->td_bitspersample == 64)) + { + /* Check for NaN values */ + unsigned i; + const unsigned nb_pixels = sp->segment_width * sp->segment_height; + if (td->td_bitspersample == 32) + { + for (i = 0; i < nb_pixels; i++) + { + const float val = ((float *)sp->uncompressed_buffer)[i]; + if (val != val) + { + use_mask = 1; + break; + } + } + } + else + { + for (i = 0; i < nb_pixels; i++) + { + const double val = ((double *)sp->uncompressed_buffer)[i]; + if (val != val) + { + use_mask = 1; + break; + } + } + } + + if (use_mask) + { + if (td->td_bitspersample == 32) + { + for (i = 0; i < nb_pixels; i++) + { + const float val = ((float *)sp->uncompressed_buffer)[i]; + sp->mask_buffer[i] = (val == val) ? 255 : 0; + } + } + else + { + for (i = 0; i < nb_pixels; i++) + { + const double val = ((double *)sp->uncompressed_buffer)[i]; + sp->mask_buffer[i] = (val == val) ? 255 : 0; + } + } + } + } + +#if 0 + lerc_ret = lerc_computeCompressedSize( + sp->uncompressed_buffer, + sp->lerc_version, + GetLercDataType(tif), + td->td_planarconfig == PLANARCONFIG_CONTIG ? + dst_nbands : 1, + sp->segment_width, + sp->segment_height, + 1, + use_mask ? sp->mask_buffer : NULL, + sp->maxzerror, + &numBytes); + if( lerc_ret != 0 ) + { + TIFFErrorExtR(tif, module, + "lerc_computeCompressedSize() failed"); + return 0; + } +#else + numBytes = sp->uncompressed_alloc; +#endif + + if (sp->compressed_size < numBytes) + { + _TIFFfreeExt(tif, sp->compressed_buffer); + sp->compressed_buffer = _TIFFmallocExt(tif, numBytes); + if (!sp->compressed_buffer) + { + sp->compressed_size = 0; + return 0; + } + sp->compressed_size = numBytes; + } + + lerc_ret = lerc_encodeForVersion( + sp->uncompressed_buffer, sp->lerc_version, GetLercDataType(tif), + td->td_planarconfig == PLANARCONFIG_CONTIG ? dst_nbands : 1, + sp->segment_width, sp->segment_height, 1, +#if LERC_AT_LEAST_VERSION(3, 0, 0) + use_mask ? 1 : 0, +#endif + use_mask ? sp->mask_buffer : NULL, sp->maxzerror, sp->compressed_buffer, + sp->compressed_size, &numBytesWritten); + if (lerc_ret != 0) + { + TIFFErrorExtR(tif, module, "lerc_encode() failed"); + return 0; + } + assert(numBytesWritten < numBytes); + + if (sp->additional_compression == LERC_ADD_COMPRESSION_DEFLATE) + { +#if LIBDEFLATE_SUPPORT + if (sp->libdeflate_enc == NULL) + { + /* To get results as good as zlib, we ask 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) + { + TIFFErrorExtR(tif, module, "Cannot allocate compressor"); + return 0; + } + } + + /* Should not happen normally */ + if (libdeflate_zlib_compress_bound( + sp->libdeflate_enc, numBytesWritten) > sp->uncompressed_alloc) + { + TIFFErrorExtR(tif, module, + "Output buffer for libdeflate too small"); + return 0; + } + + tif->tif_rawcc = libdeflate_zlib_compress( + sp->libdeflate_enc, sp->compressed_buffer, numBytesWritten, + sp->uncompressed_buffer, sp->uncompressed_alloc); + + if (tif->tif_rawcc == 0) + { + TIFFErrorExtR(tif, module, "Encoder error at scanline %lu", + (unsigned long)tif->tif_row); + return 0; + } +#else + z_stream strm; + int zlib_ret; + int cappedQuality = sp->zipquality; + if (cappedQuality > Z_BEST_COMPRESSION) + cappedQuality = Z_BEST_COMPRESSION; + + memset(&strm, 0, sizeof(strm)); + strm.zalloc = NULL; + strm.zfree = NULL; + strm.opaque = NULL; + zlib_ret = deflateInit(&strm, cappedQuality); + if (zlib_ret != Z_OK) + { + TIFFErrorExtR(tif, module, "deflateInit() failed"); + return 0; + } + + strm.avail_in = numBytesWritten; + strm.next_in = sp->compressed_buffer; + strm.avail_out = sp->uncompressed_alloc; + strm.next_out = sp->uncompressed_buffer; + zlib_ret = deflate(&strm, Z_FINISH); + if (zlib_ret == Z_STREAM_END) + { + tif->tif_rawcc = sp->uncompressed_alloc - strm.avail_out; + } + deflateEnd(&strm); + if (zlib_ret != Z_STREAM_END) + { + TIFFErrorExtR(tif, module, "deflate() failed"); + return 0; + } +#endif + { + int ret; + uint8_t *tif_rawdata_backup = tif->tif_rawdata; + tif->tif_rawdata = sp->uncompressed_buffer; + ret = TIFFFlushData1(tif); + tif->tif_rawdata = tif_rawdata_backup; + if (!ret) + { + return 0; + } + } + } + else if (sp->additional_compression == LERC_ADD_COMPRESSION_ZSTD) + { +#ifdef ZSTD_SUPPORT + size_t zstd_ret = ZSTD_compress( + sp->uncompressed_buffer, sp->uncompressed_alloc, + sp->compressed_buffer, numBytesWritten, sp->zstd_compress_level); + if (ZSTD_isError(zstd_ret)) + { + TIFFErrorExtR(tif, module, "Error in ZSTD_compress(): %s", + ZSTD_getErrorName(zstd_ret)); + return 0; + } + + { + int ret; + uint8_t *tif_rawdata_backup = tif->tif_rawdata; + tif->tif_rawdata = sp->uncompressed_buffer; + tif->tif_rawcc = zstd_ret; + ret = TIFFFlushData1(tif); + tif->tif_rawdata = tif_rawdata_backup; + if (!ret) + { + return 0; + } + } +#else + TIFFErrorExtR(tif, module, "ZSTD support missing"); + return 0; +#endif + } + else if (sp->additional_compression != LERC_ADD_COMPRESSION_NONE) + { + TIFFErrorExtR(tif, module, "Unhandled additional compression"); + return 0; + } + else + { + int ret; + uint8_t *tif_rawdata_backup = tif->tif_rawdata; + tif->tif_rawdata = sp->compressed_buffer; + tif->tif_rawcc = numBytesWritten; + ret = TIFFFlushData1(tif); + tif->tif_rawdata = tif_rawdata_backup; + if (!ret) + return 0; + } + + return 1; +} + +static void LERCCleanup(TIFF *tif) +{ + LERCState *sp = LState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + _TIFFfreeExt(tif, sp->uncompressed_buffer); + _TIFFfreeExt(tif, sp->compressed_buffer); + _TIFFfreeExt(tif, sp->mask_buffer); + +#if LIBDEFLATE_SUPPORT + if (sp->libdeflate_dec) + libdeflate_free_decompressor(sp->libdeflate_dec); + if (sp->libdeflate_enc) + libdeflate_free_compressor(sp->libdeflate_enc); +#endif + + _TIFFfreeExt(tif, sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static const TIFFField LERCFields[] = { + {TIFFTAG_LERC_PARAMETERS, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG, 0, + TIFF_SETGET_C32_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, FALSE, TRUE, + "LercParameters", NULL}, + {TIFFTAG_LERC_MAXZERROR, 0, 0, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "LercMaximumError", + NULL}, + {TIFFTAG_LERC_VERSION, 0, 0, TIFF_ANY, 0, TIFF_SETGET_UINT32, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "LercVersion", NULL}, + {TIFFTAG_LERC_ADD_COMPRESSION, 0, 0, TIFF_ANY, 0, TIFF_SETGET_UINT32, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, + "LercAdditionalCompression", NULL}, + {TIFFTAG_ZSTD_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, + "ZSTD zstd_compress_level", NULL}, + {TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL}, +}; + +static int LERCVSetFieldBase(TIFF *tif, uint32_t tag, ...) +{ + LERCState *sp = LState(tif); + int ret; + va_list ap; + va_start(ap, tag); + ret = (*sp->vsetparent)(tif, tag, ap); + va_end(ap); + return ret; +} + +static int LERCVSetField(TIFF *tif, uint32_t tag, va_list ap) +{ + static const char module[] = "LERCVSetField"; + LERCState *sp = LState(tif); + + switch (tag) + { + case TIFFTAG_LERC_PARAMETERS: + { + uint32_t count = va_arg(ap, int); + int *params = va_arg(ap, int *); + if (count < 2) + { + TIFFErrorExtR(tif, module, + "Invalid count for LercParameters: %u", count); + return 0; + } + sp->lerc_version = params[0]; + sp->additional_compression = params[1]; + return LERCVSetFieldBase(tif, TIFFTAG_LERC_PARAMETERS, count, + params); + } + case TIFFTAG_LERC_MAXZERROR: + sp->maxzerror = va_arg(ap, double); + return 1; + case TIFFTAG_LERC_VERSION: + { + int params[2] = {0, 0}; + int version = va_arg(ap, int); + if (version != LERC_VERSION_2_4) + { + TIFFErrorExtR(tif, module, "Invalid value for LercVersion: %d", + version); + return 0; + } + sp->lerc_version = version; + params[0] = sp->lerc_version; + params[1] = sp->additional_compression; + return LERCVSetFieldBase(tif, TIFFTAG_LERC_PARAMETERS, 2, params); + } + case TIFFTAG_LERC_ADD_COMPRESSION: + { + int params[2] = {0, 0}; + int additional_compression = va_arg(ap, int); +#ifndef ZSTD_SUPPORT + if (additional_compression == LERC_ADD_COMPRESSION_ZSTD) + { + TIFFErrorExtR(tif, module, + "LERC_ZSTD requested, but ZSTD not available"); + return 0; + } +#endif + if (additional_compression != LERC_ADD_COMPRESSION_NONE && + additional_compression != LERC_ADD_COMPRESSION_DEFLATE && + additional_compression != LERC_ADD_COMPRESSION_ZSTD) + { + TIFFErrorExtR(tif, module, + "Invalid value for LercAdditionalCompression: %d", + additional_compression); + return 0; + } + sp->additional_compression = additional_compression; + params[0] = sp->lerc_version; + params[1] = sp->additional_compression; + return LERCVSetFieldBase(tif, TIFFTAG_LERC_PARAMETERS, 2, params); + } +#ifdef ZSTD_SUPPORT + case TIFFTAG_ZSTD_LEVEL: + { + sp->zstd_compress_level = (int)va_arg(ap, int); + if (sp->zstd_compress_level <= 0 || + sp->zstd_compress_level > ZSTD_maxCLevel()) + { + TIFFWarningExtR(tif, module, + "ZSTD_LEVEL should be between 1 and %d", + ZSTD_maxCLevel()); + } + return 1; + } +#endif + case TIFFTAG_ZIPQUALITY: + { + sp->zipquality = (int)va_arg(ap, int); + if (sp->zipquality < Z_DEFAULT_COMPRESSION || + sp->zipquality > LIBDEFLATE_MAX_COMPRESSION_LEVEL) + { + TIFFErrorExtR( + tif, module, + "Invalid ZipQuality value. Should be in [-1,%d] range", + LIBDEFLATE_MAX_COMPRESSION_LEVEL); + return 0; + } + +#if LIBDEFLATE_SUPPORT + if (sp->libdeflate_enc) + { + libdeflate_free_compressor(sp->libdeflate_enc); + sp->libdeflate_enc = NULL; + } +#endif + + return (1); + } + default: + return (*sp->vsetparent)(tif, tag, ap); + } + /*NOTREACHED*/ +} + +static int LERCVGetField(TIFF *tif, uint32_t tag, va_list ap) +{ + LERCState *sp = LState(tif); + + switch (tag) + { + case TIFFTAG_LERC_MAXZERROR: + *va_arg(ap, double *) = sp->maxzerror; + break; + case TIFFTAG_LERC_VERSION: + *va_arg(ap, int *) = sp->lerc_version; + break; + case TIFFTAG_LERC_ADD_COMPRESSION: + *va_arg(ap, int *) = sp->additional_compression; + break; + case TIFFTAG_ZSTD_LEVEL: + *va_arg(ap, int *) = sp->zstd_compress_level; + break; + case TIFFTAG_ZIPQUALITY: + *va_arg(ap, int *) = sp->zipquality; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return 1; +} + +int TIFFInitLERC(TIFF *tif, int scheme) +{ + static const char module[] = "TIFFInitLERC"; + LERCState *sp; + + (void)scheme; + assert(scheme == COMPRESSION_LERC); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, LERCFields, TIFFArrayCount(LERCFields))) + { + TIFFErrorExtR(tif, module, "Merging LERC codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t *)_TIFFcallocExt(tif, 1, sizeof(LERCState)); + if (tif->tif_data == NULL) + goto bad; + sp = LState(tif); + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = LERCVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = LERCVSetField; /* hook for codec tags */ + + /* + * Install codec methods. + */ + tif->tif_fixuptags = LERCFixupTags; + tif->tif_setupdecode = LERCSetupDecode; + tif->tif_predecode = LERCPreDecode; + tif->tif_decoderow = LERCDecode; + tif->tif_decodestrip = LERCDecode; + tif->tif_decodetile = LERCDecode; + tif->tif_setupencode = LERCSetupEncode; + tif->tif_preencode = LERCPreEncode; + tif->tif_postencode = LERCPostEncode; + tif->tif_encoderow = LERCEncode; + tif->tif_encodestrip = LERCEncode; + tif->tif_encodetile = LERCEncode; + tif->tif_cleanup = LERCCleanup; + + /* Default values for codec-specific fields */ + TIFFSetField(tif, TIFFTAG_LERC_VERSION, LERC_VERSION_2_4); + TIFFSetField(tif, TIFFTAG_LERC_ADD_COMPRESSION, LERC_ADD_COMPRESSION_NONE); + sp->maxzerror = 0.0; + sp->zstd_compress_level = 9; /* default comp. level */ + sp->zipquality = Z_DEFAULT_COMPRESSION; /* default comp. level */ + sp->state = 0; + + return 1; +bad: + TIFFErrorExtR(tif, module, "No space for LERC state block"); + return 0; +} +#endif /* LERC_SUPPORT */ diff --git a/LibTiff/tif_luv.c b/LibTiff/tif_luv.c index eb622b9b..021756d5 100644 --- a/LibTiff/tif_luv.c +++ b/LibTiff/tif_luv.c @@ -1,26 +1,24 @@ -/* $Id: tif_luv.c,v 1.17.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1997 Greg Ward Larson * Copyright (c) 1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -36,7 +34,7 @@ * 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 + * 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: @@ -147,191 +145,242 @@ * quantization errors into noise. */ +#include #include #include -#include /* * State block for each open TIFF * file using LogLuv compression/decompression. */ -typedef struct logLuvState LogLuvState; +typedef struct logLuvState LogLuvState; -struct logLuvState { - int user_datafmt; /* user data format */ - int encode_meth; /* encoding method */ - int pixel_size; /* bytes per pixel */ +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 */ - tidata_t* tbuf; /* translation buffer */ - int tbuflen; /* buffer length */ - void (*tfunc)(LogLuvState*, tidata_t, int); + 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 */ + 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 DecoderState(tif) ((LogLuvState *)(tif)->tif_data) +#define EncoderState(tif) ((LogLuvState *)(tif)->tif_data) -#define SGILOGDATAFMT_UNKNOWN -1 +#define SGILOGDATAFMT_UNKNOWN -1 -#define MINRUN 4 /* minimum run length */ +#define MINRUN 4 /* minimum run length */ /* * Decode a string of 16-bit gray pixels. */ -static int -LogL16Decode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +static int LogL16Decode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) { - LogLuvState* sp = DecoderState(tif); - int shft, i, npixels; - unsigned char* bp; - int16* tp; - int16 b; - int cc, rc; - - assert(s == 0); - assert(sp != NULL); - - npixels = occ / sp->pixel_size; - - if (sp->user_datafmt == SGILOGDATAFMT_16BIT) - tp = (int16*) op; - else { - assert(sp->tbuflen >= npixels); - tp = (int16*) sp->tbuf; - } - _TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0])); - - bp = (unsigned char*) tif->tif_rawcp; - cc = tif->tif_rawcc; - /* get each byte string */ - for (shft = 2*8; (shft -= 8) >= 0; ) { - for (i = 0; i < npixels && cc > 0; ) - if (*bp >= 128) { /* run */ - rc = *bp++ + (2-128); - b = (int16)(*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)*bp++ << shft; - } - if (i != npixels) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "LogL16Decode: Not enough data at row %d (short %d pixels)", - tif->tif_row, npixels - i); - tif->tif_rawcp = (tidata_t) bp; - tif->tif_rawcc = cc; - return (0); - } - } - (*sp->tfunc)(sp, op, npixels); - tif->tif_rawcp = (tidata_t) bp; - tif->tif_rawcc = cc; - return (1); + 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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, tidata_t op, tsize_t occ, tsample_t s) +static int LogLuvDecode24(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) { - LogLuvState* sp = DecoderState(tif); - int cc, i, npixels; - unsigned char* bp; - uint32* tp; - - assert(s == 0); - assert(sp != NULL); - - npixels = occ / sp->pixel_size; - - if (sp->user_datafmt == SGILOGDATAFMT_RAW) - tp = (uint32 *)op; - else { - assert(sp->tbuflen >= npixels); - tp = (uint32 *) sp->tbuf; - } - /* copy to array of uint32 */ - bp = (unsigned char*) tif->tif_rawcp; - cc = tif->tif_rawcc; - for (i = 0; i < npixels && cc > 0; i++) { - tp[i] = bp[0] << 16 | bp[1] << 8 | bp[2]; - bp += 3; - cc -= 3; - } - tif->tif_rawcp = (tidata_t) bp; - tif->tif_rawcc = cc; - if (i != npixels) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "LogLuvDecode24: Not enough data at row %d (short %d pixels)", - tif->tif_row, npixels - i); - return (0); - } - (*sp->tfunc)(sp, op, npixels); - return (1); + 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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, tidata_t op, tsize_t occ, tsample_t s) +static int LogLuvDecode32(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) { - LogLuvState* sp; - int shft, i, npixels; - unsigned char* bp; - uint32* tp; - uint32 b; - int cc, rc; - - assert(s == 0); - sp = DecoderState(tif); - assert(sp != NULL); - - npixels = occ / sp->pixel_size; - - if (sp->user_datafmt == SGILOGDATAFMT_RAW) - tp = (uint32*) op; - else { - assert(sp->tbuflen >= npixels); - tp = (uint32*) sp->tbuf; - } - _TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0])); - - bp = (unsigned char*) tif->tif_rawcp; - cc = tif->tif_rawcc; - /* get each byte string */ - for (shft = 4*8; (shft -= 8) >= 0; ) { - for (i = 0; i < npixels && cc > 0; ) - if (*bp >= 128) { /* run */ - rc = *bp++ + (2-128); - b = (uint32)*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)*bp++ << shft; - } - if (i != npixels) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "LogLuvDecode32: Not enough data at row %d (short %d pixels)", - tif->tif_row, npixels - i); - tif->tif_rawcp = (tidata_t) bp; - tif->tif_rawcc = cc; - return (0); - } - } - (*sp->tfunc)(sp, op, npixels); - tif->tif_rawcp = (tidata_t) bp; - tif->tif_rawcc = cc; - return (1); + 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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); } /* @@ -339,15 +388,20 @@ LogLuvDecode32(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) * maintain synchrony with the encode algorithm, which * is row by row. */ -static int -LogLuvDecodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +static int LogLuvDecodeStrip(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - tsize_t rowlen = TIFFScanlineSize(tif); - - assert(cc%rowlen == 0); - while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) - bp += rowlen, cc -= rowlen; - return (cc == 0); + 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); } /* @@ -355,267 +409,342 @@ LogLuvDecodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) * maintain synchrony with the encode algorithm, which * is row by row. */ -static int -LogLuvDecodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +static int LogLuvDecodeTile(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - tsize_t rowlen = TIFFTileRowSize(tif); - - assert(cc%rowlen == 0); - while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) - bp += rowlen, cc -= rowlen; - return (cc == 0); + 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, tidata_t bp, tsize_t cc, tsample_t s) +static int LogL16Encode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - LogLuvState* sp = EncoderState(tif); - int shft, i, j, npixels; - tidata_t op; - int16* tp; - int16 b; - int occ, rc=0, mask, beg; - - assert(s == 0); - assert(sp != NULL); - npixels = cc / sp->pixel_size; - - if (sp->user_datafmt == SGILOGDATAFMT_16BIT) - tp = (int16*) bp; - else { - tp = (int16*) sp->tbuf; - assert(sp->tbuflen >= npixels); - (*sp->tfunc)(sp, bp, npixels); - } - /* compress each byte string */ - op = tif->tif_rawcp; - occ = tif->tif_rawdatasize - tif->tif_rawcc; - for (shft = 2*8; (shft -= 8) >= 0; ) - 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 (-1); - 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) (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) (tp[i] & mask);/*check short run */ - j = i+1; - while ((tp[j++] & mask) == b) - if (j == beg) { - *op++ = (tidataval_t)(128-2+j-i); - *op++ = (tidataval_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 (-1); - op = tif->tif_rawcp; - occ = tif->tif_rawdatasize - tif->tif_rawcc; - } - *op++ = (tidataval_t) j; occ--; - while (j--) { - *op++ = (tidataval_t) (tp[i++] >> shft & 0xff); - occ--; - } - } - if (rc >= MINRUN) { /* write out run */ - *op++ = (tidataval_t) (128-2+rc); - *op++ = (tidataval_t) (tp[beg] >> shft & 0xff); - occ -= 2; - } else - rc = 0; - } - tif->tif_rawcp = op; - tif->tif_rawcc = tif->tif_rawdatasize - occ; - - return (1); + 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) + { + TIFFErrorExtR(tif, 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, tidata_t bp, tsize_t cc, tsample_t s) +static int LogLuvEncode24(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - LogLuvState* sp = EncoderState(tif); - int i, npixels, occ; - tidata_t op; - uint32* tp; - - assert(s == 0); - assert(sp != NULL); - npixels = cc / sp->pixel_size; - - if (sp->user_datafmt == SGILOGDATAFMT_RAW) - tp = (uint32*) bp; - else { - tp = (uint32*) sp->tbuf; - assert(sp->tbuflen >= npixels); - (*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 (-1); - op = tif->tif_rawcp; - occ = tif->tif_rawdatasize - tif->tif_rawcc; - } - *op++ = (tidataval_t)(*tp >> 16); - *op++ = (tidataval_t)(*tp >> 8 & 0xff); - *op++ = (tidataval_t)(*tp++ & 0xff); - occ -= 3; - } - tif->tif_rawcp = op; - tif->tif_rawcc = tif->tif_rawdatasize - occ; - - return (1); + 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) + { + TIFFErrorExtR(tif, 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, tidata_t bp, tsize_t cc, tsample_t s) +static int LogLuvEncode32(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - LogLuvState* sp = EncoderState(tif); - int shft, i, j, npixels; - tidata_t op; - uint32* tp; - uint32 b; - int occ, rc=0, mask, beg; - - assert(s == 0); - assert(sp != NULL); - - npixels = cc / sp->pixel_size; - - if (sp->user_datafmt == SGILOGDATAFMT_RAW) - tp = (uint32*) bp; - else { - tp = (uint32*) sp->tbuf; - assert(sp->tbuflen >= npixels); - (*sp->tfunc)(sp, bp, npixels); - } - /* compress each byte string */ - op = tif->tif_rawcp; - occ = tif->tif_rawdatasize - tif->tif_rawcc; - for (shft = 4*8; (shft -= 8) >= 0; ) - 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 (-1); - 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++ = (tidataval_t)(128-2+j-i); - *op++ = (tidataval_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 (-1); - op = tif->tif_rawcp; - occ = tif->tif_rawdatasize - tif->tif_rawcc; - } - *op++ = (tidataval_t) j; occ--; - while (j--) { - *op++ = (tidataval_t)(tp[i++] >> shft & 0xff); - occ--; - } - } - if (rc >= MINRUN) { /* write out run */ - *op++ = (tidataval_t) (128-2+rc); - *op++ = (tidataval_t)(tp[beg] >> shft & 0xff); - occ -= 2; - } else - rc = 0; - } - tif->tif_rawcp = op; - tif->tif_rawcc = tif->tif_rawdatasize - occ; - - return (1); + 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; + 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) + { + TIFFErrorExtR(tif, 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) + { + const uint32_t mask = 0xffU << shft; /* find next run */ + 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; + } + 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, tidata_t bp, tsize_t cc, tsample_t s) +static int LogLuvEncodeStrip(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - tsize_t rowlen = TIFFScanlineSize(tif); - - assert(cc%rowlen == 0); - while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) - bp += rowlen, cc -= rowlen; - return (cc == 0); + 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, tidata_t bp, tsize_t cc, tsample_t s) +static int LogLuvEncodeTile(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - tsize_t rowlen = TIFFTileRowSize(tif); - - assert(cc%rowlen == 0); - while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1) - bp += rowlen, cc -= rowlen; - return (cc == 0); + 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); } /* @@ -625,183 +754,192 @@ LogLuvEncodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) #include "uvcode.h" #ifndef UVSCALE -#define U_NEU 0.210526316 -#define V_NEU 0.473684211 -#define UVSCALE 410. +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 +#define UVSCALE 410. #endif -#ifndef M_LN2 -#define M_LN2 0.69314718055994530942 +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 #endif #ifndef M_PI -#define M_PI 3.14159265358979323846 +#define M_PI 3.14159265358979323846 #endif -#define log2(x) ((1./M_LN2)*log(x)) -#define exp2(x) exp(M_LN2*(x)) +#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)) -#define itrunc(x,m) ((m)==SGILOGENCODE_NODITHER ? \ - (int)(x) : \ - (int)((x) + rand()*(1./RAND_MAX) - .5)) +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 */ + double + LogL16toY(int p16) /* compute luminance from 16-bit LogL */ { - int Le = p16 & 0x7fff; - double Y; + 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 (!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 */ + 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 itrunc(256.*(log2(Y) + 64.), em); - if (Y < -5.4136769e-20) - return (~0x7fff | itrunc(256.*(log2(-Y) + 64.), em)); - return (0); + 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, tidata_t op, int n) +static void L16toY(LogLuvState *sp, uint8_t *op, tmsize_t n) { - int16* l16 = (int16*) sp->tbuf; - float* yp = (float*) op; + int16_t *l16 = (int16_t *)sp->tbuf; + float *yp = (float *)op; - while (n-- > 0) - *yp++ = (float)LogL16toY(*l16++); + while (n-- > 0) + *yp++ = (float)LogL16toY(*l16++); } -static void -L16toGry(LogLuvState* sp, tidata_t op, int n) +static void L16toGry(LogLuvState *sp, uint8_t *op, tmsize_t n) { - int16* l16 = (int16*) sp->tbuf; - uint8* gp = (uint8*) op; - - while (n-- > 0) { - double Y = LogL16toY(*l16++); - *gp++ = (uint8) ((Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256.*sqrt(Y))); - } + 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, tidata_t op, int n) +static void L16fromY(LogLuvState *sp, uint8_t *op, tmsize_t n) { - int16* l16 = (int16*) sp->tbuf; - float* yp = (float*) op; + int16_t *l16 = (int16_t *)sp->tbuf; + float *yp = (float *)op; - while (n-- > 0) - *l16++ = (int16) (LogL16fromY(*yp++, sp->encode_meth)); + while (n-- > 0) + *l16++ = (int16_t)(LogL16fromY(*yp++, sp->encode_meth)); } #if !LOGLUV_PUBLIC static #endif -void -XYZtoRGB24(float xyz[3], uint8 rgb[3]) + void + XYZtoRGB24(float *xyz, uint8_t *rgb) { - 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)((r<=0.) ? 0 : (r >= 1.) ? 255 : (int)(256.*sqrt(r))); - rgb[1] = (uint8)((g<=0.) ? 0 : (g >= 1.) ? 255 : (int)(256.*sqrt(g))); - rgb[2] = (uint8)((b<=0.) ? 0 : (b >= 1.) ? 255 : (int)(256.*sqrt(b))); + 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 */ + 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 (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 */ + 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 itrunc(64.*(log2(Y) + 12.), em); + 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 ) +#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_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]); + 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 @@ -810,820 +948,891 @@ oog_encode(double u, double v) /* encode out-of-gamut chroma */ #if !LOGLUV_PUBLIC static #endif -int -uv_encode(double u, double v, int em) /* encode (u',v') coordinates */ + 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 = 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 = 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); + register int vi, ui; + + /* check for NaN */ + if (u != u || v != v) + { + u = U_NEU; + v = V_NEU; + } + + 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 + 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); + 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 p, float XYZ[3]) + void + LogLuv24toXYZ(uint32_t p, float *XYZ) { - 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); + 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 -LogLuv24fromXYZ(float XYZ[3], int em) + uint32_t + LogLuv24fromXYZ(float *XYZ, 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); + 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, tidata_t op, int n) +static void Luv24toXYZ(LogLuvState *sp, uint8_t *op, tmsize_t n) { - uint32* luv = (uint32*) sp->tbuf; - float* xyz = (float*) op; - - while (n-- > 0) { - LogLuv24toXYZ(*luv, xyz); - xyz += 3; - luv++; - } + 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, tidata_t op, int n) +static void Luv24toLuv48(LogLuvState *sp, uint8_t *op, tmsize_t n) { - uint32* luv = (uint32*) sp->tbuf; - int16* luv3 = (int16*) op; - - while (n-- > 0) { - double u, v; - - *luv3++ = (int16)((*luv >> 12 & 0xffd) + 13314); - if (uv_decode(&u, &v, *luv&0x3fff) < 0) { - u = U_NEU; - v = V_NEU; - } - *luv3++ = (int16)(u * (1L<<15)); - *luv3++ = (int16)(v * (1L<<15)); - luv++; - } + 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, tidata_t op, int n) +static void Luv24toRGB(LogLuvState *sp, uint8_t *op, tmsize_t n) { - uint32* luv = (uint32*) sp->tbuf; - uint8* rgb = (uint8*) op; + uint32_t *luv = (uint32_t *)sp->tbuf; + uint8_t *rgb = (uint8_t *)op; - while (n-- > 0) { - float xyz[3]; + while (n-- > 0) + { + float xyz[3]; - LogLuv24toXYZ(*luv++, xyz); - XYZtoRGB24(xyz, rgb); - rgb += 3; - } + LogLuv24toXYZ(*luv++, xyz); + XYZtoRGB24(xyz, rgb); + rgb += 3; + } } -static void -Luv24fromXYZ(LogLuvState* sp, tidata_t op, int n) +static void Luv24fromXYZ(LogLuvState *sp, uint8_t *op, tmsize_t n) { - uint32* luv = (uint32*) sp->tbuf; - float* xyz = (float*) op; - - while (n-- > 0) { - *luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth); - xyz += 3; - } + 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, tidata_t op, int n) +static void Luv24fromLuv48(LogLuvState *sp, uint8_t *op, tmsize_t n) { - uint32* luv = (uint32*) sp->tbuf; - int16* luv3 = (int16*) 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 = 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)Le << 14 | Ce; - luv3 += 3; - } + 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 p, float XYZ[3]) + void + LogLuv32toXYZ(uint32_t p, float *XYZ) { - 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); + 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 -LogLuv32fromXYZ(float XYZ[3], int em) + uint32_t + LogLuv32fromXYZ(float *XYZ, 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 = itrunc(UVSCALE*u, em); - if (ue > 255) ue = 255; - if (v <= 0.) ve = 0; - else ve = itrunc(UVSCALE*v, em); - if (ve > 255) ve = 255; - /* combine encodings */ - return (Le << 16 | ue << 8 | ve); + 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, tidata_t op, int n) +static void Luv32toXYZ(LogLuvState *sp, uint8_t *op, tmsize_t n) { - uint32* luv = (uint32*) sp->tbuf; - float* xyz = (float*) op; - - while (n-- > 0) { - LogLuv32toXYZ(*luv++, xyz); - xyz += 3; - } + uint32_t *luv = (uint32_t *)sp->tbuf; + float *xyz = (float *)op; + + while (n-- > 0) + { + LogLuv32toXYZ(*luv++, xyz); + xyz += 3; + } } -static void -Luv32toLuv48(LogLuvState* sp, tidata_t op, int n) +static void Luv32toLuv48(LogLuvState *sp, uint8_t *op, tmsize_t n) { - uint32* luv = (uint32*) sp->tbuf; - int16* luv3 = (int16*) op; - - while (n-- > 0) { - double u, v; - - *luv3++ = (int16)(*luv >> 16); - u = 1./UVSCALE * ((*luv>>8 & 0xff) + .5); - v = 1./UVSCALE * ((*luv & 0xff) + .5); - *luv3++ = (int16)(u * (1L<<15)); - *luv3++ = (int16)(v * (1L<<15)); - luv++; - } + 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, tidata_t op, int n) +static void Luv32toRGB(LogLuvState *sp, uint8_t *op, tmsize_t n) { - uint32* luv = (uint32*) sp->tbuf; - uint8* rgb = (uint8*) op; + uint32_t *luv = (uint32_t *)sp->tbuf; + uint8_t *rgb = (uint8_t *)op; - while (n-- > 0) { - float xyz[3]; + while (n-- > 0) + { + float xyz[3]; - LogLuv32toXYZ(*luv++, xyz); - XYZtoRGB24(xyz, rgb); - rgb += 3; - } + LogLuv32toXYZ(*luv++, xyz); + XYZtoRGB24(xyz, rgb); + rgb += 3; + } } -static void -Luv32fromXYZ(LogLuvState* sp, tidata_t op, int n) +static void Luv32fromXYZ(LogLuvState *sp, uint8_t *op, tmsize_t n) { - uint32* luv = (uint32*) sp->tbuf; - float* xyz = (float*) op; - - while (n-- > 0) { - *luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth); - xyz += 3; - } + 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, tidata_t op, int n) +static void Luv32fromLuv48(LogLuvState *sp, uint8_t *op, tmsize_t n) { - uint32* luv = (uint32*) sp->tbuf; - int16* luv3 = (int16*) op; - - if (sp->encode_meth == SGILOGENCODE_NODITHER) { - while (n-- > 0) { - *luv++ = (uint32)luv3[0] << 16 | - (luv3[1]*(uint32)(UVSCALE+.5) >> 7 & 0xff00) | - (luv3[2]*(uint32)(UVSCALE+.5) >> 15 & 0xff); - luv3 += 3; - } - return; - } - while (n-- > 0) { - *luv++ = (uint32)luv3[0] << 16 | - (itrunc(luv3[1]*(UVSCALE/(1<<15)), sp->encode_meth) << 8 & 0xff00) | - (itrunc(luv3[2]*(UVSCALE/(1<<15)), sp->encode_meth) & 0xff); - luv3 += 3; - } + 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, tidata_t op, int n) +static void _logLuvNop(LogLuvState *sp, uint8_t *op, tmsize_t n) { - (void) sp; (void) op; (void) n; + (void)sp; + (void)op; + (void)n; } -static int -LogL16GuessDataFmt(TIFFDirectory *td) +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); - } +#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); + return (SGILOGDATAFMT_UNKNOWN); } -static uint32 -multiply(size_t m1, size_t m2) +static tmsize_t multiply_ms(tmsize_t m1, tmsize_t m2) { - uint32 bytes = m1 * m2; - - if (m1 && bytes / m1 != m2) - bytes = 0; - - return bytes; + return _TIFFMultiplySSize(NULL, m1, m2, NULL); } -static int -LogL16InitState(TIFF* tif) +static int LogL16InitState(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - LogLuvState* sp = DecoderState(tif); - static const char module[] = "LogL16InitState"; - - assert(sp != NULL); - assert(td->td_photometric == PHOTOMETRIC_LOGL); - - /* 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); - break; - case SGILOGDATAFMT_8BIT: - sp->pixel_size = sizeof (uint8); - break; - default: - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "No support for converting user data format to LogL"); - return (0); - } - if( isTiled(tif) ) - sp->tbuflen = multiply(td->td_tilewidth, td->td_tilelength); - else - sp->tbuflen = multiply(td->td_imagewidth, td->td_rowsperstrip); - if (multiply(sp->tbuflen, sizeof (int16)) == 0 || - (sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (int16))) == NULL) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for SGILog translation buffer", - tif->tif_name); - return (0); - } - return (1); + 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) + { + TIFFErrorExtR(tif, 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: + TIFFErrorExtR(tif, 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 *)_TIFFmallocExt( + tif, sp->tbuflen * sizeof(int16_t))) == NULL) + { + TIFFErrorExtR(tif, module, "No space for SGILog translation buffer"); + return (0); + } + return (1); } -static int -LogLuvGuessDataFmt(TIFFDirectory *td) +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; + 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); + } + /* + * 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 int LogLuvInitState(TIFF *tif) { - TIFFDirectory* td = &tif->tif_dir; - LogLuvState* sp = DecoderState(tif); - static const char module[] = "LogLuvInitState"; - - 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); - break; - case SGILOGDATAFMT_RAW: - sp->pixel_size = sizeof (uint32); - break; - case SGILOGDATAFMT_8BIT: - sp->pixel_size = 3*sizeof (uint8); - break; - default: - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "No support for converting user data format to LogLuv"); - return (0); - } - if( isTiled(tif) ) - sp->tbuflen = multiply(td->td_tilewidth, td->td_tilelength); - else - sp->tbuflen = multiply(td->td_imagewidth, td->td_rowsperstrip); - if (multiply(sp->tbuflen, sizeof (uint32)) == 0 || - (sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (uint32))) == NULL) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for SGILog translation buffer", - tif->tif_name); - return (0); - } - return (1); + 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) + { + TIFFErrorExtR(tif, 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: + TIFFErrorExtR( + tif, 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 *)_TIFFmallocExt( + tif, sp->tbuflen * sizeof(uint32_t))) == NULL) + { + TIFFErrorExtR(tif, module, "No space for SGILog translation buffer"); + return (0); + } + return (1); } -static int -LogLuvSetupDecode(TIFF* tif) +static int LogLuvFixupTags(TIFF *tif) { - 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, tif->tif_name, - "Inappropriate photometric interpretation %d for SGILog compression; %s", - td->td_photometric, "must be either LogLUV or LogL"); - break; - } - return (0); + (void)tif; + return (1); } -static int -LogLuvSetupEncode(TIFF* tif) +static int LogLuvSetupDecode(TIFF *tif) { - LogLuvState* sp = EncoderState(tif); - TIFFDirectory* td = &tif->tif_dir; - - switch (td->td_photometric) { - case PHOTOMETRIC_LOGLUV: - if (!LogLuvInitState(tif)) - break; - 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)) - break; - 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, tif->tif_name, - "Inappropriate photometric interpretation %d for SGILog compression; %s", - td->td_photometric, "must be either LogLUV or LogL"); - break; - } - return (1); + 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: + TIFFErrorExtR(tif, 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: + TIFFErrorExtR(tif, 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, tif->tif_name, - "SGILog compression supported only for %s, or raw data", - td->td_photometric == PHOTOMETRIC_LOGL ? "Y, L" : "XYZ, Luv"); - return (0); + TIFFErrorExtR(tif, 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) +static void LogLuvClose(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - - /* - * 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. - */ - td->td_samplesperpixel = - (td->td_photometric == PHOTOMETRIC_LOGL) ? 1 : 3; - td->td_bitspersample = 16; - td->td_sampleformat = SAMPLEFORMAT_INT; + 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) +static void LogLuvCleanup(TIFF *tif) { - LogLuvState* sp = (LogLuvState *)tif->tif_data; + LogLuvState *sp = (LogLuvState *)tif->tif_data; - assert(sp != 0); + assert(sp != 0); - tif->tif_tagmethods.vgetfield = sp->vgetparent; - tif->tif_tagmethods.vsetfield = sp->vsetparent; + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; - if (sp->tbuf) - _TIFFfree(sp->tbuf); - _TIFFfree(sp); - tif->tif_data = NULL; + if (sp->tbuf) + _TIFFfreeExt(tif, sp->tbuf); + _TIFFfreeExt(tif, sp); + tif->tif_data = NULL; - _TIFFSetDefaultCompressionState(tif); + _TIFFSetDefaultCompressionState(tif); } -static int -LogLuvVSetField(TIFF* tif, ttag_t tag, va_list ap) +static int LogLuvVSetField(TIFF *tif, uint32_t tag, va_list ap) { - LogLuvState* sp = DecoderState(tif); - int bps, fmt; - - switch (tag) { - case TIFFTAG_SGILOGDATAFMT: - sp->user_datafmt = 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) : (tsize_t) -1; - tif->tif_scanlinesize = TIFFScanlineSize(tif); - return (1); - case TIFFTAG_SGILOGENCODE: - sp->encode_meth = va_arg(ap, int); - if (sp->encode_meth != SGILOGENCODE_NODITHER && - sp->encode_meth != SGILOGENCODE_RANDITHER) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Unknown encoding %d for LogLuv compression", - sp->encode_meth); - return (0); - } - return (1); - default: - return (*sp->vsetparent)(tif, tag, 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: + TIFFErrorExtR( + tif, 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) + { + TIFFErrorExtR(tif, 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, ttag_t tag, va_list 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); - } + 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 TIFFFieldInfo LogLuvFieldInfo[] = { - { TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, FIELD_PSEUDO, - TRUE, FALSE, "SGILogDataFmt"}, - { TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, FIELD_PSEUDO, - TRUE, FALSE, "SGILogEncode"} -}; +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) +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 (!_TIFFMergeFieldInfo(tif, LogLuvFieldInfo, - TIFFArrayCount(LogLuvFieldInfo))) { - 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 = (tidata_t) _TIFFmalloc(sizeof (LogLuvState)); - if (tif->tif_data == NULL) - goto bad; - sp = (LogLuvState*) tif->tif_data; - _TIFFmemset((tdata_t)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_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); + 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))) + { + TIFFErrorExtR(tif, 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 *)_TIFFmallocExt(tif, 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); + TIFFErrorExtR(tif, 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/LibTiff/tif_lzma.c b/LibTiff/tif_lzma.c new file mode 100644 index 00000000..4cfd5e88 --- /dev/null +++ b/LibTiff/tif_lzma.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2010, Andrey Kiselev + * + * 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 LZMA_SUPPORT +/* + * TIFF Library. + * + * LZMA2 Compression Support + * + * You need an LZMA2 SDK to link with. See http://tukaani.org/xz/ for details. + * + * The codec is derived from ZLIB codec (tif_zip.c). + */ + +#include "lzma.h" +#include "tif_predict.h" + +#include + +/* + * State block for each open TIFF file using LZMA2 compression/decompression. + */ +typedef struct +{ + TIFFPredictorState predict; + lzma_stream stream; + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + lzma_options_delta opt_delta; /* delta filter options */ + lzma_options_lzma opt_lzma; /* LZMA2 filter options */ + int preset; /* compression level */ + lzma_check check; /* type of the integrity check */ + int state; /* state flags */ +#define LSTATE_INIT_DECODE 0x01 +#define LSTATE_INIT_ENCODE 0x02 + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +} LZMAState; + +#define LState(tif) ((LZMAState *)(tif)->tif_data) +#define DecoderState(tif) LState(tif) +#define EncoderState(tif) LState(tif) + +static int LZMAEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); +static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); + +static const char *LZMAStrerror(lzma_ret ret) +{ + switch (ret) + { + case LZMA_OK: + return "operation completed successfully"; + case LZMA_STREAM_END: + return "end of stream was reached"; + case LZMA_NO_CHECK: + return "input stream has no integrity check"; + case LZMA_UNSUPPORTED_CHECK: + return "cannot calculate the integrity check"; + case LZMA_GET_CHECK: + return "integrity check type is now available"; + case LZMA_MEM_ERROR: + return "cannot allocate memory"; + case LZMA_MEMLIMIT_ERROR: + return "memory usage limit was reached"; + case LZMA_FORMAT_ERROR: + return "file format not recognized"; + case LZMA_OPTIONS_ERROR: + return "invalid or unsupported options"; + case LZMA_DATA_ERROR: + return "data is corrupt"; + case LZMA_BUF_ERROR: + return "no progress is possible (stream is truncated or corrupt)"; + case LZMA_PROG_ERROR: + return "programming error"; + default: + return "unidentified liblzma error"; + } +} + +static int LZMAFixupTags(TIFF *tif) +{ + (void)tif; + return 1; +} + +static int LZMASetupDecode(TIFF *tif) +{ + LZMAState *sp = DecoderState(tif); + + assert(sp != NULL); + + /* if we were last encoding, terminate this mode */ + if (sp->state & LSTATE_INIT_ENCODE) + { + lzma_end(&sp->stream); + sp->state = 0; + } + + sp->state |= LSTATE_INIT_DECODE; + return 1; +} + +/* + * Setup state for decoding a strip. + */ +static int LZMAPreDecode(TIFF *tif, uint16_t s) +{ + static const char module[] = "LZMAPreDecode"; + LZMAState *sp = DecoderState(tif); + lzma_ret ret; + + (void)s; + assert(sp != NULL); + + if ((sp->state & LSTATE_INIT_DECODE) == 0) + tif->tif_setupdecode(tif); + + sp->stream.next_in = tif->tif_rawdata; + sp->stream.avail_in = (size_t)tif->tif_rawcc; + if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc) + { + TIFFErrorExtR(tif, module, + "Liblzma cannot deal with buffers this size"); + return 0; + } + + /* + * Disable memory limit when decoding. UINT64_MAX is a flag to disable + * the limit, we are passing (uint64_t)-1 which should be the same. + */ + ret = lzma_stream_decoder(&sp->stream, (uint64_t)-1, 0); + if (ret != LZMA_OK) + { + TIFFErrorExtR(tif, module, "Error initializing the stream decoder, %s", + LZMAStrerror(ret)); + return 0; + } + return 1; +} + +static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) +{ + static const char module[] = "LZMADecode"; + LZMAState *sp = DecoderState(tif); + + (void)s; + assert(sp != NULL); + assert(sp->state == LSTATE_INIT_DECODE); + + sp->stream.next_in = tif->tif_rawcp; + sp->stream.avail_in = (size_t)tif->tif_rawcc; + + sp->stream.next_out = op; + sp->stream.avail_out = (size_t)occ; + if ((tmsize_t)sp->stream.avail_out != occ) + { + TIFFErrorExtR(tif, module, + "Liblzma cannot deal with buffers this size"); + return 0; + } + + do + { + /* + * Save the current stream state to properly recover from the + * decoding errors later. + */ + const uint8_t *next_in = sp->stream.next_in; + size_t avail_in = sp->stream.avail_in; + + lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN); + if (ret == LZMA_STREAM_END) + break; + if (ret == LZMA_MEMLIMIT_ERROR) + { + lzma_ret r = + lzma_stream_decoder(&sp->stream, lzma_memusage(&sp->stream), 0); + if (r != LZMA_OK) + { + TIFFErrorExtR(tif, module, + "Error initializing the stream decoder, %s", + LZMAStrerror(r)); + break; + } + sp->stream.next_in = next_in; + sp->stream.avail_in = avail_in; + continue; + } + if (ret != LZMA_OK) + { + TIFFErrorExtR(tif, module, + "Decoding error at scanline %" PRIu32 ", %s", + tif->tif_row, LZMAStrerror(ret)); + break; + } + } while (sp->stream.avail_out > 0); + if (sp->stream.avail_out != 0) + { + TIFFErrorExtR(tif, module, + "Not enough data at scanline %" PRIu32 + " (short %" TIFF_SIZE_FORMAT " bytes)", + tif->tif_row, sp->stream.avail_out); + return 0; + } + + tif->tif_rawcp = (uint8_t *)sp->stream.next_in; /* cast away const */ + tif->tif_rawcc = sp->stream.avail_in; + + return 1; +} + +static int LZMASetupEncode(TIFF *tif) +{ + LZMAState *sp = EncoderState(tif); + + assert(sp != NULL); + if (sp->state & LSTATE_INIT_DECODE) + { + lzma_end(&sp->stream); + sp->state = 0; + } + + sp->state |= LSTATE_INIT_ENCODE; + return 1; +} + +/* + * Reset encoding state at the start of a strip. + */ +static int LZMAPreEncode(TIFF *tif, uint16_t s) +{ + static const char module[] = "LZMAPreEncode"; + LZMAState *sp = EncoderState(tif); + lzma_ret ret; + + (void)s; + assert(sp != NULL); + if (sp->state != LSTATE_INIT_ENCODE) + tif->tif_setupencode(tif); + + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = (size_t)tif->tif_rawdatasize; + if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) + { + TIFFErrorExtR(tif, module, + "Liblzma cannot deal with buffers this size"); + return 0; + } + ret = lzma_stream_encoder(&sp->stream, sp->filters, sp->check); + if (ret != LZMA_OK) + { + TIFFErrorExtR(tif, module, "Error in lzma_stream_encoder(): %s", + LZMAStrerror(ret)); + return 0; + } + return 1; +} + +/* + * Encode a chunk of pixels. + */ +static int LZMAEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "LZMAEncode"; + LZMAState *sp = EncoderState(tif); + + assert(sp != NULL); + assert(sp->state == LSTATE_INIT_ENCODE); + + (void)s; + sp->stream.next_in = bp; + sp->stream.avail_in = (size_t)cc; + if ((tmsize_t)sp->stream.avail_in != cc) + { + TIFFErrorExtR(tif, module, + "Liblzma cannot deal with buffers this size"); + return 0; + } + do + { + lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN); + if (ret != LZMA_OK) + { + TIFFErrorExtR(tif, module, + "Encoding error at scanline %" PRIu32 ", %s", + tif->tif_row, LZMAStrerror(ret)); + 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 = + (size_t) + tif->tif_rawdatasize; /* this is a safe typecast, as check + is made already in LZMAPreEncode */ + } + } 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 LZMAPostEncode(TIFF *tif) +{ + static const char module[] = "LZMAPostEncode"; + LZMAState *sp = EncoderState(tif); + lzma_ret ret; + + sp->stream.avail_in = 0; + do + { + ret = lzma_code(&sp->stream, LZMA_FINISH); + switch (ret) + { + case LZMA_STREAM_END: + case LZMA_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 = + (size_t) + tif->tif_rawdatasize; /* this is a safe typecast, as + check is made already in + ZIPPreEncode */ + } + break; + default: + TIFFErrorExtR(tif, module, "Liblzma error: %s", + LZMAStrerror(ret)); + return 0; + } + } while (ret != LZMA_STREAM_END); + return 1; +} + +static void LZMACleanup(TIFF *tif) +{ + LZMAState *sp = LState(tif); + + assert(sp != 0); + + (void)TIFFPredictorCleanup(tif); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->state) + { + lzma_end(&sp->stream); + sp->state = 0; + } + _TIFFfreeExt(tif, sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int LZMAVSetField(TIFF *tif, uint32_t tag, va_list ap) +{ + static const char module[] = "LZMAVSetField"; + LZMAState *sp = LState(tif); + + switch (tag) + { + case TIFFTAG_LZMAPRESET: + sp->preset = (int)va_arg(ap, int); + lzma_lzma_preset(&sp->opt_lzma, sp->preset); + if (sp->state & LSTATE_INIT_ENCODE) + { + lzma_ret ret = + lzma_stream_encoder(&sp->stream, sp->filters, sp->check); + if (ret != LZMA_OK) + { + TIFFErrorExtR(tif, module, "Liblzma error: %s", + LZMAStrerror(ret)); + } + } + return 1; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + /*NOTREACHED*/ +} + +static int LZMAVGetField(TIFF *tif, uint32_t tag, va_list ap) +{ + LZMAState *sp = LState(tif); + + switch (tag) + { + case TIFFTAG_LZMAPRESET: + *va_arg(ap, int *) = sp->preset; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return 1; +} + +static const TIFFField lzmaFields[] = { + {TIFFTAG_LZMAPRESET, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, + "LZMA2 Compression Preset", NULL}, +}; + +int TIFFInitLZMA(TIFF *tif, int scheme) +{ + static const char module[] = "TIFFInitLZMA"; + LZMAState *sp; + lzma_stream tmp_stream = LZMA_STREAM_INIT; + + (void)scheme; + assert(scheme == COMPRESSION_LZMA); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, lzmaFields, TIFFArrayCount(lzmaFields))) + { + TIFFErrorExtR(tif, module, "Merging LZMA2 codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(LZMAState)); + if (tif->tif_data == NULL) + goto bad; + sp = LState(tif); + memcpy(&sp->stream, &tmp_stream, sizeof(lzma_stream)); + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = LZMAVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = LZMAVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->preset = LZMA_PRESET_DEFAULT; /* default comp. level */ + sp->check = LZMA_CHECK_NONE; + sp->state = 0; + + /* Data filters. So far we are using delta and LZMA2 filters only. */ + sp->opt_delta.type = LZMA_DELTA_TYPE_BYTE; + /* + * The sample size in bytes seems to be reasonable distance for delta + * filter. + */ + sp->opt_delta.dist = (tif->tif_dir.td_bitspersample % 8) + ? 1 + : tif->tif_dir.td_bitspersample / 8; + sp->filters[0].id = LZMA_FILTER_DELTA; + sp->filters[0].options = &sp->opt_delta; + + lzma_lzma_preset(&sp->opt_lzma, sp->preset); + sp->filters[1].id = LZMA_FILTER_LZMA2; + sp->filters[1].options = &sp->opt_lzma; + + sp->filters[2].id = LZMA_VLI_UNKNOWN; + sp->filters[2].options = NULL; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = LZMAFixupTags; + tif->tif_setupdecode = LZMASetupDecode; + tif->tif_predecode = LZMAPreDecode; + tif->tif_decoderow = LZMADecode; + tif->tif_decodestrip = LZMADecode; + tif->tif_decodetile = LZMADecode; + tif->tif_setupencode = LZMASetupEncode; + tif->tif_preencode = LZMAPreEncode; + tif->tif_postencode = LZMAPostEncode; + tif->tif_encoderow = LZMAEncode; + tif->tif_encodestrip = LZMAEncode; + tif->tif_encodetile = LZMAEncode; + tif->tif_cleanup = LZMACleanup; + /* + * Setup predictor setup. + */ + (void)TIFFPredictorInit(tif); + return 1; +bad: + TIFFErrorExtR(tif, module, "No space for LZMA2 state block"); + return 0; +} +#endif /* LZMA_SUPPORT */ diff --git a/LibTiff/tif_lzw.c b/LibTiff/tif_lzw.c index d4238663..d631fa10 100644 --- a/LibTiff/tif_lzw.c +++ b/LibTiff/tif_lzw.c @@ -1,26 +1,25 @@ -/* $Id: tif_lzw.c,v 1.29.2.6 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * Copyright (c) 2022 Even Rouault * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -38,7 +37,13 @@ */ #include "tif_predict.h" +#include #include +#include + +/* Select the plausible largest natural integer type for the architecture */ +#define SIZEOF_WORDTYPE SIZEOF_SIZE_T +typedef size_t WordType; /* * NB: The 5.0 spec describes a different algorithm than Aldus @@ -53,34 +58,27 @@ * * 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 LZW_COMPAT /* include backwards compatibility code */ -#define MAXCODE(n) ((1L<<(n))-1) +#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 */ +#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) +#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) +#define CSIZE (MAXCODE(BITS_MAX) + 1024L) #else -#define CSIZE (MAXCODE(BITS_MAX)+1L) +#define CSIZE (MAXCODE(BITS_MAX) + 1L) #endif /* @@ -88,649 +86,936 @@ * compression/decompression. Note that the predictor * state block must be first in this data structure. */ -typedef struct { - TIFFPredictorState predict; /* predictor super class */ +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 */ - long nextdata; /* next bits of i/o */ - long nextbits; /* # of valid bits in lzw_nextdata */ + unsigned short nbits; /* # of bits/code */ + unsigned short maxcode; /* maximum code for lzw_nbits */ + unsigned short free_ent; /* next free entry in hash table */ + WordType nextdata; /* next bits of i/o */ + long nextbits; /* # of valid bits in lzw_nextdata */ - int rw_mode; /* preserve rw_mode from init */ + 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 +#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 hcode_t; /* codes fit in 16 bits */ -typedef struct { - long hash; - hcode_t code; +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 */ +typedef struct code_ent +{ + struct code_ent *next; + unsigned short length; /* string len, including this token */ + /* firstchar should be placed immediately before value in this structure */ + unsigned char firstchar; /* first token of string */ + unsigned char value; /* data value */ + bool repeated; } code_t; -typedef int (*decodeFunc)(TIFF*, tidata_t, tsize_t, tsample_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 - long dec_bitsleft; /* available bits in raw data */ -#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 */ - tidata_t enc_rawlimit; /* bound on tif_rawdata buffer */ - hash_t* enc_hashtab; /* kept separate for small machines */ +typedef struct +{ + LZWBaseState base; + + /* Decoding specific data */ + long dec_nbitsmask; /* lzw_nbits 1 bits, right adjusted */ + tmsize_t dec_restart; /* restart count */ + 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 */ + 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 */ + int read_error; /* whether a read error has occurred, and which should cause + further reads in the same strip/tile to be aborted */ + + /* Encoding specific data */ + int enc_oldcode; /* last code encountered */ + tmsize_t enc_checkpoint; /* point at which to clear table */ +#define CHECK_GAP 10000 /* enc_ratio check interval */ + tmsize_t enc_ratio; /* current compression ratio */ + tmsize_t enc_incount; /* (input) data bytes encoded */ + tmsize_t 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)) +#define LZWState(tif) ((LZWBaseState *)(tif)->tif_data) +#define DecoderState(tif) ((LZWCodecState *)LZWState(tif)) +#define EncoderState(tif) ((LZWCodecState *)LZWState(tif)) -static int LZWDecode(TIFF*, tidata_t, tsize_t, tsample_t); +static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s); #ifdef LZW_COMPAT -static int LZWDecodeCompat(TIFF*, tidata_t, tsize_t, tsample_t); +static int LZWDecodeCompat(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s); #endif -static void cl_hash(LZWCodecState*); +static void cl_hash(LZWCodecState *); /* * LZW Decoder. */ -#ifdef LZW_CHECKEOS +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 *)_TIFFmallocExt(tif, sizeof(LZWCodecState)); + if (tif->tif_data == NULL) + { + TIFFErrorExtR(tif, 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 *)_TIFFmallocExt(tif, CSIZE * sizeof(code_t)); + if (sp->dec_codetab == NULL) + { + TIFFErrorExtR(tif, module, "No space for LZW code table"); + return (0); + } + /* + * Pre-load the table. + */ + code = 255; + do + { + sp->dec_codetab[code].firstchar = (unsigned char)code; + sp->dec_codetab[code].value = (unsigned char)code; + sp->dec_codetab[code].repeated = true; + 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] */ + memset(&sp->dec_codetab[CODE_CLEAR], 0, + (CODE_FIRST - CODE_CLEAR) * sizeof(code_t)); + } + return (1); +} + /* - * This check shouldn't be necessary because each - * strip is suppose to be terminated with CODE_EOI. + * Setup state for decoding a strip. */ -#define NextCode(_tif, _sp, _bp, _code, _get) { \ - if ((_sp)->dec_bitsleft < nbits) { \ - TIFFWarningExt(_tif->tif_clientdata, _tif->tif_name, \ - "LZWDecode: Strip %d not terminated with EOI code", \ - _tif->tif_curstrip); \ - _code = CODE_EOI; \ - } else { \ - _get(_sp,_bp,_code); \ - (_sp)->dec_bitsleft -= nbits; \ - } \ +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) + { + TIFFWarningExtR(tif, 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) + { + TIFFErrorExtR(tif, 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); + sp->dec_bitsleft = 0; + sp->old_tif_rawcc = 0; + sp->dec_free_entp = sp->dec_codetab - 1; // + 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. + */ + sp->dec_oldcodep = &sp->dec_codetab[0]; + sp->dec_maxcodep = &sp->dec_codetab[sp->dec_nbitsmask - 1]; + sp->read_error = 0; + return (1); } + +/* + * Decode a "hunk of data". + */ + +/* Get the next 32 or 64-bit from the input data */ +#ifdef WORDS_BIGENDIAN +#define GetNextData(nextdata, bp) memcpy(&nextdata, bp, sizeof(nextdata)) +#elif SIZEOF_WORDTYPE == 8 +#if defined(__GNUC__) && defined(__x86_64__) +#define GetNextData(nextdata, bp) \ + nextdata = __builtin_bswap64(*(uint64_t *)(bp)) +#elif defined(_M_X64) +#define GetNextData(nextdata, bp) nextdata = _byteswap_uint64(*(uint64_t *)(bp)) +#elif defined(__GNUC__) +#define GetNextData(nextdata, bp) \ + memcpy(&nextdata, bp, sizeof(nextdata)); \ + nextdata = __builtin_bswap64(nextdata) +#else +#define GetNextData(nextdata, bp) \ + nextdata = (((uint64_t)bp[0]) << 56) | (((uint64_t)bp[1]) << 48) | \ + (((uint64_t)bp[2]) << 40) | (((uint64_t)bp[3]) << 32) | \ + (((uint64_t)bp[4]) << 24) | (((uint64_t)bp[5]) << 16) | \ + (((uint64_t)bp[6]) << 8) | (((uint64_t)bp[7])) +#endif +#elif SIZEOF_WORDTYPE == 4 +#if defined(__GNUC__) && defined(__i386__) +#define GetNextData(nextdata, bp) \ + nextdata = __builtin_bswap32(*(uint32_t *)(bp)) +#elif defined(_M_X86) +#define GetNextData(nextdata, bp) \ + nextdata = _byteswap_ulong(*(unsigned long *)(bp)) +#elif defined(__GNUC__) +#define GetNextData(nextdata, bp) \ + memcpy(&nextdata, bp, sizeof(nextdata)); \ + nextdata = __builtin_bswap32(nextdata) #else -#define NextCode(tif, sp, bp, code, get) get(sp, bp, code) +#define GetNextData(nextdata, bp) \ + nextdata = (((uint32_t)bp[0]) << 24) | (((uint32_t)bp[1]) << 16) | \ + (((uint32_t)bp[2]) << 8) | (((uint32_t)bp[3])) +#endif +#else +#error "Unhandled SIZEOF_WORDTYPE" #endif -static int -LZWSetupDecode(TIFF* tif) +#define GetNextCodeLZW() \ + do \ + { \ + nextbits -= nbits; \ + if (nextbits < 0) \ + { \ + if (dec_bitsleft >= 8 * SIZEOF_WORDTYPE) \ + { \ + unsigned codetmp = (unsigned)(nextdata << (-nextbits)); \ + GetNextData(nextdata, bp); \ + bp += SIZEOF_WORDTYPE; \ + nextbits += 8 * SIZEOF_WORDTYPE; \ + dec_bitsleft -= 8 * SIZEOF_WORDTYPE; \ + code = (WordType)((codetmp | (nextdata >> nextbits)) & \ + nbitsmask); \ + break; \ + } \ + else \ + { \ + if (dec_bitsleft < 8) \ + { \ + goto no_eoi; \ + } \ + nextdata = (nextdata << 8) | *(bp)++; \ + nextbits += 8; \ + dec_bitsleft -= 8; \ + if (nextbits < 0) \ + { \ + if (dec_bitsleft < 8) \ + { \ + goto no_eoi; \ + } \ + nextdata = (nextdata << 8) | *(bp)++; \ + nextbits += 8; \ + dec_bitsleft -= 8; \ + } \ + } \ + } \ + code = (WordType)((nextdata >> nextbits) & nbitsmask); \ + } while (0) + +static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s) { - LZWCodecState* sp = DecoderState(tif); - static const char module[] = " LZWSetupDecode"; - int code; - - if( sp == NULL ) + static const char module[] = "LZWDecode"; + LZWCodecState *sp = DecoderState(tif); + uint8_t *op = (uint8_t *)op0; + tmsize_t occ = occ0; + uint8_t *bp; + long nbits, nextbits, nbitsmask; + WordType nextdata; + code_t *free_entp, *maxcodep, *oldcodep; + + (void)s; + assert(sp != NULL); + assert(sp->dec_codetab != NULL); + + if (sp->read_error) + { + TIFFErrorExtR(tif, module, + "LZWDecode: Scanline %" PRIu32 " cannot be read due to " + "previous error", + tif->tif_row); + return 0; + } + + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) + { + tmsize_t residue; + + code_t *codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { /* - * Allocate state block so tag methods have storage to record - * values. + * 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. */ - tif->tif_data = (tidata_t) _TIFFmalloc(sizeof(LZWCodecState)); - if (tif->tif_data == NULL) + sp->dec_restart += occ; + do { - TIFFErrorExt(tif->tif_clientdata, "LZWPreDecode", "No space for LZW state block"); - return (0); + codep = codep->next; + } while (--residue > occ && codep); + if (codep) + { + uint8_t *tp = op + occ; + do + { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); } - - DecoderState(tif)->dec_codetab = NULL; - DecoderState(tif)->dec_decode = NULL; - - /* - * Setup predictor setup. - */ - (void) TIFFPredictorInit(tif); - - sp = DecoderState(tif); + return (1); } - - assert(sp != NULL); - - 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 = code; - sp->dec_codetab[code].firstchar = code; - sp->dec_codetab[code].length = 1; - sp->dec_codetab[code].next = NULL; - } while (code--); - /* - * Zero-out the unused entries - */ - _TIFFmemset(&sp->dec_codetab[CODE_CLEAR], 0, - (CODE_FIRST - CODE_CLEAR) * sizeof (code_t)); - } - return (1); + /* + * Residue satisfies only part of the decode request. + */ + op += residue; + occ -= residue; + uint8_t *tp = op; + do + { + *--tp = codep->value; + codep = codep->next; + } while (--residue && codep); + sp->dec_restart = 0; + } + + bp = (uint8_t *)tif->tif_rawcp; + sp->dec_bitsleft += (((uint64_t)tif->tif_rawcc - sp->old_tif_rawcc) << 3); + uint64_t dec_bitsleft = sp->dec_bitsleft; + 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; + code_t *const dec_codetab = sp->dec_codetab; + code_t *codep; + + if (occ == 0) + { + goto after_loop; + } + +begin: +{ + WordType code; + GetNextCodeLZW(); + codep = dec_codetab + code; + if (code >= CODE_FIRST) + goto code_above_or_equal_to_258; + if (code < 256) + goto code_below_256; + if (code == CODE_EOI) + goto after_loop; + goto code_clear; + +code_below_256: +{ + if (codep > free_entp) + goto error_code; + free_entp->next = oldcodep; + free_entp->firstchar = oldcodep->firstchar; + free_entp->length = oldcodep->length + 1; + free_entp->value = (uint8_t)code; + free_entp->repeated = + (bool)(oldcodep->repeated & (oldcodep->value == code)); + if (++free_entp > maxcodep) + { + if (++nbits > BITS_MAX) /* should not happen for a conformant encoder */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = dec_codetab + nbitsmask - 1; + if (free_entp >= &dec_codetab[CSIZE]) + { + /* At that point, the next valid states are either EOI or a */ + /* CODE_CLEAR. If a regular code is read, at the next */ + /* attempt at registering a new entry, we will error out */ + /* due to setting free_entp before any valid code */ + free_entp = dec_codetab - 1; + } + } + oldcodep = codep; + *op++ = (uint8_t)code; + occ--; + if (occ == 0) + goto after_loop; + goto begin; } -/* - * Setup state for decoding a strip. - */ -static int -LZWPreDecode(TIFF* tif, tsample_t s) +code_above_or_equal_to_258: { - LZWCodecState *sp = DecoderState(tif); + /* + * Add the new entry to the code table. + */ + + if (codep >= free_entp) + { + if (codep != free_entp) + goto error_code; + free_entp->value = oldcodep->firstchar; + } + else + { + free_entp->value = codep->firstchar; + } + free_entp->repeated = + (bool)(oldcodep->repeated & (oldcodep->value == free_entp->value)); + free_entp->next = oldcodep; + + free_entp->firstchar = oldcodep->firstchar; + free_entp->length = oldcodep->length + 1; + if (++free_entp > maxcodep) + { + if (++nbits > BITS_MAX) /* should not happen for a conformant encoder */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = dec_codetab + nbitsmask - 1; + if (free_entp >= &dec_codetab[CSIZE]) + { + /* At that point, the next valid states are either EOI or a */ + /* CODE_CLEAR. If a regular code is read, at the next */ + /* attempt at registering a new entry, we will error out */ + /* due to setting free_entp before any valid code */ + free_entp = dec_codetab - 1; + } + } + oldcodep = codep; + + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + /* tiny bit faster on x86_64 to store in unsigned short than int */ + unsigned short len = codep->length; + + if (len < 3) /* equivalent to len == 2 given all other conditions */ + { + if (occ <= 2) + { + if (occ == 2) + { + memcpy(op, &(codep->firstchar), 2); + op += 2; + occ -= 2; + goto after_loop; + } + goto too_short_buffer; + } + + memcpy(op, &(codep->firstchar), 2); + op += 2; + occ -= 2; + goto begin; /* we can save the comparison occ > 0 */ + } - (void) s; - assert(sp != NULL); - if( sp->dec_codetab == NULL ) + if (len == 3) + { + if (occ <= 3) { - tif->tif_setupdecode( tif ); + if (occ == 3) + { + op[0] = codep->firstchar; + op[1] = codep->next->value; + op[2] = codep->value; + op += 3; + occ -= 3; + goto after_loop; + } + goto too_short_buffer; } - /* - * Check for old bit-reversed codes. - */ - if (tif->tif_rawdata[0] == 0 && (tif->tif_rawdata[1] & 0x1)) { -#ifdef LZW_COMPAT - if (!sp->dec_decode) { - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, - "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, tif->tif_name, - "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 = tif->tif_rawcc << 3; -#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); + op[0] = codep->firstchar; + op[1] = codep->next->value; + op[2] = codep->value; + op += 3; + occ -= 3; + goto begin; /* we can save the comparison occ > 0 */ + } + + if (len > occ) + { + goto too_short_buffer; + } + + if (codep->repeated) + { + memset(op, codep->value, len); + op += len; + occ -= len; + if (occ == 0) + goto after_loop; + goto begin; + } + + uint8_t *tp = op + len; + + assert(len >= 4); + + *--tp = codep->value; + codep = codep->next; + *--tp = codep->value; + codep = codep->next; + *--tp = codep->value; + codep = codep->next; + *--tp = codep->value; + if (tp > op) + { + do + { + codep = codep->next; + *--tp = codep->value; + } while (tp > op); + } + + assert(occ >= len); + op += len; + occ -= len; + if (occ == 0) + goto after_loop; + goto begin; } -/* - * 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; \ +code_clear: +{ + free_entp = dec_codetab + CODE_FIRST; + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = dec_codetab + nbitsmask - 1; + do + { + GetNextCodeLZW(); + } while (code == CODE_CLEAR); /* consecutive CODE_CLEAR codes */ + if (code == CODE_EOI) + goto after_loop; + if (code > CODE_EOI) + { + goto error_code; + } + *op++ = (uint8_t)code; + occ--; + oldcodep = dec_codetab + code; + if (occ == 0) + goto after_loop; + goto begin; +} } -static void -codeLoop(TIFF* tif) +too_short_buffer: { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "LZWDecode: Bogus encoding, loop in the code table; scanline %d", - tif->tif_row); + /* + * 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; + uint8_t *tp = op + occ; + do + { + *--tp = codep->value; + codep = codep->next; + } while (--occ); } -static int -LZWDecode(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) -{ - 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, nextdata, nbitsmask; - code_t *codep, *free_entp, *maxcodep, *oldcodep; - - (void) s; - assert(sp != NULL); - assert(sp->dec_codetab != NULL); - /* - * 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 = t; - } while (--residue && codep); - sp->dec_restart = 0; - } - - bp = (unsigned char *)tif->tif_rawcp; - 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) { - 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); - if (code == CODE_EOI) - break; - if (code == CODE_CLEAR) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "LZWDecode: Corrupted LZW table at scanline %d", - 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, tif->tif_name, - "LZWDecode: Corrupted LZW table at scanline %d", - 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, tif->tif_name, - "LZWDecode: Corrupted LZW table at scanline %d", - 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, tif->tif_name, - "LZWDecode: Wrong length of decoded string: " - "data probably corrupted at scanline %d", - 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 = occ; - tp = op + occ; - do { - *--tp = codep->value; - codep = codep->next; - } while (--occ && codep); - if (codep) - codeLoop(tif); - } - break; - } - len = codep->length; - tp = op + len; - do { - int t; - --tp; - t = codep->value; - codep = codep->next; - *tp = t; - } while (codep && tp > op); - if (codep) { - codeLoop(tif); - break; - } - op += len, occ -= len; - } else - *op++ = (char)code, occ--; - } - - tif->tif_rawcp = (tidata_t) bp; - 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, tif->tif_name, - "LZWDecode: Not enough data at scanline %d (short %ld bytes)", - tif->tif_row, occ); - return (0); - } - return (1); +after_loop: + tif->tif_rawcc -= (tmsize_t)((uint8_t *)bp - tif->tif_rawcp); + tif->tif_rawcp = (uint8_t *)bp; + sp->old_tif_rawcc = tif->tif_rawcc; + sp->dec_bitsleft = dec_bitsleft; + 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) + { + TIFFErrorExtR(tif, module, + "Not enough data at scanline %" PRIu32 " (short %" PRIu64 + " bytes)", + tif->tif_row, (uint64_t)occ); + return (0); + } + return (1); + +no_eoi: + sp->read_error = 1; + TIFFErrorExtR(tif, module, + "LZWDecode: Strip %" PRIu32 " not terminated with EOI code", + tif->tif_curstrip); + return 0; +error_code: + sp->read_error = 1; + TIFFErrorExtR(tif, tif->tif_name, "Using code not yet in table"); + return 0; } #ifdef LZW_COMPAT + /* - * Decode a "hunk of data" for old images. + * This check shouldn't be necessary because each + * strip is suppose to be terminated with CODE_EOI. */ -#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; \ -} +#define NextCode(_tif, _sp, _bp, _code, _get, dec_bitsleft) \ + { \ + if (dec_bitsleft < (uint64_t)nbits) \ + { \ + TIFFWarningExtR(_tif, module, \ + "LZWDecode: Strip %" PRIu32 \ + " not terminated with EOI code", \ + _tif->tif_curstrip); \ + _code = CODE_EOI; \ + } \ + else \ + { \ + _get(_sp, _bp, _code); \ + dec_bitsleft -= nbits; \ + } \ + } -static int -LZWDecodeCompat(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +/* + * 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) { - LZWCodecState *sp = DecoderState(tif); - char *op = (char*) op0; - long occ = (long) occ0; - char *tp; - unsigned char *bp; - int code, nbits; - long nextbits, nextdata, nbitsmask; - code_t *codep, *free_entp, *maxcodep, *oldcodep; - - (void) s; - assert(sp != NULL); - /* - * 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; - 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) { - 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); - if (code == CODE_EOI) - break; - if (code == CODE_CLEAR) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "LZWDecode: Corrupted LZW table at scanline %d", - tif->tif_row); - return (0); - } - *op++ = 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, tif->tif_name, - "LZWDecodeCompat: Corrupted LZW table at scanline %d", - 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, tif->tif_name, - "LZWDecodeCompat: Corrupted LZW table at scanline %d", - 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) { - char *op_orig = op; - /* - * Code maps to a string, copy string - * value to output (written in reverse). - */ - if(codep->length == 0) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "LZWDecodeCompat: Wrong length of decoded " - "string: data probably corrupted at scanline %d", - 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; - } - op += codep->length, occ -= codep->length; - tp = op; - do { - *--tp = codep->value; - } while( (codep = codep->next) != NULL && tp > op_orig); - } else - *op++ = code, occ--; - } - - tif->tif_rawcp = (tidata_t) bp; - sp->lzw_nbits = 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, tif->tif_name, - "LZWDecodeCompat: Not enough data at scanline %d (short %ld bytes)", - tif->tif_row, occ); - return (0); - } - return (1); + static const char module[] = "LZWDecodeCompat"; + LZWCodecState *sp = DecoderState(tif); + uint8_t *op = (uint8_t *)op0; + tmsize_t occ = occ0; + uint8_t *tp; + uint8_t *bp; + int code, nbits; + int len; + long nextbits, nbitsmask; + WordType nextdata; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + (void)s; + assert(sp != NULL); + + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) + { + tmsize_t 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 = (uint8_t *)tif->tif_rawcp; + + sp->dec_bitsleft += (((uint64_t)tif->tif_rawcc - sp->old_tif_rawcc) << 3); + uint64_t dec_bitsleft = sp->dec_bitsleft; + + 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, dec_bitsleft); + 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, dec_bitsleft); + } while (code == CODE_CLEAR); /* consecutive CODE_CLEAR codes */ + if (code == CODE_EOI) + break; + if (code > CODE_CLEAR) + { + TIFFErrorExtR( + tif, tif->tif_name, + "LZWDecode: Corrupted LZW table at scanline %" PRIu32, + tif->tif_row); + return (0); + } + *op++ = (uint8_t)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]) + { + TIFFErrorExtR(tif, 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]) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR( + tif, 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 + { + *--tp = codep->value; + codep = codep->next; + } while (codep && tp > op); + assert(occ >= len); + op += len; + occ -= len; + } + else + { + *op++ = (uint8_t)code; + occ--; + } + } + + tif->tif_rawcc -= (tmsize_t)((uint8_t *)bp - tif->tif_rawcp); + tif->tif_rawcp = (uint8_t *)bp; + + sp->old_tif_rawcc = tif->tif_rawcc; + sp->dec_bitsleft = dec_bitsleft; + + 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) + { + TIFFErrorExtR(tif, module, + "Not enough data at scanline %" PRIu32 " (short %" PRIu64 + " bytes)", + tif->tif_row, (uint64_t)occ); + return (0); + } + return (1); } #endif /* LZW_COMPAT */ @@ -738,363 +1023,416 @@ LZWDecodeCompat(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) * LZW Encoding. */ -static int -LZWSetupEncode(TIFF* tif) +static int LZWSetupEncode(TIFF *tif) { - LZWCodecState* sp = EncoderState(tif); - static const char module[] = "LZWSetupEncode"; - - 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); + static const char module[] = "LZWSetupEncode"; + LZWCodecState *sp = EncoderState(tif); + + assert(sp != NULL); + sp->enc_hashtab = (hash_t *)_TIFFmallocExt(tif, HSIZE * sizeof(hash_t)); + if (sp->enc_hashtab == NULL) + { + TIFFErrorExtR(tif, 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, tsample_t s) +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); + 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; \ -} -#define PutNextCode(op, c) { \ - nextdata = (nextdata << nbits) | c; \ - nextbits += nbits; \ - *op++ = (unsigned char)(nextdata >> (nextbits-8)); \ - nextbits -= 8; \ - if (nextbits >= 8) { \ - *op++ = (unsigned char)(nextdata >> (nextbits-8)); \ - nextbits -= 8; \ - } \ - outcount += nbits; \ -} +#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 + * 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. + * 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. + * for the decoder. */ -static int -LZWEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +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; - long nextdata, nextbits; - int free_ent, maxcode, nbits; - tidata_t op, 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 = 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 */ + register LZWCodecState *sp = EncoderState(tif); + register long fcode; + register hash_t *hp; + register int h, c; + hcode_t ent; + long disp; + tmsize_t incount, outcount, checkpoint; + WordType 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; + /* + * 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 'cuz 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 = (tsize_t)(op - tif->tif_rawdata); - TIFFFlushData1(tif); - op = tif->tif_rawdata; - } - PutNextCode(op, ent); - ent = c; - hp->code = 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 = free_ent; - sp->lzw_maxcode = maxcode; - sp->lzw_nbits = nbits; - tif->tif_rawcp = op; - return (1); + 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) + { + tmsize_t 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) +static int LZWPostEncode(TIFF *tif) { - register LZWCodecState *sp = EncoderState(tif); - tidata_t op = tif->tif_rawcp; - long nextbits = sp->lzw_nextbits; - long nextdata = sp->lzw_nextdata; - long outcount = sp->enc_outcount; - int nbits = sp->lzw_nbits; - - if (op > sp->enc_rawlimit) { - tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata); - TIFFFlushData1(tif); - op = tif->tif_rawdata; - } - if (sp->enc_oldcode != (hcode_t) -1) { - PutNextCode(op, sp->enc_oldcode); - sp->enc_oldcode = (hcode_t) -1; - } - PutNextCode(op, CODE_EOI); - if (nextbits > 0) - *op++ = (unsigned char)(nextdata << (8-nextbits)); - tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata); - return (1); + register LZWCodecState *sp = EncoderState(tif); + uint8_t *op = tif->tif_rawcp; + long nextbits = sp->lzw_nextbits; + WordType nextdata = sp->lzw_nextdata; + tmsize_t 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); + (void)outcount; + return (1); } /* * Reset encoding hash table. */ -static void -cl_hash(LZWCodecState* sp) +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; + 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) +static void LZWCleanup(TIFF *tif) { - (void)TIFFPredictorCleanup(tif); + (void)TIFFPredictorCleanup(tif); - assert(tif->tif_data != 0); + assert(tif->tif_data != 0); - if (DecoderState(tif)->dec_codetab) - _TIFFfree(DecoderState(tif)->dec_codetab); + if (DecoderState(tif)->dec_codetab) + _TIFFfreeExt(tif, DecoderState(tif)->dec_codetab); - if (EncoderState(tif)->enc_hashtab) - _TIFFfree(EncoderState(tif)->enc_hashtab); + if (EncoderState(tif)->enc_hashtab) + _TIFFfreeExt(tif, EncoderState(tif)->enc_hashtab); - _TIFFfree(tif->tif_data); - tif->tif_data = NULL; + _TIFFfreeExt(tif, tif->tif_data); + tif->tif_data = NULL; - _TIFFSetDefaultCompressionState(tif); + _TIFFSetDefaultCompressionState(tif); } -int -TIFFInitLZW(TIFF* tif, int scheme) +int TIFFInitLZW(TIFF *tif, int scheme) { - assert(scheme == COMPRESSION_LZW); - /* - * Allocate state block so tag methods have storage to record values. - */ - tif->tif_data = (tidata_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_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); + 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 *)_TIFFmallocExt(tif, 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, "TIFFInitLZW", - "No space for LZW state block"); - return (0); + TIFFErrorExtR(tif, module, "No space for LZW state block"); + return (0); } /* @@ -1115,15 +1453,6 @@ TIFFInitLZW(TIFF* tif, int scheme) * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * 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/LibTiff/tif_next.c b/LibTiff/tif_next.c index d7652bb4..f000574e 100644 --- a/LibTiff/tif_next.c +++ b/LibTiff/tif_next.c @@ -1,26 +1,24 @@ -/* $Id: tif_next.c,v 1.8.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -32,123 +30,165 @@ * 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); break; \ - } \ -} +#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) +#define LITERALROW 0x00 +#define LITERALSPAN 0x40 +#define WHITE ((1 << 2) - 1) -static int -NeXTDecode(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +static int NeXTDecode(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s) { - unsigned char *bp, *op; - tsize_t cc; - tidata_t row; - tsize_t scanline, n; + 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 = buf, cc = occ; cc-- > 0;) - *op++ = 0xff; + (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; - for (row = buf; 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: { - tsize_t off; - /* - * The scanline has a literal span that begins at some - * offset. - */ - 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 npixels = 0, grey; - uint32 imagewidth = tif->tif_dir.td_imagewidth; + bp = (unsigned char *)tif->tif_rawcp; + cc = tif->tif_rawcc; + scanline = tif->tif_scanlinesize; + if (occ % scanline) + { + TIFFErrorExtR(tif, 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 = (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) - SETPIXEL(op, grey); - if (npixels >= imagewidth) - break; - if (cc == 0) - goto bad; - n = *bp++, cc--; - } - break; - } - } - } - tif->tif_rawcp = (tidata_t) bp; - tif->tif_rawcc = cc; - return (1); + /* + * 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) + { + TIFFErrorExtR(tif, 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, tif->tif_name, "NeXTDecode: Not enough data for scanline %ld", - (long) tif->tif_row); - return (0); + TIFFErrorExtR(tif, module, "Not enough data for scanline %" PRIu32, + tif->tif_row); + return (0); } -int -TIFFInitNeXT(TIFF* tif, int scheme) +static int NeXTPreDecode(TIFF *tif, uint16_t s) { - (void) scheme; - tif->tif_decoderow = NeXTDecode; - tif->tif_decodestrip = NeXTDecode; - tif->tif_decodetile = NeXTDecode; - return (1); + static const char module[] = "NeXTPreDecode"; + TIFFDirectory *td = &tif->tif_dir; + (void)s; + + if (td->td_bitspersample != 2) + { + TIFFErrorExtR(tif, module, "Unsupported BitsPerSample = %" PRIu16, + td->td_bitspersample); + return (0); + } + 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: - */ +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 */ diff --git a/LibTiff/tif_ojpeg.c b/LibTiff/tif_ojpeg.c index 9ae856cf..ea572091 100644 --- a/LibTiff/tif_ojpeg.c +++ b/LibTiff/tif_ojpeg.c @@ -1,5 +1,3 @@ -/* $Id: tif_ojpeg.c,v 1.24.2.6 2010-06-08 23:29:51 bfriesen Exp $ */ - /* WARNING: The type of JPEG encapsulation defined by the TIFF Version 6.0 specification is now totally obsolete and deprecated for new applications and images. This file was was created solely in order to read unconverted images @@ -39,116 +37,123 @@ OF THIS SOFTWARE. Joris Van Damme and/or AWare Systems may be available for custom - developement. If you like what you see, and need anything similar or related, + development. If you like what you see, and need anything similar or related, contact . */ /* What is what, and what is not? - This decoder starts with an input stream, that is essentially the JpegInterchangeFormat - stream, if any, followed by the strile data, if any. This stream is read in - OJPEGReadByte and related functions. - - It analyzes the start of this stream, until it encounters non-marker data, i.e. - compressed image data. Some of the header markers it sees have no actual content, - like the SOI marker, and APP/COM markers that really shouldn't even be there. Some - other markers do have content, and the valuable bits and pieces of information - in these markers are saved, checking all to verify that the stream is more or - less within expected bounds. This happens inside the OJPEGReadHeaderInfoSecStreamXxx + This decoder starts with an input stream, that is essentially the + JpegInterchangeFormat stream, if any, followed by the strile data, if any. + This stream is read in OJPEGReadByte and related functions. + + It analyzes the start of this stream, until it encounters non-marker data, + i.e. compressed image data. Some of the header markers it sees have no actual + content, like the SOI marker, and APP/COM markers that really shouldn't even + be there. Some other markers do have content, and the valuable bits and + pieces of information in these markers are saved, checking all to verify that + the stream is more or less within expected bounds. This happens inside the + OJPEGReadHeaderInfoSecStreamXxx functions. + + Some OJPEG imagery contains no valid JPEG header markers. This situation is + picked up on if we've seen no SOF marker when we're at the start of the + compressed image data. In this case, the tables are read from JpegXxxTables + tags, and the other bits and pieces of information is initialized to its most + basic value. This is implemented in the OJPEGReadHeaderInfoSecTablesXxx functions. - Some OJPEG imagery contains no valid JPEG header markers. This situation is picked - up on if we've seen no SOF marker when we're at the start of the compressed image - data. In this case, the tables are read from JpegXxxTables tags, and the other - bits and pieces of information is initialized to its most basic value. This is - implemented in the OJPEGReadHeaderInfoSecTablesXxx functions. - - When this is complete, a good and valid JPEG header can be assembled, and this is - passed through to LibJpeg. When that's done, the remainder of the input stream, i.e. - the compressed image data, can be passed through unchanged. This is done in - OJPEGWriteStream functions. - - LibTiff rightly expects to know the subsampling values before decompression. Just like - in new-style JPEG-in-TIFF, though, or even more so, actually, the YCbCrsubsampling - tag is notoriously unreliable. To correct these tag values with the ones inside - the JPEG stream, the first part of the input stream is pre-scanned in - OJPEGSubsamplingCorrect, making no note of any other data, reporting no warnings - or errors, up to the point where either these values are read, or it's clear they - aren't there. This means that some of the data is read twice, but we feel speed - in correcting these values is important enough to warrant this sacrifice. Allthough - there is currently no define or other configuration mechanism to disable this behaviour, - the actual header scanning is build to robustly respond with error report if it - should encounter an uncorrected mismatch of subsampling values. See + When this is complete, a good and valid JPEG header can be assembled, and + this is passed through to LibJpeg. When that's done, the remainder of the + input stream, i.e. the compressed image data, can be passed through + unchanged. This is done in OJPEGWriteStream functions. + + LibTiff rightly expects to know the subsampling values before decompression. + Just like in new-style JPEG-in-TIFF, though, or even more so, actually, the + YCbCrsubsampling tag is notoriously unreliable. To correct these tag values + with the ones inside the JPEG stream, the first part of the input stream is + pre-scanned in OJPEGSubsamplingCorrect, making no note of any other data, + reporting no warnings or errors, up to the point where either these values + are read, or it's clear they aren't there. This means that some of the data + is read twice, but we feel speed in correcting these values is important + enough to warrant this sacrifice. Although there is currently no define or + other configuration mechanism to disable this behavior, the actual header + scanning is build to robustly respond with error report if it should + encounter an uncorrected mismatch of subsampling values. See OJPEGReadHeaderInfoSecStreamSof. - The restart interval and restart markers are the most tricky part... The restart - interval can be specified in a tag. It can also be set inside the input JPEG stream. - It can be used inside the input JPEG stream. If reading from strile data, we've - consistenly discovered the need to insert restart markers in between the different - striles, as is also probably the most likely interpretation of the original TIFF 6.0 - specification. With all this setting of interval, and actual use of markers that is not - predictable at the time of valid JPEG header assembly, the restart thing may turn - out the Achilles heel of this implementation. Fortunately, most OJPEG writer vendors - succeed in reading back what they write, which may be the reason why we've been able - to discover ways that seem to work. - - Some special provision is made for planarconfig separate OJPEG files. These seem - to consistently contain header info, a SOS marker, a plane, SOS marker, plane, SOS, - and plane. This may or may not be a valid JPEG configuration, we don't know and don't - care. We want LibTiff to be able to access the planes individually, without huge - buffering inside LibJpeg, anyway. So we compose headers to feed to LibJpeg, in this - case, that allow us to pass a single plane such that LibJpeg sees a valid - single-channel JPEG stream. Locating subsequent SOS markers, and thus subsequent - planes, is done inside OJPEGReadSecondarySos. - - The benefit of the scheme is... that it works, basically. We know of no other that - does. It works without checking software tag, or otherwise going about things in an - OJPEG flavor specific manner. Instead, it is a single scheme, that covers the cases - with and without JpegInterchangeFormat, with and without striles, with part of - the header in JpegInterchangeFormat and remainder in first strile, etc. It is forgiving - and robust, may likely work with OJPEG flavors we've not seen yet, and makes most out - of the data. - - Another nice side-effect is that a complete JPEG single valid stream is build if - planarconfig is not separate (vast majority). We may one day use that to build - converters to JPEG, and/or to new-style JPEG compression inside TIFF. - - A dissadvantage is the lack of random access to the individual striles. This is the - reason for much of the complicated restart-and-position stuff inside OJPEGPreDecode. - Applications would do well accessing all striles in order, as this will result in - a single sequential scan of the input stream, and no restarting of LibJpeg decoding - session. + The restart interval and restart markers are the most tricky part... The + restart interval can be specified in a tag. It can also be set inside the + input JPEG stream. It can be used inside the input JPEG stream. If reading + from strile data, we've consistently discovered the need to insert restart + markers in between the different striles, as is also probably the most likely + interpretation of the original TIFF 6.0 specification. With all this setting + of interval, and actual use of markers that is not predictable at the time of + valid JPEG header assembly, the restart thing may turn out the Achilles heel + of this implementation. Fortunately, most OJPEG writer vendors succeed in + reading back what they write, which may be the reason why we've been able to + discover ways that seem to work. + + Some special provision is made for planarconfig separate OJPEG files. These + seem to consistently contain header info, a SOS marker, a plane, SOS marker, + plane, SOS, and plane. This may or may not be a valid JPEG configuration, we + don't know and don't care. We want LibTiff to be able to access the planes + individually, without huge buffering inside LibJpeg, anyway. So we compose + headers to feed to LibJpeg, in this case, that allow us to pass a single + plane such that LibJpeg sees a valid single-channel JPEG stream. Locating + subsequent SOS markers, and thus subsequent planes, is done inside + OJPEGReadSecondarySos. + + The benefit of the scheme is... that it works, basically. We know of no other + that does. It works without checking software tag, or otherwise going about + things in an OJPEG flavor specific manner. Instead, it is a single scheme, + that covers the cases with and without JpegInterchangeFormat, with and + without striles, with part of the header in JpegInterchangeFormat and + remainder in first strile, etc. It is forgiving and robust, may likely work + with OJPEG flavors we've not seen yet, and makes most out of the data. + + Another nice side-effect is that a complete JPEG single valid stream is build + if planarconfig is not separate (vast majority). We may one day use that to + build converters to JPEG, and/or to new-style JPEG compression inside TIFF. + + A disadvantage is the lack of random access to the individual striles. This + is the reason for much of the complicated restart-and-position stuff inside + OJPEGPreDecode. Applications would do well accessing all striles in order, as + this will result in a single sequential scan of the input stream, and no + restarting of LibJpeg decoding session. */ +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN #include "tiffiop.h" #ifdef OJPEG_SUPPORT /* Configuration defines here are: - * JPEG_ENCAP_EXTERNAL: The normal way to call libjpeg, uses longjump. In some environments, - * like eg LibTiffDelphi, this is not possible. For this reason, the actual calls to - * libjpeg, with longjump stuff, are encapsulated in dedicated functions. When - * JPEG_ENCAP_EXTERNAL is defined, these encapsulating functions are declared external - * to this unit, and can be defined elsewhere to use stuff other then longjump. - * The default mode, without JPEG_ENCAP_EXTERNAL, implements the call encapsulators - * here, internally, with normal longjump. - * SETJMP, LONGJMP, JMP_BUF: On some machines/environments a longjump equivalent is - * conviniently available, but still it may be worthwhile to use _setjmp or sigsetjmp - * in place of plain setjmp. These macros will make it easier. It is useless - * to fiddle with these if you define JPEG_ENCAP_EXTERNAL. - * OJPEG_BUFFER: Define the size of the desired buffer here. Should be small enough so as to guarantee - * instant processing, optimal streaming and optimal use of processor cache, but also big - * enough so as to not result in significant call overhead. It should be at least a few - * bytes to accomodate some structures (this is verified in asserts), but it would not be - * sensible to make it this small anyway, and it should be at most 64K since it is indexed - * with uint16. We recommend 2K. - * EGYPTIANWALK: You could also define EGYPTIANWALK here, but it is not used anywhere and has - * absolutely no effect. That is why most people insist the EGYPTIANWALK is a bit silly. + * JPEG_ENCAP_EXTERNAL: The normal way to call libjpeg, uses longjump. In some + * environments, like eg LibTiffDelphi, this is not possible. For this reason, + * the actual calls to libjpeg, with longjump stuff, are encapsulated in + * dedicated functions. When JPEG_ENCAP_EXTERNAL is defined, these encapsulating + * functions are declared external to this unit, and can be defined elsewhere to + * use stuff other then longjump. The default mode, without JPEG_ENCAP_EXTERNAL, + * implements the call encapsulators here, internally, with normal longjump. + * SETJMP, LONGJMP, JMP_BUF: On some machines/environments a longjump equivalent + * is conveniently available, but still it may be worthwhile to use _setjmp or + * sigsetjmp in place of plain setjmp. These macros will make it easier. It is + * useless to fiddle with these if you define JPEG_ENCAP_EXTERNAL. OJPEG_BUFFER: + * Define the size of the desired buffer here. Should be small enough so as to + * guarantee instant processing, optimal streaming and optimal use of processor + * cache, but also big enough so as to not result in significant call overhead. + * It should be at least a few bytes to accommodate some structures (this is + * verified in asserts), but it would not be sensible to make it this small + * anyway, and it should be at most 64K since it is indexed with uint16_t. We + * recommend 2K. EGYPTIANWALK: You could also define EGYPTIANWALK here, but it + * is not used anywhere and has absolutely no effect. That is why most people + * insist the EGYPTIANWALK is a bit silly. */ -/* #define LIBJPEG_ENCAP_EXTERNAL */ +/* define LIBJPEG_ENCAP_EXTERNAL */ #define SETJMP(jbuf) setjmp(jbuf) -#define LONGJMP(jbuf,code) longjmp(jbuf,code) +#define LONGJMP(jbuf, code) longjmp(jbuf, code) #define JMP_BUF jmp_buf #define OJPEG_BUFFER 2048 /* define EGYPTIANWALK */ @@ -166,2273 +171,2645 @@ #define JPEG_MARKER_APP0 0xE0 #define JPEG_MARKER_COM 0xFE -#define FIELD_OJPEG_JPEGINTERCHANGEFORMAT (FIELD_CODEC+0) -#define FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH (FIELD_CODEC+1) -#define FIELD_OJPEG_JPEGQTABLES (FIELD_CODEC+2) -#define FIELD_OJPEG_JPEGDCTABLES (FIELD_CODEC+3) -#define FIELD_OJPEG_JPEGACTABLES (FIELD_CODEC+4) -#define FIELD_OJPEG_JPEGPROC (FIELD_CODEC+5) -#define FIELD_OJPEG_JPEGRESTARTINTERVAL (FIELD_CODEC+6) -#define FIELD_OJPEG_COUNT 7 - -static const TIFFFieldInfo ojpeg_field_info[] = { - {TIFFTAG_JPEGIFOFFSET,1,1,TIFF_LONG,FIELD_OJPEG_JPEGINTERCHANGEFORMAT,TRUE,FALSE,"JpegInterchangeFormat"}, - {TIFFTAG_JPEGIFBYTECOUNT,1,1,TIFF_LONG,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH,TRUE,FALSE,"JpegInterchangeFormatLength"}, - {TIFFTAG_JPEGQTABLES,TIFF_VARIABLE,TIFF_VARIABLE,TIFF_LONG,FIELD_OJPEG_JPEGQTABLES,FALSE,TRUE,"JpegQTables"}, - {TIFFTAG_JPEGDCTABLES,TIFF_VARIABLE,TIFF_VARIABLE,TIFF_LONG,FIELD_OJPEG_JPEGDCTABLES,FALSE,TRUE,"JpegDcTables"}, - {TIFFTAG_JPEGACTABLES,TIFF_VARIABLE,TIFF_VARIABLE,TIFF_LONG,FIELD_OJPEG_JPEGACTABLES,FALSE,TRUE,"JpegAcTables"}, - {TIFFTAG_JPEGPROC,1,1,TIFF_SHORT,FIELD_OJPEG_JPEGPROC,FALSE,FALSE,"JpegProc"}, - {TIFFTAG_JPEGRESTARTINTERVAL,1,1,TIFF_SHORT,FIELD_OJPEG_JPEGRESTARTINTERVAL,FALSE,FALSE,"JpegRestartInterval"}, +#define FIELD_OJPEG_JPEGINTERCHANGEFORMAT (FIELD_CODEC + 0) +#define FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH (FIELD_CODEC + 1) +#define FIELD_OJPEG_JPEGQTABLES (FIELD_CODEC + 2) +#define FIELD_OJPEG_JPEGDCTABLES (FIELD_CODEC + 3) +#define FIELD_OJPEG_JPEGACTABLES (FIELD_CODEC + 4) +#define FIELD_OJPEG_JPEGPROC (FIELD_CODEC + 5) +#define FIELD_OJPEG_JPEGRESTARTINTERVAL (FIELD_CODEC + 6) + +static const TIFFField ojpegFields[] = { + {TIFFTAG_JPEGIFOFFSET, 1, 1, TIFF_LONG8, 0, TIFF_SETGET_UINT64, + TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGINTERCHANGEFORMAT, TRUE, FALSE, + "JpegInterchangeFormat", NULL}, + {TIFFTAG_JPEGIFBYTECOUNT, 1, 1, TIFF_LONG8, 0, TIFF_SETGET_UINT64, + TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH, TRUE, + FALSE, "JpegInterchangeFormatLength", NULL}, + {TIFFTAG_JPEGQTABLES, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG8, 0, + TIFF_SETGET_C32_UINT64, TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGQTABLES, + FALSE, TRUE, "JpegQTables", NULL}, + {TIFFTAG_JPEGDCTABLES, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG8, 0, + TIFF_SETGET_C32_UINT64, TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGDCTABLES, + FALSE, TRUE, "JpegDcTables", NULL}, + {TIFFTAG_JPEGACTABLES, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_LONG8, 0, + TIFF_SETGET_C32_UINT64, TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGACTABLES, + FALSE, TRUE, "JpegAcTables", NULL}, + {TIFFTAG_JPEGPROC, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, + TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGPROC, FALSE, FALSE, "JpegProc", + NULL}, + {TIFFTAG_JPEGRESTARTINTERVAL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, + TIFF_SETGET_UNDEFINED, FIELD_OJPEG_JPEGRESTARTINTERVAL, FALSE, FALSE, + "JpegRestartInterval", NULL}, }; #ifndef LIBJPEG_ENCAP_EXTERNAL #include #endif -#include "jpeglib.h" +/* 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 + +/* 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 "jerror.h" +#include "jpeglib.h" typedef struct jpeg_error_mgr jpeg_error_mgr; typedef struct jpeg_common_struct jpeg_common_struct; typedef struct jpeg_decompress_struct jpeg_decompress_struct; typedef struct jpeg_source_mgr jpeg_source_mgr; -typedef enum { - osibsNotSetYet, - osibsJpegInterchangeFormat, - osibsStrile, - osibsEof +typedef enum +{ + osibsNotSetYet, + osibsJpegInterchangeFormat, + osibsStrile, + osibsEof } OJPEGStateInBufferSource; -typedef enum { - ososSoi, - ososQTable0,ososQTable1,ososQTable2,ososQTable3, - ososDcTable0,ososDcTable1,ososDcTable2,ososDcTable3, - ososAcTable0,ososAcTable1,ososAcTable2,ososAcTable3, - ososDri, - ososSof, - ososSos, - ososCompressed, - ososRst, - ososEoi +typedef enum +{ + ososSoi, + ososQTable0, + ososQTable1, + ososQTable2, + ososQTable3, + ososDcTable0, + ososDcTable1, + ososDcTable2, + ososDcTable3, + ososAcTable0, + ososAcTable1, + ososAcTable2, + ososAcTable3, + ososDri, + ososSof, + ososSos, + ososCompressed, + ososRst, + ososEoi } OJPEGStateOutState; -typedef struct { - TIFF* tif; - #ifndef LIBJPEG_ENCAP_EXTERNAL - JMP_BUF exit_jmpbuf; - #endif - TIFFVGetMethod vgetparent; - TIFFVSetMethod vsetparent; - toff_t file_size; - uint32 image_width; - uint32 image_length; - uint32 strile_width; - uint32 strile_length; - uint32 strile_length_total; - uint8 samples_per_pixel; - uint8 plane_sample_offset; - uint8 samples_per_pixel_per_plane; - toff_t jpeg_interchange_format; - toff_t jpeg_interchange_format_length; - uint8 jpeg_proc; - uint8 subsamplingcorrect; - uint8 subsamplingcorrect_done; - uint8 subsampling_tag; - uint8 subsampling_hor; - uint8 subsampling_ver; - uint8 subsampling_force_desubsampling_inside_decompression; - uint8 qtable_offset_count; - uint8 dctable_offset_count; - uint8 actable_offset_count; - toff_t qtable_offset[3]; - toff_t dctable_offset[3]; - toff_t actable_offset[3]; - uint8* qtable[4]; - uint8* dctable[4]; - uint8* actable[4]; - uint16 restart_interval; - uint8 restart_index; - uint8 sof_log; - uint8 sof_marker_id; - uint32 sof_x; - uint32 sof_y; - uint8 sof_c[3]; - uint8 sof_hv[3]; - uint8 sof_tq[3]; - uint8 sos_cs[3]; - uint8 sos_tda[3]; - struct { - uint8 log; - OJPEGStateInBufferSource in_buffer_source; - tstrile_t in_buffer_next_strile; - toff_t in_buffer_file_pos; - toff_t in_buffer_file_togo; - } sos_end[3]; - uint8 readheader_done; - uint8 writeheader_done; - tsample_t write_cursample; - tstrile_t write_curstrile; - uint8 libjpeg_session_active; - uint8 libjpeg_jpeg_query_style; - jpeg_error_mgr libjpeg_jpeg_error_mgr; - jpeg_decompress_struct libjpeg_jpeg_decompress_struct; - jpeg_source_mgr libjpeg_jpeg_source_mgr; - uint8 subsampling_convert_log; - uint32 subsampling_convert_ylinelen; - uint32 subsampling_convert_ylines; - uint32 subsampling_convert_clinelen; - uint32 subsampling_convert_clines; - uint32 subsampling_convert_ybuflen; - uint32 subsampling_convert_cbuflen; - uint32 subsampling_convert_ycbcrbuflen; - uint8* subsampling_convert_ycbcrbuf; - uint8* subsampling_convert_ybuf; - uint8* subsampling_convert_cbbuf; - uint8* subsampling_convert_crbuf; - uint32 subsampling_convert_ycbcrimagelen; - uint8** subsampling_convert_ycbcrimage; - uint32 subsampling_convert_clinelenout; - uint32 subsampling_convert_state; - uint32 bytes_per_line; /* if the codec outputs subsampled data, a 'line' in bytes_per_line */ - uint32 lines_per_strile; /* and lines_per_strile means subsampling_ver desubsampled rows */ - OJPEGStateInBufferSource in_buffer_source; - tstrile_t in_buffer_next_strile; - tstrile_t in_buffer_strile_count; - toff_t in_buffer_file_pos; - uint8 in_buffer_file_pos_log; - toff_t in_buffer_file_togo; - uint16 in_buffer_togo; - uint8* in_buffer_cur; - uint8 in_buffer[OJPEG_BUFFER]; - OJPEGStateOutState out_state; - uint8 out_buffer[OJPEG_BUFFER]; - uint8* skip_buffer; +typedef struct +{ + TIFF *tif; + int decoder_ok; + int error_in_raw_data_decoding; +#ifndef LIBJPEG_ENCAP_EXTERNAL + JMP_BUF exit_jmpbuf; +#endif + TIFFVGetMethod vgetparent; + TIFFVSetMethod vsetparent; + TIFFPrintMethod printdir; + uint64_t file_size; + uint32_t image_width; + uint32_t image_length; + uint32_t strile_width; + uint32_t strile_length; + uint32_t strile_length_total; + uint8_t samples_per_pixel; + uint8_t plane_sample_offset; + uint8_t samples_per_pixel_per_plane; + uint64_t jpeg_interchange_format; + uint64_t jpeg_interchange_format_length; + uint8_t jpeg_proc; + uint8_t subsamplingcorrect; + uint8_t subsamplingcorrect_done; + uint8_t subsampling_tag; + uint8_t subsampling_hor; + uint8_t subsampling_ver; + uint8_t subsampling_force_desubsampling_inside_decompression; + uint8_t qtable_offset_count; + uint8_t dctable_offset_count; + uint8_t actable_offset_count; + uint64_t qtable_offset[3]; + uint64_t dctable_offset[3]; + uint64_t actable_offset[3]; + uint8_t *qtable[4]; + uint8_t *dctable[4]; + uint8_t *actable[4]; + uint16_t restart_interval; + uint8_t restart_index; + uint8_t sof_log; + uint8_t sof_marker_id; + uint32_t sof_x; + uint32_t sof_y; + uint8_t sof_c[3]; + uint8_t sof_hv[3]; + uint8_t sof_tq[3]; + uint8_t sos_cs[3]; + uint8_t sos_tda[3]; + struct + { + uint8_t log; + OJPEGStateInBufferSource in_buffer_source; + uint32_t in_buffer_next_strile; + uint64_t in_buffer_file_pos; + uint64_t in_buffer_file_togo; + } sos_end[3]; + uint8_t readheader_done; + uint8_t writeheader_done; + uint16_t write_cursample; + uint32_t write_curstrile; + uint8_t libjpeg_session_active; + uint8_t libjpeg_jpeg_query_style; + jpeg_error_mgr libjpeg_jpeg_error_mgr; + jpeg_decompress_struct libjpeg_jpeg_decompress_struct; + jpeg_source_mgr libjpeg_jpeg_source_mgr; + uint8_t subsampling_convert_log; + uint32_t subsampling_convert_ylinelen; + uint32_t subsampling_convert_ylines; + uint32_t subsampling_convert_clinelen; + uint32_t subsampling_convert_clines; + uint32_t subsampling_convert_ybuflen; + uint32_t subsampling_convert_cbuflen; + uint32_t subsampling_convert_ycbcrbuflen; + uint8_t *subsampling_convert_ycbcrbuf; + uint8_t *subsampling_convert_ybuf; + uint8_t *subsampling_convert_cbbuf; + uint8_t *subsampling_convert_crbuf; + uint32_t subsampling_convert_ycbcrimagelen; + uint8_t **subsampling_convert_ycbcrimage; + uint32_t subsampling_convert_clinelenout; + uint32_t subsampling_convert_state; + uint32_t bytes_per_line; /* if the codec outputs subsampled data, a 'line' + in bytes_per_line */ + uint32_t lines_per_strile; /* and lines_per_strile means subsampling_ver + desubsampled rows */ + OJPEGStateInBufferSource in_buffer_source; + uint32_t in_buffer_next_strile; + uint32_t in_buffer_strile_count; + uint64_t in_buffer_file_pos; + uint8_t in_buffer_file_pos_log; + uint64_t in_buffer_file_togo; + uint16_t in_buffer_togo; + uint8_t *in_buffer_cur; + uint8_t in_buffer[OJPEG_BUFFER]; + OJPEGStateOutState out_state; + uint8_t out_buffer[OJPEG_BUFFER]; + uint8_t *skip_buffer; } OJPEGState; -static int OJPEGVGetField(TIFF* tif, ttag_t tag, va_list ap); -static int OJPEGVSetField(TIFF* tif, ttag_t tag, va_list ap); -static void OJPEGPrintDir(TIFF* tif, FILE* fd, long flags); - -static int OJPEGSetupDecode(TIFF* tif); -static int OJPEGPreDecode(TIFF* tif, tsample_t s); -static int OJPEGPreDecodeSkipRaw(TIFF* tif); -static int OJPEGPreDecodeSkipScanlines(TIFF* tif); -static int OJPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s); -static int OJPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc); -static int OJPEGDecodeScanlines(TIFF* tif, tidata_t buf, tsize_t cc); -static void OJPEGPostDecode(TIFF* tif, tidata_t buf, tsize_t cc); -static int OJPEGSetupEncode(TIFF* tif); -static int OJPEGPreEncode(TIFF* tif, tsample_t s); -static int OJPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s); -static int OJPEGPostEncode(TIFF* tif); -static void OJPEGCleanup(TIFF* tif); - -static void OJPEGSubsamplingCorrect(TIFF* tif); -static int OJPEGReadHeaderInfo(TIFF* tif); -static int OJPEGReadSecondarySos(TIFF* tif, tsample_t s); -static int OJPEGWriteHeaderInfo(TIFF* tif); -static void OJPEGLibjpegSessionAbort(TIFF* tif); - -static int OJPEGReadHeaderInfoSec(TIFF* tif); -static int OJPEGReadHeaderInfoSecStreamDri(TIFF* tif); -static int OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif); -static int OJPEGReadHeaderInfoSecStreamDht(TIFF* tif); -static int OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id); -static int OJPEGReadHeaderInfoSecStreamSos(TIFF* tif); -static int OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif); -static int OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif); -static int OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif); - -static int OJPEGReadBufferFill(OJPEGState* sp); -static int OJPEGReadByte(OJPEGState* sp, uint8* byte); -static int OJPEGReadBytePeek(OJPEGState* sp, uint8* byte); -static void OJPEGReadByteAdvance(OJPEGState* sp); -static int OJPEGReadWord(OJPEGState* sp, uint16* word); -static int OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem); -static void OJPEGReadSkip(OJPEGState* sp, uint16 len); - -static int OJPEGWriteStream(TIFF* tif, void** mem, uint32* len); -static void OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len); -static void OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); -static void OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); -static void OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len); -static void OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len); -static void OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len); -static void OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len); -static int OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len); -static void OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len); -static void OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len); +static int OJPEGVGetField(TIFF *tif, uint32_t tag, va_list ap); +static int OJPEGVSetField(TIFF *tif, uint32_t tag, va_list ap); +static void OJPEGPrintDir(TIFF *tif, FILE *fd, long flags); + +static int OJPEGFixupTags(TIFF *tif); +static int OJPEGSetupDecode(TIFF *tif); +static int OJPEGPreDecode(TIFF *tif, uint16_t s); +static int OJPEGPreDecodeSkipRaw(TIFF *tif); +static int OJPEGPreDecodeSkipScanlines(TIFF *tif); +static int OJPEGDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s); +static int OJPEGDecodeRaw(TIFF *tif, uint8_t *buf, tmsize_t cc); +static int OJPEGDecodeScanlines(TIFF *tif, uint8_t *buf, tmsize_t cc); +static void OJPEGPostDecode(TIFF *tif, uint8_t *buf, tmsize_t cc); +static int OJPEGSetupEncode(TIFF *tif); +static int OJPEGPreEncode(TIFF *tif, uint16_t s); +static int OJPEGEncode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s); +static int OJPEGPostEncode(TIFF *tif); +static void OJPEGCleanup(TIFF *tif); + +static void OJPEGSubsamplingCorrect(TIFF *tif); +static int OJPEGReadHeaderInfo(TIFF *tif); +static int OJPEGReadSecondarySos(TIFF *tif, uint16_t s); +static int OJPEGWriteHeaderInfo(TIFF *tif); +static void OJPEGLibjpegSessionAbort(TIFF *tif); + +static int OJPEGReadHeaderInfoSec(TIFF *tif); +static int OJPEGReadHeaderInfoSecStreamDri(TIFF *tif); +static int OJPEGReadHeaderInfoSecStreamDqt(TIFF *tif); +static int OJPEGReadHeaderInfoSecStreamDht(TIFF *tif); +static int OJPEGReadHeaderInfoSecStreamSof(TIFF *tif, uint8_t marker_id); +static int OJPEGReadHeaderInfoSecStreamSos(TIFF *tif); +static int OJPEGReadHeaderInfoSecTablesQTable(TIFF *tif); +static int OJPEGReadHeaderInfoSecTablesDcTable(TIFF *tif); +static int OJPEGReadHeaderInfoSecTablesAcTable(TIFF *tif); + +static int OJPEGReadBufferFill(OJPEGState *sp); +static int OJPEGReadByte(OJPEGState *sp, uint8_t *byte); +static int OJPEGReadBytePeek(OJPEGState *sp, uint8_t *byte); +static void OJPEGReadByteAdvance(OJPEGState *sp); +static int OJPEGReadWord(OJPEGState *sp, uint16_t *word); +static int OJPEGReadBlock(OJPEGState *sp, uint16_t len, void *mem); +static void OJPEGReadSkip(OJPEGState *sp, uint16_t len); + +static int OJPEGWriteStream(TIFF *tif, void **mem, uint32_t *len); +static void OJPEGWriteStreamSoi(TIFF *tif, void **mem, uint32_t *len); +static void OJPEGWriteStreamQTable(TIFF *tif, uint8_t table_index, void **mem, + uint32_t *len); +static void OJPEGWriteStreamDcTable(TIFF *tif, uint8_t table_index, void **mem, + uint32_t *len); +static void OJPEGWriteStreamAcTable(TIFF *tif, uint8_t table_index, void **mem, + uint32_t *len); +static void OJPEGWriteStreamDri(TIFF *tif, void **mem, uint32_t *len); +static void OJPEGWriteStreamSof(TIFF *tif, void **mem, uint32_t *len); +static void OJPEGWriteStreamSos(TIFF *tif, void **mem, uint32_t *len); +static int OJPEGWriteStreamCompressed(TIFF *tif, void **mem, uint32_t *len); +static void OJPEGWriteStreamRst(TIFF *tif, void **mem, uint32_t *len); +static void OJPEGWriteStreamEoi(TIFF *tif, void **mem, uint32_t *len); #ifdef LIBJPEG_ENCAP_EXTERNAL -extern int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); -extern int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image); -extern int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); -extern int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines); -extern int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines); -extern void jpeg_encap_unwind(TIFF* tif); +extern int jpeg_create_decompress_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo); +extern int jpeg_read_header_encap(OJPEGState *sp, jpeg_decompress_struct *cinfo, + uint8_t require_image); +extern int jpeg_start_decompress_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo); +extern int jpeg_read_scanlines_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo, + void *scanlines, uint32_t max_lines); +extern int jpeg_read_raw_data_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo, void *data, + uint32_t max_lines); +extern void jpeg_encap_unwind(TIFF *tif); #else -static int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* j); -static int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image); -static int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo); -static int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines); -static int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines); -static void jpeg_encap_unwind(TIFF* tif); +static int jpeg_create_decompress_encap(OJPEGState *sp, + jpeg_decompress_struct *j); +static int jpeg_read_header_encap(OJPEGState *sp, jpeg_decompress_struct *cinfo, + uint8_t require_image); +static int jpeg_start_decompress_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo); +static int jpeg_read_scanlines_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo, + void *scanlines, uint32_t max_lines); +static int jpeg_read_raw_data_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo, void *data, + uint32_t max_lines); +static void jpeg_encap_unwind(TIFF *tif); #endif -static void OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo); -static void OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo); -static void OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo); -static boolean OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo); -static void OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes); -static boolean OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired); -static void OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo); - -int -TIFFInitOJPEG(TIFF* tif, int scheme) -{ - static const char module[]="TIFFInitOJPEG"; - OJPEGState* sp; - - assert(scheme==COMPRESSION_OJPEG); - - /* - * Merge codec-specific tag information. - */ - if (!_TIFFMergeFieldInfo(tif,ojpeg_field_info,FIELD_OJPEG_COUNT)) { - TIFFErrorExt(tif->tif_clientdata, module, - "Merging Old JPEG codec-specific tags failed"); - return 0; - } - - /* state block */ - sp=_TIFFmalloc(sizeof(OJPEGState)); - if (sp==NULL) - { - TIFFErrorExt(tif->tif_clientdata,module,"No space for OJPEG state block"); - return(0); - } - _TIFFmemset(sp,0,sizeof(OJPEGState)); - sp->tif=tif; - sp->jpeg_proc=1; - sp->subsampling_hor=2; - sp->subsampling_ver=2; - TIFFSetField(tif,TIFFTAG_YCBCRSUBSAMPLING,2,2); - /* tif codec methods */ - tif->tif_setupdecode=OJPEGSetupDecode; - tif->tif_predecode=OJPEGPreDecode; - tif->tif_postdecode=OJPEGPostDecode; - tif->tif_decoderow=OJPEGDecode; - tif->tif_decodestrip=OJPEGDecode; - tif->tif_decodetile=OJPEGDecode; - tif->tif_setupencode=OJPEGSetupEncode; - tif->tif_preencode=OJPEGPreEncode; - tif->tif_postencode=OJPEGPostEncode; - tif->tif_encoderow=OJPEGEncode; - tif->tif_encodestrip=OJPEGEncode; - tif->tif_encodetile=OJPEGEncode; - tif->tif_cleanup=OJPEGCleanup; - tif->tif_data=(tidata_t)sp; - /* tif tag methods */ - sp->vgetparent=tif->tif_tagmethods.vgetfield; - tif->tif_tagmethods.vgetfield=OJPEGVGetField; - sp->vsetparent=tif->tif_tagmethods.vsetfield; - tif->tif_tagmethods.vsetfield=OJPEGVSetField; - tif->tif_tagmethods.printdir=OJPEGPrintDir; - /* Some OJPEG files don't have strip or tile offsets or bytecounts tags. - Some others do, but have totally meaningless or corrupt values - in these tags. In these cases, the JpegInterchangeFormat stream is - reliable. In any case, this decoder reads the compressed data itself, - from the most reliable locations, and we need to notify encapsulating - LibTiff not to read raw strips or tiles for us. */ - tif->tif_flags|=TIFF_NOREADRAW; - return(1); +static void OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct *cinfo); +static void OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct *cinfo); +static void OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct *cinfo); +static boolean +OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct *cinfo); +static void +OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct *cinfo, + long num_bytes); +static boolean +OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct *cinfo, + int desired); +static void OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct *cinfo); + +int TIFFInitOJPEG(TIFF *tif, int scheme) +{ + static const char module[] = "TIFFInitOJPEG"; + OJPEGState *sp; + + (void)scheme; + assert(scheme == COMPRESSION_OJPEG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, ojpegFields, TIFFArrayCount(ojpegFields))) + { + TIFFErrorExtR(tif, module, + "Merging Old JPEG codec-specific tags failed"); + return 0; + } + + /* state block */ + sp = _TIFFmallocExt(tif, sizeof(OJPEGState)); + if (sp == NULL) + { + TIFFErrorExtR(tif, module, "No space for OJPEG state block"); + return (0); + } + _TIFFmemset(sp, 0, sizeof(OJPEGState)); + sp->tif = tif; + sp->jpeg_proc = 1; + sp->subsampling_hor = 2; + sp->subsampling_ver = 2; + TIFFSetField(tif, TIFFTAG_YCBCRSUBSAMPLING, 2, 2); + /* tif codec methods */ + tif->tif_fixuptags = OJPEGFixupTags; + tif->tif_setupdecode = OJPEGSetupDecode; + tif->tif_predecode = OJPEGPreDecode; + tif->tif_postdecode = OJPEGPostDecode; + tif->tif_decoderow = OJPEGDecode; + tif->tif_decodestrip = OJPEGDecode; + tif->tif_decodetile = OJPEGDecode; + tif->tif_setupencode = OJPEGSetupEncode; + tif->tif_preencode = OJPEGPreEncode; + tif->tif_postencode = OJPEGPostEncode; + tif->tif_encoderow = OJPEGEncode; + tif->tif_encodestrip = OJPEGEncode; + tif->tif_encodetile = OJPEGEncode; + tif->tif_cleanup = OJPEGCleanup; + tif->tif_data = (uint8_t *)sp; + /* tif tag methods */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = OJPEGVGetField; + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = OJPEGVSetField; + sp->printdir = tif->tif_tagmethods.printdir; + tif->tif_tagmethods.printdir = OJPEGPrintDir; + /* Some OJPEG files don't have strip or tile offsets or bytecounts tags. + Some others do, but have totally meaningless or corrupt values + in these tags. In these cases, the JpegInterchangeFormat stream is + reliable. In any case, this decoder reads the compressed data itself, + from the most reliable locations, and we need to notify encapsulating + LibTiff not to read raw strips or tiles for us. */ + tif->tif_flags |= TIFF_NOREADRAW; + return (1); +} + +static int OJPEGVGetField(TIFF *tif, uint32_t tag, va_list ap) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + switch (tag) + { + case TIFFTAG_JPEGIFOFFSET: + *va_arg(ap, uint64_t *) = (uint64_t)sp->jpeg_interchange_format; + break; + case TIFFTAG_JPEGIFBYTECOUNT: + *va_arg(ap, uint64_t *) = + (uint64_t)sp->jpeg_interchange_format_length; + break; + case TIFFTAG_YCBCRSUBSAMPLING: + if (sp->subsamplingcorrect_done == 0) + OJPEGSubsamplingCorrect(tif); + *va_arg(ap, uint16_t *) = (uint16_t)sp->subsampling_hor; + *va_arg(ap, uint16_t *) = (uint16_t)sp->subsampling_ver; + break; + case TIFFTAG_JPEGQTABLES: + *va_arg(ap, uint32_t *) = (uint32_t)sp->qtable_offset_count; + *va_arg(ap, const void **) = (const void *)sp->qtable_offset; + break; + case TIFFTAG_JPEGDCTABLES: + *va_arg(ap, uint32_t *) = (uint32_t)sp->dctable_offset_count; + *va_arg(ap, const void **) = (const void *)sp->dctable_offset; + break; + case TIFFTAG_JPEGACTABLES: + *va_arg(ap, uint32_t *) = (uint32_t)sp->actable_offset_count; + *va_arg(ap, const void **) = (const void *)sp->actable_offset; + break; + case TIFFTAG_JPEGPROC: + *va_arg(ap, uint16_t *) = (uint16_t)sp->jpeg_proc; + break; + case TIFFTAG_JPEGRESTARTINTERVAL: + *va_arg(ap, uint16_t *) = sp->restart_interval; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); } -static int -OJPEGVGetField(TIFF* tif, ttag_t tag, va_list ap) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - switch(tag) - { - case TIFFTAG_JPEGIFOFFSET: - *va_arg(ap,uint32*)=(uint32)sp->jpeg_interchange_format; - break; - case TIFFTAG_JPEGIFBYTECOUNT: - *va_arg(ap,uint32*)=(uint32)sp->jpeg_interchange_format_length; - break; - case TIFFTAG_YCBCRSUBSAMPLING: - if (sp->subsamplingcorrect_done==0) - OJPEGSubsamplingCorrect(tif); - *va_arg(ap,uint16*)=(uint16)sp->subsampling_hor; - *va_arg(ap,uint16*)=(uint16)sp->subsampling_ver; - break; - case TIFFTAG_JPEGQTABLES: - *va_arg(ap,uint32*)=(uint32)sp->qtable_offset_count; - *va_arg(ap,void**)=(void*)sp->qtable_offset; - break; - case TIFFTAG_JPEGDCTABLES: - *va_arg(ap,uint32*)=(uint32)sp->dctable_offset_count; - *va_arg(ap,void**)=(void*)sp->dctable_offset; - break; - case TIFFTAG_JPEGACTABLES: - *va_arg(ap,uint32*)=(uint32)sp->actable_offset_count; - *va_arg(ap,void**)=(void*)sp->actable_offset; - break; - case TIFFTAG_JPEGPROC: - *va_arg(ap,uint16*)=(uint16)sp->jpeg_proc; - break; - case TIFFTAG_JPEGRESTARTINTERVAL: - *va_arg(ap,uint16*)=sp->restart_interval; - break; - default: - return (*sp->vgetparent)(tif,tag,ap); - } - return (1); +static int OJPEGVSetField(TIFF *tif, uint32_t tag, va_list ap) +{ + static const char module[] = "OJPEGVSetField"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint32_t ma; + uint64_t *mb; + uint32_t n; + const TIFFField *fip; + + switch (tag) + { + case TIFFTAG_JPEGIFOFFSET: + sp->jpeg_interchange_format = (uint64_t)va_arg(ap, uint64_t); + break; + case TIFFTAG_JPEGIFBYTECOUNT: + sp->jpeg_interchange_format_length = (uint64_t)va_arg(ap, uint64_t); + break; + case TIFFTAG_YCBCRSUBSAMPLING: + sp->subsampling_tag = 1; + sp->subsampling_hor = (uint8_t)va_arg(ap, uint16_vap); + sp->subsampling_ver = (uint8_t)va_arg(ap, uint16_vap); + tif->tif_dir.td_ycbcrsubsampling[0] = sp->subsampling_hor; + tif->tif_dir.td_ycbcrsubsampling[1] = sp->subsampling_ver; + break; + case TIFFTAG_JPEGQTABLES: + ma = (uint32_t)va_arg(ap, uint32_t); + if (ma != 0) + { + if (ma > 3) + { + TIFFErrorExtR(tif, module, + "JpegQTables tag has incorrect count"); + return (0); + } + sp->qtable_offset_count = (uint8_t)ma; + mb = (uint64_t *)va_arg(ap, uint64_t *); + for (n = 0; n < ma; n++) + sp->qtable_offset[n] = mb[n]; + } + break; + case TIFFTAG_JPEGDCTABLES: + ma = (uint32_t)va_arg(ap, uint32_t); + if (ma != 0) + { + if (ma > 3) + { + TIFFErrorExtR(tif, module, + "JpegDcTables tag has incorrect count"); + return (0); + } + sp->dctable_offset_count = (uint8_t)ma; + mb = (uint64_t *)va_arg(ap, uint64_t *); + for (n = 0; n < ma; n++) + sp->dctable_offset[n] = mb[n]; + } + break; + case TIFFTAG_JPEGACTABLES: + ma = (uint32_t)va_arg(ap, uint32_t); + if (ma != 0) + { + if (ma > 3) + { + TIFFErrorExtR(tif, module, + "JpegAcTables tag has incorrect count"); + return (0); + } + sp->actable_offset_count = (uint8_t)ma; + mb = (uint64_t *)va_arg(ap, uint64_t *); + for (n = 0; n < ma; n++) + sp->actable_offset[n] = mb[n]; + } + break; + case TIFFTAG_JPEGPROC: + sp->jpeg_proc = (uint8_t)va_arg(ap, uint16_vap); + break; + case TIFFTAG_JPEGRESTARTINTERVAL: + sp->restart_interval = (uint16_t)va_arg(ap, uint16_vap); + break; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + fip = TIFFFieldWithTag(tif, tag); + if (fip == NULL) /* shouldn't happen */ + return (0); + TIFFSetFieldBit(tif, fip->field_bit); + tif->tif_flags |= TIFF_DIRTYDIRECT; + return (1); } -static int -OJPEGVSetField(TIFF* tif, ttag_t tag, va_list ap) -{ - static const char module[]="OJPEGVSetField"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint32 ma; - uint32* mb; - uint32 n; - switch(tag) - { - case TIFFTAG_JPEGIFOFFSET: - sp->jpeg_interchange_format=(toff_t)va_arg(ap,uint32); - break; - case TIFFTAG_JPEGIFBYTECOUNT: - sp->jpeg_interchange_format_length=(toff_t)va_arg(ap,uint32); - break; - case TIFFTAG_YCBCRSUBSAMPLING: - sp->subsampling_tag=1; - sp->subsampling_hor=(uint8)va_arg(ap,int); - sp->subsampling_ver=(uint8)va_arg(ap,int); - tif->tif_dir.td_ycbcrsubsampling[0]=sp->subsampling_hor; - tif->tif_dir.td_ycbcrsubsampling[1]=sp->subsampling_ver; - break; - case TIFFTAG_JPEGQTABLES: - ma=va_arg(ap,uint32); - if (ma!=0) - { - if (ma>3) - { - TIFFErrorExt(tif->tif_clientdata,module,"JpegQTables tag has incorrect count"); - return(0); - } - sp->qtable_offset_count=(uint8)ma; - mb=va_arg(ap,uint32*); - for (n=0; nqtable_offset[n]=(toff_t)mb[n]; - } - break; - case TIFFTAG_JPEGDCTABLES: - ma=va_arg(ap,uint32); - if (ma!=0) - { - if (ma>3) - { - TIFFErrorExt(tif->tif_clientdata,module,"JpegDcTables tag has incorrect count"); - return(0); - } - sp->dctable_offset_count=(uint8)ma; - mb=va_arg(ap,uint32*); - for (n=0; ndctable_offset[n]=(toff_t)mb[n]; - } - break; - case TIFFTAG_JPEGACTABLES: - ma=va_arg(ap,uint32); - if (ma!=0) - { - if (ma>3) - { - TIFFErrorExt(tif->tif_clientdata,module,"JpegAcTables tag has incorrect count"); - return(0); - } - sp->actable_offset_count=(uint8)ma; - mb=va_arg(ap,uint32*); - for (n=0; nactable_offset[n]=(toff_t)mb[n]; - } - break; - case TIFFTAG_JPEGPROC: - sp->jpeg_proc=(uint8)va_arg(ap,uint32); - break; - case TIFFTAG_JPEGRESTARTINTERVAL: - sp->restart_interval=(uint16)va_arg(ap,uint32); - break; - default: - return (*sp->vsetparent)(tif,tag,ap); - } - TIFFSetFieldBit(tif,_TIFFFieldWithTag(tif,tag)->field_bit); - tif->tif_flags|=TIFF_DIRTYDIRECT; - return(1); +static void OJPEGPrintDir(TIFF *tif, FILE *fd, long flags) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t m; + (void)flags; + assert(sp != NULL); + if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGINTERCHANGEFORMAT)) + fprintf(fd, " JpegInterchangeFormat: %" PRIu64 "\n", + (uint64_t)sp->jpeg_interchange_format); + if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH)) + fprintf(fd, " JpegInterchangeFormatLength: %" PRIu64 "\n", + (uint64_t)sp->jpeg_interchange_format_length); + if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGQTABLES)) + { + fprintf(fd, " JpegQTables:"); + for (m = 0; m < sp->qtable_offset_count; m++) + fprintf(fd, " %" PRIu64, (uint64_t)sp->qtable_offset[m]); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGDCTABLES)) + { + fprintf(fd, " JpegDcTables:"); + for (m = 0; m < sp->dctable_offset_count; m++) + fprintf(fd, " %" PRIu64, (uint64_t)sp->dctable_offset[m]); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGACTABLES)) + { + fprintf(fd, " JpegAcTables:"); + for (m = 0; m < sp->actable_offset_count; m++) + fprintf(fd, " %" PRIu64, (uint64_t)sp->actable_offset[m]); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGPROC)) + fprintf(fd, " JpegProc: %" PRIu8 "\n", sp->jpeg_proc); + if (TIFFFieldSet(tif, FIELD_OJPEG_JPEGRESTARTINTERVAL)) + fprintf(fd, " JpegRestartInterval: %" PRIu16 "\n", + sp->restart_interval); + if (sp->printdir) + (*sp->printdir)(tif, fd, flags); } -static void -OJPEGPrintDir(TIFF* tif, FILE* fd, long flags) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8 m; - (void)flags; - assert(sp!=NULL); - if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMAT)) - fprintf(fd," JpegInterchangeFormat: %lu\n",(unsigned long)sp->jpeg_interchange_format); - if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH)) - fprintf(fd," JpegInterchangeFormatLength: %lu\n",(unsigned long)sp->jpeg_interchange_format_length); - if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGQTABLES)) - { - fprintf(fd," JpegQTables:"); - for (m=0; mqtable_offset_count; m++) - fprintf(fd," %lu",(unsigned long)sp->qtable_offset[m]); - fprintf(fd,"\n"); - } - if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGDCTABLES)) - { - fprintf(fd," JpegDcTables:"); - for (m=0; mdctable_offset_count; m++) - fprintf(fd," %lu",(unsigned long)sp->dctable_offset[m]); - fprintf(fd,"\n"); - } - if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGACTABLES)) - { - fprintf(fd," JpegAcTables:"); - for (m=0; mactable_offset_count; m++) - fprintf(fd," %lu",(unsigned long)sp->actable_offset[m]); - fprintf(fd,"\n"); - } - if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGPROC)) - fprintf(fd," JpegProc: %u\n",(unsigned int)sp->jpeg_proc); - if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGRESTARTINTERVAL)) - fprintf(fd," JpegRestartInterval: %u\n",(unsigned int)sp->restart_interval); +static int OJPEGFixupTags(TIFF *tif) +{ + (void)tif; + return (1); } -static int -OJPEGSetupDecode(TIFF* tif) +static int OJPEGSetupDecode(TIFF *tif) { - static const char module[]="OJPEGSetupDecode"; - TIFFWarningExt(tif->tif_clientdata,module,"Depreciated and troublesome old-style JPEG compression mode, please convert to new-style JPEG compression and notify vendor of writing software"); - return(1); + static const char module[] = "OJPEGSetupDecode"; + TIFFWarningExtR(tif, module, + "Deprecated and troublesome old-style JPEG compression " + "mode, please convert to new-style JPEG compression and " + "notify vendor of writing software"); + return (1); } -static int -OJPEGPreDecode(TIFF* tif, tsample_t s) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - tstrile_t m; - if (sp->subsamplingcorrect_done==0) - OJPEGSubsamplingCorrect(tif); - if (sp->readheader_done==0) - { - if (OJPEGReadHeaderInfo(tif)==0) - return(0); - } - if (sp->sos_end[s].log==0) - { - if (OJPEGReadSecondarySos(tif,s)==0) - return(0); - } - if isTiled(tif) - m=(tstrile_t)tif->tif_curtile; - else - m=(tstrile_t)tif->tif_curstrip; - if ((sp->writeheader_done!=0) && ((sp->write_cursample!=s) || (sp->write_curstrile>m))) - { - if (sp->libjpeg_session_active!=0) - OJPEGLibjpegSessionAbort(tif); - sp->writeheader_done=0; - } - if (sp->writeheader_done==0) - { - sp->plane_sample_offset=s; - sp->write_cursample=s; - sp->write_curstrile=s*tif->tif_dir.td_stripsperimage; - if ((sp->in_buffer_file_pos_log==0) || - (sp->in_buffer_file_pos-sp->in_buffer_togo!=sp->sos_end[s].in_buffer_file_pos)) - { - sp->in_buffer_source=sp->sos_end[s].in_buffer_source; - sp->in_buffer_next_strile=sp->sos_end[s].in_buffer_next_strile; - sp->in_buffer_file_pos=sp->sos_end[s].in_buffer_file_pos; - sp->in_buffer_file_pos_log=0; - sp->in_buffer_file_togo=sp->sos_end[s].in_buffer_file_togo; - sp->in_buffer_togo=0; - sp->in_buffer_cur=0; - } - if (OJPEGWriteHeaderInfo(tif)==0) - return(0); - } - while (sp->write_curstrilelibjpeg_jpeg_query_style==0) - { - if (OJPEGPreDecodeSkipRaw(tif)==0) - return(0); - } - else - { - if (OJPEGPreDecodeSkipScanlines(tif)==0) - return(0); - } - sp->write_curstrile++; - } - return(1); +static int OJPEGPreDecode(TIFF *tif, uint16_t s) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint32_t m; + if (sp->subsamplingcorrect_done == 0) + OJPEGSubsamplingCorrect(tif); + if (sp->readheader_done == 0) + { + if (OJPEGReadHeaderInfo(tif) == 0) + return (0); + } + if (sp->sos_end[s].log == 0) + { + if (OJPEGReadSecondarySos(tif, s) == 0) + return (0); + } + if (isTiled(tif)) + m = tif->tif_curtile; + else + m = tif->tif_curstrip; + if ((sp->writeheader_done != 0) && + ((sp->write_cursample != s) || (sp->write_curstrile > m))) + { + if (sp->libjpeg_session_active != 0) + OJPEGLibjpegSessionAbort(tif); + sp->writeheader_done = 0; + } + if (sp->writeheader_done == 0) + { + sp->plane_sample_offset = (uint8_t)s; + sp->write_cursample = s; + sp->write_curstrile = s * tif->tif_dir.td_stripsperimage; + if ((sp->in_buffer_file_pos_log == 0) || + (sp->in_buffer_file_pos - sp->in_buffer_togo != + sp->sos_end[s].in_buffer_file_pos)) + { + sp->in_buffer_source = sp->sos_end[s].in_buffer_source; + sp->in_buffer_next_strile = sp->sos_end[s].in_buffer_next_strile; + sp->in_buffer_file_pos = sp->sos_end[s].in_buffer_file_pos; + sp->in_buffer_file_pos_log = 0; + sp->in_buffer_file_togo = sp->sos_end[s].in_buffer_file_togo; + sp->in_buffer_togo = 0; + sp->in_buffer_cur = 0; + } + if (OJPEGWriteHeaderInfo(tif) == 0) + return (0); + } + while (sp->write_curstrile < m) + { + if (sp->libjpeg_jpeg_query_style == 0) + { + if (OJPEGPreDecodeSkipRaw(tif) == 0) + return (0); + } + else + { + if (OJPEGPreDecodeSkipScanlines(tif) == 0) + return (0); + } + sp->write_curstrile++; + } + sp->decoder_ok = 1; + return (1); } -static int -OJPEGPreDecodeSkipRaw(TIFF* tif) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint32 m; - m=sp->lines_per_strile; - if (sp->subsampling_convert_state!=0) - { - if (sp->subsampling_convert_clines-sp->subsampling_convert_state>=m) - { - sp->subsampling_convert_state+=m; - if (sp->subsampling_convert_state==sp->subsampling_convert_clines) - sp->subsampling_convert_state=0; - return(1); - } - m-=sp->subsampling_convert_clines-sp->subsampling_convert_state; - sp->subsampling_convert_state=0; - } - while (m>=sp->subsampling_convert_clines) - { - if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) - return(0); - m-=sp->subsampling_convert_clines; - } - if (m>0) - { - if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) - return(0); - sp->subsampling_convert_state=m; - } - return(1); +static int OJPEGPreDecodeSkipRaw(TIFF *tif) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint32_t m; + m = sp->lines_per_strile; + if (sp->subsampling_convert_state != 0) + { + if (sp->subsampling_convert_clines - sp->subsampling_convert_state >= m) + { + sp->subsampling_convert_state += m; + if (sp->subsampling_convert_state == sp->subsampling_convert_clines) + sp->subsampling_convert_state = 0; + return (1); + } + m -= sp->subsampling_convert_clines - sp->subsampling_convert_state; + sp->subsampling_convert_state = 0; + sp->error_in_raw_data_decoding = 0; + } + while (m >= sp->subsampling_convert_clines) + { + if (jpeg_read_raw_data_encap(sp, &(sp->libjpeg_jpeg_decompress_struct), + sp->subsampling_convert_ycbcrimage, + sp->subsampling_ver * 8) == 0) + return (0); + m -= sp->subsampling_convert_clines; + } + if (m > 0) + { + if (jpeg_read_raw_data_encap(sp, &(sp->libjpeg_jpeg_decompress_struct), + sp->subsampling_convert_ycbcrimage, + sp->subsampling_ver * 8) == 0) + return (0); + sp->subsampling_convert_state = m; + } + return (1); } -static int -OJPEGPreDecodeSkipScanlines(TIFF* tif) -{ - static const char module[]="OJPEGPreDecodeSkipScanlines"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint32 m; - if (sp->skip_buffer==NULL) - { - sp->skip_buffer=_TIFFmalloc(sp->bytes_per_line); - if (sp->skip_buffer==NULL) - { - TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); - return(0); - } - } - for (m=0; mlines_per_strile; m++) - { - if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&sp->skip_buffer,1)==0) - return(0); - } - return(1); +static int OJPEGPreDecodeSkipScanlines(TIFF *tif) +{ + static const char module[] = "OJPEGPreDecodeSkipScanlines"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint32_t m; + if (sp->skip_buffer == NULL) + { + sp->skip_buffer = _TIFFmallocExt(tif, sp->bytes_per_line); + if (sp->skip_buffer == NULL) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + } + for (m = 0; m < sp->lines_per_strile; m++) + { + if (jpeg_read_scanlines_encap(sp, &(sp->libjpeg_jpeg_decompress_struct), + &sp->skip_buffer, 1) == 0) + return (0); + } + return (1); } -static int -OJPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - (void)s; - if (sp->libjpeg_jpeg_query_style==0) - { - if (OJPEGDecodeRaw(tif,buf,cc)==0) - return(0); - } - else - { - if (OJPEGDecodeScanlines(tif,buf,cc)==0) - return(0); - } - return(1); +static int OJPEGDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s) +{ + static const char module[] = "OJPEGDecode"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + (void)s; + if (!sp->decoder_ok) + { + TIFFErrorExtR(tif, module, + "Cannot decode: decoder not correctly initialized"); + return 0; + } + if (sp->libjpeg_session_active == 0) + { + /* This should normally not happen, except that it does when */ + /* using TIFFReadScanline() which calls OJPEGPostDecode() for */ + /* each scanline, which assumes that a whole strile was read */ + /* and may thus incorrectly consider it has read the whole image, + * causing */ + /* OJPEGLibjpegSessionAbort() to be called prematurely. */ + /* Triggered by https://gitlab.com/libtiff/libtiff/-/issues/337 */ + TIFFErrorExtR(tif, module, + "Cannot decode: libjpeg_session_active == 0"); + return 0; + } + if (sp->error_in_raw_data_decoding) + { + return 0; + } + if (sp->libjpeg_jpeg_query_style == 0) + { + if (OJPEGDecodeRaw(tif, buf, cc) == 0) + return (0); + } + else + { + if (OJPEGDecodeScanlines(tif, buf, cc) == 0) + return (0); + } + return (1); } -static int -OJPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc) -{ - static const char module[]="OJPEGDecodeRaw"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8* m; - uint32 n; - uint8* oy; - uint8* ocb; - uint8* ocr; - uint8* p; - uint32 q; - uint8* r; - uint8 sx,sy; - if (cc%sp->bytes_per_line!=0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read"); - return(0); - } - assert(cc>0); - m=buf; - n=cc; - do - { - if (sp->subsampling_convert_state==0) - { - if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0) - return(0); - } - oy=sp->subsampling_convert_ybuf+sp->subsampling_convert_state*sp->subsampling_ver*sp->subsampling_convert_ylinelen; - ocb=sp->subsampling_convert_cbbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen; - ocr=sp->subsampling_convert_crbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen; - p=m; - for (q=0; qsubsampling_convert_clinelenout; q++) - { - r=oy; - for (sy=0; sysubsampling_ver; sy++) - { - for (sx=0; sxsubsampling_hor; sx++) - *p++=*r++; - r+=sp->subsampling_convert_ylinelen-sp->subsampling_hor; - } - oy+=sp->subsampling_hor; - *p++=*ocb++; - *p++=*ocr++; - } - sp->subsampling_convert_state++; - if (sp->subsampling_convert_state==sp->subsampling_convert_clines) - sp->subsampling_convert_state=0; - m+=sp->bytes_per_line; - n-=sp->bytes_per_line; - } while(n>0); - return(1); +static int OJPEGDecodeRaw(TIFF *tif, uint8_t *buf, tmsize_t cc) +{ + static const char module[] = "OJPEGDecodeRaw"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t *m; + tmsize_t n; + uint8_t *oy; + uint8_t *ocb; + uint8_t *ocr; + uint8_t *p; + uint32_t q; + uint8_t *r; + uint8_t sx, sy; + if (cc % sp->bytes_per_line != 0) + { + TIFFErrorExtR(tif, module, "Fractional scanline not read"); + return (0); + } + assert(cc > 0); + m = buf; + n = cc; + do + { + if (sp->subsampling_convert_state == 0) + { + if (jpeg_read_raw_data_encap(sp, + &(sp->libjpeg_jpeg_decompress_struct), + sp->subsampling_convert_ycbcrimage, + sp->subsampling_ver * 8) == 0) + { + sp->error_in_raw_data_decoding = 1; + return (0); + } + } + oy = sp->subsampling_convert_ybuf + + sp->subsampling_convert_state * sp->subsampling_ver * + sp->subsampling_convert_ylinelen; + ocb = sp->subsampling_convert_cbbuf + + sp->subsampling_convert_state * sp->subsampling_convert_clinelen; + ocr = sp->subsampling_convert_crbuf + + sp->subsampling_convert_state * sp->subsampling_convert_clinelen; + p = m; + for (q = 0; q < sp->subsampling_convert_clinelenout; q++) + { + r = oy; + for (sy = 0; sy < sp->subsampling_ver; sy++) + { + for (sx = 0; sx < sp->subsampling_hor; sx++) + *p++ = *r++; + r += sp->subsampling_convert_ylinelen - sp->subsampling_hor; + } + oy += sp->subsampling_hor; + *p++ = *ocb++; + *p++ = *ocr++; + } + sp->subsampling_convert_state++; + if (sp->subsampling_convert_state == sp->subsampling_convert_clines) + sp->subsampling_convert_state = 0; + m += sp->bytes_per_line; + n -= sp->bytes_per_line; + } while (n > 0); + return (1); } -static int -OJPEGDecodeScanlines(TIFF* tif, tidata_t buf, tsize_t cc) -{ - static const char module[]="OJPEGDecodeScanlines"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8* m; - uint32 n; - if (cc%sp->bytes_per_line!=0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read"); - return(0); - } - assert(cc>0); - m=buf; - n=cc; - do - { - if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&m,1)==0) - return(0); - m+=sp->bytes_per_line; - n-=sp->bytes_per_line; - } while(n>0); - return(1); +static int OJPEGDecodeScanlines(TIFF *tif, uint8_t *buf, tmsize_t cc) +{ + static const char module[] = "OJPEGDecodeScanlines"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t *m; + tmsize_t n; + if (cc % sp->bytes_per_line != 0) + { + TIFFErrorExtR(tif, module, "Fractional scanline not read"); + return (0); + } + assert(cc > 0); + m = buf; + n = cc; + do + { + if (jpeg_read_scanlines_encap(sp, &(sp->libjpeg_jpeg_decompress_struct), + &m, 1) == 0) + return (0); + m += sp->bytes_per_line; + n -= sp->bytes_per_line; + } while (n > 0); + return (1); } -static void -OJPEGPostDecode(TIFF* tif, tidata_t buf, tsize_t cc) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - (void)buf; - (void)cc; - sp->write_curstrile++; - if (sp->write_curstrile%tif->tif_dir.td_stripsperimage==0) - { - assert(sp->libjpeg_session_active!=0); - OJPEGLibjpegSessionAbort(tif); - sp->writeheader_done=0; - } +static void OJPEGPostDecode(TIFF *tif, uint8_t *buf, tmsize_t cc) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + (void)buf; + (void)cc; + /* This function somehow incorrectly assumes that a whole strile was read, + */ + /* which is not true when TIFFReadScanline() is called, */ + /* and may thus incorrectly consider it has read the whole image, causing */ + /* OJPEGLibjpegSessionAbort() to be called prematurely. */ + /* So this logic should be fixed to take into account cc, or disable */ + /* the scan line reading interface. */ + /* Triggered by https://gitlab.com/libtiff/libtiff/-/issues/337 */ + sp->write_curstrile++; + if (sp->write_curstrile % tif->tif_dir.td_stripsperimage == 0) + { + assert(sp->libjpeg_session_active != 0); + OJPEGLibjpegSessionAbort(tif); + sp->writeheader_done = 0; + } } -static int -OJPEGSetupEncode(TIFF* tif) +static int OJPEGSetupEncode(TIFF *tif) { - static const char module[]="OJPEGSetupEncode"; - TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); - return(0); + static const char module[] = "OJPEGSetupEncode"; + TIFFErrorExtR( + tif, module, + "OJPEG encoding not supported; use new-style JPEG compression instead"); + return (0); } -static int -OJPEGPreEncode(TIFF* tif, tsample_t s) +static int OJPEGPreEncode(TIFF *tif, uint16_t s) { - static const char module[]="OJPEGPreEncode"; - (void)s; - TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); - return(0); + static const char module[] = "OJPEGPreEncode"; + (void)s; + TIFFErrorExtR( + tif, module, + "OJPEG encoding not supported; use new-style JPEG compression instead"); + return (0); } -static int -OJPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +static int OJPEGEncode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s) { - static const char module[]="OJPEGEncode"; - (void)buf; - (void)cc; - (void)s; - TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); - return(0); + static const char module[] = "OJPEGEncode"; + (void)buf; + (void)cc; + (void)s; + TIFFErrorExtR( + tif, module, + "OJPEG encoding not supported; use new-style JPEG compression instead"); + return (0); } -static int -OJPEGPostEncode(TIFF* tif) +static int OJPEGPostEncode(TIFF *tif) { - static const char module[]="OJPEGPostEncode"; - TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead"); - return(0); + static const char module[] = "OJPEGPostEncode"; + TIFFErrorExtR( + tif, module, + "OJPEG encoding not supported; use new-style JPEG compression instead"); + return (0); } -static void -OJPEGCleanup(TIFF* tif) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - if (sp!=0) - { - tif->tif_tagmethods.vgetfield=sp->vgetparent; - tif->tif_tagmethods.vsetfield=sp->vsetparent; - if (sp->qtable[0]!=0) - _TIFFfree(sp->qtable[0]); - if (sp->qtable[1]!=0) - _TIFFfree(sp->qtable[1]); - if (sp->qtable[2]!=0) - _TIFFfree(sp->qtable[2]); - if (sp->qtable[3]!=0) - _TIFFfree(sp->qtable[3]); - if (sp->dctable[0]!=0) - _TIFFfree(sp->dctable[0]); - if (sp->dctable[1]!=0) - _TIFFfree(sp->dctable[1]); - if (sp->dctable[2]!=0) - _TIFFfree(sp->dctable[2]); - if (sp->dctable[3]!=0) - _TIFFfree(sp->dctable[3]); - if (sp->actable[0]!=0) - _TIFFfree(sp->actable[0]); - if (sp->actable[1]!=0) - _TIFFfree(sp->actable[1]); - if (sp->actable[2]!=0) - _TIFFfree(sp->actable[2]); - if (sp->actable[3]!=0) - _TIFFfree(sp->actable[3]); - if (sp->libjpeg_session_active!=0) - OJPEGLibjpegSessionAbort(tif); - if (sp->subsampling_convert_ycbcrbuf!=0) - _TIFFfree(sp->subsampling_convert_ycbcrbuf); - if (sp->subsampling_convert_ycbcrimage!=0) - _TIFFfree(sp->subsampling_convert_ycbcrimage); - if (sp->skip_buffer!=0) - _TIFFfree(sp->skip_buffer); - _TIFFfree(sp); - tif->tif_data=NULL; - _TIFFSetDefaultCompressionState(tif); - } +static void OJPEGCleanup(TIFF *tif) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + if (sp != 0) + { + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + tif->tif_tagmethods.printdir = sp->printdir; + if (sp->qtable[0] != 0) + _TIFFfreeExt(tif, sp->qtable[0]); + if (sp->qtable[1] != 0) + _TIFFfreeExt(tif, sp->qtable[1]); + if (sp->qtable[2] != 0) + _TIFFfreeExt(tif, sp->qtable[2]); + if (sp->qtable[3] != 0) + _TIFFfreeExt(tif, sp->qtable[3]); + if (sp->dctable[0] != 0) + _TIFFfreeExt(tif, sp->dctable[0]); + if (sp->dctable[1] != 0) + _TIFFfreeExt(tif, sp->dctable[1]); + if (sp->dctable[2] != 0) + _TIFFfreeExt(tif, sp->dctable[2]); + if (sp->dctable[3] != 0) + _TIFFfreeExt(tif, sp->dctable[3]); + if (sp->actable[0] != 0) + _TIFFfreeExt(tif, sp->actable[0]); + if (sp->actable[1] != 0) + _TIFFfreeExt(tif, sp->actable[1]); + if (sp->actable[2] != 0) + _TIFFfreeExt(tif, sp->actable[2]); + if (sp->actable[3] != 0) + _TIFFfreeExt(tif, sp->actable[3]); + if (sp->libjpeg_session_active != 0) + OJPEGLibjpegSessionAbort(tif); + if (sp->subsampling_convert_ycbcrbuf != 0) + _TIFFfreeExt(tif, sp->subsampling_convert_ycbcrbuf); + if (sp->subsampling_convert_ycbcrimage != 0) + _TIFFfreeExt(tif, sp->subsampling_convert_ycbcrimage); + if (sp->skip_buffer != 0) + _TIFFfreeExt(tif, sp->skip_buffer); + _TIFFfreeExt(tif, sp); + tif->tif_data = NULL; + _TIFFSetDefaultCompressionState(tif); + } } -static void -OJPEGSubsamplingCorrect(TIFF* tif) -{ - static const char module[]="OJPEGSubsamplingCorrect"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8 mh; - uint8 mv; - assert(sp->subsamplingcorrect_done==0); - if ((tif->tif_dir.td_samplesperpixel!=3) || ((tif->tif_dir.td_photometric!=PHOTOMETRIC_YCBCR) && - (tif->tif_dir.td_photometric!=PHOTOMETRIC_ITULAB))) - { - if (sp->subsampling_tag!=0) - TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag not appropriate for this Photometric and/or SamplesPerPixel"); - sp->subsampling_hor=1; - sp->subsampling_ver=1; - sp->subsampling_force_desubsampling_inside_decompression=0; - } - else - { - sp->subsamplingcorrect_done=1; - mh=sp->subsampling_hor; - mv=sp->subsampling_ver; - sp->subsamplingcorrect=1; - OJPEGReadHeaderInfoSec(tif); - if (sp->subsampling_force_desubsampling_inside_decompression!=0) - { - sp->subsampling_hor=1; - sp->subsampling_ver=1; - } - sp->subsamplingcorrect=0; - if (((sp->subsampling_hor!=mh) || (sp->subsampling_ver!=mv)) && (sp->subsampling_force_desubsampling_inside_decompression==0)) - { - if (sp->subsampling_tag==0) - TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data [%d,%d] does not match default values [2,2]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver); - else - TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data [%d,%d] does not match subsampling tag values [%d,%d]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver,mh,mv); - } - if (sp->subsampling_force_desubsampling_inside_decompression!=0) - { - if (sp->subsampling_tag==0) - TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data does not match default values [2,2] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression"); - else - TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data does not match subsampling tag values [%d,%d] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression",mh,mv); - } - if (sp->subsampling_force_desubsampling_inside_decompression==0) - { - if (sp->subsampling_horsubsampling_ver) - TIFFWarningExt(tif->tif_clientdata,module,"Subsampling values [%d,%d] are not allowed in TIFF",sp->subsampling_hor,sp->subsampling_ver); - } - } - sp->subsamplingcorrect_done=1; +static void OJPEGSubsamplingCorrect(TIFF *tif) +{ + static const char module[] = "OJPEGSubsamplingCorrect"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t mh; + uint8_t mv; + + assert(sp->subsamplingcorrect_done == 0); + if ((tif->tif_dir.td_samplesperpixel != 3) || + ((tif->tif_dir.td_photometric != PHOTOMETRIC_YCBCR) && + (tif->tif_dir.td_photometric != PHOTOMETRIC_ITULAB))) + { + if (sp->subsampling_tag != 0) + TIFFWarningExtR(tif, module, + "Subsampling tag not appropriate for this " + "Photometric and/or SamplesPerPixel"); + sp->subsampling_hor = 1; + sp->subsampling_ver = 1; + sp->subsampling_force_desubsampling_inside_decompression = 0; + } + else + { + sp->subsamplingcorrect_done = 1; + mh = sp->subsampling_hor; + mv = sp->subsampling_ver; + sp->subsamplingcorrect = 1; + OJPEGReadHeaderInfoSec(tif); + if (sp->subsampling_force_desubsampling_inside_decompression != 0) + { + sp->subsampling_hor = 1; + sp->subsampling_ver = 1; + } + sp->subsamplingcorrect = 0; + if (((sp->subsampling_hor != mh) || (sp->subsampling_ver != mv)) && + (sp->subsampling_force_desubsampling_inside_decompression == 0)) + { + if (sp->subsampling_tag == 0) + TIFFWarningExtR( + tif, module, + "Subsampling tag is not set, yet subsampling inside JPEG " + "data [%" PRIu8 ",%" PRIu8 + "] does not match default values [2,2]; assuming " + "subsampling inside JPEG data is correct", + sp->subsampling_hor, sp->subsampling_ver); + else + TIFFWarningExtR( + tif, module, + "Subsampling inside JPEG data [%" PRIu8 ",%" PRIu8 + "] does not match subsampling tag values [%" PRIu8 + ",%" PRIu8 + "]; assuming subsampling inside JPEG data is correct", + sp->subsampling_hor, sp->subsampling_ver, mh, mv); + } + if (sp->subsampling_force_desubsampling_inside_decompression != 0) + { + if (sp->subsampling_tag == 0) + TIFFWarningExtR( + tif, module, + "Subsampling tag is not set, yet subsampling inside JPEG " + "data does not match default values [2,2] (nor any other " + "values allowed in TIFF); assuming subsampling inside JPEG " + "data is correct and desubsampling inside JPEG " + "decompression"); + else + TIFFWarningExtR( + tif, module, + "Subsampling inside JPEG data does not match subsampling " + "tag values [%" PRIu8 ",%" PRIu8 + "] (nor any other values allowed in TIFF); assuming " + "subsampling inside JPEG data is correct and desubsampling " + "inside JPEG decompression", + mh, mv); + } + if (sp->subsampling_force_desubsampling_inside_decompression == 0) + { + if (sp->subsampling_hor < sp->subsampling_ver) + TIFFWarningExtR(tif, module, + "Subsampling values [%" PRIu8 ",%" PRIu8 + "] are not allowed in TIFF", + sp->subsampling_hor, sp->subsampling_ver); + } + } + sp->subsamplingcorrect_done = 1; } -static int -OJPEGReadHeaderInfo(TIFF* tif) -{ - static const char module[]="OJPEGReadHeaderInfo"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - assert(sp->readheader_done==0); - sp->image_width=tif->tif_dir.td_imagewidth; - sp->image_length=tif->tif_dir.td_imagelength; - if isTiled(tif) - { - sp->strile_width=tif->tif_dir.td_tilewidth; - sp->strile_length=tif->tif_dir.td_tilelength; - sp->strile_length_total=((sp->image_length+sp->strile_length-1)/sp->strile_length)*sp->strile_length; - } - else - { - sp->strile_width=sp->image_width; - sp->strile_length=tif->tif_dir.td_rowsperstrip; - sp->strile_length_total=sp->image_length; - } - sp->samples_per_pixel=tif->tif_dir.td_samplesperpixel; - if (sp->samples_per_pixel==1) - { - sp->plane_sample_offset=0; - sp->samples_per_pixel_per_plane=sp->samples_per_pixel; - sp->subsampling_hor=1; - sp->subsampling_ver=1; - } - else - { - if (sp->samples_per_pixel!=3) - { - TIFFErrorExt(tif->tif_clientdata,module,"SamplesPerPixel %d not supported for this compression scheme",sp->samples_per_pixel); - return(0); - } - sp->plane_sample_offset=0; - if (tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG) - sp->samples_per_pixel_per_plane=3; - else - sp->samples_per_pixel_per_plane=1; - } - if (sp->strile_lengthimage_length) - { - if (sp->strile_length%(sp->subsampling_ver*8)!=0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Incompatible vertical subsampling and image strip/tile length"); - return(0); - } - sp->restart_interval=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8))*(sp->strile_length/(sp->subsampling_ver*8)); - } - if (OJPEGReadHeaderInfoSec(tif)==0) - return(0); - sp->sos_end[0].log=1; - sp->sos_end[0].in_buffer_source=sp->in_buffer_source; - sp->sos_end[0].in_buffer_next_strile=sp->in_buffer_next_strile; - sp->sos_end[0].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo; - sp->sos_end[0].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo; - sp->readheader_done=1; - return(1); +static int OJPEGReadHeaderInfo(TIFF *tif) +{ + static const char module[] = "OJPEGReadHeaderInfo"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + assert(sp->readheader_done == 0); + sp->image_width = tif->tif_dir.td_imagewidth; + sp->image_length = tif->tif_dir.td_imagelength; + if (isTiled(tif)) + { + sp->strile_width = tif->tif_dir.td_tilewidth; + sp->strile_length = tif->tif_dir.td_tilelength; + sp->strile_length_total = + ((sp->image_length + sp->strile_length - 1) / sp->strile_length) * + sp->strile_length; + } + else + { + sp->strile_width = sp->image_width; + sp->strile_length = tif->tif_dir.td_rowsperstrip; + if (sp->strile_length == (uint32_t)-1) + sp->strile_length = sp->image_length; + sp->strile_length_total = sp->image_length; + } + if (tif->tif_dir.td_samplesperpixel == 1) + { + sp->samples_per_pixel = 1; + sp->plane_sample_offset = 0; + sp->samples_per_pixel_per_plane = sp->samples_per_pixel; + sp->subsampling_hor = 1; + sp->subsampling_ver = 1; + } + else + { + if (tif->tif_dir.td_samplesperpixel != 3) + { + TIFFErrorExtR(tif, module, + "SamplesPerPixel %" PRIu8 + " not supported for this compression scheme", + sp->samples_per_pixel); + return (0); + } + sp->samples_per_pixel = 3; + sp->plane_sample_offset = 0; + if (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG) + sp->samples_per_pixel_per_plane = 3; + else + sp->samples_per_pixel_per_plane = 1; + } + if (sp->strile_length < sp->image_length) + { + if (((sp->subsampling_hor != 1) && (sp->subsampling_hor != 2) && + (sp->subsampling_hor != 4)) || + ((sp->subsampling_ver != 1) && (sp->subsampling_ver != 2) && + (sp->subsampling_ver != 4))) + { + TIFFErrorExtR(tif, module, "Invalid subsampling values"); + return (0); + } + if (sp->strile_length % (sp->subsampling_ver * 8) != 0) + { + TIFFErrorExtR(tif, module, + "Incompatible vertical subsampling and image " + "strip/tile length"); + return (0); + } + sp->restart_interval = + (uint16_t)(((sp->strile_width + sp->subsampling_hor * 8 - 1) / + (sp->subsampling_hor * 8)) * + (sp->strile_length / (sp->subsampling_ver * 8))); + } + if (OJPEGReadHeaderInfoSec(tif) == 0) + return (0); + sp->sos_end[0].log = 1; + sp->sos_end[0].in_buffer_source = sp->in_buffer_source; + sp->sos_end[0].in_buffer_next_strile = sp->in_buffer_next_strile; + sp->sos_end[0].in_buffer_file_pos = + sp->in_buffer_file_pos - sp->in_buffer_togo; + sp->sos_end[0].in_buffer_file_togo = + sp->in_buffer_file_togo + sp->in_buffer_togo; + sp->readheader_done = 1; + return (1); } -static int -OJPEGReadSecondarySos(TIFF* tif, tsample_t s) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8 m; - assert(s>0); - assert(s<3); - assert(sp->sos_end[0].log!=0); - assert(sp->sos_end[s].log==0); - sp->plane_sample_offset=s-1; - while(sp->sos_end[sp->plane_sample_offset].log==0) - sp->plane_sample_offset--; - sp->in_buffer_source=sp->sos_end[sp->plane_sample_offset].in_buffer_source; - sp->in_buffer_next_strile=sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile; - sp->in_buffer_file_pos=sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos; - sp->in_buffer_file_pos_log=0; - sp->in_buffer_file_togo=sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo; - sp->in_buffer_togo=0; - sp->in_buffer_cur=0; - while(sp->plane_sample_offsetplane_sample_offset++; - if (OJPEGReadHeaderInfoSecStreamSos(tif)==0) - return(0); - sp->sos_end[sp->plane_sample_offset].log=1; - sp->sos_end[sp->plane_sample_offset].in_buffer_source=sp->in_buffer_source; - sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile=sp->in_buffer_next_strile; - sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo; - sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo; - } - return(1); +static int OJPEGReadSecondarySos(TIFF *tif, uint16_t s) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t m; + assert(s > 0); + assert(s < 3); + assert(sp->sos_end[0].log != 0); + assert(sp->sos_end[s].log == 0); + sp->plane_sample_offset = (uint8_t)(s - 1); + while (sp->sos_end[sp->plane_sample_offset].log == 0) + sp->plane_sample_offset--; + sp->in_buffer_source = + sp->sos_end[sp->plane_sample_offset].in_buffer_source; + sp->in_buffer_next_strile = + sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile; + sp->in_buffer_file_pos = + sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos; + sp->in_buffer_file_pos_log = 0; + sp->in_buffer_file_togo = + sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo; + sp->in_buffer_togo = 0; + sp->in_buffer_cur = 0; + while (sp->plane_sample_offset < s) + { + do + { + if (OJPEGReadByte(sp, &m) == 0) + return (0); + if (m == 255) + { + do + { + if (OJPEGReadByte(sp, &m) == 0) + return (0); + if (m != 255) + break; + } while (1); + if (m == JPEG_MARKER_SOS) + break; + } + } while (1); + sp->plane_sample_offset++; + if (OJPEGReadHeaderInfoSecStreamSos(tif) == 0) + return (0); + sp->sos_end[sp->plane_sample_offset].log = 1; + sp->sos_end[sp->plane_sample_offset].in_buffer_source = + sp->in_buffer_source; + sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile = + sp->in_buffer_next_strile; + sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos = + sp->in_buffer_file_pos - sp->in_buffer_togo; + sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo = + sp->in_buffer_file_togo + sp->in_buffer_togo; + } + return (1); } -static int -OJPEGWriteHeaderInfo(TIFF* tif) -{ - static const char module[]="OJPEGWriteHeaderInfo"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8** m; - uint32 n; - assert(sp->libjpeg_session_active==0); - sp->out_state=ososSoi; - sp->restart_index=0; - jpeg_std_error(&(sp->libjpeg_jpeg_error_mgr)); - sp->libjpeg_jpeg_error_mgr.output_message=OJPEGLibjpegJpegErrorMgrOutputMessage; - sp->libjpeg_jpeg_error_mgr.error_exit=OJPEGLibjpegJpegErrorMgrErrorExit; - sp->libjpeg_jpeg_decompress_struct.err=&(sp->libjpeg_jpeg_error_mgr); - sp->libjpeg_jpeg_decompress_struct.client_data=(void*)tif; - if (jpeg_create_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0) - return(0); - sp->libjpeg_session_active=1; - sp->libjpeg_jpeg_source_mgr.bytes_in_buffer=0; - sp->libjpeg_jpeg_source_mgr.init_source=OJPEGLibjpegJpegSourceMgrInitSource; - sp->libjpeg_jpeg_source_mgr.fill_input_buffer=OJPEGLibjpegJpegSourceMgrFillInputBuffer; - sp->libjpeg_jpeg_source_mgr.skip_input_data=OJPEGLibjpegJpegSourceMgrSkipInputData; - sp->libjpeg_jpeg_source_mgr.resync_to_restart=OJPEGLibjpegJpegSourceMgrResyncToRestart; - sp->libjpeg_jpeg_source_mgr.term_source=OJPEGLibjpegJpegSourceMgrTermSource; - sp->libjpeg_jpeg_decompress_struct.src=&(sp->libjpeg_jpeg_source_mgr); - if (jpeg_read_header_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),1)==0) - return(0); - if ((sp->subsampling_force_desubsampling_inside_decompression==0) && (sp->samples_per_pixel_per_plane>1)) - { - sp->libjpeg_jpeg_decompress_struct.raw_data_out=1; +static int OJPEGWriteHeaderInfo(TIFF *tif) +{ + static const char module[] = "OJPEGWriteHeaderInfo"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t **m; + uint32_t n; + /* if a previous attempt failed, don't try again */ + if (sp->libjpeg_session_active != 0) + return 0; + sp->out_state = ososSoi; + sp->restart_index = 0; + jpeg_std_error(&(sp->libjpeg_jpeg_error_mgr)); + sp->libjpeg_jpeg_error_mgr.output_message = + OJPEGLibjpegJpegErrorMgrOutputMessage; + sp->libjpeg_jpeg_error_mgr.error_exit = OJPEGLibjpegJpegErrorMgrErrorExit; + sp->libjpeg_jpeg_decompress_struct.err = &(sp->libjpeg_jpeg_error_mgr); + sp->libjpeg_jpeg_decompress_struct.client_data = (void *)tif; + if (jpeg_create_decompress_encap( + sp, &(sp->libjpeg_jpeg_decompress_struct)) == 0) + return (0); + sp->libjpeg_session_active = 1; + sp->libjpeg_jpeg_source_mgr.bytes_in_buffer = 0; + sp->libjpeg_jpeg_source_mgr.init_source = + OJPEGLibjpegJpegSourceMgrInitSource; + sp->libjpeg_jpeg_source_mgr.fill_input_buffer = + OJPEGLibjpegJpegSourceMgrFillInputBuffer; + sp->libjpeg_jpeg_source_mgr.skip_input_data = + OJPEGLibjpegJpegSourceMgrSkipInputData; + sp->libjpeg_jpeg_source_mgr.resync_to_restart = + OJPEGLibjpegJpegSourceMgrResyncToRestart; + sp->libjpeg_jpeg_source_mgr.term_source = + OJPEGLibjpegJpegSourceMgrTermSource; + sp->libjpeg_jpeg_decompress_struct.src = &(sp->libjpeg_jpeg_source_mgr); + if (jpeg_read_header_encap(sp, &(sp->libjpeg_jpeg_decompress_struct), 1) == + 0) + return (0); + if ((sp->subsampling_force_desubsampling_inside_decompression == 0) && + (sp->samples_per_pixel_per_plane > 1)) + { + sp->libjpeg_jpeg_decompress_struct.raw_data_out = 1; #if JPEG_LIB_VERSION >= 70 - sp->libjpeg_jpeg_decompress_struct.do_fancy_upsampling=FALSE; + sp->libjpeg_jpeg_decompress_struct.do_fancy_upsampling = FALSE; #endif - sp->libjpeg_jpeg_query_style=0; - if (sp->subsampling_convert_log==0) - { - assert(sp->subsampling_convert_ycbcrbuf==0); - assert(sp->subsampling_convert_ycbcrimage==0); - sp->subsampling_convert_ylinelen=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8)*sp->subsampling_hor*8); - sp->subsampling_convert_ylines=sp->subsampling_ver*8; - sp->subsampling_convert_clinelen=sp->subsampling_convert_ylinelen/sp->subsampling_hor; - sp->subsampling_convert_clines=8; - sp->subsampling_convert_ybuflen=sp->subsampling_convert_ylinelen*sp->subsampling_convert_ylines; - sp->subsampling_convert_cbuflen=sp->subsampling_convert_clinelen*sp->subsampling_convert_clines; - sp->subsampling_convert_ycbcrbuflen=sp->subsampling_convert_ybuflen+2*sp->subsampling_convert_cbuflen; - sp->subsampling_convert_ycbcrbuf=_TIFFmalloc(sp->subsampling_convert_ycbcrbuflen); - if (sp->subsampling_convert_ycbcrbuf==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); - return(0); - } - sp->subsampling_convert_ybuf=sp->subsampling_convert_ycbcrbuf; - sp->subsampling_convert_cbbuf=sp->subsampling_convert_ybuf+sp->subsampling_convert_ybuflen; - sp->subsampling_convert_crbuf=sp->subsampling_convert_cbbuf+sp->subsampling_convert_cbuflen; - sp->subsampling_convert_ycbcrimagelen=3+sp->subsampling_convert_ylines+2*sp->subsampling_convert_clines; - sp->subsampling_convert_ycbcrimage=_TIFFmalloc(sp->subsampling_convert_ycbcrimagelen*sizeof(uint8*)); - if (sp->subsampling_convert_ycbcrimage==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); - return(0); - } - m=sp->subsampling_convert_ycbcrimage; - *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3); - *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines); - *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines+sp->subsampling_convert_clines); - for (n=0; nsubsampling_convert_ylines; n++) - *m++=sp->subsampling_convert_ybuf+n*sp->subsampling_convert_ylinelen; - for (n=0; nsubsampling_convert_clines; n++) - *m++=sp->subsampling_convert_cbbuf+n*sp->subsampling_convert_clinelen; - for (n=0; nsubsampling_convert_clines; n++) - *m++=sp->subsampling_convert_crbuf+n*sp->subsampling_convert_clinelen; - sp->subsampling_convert_clinelenout=((sp->strile_width+sp->subsampling_hor-1)/sp->subsampling_hor); - sp->subsampling_convert_state=0; - sp->bytes_per_line=sp->subsampling_convert_clinelenout*(sp->subsampling_ver*sp->subsampling_hor+2); - sp->lines_per_strile=((sp->strile_length+sp->subsampling_ver-1)/sp->subsampling_ver); - sp->subsampling_convert_log=1; - } - } - else - { - sp->libjpeg_jpeg_decompress_struct.jpeg_color_space=JCS_UNKNOWN; - sp->libjpeg_jpeg_decompress_struct.out_color_space=JCS_UNKNOWN; - sp->libjpeg_jpeg_query_style=1; - sp->bytes_per_line=sp->samples_per_pixel_per_plane*sp->strile_width; - sp->lines_per_strile=sp->strile_length; - } - if (jpeg_start_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0) - return(0); - sp->writeheader_done=1; - return(1); + sp->libjpeg_jpeg_query_style = 0; + if (sp->subsampling_convert_log == 0) + { + assert(sp->subsampling_convert_ycbcrbuf == 0); + assert(sp->subsampling_convert_ycbcrimage == 0); + /* Check for division by zero. */ + if (sp->subsampling_hor == 0 || sp->subsampling_ver == 0) + return (0); + sp->subsampling_convert_ylinelen = + ((sp->strile_width + sp->subsampling_hor * 8 - 1) / + (sp->subsampling_hor * 8) * sp->subsampling_hor * 8); + sp->subsampling_convert_ylines = sp->subsampling_ver * 8; + sp->subsampling_convert_clinelen = + sp->subsampling_convert_ylinelen / sp->subsampling_hor; + sp->subsampling_convert_clines = 8; + sp->subsampling_convert_ybuflen = sp->subsampling_convert_ylinelen * + sp->subsampling_convert_ylines; + sp->subsampling_convert_cbuflen = sp->subsampling_convert_clinelen * + sp->subsampling_convert_clines; + sp->subsampling_convert_ycbcrbuflen = + sp->subsampling_convert_ybuflen + + 2 * sp->subsampling_convert_cbuflen; + /* The calloc is not normally necessary, except in some edge/broken + * cases */ + /* for example for a tiled image of height 1 with a tile height of 1 + * and subsampling_hor=subsampling_ver=2 */ + /* In that case, libjpeg will only fill the 8 first lines of the 16 + * lines */ + /* See https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=16844 + */ + /* Even if this case is allowed (?), its handling is broken because + * OJPEGPreDecode() should also likely */ + /* reset subsampling_convert_state to 0 when changing tile. */ + sp->subsampling_convert_ycbcrbuf = + _TIFFcallocExt(tif, 1, sp->subsampling_convert_ycbcrbuflen); + if (sp->subsampling_convert_ycbcrbuf == 0) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + sp->subsampling_convert_ybuf = sp->subsampling_convert_ycbcrbuf; + sp->subsampling_convert_cbbuf = + sp->subsampling_convert_ybuf + sp->subsampling_convert_ybuflen; + sp->subsampling_convert_crbuf = + sp->subsampling_convert_cbbuf + sp->subsampling_convert_cbuflen; + sp->subsampling_convert_ycbcrimagelen = + 3 + sp->subsampling_convert_ylines + + 2 * sp->subsampling_convert_clines; + sp->subsampling_convert_ycbcrimage = _TIFFmallocExt( + tif, sp->subsampling_convert_ycbcrimagelen * sizeof(uint8_t *)); + if (sp->subsampling_convert_ycbcrimage == 0) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + m = sp->subsampling_convert_ycbcrimage; + *m++ = (uint8_t *)(sp->subsampling_convert_ycbcrimage + 3); + *m++ = (uint8_t *)(sp->subsampling_convert_ycbcrimage + 3 + + sp->subsampling_convert_ylines); + *m++ = (uint8_t *)(sp->subsampling_convert_ycbcrimage + 3 + + sp->subsampling_convert_ylines + + sp->subsampling_convert_clines); + for (n = 0; n < sp->subsampling_convert_ylines; n++) + *m++ = sp->subsampling_convert_ybuf + + n * sp->subsampling_convert_ylinelen; + for (n = 0; n < sp->subsampling_convert_clines; n++) + *m++ = sp->subsampling_convert_cbbuf + + n * sp->subsampling_convert_clinelen; + for (n = 0; n < sp->subsampling_convert_clines; n++) + *m++ = sp->subsampling_convert_crbuf + + n * sp->subsampling_convert_clinelen; + sp->subsampling_convert_clinelenout = + sp->strile_width / sp->subsampling_hor + + ((sp->strile_width % sp->subsampling_hor) != 0 ? 1 : 0); + sp->subsampling_convert_state = 0; + sp->error_in_raw_data_decoding = 0; + sp->bytes_per_line = + sp->subsampling_convert_clinelenout * + (sp->subsampling_ver * sp->subsampling_hor + 2); + sp->lines_per_strile = + sp->strile_length / sp->subsampling_ver + + ((sp->strile_length % sp->subsampling_ver) != 0 ? 1 : 0); + sp->subsampling_convert_log = 1; + } + } + else + { + sp->libjpeg_jpeg_decompress_struct.jpeg_color_space = JCS_UNKNOWN; + sp->libjpeg_jpeg_decompress_struct.out_color_space = JCS_UNKNOWN; + sp->libjpeg_jpeg_query_style = 1; + sp->bytes_per_line = sp->samples_per_pixel_per_plane * sp->strile_width; + sp->lines_per_strile = sp->strile_length; + } + if (jpeg_start_decompress_encap(sp, + &(sp->libjpeg_jpeg_decompress_struct)) == 0) + return (0); + if (sp->libjpeg_jpeg_decompress_struct.image_width != sp->strile_width) + { + TIFFErrorExtR(tif, module, + "jpeg_start_decompress() returned image_width = %u, " + "expected %" PRIu32, + sp->libjpeg_jpeg_decompress_struct.image_width, + sp->strile_width); + return 0; + } + if (sp->libjpeg_jpeg_decompress_struct.max_h_samp_factor != + sp->subsampling_hor || + sp->libjpeg_jpeg_decompress_struct.max_v_samp_factor != + sp->subsampling_ver) + { + TIFFErrorExtR(tif, module, + "jpeg_start_decompress() returned max_h_samp_factor = %d " + "and max_v_samp_factor = %d, expected %" PRIu8 + " and %" PRIu8, + sp->libjpeg_jpeg_decompress_struct.max_h_samp_factor, + sp->libjpeg_jpeg_decompress_struct.max_v_samp_factor, + sp->subsampling_hor, sp->subsampling_ver); + return 0; + } + + sp->writeheader_done = 1; + return (1); } -static void -OJPEGLibjpegSessionAbort(TIFF* tif) +static void OJPEGLibjpegSessionAbort(TIFF *tif) { - OJPEGState* sp=(OJPEGState*)tif->tif_data; - assert(sp->libjpeg_session_active!=0); - jpeg_destroy((jpeg_common_struct*)(&(sp->libjpeg_jpeg_decompress_struct))); - sp->libjpeg_session_active=0; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + assert(sp->libjpeg_session_active != 0); + jpeg_destroy((jpeg_common_struct *)(&(sp->libjpeg_jpeg_decompress_struct))); + sp->libjpeg_session_active = 0; } -static int -OJPEGReadHeaderInfoSec(TIFF* tif) -{ - static const char module[]="OJPEGReadHeaderInfoSec"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8 m; - uint16 n; - uint8 o; - if (sp->file_size==0) - sp->file_size=TIFFGetFileSize(tif); - if (sp->jpeg_interchange_format!=0) - { - if (sp->jpeg_interchange_format>=sp->file_size) - { - sp->jpeg_interchange_format=0; - sp->jpeg_interchange_format_length=0; - } - else - { - if ((sp->jpeg_interchange_format_length==0) || (sp->jpeg_interchange_format+sp->jpeg_interchange_format_length>sp->file_size)) - sp->jpeg_interchange_format_length=sp->file_size-sp->jpeg_interchange_format; - } - } - sp->in_buffer_source=osibsNotSetYet; - sp->in_buffer_next_strile=0; - sp->in_buffer_strile_count=tif->tif_dir.td_nstrips; - sp->in_buffer_file_togo=0; - sp->in_buffer_togo=0; - do - { - if (OJPEGReadBytePeek(sp,&m)==0) - return(0); - if (m!=255) - break; - OJPEGReadByteAdvance(sp); - do - { - if (OJPEGReadByte(sp,&m)==0) - return(0); - } while(m==255); - 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: - /* this type of marker has data, but it has no use to us (and no place here) and should be skipped */ - if (OJPEGReadWord(sp,&n)==0) - return(0); - if (n<2) - { - if (sp->subsamplingcorrect==0) - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data"); - return(0); - } - if (n>2) - OJPEGReadSkip(sp,n-2); - break; - case JPEG_MARKER_DRI: - if (OJPEGReadHeaderInfoSecStreamDri(tif)==0) - return(0); - break; - case JPEG_MARKER_DQT: - if (OJPEGReadHeaderInfoSecStreamDqt(tif)==0) - return(0); - break; - case JPEG_MARKER_DHT: - if (OJPEGReadHeaderInfoSecStreamDht(tif)==0) - return(0); - break; - case JPEG_MARKER_SOF0: - case JPEG_MARKER_SOF1: - case JPEG_MARKER_SOF3: - if (OJPEGReadHeaderInfoSecStreamSof(tif,m)==0) - return(0); - if (sp->subsamplingcorrect!=0) - return(1); - break; - case JPEG_MARKER_SOS: - if (sp->subsamplingcorrect!=0) - return(1); - assert(sp->plane_sample_offset==0); - if (OJPEGReadHeaderInfoSecStreamSos(tif)==0) - return(0); - break; - default: - TIFFErrorExt(tif->tif_clientdata,module,"Unknown marker type %d in JPEG data",m); - return(0); - } - } while(m!=JPEG_MARKER_SOS); - if (sp->subsamplingcorrect) - return(1); - if (sp->sof_log==0) - { - if (OJPEGReadHeaderInfoSecTablesQTable(tif)==0) - return(0); - sp->sof_marker_id=JPEG_MARKER_SOF0; - for (o=0; osamples_per_pixel; o++) - sp->sof_c[o]=o; - sp->sof_hv[0]=((sp->subsampling_hor<<4)|sp->subsampling_ver); - for (o=1; osamples_per_pixel; o++) - sp->sof_hv[o]=17; - sp->sof_x=sp->strile_width; - sp->sof_y=sp->strile_length_total; - sp->sof_log=1; - if (OJPEGReadHeaderInfoSecTablesDcTable(tif)==0) - return(0); - if (OJPEGReadHeaderInfoSecTablesAcTable(tif)==0) - return(0); - for (o=1; osamples_per_pixel; o++) - sp->sos_cs[o]=o; - } - return(1); +static int OJPEGReadHeaderInfoSec(TIFF *tif) +{ + static const char module[] = "OJPEGReadHeaderInfoSec"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t m; + uint16_t n; + uint8_t o; + if (sp->file_size == 0) + sp->file_size = TIFFGetFileSize(tif); + if (sp->jpeg_interchange_format != 0) + { + if (sp->jpeg_interchange_format >= sp->file_size) + { + sp->jpeg_interchange_format = 0; + sp->jpeg_interchange_format_length = 0; + } + else + { + if ((sp->jpeg_interchange_format_length == 0) || + (sp->jpeg_interchange_format > + UINT64_MAX - sp->jpeg_interchange_format_length) || + (sp->jpeg_interchange_format + + sp->jpeg_interchange_format_length > + sp->file_size)) + sp->jpeg_interchange_format_length = + sp->file_size - sp->jpeg_interchange_format; + } + } + sp->in_buffer_source = osibsNotSetYet; + sp->in_buffer_next_strile = 0; + sp->in_buffer_strile_count = tif->tif_dir.td_nstrips; + sp->in_buffer_file_togo = 0; + sp->in_buffer_togo = 0; + do + { + if (OJPEGReadBytePeek(sp, &m) == 0) + return (0); + if (m != 255) + break; + OJPEGReadByteAdvance(sp); + do + { + if (OJPEGReadByte(sp, &m) == 0) + return (0); + } while (m == 255); + 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: + /* this type of marker has data, but it has no use to us (and no + * place here) and should be skipped */ + if (OJPEGReadWord(sp, &n) == 0) + return (0); + if (n < 2) + { + if (sp->subsamplingcorrect == 0) + TIFFErrorExtR(tif, module, "Corrupt JPEG data"); + return (0); + } + if (n > 2) + OJPEGReadSkip(sp, n - 2); + break; + case JPEG_MARKER_DRI: + if (OJPEGReadHeaderInfoSecStreamDri(tif) == 0) + return (0); + break; + case JPEG_MARKER_DQT: + if (OJPEGReadHeaderInfoSecStreamDqt(tif) == 0) + return (0); + break; + case JPEG_MARKER_DHT: + if (OJPEGReadHeaderInfoSecStreamDht(tif) == 0) + return (0); + break; + case JPEG_MARKER_SOF0: + case JPEG_MARKER_SOF1: + case JPEG_MARKER_SOF3: + if (OJPEGReadHeaderInfoSecStreamSof(tif, m) == 0) + return (0); + if (sp->subsamplingcorrect != 0) + return (1); + break; + case JPEG_MARKER_SOS: + if (sp->subsamplingcorrect != 0) + return (1); + assert(sp->plane_sample_offset == 0); + if (OJPEGReadHeaderInfoSecStreamSos(tif) == 0) + return (0); + break; + default: + TIFFErrorExtR(tif, module, + "Unknown marker type %" PRIu8 " in JPEG data", m); + return (0); + } + } while (m != JPEG_MARKER_SOS); + if (sp->subsamplingcorrect) + return (1); + if (sp->sof_log == 0) + { + if (OJPEGReadHeaderInfoSecTablesQTable(tif) == 0) + return (0); + sp->sof_marker_id = JPEG_MARKER_SOF0; + for (o = 0; o < sp->samples_per_pixel; o++) + sp->sof_c[o] = o; + sp->sof_hv[0] = ((sp->subsampling_hor << 4) | sp->subsampling_ver); + for (o = 1; o < sp->samples_per_pixel; o++) + sp->sof_hv[o] = 17; + sp->sof_x = sp->strile_width; + sp->sof_y = sp->strile_length_total; + sp->sof_log = 1; + if (OJPEGReadHeaderInfoSecTablesDcTable(tif) == 0) + return (0); + if (OJPEGReadHeaderInfoSecTablesAcTable(tif) == 0) + return (0); + for (o = 1; o < sp->samples_per_pixel; o++) + sp->sos_cs[o] = o; + } + return (1); } -static int -OJPEGReadHeaderInfoSecStreamDri(TIFF* tif) -{ - /* this could easilly cause trouble in some cases... but no such cases have occured sofar */ - static const char module[]="OJPEGReadHeaderInfoSecStreamDri"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint16 m; - if (OJPEGReadWord(sp,&m)==0) - return(0); - if (m!=4) - { - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DRI marker in JPEG data"); - return(0); - } - if (OJPEGReadWord(sp,&m)==0) - return(0); - sp->restart_interval=m; - return(1); +static int OJPEGReadHeaderInfoSecStreamDri(TIFF *tif) +{ + /* This could easily cause trouble in some cases... but no such cases have + occurred so far */ + static const char module[] = "OJPEGReadHeaderInfoSecStreamDri"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint16_t m; + if (OJPEGReadWord(sp, &m) == 0) + return (0); + if (m != 4) + { + TIFFErrorExtR(tif, module, "Corrupt DRI marker in JPEG data"); + return (0); + } + if (OJPEGReadWord(sp, &m) == 0) + return (0); + sp->restart_interval = m; + return (1); } -static int -OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif) -{ - /* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */ - static const char module[]="OJPEGReadHeaderInfoSecStreamDqt"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint16 m; - uint32 na; - uint8* nb; - uint8 o; - if (OJPEGReadWord(sp,&m)==0) - return(0); - if (m<=2) - { - if (sp->subsamplingcorrect==0) - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data"); - return(0); - } - if (sp->subsamplingcorrect!=0) - OJPEGReadSkip(sp,m-2); - else - { - m-=2; - do - { - if (m<65) - { - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data"); - return(0); - } - na=sizeof(uint32)+69; - nb=_TIFFmalloc(na); - if (nb==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); - return(0); - } - *(uint32*)nb=na; - nb[sizeof(uint32)]=255; - nb[sizeof(uint32)+1]=JPEG_MARKER_DQT; - nb[sizeof(uint32)+2]=0; - nb[sizeof(uint32)+3]=67; - if (OJPEGReadBlock(sp,65,&nb[sizeof(uint32)+4])==0) - return(0); - o=nb[sizeof(uint32)+4]&15; - if (3tif_clientdata,module,"Corrupt DQT marker in JPEG data"); - return(0); - } - if (sp->qtable[o]!=0) - _TIFFfree(sp->qtable[o]); - sp->qtable[o]=nb; - m-=65; - } while(m>0); - } - return(1); +static int OJPEGReadHeaderInfoSecStreamDqt(TIFF *tif) +{ + /* this is a table marker, and it is to be saved as a whole for exact + * pushing on the jpeg stream later on */ + static const char module[] = "OJPEGReadHeaderInfoSecStreamDqt"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint16_t m; + uint32_t na; + uint8_t *nb; + uint8_t o; + if (OJPEGReadWord(sp, &m) == 0) + return (0); + if (m <= 2) + { + if (sp->subsamplingcorrect == 0) + TIFFErrorExtR(tif, module, "Corrupt DQT marker in JPEG data"); + return (0); + } + if (sp->subsamplingcorrect != 0) + OJPEGReadSkip(sp, m - 2); + else + { + m -= 2; + do + { + if (m < 65) + { + TIFFErrorExtR(tif, module, "Corrupt DQT marker in JPEG data"); + return (0); + } + na = sizeof(uint32_t) + 69; + nb = _TIFFmallocExt(tif, na); + if (nb == 0) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + *(uint32_t *)nb = na; + nb[sizeof(uint32_t)] = 255; + nb[sizeof(uint32_t) + 1] = JPEG_MARKER_DQT; + nb[sizeof(uint32_t) + 2] = 0; + nb[sizeof(uint32_t) + 3] = 67; + if (OJPEGReadBlock(sp, 65, &nb[sizeof(uint32_t) + 4]) == 0) + { + _TIFFfreeExt(tif, nb); + return (0); + } + o = nb[sizeof(uint32_t) + 4] & 15; + if (3 < o) + { + TIFFErrorExtR(tif, module, "Corrupt DQT marker in JPEG data"); + _TIFFfreeExt(tif, nb); + return (0); + } + if (sp->qtable[o] != 0) + _TIFFfreeExt(tif, sp->qtable[o]); + sp->qtable[o] = nb; + m -= 65; + } while (m > 0); + } + return (1); } -static int -OJPEGReadHeaderInfoSecStreamDht(TIFF* tif) -{ - /* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */ - /* TODO: the following assumes there is only one table in this marker... but i'm not quite sure that assumption is guaranteed correct */ - static const char module[]="OJPEGReadHeaderInfoSecStreamDht"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint16 m; - uint32 na; - uint8* nb; - uint8 o; - if (OJPEGReadWord(sp,&m)==0) - return(0); - if (m<=2) - { - if (sp->subsamplingcorrect==0) - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); - return(0); - } - if (sp->subsamplingcorrect!=0) - { - OJPEGReadSkip(sp,m-2); - } - else - { - na=sizeof(uint32)+2+m; - nb=_TIFFmalloc(na); - if (nb==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); - return(0); - } - *(uint32*)nb=na; - nb[sizeof(uint32)]=255; - nb[sizeof(uint32)+1]=JPEG_MARKER_DHT; - nb[sizeof(uint32)+2]=(m>>8); - nb[sizeof(uint32)+3]=(m&255); - if (OJPEGReadBlock(sp,m-2,&nb[sizeof(uint32)+4])==0) - return(0); - o=nb[sizeof(uint32)+4]; - if ((o&240)==0) - { - if (3tif_clientdata,module,"Corrupt DHT marker in JPEG data"); - return(0); - } - if (sp->dctable[o]!=0) - _TIFFfree(sp->dctable[o]); - sp->dctable[o]=nb; - } - else - { - if ((o&240)!=16) - { - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data"); - return(0); - } - o&=15; - if (3tif_clientdata,module,"Corrupt DHT marker in JPEG data"); - return(0); - } - if (sp->actable[o]!=0) - _TIFFfree(sp->actable[o]); - sp->actable[o]=nb; - } - } - return(1); +static int OJPEGReadHeaderInfoSecStreamDht(TIFF *tif) +{ + /* this is a table marker, and it is to be saved as a whole for exact + * pushing on the jpeg stream later on */ + /* TODO: the following assumes there is only one table in this marker... but + * i'm not quite sure that assumption is guaranteed correct */ + static const char module[] = "OJPEGReadHeaderInfoSecStreamDht"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint16_t m; + uint32_t na; + uint8_t *nb; + uint8_t o; + if (OJPEGReadWord(sp, &m) == 0) + return (0); + if (m <= 2) + { + if (sp->subsamplingcorrect == 0) + TIFFErrorExtR(tif, module, "Corrupt DHT marker in JPEG data"); + return (0); + } + if (sp->subsamplingcorrect != 0) + { + OJPEGReadSkip(sp, m - 2); + } + else + { + na = sizeof(uint32_t) + 2 + m; + nb = _TIFFmallocExt(tif, na); + if (nb == 0) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + *(uint32_t *)nb = na; + nb[sizeof(uint32_t)] = 255; + nb[sizeof(uint32_t) + 1] = JPEG_MARKER_DHT; + nb[sizeof(uint32_t) + 2] = (m >> 8); + nb[sizeof(uint32_t) + 3] = (m & 255); + if (OJPEGReadBlock(sp, m - 2, &nb[sizeof(uint32_t) + 4]) == 0) + { + _TIFFfreeExt(tif, nb); + return (0); + } + o = nb[sizeof(uint32_t) + 4]; + if ((o & 240) == 0) + { + if (3 < o) + { + TIFFErrorExtR(tif, module, "Corrupt DHT marker in JPEG data"); + _TIFFfreeExt(tif, nb); + return (0); + } + if (sp->dctable[o] != 0) + _TIFFfreeExt(tif, sp->dctable[o]); + sp->dctable[o] = nb; + } + else + { + if ((o & 240) != 16) + { + TIFFErrorExtR(tif, module, "Corrupt DHT marker in JPEG data"); + _TIFFfreeExt(tif, nb); + return (0); + } + o &= 15; + if (3 < o) + { + TIFFErrorExtR(tif, module, "Corrupt DHT marker in JPEG data"); + _TIFFfreeExt(tif, nb); + return (0); + } + if (sp->actable[o] != 0) + _TIFFfreeExt(tif, sp->actable[o]); + sp->actable[o] = nb; + } + } + return (1); } -static int -OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id) -{ - /* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */ - static const char module[]="OJPEGReadHeaderInfoSecStreamSof"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint16 m; - uint16 n; - uint8 o; - uint16 p; - uint16 q; - if (sp->sof_log!=0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data"); - return(0); - } - if (sp->subsamplingcorrect==0) - sp->sof_marker_id=marker_id; - /* Lf: data length */ - if (OJPEGReadWord(sp,&m)==0) - return(0); - if (m<11) - { - if (sp->subsamplingcorrect==0) - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); - return(0); - } - m-=8; - if (m%3!=0) - { - if (sp->subsamplingcorrect==0) - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); - return(0); - } - n=m/3; - if (sp->subsamplingcorrect==0) - { - if (n!=sp->samples_per_pixel) - { - TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of samples"); - return(0); - } - } - /* P: Sample precision */ - if (OJPEGReadByte(sp,&o)==0) - return(0); - if (o!=8) - { - if (sp->subsamplingcorrect==0) - TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of bits per sample"); - return(0); - } - /* Y: Number of lines, X: Number of samples per line */ - if (sp->subsamplingcorrect) - OJPEGReadSkip(sp,4); - else - { - /* TODO: probably best to also add check on allowed upper bound, especially x, may cause buffer overflow otherwise i think */ - /* Y: Number of lines */ - if (OJPEGReadWord(sp,&p)==0) - return(0); - if ((pimage_length) && (pstrile_length_total)) - { - TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected height"); - return(0); - } - sp->sof_y=p; - /* X: Number of samples per line */ - if (OJPEGReadWord(sp,&p)==0) - return(0); - if ((pimage_width) && (pstrile_width)) - { - TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected width"); - return(0); - } - sp->sof_x=p; - } - /* Nf: Number of image components in frame */ - if (OJPEGReadByte(sp,&o)==0) - return(0); - if (o!=n) - { - if (sp->subsamplingcorrect==0) - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data"); - return(0); - } - /* per component stuff */ - /* TODO: double-check that flow implies that n cannot be as big as to make us overflow sof_c, sof_hv and sof_tq arrays */ - for (q=0; qsubsamplingcorrect==0) - sp->sof_c[q]=o; - /* H: Horizontal sampling factor, and V: Vertical sampling factor */ - if (OJPEGReadByte(sp,&o)==0) - return(0); - if (sp->subsamplingcorrect!=0) - { - if (q==0) - { - sp->subsampling_hor=(o>>4); - sp->subsampling_ver=(o&15); - if (((sp->subsampling_hor!=1) && (sp->subsampling_hor!=2) && (sp->subsampling_hor!=4)) || - ((sp->subsampling_ver!=1) && (sp->subsampling_ver!=2) && (sp->subsampling_ver!=4))) - sp->subsampling_force_desubsampling_inside_decompression=1; - } - else - { - if (o!=17) - sp->subsampling_force_desubsampling_inside_decompression=1; - } - } - else - { - sp->sof_hv[q]=o; - if (sp->subsampling_force_desubsampling_inside_decompression==0) - { - if (q==0) - { - if (o!=((sp->subsampling_hor<<4)|sp->subsampling_ver)) - { - TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values"); - return(0); - } - } - else - { - if (o!=17) - { - TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values"); - return(0); - } - } - } - } - /* Tq: Quantization table destination selector */ - if (OJPEGReadByte(sp,&o)==0) - return(0); - if (sp->subsamplingcorrect==0) - sp->sof_tq[q]=o; - } - if (sp->subsamplingcorrect==0) - sp->sof_log=1; - return(1); +static int OJPEGReadHeaderInfoSecStreamSof(TIFF *tif, uint8_t marker_id) +{ + /* this marker needs to be checked, and part of its data needs to be saved + * for regeneration later on */ + static const char module[] = "OJPEGReadHeaderInfoSecStreamSof"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint16_t m; + uint16_t n; + uint8_t o; + uint16_t p; + uint16_t q; + if (sp->sof_log != 0) + { + TIFFErrorExtR(tif, module, "Corrupt JPEG data"); + return (0); + } + if (sp->subsamplingcorrect == 0) + sp->sof_marker_id = marker_id; + /* Lf: data length */ + if (OJPEGReadWord(sp, &m) == 0) + return (0); + if (m < 11) + { + if (sp->subsamplingcorrect == 0) + TIFFErrorExtR(tif, module, "Corrupt SOF marker in JPEG data"); + return (0); + } + m -= 8; + if (m % 3 != 0) + { + if (sp->subsamplingcorrect == 0) + TIFFErrorExtR(tif, module, "Corrupt SOF marker in JPEG data"); + return (0); + } + n = m / 3; + if (sp->subsamplingcorrect == 0) + { + if (n != sp->samples_per_pixel) + { + TIFFErrorExtR( + tif, module, + "JPEG compressed data indicates unexpected number of samples"); + return (0); + } + } + /* P: Sample precision */ + if (OJPEGReadByte(sp, &o) == 0) + return (0); + if (o != 8) + { + if (sp->subsamplingcorrect == 0) + TIFFErrorExtR(tif, module, + "JPEG compressed data indicates unexpected number of " + "bits per sample"); + return (0); + } + /* Y: Number of lines, X: Number of samples per line */ + if (sp->subsamplingcorrect) + OJPEGReadSkip(sp, 4); + else + { + /* Y: Number of lines */ + if (OJPEGReadWord(sp, &p) == 0) + return (0); + if (((uint32_t)p < sp->image_length) && + ((uint32_t)p < sp->strile_length_total)) + { + TIFFErrorExtR(tif, module, + "JPEG compressed data indicates unexpected height"); + return (0); + } + sp->sof_y = p; + /* X: Number of samples per line */ + if (OJPEGReadWord(sp, &p) == 0) + return (0); + if (((uint32_t)p < sp->image_width) && ((uint32_t)p < sp->strile_width)) + { + TIFFErrorExtR(tif, module, + "JPEG compressed data indicates unexpected width"); + return (0); + } + if ((uint32_t)p > sp->strile_width) + { + TIFFErrorExtR(tif, module, + "JPEG compressed data image width exceeds expected " + "image width"); + return (0); + } + sp->sof_x = p; + } + /* Nf: Number of image components in frame */ + if (OJPEGReadByte(sp, &o) == 0) + return (0); + if (o != n) + { + if (sp->subsamplingcorrect == 0) + TIFFErrorExtR(tif, module, "Corrupt SOF marker in JPEG data"); + return (0); + } + /* per component stuff */ + /* TODO: double-check that flow implies that n cannot be as big as to make + * us overflow sof_c, sof_hv and sof_tq arrays */ + for (q = 0; q < n; q++) + { + /* C: Component identifier */ + if (OJPEGReadByte(sp, &o) == 0) + return (0); + if (sp->subsamplingcorrect == 0) + sp->sof_c[q] = o; + /* H: Horizontal sampling factor, and V: Vertical sampling factor */ + if (OJPEGReadByte(sp, &o) == 0) + return (0); + if (sp->subsamplingcorrect != 0) + { + if (q == 0) + { + sp->subsampling_hor = (o >> 4); + sp->subsampling_ver = (o & 15); + if (((sp->subsampling_hor != 1) && (sp->subsampling_hor != 2) && + (sp->subsampling_hor != 4)) || + ((sp->subsampling_ver != 1) && (sp->subsampling_ver != 2) && + (sp->subsampling_ver != 4))) + sp->subsampling_force_desubsampling_inside_decompression = + 1; + } + else + { + if (o != 17) + sp->subsampling_force_desubsampling_inside_decompression = + 1; + } + } + else + { + sp->sof_hv[q] = o; + if (sp->subsampling_force_desubsampling_inside_decompression == 0) + { + if (q == 0) + { + if (o != ((sp->subsampling_hor << 4) | sp->subsampling_ver)) + { + TIFFErrorExtR(tif, module, + "JPEG compressed data indicates " + "unexpected subsampling values"); + return (0); + } + } + else + { + if (o != 17) + { + TIFFErrorExtR(tif, module, + "JPEG compressed data indicates " + "unexpected subsampling values"); + return (0); + } + } + } + } + /* Tq: Quantization table destination selector */ + if (OJPEGReadByte(sp, &o) == 0) + return (0); + if (sp->subsamplingcorrect == 0) + sp->sof_tq[q] = o; + } + if (sp->subsamplingcorrect == 0) + sp->sof_log = 1; + return (1); } -static int -OJPEGReadHeaderInfoSecStreamSos(TIFF* tif) -{ - /* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */ - static const char module[]="OJPEGReadHeaderInfoSecStreamSos"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint16 m; - uint8 n; - uint8 o; - assert(sp->subsamplingcorrect==0); - if (sp->sof_log==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); - return(0); - } - /* Ls */ - if (OJPEGReadWord(sp,&m)==0) - return(0); - if (m!=6+sp->samples_per_pixel_per_plane*2) - { - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); - return(0); - } - /* Ns */ - if (OJPEGReadByte(sp,&n)==0) - return(0); - if (n!=sp->samples_per_pixel_per_plane) - { - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data"); - return(0); - } - /* Cs, Td, and Ta */ - for (o=0; osamples_per_pixel_per_plane; o++) - { - /* Cs */ - if (OJPEGReadByte(sp,&n)==0) - return(0); - sp->sos_cs[sp->plane_sample_offset+o]=n; - /* Td and Ta */ - if (OJPEGReadByte(sp,&n)==0) - return(0); - sp->sos_tda[sp->plane_sample_offset+o]=n; - } - /* skip Ss, Se, Ah, en Al -> no check, as per Tom Lane recommendation, as per LibJpeg source */ - OJPEGReadSkip(sp,3); - return(1); +static int OJPEGReadHeaderInfoSecStreamSos(TIFF *tif) +{ + /* this marker needs to be checked, and part of its data needs to be saved + * for regeneration later on */ + static const char module[] = "OJPEGReadHeaderInfoSecStreamSos"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint16_t m; + uint8_t n; + uint8_t o; + assert(sp->subsamplingcorrect == 0); + if (sp->sof_log == 0) + { + TIFFErrorExtR(tif, module, "Corrupt SOS marker in JPEG data"); + return (0); + } + /* Ls */ + if (OJPEGReadWord(sp, &m) == 0) + return (0); + if (m != 6 + sp->samples_per_pixel_per_plane * 2) + { + TIFFErrorExtR(tif, module, "Corrupt SOS marker in JPEG data"); + return (0); + } + /* Ns */ + if (OJPEGReadByte(sp, &n) == 0) + return (0); + if (n != sp->samples_per_pixel_per_plane) + { + TIFFErrorExtR(tif, module, "Corrupt SOS marker in JPEG data"); + return (0); + } + /* Cs, Td, and Ta */ + for (o = 0; o < sp->samples_per_pixel_per_plane; o++) + { + /* Cs */ + if (OJPEGReadByte(sp, &n) == 0) + return (0); + sp->sos_cs[sp->plane_sample_offset + o] = n; + /* Td and Ta */ + if (OJPEGReadByte(sp, &n) == 0) + return (0); + sp->sos_tda[sp->plane_sample_offset + o] = n; + } + /* skip Ss, Se, Ah, en Al -> no check, as per Tom Lane recommendation, as + * per LibJpeg source */ + OJPEGReadSkip(sp, 3); + return (1); } -static int -OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif) -{ - static const char module[]="OJPEGReadHeaderInfoSecTablesQTable"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8 m; - uint8 n; - uint32 oa; - uint8* ob; - uint32 p; - if (sp->qtable_offset[0]==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); - return(0); - } - sp->in_buffer_file_pos_log=0; - for (m=0; msamples_per_pixel; m++) - { - if ((sp->qtable_offset[m]!=0) && ((m==0) || (sp->qtable_offset[m]!=sp->qtable_offset[m-1]))) - { - for (n=0; nqtable_offset[m]==sp->qtable_offset[n]) - { - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegQTables tag value"); - return(0); - } - } - oa=sizeof(uint32)+69; - ob=_TIFFmalloc(oa); - if (ob==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); - return(0); - } - *(uint32*)ob=oa; - ob[sizeof(uint32)]=255; - ob[sizeof(uint32)+1]=JPEG_MARKER_DQT; - ob[sizeof(uint32)+2]=0; - ob[sizeof(uint32)+3]=67; - ob[sizeof(uint32)+4]=m; - TIFFSeekFile(tif,sp->qtable_offset[m],SEEK_SET); - p=TIFFReadFile(tif,&ob[sizeof(uint32)+5],64); - if (p!=64) - return(0); - sp->qtable[m]=ob; - sp->sof_tq[m]=m; - } - else - sp->sof_tq[m]=sp->sof_tq[m-1]; - } - return(1); +static int OJPEGReadHeaderInfoSecTablesQTable(TIFF *tif) +{ + static const char module[] = "OJPEGReadHeaderInfoSecTablesQTable"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t m; + uint8_t n; + uint32_t oa; + uint8_t *ob; + uint32_t p; + if (sp->qtable_offset[0] == 0) + { + TIFFErrorExtR(tif, module, "Missing JPEG tables"); + return (0); + } + sp->in_buffer_file_pos_log = 0; + for (m = 0; m < sp->samples_per_pixel; m++) + { + if ((sp->qtable_offset[m] != 0) && + ((m == 0) || (sp->qtable_offset[m] != sp->qtable_offset[m - 1]))) + { + for (n = 0; n < m - 1; n++) + { + if (sp->qtable_offset[m] == sp->qtable_offset[n]) + { + TIFFErrorExtR(tif, module, "Corrupt JpegQTables tag value"); + return (0); + } + } + oa = sizeof(uint32_t) + 69; + ob = _TIFFmallocExt(tif, oa); + if (ob == 0) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + *(uint32_t *)ob = oa; + ob[sizeof(uint32_t)] = 255; + ob[sizeof(uint32_t) + 1] = JPEG_MARKER_DQT; + ob[sizeof(uint32_t) + 2] = 0; + ob[sizeof(uint32_t) + 3] = 67; + ob[sizeof(uint32_t) + 4] = m; + TIFFSeekFile(tif, sp->qtable_offset[m], SEEK_SET); + p = (uint32_t)TIFFReadFile(tif, &ob[sizeof(uint32_t) + 5], 64); + if (p != 64) + { + _TIFFfreeExt(tif, ob); + return (0); + } + if (sp->qtable[m] != 0) + _TIFFfreeExt(tif, sp->qtable[m]); + sp->qtable[m] = ob; + sp->sof_tq[m] = m; + } + else + sp->sof_tq[m] = sp->sof_tq[m - 1]; + } + return (1); } -static int -OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif) -{ - static const char module[]="OJPEGReadHeaderInfoSecTablesDcTable"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8 m; - uint8 n; - uint8 o[16]; - uint32 p; - uint32 q; - uint32 ra; - uint8* rb; - if (sp->dctable_offset[0]==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); - return(0); - } - sp->in_buffer_file_pos_log=0; - for (m=0; msamples_per_pixel; m++) - { - if ((sp->dctable_offset[m]!=0) && ((m==0) || (sp->dctable_offset[m]!=sp->dctable_offset[m-1]))) - { - for (n=0; ndctable_offset[m]==sp->dctable_offset[n]) - { - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegDcTables tag value"); - return(0); - } - } - TIFFSeekFile(tif,sp->dctable_offset[m],SEEK_SET); - p=TIFFReadFile(tif,o,16); - if (p!=16) - return(0); - q=0; - for (n=0; n<16; n++) - q+=o[n]; - ra=sizeof(uint32)+21+q; - rb=_TIFFmalloc(ra); - if (rb==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); - return(0); - } - *(uint32*)rb=ra; - rb[sizeof(uint32)]=255; - rb[sizeof(uint32)+1]=JPEG_MARKER_DHT; - rb[sizeof(uint32)+2]=((19+q)>>8); - rb[sizeof(uint32)+3]=((19+q)&255); - rb[sizeof(uint32)+4]=m; - for (n=0; n<16; n++) - rb[sizeof(uint32)+5+n]=o[n]; - p=TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q); - if (p!=q) - return(0); - sp->dctable[m]=rb; - sp->sos_tda[m]=(m<<4); - } - else - sp->sos_tda[m]=sp->sos_tda[m-1]; - } - return(1); +static int OJPEGReadHeaderInfoSecTablesDcTable(TIFF *tif) +{ + static const char module[] = "OJPEGReadHeaderInfoSecTablesDcTable"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t m; + uint8_t n; + uint8_t o[16]; + uint32_t p; + uint32_t q; + uint32_t ra; + uint8_t *rb; + if (sp->dctable_offset[0] == 0) + { + TIFFErrorExtR(tif, module, "Missing JPEG tables"); + return (0); + } + sp->in_buffer_file_pos_log = 0; + for (m = 0; m < sp->samples_per_pixel; m++) + { + if ((sp->dctable_offset[m] != 0) && + ((m == 0) || (sp->dctable_offset[m] != sp->dctable_offset[m - 1]))) + { + for (n = 0; n < m - 1; n++) + { + if (sp->dctable_offset[m] == sp->dctable_offset[n]) + { + TIFFErrorExtR(tif, module, + "Corrupt JpegDcTables tag value"); + return (0); + } + } + TIFFSeekFile(tif, sp->dctable_offset[m], SEEK_SET); + p = (uint32_t)TIFFReadFile(tif, o, 16); + if (p != 16) + return (0); + q = 0; + for (n = 0; n < 16; n++) + q += o[n]; + ra = sizeof(uint32_t) + 21 + q; + rb = _TIFFmallocExt(tif, ra); + if (rb == 0) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + *(uint32_t *)rb = ra; + rb[sizeof(uint32_t)] = 255; + rb[sizeof(uint32_t) + 1] = JPEG_MARKER_DHT; + rb[sizeof(uint32_t) + 2] = (uint8_t)((19 + q) >> 8); + rb[sizeof(uint32_t) + 3] = ((19 + q) & 255); + rb[sizeof(uint32_t) + 4] = m; + for (n = 0; n < 16; n++) + rb[sizeof(uint32_t) + 5 + n] = o[n]; + p = (uint32_t)TIFFReadFile(tif, &(rb[sizeof(uint32_t) + 21]), q); + if (p != q) + { + _TIFFfreeExt(tif, rb); + return (0); + } + if (sp->dctable[m] != 0) + _TIFFfreeExt(tif, sp->dctable[m]); + sp->dctable[m] = rb; + sp->sos_tda[m] = (m << 4); + } + else + sp->sos_tda[m] = sp->sos_tda[m - 1]; + } + return (1); } -static int -OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif) -{ - static const char module[]="OJPEGReadHeaderInfoSecTablesAcTable"; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8 m; - uint8 n; - uint8 o[16]; - uint32 p; - uint32 q; - uint32 ra; - uint8* rb; - if (sp->actable_offset[0]==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables"); - return(0); - } - sp->in_buffer_file_pos_log=0; - for (m=0; msamples_per_pixel; m++) - { - if ((sp->actable_offset[m]!=0) && ((m==0) || (sp->actable_offset[m]!=sp->actable_offset[m-1]))) - { - for (n=0; nactable_offset[m]==sp->actable_offset[n]) - { - TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegAcTables tag value"); - return(0); - } - } - TIFFSeekFile(tif,sp->actable_offset[m],SEEK_SET); - p=TIFFReadFile(tif,o,16); - if (p!=16) - return(0); - q=0; - for (n=0; n<16; n++) - q+=o[n]; - ra=sizeof(uint32)+21+q; - rb=_TIFFmalloc(ra); - if (rb==0) - { - TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); - return(0); - } - *(uint32*)rb=ra; - rb[sizeof(uint32)]=255; - rb[sizeof(uint32)+1]=JPEG_MARKER_DHT; - rb[sizeof(uint32)+2]=((19+q)>>8); - rb[sizeof(uint32)+3]=((19+q)&255); - rb[sizeof(uint32)+4]=(16|m); - for (n=0; n<16; n++) - rb[sizeof(uint32)+5+n]=o[n]; - p=TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q); - if (p!=q) - return(0); - sp->actable[m]=rb; - sp->sos_tda[m]=(sp->sos_tda[m]|m); - } - else - sp->sos_tda[m]=(sp->sos_tda[m]|(sp->sos_tda[m-1]&15)); - } - return(1); +static int OJPEGReadHeaderInfoSecTablesAcTable(TIFF *tif) +{ + static const char module[] = "OJPEGReadHeaderInfoSecTablesAcTable"; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t m; + uint8_t n; + uint8_t o[16]; + uint32_t p; + uint32_t q; + uint32_t ra; + uint8_t *rb; + if (sp->actable_offset[0] == 0) + { + TIFFErrorExtR(tif, module, "Missing JPEG tables"); + return (0); + } + sp->in_buffer_file_pos_log = 0; + for (m = 0; m < sp->samples_per_pixel; m++) + { + if ((sp->actable_offset[m] != 0) && + ((m == 0) || (sp->actable_offset[m] != sp->actable_offset[m - 1]))) + { + for (n = 0; n < m - 1; n++) + { + if (sp->actable_offset[m] == sp->actable_offset[n]) + { + TIFFErrorExtR(tif, module, + "Corrupt JpegAcTables tag value"); + return (0); + } + } + TIFFSeekFile(tif, sp->actable_offset[m], SEEK_SET); + p = (uint32_t)TIFFReadFile(tif, o, 16); + if (p != 16) + return (0); + q = 0; + for (n = 0; n < 16; n++) + q += o[n]; + ra = sizeof(uint32_t) + 21 + q; + rb = _TIFFmallocExt(tif, ra); + if (rb == 0) + { + TIFFErrorExtR(tif, module, "Out of memory"); + return (0); + } + *(uint32_t *)rb = ra; + rb[sizeof(uint32_t)] = 255; + rb[sizeof(uint32_t) + 1] = JPEG_MARKER_DHT; + rb[sizeof(uint32_t) + 2] = (uint8_t)((19 + q) >> 8); + rb[sizeof(uint32_t) + 3] = ((19 + q) & 255); + rb[sizeof(uint32_t) + 4] = (16 | m); + for (n = 0; n < 16; n++) + rb[sizeof(uint32_t) + 5 + n] = o[n]; + p = (uint32_t)TIFFReadFile(tif, &(rb[sizeof(uint32_t) + 21]), q); + if (p != q) + { + _TIFFfreeExt(tif, rb); + return (0); + } + if (sp->actable[m] != 0) + _TIFFfreeExt(tif, sp->actable[m]); + sp->actable[m] = rb; + sp->sos_tda[m] = (sp->sos_tda[m] | m); + } + else + sp->sos_tda[m] = (sp->sos_tda[m] | (sp->sos_tda[m - 1] & 15)); + } + return (1); } -static int -OJPEGReadBufferFill(OJPEGState* sp) -{ - uint16 m; - tsize_t n; - /* TODO: double-check: when subsamplingcorrect is set, no call to TIFFErrorExt or TIFFWarningExt should be made - * in any other case, seek or read errors should be passed through */ - do - { - if (sp->in_buffer_file_togo!=0) - { - if (sp->in_buffer_file_pos_log==0) - { - TIFFSeekFile(sp->tif,sp->in_buffer_file_pos,SEEK_SET); - sp->in_buffer_file_pos_log=1; - } - m=OJPEG_BUFFER; - if (m>sp->in_buffer_file_togo) - m=(uint16)sp->in_buffer_file_togo; - n=TIFFReadFile(sp->tif,sp->in_buffer,(tsize_t)m); - if (n==0) - return(0); - assert(n>0); - assert(n<=OJPEG_BUFFER); - assert(n<65536); - assert((uint16)n<=sp->in_buffer_file_togo); - m=(uint16)n; - sp->in_buffer_togo=m; - sp->in_buffer_cur=sp->in_buffer; - sp->in_buffer_file_togo-=m; - sp->in_buffer_file_pos+=m; - break; - } - sp->in_buffer_file_pos_log=0; - switch(sp->in_buffer_source) - { - case osibsNotSetYet: - if (sp->jpeg_interchange_format!=0) - { - sp->in_buffer_file_pos=sp->jpeg_interchange_format; - sp->in_buffer_file_togo=sp->jpeg_interchange_format_length; - } - sp->in_buffer_source=osibsJpegInterchangeFormat; - break; - case osibsJpegInterchangeFormat: - sp->in_buffer_source=osibsStrile; - case osibsStrile: - if (sp->in_buffer_next_strile==sp->in_buffer_strile_count) - sp->in_buffer_source=osibsEof; - else - { - if (sp->tif->tif_dir.td_stripoffset == 0) { - TIFFErrorExt(sp->tif->tif_clientdata,sp->tif->tif_name,"Strip offsets are missing"); - return(0); - } - sp->in_buffer_file_pos=sp->tif->tif_dir.td_stripoffset[sp->in_buffer_next_strile]; - if (sp->in_buffer_file_pos!=0) - { - if (sp->in_buffer_file_pos>=sp->file_size) - sp->in_buffer_file_pos=0; - else - { - sp->in_buffer_file_togo=sp->tif->tif_dir.td_stripbytecount[sp->in_buffer_next_strile]; - if (sp->in_buffer_file_togo==0) - sp->in_buffer_file_pos=0; - else if (sp->in_buffer_file_pos+sp->in_buffer_file_togo>sp->file_size) - sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos; - } - } - sp->in_buffer_next_strile++; - } - break; - default: - return(0); - } - } while (1); - return(1); +static int OJPEGReadBufferFill(OJPEGState *sp) +{ + uint16_t m; + tmsize_t n; + /* TODO: double-check: when subsamplingcorrect is set, no call to + * TIFFErrorExt or TIFFWarningExt should be made in any other case, seek or + * read errors should be passed through */ + do + { + if (sp->in_buffer_file_togo != 0) + { + if (sp->in_buffer_file_pos_log == 0) + { + TIFFSeekFile(sp->tif, sp->in_buffer_file_pos, SEEK_SET); + sp->in_buffer_file_pos_log = 1; + } + m = OJPEG_BUFFER; + if ((uint64_t)m > sp->in_buffer_file_togo) + m = (uint16_t)sp->in_buffer_file_togo; + n = TIFFReadFile(sp->tif, sp->in_buffer, (tmsize_t)m); + if (n == 0) + return (0); + assert(n > 0); + assert(n <= OJPEG_BUFFER); + assert(n < 65536); + assert((uint64_t)n <= sp->in_buffer_file_togo); + m = (uint16_t)n; + sp->in_buffer_togo = m; + sp->in_buffer_cur = sp->in_buffer; + sp->in_buffer_file_togo -= m; + sp->in_buffer_file_pos += m; + break; + } + sp->in_buffer_file_pos_log = 0; + switch (sp->in_buffer_source) + { + case osibsNotSetYet: + if (sp->jpeg_interchange_format != 0) + { + sp->in_buffer_file_pos = sp->jpeg_interchange_format; + sp->in_buffer_file_togo = + sp->jpeg_interchange_format_length; + } + sp->in_buffer_source = osibsJpegInterchangeFormat; + break; + case osibsJpegInterchangeFormat: + sp->in_buffer_source = osibsStrile; + break; + case osibsStrile: + if (sp->in_buffer_next_strile == sp->in_buffer_strile_count) + sp->in_buffer_source = osibsEof; + else + { + int err = 0; + sp->in_buffer_file_pos = TIFFGetStrileOffsetWithErr( + sp->tif, sp->in_buffer_next_strile, &err); + if (err) + return 0; + if (sp->in_buffer_file_pos != 0) + { + uint64_t bytecount = TIFFGetStrileByteCountWithErr( + sp->tif, sp->in_buffer_next_strile, &err); + if (err) + return 0; + if (sp->in_buffer_file_pos >= sp->file_size) + sp->in_buffer_file_pos = 0; + else if (bytecount == 0) + sp->in_buffer_file_togo = + sp->file_size - sp->in_buffer_file_pos; + else + { + sp->in_buffer_file_togo = bytecount; + if (sp->in_buffer_file_togo == 0) + sp->in_buffer_file_pos = 0; + else if (sp->in_buffer_file_pos > + UINT64_MAX - sp->in_buffer_file_togo || + sp->in_buffer_file_pos + + sp->in_buffer_file_togo > + sp->file_size) + sp->in_buffer_file_togo = + sp->file_size - sp->in_buffer_file_pos; + } + } + sp->in_buffer_next_strile++; + } + break; + default: + return (0); + } + } while (1); + return (1); } -static int -OJPEGReadByte(OJPEGState* sp, uint8* byte) -{ - if (sp->in_buffer_togo==0) - { - if (OJPEGReadBufferFill(sp)==0) - return(0); - assert(sp->in_buffer_togo>0); - } - *byte=*(sp->in_buffer_cur); - sp->in_buffer_cur++; - sp->in_buffer_togo--; - return(1); +static int OJPEGReadByte(OJPEGState *sp, uint8_t *byte) +{ + if (sp->in_buffer_togo == 0) + { + if (OJPEGReadBufferFill(sp) == 0) + return (0); + assert(sp->in_buffer_togo > 0); + } + *byte = *(sp->in_buffer_cur); + sp->in_buffer_cur++; + sp->in_buffer_togo--; + return (1); } -static int -OJPEGReadBytePeek(OJPEGState* sp, uint8* byte) -{ - if (sp->in_buffer_togo==0) - { - if (OJPEGReadBufferFill(sp)==0) - return(0); - assert(sp->in_buffer_togo>0); - } - *byte=*(sp->in_buffer_cur); - return(1); +static int OJPEGReadBytePeek(OJPEGState *sp, uint8_t *byte) +{ + if (sp->in_buffer_togo == 0) + { + if (OJPEGReadBufferFill(sp) == 0) + return (0); + assert(sp->in_buffer_togo > 0); + } + *byte = *(sp->in_buffer_cur); + return (1); } -static void -OJPEGReadByteAdvance(OJPEGState* sp) +static void OJPEGReadByteAdvance(OJPEGState *sp) { - assert(sp->in_buffer_togo>0); - sp->in_buffer_cur++; - sp->in_buffer_togo--; + assert(sp->in_buffer_togo > 0); + sp->in_buffer_cur++; + sp->in_buffer_togo--; } -static int -OJPEGReadWord(OJPEGState* sp, uint16* word) -{ - uint8 m; - if (OJPEGReadByte(sp,&m)==0) - return(0); - *word=(m<<8); - if (OJPEGReadByte(sp,&m)==0) - return(0); - *word|=m; - return(1); +static int OJPEGReadWord(OJPEGState *sp, uint16_t *word) +{ + uint8_t m; + if (OJPEGReadByte(sp, &m) == 0) + return (0); + *word = (m << 8); + if (OJPEGReadByte(sp, &m) == 0) + return (0); + *word |= m; + return (1); } -static int -OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem) -{ - uint16 mlen; - uint8* mmem; - uint16 n; - assert(len>0); - mlen=len; - mmem=mem; - do - { - if (sp->in_buffer_togo==0) - { - if (OJPEGReadBufferFill(sp)==0) - return(0); - assert(sp->in_buffer_togo>0); - } - n=mlen; - if (n>sp->in_buffer_togo) - n=sp->in_buffer_togo; - _TIFFmemcpy(mmem,sp->in_buffer_cur,n); - sp->in_buffer_cur+=n; - sp->in_buffer_togo-=n; - mlen-=n; - mmem+=n; - } while(mlen>0); - return(1); +static int OJPEGReadBlock(OJPEGState *sp, uint16_t len, void *mem) +{ + uint16_t mlen; + uint8_t *mmem; + uint16_t n; + assert(len > 0); + mlen = len; + mmem = mem; + do + { + if (sp->in_buffer_togo == 0) + { + if (OJPEGReadBufferFill(sp) == 0) + return (0); + assert(sp->in_buffer_togo > 0); + } + n = mlen; + if (n > sp->in_buffer_togo) + n = sp->in_buffer_togo; + _TIFFmemcpy(mmem, sp->in_buffer_cur, n); + sp->in_buffer_cur += n; + sp->in_buffer_togo -= n; + mlen -= n; + mmem += n; + } while (mlen > 0); + return (1); } -static void -OJPEGReadSkip(OJPEGState* sp, uint16 len) -{ - uint16 m; - uint16 n; - m=len; - n=m; - if (n>sp->in_buffer_togo) - n=sp->in_buffer_togo; - sp->in_buffer_cur+=n; - sp->in_buffer_togo-=n; - m-=n; - if (m>0) - { - assert(sp->in_buffer_togo==0); - n=m; - if (n>sp->in_buffer_file_togo) - n=sp->in_buffer_file_togo; - sp->in_buffer_file_pos+=n; - sp->in_buffer_file_togo-=n; - sp->in_buffer_file_pos_log=0; - /* we don't skip past jpeginterchangeformat/strile block... - * if that is asked from us, we're dealing with totally bazurk - * data anyway, and we've not seen this happening on any - * testfile, so we might as well likely cause some other - * meaningless error to be passed at some later time - */ - } +static void OJPEGReadSkip(OJPEGState *sp, uint16_t len) +{ + uint16_t m; + uint16_t n; + m = len; + n = m; + if (n > sp->in_buffer_togo) + n = sp->in_buffer_togo; + sp->in_buffer_cur += n; + sp->in_buffer_togo -= n; + m -= n; + if (m > 0) + { + assert(sp->in_buffer_togo == 0); + n = m; + if ((uint64_t)n > sp->in_buffer_file_togo) + n = (uint16_t)sp->in_buffer_file_togo; + sp->in_buffer_file_pos += n; + sp->in_buffer_file_togo -= n; + sp->in_buffer_file_pos_log = 0; + /* we don't skip past jpeginterchangeformat/strile block... + * if that is asked from us, we're dealing with totally bazurk + * data anyway, and we've not seen this happening on any + * testfile, so we might as well likely cause some other + * meaningless error to be passed at some later time + */ + } } -static int -OJPEGWriteStream(TIFF* tif, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - *len=0; - do - { - assert(sp->out_state<=ososEoi); - switch(sp->out_state) - { - case ososSoi: - OJPEGWriteStreamSoi(tif,mem,len); - break; - case ososQTable0: - OJPEGWriteStreamQTable(tif,0,mem,len); - break; - case ososQTable1: - OJPEGWriteStreamQTable(tif,1,mem,len); - break; - case ososQTable2: - OJPEGWriteStreamQTable(tif,2,mem,len); - break; - case ososQTable3: - OJPEGWriteStreamQTable(tif,3,mem,len); - break; - case ososDcTable0: - OJPEGWriteStreamDcTable(tif,0,mem,len); - break; - case ososDcTable1: - OJPEGWriteStreamDcTable(tif,1,mem,len); - break; - case ososDcTable2: - OJPEGWriteStreamDcTable(tif,2,mem,len); - break; - case ososDcTable3: - OJPEGWriteStreamDcTable(tif,3,mem,len); - break; - case ososAcTable0: - OJPEGWriteStreamAcTable(tif,0,mem,len); - break; - case ososAcTable1: - OJPEGWriteStreamAcTable(tif,1,mem,len); - break; - case ososAcTable2: - OJPEGWriteStreamAcTable(tif,2,mem,len); - break; - case ososAcTable3: - OJPEGWriteStreamAcTable(tif,3,mem,len); - break; - case ososDri: - OJPEGWriteStreamDri(tif,mem,len); - break; - case ososSof: - OJPEGWriteStreamSof(tif,mem,len); - break; - case ososSos: - OJPEGWriteStreamSos(tif,mem,len); - break; - case ososCompressed: - if (OJPEGWriteStreamCompressed(tif,mem,len)==0) - return(0); - break; - case ososRst: - OJPEGWriteStreamRst(tif,mem,len); - break; - case ososEoi: - OJPEGWriteStreamEoi(tif,mem,len); - break; - } - } while (*len==0); - return(1); +static int OJPEGWriteStream(TIFF *tif, void **mem, uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + *len = 0; + do + { + assert(sp->out_state <= ososEoi); + switch (sp->out_state) + { + case ososSoi: + OJPEGWriteStreamSoi(tif, mem, len); + break; + case ososQTable0: + OJPEGWriteStreamQTable(tif, 0, mem, len); + break; + case ososQTable1: + OJPEGWriteStreamQTable(tif, 1, mem, len); + break; + case ososQTable2: + OJPEGWriteStreamQTable(tif, 2, mem, len); + break; + case ososQTable3: + OJPEGWriteStreamQTable(tif, 3, mem, len); + break; + case ososDcTable0: + OJPEGWriteStreamDcTable(tif, 0, mem, len); + break; + case ososDcTable1: + OJPEGWriteStreamDcTable(tif, 1, mem, len); + break; + case ososDcTable2: + OJPEGWriteStreamDcTable(tif, 2, mem, len); + break; + case ososDcTable3: + OJPEGWriteStreamDcTable(tif, 3, mem, len); + break; + case ososAcTable0: + OJPEGWriteStreamAcTable(tif, 0, mem, len); + break; + case ososAcTable1: + OJPEGWriteStreamAcTable(tif, 1, mem, len); + break; + case ososAcTable2: + OJPEGWriteStreamAcTable(tif, 2, mem, len); + break; + case ososAcTable3: + OJPEGWriteStreamAcTable(tif, 3, mem, len); + break; + case ososDri: + OJPEGWriteStreamDri(tif, mem, len); + break; + case ososSof: + OJPEGWriteStreamSof(tif, mem, len); + break; + case ososSos: + OJPEGWriteStreamSos(tif, mem, len); + break; + case ososCompressed: + if (OJPEGWriteStreamCompressed(tif, mem, len) == 0) + return (0); + break; + case ososRst: + OJPEGWriteStreamRst(tif, mem, len); + break; + case ososEoi: + OJPEGWriteStreamEoi(tif, mem, len); + break; + } + } while (*len == 0); + return (1); } -static void -OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - assert(OJPEG_BUFFER>=2); - sp->out_buffer[0]=255; - sp->out_buffer[1]=JPEG_MARKER_SOI; - *len=2; - *mem=(void*)sp->out_buffer; - sp->out_state++; +static void OJPEGWriteStreamSoi(TIFF *tif, void **mem, uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + assert(OJPEG_BUFFER >= 2); + sp->out_buffer[0] = 255; + sp->out_buffer[1] = JPEG_MARKER_SOI; + *len = 2; + *mem = (void *)sp->out_buffer; + sp->out_state++; } -static void -OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - if (sp->qtable[table_index]!=0) - { - *mem=(void*)(sp->qtable[table_index]+sizeof(uint32)); - *len=*((uint32*)sp->qtable[table_index])-sizeof(uint32); - } - sp->out_state++; +static void OJPEGWriteStreamQTable(TIFF *tif, uint8_t table_index, void **mem, + uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + if (sp->qtable[table_index] != 0) + { + *mem = (void *)(sp->qtable[table_index] + sizeof(uint32_t)); + *len = *((uint32_t *)sp->qtable[table_index]) - sizeof(uint32_t); + } + sp->out_state++; } -static void -OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - if (sp->dctable[table_index]!=0) - { - *mem=(void*)(sp->dctable[table_index]+sizeof(uint32)); - *len=*((uint32*)sp->dctable[table_index])-sizeof(uint32); - } - sp->out_state++; +static void OJPEGWriteStreamDcTable(TIFF *tif, uint8_t table_index, void **mem, + uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + if (sp->dctable[table_index] != 0) + { + *mem = (void *)(sp->dctable[table_index] + sizeof(uint32_t)); + *len = *((uint32_t *)sp->dctable[table_index]) - sizeof(uint32_t); + } + sp->out_state++; } -static void -OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - if (sp->actable[table_index]!=0) - { - *mem=(void*)(sp->actable[table_index]+sizeof(uint32)); - *len=*((uint32*)sp->actable[table_index])-sizeof(uint32); - } - sp->out_state++; +static void OJPEGWriteStreamAcTable(TIFF *tif, uint8_t table_index, void **mem, + uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + if (sp->actable[table_index] != 0) + { + *mem = (void *)(sp->actable[table_index] + sizeof(uint32_t)); + *len = *((uint32_t *)sp->actable[table_index]) - sizeof(uint32_t); + } + sp->out_state++; } -static void -OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - assert(OJPEG_BUFFER>=6); - if (sp->restart_interval!=0) - { - sp->out_buffer[0]=255; - sp->out_buffer[1]=JPEG_MARKER_DRI; - sp->out_buffer[2]=0; - sp->out_buffer[3]=4; - sp->out_buffer[4]=(sp->restart_interval>>8); - sp->out_buffer[5]=(sp->restart_interval&255); - *len=6; - *mem=(void*)sp->out_buffer; - } - sp->out_state++; +static void OJPEGWriteStreamDri(TIFF *tif, void **mem, uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + assert(OJPEG_BUFFER >= 6); + if (sp->restart_interval != 0) + { + sp->out_buffer[0] = 255; + sp->out_buffer[1] = JPEG_MARKER_DRI; + sp->out_buffer[2] = 0; + sp->out_buffer[3] = 4; + sp->out_buffer[4] = (sp->restart_interval >> 8); + sp->out_buffer[5] = (sp->restart_interval & 255); + *len = 6; + *mem = (void *)sp->out_buffer; + } + sp->out_state++; } -static void -OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8 m; - assert(OJPEG_BUFFER>=2+8+sp->samples_per_pixel_per_plane*3); - assert(255>=8+sp->samples_per_pixel_per_plane*3); - sp->out_buffer[0]=255; - sp->out_buffer[1]=sp->sof_marker_id; - /* Lf */ - sp->out_buffer[2]=0; - sp->out_buffer[3]=8+sp->samples_per_pixel_per_plane*3; - /* P */ - sp->out_buffer[4]=8; - /* Y */ - sp->out_buffer[5]=(sp->sof_y>>8); - sp->out_buffer[6]=(sp->sof_y&255); - /* X */ - sp->out_buffer[7]=(sp->sof_x>>8); - sp->out_buffer[8]=(sp->sof_x&255); - /* Nf */ - sp->out_buffer[9]=sp->samples_per_pixel_per_plane; - for (m=0; msamples_per_pixel_per_plane; m++) - { - /* C */ - sp->out_buffer[10+m*3]=sp->sof_c[sp->plane_sample_offset+m]; - /* H and V */ - sp->out_buffer[10+m*3+1]=sp->sof_hv[sp->plane_sample_offset+m]; - /* Tq */ - sp->out_buffer[10+m*3+2]=sp->sof_tq[sp->plane_sample_offset+m]; - } - *len=10+sp->samples_per_pixel_per_plane*3; - *mem=(void*)sp->out_buffer; - sp->out_state++; +static void OJPEGWriteStreamSof(TIFF *tif, void **mem, uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t m; + assert(OJPEG_BUFFER >= 2 + 8 + sp->samples_per_pixel_per_plane * 3); + assert(255 >= 8 + sp->samples_per_pixel_per_plane * 3); + sp->out_buffer[0] = 255; + sp->out_buffer[1] = sp->sof_marker_id; + /* Lf */ + sp->out_buffer[2] = 0; + sp->out_buffer[3] = 8 + sp->samples_per_pixel_per_plane * 3; + /* P */ + sp->out_buffer[4] = 8; + /* Y */ + sp->out_buffer[5] = (uint8_t)(sp->sof_y >> 8); + sp->out_buffer[6] = (sp->sof_y & 255); + /* X */ + sp->out_buffer[7] = (uint8_t)(sp->sof_x >> 8); + sp->out_buffer[8] = (sp->sof_x & 255); + /* Nf */ + sp->out_buffer[9] = sp->samples_per_pixel_per_plane; + for (m = 0; m < sp->samples_per_pixel_per_plane; m++) + { + /* C */ + sp->out_buffer[10 + m * 3] = sp->sof_c[sp->plane_sample_offset + m]; + /* H and V */ + sp->out_buffer[10 + m * 3 + 1] = + sp->sof_hv[sp->plane_sample_offset + m]; + /* Tq */ + sp->out_buffer[10 + m * 3 + 2] = + sp->sof_tq[sp->plane_sample_offset + m]; + } + *len = 10 + sp->samples_per_pixel_per_plane * 3; + *mem = (void *)sp->out_buffer; + sp->out_state++; } -static void -OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - uint8 m; - assert(OJPEG_BUFFER>=2+6+sp->samples_per_pixel_per_plane*2); - assert(255>=6+sp->samples_per_pixel_per_plane*2); - sp->out_buffer[0]=255; - sp->out_buffer[1]=JPEG_MARKER_SOS; - /* Ls */ - sp->out_buffer[2]=0; - sp->out_buffer[3]=6+sp->samples_per_pixel_per_plane*2; - /* Ns */ - sp->out_buffer[4]=sp->samples_per_pixel_per_plane; - for (m=0; msamples_per_pixel_per_plane; m++) - { - /* Cs */ - sp->out_buffer[5+m*2]=sp->sos_cs[sp->plane_sample_offset+m]; - /* Td and Ta */ - sp->out_buffer[5+m*2+1]=sp->sos_tda[sp->plane_sample_offset+m]; - } - /* Ss */ - sp->out_buffer[5+sp->samples_per_pixel_per_plane*2]=0; - /* Se */ - sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+1]=63; - /* Ah and Al */ - sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+2]=0; - *len=8+sp->samples_per_pixel_per_plane*2; - *mem=(void*)sp->out_buffer; - sp->out_state++; +static void OJPEGWriteStreamSos(TIFF *tif, void **mem, uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + uint8_t m; + assert(OJPEG_BUFFER >= 2 + 6 + sp->samples_per_pixel_per_plane * 2); + assert(255 >= 6 + sp->samples_per_pixel_per_plane * 2); + sp->out_buffer[0] = 255; + sp->out_buffer[1] = JPEG_MARKER_SOS; + /* Ls */ + sp->out_buffer[2] = 0; + sp->out_buffer[3] = 6 + sp->samples_per_pixel_per_plane * 2; + /* Ns */ + sp->out_buffer[4] = sp->samples_per_pixel_per_plane; + for (m = 0; m < sp->samples_per_pixel_per_plane; m++) + { + /* Cs */ + sp->out_buffer[5 + m * 2] = sp->sos_cs[sp->plane_sample_offset + m]; + /* Td and Ta */ + sp->out_buffer[5 + m * 2 + 1] = + sp->sos_tda[sp->plane_sample_offset + m]; + } + /* Ss */ + sp->out_buffer[5 + sp->samples_per_pixel_per_plane * 2] = 0; + /* Se */ + sp->out_buffer[5 + sp->samples_per_pixel_per_plane * 2 + 1] = 63; + /* Ah and Al */ + sp->out_buffer[5 + sp->samples_per_pixel_per_plane * 2 + 2] = 0; + *len = 8 + sp->samples_per_pixel_per_plane * 2; + *mem = (void *)sp->out_buffer; + sp->out_state++; } -static int -OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - if (sp->in_buffer_togo==0) - { - if (OJPEGReadBufferFill(sp)==0) - return(0); - assert(sp->in_buffer_togo>0); - } - *len=sp->in_buffer_togo; - *mem=(void*)sp->in_buffer_cur; - sp->in_buffer_togo=0; - if (sp->in_buffer_file_togo==0) - { - switch(sp->in_buffer_source) - { - case osibsStrile: - if (sp->in_buffer_next_strilein_buffer_strile_count) - sp->out_state=ososRst; - else - sp->out_state=ososEoi; - break; - case osibsEof: - sp->out_state=ososEoi; - break; - default: - break; - } - } - return(1); +static int OJPEGWriteStreamCompressed(TIFF *tif, void **mem, uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + if (sp->in_buffer_togo == 0) + { + if (OJPEGReadBufferFill(sp) == 0) + return (0); + assert(sp->in_buffer_togo > 0); + } + *len = sp->in_buffer_togo; + *mem = (void *)sp->in_buffer_cur; + sp->in_buffer_togo = 0; + if (sp->in_buffer_file_togo == 0) + { + switch (sp->in_buffer_source) + { + case osibsStrile: + if (sp->in_buffer_next_strile < sp->in_buffer_strile_count) + sp->out_state = ososRst; + else + sp->out_state = ososEoi; + break; + case osibsEof: + sp->out_state = ososEoi; + break; + default: + break; + } + } + return (1); } -static void -OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - assert(OJPEG_BUFFER>=2); - sp->out_buffer[0]=255; - sp->out_buffer[1]=JPEG_MARKER_RST0+sp->restart_index; - sp->restart_index++; - if (sp->restart_index==8) - sp->restart_index=0; - *len=2; - *mem=(void*)sp->out_buffer; - sp->out_state=ososCompressed; +static void OJPEGWriteStreamRst(TIFF *tif, void **mem, uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + assert(OJPEG_BUFFER >= 2); + sp->out_buffer[0] = 255; + sp->out_buffer[1] = JPEG_MARKER_RST0 + sp->restart_index; + sp->restart_index++; + if (sp->restart_index == 8) + sp->restart_index = 0; + *len = 2; + *mem = (void *)sp->out_buffer; + sp->out_state = ososCompressed; } -static void -OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len) -{ - OJPEGState* sp=(OJPEGState*)tif->tif_data; - assert(OJPEG_BUFFER>=2); - sp->out_buffer[0]=255; - sp->out_buffer[1]=JPEG_MARKER_EOI; - *len=2; - *mem=(void*)sp->out_buffer; +static void OJPEGWriteStreamEoi(TIFF *tif, void **mem, uint32_t *len) +{ + OJPEGState *sp = (OJPEGState *)tif->tif_data; + assert(OJPEG_BUFFER >= 2); + sp->out_buffer[0] = 255; + sp->out_buffer[1] = JPEG_MARKER_EOI; + *len = 2; + *mem = (void *)sp->out_buffer; } #ifndef LIBJPEG_ENCAP_EXTERNAL -static int -jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo) +static int jpeg_create_decompress_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo) { - return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_create_decompress(cinfo),1)); + if (SETJMP(sp->exit_jmpbuf)) + return 0; + else + { + jpeg_create_decompress(cinfo); + return 1; + } } #endif #ifndef LIBJPEG_ENCAP_EXTERNAL -static int -jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image) +static int jpeg_read_header_encap(OJPEGState *sp, jpeg_decompress_struct *cinfo, + uint8_t require_image) { - return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_header(cinfo,require_image),1)); + if (SETJMP(sp->exit_jmpbuf)) + return 0; + else + { + jpeg_read_header(cinfo, require_image); + return 1; + } } #endif #ifndef LIBJPEG_ENCAP_EXTERNAL -static int -jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo) +static int jpeg_start_decompress_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo) { - return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_start_decompress(cinfo),1)); + if (SETJMP(sp->exit_jmpbuf)) + return 0; + else + { + jpeg_start_decompress(cinfo); + return 1; + } } #endif #ifndef LIBJPEG_ENCAP_EXTERNAL -static int -jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines) +static int jpeg_read_scanlines_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo, + void *scanlines, uint32_t max_lines) { - return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_scanlines(cinfo,scanlines,max_lines),1)); + if (SETJMP(sp->exit_jmpbuf)) + return 0; + else + { + jpeg_read_scanlines(cinfo, scanlines, max_lines); + return 1; + } } #endif #ifndef LIBJPEG_ENCAP_EXTERNAL -static int -jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines) +static int jpeg_read_raw_data_encap(OJPEGState *sp, + jpeg_decompress_struct *cinfo, void *data, + uint32_t max_lines) { - return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_raw_data(cinfo,data,max_lines),1)); + if (SETJMP(sp->exit_jmpbuf)) + return 0; + else + { + jpeg_read_raw_data(cinfo, data, max_lines); + return 1; + } } #endif #ifndef LIBJPEG_ENCAP_EXTERNAL -static void -jpeg_encap_unwind(TIFF* tif) +static void jpeg_encap_unwind(TIFF *tif) { - OJPEGState* sp=(OJPEGState*)tif->tif_data; - LONGJMP(sp->exit_jmpbuf,1); + OJPEGState *sp = (OJPEGState *)tif->tif_data; + LONGJMP(sp->exit_jmpbuf, 1); } #endif -static void -OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo) +static void OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct *cinfo) { - char buffer[JMSG_LENGTH_MAX]; - (*cinfo->err->format_message)(cinfo,buffer); - TIFFWarningExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg", "%s", buffer); + char buffer[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message)(cinfo, buffer); + TIFFWarningExtR(((TIFF *)(cinfo->client_data)), "LibJpeg", "%s", buffer); } -static void -OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo) +static void OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct *cinfo) { - char buffer[JMSG_LENGTH_MAX]; - (*cinfo->err->format_message)(cinfo,buffer); - TIFFErrorExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg", "%s", buffer); - jpeg_encap_unwind((TIFF*)(cinfo->client_data)); + char buffer[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message)(cinfo, buffer); + TIFFErrorExtR(((TIFF *)(cinfo->client_data)), "LibJpeg", "%s", buffer); + jpeg_encap_unwind((TIFF *)(cinfo->client_data)); } -static void -OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo) +static void OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct *cinfo) { - (void)cinfo; + (void)cinfo; } static boolean -OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo) -{ - TIFF* tif=(TIFF*)cinfo->client_data; - OJPEGState* sp=(OJPEGState*)tif->tif_data; - void* mem=0; - uint32 len=0; - if (OJPEGWriteStream(tif,&mem,&len)==0) - { - TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Premature end of JPEG data"); - jpeg_encap_unwind(tif); - } - sp->libjpeg_jpeg_source_mgr.bytes_in_buffer=len; - sp->libjpeg_jpeg_source_mgr.next_input_byte=mem; - return(1); +OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct *cinfo) +{ + TIFF *tif = (TIFF *)cinfo->client_data; + OJPEGState *sp = (OJPEGState *)tif->tif_data; + void *mem = 0; + uint32_t len = 0U; + if (OJPEGWriteStream(tif, &mem, &len) == 0) + { + TIFFErrorExtR(tif, "LibJpeg", "Premature end of JPEG data"); + jpeg_encap_unwind(tif); + } + sp->libjpeg_jpeg_source_mgr.bytes_in_buffer = len; + sp->libjpeg_jpeg_source_mgr.next_input_byte = mem; + return (1); } static void -OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes) +OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct *cinfo, + long num_bytes) { - TIFF* tif=(TIFF*)cinfo->client_data; - (void)num_bytes; - TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error"); - jpeg_encap_unwind(tif); + TIFF *tif = (TIFF *)cinfo->client_data; + (void)num_bytes; + TIFFErrorExtR(tif, "LibJpeg", "Unexpected error"); + jpeg_encap_unwind(tif); } +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4702) /* unreachable code */ +#endif static boolean -OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired) +OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct *cinfo, + int desired) { - TIFF* tif=(TIFF*)cinfo->client_data; - (void)desired; - TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error"); - jpeg_encap_unwind(tif); - return(0); + TIFF *tif = (TIFF *)cinfo->client_data; + (void)desired; + TIFFErrorExtR(tif, "LibJpeg", "Unexpected error"); + jpeg_encap_unwind(tif); + return (0); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif -static void -OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo) +static void OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct *cinfo) { - (void)cinfo; + (void)cinfo; } #endif - - -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ diff --git a/LibTiff/tif_open.c b/LibTiff/tif_open.c index 3b3b2ce6..23fcf81c 100644 --- a/LibTiff/tif_open.c +++ b/LibTiff/tif_open.c @@ -1,26 +1,24 @@ -/* $Id: tif_open.c,v 1.33.2.1 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -28,432 +26,626 @@ * TIFF Library. */ #include "tiffiop.h" - -static const long typemask[13] = { - (long)0L, /* TIFF_NOTYPE */ - (long)0x000000ffL, /* TIFF_BYTE */ - (long)0xffffffffL, /* TIFF_ASCII */ - (long)0x0000ffffL, /* TIFF_SHORT */ - (long)0xffffffffL, /* TIFF_LONG */ - (long)0xffffffffL, /* TIFF_RATIONAL */ - (long)0x000000ffL, /* TIFF_SBYTE */ - (long)0x000000ffL, /* TIFF_UNDEFINED */ - (long)0x0000ffffL, /* TIFF_SSHORT */ - (long)0xffffffffL, /* TIFF_SLONG */ - (long)0xffffffffL, /* TIFF_SRATIONAL */ - (long)0xffffffffL, /* TIFF_FLOAT */ - (long)0xffffffffL, /* TIFF_DOUBLE */ -}; -static const int bigTypeshift[13] = { - 0, /* TIFF_NOTYPE */ - 24, /* TIFF_BYTE */ - 0, /* TIFF_ASCII */ - 16, /* TIFF_SHORT */ - 0, /* TIFF_LONG */ - 0, /* TIFF_RATIONAL */ - 24, /* TIFF_SBYTE */ - 24, /* TIFF_UNDEFINED */ - 16, /* TIFF_SSHORT */ - 0, /* TIFF_SLONG */ - 0, /* TIFF_SRATIONAL */ - 0, /* TIFF_FLOAT */ - 0, /* TIFF_DOUBLE */ -}; -static const int litTypeshift[13] = { - 0, /* TIFF_NOTYPE */ - 0, /* TIFF_BYTE */ - 0, /* TIFF_ASCII */ - 0, /* TIFF_SHORT */ - 0, /* TIFF_LONG */ - 0, /* TIFF_RATIONAL */ - 0, /* TIFF_SBYTE */ - 0, /* TIFF_UNDEFINED */ - 0, /* TIFF_SSHORT */ - 0, /* TIFF_SLONG */ - 0, /* TIFF_SRATIONAL */ - 0, /* TIFF_FLOAT */ - 0, /* TIFF_DOUBLE */ -}; +#include /* * Dummy functions to fill the omitted client procedures. */ -static int -_tiffDummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +static int _tiffDummyMapProc(thandle_t fd, void **pbase, toff_t *psize) { - (void) fd; (void) pbase; (void) psize; - return (0); + (void)fd; + (void)pbase; + (void)psize; + return (0); } -static void -_tiffDummyUnmapProc(thandle_t fd, tdata_t base, toff_t size) +static void _tiffDummyUnmapProc(thandle_t fd, void *base, toff_t size) { - (void) fd; (void) base; (void) size; + (void)fd; + (void)base; + (void)size; } -/* - * Initialize the shift & mask tables, and the - * byte swapping state according to the file - * contents and the machine architecture. +int _TIFFgetMode(TIFFOpenOptions *opts, thandle_t clientdata, 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: + _TIFFErrorEarly(opts, clientdata, module, "\"%s\": Bad mode", mode); + break; + } + return (m); +} + +TIFFOpenOptions *TIFFOpenOptionsAlloc() +{ + TIFFOpenOptions *opts = + (TIFFOpenOptions *)_TIFFcalloc(1, sizeof(TIFFOpenOptions)); + return opts; +} + +void TIFFOpenOptionsFree(TIFFOpenOptions *opts) { _TIFFfree(opts); } + +/** Define a limit in bytes for a single memory allocation done by libtiff. + * If max_single_mem_alloc is set to 0, no other limit that the underlying + * _TIFFmalloc() will be applied, which is the default. */ -static void -TIFFInitOrder(TIFF* tif, int magic) +void TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts, + tmsize_t max_single_mem_alloc) { - tif->tif_typemask = typemask; - if (magic == TIFF_BIGENDIAN) { - tif->tif_typeshift = bigTypeshift; -#ifndef WORDS_BIGENDIAN - tif->tif_flags |= TIFF_SWAB; -#endif - } else { - tif->tif_typeshift = litTypeshift; -#ifdef WORDS_BIGENDIAN - tif->tif_flags |= TIFF_SWAB; -#endif - } + opts->max_single_mem_alloc = max_single_mem_alloc; +} + +void TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts, + TIFFErrorHandlerExtR handler, + void *errorhandler_user_data) +{ + opts->errorhandler = handler; + opts->errorhandler_user_data = errorhandler_user_data; +} + +void TIFFOpenOptionsSetWarningHandlerExtR(TIFFOpenOptions *opts, + TIFFErrorHandlerExtR handler, + void *warnhandler_user_data) +{ + opts->warnhandler = handler; + opts->warnhandler_user_data = warnhandler_user_data; } -int -_TIFFgetMode(const char* mode, const char* module) +static void _TIFFEmitErrorAboveMaxSingleMemAlloc(TIFF *tif, + const char *pszFunction, + tmsize_t s) { - 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); + TIFFErrorExtR(tif, pszFunction, + "Memory allocation of %" PRIu64 + " bytes is beyond the %" PRIu64 + " byte limit defined in open options", + (uint64_t)s, (uint64_t)tif->tif_max_single_mem_alloc); } -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 -) +/** malloc() version that takes into account memory-specific open options */ +void *_TIFFmallocExt(TIFF *tif, tmsize_t s) { - static const char module[] = "TIFFClientOpen"; - TIFF *tif; - int m; - const char* cp; - - m = _TIFFgetMode(mode, module); - if (m == -1) - goto bad2; - tif = (TIFF *)_TIFFmalloc(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 = (tdir_t) -1; /* non-existent directory */ - tif->tif_curoff = 0; - tif->tif_curstrip = (tstrip_t) -1; /* invalid strip */ - tif->tif_row = (uint32) -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."); - 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; + if (tif != NULL && tif->tif_max_single_mem_alloc > 0 && + s > tif->tif_max_single_mem_alloc) + { + _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFmallocExt", s); + return NULL; + } + return _TIFFmalloc(s); +} + +/** calloc() version that takes into account memory-specific open options */ +void *_TIFFcallocExt(TIFF *tif, tmsize_t nmemb, tmsize_t siz) +{ + if (tif != NULL && tif->tif_max_single_mem_alloc > 0) + { + if (nmemb <= 0 || siz <= 0 || nmemb > TIFF_TMSIZE_T_MAX / siz) + return NULL; + if (nmemb * siz > tif->tif_max_single_mem_alloc) + { + _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFcallocExt", + nmemb * siz); + return NULL; + } + } + return _TIFFcalloc(nmemb, siz); +} + +/** realloc() version that takes into account memory-specific open options */ +void *_TIFFreallocExt(TIFF *tif, void *p, tmsize_t s) +{ + if (tif != NULL && tif->tif_max_single_mem_alloc > 0 && + s > tif->tif_max_single_mem_alloc) + { + _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFreallocExt", s); + return NULL; + } + return _TIFFrealloc(p, s); +} + +/** free() version that takes into account memory-specific open options */ +void _TIFFfreeExt(TIFF *tif, void *p) +{ + (void)tif; + _TIFFfree(p); +} + +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) +{ + return TIFFClientOpenExt(name, mode, clientdata, readproc, writeproc, + seekproc, closeproc, sizeproc, mapproc, unmapproc, + NULL); +} + +TIFF *TIFFClientOpenExt(const char *name, const char *mode, + thandle_t clientdata, TIFFReadWriteProc readproc, + TIFFReadWriteProc writeproc, TIFFSeekProc seekproc, + TIFFCloseProc closeproc, TIFFSizeProc sizeproc, + TIFFMapFileProc mapproc, TIFFUnmapFileProc unmapproc, + TIFFOpenOptions *opts) +{ + static const char module[] = "TIFFClientOpenExt"; + 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); + { + 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(opts, clientdata, mode, module); + if (m == -1) + goto bad2; + tmsize_t size_to_alloc = (tmsize_t)(sizeof(TIFF) + strlen(name) + 1); + if (opts && opts->max_single_mem_alloc > 0 && + size_to_alloc > opts->max_single_mem_alloc) + { + _TIFFErrorEarly(opts, clientdata, module, + "%s: Memory allocation of %" PRIu64 + " bytes is beyond the %" PRIu64 + " byte limit defined in open options", + name, (uint64_t)size_to_alloc, + (uint64_t)opts->max_single_mem_alloc); + goto bad2; + } + tif = (TIFF *)_TIFFmallocExt(NULL, size_to_alloc); + if (tif == NULL) + { + _TIFFErrorEarly(opts, 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 = TIFF_NON_EXISTENT_DIR_NUMBER; /* 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; + tif->tif_readproc = readproc; + tif->tif_writeproc = writeproc; + tif->tif_seekproc = seekproc; + tif->tif_closeproc = closeproc; + tif->tif_sizeproc = sizeproc; + tif->tif_mapproc = mapproc ? mapproc : _tiffDummyMapProc; + tif->tif_unmapproc = unmapproc ? unmapproc : _tiffDummyUnmapProc; + if (opts) + { + tif->tif_errorhandler = opts->errorhandler; + tif->tif_errorhandler_user_data = opts->errorhandler_user_data; + tif->tif_warnhandler = opts->warnhandler; + tif->tif_warnhandler_user_data = opts->warnhandler_user_data; + tif->tif_max_single_mem_alloc = opts->max_single_mem_alloc; + } + + if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) + { + TIFFErrorExtR(tif, module, + "One of the client procedures is NULL pointer."); + _TIFFfreeExt(NULL, tif); + goto bad2; + } + + _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; + 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 - * behaviour that may or may not be desirable (usually for - * compatibility with some application that claims to support - * TIFF but only supports some braindead 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 - * - * 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 compatibiltiy 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 behaviour 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': + /* + * 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; + if (m & O_CREAT) + tif->tif_flags |= TIFF_SWAB; #endif - break; - case 'l': + break; + case 'l': #ifdef WORDS_BIGENDIAN - if ((m&O_CREAT)) - tif->tif_flags |= TIFF_SWAB; + 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': + TIFFWarningExtR(tif, name, + "H(ost) mode is deprecated. Since " + "libtiff 4.5.1, it is an alias of 'B' / " + "FILLORDER_MSB2LSB."); + tif->tif_flags = + (tif->tif_flags & ~TIFF_FILLORDER) | FILLORDER_MSB2LSB; + 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 - 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; - } - /* - * Read in TIFF header. - */ - if (tif->tif_mode & O_TRUNC || - !ReadOK(tif, &tif->tif_header, sizeof (TIFFHeader))) { - if (tif->tif_mode == O_RDONLY) { - TIFFErrorExt(tif->tif_clientdata, name, - "Cannot read TIFF header"); - goto bad; - } - /* - * Setup header and write. - */ + + /* + * Read in TIFF header. + */ + if ((m & O_TRUNC) || + !ReadOK(tif, &tif->tif_header, sizeof(TIFFHeaderClassic))) + { + if (tif->tif_mode == O_RDONLY) + { + TIFFErrorExtR(tif, name, "Cannot read TIFF header"); + goto bad; + } +/* + * Setup header and write. + */ #ifdef WORDS_BIGENDIAN - tif->tif_header.tiff_magic = tif->tif_flags & TIFF_SWAB - ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN; + tif->tif_header.common.tiff_magic = + (tif->tif_flags & TIFF_SWAB) ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN; #else - tif->tif_header.tiff_magic = tif->tif_flags & TIFF_SWAB - ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN; + 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))) + { + TIFFErrorExtR(tif, 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 - tif->tif_header.tiff_version = TIFF_VERSION; - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabShort(&tif->tif_header.tiff_version); - tif->tif_header.tiff_diroff = 0; /* filled in later */ - - - /* - * 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, sizeof (TIFFHeader))) { - TIFFErrorExt(tif->tif_clientdata, name, - "Error writing TIFF header"); - goto bad; - } - /* - * Setup the byte order handling. - */ - TIFFInitOrder(tif, tif->tif_header.tiff_magic); - /* - * 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.tiff_magic != TIFF_BIGENDIAN && - tif->tif_header.tiff_magic != TIFF_LITTLEENDIAN + } + /* + * Setup default directory. + */ + if (!TIFFDefaultDirectory(tif)) + goto bad; + tif->tif_diroff = 0; + tif->tif_lastdiroff = 0; + tif->tif_setdirectory_force_absolute = FALSE; + 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.tiff_magic != MDI_BIGENDIAN + tif->tif_header.common.tiff_magic != MDI_BIGENDIAN #else - tif->tif_header.tiff_magic != MDI_LITTLEENDIAN + tif->tif_header.common.tiff_magic != MDI_LITTLEENDIAN #endif - ) { - TIFFErrorExt(tif->tif_clientdata, name, - "Not a TIFF or MDI file, bad magic number %d (0x%x)", + ) + { + TIFFErrorExtR(tif, 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 %d (0x%x)", + ) + { + TIFFErrorExtR(tif, 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 - tif->tif_header.tiff_magic, - tif->tif_header.tiff_magic); - goto bad; - } - TIFFInitOrder(tif, tif->tif_header.tiff_magic); - /* - * Swap header if required. - */ - if (tif->tif_flags & TIFF_SWAB) { - TIFFSwabShort(&tif->tif_header.tiff_version); - TIFFSwabLong(&tif->tif_header.tiff_diroff); - } - /* - * Now check version (if needed, it's been byte-swapped). - * Note that this isn't actually a version number, it's a - * magic number that doesn't change (stupid). - */ - if (tif->tif_header.tiff_version == TIFF_BIGTIFF_VERSION) { - TIFFErrorExt(tif->tif_clientdata, name, - "This is a BigTIFF file. This format not supported\n" - "by this version of libtiff." ); - goto bad; - } - if (tif->tif_header.tiff_version != TIFF_VERSION) { - TIFFErrorExt(tif->tif_clientdata, name, - "Not a TIFF file, bad version number %d (0x%x)", - tif->tif_header.tiff_version, - tif->tif_header.tiff_version); - goto bad; - } - tif->tif_flags |= TIFF_MYBUFFER; - tif->tif_rawcp = tif->tif_rawdata = 0; - tif->tif_rawdatasize = 0; - - /* - * 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. - */ - switch (mode[0]) { - case 'r': - tif->tif_nextdiroff = tif->tif_header.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) && - !TIFFMapFileContents(tif, (tdata_t*) &tif->tif_base, &tif->tif_size)) - tif->tif_flags &= ~TIFF_MAPPED; - if (TIFFReadDirectory(tif)) { - tif->tif_rawcc = -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); - } + } + 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)) + { + TIFFErrorExtR(tif, 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)))) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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)) + { + 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); + tif->tif_mode = O_RDONLY; /* XXX avoid flush */ + TIFFCleanup(tif); bad2: - return ((TIFF*)0); + return ((TIFF *)0); } /* @@ -463,233 +655,154 @@ TIFFClientOpen( /* * Return open file's name. */ -const char * -TIFFFileName(TIFF* tif) -{ - return (tif->tif_name); -} +const char *TIFFFileName(TIFF *tif) { return (tif->tif_name); } /* * Set the file name. */ -const char * -TIFFSetFileName(TIFF* tif, const char *name) +const char *TIFFSetFileName(TIFF *tif, const char *name) { - const char* old_name = tif->tif_name; - tif->tif_name = (char *)name; - return (old_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); -} +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 TIFFSetFileno(TIFF *tif, int fd) { - int old_fd = tif->tif_fd; - tif->tif_fd = fd; - return old_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); -} +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 TIFFSetClientdata(TIFF *tif, thandle_t newvalue) { - thandle_t m = tif->tif_clientdata; - tif->tif_clientdata = newvalue; - return m; + thandle_t m = tif->tif_clientdata; + tif->tif_clientdata = newvalue; + return m; } /* * Return read/write mode. */ -int -TIFFGetMode(TIFF* tif) -{ - return (tif->tif_mode); -} +int TIFFGetMode(TIFF *tif) { return (tif->tif_mode); } /* * Return read/write mode. */ -int -TIFFSetMode(TIFF* tif, int mode) +int TIFFSetMode(TIFF *tif, int mode) { - int old_mode = tif->tif_mode; - tif->tif_mode = mode; - return (old_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)); -} +int TIFFIsTiled(TIFF *tif) { return (isTiled(tif)); } /* * Return current row being read/written. */ -uint32 -TIFFCurrentRow(TIFF* tif) -{ - return (tif->tif_row); -} +uint32_t TIFFCurrentRow(TIFF *tif) { return (tif->tif_row); } /* * Return index of the current directory. */ -tdir_t -TIFFCurrentDirectory(TIFF* tif) -{ - return (tif->tif_curdir); -} +tdir_t TIFFCurrentDirectory(TIFF *tif) { return (tif->tif_curdir); } /* * Return current strip. */ -tstrip_t -TIFFCurrentStrip(TIFF* tif) -{ - return (tif->tif_curstrip); -} +uint32_t TIFFCurrentStrip(TIFF *tif) { return (tif->tif_curstrip); } /* * Return current tile. */ -ttile_t -TIFFCurrentTile(TIFF* tif) -{ - return (tif->tif_curtile); -} +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); -} +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)); -} +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)); -} +int TIFFIsMSB2LSB(TIFF *tif) { return (isFillOrder(tif, FILLORDER_MSB2LSB)); } /* * Return nonzero if given file was written in big-endian order. */ -int -TIFFIsBigEndian(TIFF* tif) +int TIFFIsBigEndian(TIFF *tif) { - return (tif->tif_header.tiff_magic == TIFF_BIGENDIAN); + return (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN); } /* - * Return pointer to file read method. + * Return nonzero if given file is BigTIFF style. */ -TIFFReadWriteProc -TIFFGetReadProc(TIFF* tif) +int TIFFIsBigTIFF(TIFF *tif) { - return (tif->tif_readproc); + return (tif->tif_header.common.tiff_version == TIFF_VERSION_BIG); } +/* + * 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); -} +TIFFReadWriteProc TIFFGetWriteProc(TIFF *tif) { return (tif->tif_writeproc); } /* * Return pointer to file seek method. */ -TIFFSeekProc -TIFFGetSeekProc(TIFF* tif) -{ - return (tif->tif_seekproc); -} +TIFFSeekProc TIFFGetSeekProc(TIFF *tif) { return (tif->tif_seekproc); } /* * Return pointer to file close method. */ -TIFFCloseProc -TIFFGetCloseProc(TIFF* tif) -{ - return (tif->tif_closeproc); -} +TIFFCloseProc TIFFGetCloseProc(TIFF *tif) { return (tif->tif_closeproc); } /* * Return pointer to file size requesting method. */ -TIFFSizeProc -TIFFGetSizeProc(TIFF* tif) -{ - return (tif->tif_sizeproc); -} +TIFFSizeProc TIFFGetSizeProc(TIFF *tif) { return (tif->tif_sizeproc); } /* * Return pointer to memory mapping method. */ -TIFFMapFileProc -TIFFGetMapFileProc(TIFF* tif) -{ - return (tif->tif_mapproc); -} +TIFFMapFileProc TIFFGetMapFileProc(TIFF *tif) { return (tif->tif_mapproc); } /* * Return pointer to memory unmapping method. */ -TIFFUnmapFileProc -TIFFGetUnmapFileProc(TIFF* tif) +TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF *tif) { - return (tif->tif_unmapproc); + 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/LibTiff/tif_packbits.c b/LibTiff/tif_packbits.c index ee095f56..62849f8f 100644 --- a/LibTiff/tif_packbits.c +++ b/LibTiff/tif_packbits.c @@ -1,26 +1,24 @@ -/* $Id: tif_packbits.c,v 1.13.2.2 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -33,159 +31,178 @@ */ #include -static int -PackBitsPreEncode(TIFF* tif, tsample_t s) +static int PackBitsPreEncode(TIFF *tif, uint16_t s) { - (void) s; + (void)s; - if (!(tif->tif_data = (tidata_t)_TIFFmalloc(sizeof(tsize_t)))) - return (0); - /* - * Calculate the scanline/tile-width size in bytes. - */ - if (isTiled(tif)) - *(tsize_t*)tif->tif_data = TIFFTileRowSize(tif); - else - *(tsize_t*)tif->tif_data = TIFFScanlineSize(tif); - return (1); + tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, 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) +static int PackBitsPostEncode(TIFF *tif) { - if (tif->tif_data) - _TIFFfree(tif->tif_data); - return (1); + if (tif->tif_data) + _TIFFfreeExt(tif, tif->tif_data); + return (1); } -/* - * NB: tidata is the type representing *(tidata_t); - * if tidata_t is made signed then this type must - * be adjusted accordingly. - */ -typedef unsigned char tidata; - /* * Encode a run of pixels. */ -static int -PackBitsEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +static int PackBitsEncode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s) { - unsigned char* bp = (unsigned char*) buf; - tidata_t op, ep, lastliteral; - long n, slop; - int b; - enum { BASE, LITERAL, RUN, LITERAL_RUN } state; + 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 = op - lastliteral; - tif->tif_rawcc += lastliteral - tif->tif_rawcp; - if (!TIFFFlushData1(tif)) - return (-1); - op = tif->tif_rawcp; - while (slop-- > 0) - *op++ = *lastliteral++; - lastliteral = tif->tif_rawcp; - } else { - tif->tif_rawcc += op - tif->tif_rawcp; - if (!TIFFFlushData1(tif)) - return (-1); - op = tif->tif_rawcp; - } - } - switch (state) { - case BASE: /* initial state, set run/literal */ - if (n > 1) { - state = RUN; - if (n > 128) { - *op++ = (tidata) -127; - *op++ = (tidataval_t) b; - n -= 128; - goto again; - } - *op++ = (tidataval_t)(-(n-1)); - *op++ = (tidataval_t) b; - } else { - lastliteral = op; - *op++ = 0; - *op++ = (tidataval_t) b; - state = LITERAL; - } - break; - case LITERAL: /* last object was literal string */ - if (n > 1) { - state = LITERAL_RUN; - if (n > 128) { - *op++ = (tidata) -127; - *op++ = (tidataval_t) b; - n -= 128; - goto again; - } - *op++ = (tidataval_t)(-(n-1)); /* encode run */ - *op++ = (tidataval_t) b; - } else { /* extend literal */ - if (++(*lastliteral) == 127) - state = BASE; - *op++ = (tidataval_t) b; - } - break; - case RUN: /* last object was run */ - if (n > 1) { - if (n > 128) { - *op++ = (tidata) -127; - *op++ = (tidataval_t) b; - n -= 128; - goto again; - } - *op++ = (tidataval_t)(-(n-1)); - *op++ = (tidataval_t) b; - } else { - lastliteral = op; - *op++ = 0; - *op++ = (tidataval_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] == (tidata) -1 && - *lastliteral < 126) { - state = (((*lastliteral) += 2) == 127 ? - BASE : LITERAL); - op[-2] = op[-1]; /* replicate */ - } else - state = RUN; - goto again; - } - } - tif->tif_rawcc += op - tif->tif_rawcp; - tif->tif_rawcp = op; - return (1); + (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); } /* @@ -195,106 +212,112 @@ PackBitsEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) * the decoder if data is read, for example, by scanlines * when it was encoded by strips. */ -static int -PackBitsEncodeChunk(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +static int PackBitsEncodeChunk(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - tsize_t rowsize = *(tsize_t*)tif->tif_data; + tmsize_t rowsize = *(tmsize_t *)tif->tif_data; + + while (cc > 0) + { + tmsize_t chunk = rowsize; - while ((long)cc > 0) { - int chunk = rowsize; - - if( cc < chunk ) - chunk = cc; + if (cc < chunk) + chunk = cc; - if (PackBitsEncode(tif, bp, chunk, s) < 0) - return (-1); - bp += chunk; - cc -= chunk; - } - return (1); + if (PackBitsEncode(tif, bp, chunk, s) < 0) + return (-1); + bp += chunk; + cc -= chunk; + } + return (1); } -static int -PackBitsDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +static int PackBitsDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) { - char *bp; - tsize_t cc; - long n; - int b; + static const char module[] = "PackBitsDecode"; + int8_t *bp; + tmsize_t cc; + long n; + int b; - (void) s; - bp = (char*) tif->tif_rawcp; - cc = tif->tif_rawcc; - while (cc > 0 && (long)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 < n ) - { - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, - "PackBitsDecode: discarding %ld bytes " - "to avoid buffer overrun", - n - occ); - n = occ; - } - occ -= n; - b = *bp++, cc--; - while (n-- > 0) - *op++ = (tidataval_t) b; - } else { /* copy next n+1 bytes literally */ - if (occ < n + 1) - { - TIFFWarningExt(tif->tif_clientdata, tif->tif_name, - "PackBitsDecode: discarding %ld bytes " - "to avoid buffer overrun", - n - occ + 1); - n = occ - 1; - } - _TIFFmemcpy(op, bp, ++n); - op += n; occ -= n; - bp += n; cc -= n; - } - } - tif->tif_rawcp = (tidata_t) bp; - tif->tif_rawcc = cc; - if (occ > 0) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "PackBitsDecode: Not enough data for scanline %ld", - (long) tif->tif_row); - return (0); - } - return (1); + (void)s; + bp = (int8_t *)tif->tif_rawcp; + cc = tif->tif_rawcc; + while (cc > 0 && occ > 0) + { + n = (long)*bp++; + cc--; + if (n < 0) + { /* replicate next byte -n+1 times */ + if (n == -128) /* nop */ + continue; + n = -n + 1; + if (occ < (tmsize_t)n) + { + TIFFWarningExtR(tif, module, + "Discarding %" TIFF_SSIZE_FORMAT + " bytes to avoid buffer overrun", + (tmsize_t)n - occ); + n = (long)occ; + } + if (cc == 0) + { + TIFFWarningExtR( + tif, 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)) + { + TIFFWarningExtR(tif, 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)) + { + TIFFWarningExtR( + tif, 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) + { + TIFFErrorExtR(tif, module, "Not enough data for scanline %" PRIu32, + tif->tif_row); + return (0); + } + return (1); } -int -TIFFInitPackBits(TIFF* tif, int scheme) +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); + (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/LibTiff/tif_pixarlog.c b/LibTiff/tif_pixarlog.c index ed8eb402..5c0346b6 100644 --- a/LibTiff/tif_pixarlog.c +++ b/LibTiff/tif_pixarlog.c @@ -1,26 +1,24 @@ -/* $Id: tif_pixarlog.c,v 1.15.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1996-1997 Sam Leffler * Copyright (c) 1996 Pixar * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -34,10 +32,10 @@ * 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. + * 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 + * 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 @@ -45,15 +43,15 @@ * 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" hightlights and such. + * 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 - * susceptable to such errors than standard 8-bit encodings, but more - * susceptable than straight 16-bit or 32-bit encodings. + * 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 @@ -83,367 +81,438 @@ * 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 -#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); } +#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 *wp, int n, int stride, float *op, - float *ToLinearF) +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]]; - t1 = ToLinearF[cg = wp[1]]; - t2 = ToLinearF[cb = wp[2]]; - 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]]; - t1 = ToLinearF[cg = wp[1]]; - t2 = ToLinearF[cb = wp[2]]; - t3 = ToLinearF[ca = wp[3]]; - 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; - } - } + 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 *wp, int n, int stride, int16 *op, - float *ToLinearF) +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; + 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) : 3071) - - if (n >= stride) { - mask = CODE_MASK; - if (stride == 3) { - t0 = ToLinearF[cr = wp[0]] * SCALE12; - t1 = ToLinearF[cg = wp[1]] * SCALE12; - t2 = ToLinearF[cb = wp[2]] * 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]] * SCALE12; - t1 = ToLinearF[cg = wp[1]] * SCALE12; - t2 = ToLinearF[cb = wp[2]] * SCALE12; - t3 = ToLinearF[ca = wp[3]] * 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; - } - } +#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 *wp, int n, int stride, uint16 *op, - uint16 *ToLinear16) +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]]; - op[1] = ToLinear16[cg = wp[1]]; - op[2] = ToLinear16[cb = wp[2]]; - 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]]; - op[1] = ToLinear16[cg = wp[1]]; - op[2] = ToLinear16[cb = wp[2]]; - op[3] = ToLinear16[ca = wp[3]]; - 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; - } - } + 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 *wp, int n, int stride, uint16 *op) +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] = cr = wp[0]; op[1] = cg = wp[1]; op[2] = cb = wp[2]; - n -= 3; - while (n > 0) { - wp += 3; - op += 3; - n -= 3; - op[0] = (cr += wp[0]) & mask; - op[1] = (cg += wp[1]) & mask; - op[2] = (cb += wp[2]) & mask; - } - } else if (stride == 4) { - op[0] = cr = wp[0]; op[1] = cg = wp[1]; - op[2] = cb = wp[2]; op[3] = ca = wp[3]; - n -= 4; - while (n > 0) { - wp += 4; - op += 4; - n -= 4; - op[0] = (cr += wp[0]) & mask; - op[1] = (cg += wp[1]) & mask; - op[2] = (cb += wp[2]) & mask; - op[3] = (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; - } - } + 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 *wp, int n, int stride, unsigned char *op, - unsigned char *ToLinear8) +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]]; - op[1] = ToLinear8[cg = wp[1]]; - op[2] = ToLinear8[cb = wp[2]]; - 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]]; - op[1] = ToLinear8[cg = wp[1]]; - op[2] = ToLinear8[cb = wp[2]]; - op[3] = ToLinear8[ca = wp[3]]; - 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; - } - } + 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 *wp, int n, int stride, unsigned char *op, - unsigned char *ToLinear8) +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]]; - t2 = ToLinear8[cg = wp[1]]; - t3 = ToLinear8[cr = wp[0]]; - 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]]; - t1 = ToLinear8[cb = wp[2]]; - t2 = ToLinear8[cg = wp[1]]; - t3 = ToLinear8[cr = wp[0]]; - 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; - } - } + 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; + } + } } } @@ -451,109 +520,121 @@ horizontalAccumulate8abgr(uint16 *wp, int n, int stride, unsigned char *op, * State block for each open TIFF * file using PixarLog compression/decompression. */ -typedef struct { - TIFFPredictorState predict; - z_stream stream; - uint16 *tbuf; - uint16 stride; - int state; - int user_datafmt; - int quality; +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 */ + 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; - float *ToLinearF; - uint16 *ToLinear16; - unsigned char *ToLinear8; - uint16 *FromLT2; - uint16 *From14; /* Really for 16-bit data, but we shift down 2 */ - uint16 *From8; - } PixarLogState; -static int -PixarLogMakeTables(PixarLogState *sp) +static int PixarLogMakeTables(TIFF *tif, 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. - */ + /* + * 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; + int nlin, lt2size; + int i, j; + double b, c, linstep, v; float *ToLinearF; - uint16 *ToLinear16; + uint16_t *ToLinear16; unsigned char *ToLinear8; - uint16 *FromLT2; - uint16 *From14; /* Really for 16-bit data, but we shift down 2 */ - uint16 *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 *)_TIFFmalloc(lt2size*sizeof(uint16)); - From14 = (uint16 *)_TIFFmalloc(16384*sizeof(uint16)); - From8 = (uint16 *)_TIFFmalloc(256*sizeof(uint16)); - ToLinearF = (float *)_TIFFmalloc(TSIZEP1 * sizeof(float)); - ToLinear16 = (uint16 *)_TIFFmalloc(TSIZEP1 * sizeof(uint16)); - 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; + 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 *)_TIFFmallocExt(tif, lt2size * sizeof(uint16_t)); + From14 = (uint16_t *)_TIFFmallocExt(tif, 16384 * sizeof(uint16_t)); + From8 = (uint16_t *)_TIFFmallocExt(tif, 256 * sizeof(uint16_t)); + ToLinearF = (float *)_TIFFmallocExt(tif, TSIZEP1 * sizeof(float)); + ToLinear16 = (uint16_t *)_TIFFmallocExt(tif, TSIZEP1 * sizeof(uint16_t)); + ToLinear8 = + (unsigned char *)_TIFFmallocExt(tif, TSIZEP1 * sizeof(unsigned char)); + if (FromLT2 == NULL || From14 == NULL || From8 == NULL || + ToLinearF == NULL || ToLinear16 == NULL || ToLinear8 == NULL) + { + if (FromLT2) + _TIFFfreeExt(tif, FromLT2); + if (From14) + _TIFFfreeExt(tif, From14); + if (From8) + _TIFFfreeExt(tif, From8); + if (ToLinearF) + _TIFFfreeExt(tif, ToLinearF); + if (ToLinear16) + _TIFFfreeExt(tif, ToLinear16); + if (ToLinear8) + _TIFFfreeExt(tif, 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 = 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[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)v; - v = ToLinearF[i]*255.0 + 0.5; - ToLinear8[i] = (v > 255.0) ? 255 : (unsigned char)v; + 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] = j; + for (i = 0; i < lt2size; i++) + { + if ((i * linstep) * (i * linstep) > ToLinearF[j] * ToLinearF[j + 1]) + j++; + FromLT2[i] = (uint16_t)j; } /* @@ -562,20 +643,22 @@ PixarLogMakeTables(PixarLogState *sp) * 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] = j; + 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] = j; + 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); + Fltsize = (float)(lt2size / 2); sp->ToLinearF = ToLinearF; sp->ToLinear16 = ToLinear16; @@ -587,535 +670,727 @@ PixarLogMakeTables(PixarLogState *sp) return 1; } -#define DecoderState(tif) ((PixarLogState*) (tif)->tif_data) -#define EncoderState(tif) ((PixarLogState*) (tif)->tif_data) +#define DecoderState(tif) ((PixarLogState *)(tif)->tif_data) +#define EncoderState(tif) ((PixarLogState *)(tif)->tif_data) -static int PixarLogEncode(TIFF*, tidata_t, tsize_t, tsample_t); -static int PixarLogDecode(TIFF*, tidata_t, tsize_t, tsample_t); +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 +#define PIXARLOGDATAFMT_UNKNOWN -1 -static int -PixarLogGuessDataFmt(TIFFDirectory *td) +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; + 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 uint32 -multiply(size_t m1, size_t m2) +static tmsize_t multiply_ms(tmsize_t m1, tmsize_t m2) { - uint32 bytes = m1 * m2; + return _TIFFMultiplySSize(NULL, m1, m2, NULL); +} - if (m1 && bytes / m1 != m2) - bytes = 0; +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; +} - return bytes; +static int PixarLogFixupTags(TIFF *tif) +{ + (void)tif; + return (1); } -static int -PixarLogSetupDecode(TIFF* tif) +static int PixarLogSetupDecode(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - PixarLogState* sp = DecoderState(tif); - tsize_t tbuf_size; - static const char module[] = "PixarLogSetupDecode"; - - assert(sp != NULL); - - /* 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(multiply(multiply(sp->stride, td->td_imagewidth), - td->td_rowsperstrip), sizeof(uint16)); - if (tbuf_size == 0) - return (0); - sp->tbuf = (uint16 *) _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 bits depth/data format combination (depth: %d)", - td->td_bitspersample); - return (0); - } - - if (inflateInit(&sp->stream) != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg); - return (0); - } else { - sp->state |= PLSTATE_INIT; - return (1); - } + 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 *)_TIFFmallocExt(tif, 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) + { + _TIFFfreeExt(tif, sp->tbuf); + sp->tbuf = NULL; + sp->tbuf_size = 0; + TIFFErrorExtR(tif, module, + "PixarLog compression can't handle bits depth/data " + "format combination (depth: %" PRIu16 ")", + td->td_bitspersample); + return (0); + } + + if (inflateInit(&sp->stream) != Z_OK) + { + _TIFFfreeExt(tif, sp->tbuf); + sp->tbuf = NULL; + sp->tbuf_size = 0; + TIFFErrorExtR(tif, 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, tsample_t s) +static int PixarLogPreDecode(TIFF *tif, uint16_t s) { - PixarLogState* sp = DecoderState(tif); - - (void) s; - assert(sp != NULL); - sp->stream.next_in = tif->tif_rawdata; - sp->stream.avail_in = tif->tif_rawcc; - return (inflateReset(&sp->stream) == Z_OK); + 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) + { + TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size"); + return (0); + } + return (inflateReset(&sp->stream) == Z_OK); } -static int -PixarLogDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) { - TIFFDirectory *td = &tif->tif_dir; - PixarLogState* sp = DecoderState(tif); - static const char module[] = "PixarLogDecode"; - int i, nsamples, llen; - uint16 *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); /* XXX uint16 == 16 bits */ - break; - case PIXARLOGDATAFMT_8BIT: - case PIXARLOGDATAFMT_8BITABGR: - nsamples = occ; - break; - default: - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%d 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_out = (unsigned char *) sp->tbuf; - sp->stream.avail_out = nsamples * sizeof(uint16); - 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, - "%s: Decoding error at scanline %d, %s", - tif->tif_name, tif->tif_row, sp->stream.msg); - if (inflateSync(&sp->stream) != Z_OK) - return (0); - continue; - } - if (state != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", - tif->tif_name, sp->stream.msg); - 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, - "%s: Not enough data at scanline %d (short %d bytes)", - tif->tif_name, tif->tif_row, sp->stream.avail_out); - return (0); - } - - 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, - "%s: stride %d is not a multiple of sample count, " - "%d, data truncated.", tif->tif_name, 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 *)op, sp->ToLinear16); - op += llen * sizeof(uint16); - break; - case PIXARLOGDATAFMT_12BITPICIO: - horizontalAccumulate12(up, llen, sp->stride, - (int16 *)op, sp->ToLinearF); - op += llen * sizeof(int16); - break; - case PIXARLOGDATAFMT_11BITLOG: - horizontalAccumulate11(up, llen, sp->stride, - (uint16 *)op); - op += llen * sizeof(uint16); - 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, tif->tif_name, - "PixarLogDecode: unsupported bits/sample: %d", - td->td_bitspersample); - return (0); - } - } - - return (1); + 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: + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR( + tif, module, "Decoding error at scanline %" PRIu32 ", %s", + tif->tif_row, sp->stream.msg ? sp->stream.msg : "(null)"); + return (0); + } + if (state != Z_OK) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFWarningExtR(tif, 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: + TIFFErrorExtR(tif, module, "Unsupported bits/sample: %" PRIu16, + td->td_bitspersample); + return (0); + } + } + + return (1); } -static int -PixarLogSetupEncode(TIFF* tif) +static int PixarLogSetupEncode(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - PixarLogState* sp = EncoderState(tif); - tsize_t tbuf_size; - static const char module[] = "PixarLogSetupEncode"; - - 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(multiply(multiply(sp->stride, td->td_imagewidth), - td->td_rowsperstrip), sizeof(uint16)); - if (tbuf_size == 0) - return (0); - sp->tbuf = (uint16 *) _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 %d bit linear encodings", td->td_bitspersample); - return (0); - } - - if (deflateInit(&sp->stream, sp->quality) != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg); - return (0); - } else { - sp->state |= PLSTATE_INIT; - return (1); - } + 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 *)_TIFFmallocExt(tif, 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) + { + TIFFErrorExtR(tif, module, + "PixarLog compression can't handle %" PRIu16 + " bit linear encodings", + td->td_bitspersample); + return (0); + } + + if (deflateInit(&sp->stream, sp->quality) != Z_OK) + { + TIFFErrorExtR(tif, 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, tsample_t s) +static int PixarLogPreEncode(TIFF *tif, uint16_t s) { - PixarLogState *sp = EncoderState(tif); - - (void) s; - assert(sp != NULL); - sp->stream.next_out = tif->tif_rawdata; - sp->stream.avail_out = tif->tif_rawdatasize; - return (deflateReset(&sp->stream) == Z_OK); + 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) + { + TIFFErrorExtR(tif, 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 *wp, uint16 *FromLT2) +static void horizontalDifferenceF(float *ip, int n, int stride, uint16_t *wp, + uint16_t *FromLT2) { - - int32 r1, g1, b1, a1, r2, g2, b2, a2, mask; + 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 ) +#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) CLAMP(ip[0]); - g2 = wp[1] = (uint16) CLAMP(ip[1]); - b2 = wp[2] = (uint16) CLAMP(ip[2]); - n -= 3; - while (n > 0) { - n -= 3; - wp += 3; - ip += 3; - r1 = (int32) CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; - g1 = (int32) CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; - b1 = (int32) CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; - } - } else if (stride == 4) { - r2 = wp[0] = (uint16) CLAMP(ip[0]); - g2 = wp[1] = (uint16) CLAMP(ip[1]); - b2 = wp[2] = (uint16) CLAMP(ip[2]); - a2 = wp[3] = (uint16) CLAMP(ip[3]); - n -= 4; - while (n > 0) { - n -= 4; - wp += 4; - ip += 4; - r1 = (int32) CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; - g1 = (int32) CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; - b1 = (int32) CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; - a1 = (int32) CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1; - } - } else { - ip += n - 1; /* point to last one */ - wp += n - 1; /* point to last one */ - n -= stride; - while (n > 0) { - REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); - wp[stride] -= wp[0]; - wp[stride] &= mask; - wp--; ip--) - n -= stride; - } - REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); wp--; ip--) - } + 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 *From14) +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; + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; /* assumption is unsigned pixel values */ -#undef CLAMP -#define CLAMP(v) From14[(v) >> 2] +#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] = (r1-r2) & mask; r2 = r1; - g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; - b1 = CLAMP(ip[2]); wp[2] = (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] = (r1-r2) & mask; r2 = r1; - g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; - b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; - a1 = CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1; - } - } else { - ip += n - 1; /* point to last one */ - wp += n - 1; /* point to last one */ - n -= stride; - while (n > 0) { - REPEAT(stride, wp[0] = CLAMP(ip[0]); - wp[stride] -= wp[0]; - wp[stride] &= mask; - wp--; ip--) - n -= stride; - } - REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) - } + 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 *From8) +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; + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; -#undef CLAMP -#define CLAMP(v) (From8[(v)]) +#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] = (r1-r2) & mask; r2 = r1; - g1 = CLAMP(ip[4]); wp[4] = (g1-g2) & mask; g2 = g1; - b1 = CLAMP(ip[5]); wp[5] = (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] = (r1-r2) & mask; r2 = r1; - g1 = CLAMP(ip[5]); wp[5] = (g1-g2) & mask; g2 = g1; - b1 = CLAMP(ip[6]); wp[6] = (b1-b2) & mask; b2 = b1; - a1 = CLAMP(ip[7]); wp[7] = (a1-a2) & mask; a2 = a1; - wp += 4; - ip += 4; - } - } else { - wp += n + stride - 1; /* point to last one */ - ip += n + stride - 1; /* point to last one */ - n -= stride; - while (n > 0) { - REPEAT(stride, wp[0] = CLAMP(ip[0]); - wp[stride] -= wp[0]; - wp[stride] &= mask; - wp--; ip--) - n -= stride; - } - REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) - } + 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, tidata_t bp, tsize_t cc, tsample_t s) +static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - TIFFDirectory *td = &tif->tif_dir; - PixarLogState *sp = EncoderState(tif); - static const char module[] = "PixarLogEncode"; - int i, n, 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); /* XXX uint16 == 16 bits */ - break; - case PIXARLOGDATAFMT_8BIT: - case PIXARLOGDATAFMT_8BITABGR: - n = cc; - break; - default: - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%d bit input not supported in PixarLog", - td->td_bitspersample); - return 0; - } - - llen = sp->stride * td->td_imagewidth; - - 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 *)bp, llen, - sp->stride, up, sp->From14); - bp += llen * sizeof(uint16); - 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, tif->tif_name, - "%d bit input not supported in PixarLog", - td->td_bitspersample); - return 0; - } - } - - sp->stream.next_in = (unsigned char *) sp->tbuf; - sp->stream.avail_in = n * sizeof(uint16); - - do { - if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: Encoder error: %s", - tif->tif_name, sp->stream.msg); - return (0); - } - if (sp->stream.avail_out == 0) { - tif->tif_rawcc = tif->tif_rawdatasize; - TIFFFlushData1(tif); - sp->stream.next_out = tif->tif_rawdata; - sp->stream.avail_out = tif->tif_rawdatasize; - } - } while (sp->stream.avail_in > 0); - return (1); + 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: + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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: + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size"); + return (0); + } + + do + { + if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) + { + TIFFErrorExtR(tif, 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); } /* @@ -1123,249 +1398,273 @@ PixarLogEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) * string and tacking on an End Of Information code. */ -static int -PixarLogPostEncode(TIFF* tif) +static int PixarLogPostEncode(TIFF *tif) { - PixarLogState *sp = EncoderState(tif); - static const char module[] = "PixarLogPostEncode"; - int state; - - sp->stream.avail_in = 0; - - do { - state = deflate(&sp->stream, Z_FINISH); - switch (state) { - case Z_STREAM_END: - case Z_OK: - if (sp->stream.avail_out != (uint32)tif->tif_rawdatasize) { - tif->tif_rawcc = - tif->tif_rawdatasize - sp->stream.avail_out; - TIFFFlushData1(tif); - sp->stream.next_out = tif->tif_rawdata; - sp->stream.avail_out = tif->tif_rawdatasize; - } - break; - default: - TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", - tif->tif_name, sp->stream.msg); - return (0); - } - } while (state != Z_STREAM_END); - return (1); + 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: + TIFFErrorExtR(tif, 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) +static void PixarLogClose(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - - /* In a really sneaky maneuver, 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. - */ - td->td_bitspersample = 8; - td->td_sampleformat = SAMPLEFORMAT_UINT; + 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) +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); + 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) + _TIFFfreeExt(tif, sp->FromLT2); + if (sp->From14) + _TIFFfreeExt(tif, sp->From14); + if (sp->From8) + _TIFFfreeExt(tif, sp->From8); + if (sp->ToLinearF) + _TIFFfreeExt(tif, sp->ToLinearF); + if (sp->ToLinear16) + _TIFFfreeExt(tif, sp->ToLinear16); + if (sp->ToLinear8) + _TIFFfreeExt(tif, sp->ToLinear8); + if (sp->state & PLSTATE_INIT) + { + if (tif->tif_mode == O_RDONLY) + inflateEnd(&sp->stream); + else + deflateEnd(&sp->stream); + } + if (sp->tbuf) + _TIFFfreeExt(tif, sp->tbuf); + _TIFFfreeExt(tif, sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); } -static int -PixarLogVSetField(TIFF* tif, ttag_t tag, va_list ap) +static int PixarLogVSetField(TIFF *tif, uint32_t tag, va_list ap) { + static const char module[] = "PixarLogVSetField"; PixarLogState *sp = (PixarLogState *)tif->tif_data; int result; - static const char module[] = "PixarLogVSetField"; - switch (tag) { - case TIFFTAG_PIXARLOGQUALITY: - sp->quality = 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, "%s: zlib error: %s", - tif->tif_name, sp->stream.msg); - return (0); - } - } - return (1); - case TIFFTAG_PIXARLOGDATAFMT: - sp->user_datafmt = 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) : (tsize_t) -1; - tif->tif_scanlinesize = TIFFScanlineSize(tif); - result = 1; /* NB: pseudo tag */ - break; - default: - result = (*sp->vsetparent)(tif, tag, ap); + 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) + { + TIFFErrorExtR(tif, 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, ttag_t tag, va_list ap) +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); + 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 TIFFFieldInfo pixarlogFieldInfo[] = { - {TIFFTAG_PIXARLOGDATAFMT,0,0,TIFF_ANY, FIELD_PSEUDO,FALSE,FALSE,""}, - {TIFFTAG_PIXARLOGQUALITY,0,0,TIFF_ANY, FIELD_PSEUDO,FALSE,FALSE,""} -}; +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) +int TIFFInitPixarLog(TIFF *tif, int scheme) { - static const char module[] = "TIFFInitPixarLog"; - - PixarLogState* sp; - - assert(scheme == COMPRESSION_PIXARLOG); - - /* - * Merge codec-specific tag information. - */ - if (!_TIFFMergeFieldInfo(tif, pixarlogFieldInfo, - TIFFArrayCount(pixarlogFieldInfo))) { - 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 = (tidata_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_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); + static const char module[] = "TIFFInitPixarLog"; + + PixarLogState *sp; + + (void)scheme; + assert(scheme == COMPRESSION_PIXARLOG); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, pixarlogFields, TIFFArrayCount(pixarlogFields))) + { + TIFFErrorExtR(tif, 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 *)_TIFFmallocExt(tif, 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(tif, sp); + + return (1); bad: - TIFFErrorExt(tif->tif_clientdata, module, - "No space for PixarLog state block"); - return (0); + TIFFErrorExtR(tif, 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/LibTiff/tif_predict.c b/LibTiff/tif_predict.c index bbc221f2..386b5fe8 100644 --- a/LibTiff/tif_predict.c +++ b/LibTiff/tif_predict.c @@ -1,26 +1,24 @@ -/* $Id: tif_predict.c,v 1.11.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -29,376 +27,548 @@ * * Predictor Tag Support (used by multiple codecs). */ -#include "tiffiop.h" #include "tif_predict.h" +#include "tiffiop.h" -#define PredictorState(tif) ((TIFFPredictorState*) (tif)->tif_data) - -static void horAcc8(TIFF*, tidata_t, tsize_t); -static void horAcc16(TIFF*, tidata_t, tsize_t); -static void horAcc32(TIFF*, tidata_t, tsize_t); -static void swabHorAcc16(TIFF*, tidata_t, tsize_t); -static void swabHorAcc32(TIFF*, tidata_t, tsize_t); -static void horDiff8(TIFF*, tidata_t, tsize_t); -static void horDiff16(TIFF*, tidata_t, tsize_t); -static void horDiff32(TIFF*, tidata_t, tsize_t); -static void fpAcc(TIFF*, tidata_t, tsize_t); -static void fpDiff(TIFF*, tidata_t, tsize_t); -static int PredictorDecodeRow(TIFF*, tidata_t, tsize_t, tsample_t); -static int PredictorDecodeTile(TIFF*, tidata_t, tsize_t, tsample_t); -static int PredictorEncodeRow(TIFF*, tidata_t, tsize_t, tsample_t); -static int PredictorEncodeTile(TIFF*, tidata_t, tsize_t, tsample_t); - -static int -PredictorSetup(TIFF* tif) +#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 horAcc64(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 swabHorAcc64(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 horDiff64(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 swabHorDiff64(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 %d-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 %d data format", - td->td_sampleformat); - 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); - - return 1; + 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 && td->td_bitspersample != 64) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR( + tif, 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? */ + TIFFErrorExtR( + tif, module, + "Floating point \"Predictor\" not supported with %" PRIu16 + "-bit samples", + td->td_bitspersample); + return 0; + } + break; + default: + TIFFErrorExtR(tif, 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) +static int PredictorSetupDecode(TIFF *tif) { - TIFFPredictorState* sp = PredictorState(tif); - TIFFDirectory* td = &tif->tif_dir; - - 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 ight order - */ - } - - return 1; + 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; + case 64: + sp->decodepfunc = horAcc64; + 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->decodepfunc == horAcc64) + { + sp->decodepfunc = swabHorAcc64; + 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) +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; - } - } - - 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; + 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; + case 64: + sp->encodepfunc = horDiff64; + 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->encodepfunc == horDiff64) + { + sp->encodepfunc = swabHorDiff64; + 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: { int i; for (i = n-4; i > 0; i--) { op; } } \ - case 4: op; \ - case 3: op; \ - case 2: op; \ - case 1: op; \ - case 0: ; \ +#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) + { + TIFFErrorExtR(tif, "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]; + tmsize_t i = stride; + for (; i < cc; i += stride) + { + cp[i + 0] = (unsigned char)((cr += cp[i + 0]) & 0xff); + cp[i + 1] = (unsigned char)((cg += cp[i + 1]) & 0xff); + cp[i + 2] = (unsigned char)((cb += cp[i + 2]) & 0xff); + } + } + else if (stride == 4) + { + unsigned int cr = cp[0]; + unsigned int cg = cp[1]; + unsigned int cb = cp[2]; + unsigned int ca = cp[3]; + tmsize_t i = stride; + for (; i < cc; i += stride) + { + cp[i + 0] = (unsigned char)((cr += cp[i + 0]) & 0xff); + cp[i + 1] = (unsigned char)((cg += cp[i + 1]) & 0xff); + cp[i + 2] = (unsigned char)((cb += cp[i + 2]) & 0xff); + cp[i + 3] = (unsigned char)((ca += cp[i + 3]) & 0xff); + } + } + 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); +} -static void -horAcc8(TIFF* tif, tidata_t cp0, tsize_t cc) +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int horAcc16(TIFF *tif, uint8_t *cp0, tmsize_t cc) { - tsize_t stride = PredictorState(tif)->stride; - - char* cp = (char*) cp0; - if (cc > stride) { - 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]; - do { - cc -= 3, cp += 3; - cp[0] = (char) (cr += cp[0]); - cp[1] = (char) (cg += cp[1]); - cp[2] = (char) (cb += cp[2]); - } while ((int32) cc > 0); - } else if (stride == 4) { - unsigned int cr = cp[0]; - unsigned int cg = cp[1]; - unsigned int cb = cp[2]; - unsigned int ca = cp[3]; - do { - cc -= 4, cp += 4; - cp[0] = (char) (cr += cp[0]); - cp[1] = (char) (cg += cp[1]); - cp[2] = (char) (cb += cp[2]); - cp[3] = (char) (ca += cp[3]); - } while ((int32) cc > 0); - } else { - do { - REPEAT4(stride, cp[stride] = - (char) (cp[stride] + *cp); cp++) - cc -= stride; - } while ((int32) cc > 0); - } - } + tmsize_t stride = PredictorState(tif)->stride; + uint16_t *wp = (uint16_t *)cp0; + tmsize_t wc = cc / 2; + + if ((cc % (2 * stride)) != 0) + { + TIFFErrorExtR(tif, "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 void -swabHorAcc16(TIFF* tif, tidata_t cp0, tsize_t cc) +static int swabHorAcc32(TIFF *tif, uint8_t *cp0, tmsize_t cc) { - tsize_t stride = PredictorState(tif)->stride; - uint16* wp = (uint16*) cp0; - tsize_t wc = cc / 2; - - if (wc > stride) { - TIFFSwabArrayOfShort(wp, wc); - wc -= stride; - do { - REPEAT4(stride, wp[stride] += wp[0]; wp++) - wc -= stride; - } while ((int32) wc > 0); - } + uint32_t *wp = (uint32_t *)cp0; + tmsize_t wc = cc / 4; + + TIFFSwabArrayOfLong(wp, wc); + return horAcc32(tif, cp0, cc); } -static void -horAcc16(TIFF* tif, tidata_t cp0, tsize_t cc) +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int horAcc32(TIFF *tif, uint8_t *cp0, tmsize_t cc) { - tsize_t stride = PredictorState(tif)->stride; - uint16* wp = (uint16*) cp0; - tsize_t wc = cc / 2; - - if (wc > stride) { - wc -= stride; - do { - REPEAT4(stride, wp[stride] += wp[0]; wp++) - wc -= stride; - } while ((int32) wc > 0); - } + tmsize_t stride = PredictorState(tif)->stride; + uint32_t *wp = (uint32_t *)cp0; + tmsize_t wc = cc / 4; + + if ((cc % (4 * stride)) != 0) + { + TIFFErrorExtR(tif, "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; } -static void -swabHorAcc32(TIFF* tif, tidata_t cp0, tsize_t cc) +static int swabHorAcc64(TIFF *tif, uint8_t *cp0, tmsize_t cc) { - tsize_t stride = PredictorState(tif)->stride; - uint32* wp = (uint32*) cp0; - tsize_t wc = cc / 4; - - if (wc > stride) { - TIFFSwabArrayOfLong(wp, wc); - wc -= stride; - do { - REPEAT4(stride, wp[stride] += wp[0]; wp++) - wc -= stride; - } while ((int32) wc > 0); - } + uint64_t *wp = (uint64_t *)cp0; + tmsize_t wc = cc / 8; + + TIFFSwabArrayOfLong8(wp, wc); + return horAcc64(tif, cp0, cc); } -static void -horAcc32(TIFF* tif, tidata_t cp0, tsize_t cc) +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int horAcc64(TIFF *tif, uint8_t *cp0, tmsize_t cc) { - tsize_t stride = PredictorState(tif)->stride; - uint32* wp = (uint32*) cp0; - tsize_t wc = cc / 4; - - if (wc > stride) { - wc -= stride; - do { - REPEAT4(stride, wp[stride] += wp[0]; wp++) - wc -= stride; - } while ((int32) wc > 0); - } + tmsize_t stride = PredictorState(tif)->stride; + uint64_t *wp = (uint64_t *)cp0; + tmsize_t wc = cc / 8; + + if ((cc % (8 * stride)) != 0) + { + TIFFErrorExtR(tif, "horAcc64", "%s", "cc%(8*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 void -fpAcc(TIFF* tif, tidata_t cp0, tsize_t cc) +static int fpAcc(TIFF *tif, uint8_t *cp0, tmsize_t cc) { - tsize_t stride = PredictorState(tif)->stride; - uint32 bps = tif->tif_dir.td_bitspersample / 8; - tsize_t wc = cc / bps; - tsize_t count = cc; - uint8 *cp = (uint8 *) cp0; - uint8 *tmp = (uint8 *)_TIFFmalloc(cc); - - if (!tmp) - return; - - while (count > stride) { - REPEAT4(stride, cp[stride] += cp[0]; cp++) - count -= stride; - } - - _TIFFmemcpy(tmp, cp0, cc); - cp = (uint8 *) cp0; - for (count = 0; count < wc; count++) { - uint32 byte; - for (byte = 0; byte < bps; byte++) { + 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) + { + TIFFErrorExtR(tif, "fpAcc", "%s", "cc%(bps*stride))!=0"); + return 0; + } + + tmp = (uint8_t *)_TIFFmallocExt(tif, 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]; + cp[bps * count + byte] = tmp[byte * wc + count]; #else - cp[bps * count + byte] = - tmp[(bps - byte - 1) * wc + count]; + cp[bps * count + byte] = tmp[(bps - byte - 1) * wc + count]; #endif - } - } - _TIFFfree(tmp); + } + } + _TIFFfreeExt(tif, tmp); + return 1; } /* * Decode a scanline and apply the predictor routine. */ -static int -PredictorDecodeRow(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +static int PredictorDecodeRow(TIFF *tif, uint8_t *op0, tmsize_t occ0, + uint16_t s) { - TIFFPredictorState *sp = PredictorState(tif); + TIFFPredictorState *sp = PredictorState(tif); - assert(sp != NULL); - assert(sp->decoderow != NULL); - assert(sp->decodepfunc != NULL); + assert(sp != NULL); + assert(sp->decoderow != NULL); + assert(sp->decodepfunc != NULL); - if ((*sp->decoderow)(tif, op0, occ0, s)) { - (*sp->decodepfunc)(tif, op0, occ0); - return 1; - } else - return 0; + if ((*sp->decoderow)(tif, op0, occ0, s)) + { + return (*sp->decodepfunc)(tif, op0, occ0); + } + else + return 0; } /* @@ -408,329 +578,469 @@ PredictorDecodeRow(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) * been calculated at pre-decode time according to the * strip/tile dimensions. */ -static int -PredictorDecodeTile(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +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) + { + TIFFErrorExtR(tif, "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) + { + TIFFErrorExtR(tif, "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) + { + TIFFErrorExtR(tif, "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); - - assert(sp != NULL); - assert(sp->decodetile != NULL); - - if ((*sp->decodetile)(tif, op0, occ0, s)) { - tsize_t rowsize = sp->rowsize; - assert(rowsize > 0); - assert(sp->decodepfunc != NULL); - while ((long)occ0 > 0) { - (*sp->decodepfunc)(tif, op0, (tsize_t) rowsize); - occ0 -= rowsize; - op0 += rowsize; - } - return 1; - } else - return 0; + 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) + { + TIFFErrorExtR(tif, "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 void -horDiff8(TIFF* tif, tidata_t cp0, tsize_t cc) +static int swabHorDiff32(TIFF *tif, uint8_t *cp0, tmsize_t cc) { - TIFFPredictorState* sp = PredictorState(tif); - tsize_t stride = sp->stride; - char* cp = (char*) cp0; - - if (cc > stride) { - cc -= stride; - /* - * Pipeline the most common cases. - */ - if (stride == 3) { - int r1, g1, b1; - int r2 = cp[0]; - int g2 = cp[1]; - int b2 = cp[2]; - do { - r1 = cp[3]; cp[3] = r1-r2; r2 = r1; - g1 = cp[4]; cp[4] = g1-g2; g2 = g1; - b1 = cp[5]; cp[5] = b1-b2; b2 = b1; - cp += 3; - } while ((int32)(cc -= 3) > 0); - } else if (stride == 4) { - int r1, g1, b1, a1; - int r2 = cp[0]; - int g2 = cp[1]; - int b2 = cp[2]; - int a2 = cp[3]; - do { - r1 = cp[4]; cp[4] = r1-r2; r2 = r1; - g1 = cp[5]; cp[5] = g1-g2; g2 = g1; - b1 = cp[6]; cp[6] = b1-b2; b2 = b1; - a1 = cp[7]; cp[7] = a1-a2; a2 = a1; - cp += 4; - } while ((int32)(cc -= 4) > 0); - } else { - cp += cc - 1; - do { - REPEAT4(stride, cp[stride] -= cp[0]; cp--) - } while ((int32)(cc -= stride) > 0); - } - } + uint32_t *wp = (uint32_t *)cp0; + tmsize_t wc = cc / 4; + + if (!horDiff32(tif, cp0, cc)) + return 0; + + TIFFSwabArrayOfLong(wp, wc); + return 1; } -static void -horDiff16(TIFF* tif, tidata_t cp0, tsize_t cc) +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int horDiff64(TIFF *tif, uint8_t *cp0, tmsize_t cc) { - TIFFPredictorState* sp = PredictorState(tif); - tsize_t stride = sp->stride; - int16 *wp = (int16*) cp0; - tsize_t wc = cc/2; - - if (wc > stride) { - wc -= stride; - wp += wc - 1; - do { - REPEAT4(stride, wp[stride] -= wp[0]; wp--) - wc -= stride; - } while ((int32) wc > 0); - } + TIFFPredictorState *sp = PredictorState(tif); + tmsize_t stride = sp->stride; + uint64_t *wp = (uint64_t *)cp0; + tmsize_t wc = cc / 8; + + if ((cc % (8 * stride)) != 0) + { + TIFFErrorExtR(tif, "horDiff64", "%s", "(cc%(8*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 void -horDiff32(TIFF* tif, tidata_t cp0, tsize_t cc) +static int swabHorDiff64(TIFF *tif, uint8_t *cp0, tmsize_t cc) { - TIFFPredictorState* sp = PredictorState(tif); - tsize_t stride = sp->stride; - int32 *wp = (int32*) cp0; - tsize_t wc = cc/4; - - if (wc > stride) { - wc -= stride; - wp += wc - 1; - do { - REPEAT4(stride, wp[stride] -= wp[0]; wp--) - wc -= stride; - } while ((int32) wc > 0); - } + uint64_t *wp = (uint64_t *)cp0; + tmsize_t wc = cc / 8; + + if (!horDiff64(tif, cp0, cc)) + return 0; + + TIFFSwabArrayOfLong8(wp, wc); + return 1; } /* * Floating point predictor differencing routine. */ -static void -fpDiff(TIFF* tif, tidata_t cp0, tsize_t cc) +TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW +static int fpDiff(TIFF *tif, uint8_t *cp0, tmsize_t cc) { - tsize_t stride = PredictorState(tif)->stride; - uint32 bps = tif->tif_dir.td_bitspersample / 8; - tsize_t wc = cc / bps; - tsize_t count; - uint8 *cp = (uint8 *) cp0; - uint8 *tmp = (uint8 *)_TIFFmalloc(cc); - - if (!tmp) - return; - - _TIFFmemcpy(tmp, cp0, cc); - for (count = 0; count < wc; count++) { - uint32 byte; - for (byte = 0; byte < bps; byte++) { + 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) + { + TIFFErrorExtR(tif, "fpDiff", "%s", "(cc%(bps*stride))!=0"); + return 0; + } + + tmp = (uint8_t *)_TIFFmallocExt(tif, 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]; + cp[byte * wc + count] = tmp[bps * count + byte]; #else - cp[(bps - byte - 1) * wc + count] = - tmp[bps * count + byte]; + cp[(bps - byte - 1) * wc + count] = tmp[bps * count + byte]; #endif - } - } - _TIFFfree(tmp); - - cp = (uint8 *) cp0; - cp += cc - stride - 1; - for (count = cc; count > stride; count -= stride) - REPEAT4(stride, cp[stride] -= cp[0]; cp--) + } + } + _TIFFfreeExt(tif, 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, tidata_t bp, tsize_t cc, tsample_t s) +static int PredictorEncodeRow(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - TIFFPredictorState *sp = PredictorState(tif); + TIFFPredictorState *sp = PredictorState(tif); - assert(sp != NULL); - assert(sp->encodepfunc != NULL); - assert(sp->encoderow != NULL); + assert(sp != NULL); + assert(sp->encodepfunc != NULL); + assert(sp->encoderow != NULL); - /* XXX horizontal differencing alters user's data XXX */ - (*sp->encodepfunc)(tif, bp, cc); - return (*sp->encoderow)(tif, bp, cc, s); + /* 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, tidata_t bp0, tsize_t cc0, tsample_t 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 *working_copy; - tsize_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*) _TIFFmalloc(cc0); - if( working_copy == NULL ) - { - TIFFErrorExt(tif->tif_clientdata, module, - "Out of memory allocating %d byte temp buffer.", - cc0 ); - return 0; - } - memcpy( working_copy, bp0, cc0 ); - bp = working_copy; - - rowsize = sp->rowsize; - assert(rowsize > 0); - assert((cc0%rowsize)==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; + 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 *)_TIFFmallocExt(tif, cc0); + if (working_copy == NULL) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, "PredictorEncodeTile", "%s", "(cc0%rowsize)!=0"); + _TIFFfreeExt(tif, 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); + + _TIFFfreeExt(tif, working_copy); + + return result_code; } -#define FIELD_PREDICTOR (FIELD_CODEC+0) /* XXX */ +#define FIELD_PREDICTOR (FIELD_CODEC + 0) /* XXX */ -static const TIFFFieldInfo predictFieldInfo[] = { - { TIFFTAG_PREDICTOR, 1, 1, TIFF_SHORT, FIELD_PREDICTOR, - FALSE, FALSE, "Predictor" }, +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, ttag_t tag, va_list ap) +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) va_arg(ap, int); - TIFFSetFieldBit(tif, FIELD_PREDICTOR); - break; - default: - return (*sp->vsetparent)(tif, tag, ap); - } - tif->tif_flags |= TIFF_DIRTYDIRECT; - return 1; + 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, ttag_t tag, va_list ap) +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*) = sp->predictor; - break; - default: - return (*sp->vgetparent)(tif, tag, ap); - } - return 1; + 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) +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, "%u (0x%x)\n", sp->predictor, sp->predictor); - } - if (sp->printdir) - (*sp->printdir)(tif, fd, 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) +int TIFFPredictorInit(TIFF *tif) { - TIFFPredictorState* sp = PredictorState(tif); - - assert(sp != 0); - - /* - * Merge codec-specific tag information. - */ - if (!_TIFFMergeFieldInfo(tif, predictFieldInfo, - TIFFArrayCount(predictFieldInfo))) { - 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; + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != 0); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, predictFields, TIFFArrayCount(predictFields))) + { + TIFFErrorExtR(tif, "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) +int TIFFPredictorCleanup(TIFF *tif) { - TIFFPredictorState* sp = PredictorState(tif); + TIFFPredictorState *sp = PredictorState(tif); - assert(sp != 0); + 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; + 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; + 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/LibTiff/tif_predict.h b/LibTiff/tif_predict.h index da0ad989..de773283 100644 --- a/LibTiff/tif_predict.h +++ b/LibTiff/tif_predict.h @@ -1,77 +1,74 @@ -/* $Id: tif_predict.h,v 1.3.2.2 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1995-1997 Sam Leffler * Copyright (c) 1995-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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_ +#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 */ - int stride; /* sample stride over data */ - tsize_t rowsize; /* tile/strip row size */ +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 encoderow; /* parent codec encode/decode row */ - TIFFCodeMethod encodestrip; /* parent codec encode/decode strip */ - TIFFCodeMethod encodetile; /* parent codec encode/decode tile */ - TIFFPostMethod encodepfunc; /* horizontal differencer */ - - TIFFCodeMethod decoderow; /* parent codec encode/decode row */ - TIFFCodeMethod decodestrip; /* parent codec encode/decode strip */ - TIFFCodeMethod decodetile; /* parent codec encode/decode tile */ - TIFFPostMethod decodepfunc; /* horizontal accumulator */ + 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 */ + 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" { +extern "C" +{ #endif -extern int TIFFPredictorInit(TIFF*); -extern int TIFFPredictorCleanup(TIFF*); + 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/LibTiff/tif_print.c b/LibTiff/tif_print.c index 09a6ee6c..2b7fd176 100644 --- a/LibTiff/tif_print.c +++ b/LibTiff/tif_print.c @@ -1,26 +1,24 @@ -/* $Id: tif_print.c,v 1.36.2.4 2010-06-08 18:50:42 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,616 +29,727 @@ */ #include "tiffiop.h" #include -#include + #include -static const char *photoNames[] = { - "min-is-white", /* PHOTOMETRIC_MINISWHITE */ - "min-is-black", /* PHOTOMETRIC_MINISBLACK */ - "RGB color", /* PHOTOMETRIC_RGB */ - "palette color (RGB from colormap)", /* PHOTOMETRIC_PALETTE */ - "transparency mask", /* PHOTOMETRIC_MASK */ - "separated", /* PHOTOMETRIC_SEPARATED */ - "YCbCr", /* PHOTOMETRIC_YCBCR */ +static void _TIFFprintAsciiBounded(FILE *fd, const char *cp, size_t max_chars); + +static const char *const photoNames[] = { + "min-is-white", /* PHOTOMETRIC_MINISWHITE */ + "min-is-black", /* PHOTOMETRIC_MINISBLACK */ + "RGB color", /* PHOTOMETRIC_RGB */ + "palette color (RGB from colormap)", /* PHOTOMETRIC_PALETTE */ + "transparency mask", /* PHOTOMETRIC_MASK */ + "separated", /* PHOTOMETRIC_SEPARATED */ + "YCbCr", /* PHOTOMETRIC_YCBCR */ "7 (0x7)", - "CIE L*a*b*", /* PHOTOMETRIC_CIELAB */ + "CIE L*a*b*", /* PHOTOMETRIC_CIELAB */ + "ICC L*a*b*", /* PHOTOMETRIC_ICCLAB */ + "ITU L*a*b*" /* PHOTOMETRIC_ITULAB */ }; -#define NPHOTONAMES (sizeof (photoNames) / sizeof (photoNames[0])) +#define NPHOTONAMES (sizeof(photoNames) / sizeof(photoNames[0])) -static const char *orientNames[] = { +static const char *const orientNames[] = { "0 (0x0)", - "row 0 top, col 0 lhs", /* ORIENTATION_TOPLEFT */ - "row 0 top, col 0 rhs", /* ORIENTATION_TOPRIGHT */ - "row 0 bottom, col 0 rhs", /* ORIENTATION_BOTRIGHT */ - "row 0 bottom, col 0 lhs", /* ORIENTATION_BOTLEFT */ - "row 0 lhs, col 0 top", /* ORIENTATION_LEFTTOP */ - "row 0 rhs, col 0 top", /* ORIENTATION_RIGHTTOP */ - "row 0 rhs, col 0 bottom", /* ORIENTATION_RIGHTBOT */ - "row 0 lhs, col 0 bottom", /* ORIENTATION_LEFTBOT */ + "row 0 top, col 0 lhs", /* ORIENTATION_TOPLEFT */ + "row 0 top, col 0 rhs", /* ORIENTATION_TOPRIGHT */ + "row 0 bottom, col 0 rhs", /* ORIENTATION_BOTRIGHT */ + "row 0 bottom, col 0 lhs", /* ORIENTATION_BOTLEFT */ + "row 0 lhs, col 0 top", /* ORIENTATION_LEFTTOP */ + "row 0 rhs, col 0 top", /* ORIENTATION_RIGHTTOP */ + "row 0 rhs, col 0 bottom", /* ORIENTATION_RIGHTBOT */ + "row 0 lhs, col 0 bottom", /* ORIENTATION_LEFTBOT */ }; -#define NORIENTNAMES (sizeof (orientNames) / sizeof (orientNames[0])) +#define NORIENTNAMES (sizeof(orientNames) / sizeof(orientNames[0])) -static void -_TIFFPrintField(FILE* fd, const TIFFFieldInfo *fip, - uint32 value_count, void *raw_data) +static const struct tagname { - uint32 j; - - fprintf(fd, " %s: ", fip->field_name); - - for(j = 0; j < value_count; j++) { - if(fip->field_type == TIFF_BYTE) - fprintf(fd, "%u", ((uint8 *) raw_data)[j]); - else if(fip->field_type == TIFF_UNDEFINED) - fprintf(fd, "0x%x", - (unsigned int) ((unsigned char *) raw_data)[j]); - else if(fip->field_type == TIFF_SBYTE) - fprintf(fd, "%d", ((int8 *) raw_data)[j]); - else if(fip->field_type == TIFF_SHORT) - fprintf(fd, "%u", ((uint16 *) raw_data)[j]); - else if(fip->field_type == TIFF_SSHORT) - fprintf(fd, "%d", ((int16 *) raw_data)[j]); - else if(fip->field_type == TIFF_LONG) - fprintf(fd, "%lu", - (unsigned long)((uint32 *) raw_data)[j]); - else if(fip->field_type == TIFF_SLONG) - fprintf(fd, "%ld", (long)((int32 *) raw_data)[j]); - else if(fip->field_type == TIFF_RATIONAL - || fip->field_type == TIFF_SRATIONAL - || fip->field_type == TIFF_FLOAT) - fprintf(fd, "%f", ((float *) raw_data)[j]); - else if(fip->field_type == TIFF_IFD) - fprintf(fd, "0x%ulx", ((uint32 *) raw_data)[j]); - else if(fip->field_type == TIFF_ASCII) { - fprintf(fd, "%s", (char *) raw_data); - break; - } - else if(fip->field_type == TIFF_DOUBLE) - fprintf(fd, "%f", ((double *) raw_data)[j]); - else if(fip->field_type == TIFF_FLOAT) - fprintf(fd, "%f", ((float *)raw_data)[j]); - else { - fprintf(fd, ""); - break; - } - - if(j < value_count - 1) - fprintf(fd, ","); - } - - fprintf(fd, "\n"); + uint16_t tag; + const char *name; +} tagnames[] = { + {TIFFTAG_GDAL_METADATA, "GDAL Metadata"}, + {TIFFTAG_GDAL_NODATA, "GDAL NoDataValue"}, +}; +#define NTAGS (sizeof(tagnames) / sizeof(tagnames[0])) + +static void _TIFFPrintField(FILE *fd, const TIFFField *fip, + uint32_t value_count, void *raw_data) +{ + uint32_t j; + + /* Print a user-friendly name for tags of relatively common use, but */ + /* which aren't registered by libtiff itself. */ + const char *field_name = fip->field_name; + if (TIFFFieldIsAnonymous(fip)) + { + for (size_t i = 0; i < NTAGS; ++i) + { + if (fip->field_tag == tagnames[i].tag) + { + field_name = tagnames[i].name; + break; + } + } + } + fprintf(fd, " %s: ", field_name); + + for (j = 0; j < value_count; j++) + { + if (fip->field_type == TIFF_BYTE) + fprintf(fd, "%" PRIu8, ((uint8_t *)raw_data)[j]); + else if (fip->field_type == TIFF_UNDEFINED) + fprintf(fd, "0x%" PRIx8, ((uint8_t *)raw_data)[j]); + else if (fip->field_type == TIFF_SBYTE) + fprintf(fd, "%" PRId8, ((int8_t *)raw_data)[j]); + else if (fip->field_type == TIFF_SHORT) + fprintf(fd, "%" PRIu16, ((uint16_t *)raw_data)[j]); + else if (fip->field_type == TIFF_SSHORT) + fprintf(fd, "%" PRId16, ((int16_t *)raw_data)[j]); + else if (fip->field_type == TIFF_LONG) + fprintf(fd, "%" PRIu32, ((uint32_t *)raw_data)[j]); + else if (fip->field_type == TIFF_SLONG) + fprintf(fd, "%" PRId32, ((int32_t *)raw_data)[j]); + else if (fip->field_type == TIFF_IFD) + fprintf(fd, "0x%" PRIx32, ((uint32_t *)raw_data)[j]); + else if (fip->field_type == TIFF_RATIONAL || + fip->field_type == TIFF_SRATIONAL) + { + int tv_size = TIFFFieldSetGetSize(fip); + if (tv_size == 8) + fprintf(fd, "%lf", ((double *)raw_data)[j]); + else + fprintf(fd, "%f", ((float *)raw_data)[j]); + } + else if (fip->field_type == TIFF_FLOAT) + fprintf(fd, "%f", ((float *)raw_data)[j]); + else if (fip->field_type == TIFF_LONG8) + fprintf(fd, "%" PRIu64, ((uint64_t *)raw_data)[j]); + else if (fip->field_type == TIFF_SLONG8) + fprintf(fd, "%" PRId64, ((int64_t *)raw_data)[j]); + else if (fip->field_type == TIFF_IFD8) + fprintf(fd, "0x%" PRIx64, ((uint64_t *)raw_data)[j]); + else if (fip->field_type == TIFF_DOUBLE) + fprintf(fd, "%lf", ((double *)raw_data)[j]); + else if (fip->field_type == TIFF_ASCII) + { + fprintf(fd, "%s", (char *)raw_data); + break; + } + else + { + fprintf(fd, ""); + break; + } + + if (j < value_count - 1) + fprintf(fd, ","); + } + + fprintf(fd, "\n"); } -static int -_TIFFPrettyPrintField(TIFF* tif, FILE* fd, ttag_t tag, - uint32 value_count, void *raw_data) +static int _TIFFPrettyPrintField(TIFF *tif, const TIFFField *fip, FILE *fd, + uint32_t tag, uint32_t value_count, + void *raw_data) { - //TIFFDirectory *td = &tif->tif_dir; - - switch (tag) - { - case TIFFTAG_INKSET: - fprintf(fd, " Ink Set: "); - switch (*((uint16*)raw_data)) { - case INKSET_CMYK: - fprintf(fd, "CMYK\n"); - break; - default: - fprintf(fd, "%u (0x%x)\n", - *((uint16*)raw_data), - *((uint16*)raw_data)); - break; - } - return 1; - case TIFFTAG_DOTRANGE: - fprintf(fd, " Dot Range: %u-%u\n", - ((uint16*)raw_data)[0], ((uint16*)raw_data)[1]); - return 1; - case TIFFTAG_WHITEPOINT: - fprintf(fd, " White Point: %g-%g\n", - ((float *)raw_data)[0], ((float *)raw_data)[1]); return 1; - case TIFFTAG_REFERENCEBLACKWHITE: - { - uint16 i; - - fprintf(fd, " Reference Black/White:\n"); - for (i = 0; i < 3; i++) - fprintf(fd, " %2d: %5g %5g\n", i, - ((float *)raw_data)[2*i+0], - ((float *)raw_data)[2*i+1]); - return 1; - } - case TIFFTAG_XMLPACKET: - { - uint32 i; - - fprintf(fd, " XMLPacket (XMP Metadata):\n" ); - for(i = 0; i < value_count; i++) - fputc(((char *)raw_data)[i], fd); - fprintf( fd, "\n" ); - return 1; - } - case TIFFTAG_RICHTIFFIPTC: - /* - * XXX: for some weird reason RichTIFFIPTC tag - * defined as array of LONG values. - */ - fprintf(fd, - " RichTIFFIPTC Data: , %lu bytes\n", - (unsigned long) value_count * 4); - return 1; - case TIFFTAG_PHOTOSHOP: - fprintf(fd, " Photoshop Data: , %lu bytes\n", - (unsigned long) value_count); - return 1; - case TIFFTAG_ICCPROFILE: - fprintf(fd, " ICC Profile: , %lu bytes\n", - (unsigned long) value_count); - return 1; - case TIFFTAG_STONITS: - fprintf(fd, - " Sample to Nits conversion factor: %.4e\n", - *((double*)raw_data)); - return 1; + (void)tif; + + /* do not try to pretty print auto-defined fields */ + if (TIFFFieldIsAnonymous(fip)) + { + return 0; + } + + switch (tag) + { + case TIFFTAG_INKSET: + if (value_count == 2 && fip->field_type == TIFF_SHORT) + { + fprintf(fd, " Ink Set: "); + switch (*((uint16_t *)raw_data)) + { + case INKSET_CMYK: + fprintf(fd, "CMYK\n"); + break; + default: + fprintf(fd, "%" PRIu16 " (0x%" PRIx16 ")\n", + *((uint16_t *)raw_data), + *((uint16_t *)raw_data)); + break; + } + return 1; + } + return 0; + + case TIFFTAG_DOTRANGE: + if (value_count == 2 && fip->field_type == TIFF_SHORT) + { + fprintf(fd, " Dot Range: %" PRIu16 "-%" PRIu16 "\n", + ((uint16_t *)raw_data)[0], ((uint16_t *)raw_data)[1]); + return 1; + } + return 0; + + case TIFFTAG_WHITEPOINT: + if (value_count == 2 && fip->field_type == TIFF_RATIONAL) + { + fprintf(fd, " White Point: %g-%g\n", ((float *)raw_data)[0], + ((float *)raw_data)[1]); + return 1; + } + return 0; + + case TIFFTAG_XMLPACKET: + { + uint32_t i; + + fprintf(fd, " XMLPacket (XMP Metadata):\n"); + for (i = 0; i < value_count; i++) + fputc(((char *)raw_data)[i], fd); + fprintf(fd, "\n"); + return 1; } + case TIFFTAG_RICHTIFFIPTC: + fprintf(fd, " RichTIFFIPTC Data: , %" PRIu32 " bytes\n", + value_count); + return 1; + + case TIFFTAG_PHOTOSHOP: + fprintf(fd, " Photoshop Data: , %" PRIu32 " bytes\n", + value_count); + return 1; + + case TIFFTAG_ICCPROFILE: + fprintf(fd, " ICC Profile: , %" PRIu32 " bytes\n", + value_count); + return 1; - return 0; + case TIFFTAG_STONITS: + if (value_count == 1 && fip->field_type == TIFF_DOUBLE) + { + fprintf(fd, " Sample to Nits conversion factor: %.4e\n", + *((double *)raw_data)); + return 1; + } + return 0; + } + + return 0; } /* * Print the contents of the current directory * to the specified stdio file stream. */ -void -TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) +void TIFFPrintDirectory(TIFF *tif, FILE *fd, long flags) { - TIFFDirectory *td = &tif->tif_dir; - char *sep; - uint16 i; - long l, n; - - fprintf(fd, "TIFF Directory at offset 0x%lx (%lu)\n", - (unsigned long)tif->tif_diroff, (unsigned long)tif->tif_diroff); - if (TIFFFieldSet(tif,FIELD_SUBFILETYPE)) { - fprintf(fd, " Subfile Type:"); - sep = " "; - if (td->td_subfiletype & FILETYPE_REDUCEDIMAGE) { - fprintf(fd, "%sreduced-resolution image", sep); - sep = "/"; - } - if (td->td_subfiletype & FILETYPE_PAGE) { - fprintf(fd, "%smulti-page document", sep); - sep = "/"; - } - if (td->td_subfiletype & FILETYPE_MASK) - fprintf(fd, "%stransparency mask", sep); - fprintf(fd, " (%lu = 0x%lx)\n", - (long) td->td_subfiletype, (long) td->td_subfiletype); - } - if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) { - fprintf(fd, " Image Width: %lu Image Length: %lu", - (unsigned long) td->td_imagewidth, (unsigned long) td->td_imagelength); - if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH)) - fprintf(fd, " Image Depth: %lu", - (unsigned long) td->td_imagedepth); - fprintf(fd, "\n"); - } - if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS)) { - fprintf(fd, " Tile Width: %lu Tile Length: %lu", - (unsigned long) td->td_tilewidth, (unsigned long) td->td_tilelength); - if (TIFFFieldSet(tif,FIELD_TILEDEPTH)) - fprintf(fd, " Tile Depth: %lu", - (unsigned long) td->td_tiledepth); - fprintf(fd, "\n"); - } - if (TIFFFieldSet(tif,FIELD_RESOLUTION)) { - fprintf(fd, " Resolution: %g, %g", - td->td_xresolution, td->td_yresolution); - if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT)) { - switch (td->td_resolutionunit) { - case RESUNIT_NONE: - fprintf(fd, " (unitless)"); - break; - case RESUNIT_INCH: - fprintf(fd, " pixels/inch"); - break; - case RESUNIT_CENTIMETER: - fprintf(fd, " pixels/cm"); - break; - default: - fprintf(fd, " (unit %u = 0x%x)", - td->td_resolutionunit, - td->td_resolutionunit); - break; - } - } - fprintf(fd, "\n"); - } - if (TIFFFieldSet(tif,FIELD_POSITION)) - fprintf(fd, " Position: %g, %g\n", - td->td_xposition, td->td_yposition); - if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) - fprintf(fd, " Bits/Sample: %u\n", td->td_bitspersample); - if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT)) { - fprintf(fd, " Sample Format: "); - switch (td->td_sampleformat) { - case SAMPLEFORMAT_VOID: - fprintf(fd, "void\n"); - break; - case SAMPLEFORMAT_INT: - fprintf(fd, "signed integer\n"); - break; - case SAMPLEFORMAT_UINT: - fprintf(fd, "unsigned integer\n"); - break; - case SAMPLEFORMAT_IEEEFP: - fprintf(fd, "IEEE floating point\n"); - break; - case SAMPLEFORMAT_COMPLEXINT: - fprintf(fd, "complex signed integer\n"); - break; - case SAMPLEFORMAT_COMPLEXIEEEFP: - fprintf(fd, "complex IEEE floating point\n"); - break; - default: - fprintf(fd, "%u (0x%x)\n", - td->td_sampleformat, td->td_sampleformat); - break; - } - } - if (TIFFFieldSet(tif,FIELD_COMPRESSION)) { - const TIFFCodec* c = TIFFFindCODEC(td->td_compression); - fprintf(fd, " Compression Scheme: "); - if (c) - fprintf(fd, "%s\n", c->name); - else - fprintf(fd, "%u (0x%x)\n", - td->td_compression, td->td_compression); - } - if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) { - fprintf(fd, " Photometric Interpretation: "); - if (td->td_photometric < NPHOTONAMES) - fprintf(fd, "%s\n", photoNames[td->td_photometric]); - else { - switch (td->td_photometric) { - case PHOTOMETRIC_LOGL: - fprintf(fd, "CIE Log2(L)\n"); - break; - case PHOTOMETRIC_LOGLUV: - fprintf(fd, "CIE Log2(L) (u',v')\n"); - break; - default: - fprintf(fd, "%u (0x%x)\n", - td->td_photometric, td->td_photometric); - break; - } - } - } - if (TIFFFieldSet(tif,FIELD_EXTRASAMPLES) && td->td_extrasamples) { - fprintf(fd, " Extra Samples: %u<", td->td_extrasamples); - sep = ""; - for (i = 0; i < td->td_extrasamples; i++) { - switch (td->td_sampleinfo[i]) { - case EXTRASAMPLE_UNSPECIFIED: - fprintf(fd, "%sunspecified", sep); - break; - case EXTRASAMPLE_ASSOCALPHA: - fprintf(fd, "%sassoc-alpha", sep); - break; - case EXTRASAMPLE_UNASSALPHA: - fprintf(fd, "%sunassoc-alpha", sep); - break; - default: - fprintf(fd, "%s%u (0x%x)", sep, - td->td_sampleinfo[i], td->td_sampleinfo[i]); - break; - } - sep = ", "; - } - fprintf(fd, ">\n"); - } - if (TIFFFieldSet(tif,FIELD_INKNAMES)) { - char* cp; - fprintf(fd, " Ink Names: "); - i = td->td_samplesperpixel; - sep = ""; - for (cp = td->td_inknames; i > 0; cp = strchr(cp,'\0')+1, i--) { - fputs(sep, fd); - _TIFFprintAscii(fd, cp); - sep = ", "; - } - fputs("\n", fd); - } - if (TIFFFieldSet(tif,FIELD_THRESHHOLDING)) { - fprintf(fd, " Thresholding: "); - switch (td->td_threshholding) { - case THRESHHOLD_BILEVEL: - fprintf(fd, "bilevel art scan\n"); - break; - case THRESHHOLD_HALFTONE: - fprintf(fd, "halftone or dithered scan\n"); - break; - case THRESHHOLD_ERRORDIFFUSE: - fprintf(fd, "error diffused\n"); - break; - default: - fprintf(fd, "%u (0x%x)\n", - td->td_threshholding, td->td_threshholding); - break; - } - } - if (TIFFFieldSet(tif,FIELD_FILLORDER)) { - fprintf(fd, " FillOrder: "); - switch (td->td_fillorder) { - case FILLORDER_MSB2LSB: - fprintf(fd, "msb-to-lsb\n"); - break; - case FILLORDER_LSB2MSB: - fprintf(fd, "lsb-to-msb\n"); - break; - default: - fprintf(fd, "%u (0x%x)\n", - td->td_fillorder, td->td_fillorder); - break; - } - } - if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING)) - { - /* - * For hacky reasons (see tif_jpeg.c - JPEGFixupTestSubsampling), - * we need to fetch this rather than trust what is in our - * structures. - */ - uint16 subsampling[2]; + TIFFDirectory *td = &tif->tif_dir; + char *sep; + long l, n; - TIFFGetField( tif, TIFFTAG_YCBCRSUBSAMPLING, - subsampling + 0, subsampling + 1 ); - fprintf(fd, " YCbCr Subsampling: %u, %u\n", - subsampling[0], subsampling[1] ); + fprintf(fd, "TIFF Directory at offset 0x%" PRIx64 " (%" PRIu64 ")\n", + tif->tif_diroff, tif->tif_diroff); + if (TIFFFieldSet(tif, FIELD_SUBFILETYPE)) + { + fprintf(fd, " Subfile Type:"); + sep = " "; + if (td->td_subfiletype & FILETYPE_REDUCEDIMAGE) + { + fprintf(fd, "%sreduced-resolution image", sep); + sep = "/"; + } + if (td->td_subfiletype & FILETYPE_PAGE) + { + fprintf(fd, "%smulti-page document", sep); + sep = "/"; + } + if (td->td_subfiletype & FILETYPE_MASK) + fprintf(fd, "%stransparency mask", sep); + fprintf(fd, " (%" PRIu32 " = 0x%" PRIx32 ")\n", td->td_subfiletype, + td->td_subfiletype); + } + if (TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) + { + fprintf(fd, " Image Width: %" PRIu32 " Image Length: %" PRIu32, + td->td_imagewidth, td->td_imagelength); + if (TIFFFieldSet(tif, FIELD_IMAGEDEPTH)) + fprintf(fd, " Image Depth: %" PRIu32, td->td_imagedepth); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) + { + fprintf(fd, " Tile Width: %" PRIu32 " Tile Length: %" PRIu32, + td->td_tilewidth, td->td_tilelength); + if (TIFFFieldSet(tif, FIELD_TILEDEPTH)) + fprintf(fd, " Tile Depth: %" PRIu32, td->td_tiledepth); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif, FIELD_RESOLUTION)) + { + fprintf(fd, " Resolution: %g, %g", td->td_xresolution, + td->td_yresolution); + if (TIFFFieldSet(tif, FIELD_RESOLUTIONUNIT)) + { + switch (td->td_resolutionunit) + { + case RESUNIT_NONE: + fprintf(fd, " (unitless)"); + break; + case RESUNIT_INCH: + fprintf(fd, " pixels/inch"); + break; + case RESUNIT_CENTIMETER: + fprintf(fd, " pixels/cm"); + break; + default: + fprintf(fd, " (unit %" PRIu16 " = 0x%" PRIx16 ")", + td->td_resolutionunit, td->td_resolutionunit); + break; + } + } + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif, FIELD_POSITION)) + fprintf(fd, " Position: %g, %g\n", td->td_xposition, td->td_yposition); + if (TIFFFieldSet(tif, FIELD_BITSPERSAMPLE)) + fprintf(fd, " Bits/Sample: %" PRIu16 "\n", td->td_bitspersample); + if (TIFFFieldSet(tif, FIELD_SAMPLEFORMAT)) + { + fprintf(fd, " Sample Format: "); + switch (td->td_sampleformat) + { + case SAMPLEFORMAT_VOID: + fprintf(fd, "void\n"); + break; + case SAMPLEFORMAT_INT: + fprintf(fd, "signed integer\n"); + break; + case SAMPLEFORMAT_UINT: + fprintf(fd, "unsigned integer\n"); + break; + case SAMPLEFORMAT_IEEEFP: + fprintf(fd, "IEEE floating point\n"); + break; + case SAMPLEFORMAT_COMPLEXINT: + fprintf(fd, "complex signed integer\n"); + break; + case SAMPLEFORMAT_COMPLEXIEEEFP: + fprintf(fd, "complex IEEE floating point\n"); + break; + default: + fprintf(fd, "%" PRIu16 " (0x%" PRIx16 ")\n", + td->td_sampleformat, td->td_sampleformat); + break; + } + } + if (TIFFFieldSet(tif, FIELD_COMPRESSION)) + { + const TIFFCodec *c = TIFFFindCODEC(td->td_compression); + fprintf(fd, " Compression Scheme: "); + if (c) + fprintf(fd, "%s\n", c->name); + else + fprintf(fd, "%" PRIu16 " (0x%" PRIx16 ")\n", td->td_compression, + td->td_compression); + } + if (TIFFFieldSet(tif, FIELD_PHOTOMETRIC)) + { + fprintf(fd, " Photometric Interpretation: "); + if (td->td_photometric < NPHOTONAMES) + fprintf(fd, "%s\n", photoNames[td->td_photometric]); + else + { + switch (td->td_photometric) + { + case PHOTOMETRIC_LOGL: + fprintf(fd, "CIE Log2(L)\n"); + break; + case PHOTOMETRIC_LOGLUV: + fprintf(fd, "CIE Log2(L) (u',v')\n"); + break; + default: + fprintf(fd, "%" PRIu16 " (0x%" PRIx16 ")\n", + td->td_photometric, td->td_photometric); + break; + } + } + } + if (TIFFFieldSet(tif, FIELD_EXTRASAMPLES) && td->td_extrasamples) + { + uint16_t i; + fprintf(fd, " Extra Samples: %" PRIu16 "<", td->td_extrasamples); + sep = ""; + for (i = 0; i < td->td_extrasamples; i++) + { + switch (td->td_sampleinfo[i]) + { + case EXTRASAMPLE_UNSPECIFIED: + fprintf(fd, "%sunspecified", sep); + break; + case EXTRASAMPLE_ASSOCALPHA: + fprintf(fd, "%sassoc-alpha", sep); + break; + case EXTRASAMPLE_UNASSALPHA: + fprintf(fd, "%sunassoc-alpha", sep); + break; + default: + fprintf(fd, "%s%" PRIu16 " (0x%" PRIx16 ")", sep, + td->td_sampleinfo[i], td->td_sampleinfo[i]); + break; + } + sep = ", "; + } + fprintf(fd, ">\n"); + } + if (TIFFFieldSet(tif, FIELD_INKNAMES)) + { + char *cp; + uint16_t i; + fprintf(fd, " Ink Names: "); + i = td->td_samplesperpixel; + sep = ""; + for (cp = td->td_inknames; + i > 0 && cp < td->td_inknames + td->td_inknameslen; + cp = strchr(cp, '\0') + 1, i--) + { + size_t max_chars = td->td_inknameslen - (cp - td->td_inknames); + fputs(sep, fd); + _TIFFprintAsciiBounded(fd, cp, max_chars); + sep = ", "; } - if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING)) { - fprintf(fd, " YCbCr Positioning: "); - switch (td->td_ycbcrpositioning) { - case YCBCRPOSITION_CENTERED: - fprintf(fd, "centered\n"); - break; - case YCBCRPOSITION_COSITED: - fprintf(fd, "cosited\n"); - break; - default: - fprintf(fd, "%u (0x%x)\n", - td->td_ycbcrpositioning, td->td_ycbcrpositioning); - break; - } - } - if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS)) - fprintf(fd, " Halftone Hints: light %u dark %u\n", - td->td_halftonehints[0], td->td_halftonehints[1]); - if (TIFFFieldSet(tif,FIELD_ORIENTATION)) { - fprintf(fd, " Orientation: "); - if (td->td_orientation < NORIENTNAMES) - fprintf(fd, "%s\n", orientNames[td->td_orientation]); - else - fprintf(fd, "%u (0x%x)\n", - td->td_orientation, td->td_orientation); - } - if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) - fprintf(fd, " Samples/Pixel: %u\n", td->td_samplesperpixel); - if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP)) { - fprintf(fd, " Rows/Strip: "); - if (td->td_rowsperstrip == (uint32) -1) - fprintf(fd, "(infinite)\n"); - else - fprintf(fd, "%lu\n", (unsigned long) td->td_rowsperstrip); - } - if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE)) - fprintf(fd, " Min Sample Value: %u\n", td->td_minsamplevalue); - if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE)) - fprintf(fd, " Max Sample Value: %u\n", td->td_maxsamplevalue); - if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE)) - fprintf(fd, " SMin Sample Value: %g\n", - td->td_sminsamplevalue); - if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE)) - fprintf(fd, " SMax Sample Value: %g\n", - td->td_smaxsamplevalue); - if (TIFFFieldSet(tif,FIELD_PLANARCONFIG)) { - fprintf(fd, " Planar Configuration: "); - switch (td->td_planarconfig) { - case PLANARCONFIG_CONTIG: - fprintf(fd, "single image plane\n"); - break; - case PLANARCONFIG_SEPARATE: - fprintf(fd, "separate image planes\n"); - break; - default: - fprintf(fd, "%u (0x%x)\n", - td->td_planarconfig, td->td_planarconfig); - break; - } - } - if (TIFFFieldSet(tif,FIELD_PAGENUMBER)) - fprintf(fd, " Page Number: %u-%u\n", - td->td_pagenumber[0], td->td_pagenumber[1]); - if (TIFFFieldSet(tif,FIELD_COLORMAP)) { - fprintf(fd, " Color Map: "); - if (flags & TIFFPRINT_COLORMAP) { - fprintf(fd, "\n"); - n = 1L<td_bitspersample; - for (l = 0; l < n; l++) - fprintf(fd, " %5lu: %5u %5u %5u\n", - l, - td->td_colormap[0][l], - td->td_colormap[1][l], - td->td_colormap[2][l]); - } else - fprintf(fd, "(present)\n"); - } - if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION)) { - fprintf(fd, " Transfer Function: "); - if (flags & TIFFPRINT_CURVES) { - fprintf(fd, "\n"); - n = 1L<td_bitspersample; - for (l = 0; l < n; l++) { - fprintf(fd, " %2lu: %5u", - l, td->td_transferfunction[0][l]); - for (i = 1; i < td->td_samplesperpixel; i++) - fprintf(fd, " %5u", - td->td_transferfunction[i][l]); - fputc('\n', fd); - } - } else - fprintf(fd, "(present)\n"); - } - if (TIFFFieldSet(tif, FIELD_SUBIFD) && (td->td_subifd)) { - fprintf(fd, " SubIFD Offsets:"); - for (i = 0; i < td->td_nsubifd; i++) - fprintf(fd, " %5lu", (long) td->td_subifd[i]); - fputc('\n', fd); - } - - /* - ** Custom tag support. - */ + fputs("\n", fd); + } + if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS)) + { + fprintf(fd, " NumberOfInks: %d\n", td->td_numberofinks); + } + if (TIFFFieldSet(tif, FIELD_THRESHHOLDING)) + { + fprintf(fd, " Thresholding: "); + switch (td->td_threshholding) { - int i; - short count; - - count = (short) TIFFGetTagListCount(tif); - for(i = 0; i < count; i++) { - ttag_t tag = TIFFGetTagListEntry(tif, i); - const TIFFFieldInfo *fip; - uint32 value_count; - int mem_alloc = 0; - void *raw_data; - - fip = TIFFFieldWithTag(tif, tag); - if(fip == NULL) - continue; - - if(fip->field_passcount) { - if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1) - continue; - } else { - if (fip->field_readcount == TIFF_VARIABLE - || fip->field_readcount == TIFF_VARIABLE2) - value_count = 1; - else if (fip->field_readcount == TIFF_SPP) - value_count = td->td_samplesperpixel; - else - value_count = fip->field_readcount; - if ((fip->field_type == TIFF_ASCII - || fip->field_readcount == TIFF_VARIABLE - || fip->field_readcount == TIFF_VARIABLE2 - || fip->field_readcount == TIFF_SPP - || value_count > 1) - && fip->field_tag != TIFFTAG_PAGENUMBER - && fip->field_tag != TIFFTAG_HALFTONEHINTS - && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING - && fip->field_tag != TIFFTAG_DOTRANGE) { - if(TIFFGetField(tif, tag, &raw_data) != 1) - continue; - } else if (fip->field_tag != TIFFTAG_PAGENUMBER - && fip->field_tag != TIFFTAG_HALFTONEHINTS - && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING - && fip->field_tag != TIFFTAG_DOTRANGE) { - raw_data = _TIFFmalloc( - _TIFFDataSize(fip->field_type) - * value_count); - mem_alloc = 1; - if(TIFFGetField(tif, tag, raw_data) != 1) { - _TIFFfree(raw_data); - continue; - } - } else { - /* - * XXX: Should be fixed and removed, see the - * notes related to TIFFTAG_PAGENUMBER, - * TIFFTAG_HALFTONEHINTS, - * TIFFTAG_YCBCRSUBSAMPLING and - * TIFFTAG_DOTRANGE tags in tif_dir.c. */ - char *tmp; - raw_data = _TIFFmalloc( - _TIFFDataSize(fip->field_type) - * value_count); - tmp = (char*)raw_data; - mem_alloc = 1; - if(TIFFGetField(tif, tag, tmp, - tmp + _TIFFDataSize(fip->field_type)) != 1) { - _TIFFfree(raw_data); - continue; - } - } - } - - /* - * Catch the tags which needs to be specially handled and - * pretty print them. If tag not handled in - * _TIFFPrettyPrintField() fall down and print it as any other - * tag. - */ - if (_TIFFPrettyPrintField(tif, fd, tag, value_count, raw_data)) { - if(mem_alloc) - _TIFFfree(raw_data); - continue; - } - else - _TIFFPrintField(fd, fip, value_count, raw_data); - - if(mem_alloc) - _TIFFfree(raw_data); + case THRESHHOLD_BILEVEL: + fprintf(fd, "bilevel art scan\n"); + break; + case THRESHHOLD_HALFTONE: + fprintf(fd, "halftone or dithered scan\n"); + break; + case THRESHHOLD_ERRORDIFFUSE: + fprintf(fd, "error diffused\n"); + break; + default: + fprintf(fd, "%" PRIu16 " (0x%" PRIx16 ")\n", + td->td_threshholding, td->td_threshholding); + break; + } + } + if (TIFFFieldSet(tif, FIELD_FILLORDER)) + { + fprintf(fd, " FillOrder: "); + switch (td->td_fillorder) + { + case FILLORDER_MSB2LSB: + fprintf(fd, "msb-to-lsb\n"); + break; + case FILLORDER_LSB2MSB: + fprintf(fd, "lsb-to-msb\n"); + break; + default: + fprintf(fd, "%" PRIu16 " (0x%" PRIx16 ")\n", td->td_fillorder, + td->td_fillorder); + break; + } + } + if (TIFFFieldSet(tif, FIELD_YCBCRSUBSAMPLING)) + { + fprintf(fd, " YCbCr Subsampling: %" PRIu16 ", %" PRIu16 "\n", + td->td_ycbcrsubsampling[0], td->td_ycbcrsubsampling[1]); + } + if (TIFFFieldSet(tif, FIELD_YCBCRPOSITIONING)) + { + fprintf(fd, " YCbCr Positioning: "); + switch (td->td_ycbcrpositioning) + { + case YCBCRPOSITION_CENTERED: + fprintf(fd, "centered\n"); + break; + case YCBCRPOSITION_COSITED: + fprintf(fd, "cosited\n"); + break; + default: + fprintf(fd, "%" PRIu16 " (0x%" PRIx16 ")\n", + td->td_ycbcrpositioning, td->td_ycbcrpositioning); + break; + } + } + if (TIFFFieldSet(tif, FIELD_HALFTONEHINTS)) + fprintf(fd, " Halftone Hints: light %" PRIu16 " dark %" PRIu16 "\n", + td->td_halftonehints[0], td->td_halftonehints[1]); + if (TIFFFieldSet(tif, FIELD_ORIENTATION)) + { + fprintf(fd, " Orientation: "); + if (td->td_orientation < NORIENTNAMES) + fprintf(fd, "%s\n", orientNames[td->td_orientation]); + else + fprintf(fd, "%" PRIu16 " (0x%" PRIx16 ")\n", td->td_orientation, + td->td_orientation); + } + if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL)) + fprintf(fd, " Samples/Pixel: %" PRIx16 "\n", td->td_samplesperpixel); + if (TIFFFieldSet(tif, FIELD_ROWSPERSTRIP)) + { + fprintf(fd, " Rows/Strip: "); + if (td->td_rowsperstrip == (uint32_t)-1) + fprintf(fd, "(infinite)\n"); + else + fprintf(fd, "%" PRIu32 "\n", td->td_rowsperstrip); + } + if (TIFFFieldSet(tif, FIELD_MINSAMPLEVALUE)) + fprintf(fd, " Min Sample Value: %" PRIu16 "\n", td->td_minsamplevalue); + if (TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE)) + fprintf(fd, " Max Sample Value: %" PRIu16 "\n", td->td_maxsamplevalue); + if (TIFFFieldSet(tif, FIELD_SMINSAMPLEVALUE)) + { + int i; + int count = + (tif->tif_flags & TIFF_PERSAMPLE) ? td->td_samplesperpixel : 1; + fprintf(fd, " SMin Sample Value:"); + for (i = 0; i < count; ++i) + fprintf(fd, " %g", td->td_sminsamplevalue[i]); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif, FIELD_SMAXSAMPLEVALUE)) + { + int i; + int count = + (tif->tif_flags & TIFF_PERSAMPLE) ? td->td_samplesperpixel : 1; + fprintf(fd, " SMax Sample Value:"); + for (i = 0; i < count; ++i) + fprintf(fd, " %g", td->td_smaxsamplevalue[i]); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif, FIELD_PLANARCONFIG)) + { + fprintf(fd, " Planar Configuration: "); + switch (td->td_planarconfig) + { + case PLANARCONFIG_CONTIG: + fprintf(fd, "single image plane\n"); + break; + case PLANARCONFIG_SEPARATE: + fprintf(fd, "separate image planes\n"); + break; + default: + fprintf(fd, "%" PRIu16 " (0x%" PRIx16 ")\n", + td->td_planarconfig, td->td_planarconfig); + break; + } + } + if (TIFFFieldSet(tif, FIELD_PAGENUMBER)) + fprintf(fd, " Page Number: %" PRIu16 "-%" PRIu16 "\n", + td->td_pagenumber[0], td->td_pagenumber[1]); + if (TIFFFieldSet(tif, FIELD_COLORMAP)) + { + fprintf(fd, " Color Map: "); + if (flags & TIFFPRINT_COLORMAP) + { + fprintf(fd, "\n"); + n = 1L << td->td_bitspersample; + for (l = 0; l < n; l++) + fprintf(fd, " %5ld: %5" PRIu16 " %5" PRIu16 " %5" PRIu16 "\n", + l, td->td_colormap[0][l], td->td_colormap[1][l], + td->td_colormap[2][l]); + } + else + fprintf(fd, "(present)\n"); + } + if (TIFFFieldSet(tif, FIELD_REFBLACKWHITE)) + { + int i; + fprintf(fd, " Reference Black/White:\n"); + for (i = 0; i < 3; i++) + fprintf(fd, " %2d: %5g %5g\n", i, + td->td_refblackwhite[2 * i + 0], + td->td_refblackwhite[2 * i + 1]); + } + if (TIFFFieldSet(tif, FIELD_TRANSFERFUNCTION)) + { + fprintf(fd, " Transfer Function: "); + if (flags & TIFFPRINT_CURVES) + { + fprintf(fd, "\n"); + n = 1L << td->td_bitspersample; + for (l = 0; l < n; l++) + { + uint16_t i; + fprintf(fd, " %2ld: %5" PRIu16, l, + td->td_transferfunction[0][l]); + for (i = 1; + i < td->td_samplesperpixel - td->td_extrasamples && i < 3; + i++) + fprintf(fd, " %5" PRIu16, td->td_transferfunction[i][l]); + fputc('\n', fd); } } - - if (tif->tif_tagmethods.printdir) - (*tif->tif_tagmethods.printdir)(tif, fd, flags); - if ((flags & TIFFPRINT_STRIPS) && - TIFFFieldSet(tif,FIELD_STRIPOFFSETS)) { - tstrip_t s; - - fprintf(fd, " %lu %s:\n", - (long) td->td_nstrips, - isTiled(tif) ? "Tiles" : "Strips"); - for (s = 0; s < td->td_nstrips; s++) - fprintf(fd, " %3lu: [%8lu, %8lu]\n", - (unsigned long) s, - (unsigned long) td->td_stripoffset[s], - (unsigned long) td->td_stripbytecount[s]); - } + else + fprintf(fd, "(present)\n"); + } + if (TIFFFieldSet(tif, FIELD_SUBIFD) && (td->td_subifd)) + { + uint16_t i; + fprintf(fd, " SubIFD Offsets:"); + for (i = 0; i < td->td_nsubifd; i++) + fprintf(fd, " %5" PRIu64, td->td_subifd[i]); + fputc('\n', fd); + } + + /* + ** Custom tag support. + */ + { + int i; + short count; + + count = (short)TIFFGetTagListCount(tif); + for (i = 0; i < count; i++) + { + uint32_t tag = TIFFGetTagListEntry(tif, i); + const TIFFField *fip; + uint32_t value_count; + int mem_alloc = 0; + void *raw_data = NULL; + uint16_t dotrange[2]; /* must be kept in that scope and not moved in + the below TIFFTAG_DOTRANGE specific case */ + + fip = TIFFFieldWithTag(tif, tag); + if (fip == NULL) + continue; + + if (fip->field_passcount) + { + if (fip->field_readcount == TIFF_VARIABLE2) + { + if (TIFFGetField(tif, tag, &value_count, &raw_data) != 1) + continue; + } + else if (fip->field_readcount == TIFF_VARIABLE) + { + uint16_t small_value_count; + if (TIFFGetField(tif, tag, &small_value_count, &raw_data) != + 1) + continue; + value_count = small_value_count; + } + else + { + assert(fip->field_readcount == TIFF_VARIABLE || + fip->field_readcount == TIFF_VARIABLE2); + continue; + } + } + else + { + if (fip->field_readcount == TIFF_VARIABLE || + fip->field_readcount == TIFF_VARIABLE2) + value_count = 1; + else if (fip->field_readcount == TIFF_SPP) + value_count = td->td_samplesperpixel; + else + value_count = fip->field_readcount; + 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 */ + raw_data = dotrange; + TIFFGetField(tif, tag, dotrange + 0, dotrange + 1); + } + else if (fip->field_type == TIFF_ASCII || + fip->field_readcount == TIFF_VARIABLE || + fip->field_readcount == TIFF_VARIABLE2 || + fip->field_readcount == TIFF_SPP || value_count > 1) + { + if (TIFFGetField(tif, tag, &raw_data) != 1) + continue; + } + else + { + /*--: Rational2Double: For Rationals evaluate + * "set_field_type" to determine internal storage size. */ + int tv_size = TIFFFieldSetGetSize(fip); + raw_data = _TIFFmallocExt(tif, tv_size * value_count); + mem_alloc = 1; + if (TIFFGetField(tif, tag, raw_data) != 1) + { + _TIFFfreeExt(tif, raw_data); + continue; + } + } + } + + /* + * Catch the tags which needs to be specially handled + * and pretty print them. If tag not handled in + * _TIFFPrettyPrintField() fall down and print it as + * any other tag. + */ + if (raw_data != NULL && + !_TIFFPrettyPrintField(tif, fip, fd, tag, value_count, + raw_data)) + _TIFFPrintField(fd, fip, value_count, raw_data); + + if (mem_alloc) + _TIFFfreeExt(tif, raw_data); + } + } + + if (tif->tif_tagmethods.printdir) + (*tif->tif_tagmethods.printdir)(tif, fd, flags); + + if ((flags & TIFFPRINT_STRIPS) && TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) + { + uint32_t s; + + fprintf(fd, " %" PRIu32 " %s:\n", td->td_nstrips, + isTiled(tif) ? "Tiles" : "Strips"); + for (s = 0; s < td->td_nstrips; s++) + fprintf(fd, " %3" PRIu32 ": [%8" PRIu64 ", %8" PRIu64 "]\n", s, + TIFFGetStrileOffset(tif, s), + TIFFGetStrileByteCount(tif, s)); + } } -void -_TIFFprintAscii(FILE* fd, const char* cp) +void _TIFFprintAscii(FILE *fd, const char *cp) { - for (; *cp != '\0'; cp++) { - const char* tp; - - if (isprint((int)*cp)) { - fputc(*cp, fd); - continue; - } - for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++) - if (*tp++ == *cp) - break; - if (*tp) - fprintf(fd, "\\%c", *tp); - else - fprintf(fd, "\\%03o", *cp & 0xff); - } + _TIFFprintAsciiBounded(fd, cp, strlen(cp)); } -void -_TIFFprintAsciiTag(FILE* fd, const char* name, const char* value) +static void _TIFFprintAsciiBounded(FILE *fd, const char *cp, size_t max_chars) { - fprintf(fd, " %s: \"", name); - _TIFFprintAscii(fd, value); - fprintf(fd, "\"\n"); + for (; max_chars > 0 && *cp != '\0'; cp++, max_chars--) + { + const char *tp; + + if (isprint((int)*cp)) + { + fputc(*cp, fd); + continue; + } + for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++) + if (*tp++ == *cp) + break; + if (*tp) + fprintf(fd, "\\%c", *tp); + else + fprintf(fd, "\\%03o", *cp & 0xff); + } } -/* vim: set ts=8 sts=8 sw=8 noet: */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ +void _TIFFprintAsciiTag(FILE *fd, const char *name, const char *value) +{ + fprintf(fd, " %s: \"", name); + _TIFFprintAscii(fd, value); + fprintf(fd, "\"\n"); +} diff --git a/LibTiff/tif_read.c b/LibTiff/tif_read.c index 8ac0ae66..4fec8396 100644 --- a/LibTiff/tif_read.c +++ b/LibTiff/tif_read.c @@ -1,26 +1,24 @@ -/* $Id: tif_read.c,v 1.16.2.3 2010-06-09 14:32:47 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,330 +29,879 @@ #include "tiffiop.h" #include - int TIFFFillStrip(TIFF*, tstrip_t); - int TIFFFillTile(TIFF*, ttile_t); -static int TIFFStartStrip(TIFF*, tstrip_t); -static int TIFFStartTile(TIFF*, ttile_t); -static int TIFFCheckRead(TIFF*, int); +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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, "Invalid buffer size"); + return 0; + } + new_rawdata = + (uint8_t *)_TIFFrealloc(tif->tif_rawdata, tif->tif_rawdatasize); + if (new_rawdata == 0) + { + TIFFErrorExtR(tif, module, + "No space for data buffer at scanline %" PRIu32, + tif->tif_row); + _TIFFfreeExt(tif, 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) + { + TIFFErrorExtR(tif, module, + "Read error at scanline %" PRIu32 + "; got %" TIFF_SSIZE_FORMAT " bytes, " + "expected %" TIFF_SSIZE_FORMAT, + tif->tif_row, already_read, size); + } + else + { + TIFFErrorExtR(tif, 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); -#define NOSTRIP ((tstrip_t) -1) /* undefined state */ -#define NOTILE ((ttile_t) -1) /* undefined state */ + tif->tif_curstrip = NOSTRIP; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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 row, tsample_t sample) +static int TIFFSeek(TIFF *tif, uint32_t row, uint16_t sample) { - register TIFFDirectory *td = &tif->tif_dir; - tstrip_t strip; - - if (row >= td->td_imagelength) { /* out of range */ - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%lu: Row out of range, max %lu", - (unsigned long) row, - (unsigned long) td->td_imagelength); - return (0); - } - if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { - if (sample >= td->td_samplesperpixel) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%lu: Sample out of range, max %lu", - (unsigned long) sample, (unsigned long) td->td_samplesperpixel); - return (0); - } - strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip; - } else - strip = row / td->td_rowsperstrip; - if (strip != tif->tif_curstrip) { /* different strip, refill */ - if (!TIFFFillStrip(tif, strip)) - return (0); - } else 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 (!TIFFStartStrip(tif, strip)) - return (0); - } - if (row != tif->tif_row) { - /* - * Seek forward to the desired row. - */ - if (!(*tif->tif_seek)(tif, row - tif->tif_row)) - return (0); - tif->tif_row = row; - } - return (1); + 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 */ + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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, tdata_t buf, uint32 row, tsample_t sample) +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, (tidata_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, (tidata_t) buf, - tif->tif_scanlinesize); - } - return (e > 0 ? 1 : -1); + 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) + { + TIFFErrorExtR(tif, 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. */ -tsize_t -TIFFReadEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t buf, tsize_t size) +tmsize_t TIFFReadEncodedStrip(TIFF *tif, uint32_t strip, void *buf, + tmsize_t size) { - TIFFDirectory *td = &tif->tif_dir; - uint32 nrows; - tsize_t stripsize; - tstrip_t sep_strip, strips_per_sep; - - if (!TIFFCheckRead(tif, 0)) - return (-1); - if (strip >= td->td_nstrips) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%ld: Strip out of range, max %ld", - (long) strip, (long) td->td_nstrips); - return (-1); - } - /* - * Calculate the strip size according to the number of - * rows in the strip (check for truncated last strip on any - * of the separations). - */ - if( td->td_rowsperstrip >= td->td_imagelength ) - strips_per_sep = 1; - else - strips_per_sep = (td->td_imagelength+td->td_rowsperstrip-1) - / td->td_rowsperstrip; - - sep_strip = strip % strips_per_sep; - - if (sep_strip != strips_per_sep-1 || - (nrows = td->td_imagelength % td->td_rowsperstrip) == 0) - nrows = td->td_rowsperstrip; - - stripsize = TIFFVStripSize(tif, nrows); - if (size == (tsize_t) -1) - size = stripsize; - else if (size > stripsize) - size = stripsize; - if (TIFFFillStrip(tif, strip) - && (*tif->tif_decodestrip)(tif, (tidata_t) buf, size, - (tsample_t)(strip / td->td_stripsperimage)) > 0 ) { - (*tif->tif_postdecode)(tif, (tidata_t) buf, size); - return (size); - } else - return ((tsize_t) -1); + 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)) && (size < stripsize)) + stripsize = size; + if (!TIFFFillStrip(tif, strip)) + return ((tmsize_t)(-1)); + if ((*tif->tif_decodestrip)(tif, buf, stripsize, plane) <= 0) + return ((tmsize_t)(-1)); + (*tif->tif_postdecode)(tif, buf, stripsize); + return (stripsize); } -static tsize_t -TIFFReadRawStrip1(TIFF* tif, - tstrip_t strip, tdata_t buf, tsize_t size, const char* module) +/* Variant of TIFFReadEncodedStrip() that does + * * if *buf == NULL, *buf = _TIFFmallocExt(tif, 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) { - TIFFDirectory *td = &tif->tif_dir; - - assert((tif->tif_flags&TIFF_NOREADRAW)==0); - if (!isMapped(tif)) { - tsize_t cc; - - if (!SeekOK(tif, td->td_stripoffset[strip])) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Seek error at scanline %lu, strip %lu", - tif->tif_name, - (unsigned long) tif->tif_row, (unsigned long) strip); - return (-1); - } - cc = TIFFReadFile(tif, buf, size); - if (cc != size) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Read error at scanline %lu; got %lu bytes, expected %lu", - tif->tif_name, - (unsigned long) tif->tif_row, - (unsigned long) cc, - (unsigned long) size); - return (-1); - } - } else { - if (td->td_stripoffset[strip] + size > tif->tif_size) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Read error at scanline %lu, strip %lu; got %lu bytes, expected %lu", - tif->tif_name, - (unsigned long) tif->tif_row, - (unsigned long) strip, - (unsigned long) tif->tif_size - td->td_stripoffset[strip], - (unsigned long) size); - return (-1); - } - _TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[strip], - size); - } - return (size); + 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_read < this_stripsize)) + this_stripsize = size_to_read; + if (!TIFFFillStrip(tif, strip)) + return ((tmsize_t)(-1)); + + *buf = _TIFFmallocExt(tif, bufsizetoalloc); + if (*buf == NULL) + { + TIFFErrorExtR(tif, 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))) + { + TIFFErrorExtR(tif, module, + "Seek error at scanline %" PRIu32 ", strip %" PRIu32, + tif->tif_row, strip); + return ((tmsize_t)(-1)); + } + cc = TIFFReadFile(tif, buf, size); + if (cc != size) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, + "Seek error at scanline %" PRIu32 ", strip %" PRIu32, + tif->tif_row, strip_or_tile); + } + else + { + TIFFErrorExtR(tif, 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. */ -tsize_t -TIFFReadRawStrip(TIFF* tif, tstrip_t strip, tdata_t buf, tsize_t size) +tmsize_t TIFFReadRawStrip(TIFF *tif, uint32_t strip, void *buf, tmsize_t size) { - static const char module[] = "TIFFReadRawStrip"; - TIFFDirectory *td = &tif->tif_dir; - /* - * FIXME: butecount should have tsize_t type, but for now libtiff - * defines tsize_t as a signed 32-bit integer and we are losing - * ability to read arrays larger than 2^31 bytes. So we are using - * uint32 instead of tsize_t here. - */ - uint32 bytecount; - - if (!TIFFCheckRead(tif, 0)) - return ((tsize_t) -1); - if (strip >= td->td_nstrips) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%lu: Strip out of range, max %lu", - (unsigned long) strip, - (unsigned long) td->td_nstrips); - return ((tsize_t) -1); - } - if (tif->tif_flags&TIFF_NOREADRAW) - { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Compression scheme does not support access to raw uncompressed data"); - return ((tsize_t) -1); - } - bytecount = td->td_stripbytecount[strip]; - if (bytecount <= 0) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%lu: Invalid strip byte count, strip %lu", - (unsigned long) bytecount, (unsigned long) strip); - return ((tsize_t) -1); - } - if (size != (tsize_t)-1 && (uint32)size < bytecount) - bytecount = size; - return (TIFFReadRawStrip1(tif, strip, buf, bytecount, module)); + 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) + { + TIFFErrorExtR(tif, module, + "%" PRIu32 ": Strip out of range, max %" PRIu32, strip, + td->td_nstrips); + return ((tmsize_t)(-1)); + } + if (tif->tif_flags & TIFF_NOREADRAW) + { + TIFFErrorExtR(tif, 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, tstrip_t strip) +int TIFFFillStrip(TIFF *tif, uint32_t strip) { - static const char module[] = "TIFFFillStrip"; - TIFFDirectory *td = &tif->tif_dir; - - if ((tif->tif_flags&TIFF_NOREADRAW)==0) - { - /* - * FIXME: butecount should have tsize_t type, but for now - * libtiff defines tsize_t as a signed 32-bit integer and we - * are losing ability to read arrays larger than 2^31 bytes. - * So we are using uint32 instead of tsize_t here. - */ - uint32 bytecount = td->td_stripbytecount[strip]; - if (bytecount <= 0) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Invalid strip byte count %lu, strip %lu", - tif->tif_name, (unsigned long) bytecount, - (unsigned long) strip); - 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_flags &= ~TIFF_MYBUFFER; - /* - * We must check for overflow, potentially causing - * an OOB read. Instead of simple - * - * td->td_stripoffset[strip]+bytecount > tif->tif_size - * - * comparison (which can overflow) we do the following - * two comparisons: - */ - if (bytecount > tif->tif_size || - td->td_stripoffset[strip] > 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, - - "%s: Read error on strip %lu; " - "got %lu bytes, expected %lu", - tif->tif_name, (unsigned long) strip, - (unsigned long) tif->tif_size - td->td_stripoffset[strip], - (unsigned long) bytecount); - tif->tif_curstrip = NOSTRIP; - return (0); - } - tif->tif_rawdatasize = bytecount; - tif->tif_rawdata = tif->tif_base + td->td_stripoffset[strip]; - } 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?). - */ - if (bytecount > (uint32)tif->tif_rawdatasize) { - tif->tif_curstrip = NOSTRIP; - if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { - TIFFErrorExt(tif->tif_clientdata, - module, - "%s: Data buffer too small to hold strip %lu", - tif->tif_name, - (unsigned long) strip); - return (0); - } - if (!TIFFReadBufferSetup(tif, 0, - TIFFroundup(bytecount, 1024))) - return (0); - } - if ((uint32)TIFFReadRawStrip1(tif, strip, - (unsigned char *)tif->tif_rawdata, - bytecount, module) != bytecount) - return (0); - if (!isFillOrder(tif, td->td_fillorder) && - (tif->tif_flags & TIFF_NOBITREV) == 0) - TIFFReverseBits(tif->tif_rawdata, bytecount); - } - } - return (TIFFStartStrip(tif, 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) + { + TIFFErrorExtR(tif, 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; + TIFFErrorExtR(tif, 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. + */ + TIFFErrorExtR( + tif, 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) + { + _TIFFfreeExt(tif, 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) + { + TIFFErrorExtR(tif, module, "Integer overflow"); + return (0); + } + if (bytecountm > tif->tif_rawdatasize) + { + tif->tif_curstrip = NOSTRIP; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) + { + TIFFErrorExtR( + tif, 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)); } /* @@ -366,218 +913,424 @@ TIFFFillStrip(TIFF* tif, tstrip_t strip) * Read and decompress a tile of data. The * tile is selected by the (x,y,z,s) coordinates. */ -tsize_t -TIFFReadTile(TIFF* tif, - tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t s) +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 (-1); - return (TIFFReadEncodedTile(tif, - TIFFComputeTile(tif, x, y, z, s), buf, (tsize_t) -1)); + 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. */ -tsize_t -TIFFReadEncodedTile(TIFF* tif, ttile_t tile, tdata_t buf, tsize_t size) +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) + { + TIFFErrorExtR(tif, 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 = _TIFFmallocExt(tif, 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 = _TIFFmallocExt(tif, 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) { - TIFFDirectory *td = &tif->tif_dir; - tsize_t tilesize = tif->tif_tilesize; - - if (!TIFFCheckRead(tif, 1)) - return (-1); - if (tile >= td->td_nstrips) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%ld: Tile out of range, max %ld", - (long) tile, (unsigned long) td->td_nstrips); - return (-1); - } - if (size == (tsize_t) -1) - size = tilesize; - else if (size > tilesize) - size = tilesize; - if (TIFFFillTile(tif, tile) && (*tif->tif_decodetile)(tif, - (tidata_t) buf, size, (tsample_t)(tile/td->td_stripsperimage))) { - (*tif->tif_postdecode)(tif, (tidata_t) buf, size); - return (size); - } else - return (-1); + 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) + { + TIFFErrorExtR(tif, module, + "%" PRIu32 ": Tile out of range, max %" PRIu32, tile, + td->td_nstrips); + return ((tmsize_t)(-1)); + } + + if (!TIFFFillTile(tif, tile)) + return ((tmsize_t)(-1)); + + /* Sanity checks to avoid excessive memory allocation */ + /* Cf https://gitlab.com/libtiff/libtiff/-/issues/479 */ + if (td->td_compression == COMPRESSION_NONE) + { + if (tif->tif_rawdatasize != tilesize) + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Invalid tile byte count for tile %u. " + "Expected %" PRIu64 ", got %" PRIu64, + tile, (uint64_t)tilesize, + (uint64_t)tif->tif_rawdatasize); + return ((tmsize_t)(-1)); + } + } + else + { + /* Max compression ratio experimentally determined. Might be fragile... + * Only apply this heuristics to situations where the memory allocation + * would be big, to avoid breaking nominal use cases. + */ + const int maxCompressionRatio = + td->td_compression == COMPRESSION_ZSTD ? 33000 + : td->td_compression == COMPRESSION_JXL + ? + /* Evaluated on a 8000x8000 tile */ + 25000 * (td->td_planarconfig == PLANARCONFIG_CONTIG + ? td->td_samplesperpixel + : 1) + : td->td_compression == COMPRESSION_LZMA ? 7000 : 1000; + if (bufsizetoalloc > 100 * 1000 * 1000 && + tif->tif_rawdatasize < tilesize / maxCompressionRatio) + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Likely invalid tile byte count for tile %u. " + "Uncompressed tile size is %" PRIu64 ", " + "compressed one is %" PRIu64, + tile, (uint64_t)tilesize, + (uint64_t)tif->tif_rawdatasize); + return ((tmsize_t)(-1)); + } + } + + *buf = _TIFFmallocExt(tif, bufsizetoalloc); + if (*buf == NULL) + { + TIFFErrorExtR(tif, 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 tsize_t -TIFFReadRawTile1(TIFF* tif, - ttile_t tile, tdata_t buf, tsize_t size, const char* module) +static tmsize_t TIFFReadRawTile1(TIFF *tif, uint32_t tile, void *buf, + tmsize_t size, const char *module) { - TIFFDirectory *td = &tif->tif_dir; - - assert((tif->tif_flags&TIFF_NOREADRAW)==0); - if (!isMapped(tif)) { - tsize_t cc; - - if (!SeekOK(tif, td->td_stripoffset[tile])) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Seek error at row %ld, col %ld, tile %ld", - tif->tif_name, - (long) tif->tif_row, - (long) tif->tif_col, - (long) tile); - return ((tsize_t) -1); - } - cc = TIFFReadFile(tif, buf, size); - if (cc != size) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Read error at row %ld, col %ld; got %lu bytes, expected %lu", - tif->tif_name, - (long) tif->tif_row, - (long) tif->tif_col, - (unsigned long) cc, - (unsigned long) size); - return ((tsize_t) -1); - } - } else { - if (td->td_stripoffset[tile] + size > tif->tif_size) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Read error at row %ld, col %ld, tile %ld; got %lu bytes, expected %lu", - tif->tif_name, - (long) tif->tif_row, - (long) tif->tif_col, - (long) tile, - (unsigned long) tif->tif_size - td->td_stripoffset[tile], - (unsigned long) size); - return ((tsize_t) -1); - } - _TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[tile], size); - } - return (size); + assert((tif->tif_flags & TIFF_NOREADRAW) == 0); + if (!isMapped(tif)) + { + tmsize_t cc; + + if (!SeekOK(tif, TIFFGetStrileOffset(tif, tile))) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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 ((mb < ma) || (mb < size) || (mb > tif->tif_size)) + n = tif->tif_size - ma; + else + n = size; + if (n != size) + { + TIFFErrorExtR(tif, 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. */ -tsize_t -TIFFReadRawTile(TIFF* tif, ttile_t tile, tdata_t buf, tsize_t size) +tmsize_t TIFFReadRawTile(TIFF *tif, uint32_t tile, void *buf, tmsize_t size) { - static const char module[] = "TIFFReadRawTile"; - TIFFDirectory *td = &tif->tif_dir; - /* - * FIXME: butecount should have tsize_t type, but for now libtiff - * defines tsize_t as a signed 32-bit integer and we are losing - * ability to read arrays larger than 2^31 bytes. So we are using - * uint32 instead of tsize_t here. - */ - uint32 bytecount; - - if (!TIFFCheckRead(tif, 1)) - return ((tsize_t) -1); - if (tile >= td->td_nstrips) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%lu: Tile out of range, max %lu", - (unsigned long) tile, (unsigned long) td->td_nstrips); - return ((tsize_t) -1); - } - if (tif->tif_flags&TIFF_NOREADRAW) - { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Compression scheme does not support access to raw uncompressed data"); - return ((tsize_t) -1); - } - bytecount = td->td_stripbytecount[tile]; - if (size != (tsize_t) -1 && (uint32)size < bytecount) - bytecount = size; - return (TIFFReadRawTile1(tif, tile, buf, bytecount, module)); + 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) + { + TIFFErrorExtR(tif, module, + "%" PRIu32 ": Tile out of range, max %" PRIu32, tile, + td->td_nstrips); + return ((tmsize_t)(-1)); + } + if (tif->tif_flags & TIFF_NOREADRAW) + { + TIFFErrorExtR(tif, 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, ttile_t tile) +int TIFFFillTile(TIFF *tif, uint32_t tile) { - static const char module[] = "TIFFFillTile"; - TIFFDirectory *td = &tif->tif_dir; - - if ((tif->tif_flags&TIFF_NOREADRAW)==0) - { - /* - * FIXME: butecount should have tsize_t type, but for now - * libtiff defines tsize_t as a signed 32-bit integer and we - * are losing ability to read arrays larger than 2^31 bytes. - * So we are using uint32 instead of tsize_t here. - */ - uint32 bytecount = td->td_stripbytecount[tile]; - if (bytecount <= 0) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%lu: Invalid tile byte count, tile %lu", - (unsigned long) bytecount, (unsigned long) tile); - 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_flags &= ~TIFF_MYBUFFER; - /* - * We must check for overflow, potentially causing - * an OOB read. Instead of simple - * - * td->td_stripoffset[tile]+bytecount > tif->tif_size - * - * comparison (which can overflow) we do the following - * two comparisons: - */ - if (bytecount > tif->tif_size || - td->td_stripoffset[tile] > tif->tif_size - bytecount) { - tif->tif_curtile = NOTILE; - return (0); - } - tif->tif_rawdatasize = bytecount; - tif->tif_rawdata = - tif->tif_base + td->td_stripoffset[tile]; - } 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?). - */ - if (bytecount > (uint32)tif->tif_rawdatasize) { - tif->tif_curtile = NOTILE; - if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { - TIFFErrorExt(tif->tif_clientdata, - module, - "%s: Data buffer too small to hold tile %ld", - tif->tif_name, - (long) tile); - return (0); - } - if (!TIFFReadBufferSetup(tif, 0, - TIFFroundup(bytecount, 1024))) - return (0); - } - if ((uint32)TIFFReadRawTile1(tif, tile, - (unsigned char *)tif->tif_rawdata, - bytecount, module) != bytecount) - return (0); - if (!isFillOrder(tif, td->td_fillorder) && - (tif->tif_flags & TIFF_NOBITREV) == 0) - TIFFReverseBits(tif->tif_rawdata, bytecount); - } - } - return (TIFFStartTile(tif, 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) + { + TIFFErrorExtR(tif, 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; + TIFFErrorExtR(tif, 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) + { + _TIFFfreeExt(tif, 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) + { + TIFFErrorExtR(tif, module, "Integer overflow"); + return (0); + } + if (bytecountm > tif->tif_rawdatasize) + { + tif->tif_curtile = NOTILE; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) + { + TIFFErrorExtR(tif, 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)); } /* @@ -589,162 +1342,283 @@ TIFFFillTile(TIFF* tif, ttile_t tile) * large enough to hold any individual strip of * raw data. */ -int -TIFFReadBufferSetup(TIFF* tif, tdata_t bp, tsize_t size) +int TIFFReadBufferSetup(TIFF *tif, void *bp, tmsize_t size) { - static const char module[] = "TIFFReadBufferSetup"; - - assert((tif->tif_flags&TIFF_NOREADRAW)==0); - if (tif->tif_rawdata) { - if (tif->tif_flags & TIFF_MYBUFFER) - _TIFFfree(tif->tif_rawdata); - tif->tif_rawdata = NULL; - } - - if (bp) { - tif->tif_rawdatasize = size; - tif->tif_rawdata = (tidata_t) bp; - tif->tif_flags &= ~TIFF_MYBUFFER; - } else { - tif->tif_rawdatasize = TIFFroundup(size, 1024); - if (tif->tif_rawdatasize > 0) - tif->tif_rawdata = (tidata_t) _TIFFmalloc(tif->tif_rawdatasize); - tif->tif_flags |= TIFF_MYBUFFER; - } - if ((tif->tif_rawdata == NULL) || (tif->tif_rawdatasize == 0)) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: No space for data buffer at scanline %ld", - tif->tif_name, (long) tif->tif_row); - tif->tif_rawdatasize = 0; - return (0); - } - return (1); + 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) + _TIFFfreeExt(tif, 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) + { + TIFFErrorExtR(tif, 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 *)_TIFFcallocExt(tif, 1, tif->tif_rawdatasize); + tif->tif_flags |= TIFF_MYBUFFER; + } + if (tif->tif_rawdata == NULL) + { + TIFFErrorExtR(tif, 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, tstrip_t strip) +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; - if (tif->tif_flags&TIFF_NOREADRAW) - { - tif->tif_rawcp = NULL; - tif->tif_rawcc = 0; - } - else - { - tif->tif_rawcp = tif->tif_rawdata; - tif->tif_rawcc = td->td_stripbytecount[strip]; - } - return ((*tif->tif_predecode)(tif, - (tsample_t)(strip / td->td_stripsperimage))); + 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, ttile_t tile) +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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) { - 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_curtile = tile; - tif->tif_row = - (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) * - td->td_tilelength; - tif->tif_col = - (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) * - td->td_tilewidth; - if (tif->tif_flags&TIFF_NOREADRAW) - { - tif->tif_rawcp = NULL; - tif->tif_rawcc = 0; - } - else - { - tif->tif_rawcp = tif->tif_rawdata; - tif->tif_rawcc = td->td_stripbytecount[tile]; - } - return ((*tif->tif_predecode)(tif, - (tsample_t)(tile/td->td_stripsperimage))); + if (tif->tif_mode == O_WRONLY) + { + TIFFErrorExtR(tif, tif->tif_name, "File not open for reading"); + return (0); + } + if (tiles ^ isTiled(tif)) + { + TIFFErrorExtR(tif, tif->tif_name, + tiles ? "Can not read tiles from a striped image" + : "Can not read scanlines from a tiled image"); + return (0); + } + return (1); } -static int -TIFFCheckRead(TIFF* tif, int tiles) +/* 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) { - 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 stripped image" : - "Can not read scanlines from a tiled image"); - return (0); - } - return (1); + 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) + { + TIFFErrorExtR(tif, tif->tif_name, "File not open for reading"); + return 0; + } + if (tif->tif_flags & TIFF_NOREADRAW) + { + TIFFErrorExtR(tif, 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 & (TIFF_MYBUFFER | TIFF_BUFFERMMAP)) | + (tif->tif_flags & ~(TIFF_MYBUFFER | TIFF_BUFFERMMAP)); + tif->tif_rawdatasize = old_rawdatasize; + tif->tif_rawdata = old_rawdata; + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = 0; + + return ret; } -void -_TIFFNoPostDecode(TIFF* tif, tidata_t buf, tsize_t cc) +void _TIFFNoPostDecode(TIFF *tif, uint8_t *buf, tmsize_t cc) { - (void) tif; (void) buf; (void) cc; + (void)tif; + (void)buf; + (void)cc; } -void -_TIFFSwab16BitData(TIFF* tif, tidata_t buf, tsize_t cc) +void _TIFFSwab16BitData(TIFF *tif, uint8_t *buf, tmsize_t cc) { - (void) tif; + (void)tif; assert((cc & 1) == 0); - TIFFSwabArrayOfShort((uint16*) buf, cc/2); + TIFFSwabArrayOfShort((uint16_t *)buf, cc / 2); } -void -_TIFFSwab24BitData(TIFF* tif, tidata_t buf, tsize_t cc) +void _TIFFSwab24BitData(TIFF *tif, uint8_t *buf, tmsize_t cc) { - (void) tif; + (void)tif; assert((cc % 3) == 0); - TIFFSwabArrayOfTriples((uint8*) buf, cc/3); + TIFFSwabArrayOfTriples((uint8_t *)buf, cc / 3); } -void -_TIFFSwab32BitData(TIFF* tif, tidata_t buf, tsize_t cc) +void _TIFFSwab32BitData(TIFF *tif, uint8_t *buf, tmsize_t cc) { - (void) tif; + (void)tif; assert((cc & 3) == 0); - TIFFSwabArrayOfLong((uint32*) buf, cc/4); + TIFFSwabArrayOfLong((uint32_t *)buf, cc / 4); } -void -_TIFFSwab64BitData(TIFF* tif, tidata_t buf, tsize_t cc) +void _TIFFSwab64BitData(TIFF *tif, uint8_t *buf, tmsize_t cc) { - (void) tif; + (void)tif; assert((cc & 7) == 0); - TIFFSwabArrayOfDouble((double*) buf, cc/8); + 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/LibTiff/tif_stream.cxx b/LibTiff/tif_stream.cxx index 2a2351b2..92ea273c 100644 --- a/LibTiff/tif_stream.cxx +++ b/LibTiff/tif_stream.cxx @@ -1,26 +1,24 @@ -/* $Id: tif_stream.cxx,v 1.6.2.1 2009-01-01 00:10:43 bfriesen Exp $ */ - /* * Copyright (c) 1988-1996 Sam Leffler * Copyright (c) 1991-1996 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -30,266 +28,377 @@ #include "tiffiop.h" #include -#ifndef __VMS using namespace std; -#endif - -class tiffis_data -{ - public: - - istream *myIS; - long myStreamStartPos; -}; - -class tiffos_data -{ - public: - - ostream *myOS; - long myStreamStartPos; -}; - -static tsize_t -_tiffosReadProc(thandle_t, tdata_t, tsize_t) -{ - return 0; -} - -static tsize_t -_tiffisReadProc(thandle_t fd, tdata_t buf, tsize_t size) -{ - tiffis_data *data = (tiffis_data *)fd; - - data->myIS->read((char *)buf, (int)size); - - return data->myIS->gcount(); -} -static tsize_t -_tiffosWriteProc(thandle_t fd, tdata_t buf, tsize_t size) -{ - tiffos_data *data = (tiffos_data *)fd; - ostream *os = data->myOS; - int pos = os->tellp(); - - os->write((const char *)buf, size); - - return ((int)os->tellp()) - pos; -} - -static tsize_t -_tiffisWriteProc(thandle_t, tdata_t, tsize_t) -{ - return 0; -} +/* + ISO C++ uses a 'std::streamsize' type to define counts. This makes + it similar to, (but perhaps not the same as) size_t. -static toff_t -_tiffosSeekProc(thandle_t fd, toff_t off, int whence) -{ - tiffos_data *data = (tiffos_data *)fd; - ostream *os = data->myOS; - - // if the stream has already failed, don't do anything - if( os->fail() ) - return os->tellp(); - - switch(whence) { - case SEEK_SET: - os->seekp(data->myStreamStartPos + off, ios::beg); - break; - case SEEK_CUR: - os->seekp(off, ios::cur); - break; - case SEEK_END: - os->seekp(off, ios::end); - break; - } - - // Attempt to workaround problems with seeking past the end of the - // stream. ofstream doesn't have a problem with this but - // ostrstream/ostringstream does. In that situation, add intermediate - // '\0' characters. - if( os->fail() ) { -#ifdef __VMS - int old_state; -#else - ios::iostate old_state; -#endif - toff_t origin=0; - - old_state = os->rdstate(); - // reset the fail bit or else tellp() won't work below - os->clear(os->rdstate() & ~ios::failbit); - switch( whence ) { - case SEEK_SET: - origin = data->myStreamStartPos; - break; - case SEEK_CUR: - origin = os->tellp(); - break; - case SEEK_END: - os->seekp(0, ios::end); - origin = os->tellp(); - break; - } - // restore original stream state - os->clear(old_state); - - // only do something if desired seek position is valid - if( origin + off > data->myStreamStartPos ) { - toff_t num_fill; - - // clear the fail bit - os->clear(os->rdstate() & ~ios::failbit); - - // extend the stream to the expected size - os->seekp(0, ios::end); - num_fill = origin + off - (toff_t)os->tellp(); - for( toff_t i = 0; i < num_fill; i++ ) - os->put('\0'); - - // retry the seek - os->seekp(origin + off, ios::beg); - } - } - - return os->tellp(); -} + The std::ios::pos_type is used to represent stream positions as used + by tellg(), tellp(), seekg(), and seekp(). This makes it similar to + (but perhaps not the same as) 'off_t'. The std::ios::streampos type + is used for character streams, but is documented to not be an + integral type anymore, so it should *not* be assigned to an integral + type. -static toff_t -_tiffisSeekProc(thandle_t fd, toff_t off, int whence) -{ - tiffis_data *data = (tiffis_data *)fd; - - switch(whence) { - case SEEK_SET: - data->myIS->seekg(data->myStreamStartPos + off, ios::beg); - break; - case SEEK_CUR: - data->myIS->seekg(off, ios::cur); - break; - case SEEK_END: - data->myIS->seekg(off, ios::end); - break; - } - - return ((long)data->myIS->tellg()) - data->myStreamStartPos; -} + The std::ios::off_type is used to specify relative offsets needed by + the variants of seekg() and seekp() which accept a relative offset + argument. -static toff_t -_tiffosSizeProc(thandle_t fd) -{ - tiffos_data *data = (tiffos_data *)fd; - ostream *os = data->myOS; - toff_t pos = os->tellp(); - toff_t len; + Useful prototype knowledge: - os->seekp(0, ios::end); - len = os->tellp(); - os->seekp(pos); + Obtain read position + ios::pos_type basic_istream::tellg() - return len; -} + Set read position + basic_istream& basic_istream::seekg(ios::pos_type) + basic_istream& basic_istream::seekg(ios::off_type, ios_base::seekdir) -static toff_t -_tiffisSizeProc(thandle_t fd) -{ - tiffis_data *data = (tiffis_data *)fd; - int pos = data->myIS->tellg(); - int len; + Read data + basic_istream& istream::read(char *str, streamsize count) - data->myIS->seekg(0, ios::end); - len = data->myIS->tellg(); - data->myIS->seekg(pos); + Number of characters read in last unformatted read + streamsize istream::gcount(); - return len; -} + Obtain write position + ios::pos_type basic_ostream::tellp() -static int -_tiffosCloseProc(thandle_t fd) -{ - // Our stream was not allocated by us, so it shouldn't be closed by us. - delete (tiffos_data *)fd; - return 0; -} + Set write position + basic_ostream& basic_ostream::seekp(ios::pos_type) + basic_ostream& basic_ostream::seekp(ios::off_type, ios_base::seekdir) -static int -_tiffisCloseProc(thandle_t fd) -{ - // Our stream was not allocated by us, so it shouldn't be closed by us. - delete (tiffis_data *)fd; - return 0; -} + Write data + basic_ostream& ostream::write(const char *str, streamsize count) +*/ -static int -_tiffDummyMapProc(thandle_t , tdata_t* , toff_t* ) -{ - return (0); -} +struct tiffis_data; +struct tiffos_data; -static void -_tiffDummyUnmapProc(thandle_t , tdata_t , toff_t ) +extern "C" { -} -/* - * Open a TIFF file descriptor for read/writing. - */ -static TIFF* -_tiffStreamOpen(const char* name, const char* mode, void *fd) -{ - TIFF* tif; - - if( strchr(mode, 'w') ) { - tiffos_data *data = new tiffos_data; - data->myOS = (ostream *)fd; - data->myStreamStartPos = data->myOS->tellp(); - - // Open for writing. - tif = TIFFClientOpen(name, mode, - (thandle_t) data, - _tiffosReadProc, _tiffosWriteProc, - _tiffosSeekProc, _tiffosCloseProc, - _tiffosSizeProc, - _tiffDummyMapProc, _tiffDummyUnmapProc); - } else { - tiffis_data *data = new tiffis_data; - data->myIS = (istream *)fd; - data->myStreamStartPos = data->myIS->tellg(); - // Open for reading. - tif = TIFFClientOpen(name, mode, - (thandle_t) data, - _tiffisReadProc, _tiffisWriteProc, - _tiffisSeekProc, _tiffisCloseProc, - _tiffisSizeProc, - _tiffDummyMapProc, _tiffDummyUnmapProc); - } - - return (tif); -} + static tmsize_t _tiffosReadProc(thandle_t, void *, tmsize_t); + static tmsize_t _tiffisReadProc(thandle_t fd, void *buf, tmsize_t size); + static tmsize_t _tiffosWriteProc(thandle_t fd, void *buf, tmsize_t size); + static tmsize_t _tiffisWriteProc(thandle_t, void *, tmsize_t); + static uint64_t _tiffosSeekProc(thandle_t fd, uint64_t off, int whence); + static uint64_t _tiffisSeekProc(thandle_t fd, uint64_t off, int whence); + static uint64_t _tiffosSizeProc(thandle_t fd); + static uint64_t _tiffisSizeProc(thandle_t fd); + static int _tiffosCloseProc(thandle_t fd); + static int _tiffisCloseProc(thandle_t fd); + static int _tiffDummyMapProc(thandle_t, void **base, toff_t *size); + static void _tiffDummyUnmapProc(thandle_t, void *base, toff_t size); + static TIFF *_tiffStreamOpen(const char *name, const char *mode, void *fd); + + struct tiffis_data + { + istream *stream; + ios::pos_type start_pos; + }; + + struct tiffos_data + { + ostream *stream; + ios::pos_type start_pos; + }; + + static tmsize_t _tiffosReadProc(thandle_t, void *, tmsize_t) { return 0; } + + static tmsize_t _tiffisReadProc(thandle_t fd, void *buf, tmsize_t size) + { + tiffis_data *data = reinterpret_cast(fd); + + // Verify that type does not overflow. + streamsize request_size = size; + if (static_cast(request_size) != size) + return static_cast(-1); + + data->stream->read((char *)buf, request_size); + + return static_cast(data->stream->gcount()); + } + + static tmsize_t _tiffosWriteProc(thandle_t fd, void *buf, tmsize_t size) + { + tiffos_data *data = reinterpret_cast(fd); + ostream *os = data->stream; + ios::pos_type pos = os->tellp(); + + // Verify that type does not overflow. + streamsize request_size = size; + if (static_cast(request_size) != size) + return static_cast(-1); + + os->write(reinterpret_cast(buf), request_size); + + return static_cast(os->tellp() - pos); + } + + static tmsize_t _tiffisWriteProc(thandle_t, void *, tmsize_t) { return 0; } + + static uint64_t _tiffosSeekProc(thandle_t fd, uint64_t off, int whence) + { + tiffos_data *data = reinterpret_cast(fd); + ostream *os = data->stream; + + // if the stream has already failed, don't do anything + if (os->fail()) + return static_cast(-1); + + switch (whence) + { + case SEEK_SET: + { + // Compute 64-bit offset + uint64_t new_offset = + static_cast(data->start_pos) + off; + + // Verify that value does not overflow + ios::off_type offset = static_cast(new_offset); + if (static_cast(offset) != new_offset) + return static_cast(-1); + + os->seekp(offset, ios::beg); + break; + } + case SEEK_CUR: + { + // Verify that value does not overflow + ios::off_type offset = static_cast(off); + if (static_cast(offset) != off) + return static_cast(-1); + + os->seekp(offset, ios::cur); + break; + } + case SEEK_END: + { + // Verify that value does not overflow + ios::off_type offset = static_cast(off); + if (static_cast(offset) != off) + return static_cast(-1); + + os->seekp(offset, ios::end); + break; + } + } + + // Attempt to workaround problems with seeking past the end of the + // stream. ofstream doesn't have a problem with this but + // ostrstream/ostringstream does. In that situation, add intermediate + // '\0' characters. + if (os->fail()) + { + ios::iostate old_state; + ios::pos_type origin; + + old_state = os->rdstate(); + // reset the fail bit or else tellp() won't work below + os->clear(os->rdstate() & ~ios::failbit); + switch (whence) + { + case SEEK_SET: + default: + origin = data->start_pos; + break; + case SEEK_CUR: + origin = os->tellp(); + break; + case SEEK_END: + os->seekp(0, ios::end); + origin = os->tellp(); + break; + } + // restore original stream state + os->clear(old_state); + + // only do something if desired seek position is valid + if ((static_cast(origin) + off) > + static_cast(data->start_pos)) + { + uint64_t num_fill; + + // clear the fail bit + os->clear(os->rdstate() & ~ios::failbit); + + // extend the stream to the expected size + os->seekp(0, ios::end); + num_fill = (static_cast(origin)) + off - os->tellp(); + for (uint64_t i = 0; i < num_fill; i++) + os->put('\0'); + + // retry the seek + os->seekp(static_cast( + static_cast(origin) + off), + ios::beg); + } + } + + return static_cast(os->tellp()); + } + + static uint64_t _tiffisSeekProc(thandle_t fd, uint64_t off, int whence) + { + tiffis_data *data = reinterpret_cast(fd); + + switch (whence) + { + case SEEK_SET: + { + // Compute 64-bit offset + uint64_t new_offset = + static_cast(data->start_pos) + off; + + // Verify that value does not overflow + ios::off_type offset = static_cast(new_offset); + if (static_cast(offset) != new_offset) + return static_cast(-1); + + data->stream->seekg(offset, ios::beg); + break; + } + case SEEK_CUR: + { + // Verify that value does not overflow + ios::off_type offset = static_cast(off); + if (static_cast(offset) != off) + return static_cast(-1); + + data->stream->seekg(offset, ios::cur); + break; + } + case SEEK_END: + { + // Verify that value does not overflow + ios::off_type offset = static_cast(off); + if (static_cast(offset) != off) + return static_cast(-1); + + data->stream->seekg(offset, ios::end); + break; + } + } + + return (uint64_t)(data->stream->tellg() - data->start_pos); + } + + static uint64_t _tiffosSizeProc(thandle_t fd) + { + tiffos_data *data = reinterpret_cast(fd); + ostream *os = data->stream; + ios::pos_type pos = os->tellp(); + ios::pos_type len; + + os->seekp(0, ios::end); + len = os->tellp(); + os->seekp(pos); + + return (uint64_t)len; + } + + static uint64_t _tiffisSizeProc(thandle_t fd) + { + tiffis_data *data = reinterpret_cast(fd); + ios::pos_type pos = data->stream->tellg(); + ios::pos_type len; + + data->stream->seekg(0, ios::end); + len = data->stream->tellg(); + data->stream->seekg(pos); + + return (uint64_t)len; + } + + static int _tiffosCloseProc(thandle_t fd) + { + // Our stream was not allocated by us, so it shouldn't be closed by us. + delete reinterpret_cast(fd); + return 0; + } -TIFF* -TIFFStreamOpen(const char* name, ostream *os) + static int _tiffisCloseProc(thandle_t fd) + { + // Our stream was not allocated by us, so it shouldn't be closed by us. + delete reinterpret_cast(fd); + return 0; + } + + static int _tiffDummyMapProc(thandle_t, void **base, toff_t *size) + { + (void)base; + (void)size; + return (0); + } + + static void _tiffDummyUnmapProc(thandle_t, void *base, toff_t size) + { + (void)base; + (void)size; + } + + /* + * Open a TIFF file descriptor for read/writing. + */ + static TIFF *_tiffStreamOpen(const char *name, const char *mode, void *fd) + { + TIFF *tif; + + if (strchr(mode, 'w')) + { + tiffos_data *data = new tiffos_data; + data->stream = reinterpret_cast(fd); + data->start_pos = data->stream->tellp(); + + // Open for writing. + tif = TIFFClientOpen( + name, mode, reinterpret_cast(data), _tiffosReadProc, + _tiffosWriteProc, _tiffosSeekProc, _tiffosCloseProc, + _tiffosSizeProc, _tiffDummyMapProc, _tiffDummyUnmapProc); + if (!tif) + { + delete data; + } + } + else + { + tiffis_data *data = new tiffis_data; + data->stream = reinterpret_cast(fd); + data->start_pos = data->stream->tellg(); + // Open for reading. + tif = TIFFClientOpen( + name, mode, reinterpret_cast(data), _tiffisReadProc, + _tiffisWriteProc, _tiffisSeekProc, _tiffisCloseProc, + _tiffisSizeProc, _tiffDummyMapProc, _tiffDummyUnmapProc); + if (!tif) + { + delete data; + } + } + + return (tif); + } + +} /* extern "C" */ + +TIFF *TIFFStreamOpen(const char *name, ostream *os) { - // If os is either a ostrstream or ostringstream, and has no data - // written to it yet, then tellp() will return -1 which will break us. - // We workaround this by writing out a dummy character and - // then seek back to the beginning. - if( !os->fail() && (int)os->tellp() < 0 ) { - *os << '\0'; - os->seekp(0); - } - - // NB: We don't support mapped files with streams so add 'm' - return _tiffStreamOpen(name, "wm", os); + // If os is either a ostrstream or ostringstream, and has no data + // written to it yet, then tellp() will return -1 which will break us. + // We workaround this by writing out a dummy character and + // then seek back to the beginning. + if (!os->fail() && static_cast(os->tellp()) < 0) + { + *os << '\0'; + os->seekp(0); + } + + // NB: We don't support mapped files with streams so add 'm' + return _tiffStreamOpen(name, "wm", os); } -TIFF* -TIFFStreamOpen(const char* name, istream *is) +TIFF *TIFFStreamOpen(const char *name, istream *is) { - // NB: We don't support mapped files with streams so add 'm' - return _tiffStreamOpen(name, "rm", is); + // NB: We don't support mapped files with streams so add 'm' + return _tiffStreamOpen(name, "rm", is); } - -/* vim: set ts=8 sts=8 sw=8 noet: */ diff --git a/LibTiff/tif_strip.c b/LibTiff/tif_strip.c index 63dec6bd..820a2544 100644 --- a/LibTiff/tif_strip.c +++ b/LibTiff/tif_strip.c @@ -1,26 +1,24 @@ -/* $Id: tif_strip.c,v 1.19.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1991-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,143 +29,148 @@ */ #include "tiffiop.h" -static uint32 -summarize(TIFF* tif, size_t summand1, size_t summand2, const char* where) -{ - /* - * XXX: We are using casting to uint32 here, bacause sizeof(size_t) - * may be larger than sizeof(uint32) on 64-bit architectures. - */ - uint32 bytes = summand1 + summand2; - - if (bytes - summand1 != summand2) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where); - bytes = 0; - } - - return (bytes); -} - -static uint32 -multiply(TIFF* tif, size_t nmemb, size_t elem_size, const char* where) -{ - uint32 bytes = nmemb * elem_size; - - if (elem_size && bytes / elem_size != nmemb) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where); - bytes = 0; - } - - return (bytes); -} - /* * Compute which strip a (row,sample) value is in. */ -tstrip_t -TIFFComputeStrip(TIFF* tif, uint32 row, tsample_t sample) +uint32_t TIFFComputeStrip(TIFF *tif, uint32_t row, uint16_t sample) { - TIFFDirectory *td = &tif->tif_dir; - tstrip_t strip; - - strip = row / td->td_rowsperstrip; - if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { - if (sample >= td->td_samplesperpixel) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%lu: Sample out of range, max %lu", - (unsigned long) sample, (unsigned long) td->td_samplesperpixel); - return ((tstrip_t) 0); - } - strip += sample*td->td_stripsperimage; - } - return (strip); + 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) + { + TIFFErrorExtR(tif, 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. */ -tstrip_t -TIFFNumberOfStrips(TIFF* tif) +uint32_t TIFFNumberOfStrips(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - tstrip_t nstrips; - - nstrips = (td->td_rowsperstrip == (uint32) -1 ? 1 : - TIFFhowmany(td->td_imagelength, td->td_rowsperstrip)); - if (td->td_planarconfig == PLANARCONFIG_SEPARATE) - nstrips = multiply(tif, nstrips, td->td_samplesperpixel, - "TIFFNumberOfStrips"); - return (nstrips); + 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. */ -tsize_t -TIFFVStripSize(TIFF* tif, uint32 nrows) +uint64_t TIFFVStripSize64(TIFF *tif, uint32_t nrows) { - TIFFDirectory *td = &tif->tif_dir; - - if (nrows == (uint32) -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 ycbcrsubsampling[2]; - tsize_t w, scanline, samplingarea; - - TIFFGetField( tif, TIFFTAG_YCBCRSUBSAMPLING, - ycbcrsubsampling + 0, - ycbcrsubsampling + 1 ); - - samplingarea = ycbcrsubsampling[0]*ycbcrsubsampling[1]; - if (samplingarea == 0) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Invalid YCbCr subsampling"); - return 0; - } - - w = TIFFroundup(td->td_imagewidth, ycbcrsubsampling[0]); - scanline = TIFFhowmany8(multiply(tif, w, td->td_bitspersample, - "TIFFVStripSize")); - nrows = TIFFroundup(nrows, ycbcrsubsampling[1]); - /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ - scanline = multiply(tif, nrows, scanline, "TIFFVStripSize"); - return ((tsize_t) - summarize(tif, scanline, - multiply(tif, 2, scanline / samplingarea, - "TIFFVStripSize"), "TIFFVStripSize")); - } else - return ((tsize_t) multiply(tif, nrows, TIFFScanlineSize(tif), - "TIFFVStripSize")); + 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) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, 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. */ -tsize_t -TIFFRawStripSize(TIFF* tif, tstrip_t strip) +uint64_t TIFFRawStripSize64(TIFF *tif, uint32_t strip) { - TIFFDirectory* td = &tif->tif_dir; - tsize_t bytecount = td->td_stripbytecount[strip]; - - if (bytecount <= 0) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "%lu: Invalid strip byte count, strip %lu", - (unsigned long) bytecount, (unsigned long) strip); - bytecount = (tsize_t) -1; - } - - return bytecount; + static const char module[] = "TIFFRawStripSize64"; + uint64_t bytecount = TIFFGetStrileByteCount(tif, strip); + + if (bytecount == 0) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, "Integer overflow"); + n = 0; + } + } + return (n); } /* @@ -178,14 +181,20 @@ TIFFRawStripSize(TIFF* tif, tstrip_t strip) * truncated to reflect the actual space required * to hold the strip. */ -tsize_t -TIFFStripSize(TIFF* tif) +uint64_t TIFFStripSize64(TIFF *tif) { - TIFFDirectory* td = &tif->tif_dir; - uint32 rps = td->td_rowsperstrip; - if (rps > td->td_imagelength) - rps = td->td_imagelength; - return (TIFFVStripSize(tif, rps)); + 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); } /* @@ -194,95 +203,33 @@ TIFFStripSize(TIFF* tif) * request is <1 then we choose a strip size according * to certain heuristics. */ -uint32 -TIFFDefaultStripSize(TIFF* tif, uint32 request) +uint32_t TIFFDefaultStripSize(TIFF *tif, uint32_t request) { - return (*tif->tif_defstripsize)(tif, request); + return (*tif->tif_defstripsize)(tif, request); } -uint32 -_TIFFDefaultStripSize(TIFF* tif, uint32 s) +uint32_t _TIFFDefaultStripSize(TIFF *tif, uint32_t s) { - if ((int32) s < 1) { - /* - * If RowsPerStrip is unspecified, try to break the - * image up into strips that are approximately - * STRIP_SIZE_DEFAULT bytes long. - */ - tsize_t scanline = TIFFScanlineSize(tif); - s = (uint32)STRIP_SIZE_DEFAULT / (scanline == 0 ? 1 : scanline); - if (s == 0) /* very wide images */ - s = 1; - } - 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. - */ -tsize_t -TIFFScanlineSize(TIFF* tif) -{ - TIFFDirectory *td = &tif->tif_dir; - tsize_t scanline; - - if (td->td_planarconfig == PLANARCONFIG_CONTIG) { - if (td->td_photometric == PHOTOMETRIC_YCBCR - && !isUpSampled(tif)) { - uint16 ycbcrsubsampling[2]; - - TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, - ycbcrsubsampling + 0, - ycbcrsubsampling + 1); - - if (ycbcrsubsampling[0] == 0) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Invalid YCbCr subsampling"); - return 0; - } - - scanline = TIFFroundup(td->td_imagewidth, - ycbcrsubsampling[0]); - scanline = TIFFhowmany8(multiply(tif, scanline, - td->td_bitspersample, - "TIFFScanlineSize")); - return ((tsize_t) - summarize(tif, scanline, - multiply(tif, 2, - scanline / ycbcrsubsampling[0], - "TIFFVStripSize"), - "TIFFVStripSize")); - } else { - scanline = multiply(tif, td->td_imagewidth, - td->td_samplesperpixel, - "TIFFScanlineSize"); - } - } else - scanline = td->td_imagewidth; - return ((tsize_t) TIFFhowmany8(multiply(tif, scanline, - td->td_bitspersample, - "TIFFScanlineSize"))); -} - -/* - * Some stuff depends on this older version of TIFFScanlineSize - * TODO: resolve this - */ -tsize_t -TIFFOldScanlineSize(TIFF* tif) -{ - TIFFDirectory *td = &tif->tif_dir; - tsize_t scanline; - - scanline = multiply (tif, td->td_bitspersample, td->td_imagewidth, - "TIFFScanlineSize"); - if (td->td_planarconfig == PLANARCONFIG_CONTIG) - scanline = multiply (tif, scanline, td->td_samplesperpixel, - "TIFFScanlineSize"); - return ((tsize_t) TIFFhowmany8(scanline)); + 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); } /* @@ -294,46 +241,80 @@ TIFFOldScanlineSize(TIFF* tif) * 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. - * Some stuff depends on this newer version of TIFFScanlineSize - * TODO: resolve this */ -tsize_t -TIFFNewScanlineSize(TIFF* tif) +uint64_t TIFFScanlineSize64(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - tsize_t scanline; - - if (td->td_planarconfig == PLANARCONFIG_CONTIG) { - if (td->td_photometric == PHOTOMETRIC_YCBCR - && !isUpSampled(tif)) { - uint16 ycbcrsubsampling[2]; - - TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, - ycbcrsubsampling + 0, - ycbcrsubsampling + 1); - - if (ycbcrsubsampling[0]*ycbcrsubsampling[1] == 0) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "Invalid YCbCr subsampling"); - return 0; - } - - return((tsize_t) ((((td->td_imagewidth+ycbcrsubsampling[0]-1) - /ycbcrsubsampling[0]) - *(ycbcrsubsampling[0]*ycbcrsubsampling[1]+2) - *td->td_bitspersample+7) - /8)/ycbcrsubsampling[1]); - - } else { - scanline = multiply(tif, td->td_imagewidth, - td->td_samplesperpixel, - "TIFFScanlineSize"); - } - } else - scanline = td->td_imagewidth; - return ((tsize_t) TIFFhowmany8(multiply(tif, scanline, - td->td_bitspersample, - "TIFFScanlineSize"))); + 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) + { + TIFFErrorExtR(tif, 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))) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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); } /* @@ -342,29 +323,28 @@ TIFFNewScanlineSize(TIFF* tif) * I/O size returned by TIFFScanlineSize which may be less * if data is store as separate planes). */ -tsize_t -TIFFRasterScanlineSize(TIFF* tif) +uint64_t TIFFRasterScanlineSize64(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - tsize_t scanline; - - scanline = multiply (tif, td->td_bitspersample, td->td_imagewidth, - "TIFFRasterScanlineSize"); - if (td->td_planarconfig == PLANARCONFIG_CONTIG) { - scanline = multiply (tif, scanline, td->td_samplesperpixel, - "TIFFRasterScanlineSize"); - return ((tsize_t) TIFFhowmany8(scanline)); - } else - return ((tsize_t) multiply (tif, TIFFhowmany8(scanline), - td->td_samplesperpixel, - "TIFFRasterScanlineSize")); + 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/LibTiff/tif_swab.c b/LibTiff/tif_swab.c index e4f1a6d1..827b025c 100644 --- a/LibTiff/tif_swab.c +++ b/LibTiff/tif_swab.c @@ -1,26 +1,24 @@ -/* $Id: tif_swab.c,v 1.4.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,102 +29,219 @@ */ #include "tiffiop.h" -#ifndef TIFFSwabShort -void -TIFFSwabShort(uint16* wp) +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabShort) +void TIFFSwabShort(uint16_t *wp) { - register unsigned char* cp = (unsigned char*) wp; - unsigned char t; + 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 - t = cp[1]; cp[1] = cp[0]; cp[0] = t; +#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 -#ifndef TIFFSwabLong -void -TIFFSwabLong(uint32* lp) +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabLong8) +void TIFFSwabLong8(uint64_t *lp) { - register unsigned char* cp = (unsigned char*) lp; - unsigned char t; + 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 - t = cp[3]; cp[3] = cp[0]; cp[0] = t; - t = cp[2]; cp[2] = cp[1]; cp[1] = t; +#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 -#ifndef TIFFSwabArrayOfShort -void -TIFFSwabArrayOfShort(uint16* wp, register unsigned long n) +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabArrayOfTriples) +void TIFFSwabArrayOfTriples(register uint8_t *tp, tmsize_t n) { - register unsigned char* cp; - register unsigned char t; - - /* XXX unroll loop some */ - while (n-- > 0) { - cp = (unsigned char*) wp; - t = cp[1]; cp[1] = cp[0]; cp[0] = t; - wp++; - } + 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 -#ifndef TIFFSwabArrayOfTriples -void -TIFFSwabArrayOfTriples(uint8* tp, unsigned long n) +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabArrayOfLong) +void TIFFSwabArrayOfLong(register uint32_t *lp, 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; - } + 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 -#ifndef TIFFSwabArrayOfLong -void -TIFFSwabArrayOfLong(register uint32* lp, register unsigned long n) +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabArrayOfLong8) +void TIFFSwabArrayOfLong8(register uint64_t *lp, tmsize_t n) { - register unsigned char *cp; - register unsigned char t; - - /* 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++; - } + 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 -#ifndef TIFFSwabDouble -void -TIFFSwabDouble(double *dp) +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabFloat) +void TIFFSwabFloat(float *fp) { - register uint32* lp = (uint32*) dp; - uint32 t; + 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 - TIFFSwabArrayOfLong(lp, 2); - t = lp[0]; lp[0] = lp[1]; lp[1] = t; +#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 -#ifndef TIFFSwabArrayOfDouble -void -TIFFSwabArrayOfDouble(double* dp, register unsigned long n) +#if defined(DISABLE_CHECK_TIFFSWABMACROS) || !defined(TIFFSwabArrayOfDouble) +void TIFFSwabArrayOfDouble(double *dp, tmsize_t n) { - register uint32* lp = (uint32*) dp; - register uint32 t; - - TIFFSwabArrayOfLong(lp, n + n); - while (n-- > 0) { - t = lp[0]; lp[0] = lp[1]; lp[1] = t; - lp += 2; - } + 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 @@ -140,103 +255,75 @@ TIFFSwabArrayOfDouble(double* dp, register unsigned long n) * 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 -}; + 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, + 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) +const unsigned char *TIFFGetBitRevTable(int reversed) { - return (reversed ? TIFFBitRevTable : TIFFNoBitRevTable); + return (reversed ? TIFFBitRevTable : TIFFNoBitRevTable); } -void -TIFFReverseBits(register unsigned char* cp, register unsigned long n) +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++; + 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/LibTiff/tif_thunder.c b/LibTiff/tif_thunder.c index 8e7a1258..1f97362c 100644 --- a/LibTiff/tif_thunder.c +++ b/LibTiff/tif_thunder.c @@ -1,30 +1,29 @@ -/* $Id: tif_thunder.c,v 1.5.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. @@ -42,124 +41,158 @@ * 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 */ +#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 */ +#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"; -static const int twobitdeltas[4] = { 0, 1, 0, -1 }; -static const int threebitdeltas[8] = { 0, 1, 2, 3, 0, -3, -2, -1 }; + if (tif->tif_dir.td_bitspersample != 4) + { + TIFFErrorExtR(tif, module, + "Wrong bitspersample value (%d), Thunder decoder only " + "supports 4bits per sample.", + (int)tif->tif_dir.td_bitspersample); + return 0; + } -#define SETPIXEL(op, v) { \ - lastpixel = (v) & 0xf; \ - if (npixels++ & 1) \ - *op++ |= lastpixel; \ - else \ - op[0] = (tidataval_t) (lastpixel << 4); \ + return (1); } -static int -ThunderDecode(TIFF* tif, tidata_t op, tsize_t maxpixels) +static int ThunderDecode(TIFF *tif, uint8_t *op, tmsize_t maxpixels) { - register unsigned char *bp; - register tsize_t cc; - unsigned int lastpixel; - tsize_t npixels; + 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; + 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++ = (tidataval_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, lastpixel + twobitdeltas[delta]); - if ((delta = ((n >> 2) & 3)) != DELTA2_SKIP) - SETPIXEL(op, lastpixel + twobitdeltas[delta]); - if ((delta = (n & 3)) != DELTA2_SKIP) - SETPIXEL(op, lastpixel + twobitdeltas[delta]); - break; - case THUNDER_3BITDELTAS: /* 3-bit deltas */ - if ((delta = ((n >> 3) & 7)) != DELTA3_SKIP) - SETPIXEL(op, lastpixel + threebitdeltas[delta]); - if ((delta = (n & 7)) != DELTA3_SKIP) - SETPIXEL(op, lastpixel + threebitdeltas[delta]); - break; - case THUNDER_RAW: /* raw data */ - SETPIXEL(op, n); - break; - } - } - tif->tif_rawcp = (tidata_t) bp; - tif->tif_rawcc = cc; - if (npixels != maxpixels) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, - "ThunderDecode: %s data at scanline %ld (%lu != %lu)", - npixels < maxpixels ? "Not enough" : "Too much", - (long) tif->tif_row, (long) npixels, (long) maxpixels); - return (0); - } - return (1); + 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) + { + TIFFErrorExtR(tif, 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, tidata_t buf, tsize_t occ, tsample_t s) +static int ThunderDecodeRow(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s) { - tidata_t row = buf; - - (void) s; - while ((long)occ > 0) { - if (!ThunderDecode(tif, row, tif->tif_dir.td_imagewidth)) - return (0); - occ -= tif->tif_scanlinesize; - row += tif->tif_scanlinesize; - } - return (1); + static const char module[] = "ThunderDecodeRow"; + uint8_t *row = buf; + + (void)s; + if (occ % tif->tif_scanlinesize) + { + TIFFErrorExtR(tif, 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) +int TIFFInitThunderScan(TIFF *tif, int scheme) { - (void) scheme; - tif->tif_decoderow = ThunderDecodeRow; - tif->tif_decodestrip = ThunderDecodeRow; - return (1); + (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/LibTiff/tif_tile.c b/LibTiff/tif_tile.c index d8379e61..f07032f7 100644 --- a/LibTiff/tif_tile.c +++ b/LibTiff/tif_tile.c @@ -1,26 +1,24 @@ -/* $Id: tif_tile.c,v 1.12.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1991-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,216 +29,233 @@ */ #include "tiffiop.h" -static uint32 -summarize(TIFF* tif, size_t summand1, size_t summand2, const char* where) -{ - /* - * XXX: We are using casting to uint32 here, because sizeof(size_t) - * may be larger than sizeof(uint32) on 64-bit architectures. - */ - uint32 bytes = summand1 + summand2; - - if (bytes - summand1 != summand2) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where); - bytes = 0; - } - - return (bytes); -} - -static uint32 -multiply(TIFF* tif, size_t nmemb, size_t elem_size, const char* where) -{ - uint32 bytes = nmemb * elem_size; - - if (elem_size && bytes / elem_size != nmemb) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where); - bytes = 0; - } - - return (bytes); -} - /* * Compute which tile an (x,y,z,s) value is in. */ -ttile_t -TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, tsample_t s) +uint32_t TIFFComputeTile(TIFF *tif, uint32_t x, uint32_t y, uint32_t z, + uint16_t s) { - TIFFDirectory *td = &tif->tif_dir; - uint32 dx = td->td_tilewidth; - uint32 dy = td->td_tilelength; - uint32 dz = td->td_tiledepth; - ttile_t tile = 1; + 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) -1) - dx = td->td_imagewidth; - if (dy == (uint32) -1) - dy = td->td_imagelength; - if (dz == (uint32) -1) - dz = td->td_imagedepth; - if (dx != 0 && dy != 0 && dz != 0) { - uint32 xpt = TIFFhowmany(td->td_imagewidth, dx); - uint32 ypt = TIFFhowmany(td->td_imagelength, dy); - uint32 zpt = TIFFhowmany(td->td_imagedepth, dz); + 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); + 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 x, uint32 y, uint32 z, tsample_t s) +int TIFFCheckTile(TIFF *tif, uint32_t x, uint32_t y, uint32_t z, uint16_t s) { - TIFFDirectory *td = &tif->tif_dir; + 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); + if (x >= td->td_imagewidth) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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. */ -ttile_t -TIFFNumberOfTiles(TIFF* tif) +uint32_t TIFFNumberOfTiles(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - uint32 dx = td->td_tilewidth; - uint32 dy = td->td_tilelength; - uint32 dz = td->td_tiledepth; - ttile_t ntiles; + 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) -1) - dx = td->td_imagewidth; - if (dy == (uint32) -1) - dy = td->td_imagelength; - if (dz == (uint32) -1) - dz = td->td_imagedepth; - ntiles = (dx == 0 || dy == 0 || dz == 0) ? 0 : - multiply(tif, multiply(tif, TIFFhowmany(td->td_imagewidth, dx), - TIFFhowmany(td->td_imagelength, dy), - "TIFFNumberOfTiles"), - TIFFhowmany(td->td_imagedepth, dz), "TIFFNumberOfTiles"); - if (td->td_planarconfig == PLANARCONFIG_SEPARATE) - ntiles = multiply(tif, ntiles, td->td_samplesperpixel, - "TIFFNumberOfTiles"); - return (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. */ -tsize_t -TIFFTileRowSize(TIFF* tif) +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) + { + TIFFErrorExtR(tif, module, "Tile length is zero"); + return 0; + } + if (td->td_tilewidth == 0) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, "Samples per pixel is zero"); + return 0; + } + rowsize = _TIFFMultiply64(tif, rowsize, td->td_samplesperpixel, + "TIFFTileRowSize"); + } + tilerowsize = TIFFhowmany8_64(rowsize); + if (tilerowsize == 0) + { + TIFFErrorExtR(tif, module, "Computed tile row size is zero"); + return 0; + } + return (tilerowsize); +} +tmsize_t TIFFTileRowSize(TIFF *tif) { - TIFFDirectory *td = &tif->tif_dir; - tsize_t rowsize; - - if (td->td_tilelength == 0 || td->td_tilewidth == 0) - return ((tsize_t) 0); - rowsize = multiply(tif, td->td_bitspersample, td->td_tilewidth, - "TIFFTileRowSize"); - if (td->td_planarconfig == PLANARCONFIG_CONTIG) - rowsize = multiply(tif, rowsize, td->td_samplesperpixel, - "TIFFTileRowSize"); - return ((tsize_t) TIFFhowmany8(rowsize)); + 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. */ -tsize_t -TIFFVTileSize(TIFF* tif, uint32 nrows) +uint64_t TIFFVTileSize64(TIFF *tif, uint32_t nrows) { - TIFFDirectory *td = &tif->tif_dir; - tsize_t tilesize; - - if (td->td_tilelength == 0 || td->td_tilewidth == 0 || - td->td_tiledepth == 0) - return ((tsize_t) 0); - 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. - */ - tsize_t w = - TIFFroundup(td->td_tilewidth, td->td_ycbcrsubsampling[0]); - tsize_t rowsize = - TIFFhowmany8(multiply(tif, w, td->td_bitspersample, - "TIFFVTileSize")); - tsize_t samplingarea = - td->td_ycbcrsubsampling[0]*td->td_ycbcrsubsampling[1]; - if (samplingarea == 0) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Invalid YCbCr subsampling"); - return 0; - } - nrows = TIFFroundup(nrows, td->td_ycbcrsubsampling[1]); - /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ - tilesize = multiply(tif, nrows, rowsize, "TIFFVTileSize"); - tilesize = summarize(tif, tilesize, - multiply(tif, 2, tilesize / samplingarea, - "TIFFVTileSize"), - "TIFFVTileSize"); - } else - tilesize = multiply(tif, nrows, TIFFTileRowSize(tif), - "TIFFVTileSize"); - return ((tsize_t) - multiply(tif, tilesize, td->td_tiledepth, "TIFFVTileSize")); + 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)) + { + TIFFErrorExtR(tif, 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. */ -tsize_t -TIFFTileSize(TIFF* tif) +uint64_t TIFFTileSize64(TIFF *tif) +{ + return (TIFFVTileSize64(tif, tif->tif_dir.td_tilelength)); +} +tmsize_t TIFFTileSize(TIFF *tif) { - return (TIFFVTileSize(tif, tif->tif_dir.td_tilelength)); + static const char module[] = "TIFFTileSize"; + uint64_t m; + m = TIFFTileSize64(tif); + return _TIFFCastUInt64ToSSize(tif, m, module); } /* @@ -249,32 +264,21 @@ TIFFTileSize(TIFF* tif) * request is <1 then we choose a size according * to certain heuristics. */ -void -TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +void TIFFDefaultTileSize(TIFF *tif, uint32_t *tw, uint32_t *th) { - (*tif->tif_deftilesize)(tif, tw, th); + (*tif->tif_deftilesize)(tif, tw, th); } -void -_TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +void _TIFFDefaultTileSize(TIFF *tif, uint32_t *tw, uint32_t *th) { - (void) tif; - if (*(int32*) tw < 1) - *tw = 256; - if (*(int32*) th < 1) - *th = 256; - /* roundup to a multiple of 16 per the spec */ - if (*tw & 0xf) - *tw = TIFFroundup(*tw, 16); - if (*th & 0xf) - *th = TIFFroundup(*th, 16); + (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/LibTiff/tif_unix.c b/LibTiff/tif_unix.c index 5ea6b02e..34dd53b9 100644 --- a/LibTiff/tif_unix.c +++ b/LibTiff/tif_unix.c @@ -1,26 +1,24 @@ -/* $Id: tif_unix.c,v 1.12.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -28,157 +26,236 @@ * TIFF Library UNIX-specific Routines. These are should also work with the * Windows Common RunTime Library. */ + #include "tif_config.h" #ifdef HAVE_SYS_TYPES_H -# include +#include #endif +#include + #include #include #include -#if !(defined(_WIN32) || defined(WIN32)) -# include +#ifdef HAVE_UNISTD_H +#include #endif #ifdef HAVE_FCNTL_H -# include +#include #endif #ifdef HAVE_IO_H -# include +#include #endif #include "tiffiop.h" -static tsize_t -_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +#define TIFF_IO_MAX 2147483647U + +typedef union fd_as_handle_union { - return ((tsize_t) read((int) fd, buf, (size_t) size)); -} + int fd; + thandle_t h; +} fd_as_handle_union_t; -static tsize_t -_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +static tmsize_t _tiffReadProc(thandle_t fd, void *buf, tmsize_t size) { - return ((tsize_t) write((int) fd, buf, (size_t) size)); + fd_as_handle_union_t fdh; + const size_t bytes_total = (size_t)size; + size_t bytes_read; + tmsize_t count = -1; + if ((tmsize_t)bytes_total != size) + { + errno = EINVAL; + return (tmsize_t)-1; + } + fdh.h = fd; + for (bytes_read = 0; bytes_read < bytes_total; bytes_read += count) + { + char *buf_offset = (char *)buf + bytes_read; + size_t io_size = bytes_total - bytes_read; + if (io_size > TIFF_IO_MAX) + io_size = TIFF_IO_MAX; + count = read(fdh.fd, buf_offset, (TIFFIOSize_t)io_size); + if (count <= 0) + break; + } + if (count < 0) + return (tmsize_t)-1; + return (tmsize_t)bytes_read; } -static toff_t -_tiffSeekProc(thandle_t fd, toff_t off, int whence) +static tmsize_t _tiffWriteProc(thandle_t fd, void *buf, tmsize_t size) { - return ((toff_t) lseek((int) fd, (off_t) off, whence)); + fd_as_handle_union_t fdh; + const size_t bytes_total = (size_t)size; + size_t bytes_written; + tmsize_t count = -1; + if ((tmsize_t)bytes_total != size) + { + errno = EINVAL; + return (tmsize_t)-1; + } + fdh.h = fd; + for (bytes_written = 0; bytes_written < bytes_total; bytes_written += count) + { + const char *buf_offset = (char *)buf + bytes_written; + size_t io_size = bytes_total - bytes_written; + if (io_size > TIFF_IO_MAX) + io_size = TIFF_IO_MAX; + count = write(fdh.fd, buf_offset, (TIFFIOSize_t)io_size); + if (count <= 0) + break; + } + if (count < 0) + return (tmsize_t)-1; + return (tmsize_t)bytes_written; + /* return ((tmsize_t) write(fdh.fd, buf, bytes_total)); */ } -static int -_tiffCloseProc(thandle_t fd) +static uint64_t _tiffSeekProc(thandle_t fd, uint64_t off, int whence) { - return (close((int) fd)); + fd_as_handle_union_t fdh; + _TIFF_off_t off_io = (_TIFF_off_t)off; + if ((uint64_t)off_io != off) + { + errno = EINVAL; + return (uint64_t)-1; /* this is really gross */ + } + fdh.h = fd; + return ((uint64_t)_TIFF_lseek_f(fdh.fd, off_io, whence)); } +static int _tiffCloseProc(thandle_t fd) +{ + fd_as_handle_union_t fdh; + fdh.h = fd; + return (close(fdh.fd)); +} -static toff_t -_tiffSizeProc(thandle_t fd) +static uint64_t _tiffSizeProc(thandle_t fd) { -#ifdef _AM29K - long fsize; - return ((fsize = lseek((int) fd, 0, SEEK_END)) < 0 ? 0 : fsize); -#else - struct stat sb; - return (toff_t) (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size); -#endif + _TIFF_stat_s sb; + fd_as_handle_union_t fdh; + fdh.h = fd; + if (_TIFF_fstat_f(fdh.fd, &sb) < 0) + return (0); + else + return ((uint64_t)sb.st_size); } #ifdef HAVE_MMAP #include -static int -_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +static int _tiffMapProc(thandle_t fd, void **pbase, toff_t *psize) { - toff_t size = _tiffSizeProc(fd); - if (size != (toff_t) -1) { - *pbase = (tdata_t) - mmap(0, size, PROT_READ, MAP_SHARED, (int) fd, 0); - if (*pbase != (tdata_t) -1) { - *psize = size; - return (1); - } - } - return (0); + uint64_t size64 = _tiffSizeProc(fd); + tmsize_t sizem = (tmsize_t)size64; + if (size64 && (uint64_t)sizem == size64) + { + fd_as_handle_union_t fdh; + fdh.h = fd; + *pbase = + (void *)mmap(0, (size_t)sizem, PROT_READ, MAP_SHARED, fdh.fd, 0); + if (*pbase != (void *)-1) + { + *psize = (tmsize_t)sizem; + return (1); + } + } + return (0); } -static void -_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +static void _tiffUnmapProc(thandle_t fd, void *base, toff_t size) { - (void) fd; - (void) munmap(base, (off_t) size); + (void)fd; + (void)munmap(base, (off_t)size); } -#else /* !HAVE_MMAP */ -static int -_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +#else /* !HAVE_MMAP */ +static int _tiffMapProc(thandle_t fd, void **pbase, toff_t *psize) { - (void) fd; (void) pbase; (void) psize; - return (0); + (void)fd; + (void)pbase; + (void)psize; + return (0); } -static void -_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +static void _tiffUnmapProc(thandle_t fd, void *base, toff_t size) { - (void) fd; (void) base; (void) size; + (void)fd; + (void)base; + (void)size; } #endif /* !HAVE_MMAP */ /* * Open a TIFF file descriptor for read/writing. */ -TIFF* -TIFFFdOpen(int fd, const char* name, const char* mode) +TIFF *TIFFFdOpen(int fd, const char *name, const char *mode) { - TIFF* tif; - - tif = TIFFClientOpen(name, mode, - (thandle_t) fd, - _tiffReadProc, _tiffWriteProc, - _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, - _tiffMapProc, _tiffUnmapProc); - if (tif) - tif->tif_fd = fd; - return (tif); + return TIFFFdOpenExt(fd, name, mode, NULL); +} + +TIFF *TIFFFdOpenExt(int fd, const char *name, const char *mode, + TIFFOpenOptions *opts) +{ + TIFF *tif; + + fd_as_handle_union_t fdh; + fdh.fd = fd; + tif = TIFFClientOpenExt(name, mode, fdh.h, _tiffReadProc, _tiffWriteProc, + _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, + _tiffMapProc, _tiffUnmapProc, opts); + if (tif) + tif->tif_fd = fd; + return (tif); } /* * Open a TIFF file for read/writing. */ -TIFF* -TIFFOpen(const char* name, const char* mode) +TIFF *TIFFOpen(const char *name, const char *mode) +{ + return TIFFOpenExt(name, mode, NULL); +} + +TIFF *TIFFOpenExt(const char *name, const char *mode, TIFFOpenOptions *opts) { - static const char module[] = "TIFFOpen"; - int m, fd; - TIFF* tif; + static const char module[] = "TIFFOpen"; + int m, fd; + TIFF *tif; - m = _TIFFgetMode(mode, module); - if (m == -1) - return ((TIFF*)0); + m = _TIFFgetMode(opts, NULL, mode, module); + if (m == -1) + return ((TIFF *)0); -/* for cygwin and mingw */ +/* for cygwin and mingw */ #ifdef O_BINARY - m |= O_BINARY; -#endif - -#ifdef _AM29K - fd = open(name, m); -#else - fd = open(name, m, 0666); + m |= O_BINARY; #endif - if (fd < 0) { - TIFFErrorExt(0, module, "%s: Cannot open", name); - return ((TIFF *)0); - } - - tif = TIFFFdOpen((int)fd, name, mode); - if(!tif) - close(fd); - return tif; + + fd = open(name, m, 0666); + if (fd < 0) + { + if (errno > 0 && strerror(errno) != NULL) + { + _TIFFErrorEarly(opts, NULL, module, "%s: %s", name, + strerror(errno)); + } + else + { + _TIFFErrorEarly(opts, NULL, module, "%s: Cannot open", name); + } + return ((TIFF *)0); + } + + tif = TIFFFdOpenExt((int)fd, name, mode, opts); + if (!tif) + close(fd); + return tif; } #ifdef __WIN32__ @@ -186,115 +263,108 @@ TIFFOpen(const char* name, const char* mode) /* * Open a TIFF file with a Unicode filename, for read/writing. */ -TIFF* -TIFFOpenW(const wchar_t* name, const char* mode) +TIFF *TIFFOpenW(const wchar_t *name, const char *mode) +{ + return TIFFOpenWExt(name, mode, NULL); +} +TIFF *TIFFOpenWExt(const wchar_t *name, const char *mode, TIFFOpenOptions *opts) { - static const char module[] = "TIFFOpenW"; - int m, fd; - int mbsize; - char *mbname; - TIFF* tif; + static const char module[] = "TIFFOpenW"; + int m, fd; + int mbsize; + char *mbname; + TIFF *tif; - m = _TIFFgetMode(mode, module); - if (m == -1) - return ((TIFF*)0); + m = _TIFFgetMode(opts, NULL, mode, module); + if (m == -1) + return ((TIFF *)0); -/* for cygwin and mingw */ +/* for cygwin and mingw */ #ifdef O_BINARY - m |= O_BINARY; -#endif - - fd = _wopen(name, m, 0666); - if (fd < 0) { - 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 = _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((int)fd, (mbname != NULL) ? mbname : "", - mode); - - _TIFFfree(mbname); - - if(!tif) - close(fd); - return tif; -} + m |= O_BINARY; #endif -void* -_TIFFmalloc(tsize_t s) -{ - return (malloc((size_t) s)); + fd = _wopen(name, m, 0666); + if (fd < 0) + { + _TIFFErrorEarly(opts, NULL, module, "%ls: Cannot open", name); + return ((TIFF *)0); + } + + mbname = NULL; + mbsize = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL); + if (mbsize > 0) + { + mbname = _TIFFmalloc(mbsize); + if (!mbname) + { + _TIFFErrorEarly( + opts, NULL, module, + "Can't allocate space for filename conversion buffer"); + return ((TIFF *)0); + } + + WideCharToMultiByte(CP_ACP, 0, name, -1, mbname, mbsize, NULL, NULL); + } + + tif = TIFFFdOpenExt((int)fd, (mbname != NULL) ? mbname : "", mode, + opts); + + _TIFFfree(mbname); + + if (!tif) + close(fd); + return tif; } +#endif -void -_TIFFfree(tdata_t p) +void *_TIFFmalloc(tmsize_t s) { - free(p); -} + if (s == 0) + return ((void *)NULL); -void* -_TIFFrealloc(tdata_t p, tsize_t s) -{ - return (realloc(p, (size_t) s)); + return (malloc((size_t)s)); } -void -_TIFFmemset(tdata_t p, int v, tsize_t c) +void *_TIFFcalloc(tmsize_t nmemb, tmsize_t siz) { - memset(p, v, (size_t) c); + if (nmemb == 0 || siz == 0) + return ((void *)NULL); + + return calloc((size_t)nmemb, (size_t)siz); } -void -_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) +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); + memcpy(d, s, (size_t)c); } -int -_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +int _TIFFmemcmp(const void *p1, const void *p2, tmsize_t c) { - return (memcmp(p1, p2, (size_t) c)); + return (memcmp(p1, p2, (size_t)c)); } -static void -unixWarningHandler(const char* module, const char* fmt, va_list ap) +static void unixWarningHandler(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"); + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); } TIFFErrorHandler _TIFFwarningHandler = unixWarningHandler; -static void -unixErrorHandler(const char* module, const char* fmt, va_list ap) +static void unixErrorHandler(const char *module, const char *fmt, va_list ap) { - if (module != NULL) - fprintf(stderr, "%s: ", module); - vfprintf(stderr, fmt, ap); - fprintf(stderr, ".\n"); + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); } TIFFErrorHandler _TIFFerrorHandler = unixErrorHandler; -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ diff --git a/LibTiff/tif_version.c b/LibTiff/tif_version.c index 218dab56..0b6c9bc0 100644 --- a/LibTiff/tif_version.c +++ b/LibTiff/tif_version.c @@ -1,40 +1,28 @@ -/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_version.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ /* * Copyright (c) 1992-1997 Sam Leffler * Copyright (c) 1992-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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" static const char TIFFVersion[] = TIFFLIB_VERSION_STR; -const char* -TIFFGetVersion(void) -{ - return (TIFFVersion); -} -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ +const char *TIFFGetVersion(void) { return (TIFFVersion); } diff --git a/LibTiff/tif_warning.c b/LibTiff/tif_warning.c index fe974d90..5468de55 100644 --- a/LibTiff/tif_warning.c +++ b/LibTiff/tif_warning.c @@ -1,26 +1,24 @@ -/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_warning.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,51 +29,77 @@ TIFFErrorHandlerExt _TIFFwarningHandlerExt = NULL; -TIFFErrorHandler -TIFFSetWarningHandler(TIFFErrorHandler handler) +TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler handler) { - TIFFErrorHandler prev = _TIFFwarningHandler; - _TIFFwarningHandler = handler; - return (prev); + TIFFErrorHandler prev = _TIFFwarningHandler; + _TIFFwarningHandler = handler; + return (prev); } -TIFFErrorHandlerExt -TIFFSetWarningHandlerExt(TIFFErrorHandlerExt handler) +TIFFErrorHandlerExt TIFFSetWarningHandlerExt(TIFFErrorHandlerExt handler) { - TIFFErrorHandlerExt prev = _TIFFwarningHandlerExt; - _TIFFwarningHandlerExt = handler; - return (prev); + TIFFErrorHandlerExt prev = _TIFFwarningHandlerExt; + _TIFFwarningHandlerExt = handler; + return (prev); } -void -TIFFWarning(const char* module, const char* fmt, ...) +void TIFFWarning(const char *module, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - if (_TIFFwarningHandler) - (*_TIFFwarningHandler)(module, fmt, ap); - if (_TIFFwarningHandlerExt) - (*_TIFFwarningHandlerExt)(0, module, fmt, ap); - va_end(ap); + 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 -TIFFWarningExt(thandle_t fd, const char* module, const char* fmt, ...) +void TIFFWarningExt(thandle_t fd, const char *module, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - if (_TIFFwarningHandler) - (*_TIFFwarningHandler)(module, fmt, ap); - if (_TIFFwarningHandlerExt) - (*_TIFFwarningHandlerExt)(fd, module, fmt, ap); - va_end(ap); + 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: - */ +void TIFFWarningExtR(TIFF *tif, const char *module, const char *fmt, ...) +{ + va_list ap; + if (tif && tif->tif_warnhandler) + { + va_start(ap, fmt); + int stop = (*tif->tif_warnhandler)(tif, tif->tif_warnhandler_user_data, + module, fmt, ap); + va_end(ap); + if (stop) + return; + } + if (_TIFFwarningHandler) + { + va_start(ap, fmt); + (*_TIFFwarningHandler)(module, fmt, ap); + va_end(ap); + } + if (_TIFFwarningHandlerExt) + { + va_start(ap, fmt); + (*_TIFFwarningHandlerExt)(tif ? tif->tif_clientdata : 0, module, fmt, + ap); + va_end(ap); + } +} diff --git a/LibTiff/tif_webp.c b/LibTiff/tif_webp.c new file mode 100644 index 00000000..bf9d77eb --- /dev/null +++ b/LibTiff/tif_webp.c @@ -0,0 +1,881 @@ +/* + * Copyright (c) 2018, Mapbox + * Author: + * + * 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 WEBP_SUPPORT +/* + * TIFF Library. + * + * WEBP Compression Support + * + */ + +#include "webp/decode.h" +#include "webp/encode.h" + +#include +#include + +#define LSTATE_INIT_DECODE 0x01 +#define LSTATE_INIT_ENCODE 0x02 +/* + * State block for each open TIFF + * file using WEBP compression/decompression. + */ +typedef struct +{ + uint16_t nSamples; /* number of samples per pixel */ + + int lossless; /* lossy/lossless compression */ + int lossless_exact; /* lossless exact mode. If TRUE, R,G,B values in areas + with alpha = 0 will be preserved */ + int quality_level; /* compression level */ + WebPPicture sPicture; /* WebP Picture */ + WebPConfig sEncoderConfig; /* WebP encoder config */ + uint8_t *pBuffer; /* buffer to hold raw data on encoding */ + unsigned int buffer_offset; /* current offset into the buffer */ + unsigned int buffer_size; + + WebPIDecoder *psDecoder; /* WebPIDecoder */ + WebPDecBuffer sDecBuffer; /* Decoder buffer */ + int last_y; /* Last row decoded */ + + int state; /* state flags */ + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +} WebPState; + +#define LState(tif) ((WebPState *)(tif)->tif_data) +#define DecoderState(tif) LState(tif) +#define EncoderState(tif) LState(tif) + +static int TWebPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); +static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); + +static int TWebPDatasetWriter(const uint8_t *data, size_t data_size, + const WebPPicture *const picture) +{ + static const char module[] = "TWebPDatasetWriter"; + TIFF *tif = (TIFF *)(picture->custom_ptr); + + if ((tif->tif_rawcc + (tmsize_t)data_size) > tif->tif_rawdatasize) + { + TIFFErrorExtR( + tif, module, "Buffer too small by %" TIFF_SIZE_FORMAT " bytes.", + (size_t)(tif->tif_rawcc + data_size - tif->tif_rawdatasize)); + return 0; + } + else + { + _TIFFmemcpy(tif->tif_rawcp, data, data_size); + tif->tif_rawcc += data_size; + tif->tif_rawcp += data_size; + return 1; + } +} + +/* + * Encode a chunk of pixels. + */ +static int TWebPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "TWebPEncode"; + WebPState *sp = EncoderState(tif); + (void)s; + + assert(sp != NULL); + assert(sp->state == LSTATE_INIT_ENCODE); + + if ((uint64_t)sp->buffer_offset + (uint64_t)cc > sp->buffer_size) + { + TIFFErrorExtR(tif, module, "Too many bytes to be written"); + return 0; + } + + memcpy(sp->pBuffer + sp->buffer_offset, bp, cc); + sp->buffer_offset += (unsigned)cc; + + return 1; +} + +static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) +{ + static const char module[] = "WebPDecode"; + VP8StatusCode status = VP8_STATUS_OK; + WebPState *sp = DecoderState(tif); + uint32_t segment_width, segment_height; + bool decode_whole_strile = false; + + (void)s; + + assert(sp != NULL); + assert(sp->state == LSTATE_INIT_DECODE); + + if (sp->psDecoder == NULL) + { + TIFFDirectory *td = &tif->tif_dir; + uint32_t buffer_size; + + if (isTiled(tif)) + { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + } + 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; + } + + int webp_width, webp_height; + if (!WebPGetInfo(tif->tif_rawcp, + (uint64_t)tif->tif_rawcc > UINT32_MAX + ? UINT32_MAX + : (uint32_t)tif->tif_rawcc, + &webp_width, &webp_height)) + { + TIFFErrorExtR(tif, module, "WebPGetInfo() failed"); + return 0; + } + if ((uint32_t)webp_width != segment_width || + (uint32_t)webp_height != segment_height) + { + TIFFErrorExtR( + tif, module, "WebP blob dimension is %dx%d. Expected %ux%u", + webp_width, webp_height, segment_width, segment_height); + return 0; + } + +#if WEBP_DECODER_ABI_VERSION >= 0x0002 + WebPDecoderConfig config; + if (!WebPInitDecoderConfig(&config)) + { + TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed"); + return 0; + } + + const bool bWebPGetFeaturesOK = + WebPGetFeatures(tif->tif_rawcp, + (uint64_t)tif->tif_rawcc > UINT32_MAX + ? UINT32_MAX + : (uint32_t)tif->tif_rawcc, + &config.input) == VP8_STATUS_OK; + + WebPFreeDecBuffer(&config.output); + + if (!bWebPGetFeaturesOK) + { + TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed"); + return 0; + } + + const int webp_bands = config.input.has_alpha ? 4 : 3; + if (webp_bands != sp->nSamples && + /* We accept the situation where the WebP blob has only 3 bands, + * whereas the raster is 4 bands. This can happen when the alpha + * channel is fully opaque, and WebP decoding works fine in that + * situation. + */ + !(webp_bands == 3 && sp->nSamples == 4)) + { + TIFFErrorExtR(tif, module, + "WebP blob band count is %d. Expected %d", webp_bands, + sp->nSamples); + return 0; + } +#endif + + buffer_size = segment_width * segment_height * sp->nSamples; + if (occ == (tmsize_t)buffer_size) + { + /* If decoding the whole strip/tile, we can directly use the */ + /* output buffer */ + decode_whole_strile = true; + } + else if (sp->pBuffer == NULL || buffer_size > sp->buffer_size) + { + if (sp->pBuffer != NULL) + { + _TIFFfreeExt(tif, sp->pBuffer); + sp->pBuffer = NULL; + } + + sp->pBuffer = _TIFFmallocExt(tif, buffer_size); + if (!sp->pBuffer) + { + TIFFErrorExtR(tif, module, "Cannot allocate buffer"); + return 0; + } + sp->buffer_size = buffer_size; + } + + sp->last_y = 0; + + WebPInitDecBuffer(&sp->sDecBuffer); + + sp->sDecBuffer.is_external_memory = 1; + sp->sDecBuffer.width = segment_width; + sp->sDecBuffer.height = segment_height; + sp->sDecBuffer.u.RGBA.rgba = decode_whole_strile ? op : sp->pBuffer; + sp->sDecBuffer.u.RGBA.stride = segment_width * sp->nSamples; + sp->sDecBuffer.u.RGBA.size = buffer_size; + + if (sp->nSamples > 3) + { + sp->sDecBuffer.colorspace = MODE_RGBA; + } + else + { + sp->sDecBuffer.colorspace = MODE_RGB; + } + + sp->psDecoder = WebPINewDecoder(&sp->sDecBuffer); + + if (sp->psDecoder == NULL) + { + TIFFErrorExtR(tif, module, "Unable to allocate WebP decoder."); + return 0; + } + } + + if (occ % sp->sDecBuffer.u.RGBA.stride) + { + TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); + return 0; + } + + status = WebPIAppend(sp->psDecoder, tif->tif_rawcp, tif->tif_rawcc); + + if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) + { + if (status == VP8_STATUS_INVALID_PARAM) + { + TIFFErrorExtR(tif, module, "Invalid parameter used."); + } + else if (status == VP8_STATUS_OUT_OF_MEMORY) + { + TIFFErrorExtR(tif, module, "Out of memory."); + } + else + { + TIFFErrorExtR(tif, module, "Unrecognized error."); + } + return 0; + } + else + { + int current_y, stride; + uint8_t *buf; + + /* Returns the RGB/A image decoded so far */ + buf = WebPIDecGetRGB(sp->psDecoder, ¤t_y, NULL, NULL, &stride); + + if ((buf != NULL) && + (occ <= (tmsize_t)stride * (current_y - sp->last_y))) + { + const int numberOfExpectedLines = + (int)(occ / sp->sDecBuffer.u.RGBA.stride); + if (decode_whole_strile) + { + if (current_y != numberOfExpectedLines) + { + TIFFErrorExtR(tif, module, + "Unable to decode WebP data: less lines than " + "expected."); + return 0; + } + } + else + { + memcpy(op, buf + (sp->last_y * stride), occ); + } + + tif->tif_rawcp += tif->tif_rawcc; + tif->tif_rawcc = 0; + sp->last_y += numberOfExpectedLines; + + if (decode_whole_strile) + { + /* We can now free the decoder as we're completely done */ + if (sp->psDecoder != NULL) + { + WebPIDelete(sp->psDecoder); + WebPFreeDecBuffer(&sp->sDecBuffer); + sp->psDecoder = NULL; + } + } + return 1; + } + else + { + TIFFErrorExtR(tif, module, "Unable to decode WebP data."); + return 0; + } + } +} + +static int TWebPFixupTags(TIFF *tif) +{ + (void)tif; + if (tif->tif_dir.td_planarconfig != PLANARCONFIG_CONTIG) + { + static const char module[] = "TWebPFixupTags"; + TIFFErrorExtR(tif, module, + "TIFF WEBP requires data to be stored contiguously in " + "RGB e.g. RGBRGBRGB " +#if WEBP_ENCODER_ABI_VERSION >= 0x0100 + "or RGBARGBARGBA" +#endif + ); + return 0; + } + return 1; +} + +static int TWebPSetupDecode(TIFF *tif) +{ + static const char module[] = "WebPSetupDecode"; + uint16_t nBitsPerSample = tif->tif_dir.td_bitspersample; + uint16_t sampleFormat = tif->tif_dir.td_sampleformat; + + WebPState *sp = DecoderState(tif); + assert(sp != NULL); + + sp->nSamples = tif->tif_dir.td_samplesperpixel; + + /* check band count */ + if (sp->nSamples != 3 +#if WEBP_ENCODER_ABI_VERSION >= 0x0100 + && sp->nSamples != 4 +#endif + ) + { + TIFFErrorExtR(tif, module, + "WEBP driver doesn't support %d bands. Must be 3 (RGB) " +#if WEBP_ENCODER_ABI_VERSION >= 0x0100 + "or 4 (RGBA) " +#endif + "bands.", + sp->nSamples); + return 0; + } + + /* check bits per sample and data type */ + if ((nBitsPerSample != 8) && (sampleFormat != 1)) + { + TIFFErrorExtR(tif, module, "WEBP driver requires 8 bit unsigned data"); + return 0; + } + + /* if we were last encoding, terminate this mode */ + if (sp->state & LSTATE_INIT_ENCODE) + { + WebPPictureFree(&sp->sPicture); + if (sp->pBuffer != NULL) + { + _TIFFfreeExt(tif, sp->pBuffer); + sp->pBuffer = NULL; + } + sp->buffer_offset = 0; + sp->state = 0; + } + + sp->state |= LSTATE_INIT_DECODE; + + return 1; +} + +/* + * Setup state for decoding a strip. + */ +static int TWebPPreDecode(TIFF *tif, uint16_t s) +{ + static const char module[] = "TWebPPreDecode"; + uint32_t segment_width, segment_height; + WebPState *sp = DecoderState(tif); + TIFFDirectory *td = &tif->tif_dir; + (void)s; + assert(sp != NULL); + + if (isTiled(tif)) + { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + } + 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; + } + + if (segment_width > 16383 || segment_height > 16383) + { + TIFFErrorExtR(tif, module, + "WEBP maximum image dimensions are 16383 x 16383."); + return 0; + } + + if ((sp->state & LSTATE_INIT_DECODE) == 0) + tif->tif_setupdecode(tif); + + if (sp->psDecoder != NULL) + { + WebPIDelete(sp->psDecoder); + WebPFreeDecBuffer(&sp->sDecBuffer); + sp->psDecoder = NULL; + } + + return 1; +} + +static int TWebPSetupEncode(TIFF *tif) +{ + static const char module[] = "WebPSetupEncode"; + uint16_t nBitsPerSample = tif->tif_dir.td_bitspersample; + uint16_t sampleFormat = tif->tif_dir.td_sampleformat; + + WebPState *sp = EncoderState(tif); + assert(sp != NULL); + + sp->nSamples = tif->tif_dir.td_samplesperpixel; + + /* check band count */ + if (sp->nSamples != 3 +#if WEBP_ENCODER_ABI_VERSION >= 0x0100 + && sp->nSamples != 4 +#endif + ) + { + TIFFErrorExtR(tif, module, + "WEBP driver doesn't support %d bands. Must be 3 (RGB) " +#if WEBP_ENCODER_ABI_VERSION >= 0x0100 + "or 4 (RGBA) " +#endif + "bands.", + sp->nSamples); + return 0; + } + + /* check bits per sample and data type */ + if ((nBitsPerSample != 8) || (sampleFormat != SAMPLEFORMAT_UINT)) + { + TIFFErrorExtR(tif, module, "WEBP driver requires 8 bit unsigned data"); + return 0; + } + + if (sp->state & LSTATE_INIT_DECODE) + { + WebPIDelete(sp->psDecoder); + WebPFreeDecBuffer(&sp->sDecBuffer); + sp->psDecoder = NULL; + sp->last_y = 0; + sp->state = 0; + } + + sp->state |= LSTATE_INIT_ENCODE; + + if (!WebPPictureInit(&sp->sPicture)) + { + TIFFErrorExtR(tif, module, "Error initializing WebP picture."); + return 0; + } + + if (!WebPConfigInitInternal(&sp->sEncoderConfig, WEBP_PRESET_DEFAULT, + (float)sp->quality_level, + WEBP_ENCODER_ABI_VERSION)) + { + TIFFErrorExtR(tif, module, + "Error creating WebP encoder configuration."); + return 0; + } + +// WebPConfigInitInternal above sets lossless to false +#if WEBP_ENCODER_ABI_VERSION >= 0x0100 + sp->sEncoderConfig.lossless = sp->lossless; + if (sp->lossless) + { + sp->sPicture.use_argb = 1; +#if WEBP_ENCODER_ABI_VERSION >= 0x0209 + sp->sEncoderConfig.exact = sp->lossless_exact; +#endif + } +#endif + + if (!WebPValidateConfig(&sp->sEncoderConfig)) + { + TIFFErrorExtR(tif, module, "Error with WebP encoder configuration."); + return 0; + } + + return 1; +} + +/* + * Reset encoding state at the start of a strip. + */ +static int TWebPPreEncode(TIFF *tif, uint16_t s) +{ + static const char module[] = "TWebPPreEncode"; + uint32_t segment_width, segment_height; + WebPState *sp = EncoderState(tif); + TIFFDirectory *td = &tif->tif_dir; + + (void)s; + + assert(sp != NULL); + if (sp->state != LSTATE_INIT_ENCODE) + tif->tif_setupencode(tif); + + /* + * Set encoding parameters for this strip/tile. + */ + if (isTiled(tif)) + { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + } + 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; + } + + if (segment_width > 16383 || segment_height > 16383) + { + TIFFErrorExtR(tif, module, + "WEBP maximum image dimensions are 16383 x 16383."); + return 0; + } + + /* set up buffer for raw data */ + /* given above check and that nSamples <= 4, buffer_size is <= 1 GB */ + sp->buffer_size = segment_width * segment_height * sp->nSamples; + + if (sp->pBuffer != NULL) + { + _TIFFfreeExt(tif, sp->pBuffer); + sp->pBuffer = NULL; + } + + sp->pBuffer = _TIFFmallocExt(tif, sp->buffer_size); + if (!sp->pBuffer) + { + TIFFErrorExtR(tif, module, "Cannot allocate buffer"); + return 0; + } + sp->buffer_offset = 0; + + sp->sPicture.width = segment_width; + sp->sPicture.height = segment_height; + sp->sPicture.writer = TWebPDatasetWriter; + sp->sPicture.custom_ptr = tif; + + return 1; +} + +/* + * Finish off an encoded strip by flushing it. + */ +static int TWebPPostEncode(TIFF *tif) +{ + static const char module[] = "WebPPostEncode"; + int64_t stride; + WebPState *sp = EncoderState(tif); + assert(sp != NULL); + + assert(sp->state == LSTATE_INIT_ENCODE); + + stride = (int64_t)sp->sPicture.width * sp->nSamples; + +#if WEBP_ENCODER_ABI_VERSION >= 0x0100 + if (sp->nSamples == 4) + { + if (!WebPPictureImportRGBA(&sp->sPicture, sp->pBuffer, (int)stride)) + { + TIFFErrorExtR(tif, module, "WebPPictureImportRGBA() failed"); + return 0; + } + } + else +#endif + if (!WebPPictureImportRGB(&sp->sPicture, sp->pBuffer, (int)stride)) + { + TIFFErrorExtR(tif, module, "WebPPictureImportRGB() failed"); + return 0; + } + + if (!WebPEncode(&sp->sEncoderConfig, &sp->sPicture)) + { + +#if WEBP_ENCODER_ABI_VERSION >= 0x0100 + const char *pszErrorMsg = NULL; + switch (sp->sPicture.error_code) + { + case VP8_ENC_ERROR_OUT_OF_MEMORY: + pszErrorMsg = "Out of memory"; + break; + case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY: + pszErrorMsg = "Out of memory while flushing bits"; + break; + case VP8_ENC_ERROR_NULL_PARAMETER: + pszErrorMsg = "A pointer parameter is NULL"; + break; + case VP8_ENC_ERROR_INVALID_CONFIGURATION: + pszErrorMsg = "Configuration is invalid"; + break; + case VP8_ENC_ERROR_BAD_DIMENSION: + pszErrorMsg = "Picture has invalid width/height"; + break; + case VP8_ENC_ERROR_PARTITION0_OVERFLOW: + pszErrorMsg = "Partition is bigger than 512k. Try using less " + "SEGMENTS, or increase PARTITION_LIMIT value"; + break; + case VP8_ENC_ERROR_PARTITION_OVERFLOW: + pszErrorMsg = "Partition is bigger than 16M"; + break; + case VP8_ENC_ERROR_BAD_WRITE: + pszErrorMsg = "Error while fludshing bytes"; + break; + case VP8_ENC_ERROR_FILE_TOO_BIG: + pszErrorMsg = "File is bigger than 4G"; + break; + case VP8_ENC_ERROR_USER_ABORT: + pszErrorMsg = "User interrupted"; + break; + default: + TIFFErrorExtR(tif, module, + "WebPEncode returned an unknown error code: %d", + sp->sPicture.error_code); + pszErrorMsg = "Unknown WebP error type."; + break; + } + TIFFErrorExtR(tif, module, "WebPEncode() failed : %s", pszErrorMsg); +#else + TIFFErrorExtR(tif, module, "Error in WebPEncode()"); +#endif + return 0; + } + + sp->sPicture.custom_ptr = NULL; + + if (!TIFFFlushData1(tif)) + { + TIFFErrorExtR(tif, module, "Error flushing TIFF WebP encoder."); + return 0; + } + + return 1; +} + +static void TWebPCleanup(TIFF *tif) +{ + WebPState *sp = LState(tif); + + assert(sp != 0); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->state & LSTATE_INIT_ENCODE) + { + WebPPictureFree(&sp->sPicture); + } + + if (sp->psDecoder != NULL) + { + WebPIDelete(sp->psDecoder); + WebPFreeDecBuffer(&sp->sDecBuffer); + sp->psDecoder = NULL; + sp->last_y = 0; + } + + if (sp->pBuffer != NULL) + { + _TIFFfreeExt(tif, sp->pBuffer); + sp->pBuffer = NULL; + } + + _TIFFfreeExt(tif, tif->tif_data); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int TWebPVSetField(TIFF *tif, uint32_t tag, va_list ap) +{ + static const char module[] = "WebPVSetField"; + WebPState *sp = LState(tif); + + switch (tag) + { + case TIFFTAG_WEBP_LEVEL: + sp->quality_level = (int)va_arg(ap, int); + if (sp->quality_level <= 0 || sp->quality_level > 100.0f) + { + TIFFWarningExtR(tif, module, + "WEBP_LEVEL should be between 1 and 100"); + } + return 1; + case TIFFTAG_WEBP_LOSSLESS: +#if WEBP_ENCODER_ABI_VERSION >= 0x0100 + sp->lossless = va_arg(ap, int); + if (sp->lossless) + { + sp->quality_level = 100; + } + return 1; +#else + TIFFErrorExtR( + tif, module, + "Need to upgrade WEBP driver, this version doesn't support " + "lossless compression."); + return 0; +#endif + case TIFFTAG_WEBP_LOSSLESS_EXACT: +#if WEBP_ENCODER_ABI_VERSION >= 0x0209 + sp->lossless_exact = va_arg(ap, int); + return 1; +#else + TIFFErrorExtR( + tif, module, + "Need to upgrade WEBP driver, this version doesn't support " + "lossless compression."); + return 0; +#endif + default: + return (*sp->vsetparent)(tif, tag, ap); + } + /*NOTREACHED*/ +} + +static int TWebPVGetField(TIFF *tif, uint32_t tag, va_list ap) +{ + WebPState *sp = LState(tif); + + switch (tag) + { + case TIFFTAG_WEBP_LEVEL: + *va_arg(ap, int *) = sp->quality_level; + break; + case TIFFTAG_WEBP_LOSSLESS: + *va_arg(ap, int *) = sp->lossless; + break; + case TIFFTAG_WEBP_LOSSLESS_EXACT: + *va_arg(ap, int *) = sp->lossless_exact; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return 1; +} + +static const TIFFField TWebPFields[] = { + {TIFFTAG_WEBP_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "WEBP quality", NULL}, + {TIFFTAG_WEBP_LOSSLESS, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "WEBP lossless/lossy", + NULL}, + {TIFFTAG_WEBP_LOSSLESS_EXACT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "WEBP exact lossless", + NULL}, +}; + +int TIFFInitWebP(TIFF *tif, int scheme) +{ + static const char module[] = "TIFFInitWebP"; + WebPState *sp; + + (void)scheme; + assert(scheme == COMPRESSION_WEBP); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, TWebPFields, TIFFArrayCount(TWebPFields))) + { + TIFFErrorExtR(tif, module, "Merging WebP codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(WebPState)); + if (tif->tif_data == NULL) + goto bad; + sp = LState(tif); + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = TWebPVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = TWebPVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->quality_level = 75; /* default comp. level */ + sp->lossless = 0; /* default to false */ + sp->lossless_exact = 1; /* exact lossless mode (if lossless enabled) */ + sp->state = 0; + sp->nSamples = 0; + sp->psDecoder = NULL; + sp->last_y = 0; + + sp->buffer_offset = 0; + sp->pBuffer = NULL; + + /* + * Install codec methods. + * Notes: + * encoderow is not supported + */ + tif->tif_fixuptags = TWebPFixupTags; + tif->tif_setupdecode = TWebPSetupDecode; + tif->tif_predecode = TWebPPreDecode; + tif->tif_decoderow = TWebPDecode; + tif->tif_decodestrip = TWebPDecode; + tif->tif_decodetile = TWebPDecode; + tif->tif_setupencode = TWebPSetupEncode; + tif->tif_preencode = TWebPPreEncode; + tif->tif_postencode = TWebPPostEncode; + tif->tif_encoderow = TWebPEncode; + tif->tif_encodestrip = TWebPEncode; + tif->tif_encodetile = TWebPEncode; + tif->tif_cleanup = TWebPCleanup; + + return 1; +bad: + TIFFErrorExtR(tif, module, "No space for WebP state block"); + return 0; +} + +#endif /* WEBP_SUPPORT */ diff --git a/LibTiff/tif_win32.c b/LibTiff/tif_win32.c new file mode 100644 index 00000000..1a6b86df --- /dev/null +++ b/LibTiff/tif_win32.c @@ -0,0 +1,442 @@ +/* + * 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 + +#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) +{ + return TIFFFdOpenExt(ifd, name, mode, NULL); +} + +TIFF *TIFFFdOpenExt(int ifd, const char *name, const char *mode, + TIFFOpenOptions *opts) +{ + TIFF *tif; + int fSuppressMap; + int m; + + fSuppressMap = 0; + for (m = 0; mode[m] != 0; m++) + { + if (mode[m] == 'u') + { + fSuppressMap = 1; + break; + } + } + + tif = TIFFClientOpenExt( + name, mode, thandle_from_int(ifd), _tiffReadProc, _tiffWriteProc, + _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, + fSuppressMap ? _tiffDummyMapProc : _tiffMapProc, + fSuppressMap ? _tiffDummyUnmapProc : _tiffUnmapProc, opts); + 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) +{ + return TIFFOpenExt(name, mode, NULL); +} + +TIFF *TIFFOpenExt(const char *name, const char *mode, TIFFOpenOptions *opts) +{ + static const char module[] = "TIFFOpen"; + thandle_t fd; + int m; + DWORD dwMode; + TIFF *tif; + + m = _TIFFgetMode(opts, NULL, mode, module); + + switch (m) + { + case O_RDONLY: + dwMode = OPEN_EXISTING; + break; + case O_RDWR: + dwMode = OPEN_EXISTING; + 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) + { + _TIFFErrorEarly(opts, NULL, module, "%s: Cannot open", name); + return ((TIFF *)0); + } + + tif = TIFFFdOpenExt(thandle_to_int(fd), name, mode, opts); + 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) +{ + return TIFFOpenWExt(name, mode, NULL); +} + +TIFF *TIFFOpenWExt(const wchar_t *name, const char *mode, TIFFOpenOptions *opts) +{ + static const char module[] = "TIFFOpenW"; + thandle_t fd; + int m; + DWORD dwMode; + int mbsize; + char *mbname; + TIFF *tif; + + m = _TIFFgetMode(opts, NULL, mode, module); + + switch (m) + { + case O_RDONLY: + dwMode = OPEN_EXISTING; + break; + case O_RDWR: + dwMode = OPEN_EXISTING; + 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) + { + _TIFFErrorEarly(opts, NULL, 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) + { + _TIFFErrorEarly( + opts, NULL, module, + "Can't allocate space for filename conversion buffer"); + return ((TIFF *)0); + } + + WideCharToMultiByte(CP_ACP, 0, name, -1, mbname, mbsize, NULL, NULL); + } + + tif = TIFFFdOpenExt(thandle_to_int(fd), + (mbname != NULL) ? mbname : "", mode, opts); + 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 */ diff --git a/LibTiff/tif_write.c b/LibTiff/tif_write.c index bd084181..6631a782 100644 --- a/LibTiff/tif_write.c +++ b/LibTiff/tif_write.c @@ -1,26 +1,24 @@ -/* $Id: tif_write.c,v 1.22.2.5 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -32,144 +30,180 @@ #include "tiffiop.h" #include -#define STRIPINCR 20 /* expansion factor on strip array */ +#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, (tsize_t) -1)) +#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*, int, const char*); -static int TIFFAppendToStrip(TIFF*, tstrip_t, tidata_t, tsize_t); +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, tdata_t buf, uint32 row, tsample_t sample) +int TIFFWriteScanline(TIFF *tif, void *buf, uint32_t row, uint16_t sample) { - static const char module[] = "TIFFWriteScanline"; - register TIFFDirectory *td; - int status, imagegrew = 0; - tstrip_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); - 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, tif->tif_name, - "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, tif->tif_name, - "%d: Sample out of range, max %d", - sample, 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(td->td_imagelength,td->td_rowsperstrip); - 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[strip] > 0 ) - { - /* if we are writing over existing tiles, zero length */ - td->td_stripbytecount[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, (tidata_t) buf, tif->tif_scanlinesize ); + 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) + { + TIFFErrorExtR( + tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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; + } - status = (*tif->tif_encoderow)(tif, (tidata_t) buf, - tif->tif_scanlinesize, sample); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + /* this informs TIFFAppendToStrip() we have changed strip */ + 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); +} - /* 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; + } + } + return 1; } /* @@ -178,81 +212,112 @@ TIFFWriteScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample) * * NB: Image length must be setup before writing. */ -tsize_t -TIFFWriteEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc) +tmsize_t TIFFWriteEncodedStrip(TIFF *tif, uint32_t strip, void *data, + tmsize_t cc) { - static const char module[] = "TIFFWriteEncodedStrip"; - TIFFDirectory *td = &tif->tif_dir; - tsample_t sample; - - if (!WRITECHECKSTRIPS(tif, module)) - return ((tsize_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, tif->tif_name, - "Can not grow image by strips when using separate planes"); - return ((tsize_t) -1); - } - if (!TIFFGrowStrips(tif, 1, module)) - return ((tsize_t) -1); - td->td_stripsperimage = - TIFFhowmany(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 ((tsize_t) -1); - tif->tif_curstrip = strip; - tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; - if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { - if (!(*tif->tif_setupencode)(tif)) - return ((tsize_t) -1); - tif->tif_flags |= TIFF_CODERSETUP; - } - - tif->tif_rawcc = 0; - tif->tif_rawcp = tif->tif_rawdata; - - if( td->td_stripbytecount[strip] > 0 ) + 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) { - /* Force TIFFAppendToStrip() to consider placing data at end - of file. */ - tif->tif_curoff = 0; + TIFFErrorExtR( + tif, module, + "Can not grow image by strips when using separate planes"); + return ((tmsize_t)-1); } - - tif->tif_flags &= ~TIFF_POSTENCODE; - sample = (tsample_t)(strip / td->td_stripsperimage); - if (!(*tif->tif_preencode)(tif, sample)) - return ((tsize_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; + + /* this informs TIFFAppendToStrip() we have changed or reset strip */ + tif->tif_curoff = 0; + + if (!_TIFFReserveLargeEnoughWriteBuffer(tif, strip)) + { + return ((tmsize_t)(-1)); + } + + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + if (td->td_stripsperimage == 0) + { + TIFFErrorExtR(tif, 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, (tidata_t) data, cc ); - - if (!(*tif->tif_encodestrip)(tif, (tidata_t) data, cc, sample)) - return ((tsize_t) 0); - if (!(*tif->tif_postencode)(tif)) - return ((tsize_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 ((tsize_t) -1); - tif->tif_rawcc = 0; - tif->tif_rawcp = tif->tif_rawdata; - return (cc); + 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); } /* @@ -260,64 +325,78 @@ TIFFWriteEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc) * * NB: Image length must be setup before writing. */ -tsize_t -TIFFWriteRawStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc) +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 ((tsize_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, tif->tif_name, - "Can not grow image by strips when using separate planes"); - return ((tsize_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(td->td_imagelength,td->td_rowsperstrip); - if (!TIFFGrowStrips(tif, 1, module)) - return ((tsize_t) -1); - } - tif->tif_curstrip = strip; - tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; - return (TIFFAppendToStrip(tif, strip, (tidata_t) data, cc) ? - cc : (tsize_t) -1); + 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) + { + TIFFErrorExtR( + tif, 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); + } + + if (tif->tif_curstrip != strip) + { + tif->tif_curstrip = strip; + + /* this informs TIFFAppendToStrip() we have changed or reset strip */ + tif->tif_curoff = 0; + } + + if (td->td_stripsperimage == 0) + { + TIFFErrorExtR(tif, 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. */ -tsize_t -TIFFWriteTile(TIFF* tif, - tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t s) +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 (-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, (tsize_t) -1)); + 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))); } /* @@ -332,82 +411,114 @@ TIFFWriteTile(TIFF* tif, * interface does not support automatically growing * the image on each write (as TIFFWriteScanline does). */ -tsize_t -TIFFWriteEncodedTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc) +tmsize_t TIFFWriteEncodedTile(TIFF *tif, uint32_t tile, void *data, tmsize_t cc) { - static const char module[] = "TIFFWriteEncodedTile"; - TIFFDirectory *td; - tsample_t sample; - - if (!WRITECHECKTILES(tif, module)) - return ((tsize_t) -1); - td = &tif->tif_dir; - if (tile >= td->td_nstrips) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: Tile %lu out of range, max %lu", - tif->tif_name, (unsigned long) tile, (unsigned long) td->td_nstrips); - return ((tsize_t) -1); - } - /* - * Handle delayed allocation of data buffer. This - * permits it to be sized more intelligently (using - * directory information). - */ - if (!BUFFERCHECK(tif)) - return ((tsize_t) -1); - tif->tif_curtile = tile; - - tif->tif_rawcc = 0; - tif->tif_rawcp = tif->tif_rawdata; - - if( td->td_stripbytecount[tile] > 0 ) - { - /* Force TIFFAppendToStrip() to consider placing data at end - of file. */ - tif->tif_curoff = 0; - } - - /* - * Compute tiles per row & per column to compute - * current row and column - */ - tif->tif_row = (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) - * td->td_tilelength; - tif->tif_col = (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) - * td->td_tilewidth; - - if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { - if (!(*tif->tif_setupencode)(tif)) - return ((tsize_t) -1); - tif->tif_flags |= TIFF_CODERSETUP; - } - tif->tif_flags &= ~TIFF_POSTENCODE; - sample = (tsample_t)(tile/td->td_stripsperimage); - if (!(*tif->tif_preencode)(tif, sample)) - return ((tsize_t) -1); - /* - * 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; - + 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) + { + TIFFErrorExtR(tif, 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; + + /* this informs TIFFAppendToStrip() we have changed or reset tile */ + tif->tif_curoff = 0; + + 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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, (tidata_t) data, cc ); - - if (!(*tif->tif_encodetile)(tif, (tidata_t) data, cc, sample)) - return ((tsize_t) 0); - if (!(*tif->tif_postencode)(tif)) - return ((tsize_t) -1); - if (!isFillOrder(tif, td->td_fillorder) && - (tif->tif_flags & TIFF_NOBITREV) == 0) - TIFFReverseBits((unsigned char *)tif->tif_rawdata, tif->tif_rawcc); - if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile, - tif->tif_rawdata, tif->tif_rawcc)) - return ((tsize_t) -1); - tif->tif_rawcc = 0; - tif->tif_rawcp = tif->tif_rawdata; - return (cc); + 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); } /* @@ -419,57 +530,64 @@ TIFFWriteEncodedTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc) * interface does not support automatically growing * the image on each write (as TIFFWriteScanline does). */ -tsize_t -TIFFWriteRawTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc) +tmsize_t TIFFWriteRawTile(TIFF *tif, uint32_t tile, void *data, tmsize_t cc) { - static const char module[] = "TIFFWriteRawTile"; - - if (!WRITECHECKTILES(tif, module)) - return ((tsize_t) -1); - if (tile >= tif->tif_dir.td_nstrips) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: Tile %lu out of range, max %lu", - tif->tif_name, (unsigned long) tile, - (unsigned long) tif->tif_dir.td_nstrips); - return ((tsize_t) -1); - } - return (TIFFAppendToStrip(tif, tile, (tidata_t) data, cc) ? - cc : (tsize_t) -1); + static const char module[] = "TIFFWriteRawTile"; + + if (!WRITECHECKTILES(tif, module)) + return ((tmsize_t)(-1)); + if (tile >= tif->tif_dir.td_nstrips) + { + TIFFErrorExtR(tif, 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) +#define isUnspecified(tif, f) \ + (TIFFFieldSet(tif, f) && (tif)->tif_dir.td_imagelength == 0) -int -TIFFSetupStrips(TIFF* tif) +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; - if (td->td_planarconfig == PLANARCONFIG_SEPARATE) - td->td_stripsperimage /= td->td_samplesperpixel; - td->td_stripoffset = (uint32 *) - _TIFFmalloc(td->td_nstrips * sizeof (uint32)); - td->td_stripbytecount = (uint32 *) - _TIFFmalloc(td->td_nstrips * sizeof (uint32)); - if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL) - return (0); - /* - * Place data at the end-of-file - * (by setting offsets to zero). - */ - _TIFFmemset(td->td_stripoffset, 0, td->td_nstrips*sizeof (uint32)); - _TIFFmemset(td->td_stripbytecount, 0, td->td_nstrips*sizeof (uint32)); - TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); - TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); - return (1); + 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)) + { + TIFFErrorExtR(tif, "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 @@ -479,198 +597,325 @@ TIFFSetupStrips(TIFF* tif) * we also "freeze" the state of the directory so * that important information is not changed. */ -int -TIFFWriteCheck(TIFF* tif, int tiles, const char* module) +int TIFFWriteCheck(TIFF *tif, int tiles, const char *module) { - if (tif->tif_mode == O_RDONLY) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: File not open for writing", - tif->tif_name); - return (0); - } - if (tiles ^ isTiled(tif)) { - TIFFErrorExt(tif->tif_clientdata, tif->tif_name, tiles ? - "Can not write tiles to a stripped image" : - "Can not write scanlines to a tiled image"); - return (0); - } - - /* - * 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, - "%s: Must set \"ImageWidth\" before writing data", - tif->tif_name); - 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, - "%s: Must set \"PlanarConfiguration\" before writing data", - tif->tif_name); - return (0); - } - } - if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) { - tif->tif_dir.td_nstrips = 0; - TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for %s arrays", - tif->tif_name, isTiled(tif) ? "tile" : "strip"); - return (0); - } - tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1; - tif->tif_scanlinesize = TIFFScanlineSize(tif); - tif->tif_flags |= TIFF_BEENWRITING; - return (1); + if (tif->tif_mode == O_RDONLY) + { + TIFFErrorExtR(tif, module, "File not open for writing"); + return (0); + } + if (tiles ^ isTiled(tif)) + { + TIFFErrorExtR(tif, 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)) + { + TIFFErrorExtR(tif, module, + "Must set \"ImageWidth\" before writing data"); + return (0); + } + if (tif->tif_dir.td_stripoffset_p == NULL && !TIFFSetupStrips(tif)) + { + tif->tif_dir.td_nstrips = 0; + TIFFErrorExtR(tif, 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, tdata_t bp, tsize_t size) +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 == (tsize_t) -1) { - size = (isTiled(tif) ? - tif->tif_tilesize : TIFFStripSize(tif)); - /* - * 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, "%s: No space for output buffer", - tif->tif_name); - return (0); - } - tif->tif_flags |= TIFF_MYBUFFER; - } else - tif->tif_flags &= ~TIFF_MYBUFFER; - tif->tif_rawdata = (tidata_t) bp; - tif->tif_rawdatasize = size; - tif->tif_rawcc = 0; - tif->tif_rawcp = tif->tif_rawdata; - tif->tif_flags |= TIFF_BUFFERSETUP; - return (1); + static const char module[] = "TIFFWriteBufferSetup"; + + if (tif->tif_rawdata) + { + if (tif->tif_flags & TIFF_MYBUFFER) + { + _TIFFfreeExt(tif, 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 = _TIFFmallocExt(tif, size); + if (bp == NULL) + { + TIFFErrorExtR(tif, 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, int delta, const char* module) +static int TIFFGrowStrips(TIFF *tif, uint32_t delta, const char *module) { - TIFFDirectory *td = &tif->tif_dir; - uint32 *new_stripoffset, *new_stripbytecount; - - assert(td->td_planarconfig == PLANARCONFIG_CONTIG); - new_stripoffset = (uint32*)_TIFFrealloc(td->td_stripoffset, - (td->td_nstrips + delta) * sizeof (uint32)); - new_stripbytecount = (uint32*)_TIFFrealloc(td->td_stripbytecount, - (td->td_nstrips + delta) * sizeof (uint32)); - 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, "%s: No space to expand strip arrays", - tif->tif_name); - return (0); - } - td->td_stripoffset = new_stripoffset; - td->td_stripbytecount = new_stripbytecount; - _TIFFmemset(td->td_stripoffset + td->td_nstrips, - 0, delta*sizeof (uint32)); - _TIFFmemset(td->td_stripbytecount + td->td_nstrips, - 0, delta*sizeof (uint32)); - td->td_nstrips += delta; - return (1); + TIFFDirectory *td = &tif->tif_dir; + uint64_t *new_stripoffset; + uint64_t *new_stripbytecount; + + assert(td->td_planarconfig == PLANARCONFIG_CONTIG); + new_stripoffset = (uint64_t *)_TIFFreallocExt( + tif, td->td_stripoffset_p, (td->td_nstrips + delta) * sizeof(uint64_t)); + new_stripbytecount = (uint64_t *)_TIFFreallocExt( + tif, td->td_stripbytecount_p, + (td->td_nstrips + delta) * sizeof(uint64_t)); + if (new_stripoffset == NULL || new_stripbytecount == NULL) + { + if (new_stripoffset) + _TIFFfreeExt(tif, new_stripoffset); + if (new_stripbytecount) + _TIFFfreeExt(tif, new_stripbytecount); + td->td_nstrips = 0; + TIFFErrorExtR(tif, 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, tstrip_t strip, tidata_t data, tsize_t cc) +static int TIFFAppendToStrip(TIFF *tif, uint32_t strip, uint8_t *data, + tmsize_t cc) { - static const char module[] = "TIFFAppendToStrip"; - TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "TIFFAppendToStrip"; + TIFFDirectory *td = &tif->tif_dir; + uint64_t m; + int64_t old_byte_count = -1; - if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) { - assert(td->td_nstrips > 0); + if (tif->tif_curoff == 0) + tif->tif_lastvalidoff = 0; - if( td->td_stripbytecount[strip] != 0 - && td->td_stripoffset[strip] != 0 - && td->td_stripbytecount[strip] >= cc ) - { - /* - * There is already tile data on disk, and the new tile - * data we have to 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[strip])) { - TIFFErrorExt(tif->tif_clientdata, module, - "Seek error at scanline %lu", - (unsigned long)tif->tif_row); - return (0); - } - } - else + 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])) { - /* - * Seek to end of file, and set that as our location to - * write this strip. - */ - td->td_stripoffset[strip] = TIFFSeekFile(tif, 0, SEEK_END); + TIFFErrorExtR(tif, module, "Seek error at scanline %lu", + (unsigned long)tif->tif_row); + return (0); } - tif->tif_curoff = td->td_stripoffset[strip]; - + tif->tif_lastvalidoff = + td->td_stripoffset_p[strip] + td->td_stripbytecount_p[strip]; + } + else + { /* - * We are starting a fresh strip/tile, so set the size to zero. + * Seek to end of file, and set that as our location to + * write this strip. */ - td->td_stripbytecount[strip] = 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 = tif->tif_curoff+cc; - td->td_stripbytecount[strip] += cc; - return (1); + 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 ((m < tif->tif_curoff) || (m < (uint64_t)cc)) + { + TIFFErrorExtR(tif, module, "Maximum TIFF file size exceeded"); + return (0); + } + + if (tif->tif_lastvalidoff != 0 && m > tif->tif_lastvalidoff && + td->td_stripbytecount_p[strip] > 0) + { + /* Ouch: we have detected that we are rewriting in place a strip/tile */ + /* with several calls to TIFFAppendToStrip(). The first call was with */ + /* a size smaller than the previous size of the strip/tile, so we */ + /* opted to rewrite in place, but a following call causes us to go */ + /* outsize of the strip/tile area, so we have to finally go for a */ + /* append-at-end-of-file strategy, and start by moving what we already + */ + /* wrote. */ + tmsize_t tempSize; + void *temp; + uint64_t offsetRead; + uint64_t offsetWrite; + uint64_t toCopy = td->td_stripbytecount_p[strip]; + + if (toCopy < 1024 * 1024) + tempSize = (tmsize_t)toCopy; + else + tempSize = 1024 * 1024; + + offsetRead = td->td_stripoffset_p[strip]; + offsetWrite = TIFFSeekFile(tif, 0, SEEK_END); + + m = offsetWrite + toCopy + cc; + if (!(tif->tif_flags & TIFF_BIGTIFF) && m != (uint32_t)m) + { + TIFFErrorExtR(tif, module, "Maximum TIFF file size exceeded"); + return (0); + } + + temp = _TIFFmallocExt(tif, tempSize); + if (temp == NULL) + { + TIFFErrorExtR(tif, module, "No space for output buffer"); + return (0); + } + + tif->tif_flags |= TIFF_DIRTYSTRIP; + + td->td_stripoffset_p[strip] = offsetWrite; + td->td_stripbytecount_p[strip] = 0; + + /* Move data written by previous calls to us at end of file */ + while (toCopy > 0) + { + if (!SeekOK(tif, offsetRead)) + { + TIFFErrorExtR(tif, module, "Seek error"); + _TIFFfreeExt(tif, temp); + return (0); + } + if (!ReadOK(tif, temp, tempSize)) + { + TIFFErrorExtR(tif, module, "Cannot read"); + _TIFFfreeExt(tif, temp); + return (0); + } + if (!SeekOK(tif, offsetWrite)) + { + TIFFErrorExtR(tif, module, "Seek error"); + _TIFFfreeExt(tif, temp); + return (0); + } + if (!WriteOK(tif, temp, tempSize)) + { + TIFFErrorExtR(tif, module, "Cannot write"); + _TIFFfreeExt(tif, temp); + return (0); + } + offsetRead += tempSize; + offsetWrite += tempSize; + td->td_stripbytecount_p[strip] += tempSize; + toCopy -= tempSize; + } + _TIFFfreeExt(tif, temp); + + /* Append the data of this call */ + offsetWrite += cc; + m = offsetWrite; + } + + if (!WriteOK(tif, data, cc)) + { + TIFFErrorExtR(tif, 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); } /* @@ -678,22 +923,28 @@ TIFFAppendToStrip(TIFF* tif, tstrip_t strip, tidata_t data, tsize_t cc) * called by ``encodestrip routines'' w/o concern * for infinite recursion. */ -int -TIFFFlushData1(TIFF* tif) +int TIFFFlushData1(TIFF *tif) { - if (tif->tif_rawcc > 0) { - if (!isFillOrder(tif, tif->tif_dir.td_fillorder) && - (tif->tif_flags & TIFF_NOBITREV) == 0) - TIFFReverseBits((unsigned char *)tif->tif_rawdata, - tif->tif_rawcc); - if (!TIFFAppendToStrip(tif, - isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip, - tif->tif_rawdata, tif->tif_rawcc)) - return (0); - tif->tif_rawcc = 0; - tif->tif_rawcp = tif->tif_rawdata; - } - return (1); + 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); } /* @@ -702,17 +953,8 @@ TIFFFlushData1(TIFF* tif) * (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) +void TIFFSetWriteOffset(TIFF *tif, toff_t off) { - tif->tif_curoff = off; + tif->tif_curoff = off; + tif->tif_lastvalidoff = 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/LibTiff/tif_zip.c b/LibTiff/tif_zip.c index 15091f8d..fcf51004 100644 --- a/LibTiff/tif_zip.c +++ b/LibTiff/tif_zip.c @@ -1,26 +1,24 @@ -/* $Id: tif_zip.c,v 1.11.2.4 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1995-1997 Sam Leffler * Copyright (c) 1995-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -31,24 +29,22 @@ * * ZIP (aka Deflate) Compression Support * - * This file is simply an interface to the zlib library written by + * 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: this code assumes the 1.0 API and also depends on - * the ability to write the zlib header multiple times (one per strip) - * which was not possible with versions prior to 0.95. Note also that - * older versions of this codec avoided this bug by supressing the header - * entirely. This means that files written with the old library cannot - * be read; they should be converted to a different compression scheme - * and then reconverted. + * of the library. * - * The data format used by the zlib library is described in the files - * zlib-3.1.doc, deflate-1.1.doc and gzip-4.1.doc, available in the - * directory ftp://ftp.uu.net/pub/archiving/zip/doc. The library was - * last found at ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib-0.99.tar.gz. + * 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 /* @@ -61,359 +57,675 @@ #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 */ +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 */ + 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) +#define ZState(tif) ((ZIPState *)(tif)->tif_data) +#define DecoderState(tif) ZState(tif) +#define EncoderState(tif) ZState(tif) -static int ZIPEncode(TIFF*, tidata_t, tsize_t, tsample_t); -static int ZIPDecode(TIFF*, tidata_t, tsize_t, tsample_t); +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 -ZIPSetupDecode(TIFF* tif) +static int ZIPFixupTags(TIFF *tif) { - ZIPState* sp = DecoderState(tif); - static const char module[] = "ZIPSetupDecode"; - - assert(sp != NULL); - - /* if we were last encoding, terminate this mode */ - if (sp->state & ZSTATE_INIT_ENCODE) { - deflateEnd(&sp->stream); - sp->state = 0; - } + (void)tif; + return (1); +} - if (inflateInit(&sp->stream) != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg); - return (0); - } else { - sp->state |= ZSTATE_INIT_DECODE; - 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) + { + TIFFErrorExtR(tif, 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, tsample_t s) +static int ZIPPreDecode(TIFF *tif, uint16_t s) { - ZIPState* sp = DecoderState(tif); - - (void) s; - assert(sp != NULL); + ZIPState *sp = DecoderState(tif); - if( (sp->state & ZSTATE_INIT_DECODE) == 0 ) - tif->tif_setupdecode( tif ); + (void)s; + assert(sp != NULL); - sp->stream.next_in = tif->tif_rawdata; - sp->stream.avail_in = tif->tif_rawcc; - return (inflateReset(&sp->stream) == Z_OK); -} + if ((sp->state & ZSTATE_INIT_DECODE) == 0) + tif->tif_setupdecode(tif); -static int -ZIPDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) -{ - ZIPState* sp = DecoderState(tif); - static const char module[] = "ZIPDecode"; - - (void) s; - assert(sp != NULL); - assert(sp->state == ZSTATE_INIT_DECODE); - - sp->stream.next_out = op; - sp->stream.avail_out = occ; - do { - int state = inflate(&sp->stream, Z_PARTIAL_FLUSH); - if (state == Z_STREAM_END) - break; - if (state == Z_DATA_ERROR) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Decoding error at scanline %d, %s", - tif->tif_name, tif->tif_row, sp->stream.msg); - if (inflateSync(&sp->stream) != Z_OK) - return (0); - continue; - } - if (state != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", - tif->tif_name, sp->stream.msg); - return (0); - } - } while (sp->stream.avail_out > 0); - if (sp->stream.avail_out != 0) { - TIFFErrorExt(tif->tif_clientdata, module, - "%s: Not enough data at scanline %d (short %d bytes)", - tif->tif_name, tif->tif_row, sp->stream.avail_out); - return (0); - } - return (1); +#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 -ZIPSetupEncode(TIFF* tif) +static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) { - ZIPState* sp = EncoderState(tif); - static const char module[] = "ZIPSetupEncode"; + 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; + } - assert(sp != NULL); - if (sp->state & ZSTATE_INIT_DECODE) { - inflateEnd(&sp->stream); - sp->state = 0; + /* 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) + { + TIFFErrorExtR(tif, 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; + /* coverity[overrun-buffer-arg] */ + 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) + { + TIFFErrorExtR(tif, module, "Decoding error at scanline %lu, %s", + (unsigned long)tif->tif_row, SAFE_MSG(sp)); + return (0); } + if (state != Z_OK) + { + TIFFErrorExtR(tif, module, "ZLib error: %s", SAFE_MSG(sp)); + return (0); + } + } while (occ > 0); + if (occ != 0) + { + TIFFErrorExtR(tif, 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); +} - if (deflateInit(&sp->stream, sp->zipquality) != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg); - return (0); - } else { - sp->state |= ZSTATE_INIT_ENCODE; - 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) + { + TIFFErrorExtR(tif, 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, tsample_t s) +static int ZIPPreEncode(TIFF *tif, uint16_t s) { - ZIPState *sp = EncoderState(tif); + ZIPState *sp = EncoderState(tif); - (void) s; - assert(sp != NULL); - if( sp->state != ZSTATE_INIT_ENCODE ) - tif->tif_setupencode( tif ); + (void)s; + assert(sp != NULL); + if (sp->state != ZSTATE_INIT_ENCODE) + tif->tif_setupencode(tif); - sp->stream.next_out = tif->tif_rawdata; - sp->stream.avail_out = tif->tif_rawdatasize; - return (deflateReset(&sp->stream) == Z_OK); +#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, tidata_t bp, tsize_t cc, tsample_t s) +static int ZIPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - ZIPState *sp = EncoderState(tif); - static const char module[] = "ZIPEncode"; - - assert(sp != NULL); - assert(sp->state == ZSTATE_INIT_ENCODE); - - (void) s; - sp->stream.next_in = bp; - sp->stream.avail_in = cc; - do { - if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: Encoder error: %s", - tif->tif_name, sp->stream.msg); - return (0); - } - if (sp->stream.avail_out == 0) { - tif->tif_rawcc = tif->tif_rawdatasize; - TIFFFlushData1(tif); - sp->stream.next_out = tif->tif_rawdata; - sp->stream.avail_out = tif->tif_rawdatasize; - } - } while (sp->stream.avail_in > 0); - return (1); + 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, 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; + /* coverity[overrun-buffer-arg] */ + if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) + { + TIFFErrorExtR(tif, 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) -{ - ZIPState *sp = EncoderState(tif); - static const char module[] = "ZIPPostEncode"; - int state; - - sp->stream.avail_in = 0; - do { - state = deflate(&sp->stream, Z_FINISH); - switch (state) { - case Z_STREAM_END: - case Z_OK: - if ((int)sp->stream.avail_out != (int)tif->tif_rawdatasize) - { - tif->tif_rawcc = - tif->tif_rawdatasize - sp->stream.avail_out; - TIFFFlushData1(tif); - sp->stream.next_out = tif->tif_rawdata; - sp->stream.avail_out = tif->tif_rawdatasize; - } - break; - default: - TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", - tif->tif_name, sp->stream.msg); - return (0); - } - } while (state != Z_STREAM_END); - return (1); -} - -static void -ZIPCleanup(TIFF* tif) +static int ZIPPostEncode(TIFF *tif) { - ZIPState* sp = ZState(tif); + static const char module[] = "ZIPPostEncode"; + ZIPState *sp = EncoderState(tif); + int state; - assert(sp != 0); +#if LIBDEFLATE_SUPPORT + if (sp->libdeflate_state == 1) + return 1; +#endif - (void)TIFFPredictorCleanup(tif); + 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: + TIFFErrorExtR(tif, module, "ZLib error: %s", SAFE_MSG(sp)); + return (0); + } + } while (state != Z_STREAM_END); + return (1); +} - tif->tif_tagmethods.vgetfield = sp->vgetparent; - tif->tif_tagmethods.vsetfield = sp->vsetparent; +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 - 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; - } - _TIFFfree(sp); - tif->tif_data = NULL; + _TIFFfreeExt(tif, sp); + tif->tif_data = NULL; - _TIFFSetDefaultCompressionState(tif); + _TIFFSetDefaultCompressionState(tif); } -static int -ZIPVSetField(TIFF* tif, ttag_t tag, va_list ap) +static int ZIPVSetField(TIFF *tif, uint32_t tag, va_list ap) { - ZIPState* sp = ZState(tif); - static const char module[] = "ZIPVSetField"; - - switch (tag) { - case TIFFTAG_ZIPQUALITY: - sp->zipquality = va_arg(ap, int); - if ( sp->state&ZSTATE_INIT_ENCODE ) { - if (deflateParams(&sp->stream, - sp->zipquality, Z_DEFAULT_STRATEGY) != Z_OK) { - TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s", - tif->tif_name, sp->stream.msg); - return (0); - } - } - return (1); - default: - return (*sp->vsetparent)(tif, tag, ap); - } - /*NOTREACHED*/ + 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) + { + TIFFErrorExtR( + tif, 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) + { + TIFFErrorExtR(tif, 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) + { + TIFFErrorExtR(tif, module, "Invalid DeflateCodec value."); + return 0; + } +#if !LIBDEFLATE_SUPPORT + if (sp->subcodec == DEFLATE_SUBCODEC_LIBDEFLATE) + { + TIFFErrorExtR(tif, 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, ttag_t tag, va_list ap) +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; - default: - return (*sp->vgetparent)(tif, tag, ap); - } - return (1); + 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 TIFFFieldInfo zipFieldInfo[] = { - { TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, FIELD_PSEUDO, - TRUE, FALSE, "" }, +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) +int TIFFInitZIP(TIFF *tif, int scheme) { - static const char module[] = "TIFFInitZIP"; - ZIPState* sp; - - assert( (scheme == COMPRESSION_DEFLATE) - || (scheme == COMPRESSION_ADOBE_DEFLATE)); - - /* - * Merge codec-specific tag information. - */ - if (!_TIFFMergeFieldInfo(tif, zipFieldInfo, - TIFFArrayCount(zipFieldInfo))) { - 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 = (tidata_t) _TIFFmalloc(sizeof (ZIPState)); - 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; - - /* - * Install codec methods. - */ - 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); + 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))) + { + TIFFErrorExtR(tif, 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 *)_TIFFcallocExt(tif, 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); + TIFFErrorExtR(tif, module, "No space for ZIP state block"); + return (0); } -#endif /* ZIP_SUPORT */ - -/* vim: set ts=8 sts=8 sw=8 noet: */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ +#endif /* ZIP_SUPPORT */ diff --git a/LibTiff/tif_zstd.c b/LibTiff/tif_zstd.c new file mode 100644 index 00000000..64699310 --- /dev/null +++ b/LibTiff/tif_zstd.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2017, Planet Labs + * Author: + * + * 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 ZSTD_SUPPORT +/* + * TIFF Library. + * + * ZSTD Compression Support + * + */ + +#include "tif_predict.h" +#include "zstd.h" + +#include + +/* + * State block for each open TIFF file using ZSTD compression/decompression. + */ +typedef struct +{ + TIFFPredictorState predict; + ZSTD_DStream *dstream; + ZSTD_CStream *cstream; + int compression_level; /* compression level */ + ZSTD_outBuffer out_buffer; + int state; /* state flags */ +#define LSTATE_INIT_DECODE 0x01 +#define LSTATE_INIT_ENCODE 0x02 + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +} ZSTDState; + +#define LState(tif) ((ZSTDState *)(tif)->tif_data) +#define DecoderState(tif) LState(tif) +#define EncoderState(tif) LState(tif) + +static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); +static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); + +static int ZSTDFixupTags(TIFF *tif) +{ + (void)tif; + return 1; +} + +static int ZSTDSetupDecode(TIFF *tif) +{ + ZSTDState *sp = DecoderState(tif); + + assert(sp != NULL); + + /* if we were last encoding, terminate this mode */ + if (sp->state & LSTATE_INIT_ENCODE) + { + ZSTD_freeCStream(sp->cstream); + sp->cstream = NULL; + sp->state = 0; + } + + sp->state |= LSTATE_INIT_DECODE; + return 1; +} + +/* + * Setup state for decoding a strip. + */ +static int ZSTDPreDecode(TIFF *tif, uint16_t s) +{ + static const char module[] = "ZSTDPreDecode"; + ZSTDState *sp = DecoderState(tif); + size_t zstd_ret; + + (void)s; + assert(sp != NULL); + + if ((sp->state & LSTATE_INIT_DECODE) == 0) + tif->tif_setupdecode(tif); + + if (sp->dstream == NULL) + { + sp->dstream = ZSTD_createDStream(); + if (sp->dstream == NULL) + { + TIFFErrorExtR(tif, module, "Cannot allocate decompression stream"); + return 0; + } + } + + zstd_ret = ZSTD_initDStream(sp->dstream); + if (ZSTD_isError(zstd_ret)) + { + TIFFErrorExtR(tif, module, "Error in ZSTD_initDStream(): %s", + ZSTD_getErrorName(zstd_ret)); + return 0; + } + + return 1; +} + +static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) +{ + static const char module[] = "ZSTDDecode"; + ZSTDState *sp = DecoderState(tif); + ZSTD_inBuffer in_buffer; + ZSTD_outBuffer out_buffer; + size_t zstd_ret; + + (void)s; + assert(sp != NULL); + assert(sp->state == LSTATE_INIT_DECODE); + + in_buffer.src = tif->tif_rawcp; + in_buffer.size = (size_t)tif->tif_rawcc; + in_buffer.pos = 0; + + out_buffer.dst = op; + out_buffer.size = (size_t)occ; + out_buffer.pos = 0; + + do + { + zstd_ret = ZSTD_decompressStream(sp->dstream, &out_buffer, &in_buffer); + if (ZSTD_isError(zstd_ret)) + { + TIFFErrorExtR(tif, module, "Error in ZSTD_decompressStream(): %s", + ZSTD_getErrorName(zstd_ret)); + return 0; + } + } while (zstd_ret != 0 && in_buffer.pos < in_buffer.size && + out_buffer.pos < out_buffer.size); + + if (out_buffer.pos < (size_t)occ) + { + TIFFErrorExtR(tif, module, + "Not enough data at scanline %lu (short %lu bytes)", + (unsigned long)tif->tif_row, + (unsigned long)((size_t)occ - out_buffer.pos)); + return 0; + } + + tif->tif_rawcp += in_buffer.pos; + tif->tif_rawcc -= in_buffer.pos; + + return 1; +} + +static int ZSTDSetupEncode(TIFF *tif) +{ + ZSTDState *sp = EncoderState(tif); + + assert(sp != NULL); + if (sp->state & LSTATE_INIT_DECODE) + { + ZSTD_freeDStream(sp->dstream); + sp->dstream = NULL; + sp->state = 0; + } + + sp->state |= LSTATE_INIT_ENCODE; + return 1; +} + +/* + * Reset encoding state at the start of a strip. + */ +static int ZSTDPreEncode(TIFF *tif, uint16_t s) +{ + static const char module[] = "ZSTDPreEncode"; + ZSTDState *sp = EncoderState(tif); + size_t zstd_ret; + + (void)s; + assert(sp != NULL); + if (sp->state != LSTATE_INIT_ENCODE) + tif->tif_setupencode(tif); + + if (sp->cstream == NULL) + { + sp->cstream = ZSTD_createCStream(); + if (sp->cstream == NULL) + { + TIFFErrorExtR(tif, module, "Cannot allocate compression stream"); + return 0; + } + } + + zstd_ret = ZSTD_initCStream(sp->cstream, sp->compression_level); + if (ZSTD_isError(zstd_ret)) + { + TIFFErrorExtR(tif, module, "Error in ZSTD_initCStream(): %s", + ZSTD_getErrorName(zstd_ret)); + return 0; + } + + sp->out_buffer.dst = tif->tif_rawdata; + sp->out_buffer.size = (size_t)tif->tif_rawdatasize; + sp->out_buffer.pos = 0; + + return 1; +} + +/* + * Encode a chunk of pixels. + */ +static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) +{ + static const char module[] = "ZSTDEncode"; + ZSTDState *sp = EncoderState(tif); + ZSTD_inBuffer in_buffer; + size_t zstd_ret; + + assert(sp != NULL); + assert(sp->state == LSTATE_INIT_ENCODE); + + (void)s; + + in_buffer.src = bp; + in_buffer.size = (size_t)cc; + in_buffer.pos = 0; + + do + { + zstd_ret = + ZSTD_compressStream(sp->cstream, &sp->out_buffer, &in_buffer); + if (ZSTD_isError(zstd_ret)) + { + TIFFErrorExtR(tif, module, "Error in ZSTD_compressStream(): %s", + ZSTD_getErrorName(zstd_ret)); + return 0; + } + if (sp->out_buffer.pos == sp->out_buffer.size) + { + tif->tif_rawcc = tif->tif_rawdatasize; + if (!TIFFFlushData1(tif)) + return 0; + sp->out_buffer.dst = tif->tif_rawcp; + sp->out_buffer.pos = 0; + } + } while (in_buffer.pos < in_buffer.size); + + return 1; +} + +/* + * Finish off an encoded strip by flushing it. + */ +static int ZSTDPostEncode(TIFF *tif) +{ + static const char module[] = "ZSTDPostEncode"; + ZSTDState *sp = EncoderState(tif); + size_t zstd_ret; + + do + { + zstd_ret = ZSTD_endStream(sp->cstream, &sp->out_buffer); + if (ZSTD_isError(zstd_ret)) + { + TIFFErrorExtR(tif, module, "Error in ZSTD_endStream(): %s", + ZSTD_getErrorName(zstd_ret)); + return 0; + } + if (sp->out_buffer.pos > 0) + { + tif->tif_rawcc = sp->out_buffer.pos; + if (!TIFFFlushData1(tif)) + return 0; + sp->out_buffer.dst = tif->tif_rawcp; + sp->out_buffer.pos = 0; + } + } while (zstd_ret != 0); + return 1; +} + +static void ZSTDCleanup(TIFF *tif) +{ + ZSTDState *sp = LState(tif); + + assert(sp != 0); + + (void)TIFFPredictorCleanup(tif); + + tif->tif_tagmethods.vgetfield = sp->vgetparent; + tif->tif_tagmethods.vsetfield = sp->vsetparent; + + if (sp->dstream) + { + ZSTD_freeDStream(sp->dstream); + sp->dstream = NULL; + } + if (sp->cstream) + { + ZSTD_freeCStream(sp->cstream); + sp->cstream = NULL; + } + _TIFFfreeExt(tif, sp); + tif->tif_data = NULL; + + _TIFFSetDefaultCompressionState(tif); +} + +static int ZSTDVSetField(TIFF *tif, uint32_t tag, va_list ap) +{ + static const char module[] = "ZSTDVSetField"; + ZSTDState *sp = LState(tif); + + switch (tag) + { + case TIFFTAG_ZSTD_LEVEL: + sp->compression_level = (int)va_arg(ap, int); + if (sp->compression_level <= 0 || + sp->compression_level > ZSTD_maxCLevel()) + { + TIFFWarningExtR(tif, module, + "ZSTD_LEVEL should be between 1 and %d", + ZSTD_maxCLevel()); + } + return 1; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + /*NOTREACHED*/ +} + +static int ZSTDVGetField(TIFF *tif, uint32_t tag, va_list ap) +{ + ZSTDState *sp = LState(tif); + + switch (tag) + { + case TIFFTAG_ZSTD_LEVEL: + *va_arg(ap, int *) = sp->compression_level; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return 1; +} + +static const TIFFField ZSTDFields[] = { + {TIFFTAG_ZSTD_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "ZSTD compression_level", + NULL}, +}; + +int TIFFInitZSTD(TIFF *tif, int scheme) +{ + static const char module[] = "TIFFInitZSTD"; + ZSTDState *sp; + + (void)scheme; + assert(scheme == COMPRESSION_ZSTD); + + /* + * Merge codec-specific tag information. + */ + if (!_TIFFMergeFields(tif, ZSTDFields, TIFFArrayCount(ZSTDFields))) + { + TIFFErrorExtR(tif, module, "Merging ZSTD codec-specific tags failed"); + return 0; + } + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(ZSTDState)); + if (tif->tif_data == NULL) + goto bad; + sp = LState(tif); + + /* + * Override parent get/set field methods. + */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; + tif->tif_tagmethods.vgetfield = ZSTDVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_tagmethods.vsetfield; + tif->tif_tagmethods.vsetfield = ZSTDVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->compression_level = 9; /* default comp. level */ + sp->state = 0; + sp->dstream = 0; + sp->cstream = 0; + sp->out_buffer.dst = NULL; + sp->out_buffer.size = 0; + sp->out_buffer.pos = 0; + + /* + * Install codec methods. + */ + tif->tif_fixuptags = ZSTDFixupTags; + tif->tif_setupdecode = ZSTDSetupDecode; + tif->tif_predecode = ZSTDPreDecode; + tif->tif_decoderow = ZSTDDecode; + tif->tif_decodestrip = ZSTDDecode; + tif->tif_decodetile = ZSTDDecode; + tif->tif_setupencode = ZSTDSetupEncode; + tif->tif_preencode = ZSTDPreEncode; + tif->tif_postencode = ZSTDPostEncode; + tif->tif_encoderow = ZSTDEncode; + tif->tif_encodestrip = ZSTDEncode; + tif->tif_encodetile = ZSTDEncode; + tif->tif_cleanup = ZSTDCleanup; + /* + * Setup predictor setup. + */ + (void)TIFFPredictorInit(tif); + return 1; +bad: + TIFFErrorExtR(tif, module, "No space for ZSTD state block"); + return 0; +} +#endif /* ZSTD_SUPPORT */ diff --git a/LibTiff/tiff.h b/LibTiff/tiff.h index 0d4ab9f8..d8da33dc 100644 --- a/LibTiff/tiff.h +++ b/LibTiff/tiff.h @@ -1,31 +1,29 @@ -/* $Id: tiff.h,v 1.43.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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_ +#define _TIFF_ #include "tiffconf.h" @@ -39,86 +37,90 @@ * Suite 200 * Seattle, WA 98104 * 206-622-5500 - * + * * (http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf) * - * For Big TIFF design notes see the following link + * 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 42 -#define TIFF_BIGTIFF_VERSION 43 -#define TIFF_BIGENDIAN 0x4d4d -#define TIFF_LITTLEENDIAN 0x4949 -#define MDI_LITTLEENDIAN 0x5045 -#define MDI_BIGENDIAN 0x4550 +#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/uint8 - * 16-bit quantities int16/uint16 - * 32-bit quantities int32/uint32 - * strings unsigned char* + * 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* */ - -#ifndef HAVE_INT8 -typedef signed char int8; /* NB: non-ANSI compilers may not grok */ -#endif -typedef unsigned char uint8; -#ifndef HAVE_INT16 -typedef short int16; -#endif -typedef unsigned short uint16; /* sizeof (uint16) must == 2 */ -#if SIZEOF_INT == 4 -#ifndef HAVE_INT32 -typedef int int32; -#endif -typedef unsigned int uint32; /* sizeof (uint32) must == 4 */ -#elif SIZEOF_LONG == 4 -#ifndef HAVE_INT32 -typedef long int32; +#ifdef __GNUC__ +#define TIFF_GCC_DEPRECATED __attribute__((deprecated)) +#else +#define TIFF_GCC_DEPRECATED #endif -typedef unsigned long uint32; /* sizeof (uint32) must == 4 */ +#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 -/* For TIFFReassignTagToIgnore */ -enum TIFFIgnoreSense /* IGNORE tag table */ -{ - TIS_STORE, - TIS_EXTRACT, - TIS_EMPTY -}; +#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 */ /* - * TIFF header. + * 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 struct { - uint16 tiff_magic; /* magic number (defines byte order) */ -#define TIFF_MAGIC_SIZE 2 - uint16 tiff_version; /* TIFF version number */ -#define TIFF_VERSION_SIZE 2 - uint32 tiff_diroff; /* byte offset to first directory */ -#define TIFF_DIROFFSET_SIZE 4 -} TIFFHeader; +typedef int uint16_vap; /* - * 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, then it is placed in the offset - * field to save space. If the value is less than 4 bytes, it is - * left-justified in the offset field. + * TIFF header. */ -typedef struct { - uint16 tdir_tag; /* see below */ - uint16 tdir_type; /* data type; see below */ - uint32 tdir_count; /* number of items; length in spec */ - uint32 tdir_offset; /* byte offset to field data */ -} TIFFDirEntry; +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, @@ -133,383 +135,552 @@ typedef struct { * 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) */ +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_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 */ +/* clang-format off */ /* for better readability of tag comments */ +#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 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_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 pallette 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] */ +#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 matrice 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_XMLPACKET 700 /* %XML packet - [Adobe XMP Specification, - January 2004 */ -#define TIFFTAG_OPIIMAGEID 32781 /* %OPI ImageID - [Adobe TIFF technote] */ +#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] */ +/* For eiStream Annotation Specification, Version 1.00.06 see + * http://web.archive.org/web/20050309141348/http://www.kofile.com/support%20pro/faqs/annospec.htm */ +#define TIFFTAG_TIFFANNOTATIONDATA 32932 /* 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 */ +#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 */ +#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. + * 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_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_WRITERSERIALNUMBER 33405 /* device serial number */ +#define TIFFTAG_CFAREPEATPATTERNDIM 33421 /* (alias for TIFFTAG_EP_CFAREPEATPATTERNDIM)*/ +#define TIFFTAG_CFAPATTERN 33422 /* (alias for TIFFTAG_EP_CFAPATTERN) */ +#define TIFFTAG_BATTERYLEVEL 33423 /* (alias for TIFFTAG_EP_BATTERYLEVEL) */ /* tag 33432 is listed in the 6.0 spec w/ unknown ownership */ -#define TIFFTAG_COPYRIGHT 33432 /* copyright string */ +#define TIFFTAG_COPYRIGHT 33432 /* copyright string */ +/* Tags 33445-33452 are used for Molecular Dynamics GEL fileformat, + * see http://research.stowers-institute.org/mcm/efg/ScientificSoftware/Utility/TiffTags/GEL-FileFormat.pdf + * (2023: the above web site is unavailable but tags are explained briefly at + * https://www.awaresystems.be/imaging/tiff/tifftags/docs/gel.html + */ +#define TIFFTAG_MD_FILETAG 33445 /* Specifies the pixel data format encoding in the GEL file format. */ +#define TIFFTAG_MD_SCALEPIXEL 33446 /* scale factor */ +#define TIFFTAG_MD_COLORTABLE 33447 /* conversion from 16bit to 8bit */ +#define TIFFTAG_MD_LABNAME 33448 /* name of the lab that scanned this file. */ +#define TIFFTAG_MD_SAMPLEINFO 33449 /* information about the scanned GEL sample */ +#define TIFFTAG_MD_PREPDATE 33450 /* information about the date the sample was prepared YY/MM/DD */ +#define TIFFTAG_MD_PREPTIME 33451 /* information about the time the sample was prepared HH:MM*/ +#define TIFFTAG_MD_FILEUNITS 33452 /* Units for data in this file, as used in the GEL file format. */ /* IPTC TAG from RichTIFF specifications */ -#define TIFFTAG_RICHTIFFIPTC 33723 +#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 */ +#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_INTEROPERABILITYIFD 40965 /* Pointer to Interoperability private directory */ +#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 EXIF 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_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 (UTF-8) */ +#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 */ +/* TIFFTAG_BAYERGREENSPLIT: &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_BAYERGREENSPLIT 50733 +#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 (UTF-8) */ +#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 /* & */ + +/* DNG 1.2.0.0 */ +#define TIFFTAG_COLORIMETRICREFERENCE 50879 /* &colorimetric reference */ +#define TIFFTAG_CAMERACALIBRATIONSIGNATURE 50931 /* &camera calibration signature (UTF-8) */ +#define TIFFTAG_PROFILECALIBRATIONSIGNATURE 50932 /* &profile calibration signature (UTF-8) */ +/* TIFFTAG_EXTRACAMERAPROFILES 50933 &extra camera profiles : is already defined for GeoTIFF DGIWG */ +#define TIFFTAG_ASSHOTPROFILENAME 50934 /* &as shot profile name (UTF-8) */ +#define TIFFTAG_NOISEREDUCTIONAPPLIED 50935 /* &amount of applied noise reduction */ +#define TIFFTAG_PROFILENAME 50936 /* &camera profile name (UTF-8) */ +#define TIFFTAG_PROFILEHUESATMAPDIMS 50937 /* &dimensions of HSV mapping */ +#define TIFFTAG_PROFILEHUESATMAPDATA1 50938 /* &first HSV mapping table */ +#define TIFFTAG_PROFILEHUESATMAPDATA2 50939 /* &second HSV mapping table */ +#define TIFFTAG_PROFILETONECURVE 50940 /* &default tone curve */ +#define TIFFTAG_PROFILEEMBEDPOLICY 50941 /* &profile embedding policy */ +#define TIFFTAG_PROFILECOPYRIGHT 50942 /* &profile copyright information (UTF-8) */ +#define TIFFTAG_FORWARDMATRIX1 50964 /* &matrix for mapping white balanced camera colors to XYZ D50 */ +#define TIFFTAG_FORWARDMATRIX2 50965 /* &matrix for mapping white balanced camera colors to XYZ D50 */ +#define TIFFTAG_PREVIEWAPPLICATIONNAME 50966 /* &name of application that created preview (UTF-8) */ +#define TIFFTAG_PREVIEWAPPLICATIONVERSION 50967 /* &version of application that created preview (UTF-8) */ +#define TIFFTAG_PREVIEWSETTINGSNAME 50968 /* &name of conversion settings (UTF-8) */ +#define TIFFTAG_PREVIEWSETTINGSDIGEST 50969 /* &unique id of conversion settings */ +#define TIFFTAG_PREVIEWCOLORSPACE 50970 /* &preview color space */ +#define TIFFTAG_PREVIEWDATETIME 50971 /* &date/time preview was rendered */ +#define TIFFTAG_RAWIMAGEDIGEST 50972 /* &md5 of raw image data */ +#define TIFFTAG_ORIGINALRAWFILEDIGEST 50973 /* &md5 of the data stored in the OriginalRawFileData tag */ +#define TIFFTAG_SUBTILEBLOCKSIZE 50974 /* &subtile block size */ +#define TIFFTAG_ROWINTERLEAVEFACTOR 50975 /* &number of interleaved fields */ +#define TIFFTAG_PROFILELOOKTABLEDIMS 50981 /* &num of input samples in each dim of default "look" table */ +#define TIFFTAG_PROFILELOOKTABLEDATA 50982 /* &default "look" table for use as starting point */ + +/* DNG 1.3.0.0 */ +#define TIFFTAG_OPCODELIST1 51008 /* &opcodes that should be applied to raw image after reading */ +#define TIFFTAG_OPCODELIST2 51009 /* &opcodes that should be applied after mapping to linear reference */ +#define TIFFTAG_OPCODELIST3 51022 /* &opcodes that should be applied after demosaicing */ +#define TIFFTAG_NOISEPROFILE 51041 /* &noise profile */ + +/* DNG 1.4.0.0 */ +#define TIFFTAG_DEFAULTUSERCROP 51125 /* &default user crop rectangle in relative coords */ +#define TIFFTAG_DEFAULTBLACKRENDER 51110 /* &black rendering hint */ +#define TIFFTAG_BASELINEEXPOSUREOFFSET 51109 /* &baseline exposure offset */ +#define TIFFTAG_PROFILELOOKTABLEENCODING 51108 /* &3D LookTable indexing conversion */ +#define TIFFTAG_PROFILEHUESATMAPENCODING 51107 /* &3D HueSatMap indexing conversion */ +#define TIFFTAG_ORIGINALDEFAULTFINALSIZE 51089 /* &default final size of larger original file for this proxy */ +#define TIFFTAG_ORIGINALBESTQUALITYFINALSIZE 51090 /* &best quality final size of larger original file for this proxy */ +#define TIFFTAG_ORIGINALDEFAULTCROPSIZE 51091 /* &the default crop size of larger original file for this proxy */ +#define TIFFTAG_NEWRAWIMAGEDIGEST 51111 /* &modified MD5 digest of the raw image data */ +#define TIFFTAG_RAWTOPREVIEWGAIN 51112 /* &The gain between the main raw FD and the preview IFD containing this tag */ + +/* DNG 1.5.0.0 */ +#define TIFFTAG_DEPTHFORMAT 51177 /* &encoding of the depth data in the file */ +#define TIFFTAG_DEPTHNEAR 51178 /* &distance from the camera represented by value 0 in the depth map */ +#define TIFFTAG_DEPTHFAR 51179 /* &distance from the camera represented by the maximum value in the depth map */ +#define TIFFTAG_DEPTHUNITS 51180 /* &measurement units for DepthNear and DepthFar */ +#define TIFFTAG_DEPTHMEASURETYPE 51181 /* &measurement geometry for the depth map */ +#define TIFFTAG_ENHANCEPARAMS 51182 /* &a string that documents how the enhanced image data was processed. */ + +/* DNG 1.6.0.0 */ +#define TIFFTAG_PROFILEGAINTABLEMAP 52525 /* &spatially varying gain tables that can be applied as starting point */ +#define TIFFTAG_SEMANTICNAME 52526 /* &a string that identifies the semantic mask */ +#define TIFFTAG_SEMANTICINSTANCEID 52528 /* &a string that identifies a specific instance in a semantic mask */ +#define TIFFTAG_MASKSUBAREA 52536 /* &the crop rectangle of this IFD's mask, relative to the main image */ +#define TIFFTAG_RGBTABLES 52543 /* &color transforms to apply to masked image regions */ +#define TIFFTAG_CALIBRATIONILLUMINANT3 52529 /* &the illuminant used for the third set of color calibration tags */ +#define TIFFTAG_COLORMATRIX3 52531 /* &matrix to convert XYZ values to reference camera native color space under CalibrationIlluminant3 */ +#define TIFFTAG_CAMERACALIBRATION3 52530 /* &matrix to transform reference camera native space values to individual camera native space values under CalibrationIlluminant3 */ +#define TIFFTAG_REDUCTIONMATRIX3 52538 /* &dimensionality reduction matrix for use in color conversion to XYZ under CalibrationIlluminant3 */ +#define TIFFTAG_PROFILEHUESATMAPDATA3 52537 /* &the data for the third HSV table */ +#define TIFFTAG_FORWARDMATRIX3 52532 /* &matrix to map white balanced camera colors to XYZ D50 */ +#define TIFFTAG_ILLUMINANTDATA1 52533 /* &data for the first calibration illuminant */ +#define TIFFTAG_ILLUMINANTDATA2 52534 /* &data for the second calibration illuminant */ +#define TIFFTAG_ILLUMINANTDATA3 53535 /* &data for the third calibration illuminant */ + +/* TIFF/EP */ +#define TIFFTAG_EP_CFAREPEATPATTERNDIM 33421 /* dimensions of CFA pattern */ +#define TIFFTAG_EP_CFAPATTERN 33422 /* color filter array pattern */ +#define TIFFTAG_EP_BATTERYLEVEL 33423 /* battery level (rational or ASCII) */ +#define TIFFTAG_EP_INTERLACE 34857 /* Number of multi-field images */ +/* TIFFTAG_EP_IPTC_NAA and TIFFTAG_RICHTIFFIPTC share the same tag number (33723) + * LibTIFF type is UNDEFINED or BYTE, but often times incorrectly specified as LONG, + * because TIFF/EP (ISO/DIS 12234-2) specifies type LONG or ASCII. */ +#define TIFFTAG_EP_IPTC_NAA 33723 /* Alias IPTC/NAA Newspaper Association RichTIFF */ +#define TIFFTAG_EP_TIMEZONEOFFSET 34858 /* Time zone offset relative to UTC */ +#define TIFFTAG_EP_SELFTIMERMODE 34859 /* Number of seconds capture was delayed from button press */ +#define TIFFTAG_EP_FLASHENERGY 37387 /* Flash energy, or range if there is uncertainty */ +#define TIFFTAG_EP_SPATIALFREQUENCYRESPONSE 37388 /* Spatial frequency response */ +#define TIFFTAG_EP_NOISE 37389 /* Camera noise measurement values */ +#define TIFFTAG_EP_FOCALPLANEXRESOLUTION 37390 /* Focal plane X resolution */ +#define TIFFTAG_EP_FOCALPLANEYRESOLUTION 37391 /* Focal plane Y resolution */ +#define TIFFTAG_EP_FOCALPLANERESOLUTIONUNIT 37392 /* Focal plane resolution unit */ +#define TIFFTAG_EP_IMAGENUMBER 37393 /* Number of image when several of burst shot stored in same TIFF/EP */ +#define TIFFTAG_EP_SECURITYCLASSIFICATION 37394 /* Security classification */ +#define TIFFTAG_EP_IMAGEHISTORY 37395 /* Record of what has been done to the image */ +#define TIFFTAG_EP_EXPOSUREINDEX 37397 /* Exposure index */ +#define TIFFTAG_EP_STANDARDID 37398 /* TIFF/EP standard version, n.n.n.n */ +#define TIFFTAG_EP_SENSINGMETHOD 37399 /* Type of image sensor */ +/* + * TIFF/EP tags equivalent to EXIF tags + * Note that TIFF-EP and EXIF use nearly the same metadata tag set, but TIFF-EP stores the tags in IFD 0, + * while EXIF store the tags in a separate IFD. Either location is allowed by DNG, but the EXIF location is preferred. + */ +#define TIFFTAG_EP_EXPOSURETIME 33434 /* Exposure time */ +#define TIFFTAG_EP_FNUMBER 33437 /* F number */ +#define TIFFTAG_EP_EXPOSUREPROGRAM 34850 /* Exposure program */ +#define TIFFTAG_EP_SPECTRALSENSITIVITY 34852 /* Spectral sensitivity */ +#define TIFFTAG_EP_ISOSPEEDRATINGS 34855 /* ISO speed rating */ +#define TIFFTAG_EP_OECF 34856 /* Optoelectric conversion factor */ +#define TIFFTAG_EP_DATETIMEORIGINAL 36867 /* Date and time of original data generation */ +#define TIFFTAG_EP_COMPRESSEDBITSPERPIXEL 37122 /* Image compression mode */ +#define TIFFTAG_EP_SHUTTERSPEEDVALUE 37377 /* Shutter speed */ +#define TIFFTAG_EP_APERTUREVALUE 37378 /* Aperture */ +#define TIFFTAG_EP_BRIGHTNESSVALUE 37379 /* Brightness */ +#define TIFFTAG_EP_EXPOSUREBIASVALUE 37380 /* Exposure bias */ +#define TIFFTAG_EP_MAXAPERTUREVALUE 37381 /* Maximum lens aperture */ +#define TIFFTAG_EP_SUBJECTDISTANCE 37382 /* Subject distance */ +#define TIFFTAG_EP_METERINGMODE 37383 /* Metering mode */ +#define TIFFTAG_EP_LIGHTSOURCE 37384 /* Light source */ +#define TIFFTAG_EP_FLASH 37385 /* Flash */ +#define TIFFTAG_EP_FOCALLENGTH 37386 /* Lens focal length */ +#define TIFFTAG_EP_SUBJECTLOCATION 37396 /* Subject location (area) */ + +#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 */ +#define TIFFTAG_DCSHUESHIFTVALUES 65535 /* hue shift correction data */ /* * The following are ``pseudo tags'' that can be used to control @@ -522,133 +693,207 @@ typedef enum { * 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 */ +#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 */ +#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 */ +#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 */ +#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 */ +#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_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_WEBP_LOSSLESS_EXACT 65571 /* WebP lossless exact mode. Set-only mode. Default is 1. Can be set to 0 to increase compression rate, but R,G,B in areas where alpha = 0 will not be preserved */ +#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_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_GAINCONTROL 41991 /* Gain control */ -#define EXIFTAG_GAINCONTROL 41991 /* Gain control */ -#define EXIFTAG_IMAGEUNIQUEID 42016 /* Unique image ID */ +#define EXIFTAG_EXPOSURETIME 33434 /* Exposure time */ +#define EXIFTAG_FNUMBER 33437 /* F number */ +#define EXIFTAG_EXPOSUREPROGRAM 34850 /* Exposure program */ +#define EXIFTAG_SPECTRALSENSITIVITY 34852 /* Spectral sensitivity */ +/* After EXIF 2.2.1 ISOSpeedRatings is named PhotographicSensitivity. + In addition, while "Count=Any", only 1 count should be used. */ +#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 */ -#endif /* _TIFF_ */ +/*--: 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 ambientsituation at the shot in units of mGal (10-5 m/s^2) */ +/* EXIFTAG_CAMERAELEVATIONANGLE: 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_CAMERAELEVATIONANGLE 37893 +#define EXIFTAG_CAMERAOWNERNAME 42032 /* owner of a camera */ +#define EXIFTAG_BODYSERIALNUMBER 42033 /* serial number of the body of the camera */ +/* EXIFTAG_LENSSPECIFICATION: 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_LENSSPECIFICATION 42034 +#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 */ -/* vim: set ts=8 sts=8 sw=8 noet: */ /* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: + * 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_ */ diff --git a/LibTiff/tiffconf.h b/LibTiff/tiffconf.h index 3c78029f..d6449f84 100644 --- a/LibTiff/tiffconf.h +++ b/LibTiff/tiffconf.h @@ -4,43 +4,64 @@ from this file in your programs. */ +/* clang-format off */ +/* clang-format disabled because CMake scripts are very sensitive to the + * formatting of this file. configure_file variables of type "" are + * modified by clang-format and won't be substituted. + */ + #ifndef _TIFFCONF_ #define _TIFFCONF_ -/* Define to 1 if the system has the type `int16'. */ -/* #undef HAVE_INT16 */ - -/* Define to 1 if the system has the type `int32'. */ -/* #undef HAVE_INT32 */ -/* Define to 1 if the system has the type `int8'. */ -/* #undef HAVE_INT8 */ +#include +#include +#include -/* The size of a `int', as computed by sizeof. */ -#define SIZEOF_INT 4 -/* The size of a `long', as computed by sizeof. */ -#define SIZEOF_LONG 4 +/* Signed 16-bit type */ +#define TIFF_INT16_T int16_t -/* Signed 64-bit type formatter */ -#define TIFF_INT64_FORMAT "%I64d" +/* Signed 32-bit type */ +#define TIFF_INT32_T int32_t /* Signed 64-bit type */ -#define TIFF_INT64_T long long +#define TIFF_INT64_T int64_t -/* Unsigned 64-bit type formatter */ -#define TIFF_UINT64_FORMAT "%I64u" +/* Signed 8-bit type */ +#define TIFF_INT8_T int8_t + +/* Unsigned 16-bit type */ +#define TIFF_UINT16_T uint16_t + +/* Unsigned 32-bit type */ +#define TIFF_UINT32_T uint32_t /* Unsigned 64-bit type */ -#define TIFF_UINT64_T unsigned long long +#define TIFF_UINT64_T uint64_t + +/* Unsigned 8-bit type */ +#define TIFF_UINT8_T uint8_t + +/* Signed size type */ +#define TIFF_SSIZE_T int64_t /* Compatibility stuff. */ -/* Define as 0 or 1 according to the floating point format suported by the +/* 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) */ +/* The concept of HOST_FILLORDER is broken. Since libtiff 4.5.1 + * this macro will always be hardcoded to FILLORDER_LSB2MSB on all + * architectures, to reflect past long behavior of doing so on x86 architecture. + * Note however that the default FillOrder used by libtiff is FILLORDER_MSB2LSB, + * as mandated per the TIFF specification. + * The influence of HOST_FILLORDER is only when passing the 'H' mode in + * TIFFOpen(). + * You should NOT rely on this macro to decide the CPU endianness! + * This macro will be removed in libtiff 4.6 + */ #define HOST_FILLORDER FILLORDER_LSB2MSB /* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian @@ -79,7 +100,7 @@ /* #undef ZIP_SUPPORT */ /* Support strip chopping (whether or not to convert single-strip uncompressed - images to mutiple strips of ~8Kb to reduce memory usage) */ + images to multiple strips of ~8Kb to reduce memory usage) */ #define STRIPCHOP_DEFAULT TIFF_STRIPCHOP /* Enable SubIFD tag (330) support */ @@ -107,10 +128,5 @@ #define IPTC_SUPPORT #endif /* _TIFFCONF_ */ -/* - * Local Variables: - * mode: c - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ + +/* clang-format on */ diff --git a/LibTiff/tiffio.h b/LibTiff/tiffio.h index 06ec25c8..20460542 100644 --- a/LibTiff/tiffio.h +++ b/LibTiff/tiffio.h @@ -1,21 +1,19 @@ -/* $Id: tiffio.h,v 1.56.2.4 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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, @@ -25,7 +23,7 @@ */ #ifndef _TIFFIO_ -#define _TIFFIO_ +#define _TIFFIO_ /* * TIFF I/O Library Definitions. @@ -37,7 +35,7 @@ * TIFF is defined as an incomplete type to hide the * library's internal data structures from clients. */ -typedef struct tiff TIFF; +typedef struct tiff TIFF; /* * The following typedefs define the intrinsic size of @@ -52,21 +50,32 @@ typedef struct tiff TIFF; * 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 int32 and not uint32 because some functions + * 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 being the most important, and to ensure - * that it is unsigned, rather than signed. + * 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. */ -typedef uint32 ttag_t; /* directory tag */ -typedef uint16 tdir_t; /* directory index */ -typedef uint16 tsample_t; /* sample number */ -typedef uint32 tstrile_t; /* strip or tile number */ -typedef tstrile_t tstrip_t; /* strip number */ -typedef tstrile_t ttile_t; /* tile number */ -typedef int32 tsize_t; /* i/o size in bytes */ -typedef void* tdata_t; /* image data ref */ -typedef uint32 toff_t; /* file offset */ +/* + * 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 uint32_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__ @@ -80,21 +89,22 @@ typedef uint32 toff_t; /* file offset */ */ #if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) -# if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILEIO) -# define AVOID_WIN32_FILEIO -# endif +#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__ */ +#define VC_EXTRALEAN +#include +#ifdef __WIN32__ +DECLARE_HANDLE(thandle_t); /* Win32 file handle */ #else -typedef void* thandle_t; /* client data handle */ +typedef HFILE thandle_t; /* client data handle */ +#endif /* __WIN32__ */ +#else +typedef void *thandle_t; /* client data handle */ #endif /* USE_WIN32_FILEIO */ /* @@ -103,15 +113,15 @@ typedef void* thandle_t; /* client data handle */ * 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 */ - -/* +#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 */ @@ -126,42 +136,45 @@ typedef void* thandle_t; /* client data handle */ /* 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 d_Vrwr; /* Pixel values for ref. white */ - uint32 d_Vrwg; - uint32 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; +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* Cr_g_tab; - int32* Cb_g_tab; - int32* Y_tab; +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 */ +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 */ + 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; /* @@ -171,63 +184,69 @@ 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 + * 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*, uint32, uint32, uint32, uint32, int32, int32, - unsigned char*); -typedef void (*tileSeparateRoutine) - (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, - unsigned char*, unsigned char*, unsigned char*, unsigned char*); +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 width; /* image width */ - uint32 height; /* image height */ - uint16 bitspersample; /* image bits/sample */ - uint16 samplesperpixel; /* image samples/pixel */ - uint16 orientation; /* image orientation */ - uint16 req_orientation; /* requested orientation */ - uint16 photometric; /* image photometric interp */ - uint16* redcmap; /* colormap pallete */ - uint16* greencmap; - uint16* bluecmap; - /* get image data routine */ - int (*get)(TIFFRGBAImage*, uint32*, uint32, uint32); - /* put decoded strip/tile */ - union { - void (*any)(TIFFRGBAImage*); - tileContigRoutine contig; - tileSeparateRoutine separate; - } put; - TIFFRGBValue* Map; /* sample mapping array */ - uint32** BWmap; /* black&white map */ - uint32** PALmap; /* palette image map */ - TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */ - TIFFCIELabToRGB* cielab; /* CIE L*a*b conversion state */ - - int row_offset; - int col_offset; +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) +#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, @@ -236,291 +255,399 @@ struct _TIFFRGBAImage { * 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 scheme; - TIFFInitMethod init; +typedef int (*TIFFInitMethod)(TIFF *, int); +typedef struct +{ + char *name; + uint16_t scheme; + TIFFInitMethod init; } TIFFCodec; -#include +typedef struct +{ + uint32_t uNum; + uint32_t uDenom; +} TIFFRational_t; + #include +#include /* share internal LogLuv conversion routines? */ #ifndef LOGLUV_PUBLIC -#define LOGLUV_PUBLIC 1 +#define LOGLUV_PUBLIC 1 #endif -#if !defined(__GNUC__) && !defined(__attribute__) -# define __attribute__(x) /*nothing*/ +#if defined(__GNUC__) || defined(__clang__) || defined(__attribute__) +#define TIFF_ATTRIBUTE(x) __attribute__(x) +#else +#define TIFF_ATTRIBUTE(x) /*nothing*/ #endif #if defined(c_plusplus) || defined(__cplusplus) -extern "C" { +extern "C" +{ #endif -typedef void (*TIFFErrorHandler)(const char*, const char*, va_list); -typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list); -typedef tsize_t (*TIFFReadWriteProc)(thandle_t, tdata_t, tsize_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, tdata_t*, toff_t*); -typedef void (*TIFFUnmapFileProc)(thandle_t, tdata_t, toff_t); -typedef void (*TIFFExtendProc)(TIFF*); - -extern const char* TIFFGetVersion(void); - -extern const TIFFCodec* TIFFFindCODEC(uint16); -extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod); -extern void TIFFUnRegisterCODEC(TIFFCodec*); -extern int TIFFIsCODECConfigured(uint16); -extern TIFFCodec* TIFFGetConfiguredCODECs(void); - -/* - * Auxiliary functions. - */ - -extern tdata_t _TIFFmalloc(tsize_t); -extern tdata_t _TIFFrealloc(tdata_t, tsize_t); -extern void _TIFFmemset(tdata_t, int, tsize_t); -extern void _TIFFmemcpy(tdata_t, const tdata_t, tsize_t); -extern int _TIFFmemcmp(const tdata_t, const tdata_t, tsize_t); -extern void _TIFFfree(tdata_t); - -/* -** Stuff, related to tag handling and creating custom tags. -*/ -extern int TIFFGetTagListCount( TIFF * ); -extern ttag_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 var-length tags */ - -#define FIELD_CUSTOM 65 - -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; - -typedef struct _TIFFTagValue { - const TIFFFieldInfo *info; - int count; - void *value; -} TIFFTagValue; - -extern void TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], int); -extern const TIFFFieldInfo* TIFFFindFieldInfo(TIFF*, ttag_t, TIFFDataType); -extern const TIFFFieldInfo* TIFFFindFieldInfoByName(TIFF* , const char *, - TIFFDataType); -extern const TIFFFieldInfo* TIFFFieldWithTag(TIFF*, ttag_t); -extern const TIFFFieldInfo* TIFFFieldWithName(TIFF*, const char *); - -typedef int (*TIFFVSetMethod)(TIFF*, ttag_t, va_list); -typedef int (*TIFFVGetMethod)(TIFF*, ttag_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*); -extern void TIFFClose(TIFF*); -extern int TIFFFlush(TIFF*); -extern int TIFFFlushData(TIFF*); -extern int TIFFGetField(TIFF*, ttag_t, ...); -extern int TIFFVGetField(TIFF*, ttag_t, va_list); -extern int TIFFGetFieldDefaulted(TIFF*, ttag_t, ...); -extern int TIFFVGetFieldDefaulted(TIFF*, ttag_t, va_list); -extern int TIFFReadDirectory(TIFF*); -extern int TIFFReadCustomDirectory(TIFF*, toff_t, const TIFFFieldInfo[], - size_t); -extern int TIFFReadEXIFDirectory(TIFF*, toff_t); -extern tsize_t TIFFScanlineSize(TIFF*); -extern tsize_t TIFFOldScanlineSize(TIFF*); -extern tsize_t TIFFNewScanlineSize(TIFF*); -extern tsize_t TIFFRasterScanlineSize(TIFF*); -extern tsize_t TIFFStripSize(TIFF*); -extern tsize_t TIFFRawStripSize(TIFF*, tstrip_t); -extern tsize_t TIFFVStripSize(TIFF*, uint32); -extern tsize_t TIFFTileRowSize(TIFF*); -extern tsize_t TIFFTileSize(TIFF*); -extern tsize_t TIFFVTileSize(TIFF*, uint32); -extern uint32 TIFFDefaultStripSize(TIFF*, uint32); -extern void TIFFDefaultTileSize(TIFF*, uint32*, uint32*); -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 TIFFCurrentRow(TIFF*); -extern tdir_t TIFFCurrentDirectory(TIFF*); -extern tdir_t TIFFNumberOfDirectories(TIFF*); -extern uint32 TIFFCurrentDirOffset(TIFF*); -extern tstrip_t TIFFCurrentStrip(TIFF*); -extern ttile_t TIFFCurrentTile(TIFF*); -extern int TIFFReadBufferSetup(TIFF*, tdata_t, tsize_t); -extern int TIFFWriteBufferSetup(TIFF*, tdata_t, tsize_t); -extern int TIFFSetupStrips(TIFF *); -extern int TIFFWriteCheck(TIFF*, int, const char *); -extern void TIFFFreeDirectory(TIFF*); -extern int TIFFCreateDirectory(TIFF*); -extern int TIFFLastDirectory(TIFF*); -extern int TIFFSetDirectory(TIFF*, tdir_t); -extern int TIFFSetSubDirectory(TIFF*, uint32); -extern int TIFFUnlinkDirectory(TIFF*, tdir_t); -extern int TIFFSetField(TIFF*, ttag_t, ...); -extern int TIFFVSetField(TIFF*, ttag_t, va_list); -extern int TIFFWriteDirectory(TIFF *); -extern int TIFFCheckpointDirectory(TIFF *); -extern int TIFFRewriteDirectory(TIFF *); -extern int TIFFReassignTagToIgnore(enum TIFFIgnoreSense, int); + typedef void (*TIFFErrorHandler)(const char *, const char *, va_list); + typedef void (*TIFFErrorHandlerExt)(thandle_t, const char *, const char *, + va_list); + typedef int (*TIFFErrorHandlerExtR)(TIFF *, void *user_data, 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 *); + extern int + TIFFFieldSetGetSize(const TIFFField *); /* returns internal storage size of + TIFFSetGetFieldType in bytes. */ + extern int TIFFFieldSetGetCountSize( + const TIFFField *); /* returns size of count parameter 0=none, + 2=uint16_t, 4=uint32_t */ + extern int TIFFFieldIsAnonymous(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 TIFFGetField(TIFF *tif, uint32_t tag, ...); + extern int TIFFVGetField(TIFF *tif, uint32_t tag, va_list ap); + extern int 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 int TIFFIsBigTIFF(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 tdir_t TIFFCurrentDirectory(TIFF *); + extern tdir_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 *, tdir_t); + extern int TIFFSetSubDirectory(TIFF *, uint64_t); + extern int TIFFUnlinkDirectory(TIFF *, tdir_t); + extern int 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*, tdata_t, uint32, tsample_t = 0); -extern int TIFFWriteScanline(TIFF*, tdata_t, uint32, tsample_t = 0); -extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0); -extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, - int = ORIENTATION_BOTLEFT, int = 0); + 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*, tdata_t, uint32, tsample_t); -extern int TIFFWriteScanline(TIFF*, tdata_t, uint32, tsample_t); -extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int); -extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, int, int); +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*, tstrip_t, uint32 * ); -extern int TIFFReadRGBATile(TIFF*, uint32, uint32, uint32 * ); -extern int TIFFRGBAImageOK(TIFF*, char [1024]); -extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]); -extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32*, uint32, uint32); -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 TIFFError(const char*, const char*, ...) __attribute__((format (printf,2,3))); -extern void TIFFErrorExt(thandle_t, const char*, const char*, ...) __attribute__((format (printf,3,4))); -extern void TIFFWarning(const char*, const char*, ...) __attribute__((format (printf,2,3))); -extern void TIFFWarningExt(thandle_t, const char*, const char*, ...) __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 ttile_t TIFFComputeTile(TIFF*, uint32, uint32, uint32, tsample_t); -extern int TIFFCheckTile(TIFF*, uint32, uint32, uint32, tsample_t); -extern ttile_t TIFFNumberOfTiles(TIFF*); -extern tsize_t TIFFReadTile(TIFF*, - tdata_t, uint32, uint32, uint32, tsample_t); -extern tsize_t TIFFWriteTile(TIFF*, - tdata_t, uint32, uint32, uint32, tsample_t); -extern tstrip_t TIFFComputeStrip(TIFF*, uint32, tsample_t); -extern tstrip_t TIFFNumberOfStrips(TIFF*); -extern tsize_t TIFFReadEncodedStrip(TIFF*, tstrip_t, tdata_t, tsize_t); -extern tsize_t TIFFReadRawStrip(TIFF*, tstrip_t, tdata_t, tsize_t); -extern tsize_t TIFFReadEncodedTile(TIFF*, ttile_t, tdata_t, tsize_t); -extern tsize_t TIFFReadRawTile(TIFF*, ttile_t, tdata_t, tsize_t); -extern tsize_t TIFFWriteEncodedStrip(TIFF*, tstrip_t, tdata_t, tsize_t); -extern tsize_t TIFFWriteRawStrip(TIFF*, tstrip_t, tdata_t, tsize_t); -extern tsize_t TIFFWriteEncodedTile(TIFF*, ttile_t, tdata_t, tsize_t); -extern tsize_t TIFFWriteRawTile(TIFF*, ttile_t, tdata_t, tsize_t); -extern int TIFFDataWidth(TIFFDataType); /* table of tag datatype widths */ -extern void TIFFSetWriteOffset(TIFF*, toff_t); -extern void TIFFSwabShort(uint16*); -extern void TIFFSwabLong(uint32*); -extern void TIFFSwabDouble(double*); -extern void TIFFSwabArrayOfShort(uint16*, unsigned long); -extern void TIFFSwabArrayOfTriples(uint8*, unsigned long); -extern void TIFFSwabArrayOfLong(uint32*, unsigned long); -extern void TIFFSwabArrayOfDouble(double*, unsigned long); -extern void TIFFReverseBits(unsigned char *, unsigned long); -extern const unsigned char* TIFFGetBitRevTable(int); + 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 const char *TIFFFileName(TIFF *); + extern const char *TIFFSetFileName(TIFF *, const char *); + extern void TIFFError(const char *, const char *, ...) + TIFF_ATTRIBUTE((__format__(__printf__, 2, 3))); + extern void TIFFErrorExt(thandle_t, const char *, const char *, ...) + TIFF_ATTRIBUTE((__format__(__printf__, 3, 4))); + extern void TIFFWarning(const char *, const char *, ...) + TIFF_ATTRIBUTE((__format__(__printf__, 2, 3))); + extern void 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 void TIFFWarningExtR(TIFF *, const char *, const char *, ...) + TIFF_ATTRIBUTE((__format__(__printf__, 3, 4))); + extern void TIFFErrorExtR(TIFF *, const char *, const char *, ...) + TIFF_ATTRIBUTE((__format__(__printf__, 3, 4))); + + typedef struct TIFFOpenOptions TIFFOpenOptions; + extern TIFFOpenOptions *TIFFOpenOptionsAlloc(void); + extern void TIFFOpenOptionsFree(TIFFOpenOptions *); + extern void + TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts, + tmsize_t max_single_mem_alloc); + extern void + TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts, + TIFFErrorHandlerExtR handler, + void *errorhandler_user_data); + extern void + TIFFOpenOptionsSetWarningHandlerExtR(TIFFOpenOptions *opts, + TIFFErrorHandlerExtR handler, + void *warnhandler_user_data); + + extern TIFF *TIFFOpen(const char *, const char *); + extern TIFF *TIFFOpenExt(const char *, const char *, TIFFOpenOptions *opts); +#ifdef __WIN32__ + extern TIFF *TIFFOpenW(const wchar_t *, const char *); + extern TIFF *TIFFOpenWExt(const wchar_t *, const char *, + TIFFOpenOptions *opts); +#endif /* __WIN32__ */ + extern TIFF *TIFFFdOpen(int, const char *, const char *); + extern TIFF *TIFFFdOpenExt(int, const char *, const char *, + TIFFOpenOptions *opts); + extern TIFF *TIFFClientOpen(const char *, const char *, thandle_t, + TIFFReadWriteProc, TIFFReadWriteProc, + TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, + TIFFMapFileProc, TIFFUnmapFileProc); + extern TIFF *TIFFClientOpenExt(const char *, const char *, thandle_t, + TIFFReadWriteProc, TIFFReadWriteProc, + TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, + TIFFMapFileProc, TIFFUnmapFileProc, + TIFFOpenOptions *opts); + 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 within TIFF file. */ + 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*); -extern int uv_decode(double*, double*, int); -extern void LogLuv24toXYZ(uint32, float*); -extern void LogLuv32toXYZ(uint32, float*); +#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 LogLuv24fromXYZ(float*, int = SGILOGENCODE_NODITHER); -extern uint32 LogLuv32fromXYZ(float*, int = SGILOGENCODE_NODITHER); + 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 LogLuv24fromXYZ(float*, int); -extern uint32 LogLuv32fromXYZ(float*, int); + 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*, TIFFDisplay *, float*); -extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32, int32, int32, - float *, float *, float *); -extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float, - uint32 *, uint32 *, uint32 *); -extern int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float*, float*); -extern void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *, uint32, int32, int32, - uint32 *, uint32 *, uint32 *); + 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/LibTiff/tiffio.hxx b/LibTiff/tiffio.hxx index ee3fd32c..6182449b 100644 --- a/LibTiff/tiffio.hxx +++ b/LibTiff/tiffio.hxx @@ -1,49 +1,39 @@ -/* $Id: tiffio.hxx,v 1.1.2.1 2010-06-08 18:50:43 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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_HXX_ -#define _TIFFIO_HXX_ +#define _TIFFIO_HXX_ /* * TIFF I/O library definitions which provide C++ streams API. */ -#include #include "tiff.h" +#include "tiffio.h" +#include -extern TIFF* TIFFStreamOpen(const char*, std::ostream *); -extern TIFF* TIFFStreamOpen(const char*, std::istream *); +extern TIFF *TIFFStreamOpen(const char *, std::ostream *); +extern TIFF *TIFFStreamOpen(const char *, std::istream *); #endif /* _TIFFIO_HXX_ */ - -/* vim: set ts=8 sts=8 sw=8 noet: */ -/* - * Local Variables: - * mode: c++ - * c-basic-offset: 8 - * fill-column: 78 - * End: - */ diff --git a/LibTiff/tiffiop.h b/LibTiff/tiffiop.h index 6617877e..fbf7b070 100644 --- a/LibTiff/tiffiop.h +++ b/LibTiff/tiffiop.h @@ -1,350 +1,523 @@ -/* $Id: tiffiop.h,v 1.51.2.6 2010-06-12 02:55:16 bfriesen Exp $ */ - /* * Copyright (c) 1988-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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_ +#define _TIFFIOP_ /* * ``Library-private'' definitions. */ #include "tif_config.h" -#include "tiffio.h" #ifdef HAVE_FCNTL_H -# include +#include #endif #ifdef HAVE_SYS_TYPES_H -# include +#include #endif -#ifdef HAVE_STRING_H -# include -#endif +#include #ifdef HAVE_ASSERT_H -# include +#include #else -# define assert(x) +#define assert(x) #endif -#ifdef HAVE_SEARCH_H -# include -#else -extern void *lfind(const void *, const void *, size_t *, size_t, - int (*)(const void *, const void *)); -#endif - -/* - Libtiff itself does not require a 64-bit type, but bundled TIFF - utilities may use it. -*/ -typedef TIFF_INT64_T int64; -typedef TIFF_UINT64_T uint64; +#include "tif_hash_set.h" +#include "tiffio.h" #include "tif_dir.h" +#include + #ifndef STRIP_SIZE_DEFAULT -# define STRIP_SIZE_DEFAULT 8192 +#define STRIP_SIZE_DEFAULT 8192 #endif -#define streq(a,b) (strcmp(a,b) == 0) +#ifndef TIFF_MAX_DIR_COUNT +#define TIFF_MAX_DIR_COUNT 1048576 +#endif + +#define TIFF_NON_EXISTENT_DIR_NUMBER UINT_MAX + +#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 +#define TRUE 1 +#define FALSE 0 #endif -typedef struct client_info { +typedef struct client_info +{ struct client_info *next; - void *data; - char *name; + 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*, tsample_t); -typedef int (*TIFFCodeMethod)(TIFF*, tidata_t, tsize_t, tsample_t); -typedef int (*TIFFSeekMethod)(TIFF*, uint32); -typedef void (*TIFFPostMethod)(TIFF*, tidata_t, tsize_t); -typedef uint32 (*TIFFStripMethod)(TIFF*, uint32); -typedef void (*TIFFTileMethod)(TIFF*, uint32*, uint32*); - -struct tiff { - char* tif_name; /* name of open file */ - int tif_fd; /* open file descriptor */ - int tif_mode; /* open mode (O_*) */ - uint32 tif_flags; -#define TIFF_FILLORDER 0x00003 /* natural bit fill order for machine */ -#define TIFF_DIRTYHEADER 0x00004 /* header must be written on close */ -#define TIFF_DIRTYDIRECT 0x00008 /* current directory must be written */ -#define TIFF_BUFFERSETUP 0x00010 /* data buffers setup */ -#define TIFF_CODERSETUP 0x00020 /* encoder/decoder setup done */ -#define TIFF_BEENWRITING 0x00040 /* written 1+ scanlines to file */ -#define TIFF_SWAB 0x00080 /* byte swap file information */ -#define TIFF_NOBITREV 0x00100 /* inhibit bit reversal logic */ -#define TIFF_MYBUFFER 0x00200 /* my raw data buffer; free on close */ -#define TIFF_ISTILED 0x00400 /* file is tile, not strip- based */ -#define TIFF_MAPPED 0x00800 /* file is mapped into memory */ -#define TIFF_POSTENCODE 0x01000 /* need call to postencode routine */ -#define TIFF_INSUBIFD 0x02000 /* currently writing a subifd */ -#define TIFF_UPSAMPLED 0x04000 /* library is doing data up-sampling */ -#define TIFF_STRIPCHOP 0x08000 /* enable strip chopping support */ -#define TIFF_HEADERONLY 0x10000 /* read header only, do not process */ - /* the first directory */ -#define TIFF_NOREADRAW 0x20000 /* skip reading of raw uncompressed */ - /* image data */ -#define TIFF_INCUSTOMIFD 0x40000 /* currently writing a custom IFD */ - toff_t tif_diroff; /* file offset of current directory */ - toff_t tif_nextdiroff; /* file offset of following directory */ - toff_t* tif_dirlist; /* list of offsets to already seen */ - /* directories to prevent IFD looping */ - tsize_t tif_dirlistsize;/* number of entires in offset list */ - uint16 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 */ - TIFFHeader tif_header; /* file's header block */ - const int* tif_typeshift; /* data type shift counts */ - const long* tif_typemask; /* data type masks */ - uint32 tif_row; /* current scanline */ - tdir_t tif_curdir; /* current directory (index) */ - tstrip_t tif_curstrip; /* current strip for read/write */ - toff_t tif_curoff; /* current offset for read/write */ - toff_t tif_dataoff; /* current offset for writing dir */ -/* SubIFD support */ - uint16 tif_nsubifd; /* remaining subifds to write */ - toff_t tif_subifdoff; /* offset for patching SubIFD link */ -/* tiling support */ - uint32 tif_col; /* current column (offset by row too) */ - ttile_t tif_curtile; /* current tile for read/write */ - tsize_t tif_tilesize; /* # of bytes in a tile */ -/* compression scheme hooks */ - int tif_decodestatus; - 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 */ - tidata_t tif_data; /* compression scheme private data */ -/* input/output buffering */ - tsize_t tif_scanlinesize;/* # of bytes in a scanline */ - tsize_t tif_scanlineskew;/* scanline skew for reading strips */ - tidata_t tif_rawdata; /* raw data buffer */ - tsize_t tif_rawdatasize;/* # of bytes in raw data buffer */ - tidata_t tif_rawcp; /* current spot in raw buffer */ - tsize_t tif_rawcc; /* bytes unread from raw buffer */ -/* memory-mapped file support */ - tidata_t tif_base; /* base of mapped file */ - toff_t tif_size; /* size of mapped file region (bytes) - FIXME: it should be tsize_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 */ - TIFFFieldInfo** tif_fieldinfo; /* sorted table of registered tags */ - size_t tif_nfields; /* # entries in registered tag table */ - const TIFFFieldInfo *tif_foundfield;/* cached pointer to already found tag */ - TIFFTagMethods tif_tagmethods; /* tag get/set/print routines */ - TIFFClientInfoLink *tif_clientinfo; /* extra client information. */ +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 TIFFOffsetAndDirNumber +{ + uint64_t offset; + tdir_t dirNumber; +}; +typedef struct TIFFOffsetAndDirNumber TIFFOffsetAndDirNumber; + +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_lastdiroff; /* file offset of last directory written so far */ + TIFFHashSet *tif_map_dir_offset_to_number; + TIFFHashSet *tif_map_dir_number_to_offset; + int tif_setdirectory_force_absolute; /* switch between relative and absolute + stepping in TIFFSetDirectory() */ + 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 */ + tdir_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_lastvalidoff; /* last valid offset allowed for rewrite in + place. Used only by TIFFAppendToStrip() */ + 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; + /* Error handler support */ + TIFFErrorHandlerExtR tif_errorhandler; + void *tif_errorhandler_user_data; + TIFFErrorHandlerExtR tif_warnhandler; + void *tif_warnhandler_user_data; + tmsize_t tif_max_single_mem_alloc; /* in bytes. 0 for unlimited */ +}; + +struct TIFFOpenOptions +{ + TIFFErrorHandlerExtR errorhandler; /* may be NULL */ + void *errorhandler_user_data; /* may be NULL */ + TIFFErrorHandlerExtR warnhandler; /* may be NULL */ + void *warnhandler_user_data; /* may be NULL */ + tmsize_t max_single_mem_alloc; /* in bytes. 0 for unlimited */ }; -#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,(toff_t)(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)) +#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, (tdata_t) buf, (tsize_t)(size)) == (tsize_t)(size)) +#define ReadOK(tif, buf, size) (TIFFReadFile((tif), (buf), (size)) == (size)) #endif #ifndef SeekOK -#define SeekOK(tif, off) \ - (TIFFSeekFile(tif, (toff_t) off, SEEK_SET) == (toff_t) off) +#define SeekOK(tif, off) _TIFFSeekOK(tif, off) #endif #ifndef WriteOK -#define WriteOK(tif, buf, size) \ - (TIFFWriteFile(tif, (tdata_t) buf, (tsize_t) size) == (tsize_t) size) +#define WriteOK(tif, buf, size) (TIFFWriteFile((tif), (buf), (size)) == (size)) #endif -/* NB: the uint32 casts are to silence certain ANSI-C compilers */ -#define TIFFhowmany(x, y) (((uint32)x < (0xffffffff - (uint32)(y-1))) ? \ - ((((uint32)(x))+(((uint32)(y))-1))/((uint32)(y))) : \ - 0U) -#define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3) -#define TIFFroundup(x, y) (TIFFhowmany(x,y)*(y)) +/* 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])) -/* Safe multiply which returns zero if there is an integer overflow */ -#define TIFFSafeMultiply(t,v,m) ((((t)m != (t)0) && (((t)((v*m)/m)) == (t)v)) ? (t)(v*m) : (t)0) +/* + Support for large files. -#define TIFFmax(A,B) ((A)>(B)?(A):(B)) -#define TIFFmin(A,B) ((A)<(B)?(A):(B)) + 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 -#define TIFFArrayCount(a) (sizeof (a) / sizeof ((a)[0])) +#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" { +extern "C" +{ #endif -extern int _TIFFgetMode(const char*, const char*); -extern int _TIFFNoRowEncode(TIFF*, tidata_t, tsize_t, tsample_t); -extern int _TIFFNoStripEncode(TIFF*, tidata_t, tsize_t, tsample_t); -extern int _TIFFNoTileEncode(TIFF*, tidata_t, tsize_t, tsample_t); -extern int _TIFFNoRowDecode(TIFF*, tidata_t, tsize_t, tsample_t); -extern int _TIFFNoStripDecode(TIFF*, tidata_t, tsize_t, tsample_t); -extern int _TIFFNoTileDecode(TIFF*, tidata_t, tsize_t, tsample_t); -extern void _TIFFNoPostDecode(TIFF*, tidata_t, tsize_t); -extern int _TIFFNoPreCode (TIFF*, tsample_t); -extern int _TIFFNoSeek(TIFF*, uint32); -extern void _TIFFSwab16BitData(TIFF*, tidata_t, tsize_t); -extern void _TIFFSwab24BitData(TIFF*, tidata_t, tsize_t); -extern void _TIFFSwab32BitData(TIFF*, tidata_t, tsize_t); -extern void _TIFFSwab64BitData(TIFF*, tidata_t, tsize_t); -extern int TIFFFlushData1(TIFF*); -extern int TIFFDefaultDirectory(TIFF*); -extern void _TIFFSetDefaultCompressionState(TIFF*); -extern int TIFFSetCompressionScheme(TIFF*, int); -extern int TIFFSetDefaultCompressionState(TIFF*); -extern uint32 _TIFFDefaultStripSize(TIFF*, uint32); -extern void _TIFFDefaultTileSize(TIFF*, uint32*, uint32*); -extern int _TIFFDataSize(TIFFDataType); - -extern void _TIFFsetByteArray(void**, void*, uint32); -extern void _TIFFsetString(char**, char*); -extern void _TIFFsetShortArray(uint16**, uint16*, uint32); -extern void _TIFFsetLongArray(uint32**, uint32*, uint32); -extern void _TIFFsetFloatArray(float**, float*, uint32); -extern void _TIFFsetDoubleArray(double**, double*, uint32); - -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 tdata_t _TIFFCheckMalloc(TIFF*, size_t, size_t, const char*); -extern tdata_t _TIFFCheckRealloc(TIFF*, tdata_t, size_t, size_t, const char*); - -extern int TIFFInitDumpMode(TIFF*, int); + extern int _TIFFgetMode(TIFFOpenOptions *opts, thandle_t clientdata, + 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 void _TIFFsetByteArray(void **, const void *, uint32_t); + extern void _TIFFsetByteArrayExt(TIFF *, void **, const void *, uint32_t); + extern void _TIFFsetShortArray(uint16_t **, const uint16_t *, uint32_t); + extern void _TIFFsetShortArrayExt(TIFF *, uint16_t **, const uint16_t *, + uint32_t); + extern void _TIFFsetLongArray(uint32_t **, const uint32_t *, uint32_t); + extern void _TIFFsetLongArrayExt(TIFF *, uint32_t **, const uint32_t *, + uint32_t); + extern void _TIFFsetFloatArray(float **, const float *, uint32_t); + extern void _TIFFsetFloatArrayExt(TIFF *, float **, const float *, + uint32_t); + extern void _TIFFsetDoubleArray(double **, const double *, uint32_t); + extern void _TIFFsetDoubleArrayExt(TIFF *, double **, const 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; + void _TIFFErrorEarly(TIFFOpenOptions *opts, thandle_t clientdata, + const char *module, const char *fmt, ...) + TIFF_ATTRIBUTE((__format__(__printf__, 4, 5))); + + 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 uint32_t _TIFFClampDoubleToUInt32(double); + + extern void _TIFFCleanupIFDOffsetAndNumberMaps(TIFF *tif); + + 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); + 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); + 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); + extern int TIFFInitThunderScan(TIFF *, int); #endif #ifdef NEXT_SUPPORT -extern int TIFFInitNeXT(TIFF*, int); + extern int TIFFInitNeXT(TIFF *, int); #endif #ifdef LZW_SUPPORT -extern int TIFFInitLZW(TIFF*, int); + extern int TIFFInitLZW(TIFF *, int); #endif #ifdef OJPEG_SUPPORT -extern int TIFFInitOJPEG(TIFF*, int); + extern int TIFFInitOJPEG(TIFF *, int); #endif #ifdef JPEG_SUPPORT -extern int TIFFInitJPEG(TIFF*, int); + extern int TIFFInitJPEG(TIFF *, int); + extern int TIFFJPEGIsFullStripRequired(TIFF *); #endif #ifdef JBIG_SUPPORT -extern int TIFFInitJBIG(TIFF*, int); + extern int TIFFInitJBIG(TIFF *, int); #endif #ifdef ZIP_SUPPORT -extern int TIFFInitZIP(TIFF*, int); + extern int TIFFInitZIP(TIFF *, int); #endif #ifdef PIXARLOG_SUPPORT -extern int TIFFInitPixarLog(TIFF*, int); + extern int TIFFInitPixarLog(TIFF *, int); #endif #ifdef LOGLUV_SUPPORT -extern int TIFFInitSGILog(TIFF*, int); + extern int TIFFInitSGILog(TIFF *, int); #endif -#ifdef VMS -extern const TIFFCodec _TIFFBuiltinCODECS[]; -#else -extern TIFFCodec _TIFFBuiltinCODECS[]; +#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[]; + extern void TIFFCIELab16ToXYZ(TIFFCIELabToRGB *, uint32_t l, int32_t a, + int32_t b, float *, float *, float *); + + extern void *_TIFFmallocExt(TIFF *tif, tmsize_t s); + extern void *_TIFFcallocExt(TIFF *tif, tmsize_t nmemb, tmsize_t siz); + extern void *_TIFFreallocExt(TIFF *tif, void *p, tmsize_t s); + extern void _TIFFfreeExt(TIFF *tif, void *p); #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/LibTiff/tiffvers.h b/LibTiff/tiffvers.h index 314a22a0..4630580d 100644 --- a/LibTiff/tiffvers.h +++ b/LibTiff/tiffvers.h @@ -1,4 +1,14 @@ -#define TIFFLIB_VERSION_STR "LIBTIFF, Version 3.9.4\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." +/* tiffvers.h version information is updated according to version information + * in configure.ac */ + +/* clang-format off */ + +/* clang-format disabled because FindTIFF.cmake is very sensitive to the + * formatting of below line being a single line. + * Furthermore, configure_file variables of type "" are + * modified by clang-format and won't be substituted by CMake. + */ +#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.6.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 @@ -6,4 +16,21 @@ * version checking should be done based on the * string returned by TIFFGetVersion. */ -#define TIFFLIB_VERSION 20100615 +#define TIFFLIB_VERSION 20230908 + +/* The following defines have been added in 4.5.0 */ +#define TIFFLIB_MAJOR_VERSION 4 +#define TIFFLIB_MINOR_VERSION 6 +#define TIFFLIB_MICRO_VERSION 0 +#define TIFFLIB_VERSION_STR_MAJ_MIN_MIC "4.6.0" + +/* Macro added in 4.5.0. Returns TRUE if the current libtiff version is + * greater or equal to major.minor.micro + */ +#define TIFFLIB_AT_LEAST(major, minor, micro) \ + (TIFFLIB_MAJOR_VERSION > (major) || \ + (TIFFLIB_MAJOR_VERSION == (major) && TIFFLIB_MINOR_VERSION > (minor)) || \ + (TIFFLIB_MAJOR_VERSION == (major) && TIFFLIB_MINOR_VERSION == (minor) && \ + TIFFLIB_MICRO_VERSION >= (micro))) + +/* clang-format on */ diff --git a/LibTiff/uvcode.h b/LibTiff/uvcode.h index 50f11d7e..fc877292 100644 --- a/LibTiff/uvcode.h +++ b/LibTiff/uvcode.h @@ -1,180 +1,93 @@ /* 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 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 }, +#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: - */ diff --git a/PDFWriter/TIFFImageHandler.cpp b/PDFWriter/TIFFImageHandler.cpp index b26136ee..c6e53d56 100644 --- a/PDFWriter/TIFFImageHandler.cpp +++ b/PDFWriter/TIFFImageHandler.cpp @@ -148,9 +148,9 @@ typedef enum{ /* This struct defines a logical page of a TIFF. */ struct T2P_PAGE{ tdir_t page_directory; - uint32 page_number; + uint32_t page_number; ttile_t page_tilecount; - uint32 page_extra; + uint32_t page_extra; T2P_PAGE() { @@ -187,12 +187,12 @@ struct T2P_TILE{ /* This struct defines information about the tiles on a PDF page. */ struct T2P_TILES{ ttile_t tiles_tilecount; - uint32 tiles_tilewidth; - uint32 tiles_tilelength; - uint32 tiles_tilecountx; - uint32 tiles_tilecounty; - uint32 tiles_edgetilewidth; - uint32 tiles_edgetilelength; + uint32_t tiles_tilewidth; + uint32_t tiles_tilelength; + uint32_t tiles_tilecountx; + uint32_t tiles_tilecounty; + uint32_t tiles_edgetilewidth; + uint32_t tiles_edgetilelength; T2P_TILE* tiles_tiles; T2P_TILES() @@ -214,23 +214,23 @@ struct T2P{ T2P_PAGE* tiff_pages; T2P_TILES* tiff_tiles; tdir_t tiff_pagecount; - uint16 tiff_compression; - uint16 tiff_photometric; - uint16 tiff_fillorder; - uint16 tiff_bitspersample; - uint16 tiff_samplesperpixel; - uint16 tiff_planar; - uint32 tiff_width; - uint32 tiff_length; + uint16_t tiff_compression; + uint16_t tiff_photometric; + uint16_t tiff_fillorder; + uint16_t tiff_bitspersample; + uint16_t tiff_samplesperpixel; + uint16_t tiff_planar; + uint32_t tiff_width; + uint32_t tiff_length; float tiff_xres; float tiff_yres; - uint16 tiff_orientation; + uint16_t tiff_orientation; toff_t tiff_dataoffset; tsize_t tiff_datasize; - uint16 tiff_resunit; - uint16 pdf_centimeters; - uint16 pdf_overrideres; - uint16 pdf_overridepagesize; + uint16_t tiff_resunit; + uint16_t pdf_centimeters; + uint16_t pdf_overrideres; + uint16_t pdf_overridepagesize; float pdf_defaultxres; float pdf_defaultyres; float pdf_xres; @@ -241,23 +241,23 @@ struct T2P{ float pdf_imagelength; T2P_BOX pdf_mediabox; T2P_BOX pdf_imagebox; - uint32 pdf_catalog; - uint32 pdf_pages; - uint32 pdf_info; + uint32_t pdf_catalog; + uint32_t pdf_pages; + uint32_t pdf_info; ObjectIDType pdf_palettecs; - uint16 pdf_fitwindow; - uint32 pdf_startxref; + uint16_t pdf_fitwindow; + uint32_t pdf_startxref; t2p_cs_t pdf_colorspace; - uint16 pdf_colorspace_invert; - uint16 pdf_switchdecode; - uint16 pdf_palettesize; + uint16_t pdf_colorspace_invert; + uint16_t pdf_switchdecode; + uint16_t pdf_palettesize; unsigned char* pdf_palette; int pdf_labrange[4]; t2p_compress_t pdf_defaultcompression; - uint16 pdf_defaultcompressionquality; + uint16_t pdf_defaultcompressionquality; t2p_compress_t pdf_compression; - uint16 pdf_compressionquality; - uint16 pdf_nopassthrough; + uint16_t pdf_compressionquality; + uint16_t pdf_nopassthrough; t2p_transcode_t pdf_transcode; t2p_sample_t pdf_sample; tdir_t pdf_page; @@ -268,9 +268,9 @@ struct T2P{ float* tiff_transferfunction[3]; int pdf_image_interpolate; /* 0 (default) : do not interpolate, 1 : interpolate */ - uint16 tiff_transferfunctioncount; + uint16_t tiff_transferfunctioncount; ObjectIDType pdf_icccs; - uint32 tiff_iccprofilelength; + uint32_t tiff_iccprofilelength; tdata_t tiff_iccprofile; TIFF* input; @@ -566,9 +566,9 @@ EStatusCode TIFFImageHandler::ReadTopLevelTiffInformation() EStatusCode status = PDFHummus::eSuccess; tdir_t directorycount = TIFFNumberOfDirectories(mT2p->input); tdir_t i=0; - uint16 pagen=0; - uint16 paged=0; - uint16 xuint16=0; + uint16_t pagen=0; + uint16_t paged=0; + uint16_t xuint16_t=0; do { @@ -597,7 +597,7 @@ EStatusCode TIFFImageHandler::ReadTopLevelTiffInformation() for(i=0;iinput, i)){ TRACE_LOG2("Can't set directory %u of input file %s", @@ -649,9 +649,9 @@ EStatusCode TIFFImageHandler::ReadTopLevelTiffInformation() for(i=0;itiff_pagecount;i++) { TIFFSetDirectory(mT2p->input, mT2p->tiff_pages[i].page_directory ); - if((TIFFGetField(mT2p->input, TIFFTAG_PHOTOMETRIC, &xuint16) - && (xuint16==PHOTOMETRIC_PALETTE)) - || TIFFGetField(mT2p->input, TIFFTAG_INDEXED, &xuint16)) + if((TIFFGetField(mT2p->input, TIFFTAG_PHOTOMETRIC, &xuint16_t) + && (xuint16_t==PHOTOMETRIC_PALETTE)) + || TIFFGetField(mT2p->input, TIFFTAG_INDEXED, &xuint16_t)) { mT2p->tiff_pages[i].page_extra++; } @@ -685,11 +685,11 @@ EStatusCode TIFFImageHandler::ReadTopLevelTiffInformation() mT2p->tiff_pages[i].page_extra++; } mT2p->tiff_tiles[i].tiles_tilecount = mT2p->tiff_pages[i].page_tilecount; - if( (TIFFGetField(mT2p->input, TIFFTAG_PLANARCONFIG, &xuint16) != 0) - && (xuint16 == PLANARCONFIG_SEPARATE ) ) + if( (TIFFGetField(mT2p->input, TIFFTAG_PLANARCONFIG, &xuint16_t) != 0) + && (xuint16_t == PLANARCONFIG_SEPARATE ) ) { - TIFFGetField(mT2p->input, TIFFTAG_SAMPLESPERPIXEL, &xuint16); - mT2p->tiff_tiles[i].tiles_tilecount/= xuint16; + TIFFGetField(mT2p->input, TIFFTAG_SAMPLESPERPIXEL, &xuint16_t); + mT2p->tiff_tiles[i].tiles_tilecount/= xuint16_t; } if( mT2p->tiff_tiles[i].tiles_tilecount > 0) { @@ -722,8 +722,8 @@ EStatusCode TIFFImageHandler::ReadTopLevelTiffInformation() EStatusCode TIFFImageHandler::ReadTIFFPageInformation() //t2p_read_tiff_data { EStatusCode status = PDFHummus::eSuccess; - uint16 xuint16; - uint16* xuint16p; + uint16_t xuint16_t; + uint16_t* xuint16_tp; float* xfloatp; mT2p->pdf_transcode = T2P_TRANSCODE_ENCODE; @@ -813,9 +813,9 @@ EStatusCode TIFFImageHandler::ReadTIFFPageInformation() //t2p_read_tiff_data mT2p->tiff_samplesperpixel=1; } - if(TIFFGetField(mT2p->input, TIFFTAG_SAMPLEFORMAT, &xuint16) != 0 ) + if(TIFFGetField(mT2p->input, TIFFTAG_SAMPLEFORMAT, &xuint16_t) != 0 ) { - switch(xuint16) + switch(xuint16_t) { case 0: case 1: @@ -825,7 +825,7 @@ EStatusCode TIFFImageHandler::ReadTIFFPageInformation() //t2p_read_tiff_data TRACE_LOG2( "TIFFImageHandler::ReadTIFFPageInformation: No support for %s with sample format %u", mT2p->inputFilePath.c_str(), - xuint16); + xuint16_t); status = PDFHummus::eFailure; break; } @@ -864,9 +864,9 @@ EStatusCode TIFFImageHandler::ReadTIFFPageInformation() //t2p_read_tiff_data { break; } - if(TIFFGetField(mT2p->input, TIFFTAG_INDEXED, &xuint16)) + if(TIFFGetField(mT2p->input, TIFFTAG_INDEXED, &xuint16_t)) { - if(xuint16==1) + if(xuint16_t==1) ReadPhotometricPalette(); } if(mT2p->tiff_samplesperpixel > 3) @@ -876,15 +876,15 @@ EStatusCode TIFFImageHandler::ReadTIFFPageInformation() //t2p_read_tiff_data mT2p->pdf_colorspace = T2P_CS_RGB; if(TIFFGetField(mT2p->input, TIFFTAG_EXTRASAMPLES, - &xuint16, &xuint16p) - && xuint16 == 1) + &xuint16_t, &xuint16_tp) + && xuint16_t == 1) { - if(xuint16p[0] == EXTRASAMPLE_ASSOCALPHA) + if(xuint16_tp[0] == EXTRASAMPLE_ASSOCALPHA) { mT2p->pdf_sample=T2P_SAMPLE_RGBAA_TO_RGB; break; } - if(xuint16p[0] == EXTRASAMPLE_UNASSALPHA) + if(xuint16_tp[0] == EXTRASAMPLE_UNASSALPHA) { mT2p->pdf_sample=T2P_SAMPLE_RGBA_TO_RGB; break; @@ -924,14 +924,14 @@ EStatusCode TIFFImageHandler::ReadTIFFPageInformation() //t2p_read_tiff_data status = ReadPhotometricPalette(); break; case PHOTOMETRIC_SEPARATED: - if(TIFFGetField(mT2p->input, TIFFTAG_INDEXED, &xuint16)) + if(TIFFGetField(mT2p->input, TIFFTAG_INDEXED, &xuint16_t)) { - if(xuint16==1) + if(xuint16_t==1) ReadPhotometricPaletteCMYK(); } - if( TIFFGetField(mT2p->input, TIFFTAG_INKSET, &xuint16) ) + if( TIFFGetField(mT2p->input, TIFFTAG_INKSET, &xuint16_t) ) { - if(xuint16 != INKSET_CMYK) + if(xuint16_t != INKSET_CMYK) { TRACE_LOG1( "TIFFImageHandler::ReadTIFFPageInformation, No support for %s because its inkset is not CMYK", @@ -1199,9 +1199,9 @@ EStatusCode TIFFImageHandler::ReadTIFFPageInformation() //t2p_read_tiff_data EStatusCode TIFFImageHandler::ReadPhotometricPalette() { EStatusCode status = PDFHummus::eSuccess; - uint16* r; - uint16* g; - uint16* b; + uint16_t* r; + uint16_t* g; + uint16_t* b; do { @@ -1256,10 +1256,10 @@ EStatusCode TIFFImageHandler::ReadPhotometricPalette() EStatusCode TIFFImageHandler::ReadPhotometricPaletteCMYK() { EStatusCode status = PDFHummus::eSuccess; - uint16* r; - uint16* g; - uint16* b; - uint16* a; + uint16_t* r; + uint16_t* g; + uint16_t* b; + uint16_t* a; do { @@ -1320,14 +1320,14 @@ EStatusCode TIFFImageHandler::ReadPhotometricPaletteCMYK() void TIFFImageHandler::ComposePDFPage() { - uint32 i=0; - uint32 i2=0; + uint32_t i=0; + uint32_t i2=0; T2P_TILE* tiles=NULL; T2P_BOX* boxp=NULL; - uint32 tilecountx=0; - uint32 tilecounty=0; - uint32 tilewidth=0; - uint32 tilelength=0; + uint32_t tilecountx=0; + uint32_t tilecounty=0; + uint32_t tilewidth=0; + uint32_t tilelength=0; int istiled=0; float f=0; @@ -1515,7 +1515,7 @@ void TIFFImageHandler::ComposePDFPage() return; } -void TIFFImageHandler::ComposePDFPageOrient(T2P_BOX* boxp, uint16 orientation) +void TIFFImageHandler::ComposePDFPageOrient(T2P_BOX* boxp, uint16_t orientation) { float m1[9]; @@ -1592,7 +1592,7 @@ void TIFFImageHandler::ComposePDFPageOrient(T2P_BOX* boxp, uint16 orientation) } } -void TIFFImageHandler::ComposePDFPageOrientFlip(T2P_BOX* boxp, uint16 orientation) +void TIFFImageHandler::ComposePDFPageOrientFlip(T2P_BOX* boxp, uint16_t orientation) { float m1[9]; float f=0.0; @@ -2266,10 +2266,10 @@ void TIFFImageHandler::WriteImageXObjectFilter(DictionaryContext* inImageDiction void TIFFImageHandler::CalculateTiffTileSize(int inTileIndex) { - uint16 edge=0; + uint16_t edge=0; - edge |= (uint16)TileIsRightEdge(inTileIndex); - edge |= (uint16)TileIsBottomEdge(inTileIndex); + edge |= (uint16_t)TileIsRightEdge(inTileIndex); + edge |= (uint16_t)TileIsBottomEdge(inTileIndex); if(mT2p->pdf_transcode==T2P_TRANSCODE_RAW) { @@ -2363,21 +2363,21 @@ tsize_t GetSizeFromTIFFDataSize(T2P* inT2p) EStatusCode TIFFImageHandler::WriteImageTileData(PDFStream* inImageStream,int inTileIndex) { EStatusCode status = PDFHummus::eSuccess; - uint16 edge=0; + uint16_t edge=0; unsigned char* buffer=NULL; tsize_t bufferoffset=0; unsigned char* samplebuffer=NULL; tsize_t samplebufferoffset=0; tsize_t read=0; - uint16 i=0; + uint16_t i=0; ttile_t tilecount=0; tsize_t tilesize=0; ttile_t septilecount=0; tsize_t septilesize=0; - edge |= (uint16)TileIsRightEdge(inTileIndex); - edge |= (uint16)TileIsBottomEdge(inTileIndex); + edge |= (uint16_t)TileIsRightEdge(inTileIndex); + edge |= (uint16_t)TileIsBottomEdge(inTileIndex); do { @@ -2596,11 +2596,11 @@ void TIFFImageHandler::SamplePlanarSeparateToContig(unsigned char* inBuffer, } } -tsize_t TIFFImageHandler::SampleRGBAToRGB(tdata_t inData, uint32 inSampleCount) +tsize_t TIFFImageHandler::SampleRGBAToRGB(tdata_t inData, uint32_t inSampleCount) { - uint32 i = 0; - uint8 alpha = 0; - uint8* theData = (uint8*)inData; + uint32_t i = 0; + uint8_t alpha = 0; + uint8_t* theData = (uint8_t*)inData; for (i = 0; i < inSampleCount; i++) { @@ -2615,19 +2615,19 @@ tsize_t TIFFImageHandler::SampleRGBAToRGB(tdata_t inData, uint32 inSampleCount) return (i * 3); } -tsize_t TIFFImageHandler::SampleRGBAAToRGB(tdata_t inData, uint32 inSampleCount) +tsize_t TIFFImageHandler::SampleRGBAAToRGB(tdata_t inData, uint32_t inSampleCount) { - uint32 i; + uint32_t i; for(i = 0; i < inSampleCount; i++) - memcpy((uint8*)inData + i * 3, (uint8*)inData + i * 4, 3); + memcpy((uint8_t*)inData + i * 3, (uint8_t*)inData + i * 4, 3); return(i * 3); } -tsize_t TIFFImageHandler::SampleLABSignedToUnsigned(tdata_t inBuffer, uint32 inSampleCount) +tsize_t TIFFImageHandler::SampleLABSignedToUnsigned(tdata_t inBuffer, uint32_t inSampleCount) { - uint32 i=0; + uint32_t i=0; for(i=0;iinput, mT2p->tiff_width, mT2p->tiff_length, - (uint32*)buffer, + (uint32_t*)buffer, ORIENTATION_TOPLEFT, 0)) { @@ -3086,12 +3086,12 @@ EStatusCode TIFFImageHandler::WriteImageData(PDFStream* inImageStream) void TIFFImageHandler::SampleRealizePalette(unsigned char* inBuffer) { - uint32 sample_count=0; - uint16 component_count=0; - uint32 palette_offset=0; - uint32 sample_offset=0; - uint32 i=0; - uint32 j=0; + uint32_t sample_count=0; + uint16_t component_count=0; + uint32_t palette_offset=0; + uint32_t sample_offset=0; + uint32_t i=0; + uint32_t j=0; sample_count=mT2p->tiff_width*mT2p->tiff_length; component_count=mT2p->tiff_samplesperpixel; @@ -3104,14 +3104,14 @@ void TIFFImageHandler::SampleRealizePalette(unsigned char* inBuffer) } } -tsize_t TIFFImageHandler::SampleABGRToRGB(tdata_t inData, uint32 inSampleCount) +tsize_t TIFFImageHandler::SampleABGRToRGB(tdata_t inData, uint32_t inSampleCount) { - uint32 i=0; - uint32 sample=0; + uint32_t i=0; + uint32_t sample=0; for(i=0;i>8) & 0xff); ((char*)inData)[i*3+2]= (char) ((sample>>16) & 0xff); @@ -3121,8 +3121,8 @@ tsize_t TIFFImageHandler::SampleABGRToRGB(tdata_t inData, uint32 inSampleCount) } EStatusCode TIFFImageHandler::WriteImageBufferToStream(PDFStream* inPDFStream, - uint32 inImageWidth, - uint32 inImageLength, + uint32_t inImageWidth, + uint32_t inImageLength, unsigned char* inBuffer, ImageSizeProc inBufferSizeFunction) { diff --git a/PDFWriter/TIFFImageHandler.h b/PDFWriter/TIFFImageHandler.h index fe1d0e7b..0c1d2c18 100644 --- a/PDFWriter/TIFFImageHandler.h +++ b/PDFWriter/TIFFImageHandler.h @@ -109,8 +109,8 @@ typedef std::list StringList; typedef std::pair DoubleAndDoublePair; // tiff.h extracted defs [prefer to avoid including too much here] -typedef unsigned short uint16; /* sizeof (uint16) must == 2 */ -typedef unsigned int uint32; /* sizeof (uint32) must == 4 */ +typedef unsigned short uint16_t; /* sizeof (uint16_t) must == 2 */ +typedef unsigned int uint32_t; /* sizeof (uint32_t) must == 4 */ typedef int int32; #ifdef _INCLUDE_TIFF_HEADER /* @@ -124,9 +124,9 @@ it's not guaranteed that it will match the actual tiff headers... #include #if TIFFLIB_VERSION >= 20120218 // tiff 4.0.1 or above -typedef uint64 tsize_t_compat; +typedef uint64_t tsize_t_compat; #else // TIFFLIB_VERSION >= 20120218 -typedef uint32 tsize_t_compat; +typedef uint32_t_t tsize_t_compat; #endif // TIFFLIB_VERSION >= 20120218 @@ -138,8 +138,8 @@ typedef uint32 tsize_t_compat; */ #ifndef _USE_TIFF_TSIZE_AS_FOLLOWS -typedef int32 tsize_t; /* i/o size in bytes */ -typedef uint32 tsize_t_compat; +typedef int64_t tsize_t; /* i/o size in bytes */ // updating per new bundled version +typedef uint64_t tsize_t_compat; #else // ! _USE_TIFF_TSIZE_AS_FOLLOWS @@ -217,8 +217,8 @@ class TIFFImageHandler PDFHummus::EStatusCode ReadPhotometricPalette(); PDFHummus::EStatusCode ReadPhotometricPaletteCMYK(); void ComposePDFPage(); - void ComposePDFPageOrient(T2P_BOX*, uint16); - void ComposePDFPageOrientFlip(T2P_BOX*, uint16); + void ComposePDFPageOrient(T2P_BOX*, uint16_t); + void ComposePDFPageOrientFlip(T2P_BOX*, uint16_t); ObjectIDType WriteTransferFunction(int i); ObjectIDType WriteTransferFunctionsExtGState(const ObjectIDTypeList& inTransferFunctions); ObjectIDType WritePaletteCS(); @@ -235,21 +235,21 @@ class TIFFImageHandler void SamplePlanarSeparateToContig(unsigned char* inBuffer, unsigned char* inSamplebuffer, tsize_t inSamplebuffersize); - tsize_t SampleRGBAToRGB(tdata_t inData, uint32 inSampleCount); - tsize_t SampleRGBAAToRGB(tdata_t inData, uint32 inSampleCount); - tsize_t SampleLABSignedToUnsigned(tdata_t inBuffer, uint32 inSampleCount); + tsize_t SampleRGBAToRGB(tdata_t inData, uint32_t inSampleCount); + tsize_t SampleRGBAAToRGB(tdata_t inData, uint32_t inSampleCount); + tsize_t SampleLABSignedToUnsigned(tdata_t inBuffer, uint32_t inSampleCount); void TileCollapseLeft(tdata_t inBuffer, tsize_t inScanWidth, - uint32 inTileWidth, uint32 inEdgeTileWidth, - uint32 inTileLength); + uint32_t inTileWidth, uint32_t inEdgeTileWidth, + uint32_t inTileLength); PDFImageXObject* WriteUntiledImageXObject(); void WriteCommonImageDictionaryProperties(DictionaryContext* inImageContext); PDFHummus::EStatusCode WriteImageData(PDFStream* inImageStream); void CalculateTiffSizeNoTiles(); void SampleRealizePalette(unsigned char* inBuffer); - tsize_t SampleABGRToRGB(tdata_t inData, uint32 inSampleCount); + tsize_t SampleABGRToRGB(tdata_t inData, uint32_t inSampleCount); PDFHummus::EStatusCode WriteImageBufferToStream( PDFStream* inPDFStream, - uint32 inImageWidth, - uint32 inImageLength, + uint32_t inImageWidth, + uint32_t inImageLength, unsigned char* inBuffer, ImageSizeProc inBufferSizeFunction); PDFFormXObject* WriteImagesFormXObject(const PDFImageXObjectList& inImages,ObjectIDType inFormXObjectID); @@ -257,4 +257,4 @@ class TIFFImageHandler void WriteIndexedCSForBiLevelColorMap(); }; -#endif +#endif \ No newline at end of file