XFA: Upgrade to libtiff 4.0.6.

R=jun_fang@foxitsoftware.com, tsepez@chromium.org

Review URL: https://codereview.chromium.org/1563103002 .
diff --git a/third_party/libtiff/0000-build-config.patch b/third_party/libtiff/0000-build-config.patch
new file mode 100644
index 0000000..50af2db
--- /dev/null
+++ b/third_party/libtiff/0000-build-config.patch
@@ -0,0 +1,337 @@
+diff a/third_party/libtiff/tiffiop.h b/third_party/libtiff/tiffiop.h
+--- a/third_party/libtiff/tiffiop.h
++++ b/third_party/libtiff/tiffiop.h
+@@ -30,7 +30,7 @@
+  * ``Library-private'' definitions.
+  */
+ 
+-#include "tif_config.h"
++#include "tiffconf.h"
+ 
+ #ifdef HAVE_FCNTL_H
+ # include <fcntl.h>
+diff a/third_party/libtiff/tif_jpeg.c b/third_party/libtiff/tif_jpeg.c
+--- a/third_party/libtiff/tif_jpeg.c
++++ b/third_party/libtiff/tif_jpeg.c
+@@ -85,8 +85,16 @@
+ # define HAVE_BOOLEAN            /* prevent jmorecfg.h from redefining it */
+ #endif
+ 
+-#include "jpeglib.h"
+-#include "jerror.h"
++#if defined(USE_SYSTEM_LIBJPEG)
++#include <jerror.h>
++#include <jpeglib.h>
++#elif defined(USE_LIBJPEG_TURBO)
++#include "third_party/libjpeg_turbo/jerror.h"
++#include "third_party/libjpeg_turbo/jpeglib.h"
++#else
++#include "third_party/libjpeg/jerror.h"
++#include "third_party/libjpeg/jpeglib.h"
++#endif
+ 
+ /* 
+  * Do we want to do special processing suitable for when JSAMPLE is a
+diff a/third_party/libtiff/tif_ojpeg.c b/third_party/libtiff/tif_ojpeg.c
+--- a/third_party/libtiff/tif_ojpeg.c
++++ b/third_party/libtiff/tif_ojpeg.c
+@@ -214,8 +214,17 @@
+ # define HAVE_BOOLEAN            /* prevent jmorecfg.h from redefining it */
+ #endif
+ 
+-#include "jpeglib.h"
+-#include "jerror.h"
++#if defined(USE_SYSTEM_LIBJPEG)
++#include <jerror.h>
++#include <jpeglib.h>
++#elif defined(USE_LIBJPEG_TURBO)
++#include "third_party/libjpeg_turbo/jerror.h"
++#include "third_party/libjpeg_turbo/jpeglib.h"
++#else
++#include "third_party/libjpeg/jerror.h"
++#include "third_party/libjpeg/jpeglib.h"
++#endif
++
+ 
+ typedef struct jpeg_error_mgr jpeg_error_mgr;
+ typedef struct jpeg_common_struct jpeg_common_struct;
+diff a/third_party/libtiff/tif_pixarlog.c b/third_party/libtiff/tif_pixarlog.c
+--- a/third_party/libtiff/tif_pixarlog.c
++++ b/third_party/libtiff/tif_pixarlog.c
+@@ -90,7 +90,7 @@
+  */
+ 
+ #include "tif_predict.h"
+-#include "zlib.h"
++#include "../zlib_v128/zlib.h"
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+diff a/third_party/libtiff/tif_zip.c b/third_party/libtiff/tif_zip.c
+--- a/third_party/libtiff/tif_zip.c
++++ b/third_party/libtiff/tif_zip.c
+@@ -47,7 +47,7 @@
+  * last found at ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib-0.99.tar.gz.
+  */
+ #include "tif_predict.h"
+-#include "zlib.h"
++#include "../zlib_v128/zlib.h"
+ 
+ #include <stdio.h>
+ 
+diff a/third_party/libtiff/tiffconf.h b/third_party/libtiff/tiffconf.h
+--- /dev/null
++++ b/third_party/libtiff/tiffconf.h
+@@ -0,0 +1,252 @@
++/* libtiff/tiffconf.h.  Generated by configure.  */
++/*
++  Configuration defines for installed libtiff.
++  This file maintained for backward compatibility. Do not use definitions
++  from this file in your programs.
++*/
++#ifndef _TIFFCONF_
++#define _TIFFCONF_
++
++#ifndef _FX_SYSTEM_H_
++# include "../../core/include/fxcrt/fx_system.h"
++#endif
++
++//NOTE: The tiff codec requires an ANSI C compiler environment for building and 
++//		presumes an ANSI C environment for use.
++
++/* Define to 1 if you have the <fcntl.h> header file. */
++/* Define to 1 if you have the <sys/types.h> header file. */
++#if _FX_OS_ == _FX_WIN32_MOBILE_
++# define O_RDONLY       0x0000  /* open for reading only */
++# define O_WRONLY       0x0001  /* open for writing only */
++# define O_RDWR         0x0002  /* open for reading and writing */
++# define O_CREAT        0x0100  /* create and open file */
++# define O_TRUNC        0x0200  /* open and truncate */
++#else
++# define HAVE_SYS_TYPES_H 1
++# define HAVE_FCNTL_H 1
++#endif
++
++/* Compatibility stuff. */
++
++/* Define to 1 if you have the <assert.h> header file. */
++#define HAVE_ASSERT_H 1
++
++/* Define as 0 or 1 according to the floating point format suported by the
++   machine */
++#define HAVE_IEEEFP 1
++
++/* Define to 1 if you have the <string.h> header file. */
++//#define HAVE_STRING_H 1
++//fx_system.h already include the string.h in ANSIC
++
++/* Define to 1 if you have the <search.h> header file. */
++/*#define HAVE_SEARCH_H 1 */
++
++/* The size of a `int', as computed by sizeof. */
++/* According typedef int	int32_t; in the fx_system.h*/
++#define SIZEOF_INT 4
++
++/* Sunliang.Liu 20110325. We should config the correct long size for tif 
++   fax4decode optimize in tif_fax3.c  -- Linux64 decode issue. 
++   TESTDOC: Bug #23661 - z1.tif. */
++#if _FX_CPU_ == _FX_WIN64_ || _FX_CPU_ == _FX_X64_ || _FX_CPU_ == _FX_IA64_
++/* The size of `unsigned long', as computed by sizeof. */
++#define SIZEOF_UNSIGNED_LONG 8
++#else
++#define SIZEOF_UNSIGNED_LONG 4
++#endif
++
++#define HAVE_SNPRINTF 1
++
++/* Signed 8-bit type */
++#define TIFF_INT8_T signed char
++
++/* Unsigned 8-bit type */
++#define TIFF_UINT8_T unsigned char
++
++/* Signed 16-bit type */
++#define TIFF_INT16_T signed short
++
++/* Unsigned 16-bit type */
++#define TIFF_UINT16_T unsigned short
++
++/* Signed 32-bit type */
++#define TIFF_INT32_T signed int
++
++/* Unsigned 32-bit type */
++#define TIFF_UINT32_T unsigned int
++
++/* Signed 32-bit type formatter */
++#define TIFF_INT32_FORMAT "%d"
++
++/* Unsigned 32-bit type formatter */
++#define TIFF_UINT32_FORMAT "%u"
++
++#ifdef _MSC_VER		// windows
++
++/* Signed 64-bit type formatter */
++#define TIFF_INT64_FORMAT "%I64d"
++
++/* Unsigned 64-bit type formatter */
++#define TIFF_UINT64_FORMAT "%I64u"
++
++/* Signed 64-bit type */
++#define TIFF_INT64_T signed __int64
++
++/* Unsigned 64-bit type */
++#define TIFF_UINT64_T unsigned __int64
++
++#else						// linux/unix
++
++#if 0 //_FX_CPU_ == _FX_X64_	// linux/unix 64
++
++/* Signed 64-bit type formatter */
++#define TIFF_INT64_FORMAT "%ld"
++
++/* Unsigned 64-bit type formatter */
++#define TIFF_UINT64_FORMAT "%lu"
++
++/* Signed 64-bit type */
++#define TIFF_INT64_T signed long
++
++#else						// linux/unix 32
++
++/* Signed 64-bit type formatter */
++#define TIFF_INT64_FORMAT "%lld"
++
++/* Unsigned 64-bit type formatter */
++#define TIFF_UINT64_FORMAT "%llu"
++
++/* Signed 64-bit type */
++#define TIFF_INT64_T signed long long
++
++#endif						// end _FX_CPU_
++
++/* Unsigned 64-bit type */
++#define TIFF_UINT64_T unsigned long long
++
++#endif
++
++
++/* Signed size type */
++#ifdef _MSC_VER
++
++#if defined(_WIN64)
++#define TIFF_SSIZE_T signed __int64
++#else
++#define TIFF_SSIZE_T signed int
++#endif
++
++#else
++
++#define TIFF_SSIZE_T signed long
++
++#endif
++
++/* Signed size type formatter */
++#if defined(_WIN64)
++#define TIFF_SSIZE_FORMAT "%I64d"
++#else
++#define TIFF_SSIZE_FORMAT "%ld"
++#endif
++
++/* Pointer difference type */
++#ifdef _MSC_VER
++#define TIFF_PTRDIFF_T long
++#else
++#define TIFF_PTRDIFF_T ptrdiff_t
++#endif
++
++/* Signed 64-bit type */
++/*#define TIFF_INT64_T signed __int64*/
++
++/* Unsigned 64-bit type */
++/*#define TIFF_UINT64_T unsigned __int64*/
++
++/* 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
++# endif
++#endif
++
++#define lfind _lfind
++
++#define BSDTYPES
++
++/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */
++#define HOST_FILLORDER FILLORDER_LSB2MSB
++
++/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
++   (Intel) */
++#if _FX_ENDIAN_ == _FX_BIG_ENDIAN_
++# define HOST_BIGENDIAN 1
++#else
++# define HOST_BIGENDIAN 0
++#endif
++
++/* Support CCITT Group 3 & 4 algorithms */
++#define CCITT_SUPPORT 1
++
++/* Support JPEG compression (requires IJG JPEG library) */
++#define JPEG_SUPPORT 1
++
++/* Support LogLuv high dynamic range encoding */
++#define LOGLUV_SUPPORT 1
++
++/* Support LZW algorithm */
++#define LZW_SUPPORT 1
++
++/* Support NeXT 2-bit RLE algorithm */
++#define NEXT_SUPPORT 1
++
++/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation
++   fails with unpatched IJG JPEG library) */
++#define  OJPEG_SUPPORT	1
++
++/* Support Macintosh PackBits algorithm */
++#define PACKBITS_SUPPORT 1
++
++/* Support Pixar log-format algorithm (requires Zlib) */
++#define PIXARLOG_SUPPORT 1
++
++/* Support ThunderScan 4-bit RLE algorithm */
++#define THUNDER_SUPPORT 1
++
++/* Support Deflate compression */
++#define ZIP_SUPPORT 1
++
++/* Support strip chopping (whether or not to convert single-strip uncompressed
++   images to mutiple strips of ~8Kb to reduce memory usage) */
++#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP
++
++/* Enable SubIFD tag (330) support */
++#define SUBIFD_SUPPORT 1
++
++/* Treat extra sample as alpha (default enabled). The RGBA interface will
++   treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many
++   packages produce RGBA files but don't mark the alpha properly. */
++#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1
++
++/* Pick up YCbCr subsampling info from the JPEG data stream to support files
++   lacking the tag (default enabled). */
++#define CHECK_JPEG_YCBCR_SUBSAMPLING 1
++
++/* Support MS MDI magic number files as TIFF */
++#define MDI_SUPPORT 1
++
++/*
++ * Feature support definitions.
++ * XXX: These macros are obsoleted. Don't use them in your apps!
++ * Macros stays here for backward compatibility and should be always defined.
++ */
++#define COLORIMETRY_SUPPORT
++#define YCBCR_SUPPORT
++#define CMYK_SUPPORT
++#define ICC_SUPPORT
++#define PHOTOSHOP_SUPPORT
++#define IPTC_SUPPORT
++
++#endif /* _TIFFCONF_ */
diff --git a/third_party/libtiff/README.pdfium b/third_party/libtiff/README.pdfium
new file mode 100644
index 0000000..bee4729
--- /dev/null
+++ b/third_party/libtiff/README.pdfium
@@ -0,0 +1,12 @@
+Name: LibTIFF
+URL: http://www.remotesensing.org/libtiff/
+Version: 4.0.6
+Security Critical: yes
+License: BSD
+
+Description:
+TIFF library.
+
+Local Modifications:
+
+0000-build-config.patch: Local build configuration changes.
diff --git a/third_party/libtiff/t4.h b/third_party/libtiff/t4.h
new file mode 100644
index 0000000..b908f54
--- /dev/null
+++ b/third_party/libtiff/t4.h
@@ -0,0 +1,292 @@
+/* $Id: t4.h,v 1.3 2010-03-10 18:56:48 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
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _T4_
+#define	_T4_
+/*
+ * CCITT T.4 1D Huffman runlength codes and
+ * related definitions.  Given the small sizes
+ * of these tables it does not seem
+ * worthwhile to make code & length 8 bits.
+ */
+typedef struct tableentry {
+    unsigned short length;  /* bit length of g3 code */
+    unsigned short code;    /* g3 code */
+    short runlen;           /* run length in bits */
+} tableentry;
+
+#define EOL	0x001	/* EOL code value - 0000 0000 0000 1 */
+
+/* status values returned instead of a run length */
+#define G3CODE_EOL	-1	/* NB: ACT_EOL - ACT_WRUNT */
+#define G3CODE_INVALID	-2	/* NB: ACT_INVALID - ACT_WRUNT */
+#define G3CODE_EOF	-3	/* end of input data */
+#define G3CODE_INCOMP	-4	/* incomplete run code */
+
+/*
+ * Note that these tables are ordered such that the
+ * index into the table is known to be either the
+ * run length, or (run length / 64) + a fixed offset.
+ *
+ * NB: The G3CODE_INVALID entries are only used
+ *     during state generation (see mkg3states.c).
+ */
+#ifdef G3CODES
+const tableentry TIFFFaxWhiteCodes[] = {
+    { 8, 0x35, 0 },	/* 0011 0101 */
+    { 6, 0x7, 1 },	/* 0001 11 */
+    { 4, 0x7, 2 },	/* 0111 */
+    { 4, 0x8, 3 },	/* 1000 */
+    { 4, 0xB, 4 },	/* 1011 */
+    { 4, 0xC, 5 },	/* 1100 */
+    { 4, 0xE, 6 },	/* 1110 */
+    { 4, 0xF, 7 },	/* 1111 */
+    { 5, 0x13, 8 },	/* 1001 1 */
+    { 5, 0x14, 9 },	/* 1010 0 */
+    { 5, 0x7, 10 },	/* 0011 1 */
+    { 5, 0x8, 11 },	/* 0100 0 */
+    { 6, 0x8, 12 },	/* 0010 00 */
+    { 6, 0x3, 13 },	/* 0000 11 */
+    { 6, 0x34, 14 },	/* 1101 00 */
+    { 6, 0x35, 15 },	/* 1101 01 */
+    { 6, 0x2A, 16 },	/* 1010 10 */
+    { 6, 0x2B, 17 },	/* 1010 11 */
+    { 7, 0x27, 18 },	/* 0100 111 */
+    { 7, 0xC, 19 },	/* 0001 100 */
+    { 7, 0x8, 20 },	/* 0001 000 */
+    { 7, 0x17, 21 },	/* 0010 111 */
+    { 7, 0x3, 22 },	/* 0000 011 */
+    { 7, 0x4, 23 },	/* 0000 100 */
+    { 7, 0x28, 24 },	/* 0101 000 */
+    { 7, 0x2B, 25 },	/* 0101 011 */
+    { 7, 0x13, 26 },	/* 0010 011 */
+    { 7, 0x24, 27 },	/* 0100 100 */
+    { 7, 0x18, 28 },	/* 0011 000 */
+    { 8, 0x2, 29 },	/* 0000 0010 */
+    { 8, 0x3, 30 },	/* 0000 0011 */
+    { 8, 0x1A, 31 },	/* 0001 1010 */
+    { 8, 0x1B, 32 },	/* 0001 1011 */
+    { 8, 0x12, 33 },	/* 0001 0010 */
+    { 8, 0x13, 34 },	/* 0001 0011 */
+    { 8, 0x14, 35 },	/* 0001 0100 */
+    { 8, 0x15, 36 },	/* 0001 0101 */
+    { 8, 0x16, 37 },	/* 0001 0110 */
+    { 8, 0x17, 38 },	/* 0001 0111 */
+    { 8, 0x28, 39 },	/* 0010 1000 */
+    { 8, 0x29, 40 },	/* 0010 1001 */
+    { 8, 0x2A, 41 },	/* 0010 1010 */
+    { 8, 0x2B, 42 },	/* 0010 1011 */
+    { 8, 0x2C, 43 },	/* 0010 1100 */
+    { 8, 0x2D, 44 },	/* 0010 1101 */
+    { 8, 0x4, 45 },	/* 0000 0100 */
+    { 8, 0x5, 46 },	/* 0000 0101 */
+    { 8, 0xA, 47 },	/* 0000 1010 */
+    { 8, 0xB, 48 },	/* 0000 1011 */
+    { 8, 0x52, 49 },	/* 0101 0010 */
+    { 8, 0x53, 50 },	/* 0101 0011 */
+    { 8, 0x54, 51 },	/* 0101 0100 */
+    { 8, 0x55, 52 },	/* 0101 0101 */
+    { 8, 0x24, 53 },	/* 0010 0100 */
+    { 8, 0x25, 54 },	/* 0010 0101 */
+    { 8, 0x58, 55 },	/* 0101 1000 */
+    { 8, 0x59, 56 },	/* 0101 1001 */
+    { 8, 0x5A, 57 },	/* 0101 1010 */
+    { 8, 0x5B, 58 },	/* 0101 1011 */
+    { 8, 0x4A, 59 },	/* 0100 1010 */
+    { 8, 0x4B, 60 },	/* 0100 1011 */
+    { 8, 0x32, 61 },	/* 0011 0010 */
+    { 8, 0x33, 62 },	/* 0011 0011 */
+    { 8, 0x34, 63 },	/* 0011 0100 */
+    { 5, 0x1B, 64 },	/* 1101 1 */
+    { 5, 0x12, 128 },	/* 1001 0 */
+    { 6, 0x17, 192 },	/* 0101 11 */
+    { 7, 0x37, 256 },	/* 0110 111 */
+    { 8, 0x36, 320 },	/* 0011 0110 */
+    { 8, 0x37, 384 },	/* 0011 0111 */
+    { 8, 0x64, 448 },	/* 0110 0100 */
+    { 8, 0x65, 512 },	/* 0110 0101 */
+    { 8, 0x68, 576 },	/* 0110 1000 */
+    { 8, 0x67, 640 },	/* 0110 0111 */
+    { 9, 0xCC, 704 },	/* 0110 0110 0 */
+    { 9, 0xCD, 768 },	/* 0110 0110 1 */
+    { 9, 0xD2, 832 },	/* 0110 1001 0 */
+    { 9, 0xD3, 896 },	/* 0110 1001 1 */
+    { 9, 0xD4, 960 },	/* 0110 1010 0 */
+    { 9, 0xD5, 1024 },	/* 0110 1010 1 */
+    { 9, 0xD6, 1088 },	/* 0110 1011 0 */
+    { 9, 0xD7, 1152 },	/* 0110 1011 1 */
+    { 9, 0xD8, 1216 },	/* 0110 1100 0 */
+    { 9, 0xD9, 1280 },	/* 0110 1100 1 */
+    { 9, 0xDA, 1344 },	/* 0110 1101 0 */
+    { 9, 0xDB, 1408 },	/* 0110 1101 1 */
+    { 9, 0x98, 1472 },	/* 0100 1100 0 */
+    { 9, 0x99, 1536 },	/* 0100 1100 1 */
+    { 9, 0x9A, 1600 },	/* 0100 1101 0 */
+    { 6, 0x18, 1664 },	/* 0110 00 */
+    { 9, 0x9B, 1728 },	/* 0100 1101 1 */
+    { 11, 0x8, 1792 },	/* 0000 0001 000 */
+    { 11, 0xC, 1856 },	/* 0000 0001 100 */
+    { 11, 0xD, 1920 },	/* 0000 0001 101 */
+    { 12, 0x12, 1984 },	/* 0000 0001 0010 */
+    { 12, 0x13, 2048 },	/* 0000 0001 0011 */
+    { 12, 0x14, 2112 },	/* 0000 0001 0100 */
+    { 12, 0x15, 2176 },	/* 0000 0001 0101 */
+    { 12, 0x16, 2240 },	/* 0000 0001 0110 */
+    { 12, 0x17, 2304 },	/* 0000 0001 0111 */
+    { 12, 0x1C, 2368 },	/* 0000 0001 1100 */
+    { 12, 0x1D, 2432 },	/* 0000 0001 1101 */
+    { 12, 0x1E, 2496 },	/* 0000 0001 1110 */
+    { 12, 0x1F, 2560 },	/* 0000 0001 1111 */
+    { 12, 0x1, G3CODE_EOL },	/* 0000 0000 0001 */
+    { 9, 0x1, G3CODE_INVALID },	/* 0000 0000 1 */
+    { 10, 0x1, G3CODE_INVALID },	/* 0000 0000 01 */
+    { 11, 0x1, G3CODE_INVALID },	/* 0000 0000 001 */
+    { 12, 0x0, G3CODE_INVALID },	/* 0000 0000 0000 */
+};
+
+const tableentry TIFFFaxBlackCodes[] = {
+    { 10, 0x37, 0 },	/* 0000 1101 11 */
+    { 3, 0x2, 1 },	/* 010 */
+    { 2, 0x3, 2 },	/* 11 */
+    { 2, 0x2, 3 },	/* 10 */
+    { 3, 0x3, 4 },	/* 011 */
+    { 4, 0x3, 5 },	/* 0011 */
+    { 4, 0x2, 6 },	/* 0010 */
+    { 5, 0x3, 7 },	/* 0001 1 */
+    { 6, 0x5, 8 },	/* 0001 01 */
+    { 6, 0x4, 9 },	/* 0001 00 */
+    { 7, 0x4, 10 },	/* 0000 100 */
+    { 7, 0x5, 11 },	/* 0000 101 */
+    { 7, 0x7, 12 },	/* 0000 111 */
+    { 8, 0x4, 13 },	/* 0000 0100 */
+    { 8, 0x7, 14 },	/* 0000 0111 */
+    { 9, 0x18, 15 },	/* 0000 1100 0 */
+    { 10, 0x17, 16 },	/* 0000 0101 11 */
+    { 10, 0x18, 17 },	/* 0000 0110 00 */
+    { 10, 0x8, 18 },	/* 0000 0010 00 */
+    { 11, 0x67, 19 },	/* 0000 1100 111 */
+    { 11, 0x68, 20 },	/* 0000 1101 000 */
+    { 11, 0x6C, 21 },	/* 0000 1101 100 */
+    { 11, 0x37, 22 },	/* 0000 0110 111 */
+    { 11, 0x28, 23 },	/* 0000 0101 000 */
+    { 11, 0x17, 24 },	/* 0000 0010 111 */
+    { 11, 0x18, 25 },	/* 0000 0011 000 */
+    { 12, 0xCA, 26 },	/* 0000 1100 1010 */
+    { 12, 0xCB, 27 },	/* 0000 1100 1011 */
+    { 12, 0xCC, 28 },	/* 0000 1100 1100 */
+    { 12, 0xCD, 29 },	/* 0000 1100 1101 */
+    { 12, 0x68, 30 },	/* 0000 0110 1000 */
+    { 12, 0x69, 31 },	/* 0000 0110 1001 */
+    { 12, 0x6A, 32 },	/* 0000 0110 1010 */
+    { 12, 0x6B, 33 },	/* 0000 0110 1011 */
+    { 12, 0xD2, 34 },	/* 0000 1101 0010 */
+    { 12, 0xD3, 35 },	/* 0000 1101 0011 */
+    { 12, 0xD4, 36 },	/* 0000 1101 0100 */
+    { 12, 0xD5, 37 },	/* 0000 1101 0101 */
+    { 12, 0xD6, 38 },	/* 0000 1101 0110 */
+    { 12, 0xD7, 39 },	/* 0000 1101 0111 */
+    { 12, 0x6C, 40 },	/* 0000 0110 1100 */
+    { 12, 0x6D, 41 },	/* 0000 0110 1101 */
+    { 12, 0xDA, 42 },	/* 0000 1101 1010 */
+    { 12, 0xDB, 43 },	/* 0000 1101 1011 */
+    { 12, 0x54, 44 },	/* 0000 0101 0100 */
+    { 12, 0x55, 45 },	/* 0000 0101 0101 */
+    { 12, 0x56, 46 },	/* 0000 0101 0110 */
+    { 12, 0x57, 47 },	/* 0000 0101 0111 */
+    { 12, 0x64, 48 },	/* 0000 0110 0100 */
+    { 12, 0x65, 49 },	/* 0000 0110 0101 */
+    { 12, 0x52, 50 },	/* 0000 0101 0010 */
+    { 12, 0x53, 51 },	/* 0000 0101 0011 */
+    { 12, 0x24, 52 },	/* 0000 0010 0100 */
+    { 12, 0x37, 53 },	/* 0000 0011 0111 */
+    { 12, 0x38, 54 },	/* 0000 0011 1000 */
+    { 12, 0x27, 55 },	/* 0000 0010 0111 */
+    { 12, 0x28, 56 },	/* 0000 0010 1000 */
+    { 12, 0x58, 57 },	/* 0000 0101 1000 */
+    { 12, 0x59, 58 },	/* 0000 0101 1001 */
+    { 12, 0x2B, 59 },	/* 0000 0010 1011 */
+    { 12, 0x2C, 60 },	/* 0000 0010 1100 */
+    { 12, 0x5A, 61 },	/* 0000 0101 1010 */
+    { 12, 0x66, 62 },	/* 0000 0110 0110 */
+    { 12, 0x67, 63 },	/* 0000 0110 0111 */
+    { 10, 0xF, 64 },	/* 0000 0011 11 */
+    { 12, 0xC8, 128 },	/* 0000 1100 1000 */
+    { 12, 0xC9, 192 },	/* 0000 1100 1001 */
+    { 12, 0x5B, 256 },	/* 0000 0101 1011 */
+    { 12, 0x33, 320 },	/* 0000 0011 0011 */
+    { 12, 0x34, 384 },	/* 0000 0011 0100 */
+    { 12, 0x35, 448 },	/* 0000 0011 0101 */
+    { 13, 0x6C, 512 },	/* 0000 0011 0110 0 */
+    { 13, 0x6D, 576 },	/* 0000 0011 0110 1 */
+    { 13, 0x4A, 640 },	/* 0000 0010 0101 0 */
+    { 13, 0x4B, 704 },	/* 0000 0010 0101 1 */
+    { 13, 0x4C, 768 },	/* 0000 0010 0110 0 */
+    { 13, 0x4D, 832 },	/* 0000 0010 0110 1 */
+    { 13, 0x72, 896 },	/* 0000 0011 1001 0 */
+    { 13, 0x73, 960 },	/* 0000 0011 1001 1 */
+    { 13, 0x74, 1024 },	/* 0000 0011 1010 0 */
+    { 13, 0x75, 1088 },	/* 0000 0011 1010 1 */
+    { 13, 0x76, 1152 },	/* 0000 0011 1011 0 */
+    { 13, 0x77, 1216 },	/* 0000 0011 1011 1 */
+    { 13, 0x52, 1280 },	/* 0000 0010 1001 0 */
+    { 13, 0x53, 1344 },	/* 0000 0010 1001 1 */
+    { 13, 0x54, 1408 },	/* 0000 0010 1010 0 */
+    { 13, 0x55, 1472 },	/* 0000 0010 1010 1 */
+    { 13, 0x5A, 1536 },	/* 0000 0010 1101 0 */
+    { 13, 0x5B, 1600 },	/* 0000 0010 1101 1 */
+    { 13, 0x64, 1664 },	/* 0000 0011 0010 0 */
+    { 13, 0x65, 1728 },	/* 0000 0011 0010 1 */
+    { 11, 0x8, 1792 },	/* 0000 0001 000 */
+    { 11, 0xC, 1856 },	/* 0000 0001 100 */
+    { 11, 0xD, 1920 },	/* 0000 0001 101 */
+    { 12, 0x12, 1984 },	/* 0000 0001 0010 */
+    { 12, 0x13, 2048 },	/* 0000 0001 0011 */
+    { 12, 0x14, 2112 },	/* 0000 0001 0100 */
+    { 12, 0x15, 2176 },	/* 0000 0001 0101 */
+    { 12, 0x16, 2240 },	/* 0000 0001 0110 */
+    { 12, 0x17, 2304 },	/* 0000 0001 0111 */
+    { 12, 0x1C, 2368 },	/* 0000 0001 1100 */
+    { 12, 0x1D, 2432 },	/* 0000 0001 1101 */
+    { 12, 0x1E, 2496 },	/* 0000 0001 1110 */
+    { 12, 0x1F, 2560 },	/* 0000 0001 1111 */
+    { 12, 0x1, G3CODE_EOL },	/* 0000 0000 0001 */
+    { 9, 0x1, G3CODE_INVALID },	/* 0000 0000 1 */
+    { 10, 0x1, G3CODE_INVALID },	/* 0000 0000 01 */
+    { 11, 0x1, G3CODE_INVALID },	/* 0000 0000 001 */
+    { 12, 0x0, G3CODE_INVALID },	/* 0000 0000 0000 */
+};
+#else
+extern const tableentry TIFFFaxWhiteCodes[];
+extern const tableentry TIFFFaxBlackCodes[];
+#endif
+#endif /* _T4_ */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_aux.c b/third_party/libtiff/tif_aux.c
new file mode 100644
index 0000000..927150a
--- /dev/null
+++ b/third_party/libtiff/tif_aux.c
@@ -0,0 +1,358 @@
+/* $Id: tif_aux.c,v 1.26 2010-07-01 15:33:28 dron 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Auxiliary Support Routines.
+ */
+#include "tiffiop.h"
+#include "tif_predict.h"
+#include <math.h>
+
+uint32
+_TIFFMultiply32(TIFF* tif, uint32 first, uint32 second, const char* where)
+{
+	uint32 bytes = first * second;
+
+	if (second && bytes / second != first) {
+		TIFFErrorExt(tif->tif_clientdata, where, "Integer overflow in %s", where);
+		bytes = 0;
+	}
+
+	return bytes;
+}
+
+uint64
+_TIFFMultiply64(TIFF* tif, uint64 first, uint64 second, const char* where)
+{
+	uint64 bytes = first * second;
+
+	if (second && bytes / second != first) {
+		TIFFErrorExt(tif->tif_clientdata, where, "Integer overflow in %s", where);
+		bytes = 0;
+	}
+
+	return bytes;
+}
+
+void*
+_TIFFCheckRealloc(TIFF* tif, void* buffer,
+		  tmsize_t nmemb, tmsize_t elem_size, const char* what)
+{
+	void* cp = NULL;
+	tmsize_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;
+}
+
+void*
+_TIFFCheckMalloc(TIFF* tif, tmsize_t nmemb, tmsize_t elem_size, const char* what)
+{
+	return _TIFFCheckRealloc(tif, NULL, nmemb, elem_size, what);  
+}
+
+static int
+TIFFDefaultTransferFunction(TIFFDirectory* td)
+{
+	uint16 **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);
+	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;
+
+bad:
+	if (tf[0])
+		_TIFFfree(tf[0]);
+	if (tf[1])
+		_TIFFfree(tf[1]);
+	if (tf[2])
+		_TIFFfree(tf[2]);
+	tf[0] = tf[1] = tf[2] = 0;
+	return 0;
+}
+
+static int
+TIFFDefaultRefBlackWhite(TIFFDirectory* td)
+{
+	int i;
+
+	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->td_bitspersample)-1L);
+		}
+	}
+	return 1;
+}
+
+/*
+ * Like TIFFGetField, but return any default
+ * value if the tag is not present in the directory.
+ *
+ * NB:	We use the value in the directory, rather than
+ *	explcit values so that defaults exist only one
+ *	place in the library -- in TIFFDefaultDirectory.
+ */
+int
+TIFFVGetFieldDefaulted(TIFF* tif, uint32 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:
+                {
+			TIFFPredictorState* sp = (TIFFPredictorState*) tif->tif_data;
+			*va_arg(ap, uint16*) = (uint16) sp->predictor;
+			return 1;
+                }
+	case TIFFTAG_DOTRANGE:
+		*va_arg(ap, uint16 *) = 0;
+		*va_arg(ap, uint16 *) = (1<<td->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;
+}
+
+/*
+ * Like TIFFGetField, but return any default
+ * value if the tag is not present in the directory.
+ */
+int
+TIFFGetFieldDefaulted(TIFF* tif, uint32 tag, ...)
+{
+	int ok;
+	va_list ap;
+
+	va_start(ap, tag);
+	ok =  TIFFVGetFieldDefaulted(tif, tag, ap);
+	va_end(ap);
+	return (ok);
+}
+
+struct _Int64Parts {
+	int32 low, high;
+};
+
+typedef union {
+	struct _Int64Parts part;
+	int64 value;
+} _Int64;
+
+float
+_TIFFUInt64ToFloat(uint64 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 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;
+	}
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_close.c b/third_party/libtiff/tif_close.c
new file mode 100644
index 0000000..13d2bab
--- /dev/null
+++ b/third_party/libtiff/tif_close.c
@@ -0,0 +1,140 @@
+/* $Id: tif_close.c,v 1.19 2010-03-10 18:56:48 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#include "tiffiop.h"
+#include <string.h>
+
+/************************************************************************/
+/*                            TIFFCleanup()                             */
+/************************************************************************/
+
+/**
+ * Auxiliary function to free the TIFF structure. Given structure will be
+ * completetly freed, so you should save opened file handle and pointer
+ * to the close procedure in external variables before calling
+ * _TIFFCleanup(), if you will need these ones to close the file.
+ * 
+ * @param tif A TIFF pointer.
+ */
+
+void
+TIFFCleanup(TIFF* tif)
+{
+	/*
+         * Flush buffered data and directory (if dirty).
+         */
+	if (tif->tif_mode != O_RDONLY)
+		TIFFFlush(tif);
+	(*tif->tif_cleanup)(tif);
+	TIFFFreeDirectory(tif);
+
+	if (tif->tif_dirlist)
+		_TIFFfree(tif->tif_dirlist);
+
+	/*
+         * Clean up client info links.
+         */
+	while( tif->tif_clientinfo )
+	{
+		TIFFClientInfoLink *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, (toff_t)tif->tif_size);
+
+	/*
+         * Clean up custom fields.
+         */
+	if (tif->tif_fields && tif->tif_nfields > 0) {
+		uint32 i;
+
+		for (i = 0; i < tif->tif_nfields; i++) {
+			TIFFField *fld = tif->tif_fields[i];
+			if (fld->field_bit == FIELD_CUSTOM &&
+			    strncmp("Tag ", fld->field_name, 4) == 0) {
+				_TIFFfree(fld->field_name);
+				_TIFFfree(fld);
+			}
+		}
+
+		_TIFFfree(tif->tif_fields);
+	}
+
+        if (tif->tif_nfieldscompat > 0) {
+                uint32 i;
+
+                for (i = 0; i < tif->tif_nfieldscompat; i++) {
+                        if (tif->tif_fieldscompat[i].allocated_size)
+                                _TIFFfree(tif->tif_fieldscompat[i].fields);
+                }
+                _TIFFfree(tif->tif_fieldscompat);
+        }
+
+	_TIFFfree(tif);
+}
+
+/************************************************************************/
+/*                            TIFFClose()                               */
+/************************************************************************/
+
+/**
+ * Close a previously opened TIFF file.
+ *
+ * TIFFClose closes a file that was previously opened with TIFFOpen().
+ * Any buffered data are flushed to the file, including the contents of
+ * the current directory (if modified); and all resources are reclaimed.
+ * 
+ * @param tif A TIFF pointer.
+ */
+
+void
+TIFFClose(TIFF* tif)
+{
+	TIFFCloseProc closeproc = tif->tif_closeproc;
+	thandle_t fd = tif->tif_clientdata;
+
+	TIFFCleanup(tif);
+	(void) (*closeproc)(fd);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_codec.c b/third_party/libtiff/tif_codec.c
new file mode 100644
index 0000000..7cb46f6
--- /dev/null
+++ b/third_party/libtiff/tif_codec.c
@@ -0,0 +1,165 @@
+/* $Id: tif_codec.c,v 1.17 2015-08-19 02:31:04 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Builtin Compression Scheme Configuration Support.
+ */
+#include "tiffiop.h"
+
+static int NotConfigured(TIFF*, int);
+
+#ifndef LZW_SUPPORT
+#define TIFFInitLZW NotConfigured
+#endif
+#ifndef PACKBITS_SUPPORT
+#define TIFFInitPackBits NotConfigured
+#endif
+#ifndef THUNDER_SUPPORT
+#define TIFFInitThunderScan NotConfigured
+#endif
+#ifndef NEXT_SUPPORT
+#define TIFFInitNeXT NotConfigured
+#endif
+#ifndef JPEG_SUPPORT
+#define TIFFInitJPEG NotConfigured
+#endif
+#ifndef OJPEG_SUPPORT
+#define TIFFInitOJPEG NotConfigured
+#endif
+#ifndef CCITT_SUPPORT
+#define TIFFInitCCITTRLE NotConfigured
+#define TIFFInitCCITTRLEW NotConfigured
+#define TIFFInitCCITTFax3 NotConfigured
+#define TIFFInitCCITTFax4 NotConfigured
+#endif
+#ifndef JBIG_SUPPORT
+#define TIFFInitJBIG NotConfigured
+#endif
+#ifndef ZIP_SUPPORT
+#define TIFFInitZIP NotConfigured
+#endif
+#ifndef PIXARLOG_SUPPORT
+#define TIFFInitPixarLog NotConfigured
+#endif
+#ifndef LOGLUV_SUPPORT
+#define TIFFInitSGILog NotConfigured
+#endif
+#ifndef LZMA_SUPPORT
+#define TIFFInitLZMA 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 },
+    { "LZMA",		COMPRESSION_LZMA,	TIFFInitLZMA },
+    { NULL,             0,                      NULL }
+};
+
+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);
+}
+
+static int
+NotConfigured(TIFF* tif, int scheme)
+{
+	(void) scheme;
+
+	tif->tif_fixuptags = _notConfigured;
+	tif->tif_decodestatus = FALSE;
+	tif->tif_setupdecode = _notConfigured;
+	tif->tif_encodestatus = FALSE;
+	tif->tif_setupencode = _notConfigured;
+	return (1);
+}
+
+/************************************************************************/
+/*                       TIFFIsCODECConfigured()                        */
+/************************************************************************/
+
+/**
+ * Check whether we have working codec for the specific coding scheme.
+ *
+ * @return returns 1 if the codec is configured and working. Otherwise
+ * 0 will be returned.
+ */
+
+int
+TIFFIsCODECConfigured(uint16 scheme)
+{
+	const TIFFCodec* codec = TIFFFindCODEC(scheme);
+
+	if(codec == NULL) {
+		return 0;
+	}
+	if(codec->init == NULL) {
+		return 0;
+	}
+	if(codec->init != NotConfigured){
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_color.c b/third_party/libtiff/tif_color.c
new file mode 100644
index 0000000..be4850c
--- /dev/null
+++ b/third_party/libtiff/tif_color.c
@@ -0,0 +1,287 @@
+/* $Id: tif_color.c,v 1.19 2010-12-14 02:22:42 faxguy 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 
+ * 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.
+ */
+
+/*
+ * CIE L*a*b* to CIE XYZ and CIE XYZ to RGB conversion routines are taken
+ * from the VIPS library (http://www.vips.ecs.soton.ac.uk) with
+ * the permission of John Cupitt, the VIPS author.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Color space conversion routines.
+ */
+
+#include "tiffiop.h"
+#include <math.h>
+
+/*
+ * 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)
+{
+	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;
+}
+
+#define RINT(R) ((uint32)((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)
+{
+	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,
+		    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;
+}
+
+/* 
+ * Convert color value from the YCbCr space to CIE XYZ.
+ * 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<<SHIFT) + 0.5))
+#define	ONE_HALF		((int32)(1<<(SHIFT-1)))
+#define	Code2V(c, RB, RW, CR)	((((c)-(int32)(RB))*(float)(CR))/(float)(((RW)-(RB)) ? ((RW)-(RB)) : 1))
+#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 Y, int32 Cb, int32 Cr,
+	       uint32 *r, uint32 *g, uint32 *b)
+{
+	int32 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);
+}
+
+/*
+ * Initialize the YCbCr->RGB conversion tables.  The conversion
+ * is done according to the 6.0 spec:
+ *
+ *    R = Y + Cr*(2 - 2*LumaRed)
+ *    B = Y + Cb*(2 - 2*LumaBlue)
+ *    G =   Y
+ *        - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen
+ *        - LumaRed*Cr*(2-2*LumaRed)/LumaGreen
+ *
+ * To avoid floating point arithmetic the fractional constants that
+ * come out of the equations are represented as fixed point values
+ * in the range 0...2^16.  We also eliminate multiplications by
+ * 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)
+{
+    TIFFRGBValue* clamptab;
+    int i;
+    
+#define LumaRed	    luma[0]
+#define LumaGreen   luma[1]
+#define LumaBlue    luma[2]
+
+    clamptab = (TIFFRGBValue*)(
+	(uint8*) 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);
+    ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256;
+    ycbcr->Cr_g_tab = (int32*) (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;
+
+#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);
+      }
+    }
+
+    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:
+ */
diff --git a/third_party/libtiff/tif_compress.c b/third_party/libtiff/tif_compress.c
new file mode 100644
index 0000000..20e72fd
--- /dev/null
+++ b/third_party/libtiff/tif_compress.c
@@ -0,0 +1,304 @@
+/* $Id: tif_compress.c,v 1.22 2010-03-10 18:56:48 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Compression Scheme Configuration Support.
+ */
+#include "tiffiop.h"
+
+static int
+TIFFNoEncode(TIFF* tif, const char* method)
+{
+	const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression);
+
+	if (c) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%s %s encoding is not implemented",
+			     c->name, method);
+	} else {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			"Compression scheme %u %s encoding is not implemented",
+			     tif->tif_dir.td_compression, method);
+	}
+	return (-1);
+}
+
+int
+_TIFFNoRowEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoEncode(tif, "scanline"));
+}
+
+int
+_TIFFNoStripEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoEncode(tif, "strip"));
+}
+
+int
+_TIFFNoTileEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoEncode(tif, "tile"));
+}
+
+static int
+TIFFNoDecode(TIFF* tif, const char* method)
+{
+	const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression);
+
+	if (c)
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%s %s decoding is not implemented",
+			     c->name, method);
+	else
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "Compression scheme %u %s decoding is not implemented",
+			     tif->tif_dir.td_compression, method);
+	return (-1);
+}
+
+int
+_TIFFNoFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+int
+_TIFFNoRowDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoDecode(tif, "scanline"));
+}
+
+int
+_TIFFNoStripDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoDecode(tif, "strip"));
+}
+
+int
+_TIFFNoTileDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) pp; (void) cc; (void) s;
+	return (TIFFNoDecode(tif, "tile"));
+}
+
+int
+_TIFFNoSeek(TIFF* tif, uint32 off)
+{
+	(void) off;
+	TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		     "Compression algorithm does not support random access");
+	return (0);
+}
+
+int
+_TIFFNoPreCode(TIFF* tif, uint16 s)
+{
+	(void) tif; (void) s;
+	return (1);
+}
+
+static int _TIFFtrue(TIFF* tif) { (void) tif; return (1); }
+static void _TIFFvoid(TIFF* tif) { (void) tif; }
+
+void
+_TIFFSetDefaultCompressionState(TIFF* tif)
+{
+	tif->tif_fixuptags = _TIFFNoFixupTags; 
+	tif->tif_decodestatus = TRUE;
+	tif->tif_setupdecode = _TIFFtrue;
+	tif->tif_predecode = _TIFFNoPreCode;
+	tif->tif_decoderow = _TIFFNoRowDecode;  
+	tif->tif_decodestrip = _TIFFNoStripDecode;
+	tif->tif_decodetile = _TIFFNoTileDecode;  
+	tif->tif_encodestatus = TRUE;
+	tif->tif_setupencode = _TIFFtrue;
+	tif->tif_preencode = _TIFFNoPreCode;
+	tif->tif_postencode = _TIFFtrue;
+	tif->tif_encoderow = _TIFFNoRowEncode;
+	tif->tif_encodestrip = _TIFFNoStripEncode;  
+	tif->tif_encodetile = _TIFFNoTileEncode;  
+	tif->tif_close = _TIFFvoid;
+	tif->tif_seek = _TIFFNoSeek;
+	tif->tif_cleanup = _TIFFvoid;
+	tif->tif_defstripsize = _TIFFDefaultStripSize;
+	tif->tif_deftilesize = _TIFFDefaultTileSize;
+	tif->tif_flags &= ~(TIFF_NOBITREV|TIFF_NOREADRAW);
+}
+
+int
+TIFFSetCompressionScheme(TIFF* tif, int scheme)
+{
+	const TIFFCodec *c = TIFFFindCODEC((uint16) scheme);
+
+	_TIFFSetDefaultCompressionState(tif);
+	/*
+	 * Don't treat an unknown compression scheme as an error.
+	 * This permits applications to open files with data that
+	 * the library does not have builtin support for, but which
+	 * may still be meaningful.
+	 */
+	return (c ? (*c->init)(tif, scheme) : 1);
+}
+
+/*
+ * Other compression schemes may be registered.  Registered
+ * schemes can also override the builtin versions provided
+ * by this library.
+ */
+typedef struct _codec {
+	struct _codec* next;
+	TIFFCodec* info;
+} codec_t;
+static codec_t* registeredCODECS = NULL;
+
+const TIFFCodec*
+TIFFFindCODEC(uint16 scheme)
+{
+	const TIFFCodec* c;
+	codec_t* cd;
+
+	for (cd = registeredCODECS; cd; cd = cd->next)
+		if (cd->info->scheme == scheme)
+			return ((const TIFFCodec*) cd->info);
+	for (c = _TIFFBuiltinCODECS; c->name; c++)
+		if (c->scheme == scheme)
+			return (c);
+	return ((const TIFFCodec*) 0);
+}
+
+TIFFCodec*
+TIFFRegisterCODEC(uint16 scheme, const char* name, TIFFInitMethod init)
+{
+	codec_t* cd = (codec_t*)
+	    _TIFFmalloc((tmsize_t)(sizeof (codec_t) + sizeof (TIFFCodec) + strlen(name)+1));
+
+	if (cd != NULL) {
+		cd->info = (TIFFCodec*) ((uint8*) cd + sizeof (codec_t));
+		cd->info->name = (char*)
+		    ((uint8*) cd->info + sizeof (TIFFCodec));
+		strcpy(cd->info->name, name);
+		cd->info->scheme = scheme;
+		cd->info->init = init;
+		cd->next = registeredCODECS;
+		registeredCODECS = cd;
+	} else {
+		TIFFErrorExt(0, "TIFFRegisterCODEC",
+		    "No space to register compression scheme %s", name);
+		return NULL;
+	}
+	return (cd->info);
+}
+
+void
+TIFFUnRegisterCODEC(TIFFCodec* c)
+{
+	codec_t* cd;
+	codec_t** pcd;
+
+	for (pcd = &registeredCODECS; (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);
+}
+
+/************************************************************************/
+/*                       TIFFGetConfisuredCODECs()                      */
+/************************************************************************/
+
+/**
+ * Get list of configured codecs, both built-in and registered by user.
+ * Caller is responsible to free this structure.
+ * 
+ * @return returns array of TIFFCodec records (the last record should be NULL)
+ * or NULL if function failed.
+ */
+
+TIFFCodec*
+TIFFGetConfiguredCODECs()
+{
+	int i = 1;
+	codec_t *cd;
+	const TIFFCodec* c;
+	TIFFCodec* codecs = NULL;
+	TIFFCodec* new_codecs;
+
+	for (cd = registeredCODECS; cd; cd = cd->next) {
+		new_codecs = (TIFFCodec *)
+			_TIFFrealloc(codecs, i * sizeof(TIFFCodec));
+		if (!new_codecs) {
+			_TIFFfree (codecs);
+			return NULL;
+		}
+		codecs = new_codecs;
+		_TIFFmemcpy(codecs + i - 1, cd, sizeof(TIFFCodec));
+		i++;
+	}
+	for (c = _TIFFBuiltinCODECS; c->name; c++) {
+		if (TIFFIsCODECConfigured(c->scheme)) {
+			new_codecs = (TIFFCodec *)
+				_TIFFrealloc(codecs, i * sizeof(TIFFCodec));
+			if (!new_codecs) {
+				_TIFFfree (codecs);
+				return NULL;
+			}
+			codecs = new_codecs;
+			_TIFFmemcpy(codecs + i - 1, (const void*)c, sizeof(TIFFCodec));
+			i++;
+		}
+	}
+
+	new_codecs = (TIFFCodec *) _TIFFrealloc(codecs, i * sizeof(TIFFCodec));
+	if (!new_codecs) {
+		_TIFFfree (codecs);
+		return NULL;
+	}
+	codecs = new_codecs;
+	_TIFFmemset(codecs + i - 1, 0, sizeof(TIFFCodec));
+
+	return codecs;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_dir.c b/third_party/libtiff/tif_dir.c
new file mode 100644
index 0000000..73212c0
--- /dev/null
+++ b/third_party/libtiff/tif_dir.c
@@ -0,0 +1,1705 @@
+/* $Id: tif_dir.c,v 1.121 2015-05-31 23:11: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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Tag Get & Set Routines.
+ * (and also some miscellaneous stuff)
+ */
+#include "tiffiop.h"
+
+/*
+ * These are used in the backwards compatibility code...
+ */
+#define DATATYPE_VOID		0       /* !untyped data */
+#define DATATYPE_INT		1       /* !signed integer data */
+#define DATATYPE_UINT		2       /* !unsigned integer data */
+#define DATATYPE_IEEEFP		3       /* !IEEE floating point data */
+
+static void
+setByteArray(void** vpp, void* vp, size_t nmemb, size_t elem_size)
+{
+	if (*vpp)
+		_TIFFfree(*vpp), *vpp = 0;
+	if (vp) {
+		tmsize_t bytes = (tmsize_t)(nmemb * elem_size);
+		if (elem_size && bytes / elem_size == nmemb)
+			*vpp = (void*) _TIFFmalloc(bytes);
+		if (*vpp)
+			_TIFFmemcpy(*vpp, vp, bytes);
+	}
+}
+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 _TIFFsetLong8Array(uint64** lpp, uint64* lp, uint32 n)
+    { setByteArray((void**) lpp, (void*) lp, n, sizeof (uint64)); }
+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)); }
+
+static void
+setDoubleArrayOneValue(double** vpp, double value, size_t nmemb)
+{
+	if (*vpp)
+		_TIFFfree(*vpp);
+	*vpp = _TIFFmalloc(nmemb*sizeof(double));
+	if (*vpp)
+	{
+		while (nmemb--)
+			((double*)*vpp)[nmemb] = value;
+	}
+}
+
+/*
+ * Install extra samples information.
+ */
+static int
+setExtraSamples(TIFFDirectory* td, va_list ap, uint32* v)
+{
+/* XXX: Unassociated alpha data == 999 is a known Corel Draw bug, see below */
+#define EXTRASAMPLE_COREL_UNASSALPHA 999 
+
+	uint16* va;
+	uint32 i;
+
+	*v = (uint16) va_arg(ap, uint16_vap);
+	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;
+
+#undef EXTRASAMPLE_COREL_UNASSALPHA
+}
+
+/*
+ * Confirm we have "samplesperpixel" ink names separated by \0.  Returns 
+ * zero if the ink names are not as expected.
+ */
+static uint32
+checkInkNamesString(TIFF* tif, uint32 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 < ep && *cp != '\0'; cp++) {}
+			if (cp >= ep)
+				goto bad;
+			cp++;				/* skip \0 */
+		}
+		return ((uint32)(cp-s));
+	}
+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);
+}
+
+static int
+_TIFFVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	static const char module[] = "_TIFFVSetField";
+
+	TIFFDirectory* td = &tif->tif_dir;
+	int status = 1;
+	uint32 v32, i, v;
+    double dblval;
+	char* s;
+	const TIFFField *fip = TIFFFindField(tif, tag, TIFF_ANY);
+	uint32 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 (ie. EXIF) 
+	 */
+	if (fip->field_bit == FIELD_CUSTOM) {
+		standard_tag = 0;
+	}
+
+	switch (standard_tag) {
+	case TIFFTAG_SUBFILETYPE:
+		td->td_subfiletype = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_IMAGEWIDTH:
+		td->td_imagewidth = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_IMAGELENGTH:
+		td->td_imagelength = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_BITSPERSAMPLE:
+		td->td_bitspersample = (uint16) 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 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 == 8)
+				tif->tif_postdecode = _TIFFNoPostDecode;
+			else if (td->td_bitspersample == 16)
+				tif->tif_postdecode = _TIFFSwab16BitData;
+			else if (td->td_bitspersample == 24)
+				tif->tif_postdecode = _TIFFSwab24BitData;
+			else if (td->td_bitspersample == 32)
+				tif->tif_postdecode = _TIFFSwab32BitData;
+			else if (td->td_bitspersample == 64)
+				tif->tif_postdecode = _TIFFSwab64BitData;
+			else if (td->td_bitspersample == 128) /* two 64's */
+				tif->tif_postdecode = _TIFFSwab64BitData;
+		}
+		break;
+	case TIFFTAG_COMPRESSION:
+		v = (uint16) va_arg(ap, uint16_vap);
+		/*
+		 * If we're changing the compression scheme, the notify the
+		 * previous module so that it can cleanup any state it's
+		 * setup.
+		 */
+		if (TIFFFieldSet(tif, FIELD_COMPRESSION)) {
+			if ((uint32)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, uint16_vap);
+		break;
+	case TIFFTAG_THRESHHOLDING:
+		td->td_threshholding = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_FILLORDER:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if (v != FILLORDER_LSB2MSB && v != FILLORDER_MSB2LSB)
+			goto badvalue;
+		td->td_fillorder = (uint16) v;
+		break;
+	case TIFFTAG_ORIENTATION:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if (v < ORIENTATION_TOPLEFT || ORIENTATION_LEFTBOT < v)
+			goto badvalue;
+		else
+			td->td_orientation = (uint16) v;
+		break;
+	case TIFFTAG_SAMPLESPERPIXEL:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if (v == 0)
+			goto badvalue;
+		td->td_samplesperpixel = (uint16) v;
+		break;
+	case TIFFTAG_ROWSPERSTRIP:
+		v32 = (uint32) 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, uint16_vap);
+		break;
+	case TIFFTAG_MAXSAMPLEVALUE:
+		td->td_maxsamplevalue = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_SMINSAMPLEVALUE:
+		if (tif->tif_flags & TIFF_PERSAMPLE)
+			_TIFFsetDoubleArray(&td->td_sminsamplevalue, va_arg(ap, double*), td->td_samplesperpixel);
+		else
+			setDoubleArrayOneValue(&td->td_sminsamplevalue, va_arg(ap, double), td->td_samplesperpixel);
+		break;
+	case TIFFTAG_SMAXSAMPLEVALUE:
+		if (tif->tif_flags & TIFF_PERSAMPLE)
+			_TIFFsetDoubleArray(&td->td_smaxsamplevalue, va_arg(ap, double*), td->td_samplesperpixel);
+		else
+			setDoubleArrayOneValue(&td->td_smaxsamplevalue, va_arg(ap, double), td->td_samplesperpixel);
+		break;
+	case TIFFTAG_XRESOLUTION:
+        dblval = va_arg(ap, double);
+        if( dblval < 0 )
+            goto badvaluedouble;
+		td->td_xresolution = (float) dblval;
+		break;
+	case TIFFTAG_YRESOLUTION:
+        dblval = va_arg(ap, double);
+        if( dblval < 0 )
+            goto badvaluedouble;
+		td->td_yresolution = (float) dblval;
+		break;
+	case TIFFTAG_PLANARCONFIG:
+		v = (uint16) va_arg(ap, uint16_vap);
+		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 = (uint16) va_arg(ap, uint16_vap);
+		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, uint16_vap);
+		td->td_pagenumber[1] = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_HALFTONEHINTS:
+		td->td_halftonehints[0] = (uint16) va_arg(ap, uint16_vap);
+		td->td_halftonehints[1] = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_COLORMAP:
+		v32 = (uint32)(1L<<td->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, uint16_vap)) != 0);
+		if (td->td_extrasamples) {
+			uint16 sv = EXTRASAMPLE_ASSOCALPHA;
+			_TIFFsetShortArray(&td->td_sampleinfo, &sv, 1);
+		}
+		break;
+	case TIFFTAG_TILEWIDTH:
+		v32 = (uint32) 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 = (uint32) 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 = (uint32) va_arg(ap, uint32);
+		if (v32 == 0)
+			goto badvalue32;
+		td->td_tiledepth = v32;
+		break;
+	case TIFFTAG_DATATYPE:
+		v = (uint16) 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) v;
+		break;
+	case TIFFTAG_SAMPLEFORMAT:
+		v = (uint16) va_arg(ap, uint16_vap);
+		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 )
+		    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) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_SUBIFD:
+		if ((tif->tif_flags & TIFF_INSUBIFD) == 0) {
+			td->td_nsubifd = (uint16) va_arg(ap, uint16_vap);
+			_TIFFsetLong8Array(&td->td_subifd, (uint64*) va_arg(ap, uint64*),
+			    (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, uint16_vap);
+		break;
+	case TIFFTAG_YCBCRSUBSAMPLING:
+		td->td_ycbcrsubsampling[0] = (uint16) va_arg(ap, uint16_vap);
+		td->td_ycbcrsubsampling[1] = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_TRANSFERFUNCTION:
+		v = (td->td_samplesperpixel - td->td_extrasamples) > 1 ? 3 : 1;
+		for (i = 0; i < v; i++)
+			_TIFFsetShortArray(&td->td_transferfunction[i],
+			    va_arg(ap, uint16*), 1L<<td->td_bitspersample);
+		break;
+	case TIFFTAG_REFERENCEBLACKWHITE:
+		/* XXX should check for null range */
+		_TIFFsetFloatArray(&td->td_refblackwhite, va_arg(ap, float*), 6);
+		break;
+	case TIFFTAG_INKNAMES:
+		v = (uint16) va_arg(ap, uint16_vap);
+		s = va_arg(ap, char*);
+		v = checkInkNamesString(tif, v, s);
+		status = v > 0;
+		if( v > 0 ) {
+			_TIFFsetNString(&td->td_inknames, s, v);
+			td->td_inknameslen = v;
+		}
+		break;
+	case TIFFTAG_PERSAMPLE:
+		v = (uint16) va_arg(ap, uint16_vap);
+		if( v == PERSAMPLE_MULTI )
+			tif->tif_flags |= TIFF_PERSAMPLE;
+		else
+			tif->tif_flags &= ~TIFF_PERSAMPLE;
+		break;
+	default: {
+		TIFFTagValue *tv;
+		int tv_size, iCustom;
+
+		/*
+		 * This can happen if multiple images are open with different
+		 * codecs which have private tags.  The global tag information
+		 * table may then have tags that are valid for one file but not
+		 * the other. If the client tries to set a tag that is not valid
+		 * for the image's codec then we'll arrive here.  This
+		 * happens, for example, when tiffcp is used to convert between
+		 * compression schemes and codec-specific tags are blindly copied.
+		 */
+		if(fip->field_bit != FIELD_CUSTOM) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "%s: Invalid %stag \"%s\" (not supported by codec)",
+			    tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "",
+			    fip->field_name);
+			status = 0;
+			break;
+		}
+
+		/*
+		 * Find the existing entry for this custom value.
+		 */
+		tv = NULL;
+		for (iCustom = 0; iCustom < td->td_customValueCount; iCustom++) {
+			if (td->td_customValues[iCustom].info->field_tag == tag) {
+				tv = td->td_customValues + iCustom;
+				if (tv->value != NULL) {
+					_TIFFfree(tv->value);
+					tv->value = NULL;
+				}
+				break;
+			}
+		}
+
+		/*
+		 * Grow the custom list if the entry was not found.
+		 */
+		if(tv == NULL) {
+			TIFFTagValue *new_customValues;
+
+			td->td_customValueCount++;
+			new_customValues = (TIFFTagValue *)
+			    _TIFFrealloc(td->td_customValues,
+			    sizeof(TIFFTagValue) * td->td_customValueCount);
+			if (!new_customValues) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "%s: Failed to allocate space for list of custom values",
+				    tif->tif_name);
+				status = 0;
+				goto end;
+			}
+
+			td->td_customValues = new_customValues;
+
+			tv = td->td_customValues + (td->td_customValueCount - 1);
+			tv->info = fip;
+			tv->value = NULL;
+			tv->count = 0;
+		}
+
+		/*
+		 * Set custom value ... save a copy of the custom tag value.
+		 */
+		tv_size = _TIFFDataSize(fip->field_type);
+		if (tv_size == 0) {
+			status = 0;
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "%s: Bad field type %d for \"%s\"",
+			    tif->tif_name, fip->field_type,
+			    fip->field_name);
+			goto end;
+		}
+
+		if (fip->field_type == TIFF_ASCII)
+		{
+			uint32 ma;
+			char* mb;
+			if (fip->field_passcount)
+			{
+				assert(fip->field_writecount==TIFF_VARIABLE2);
+				ma=(uint32)va_arg(ap,uint32);
+				mb=(char*)va_arg(ap,char*);
+			}
+			else
+			{
+				mb=(char*)va_arg(ap,char*);
+				ma=(uint32)(strlen(mb)+1);
+			}
+			tv->count=ma;
+			setByteArray(&tv->value,mb,ma,1);
+		}
+		else
+		{
+			if (fip->field_passcount) {
+				if (fip->field_writecount == TIFF_VARIABLE2)
+					tv->count = (uint32) 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 (tv->count == 0) {
+				status = 0;
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "%s: Null count for \"%s\" (type "
+					     "%d, writecount %d, passcount %d)",
+					     tif->tif_name,
+					     fip->field_name,
+					     fip->field_type,
+					     fip->field_writecount,
+					     fip->field_passcount);
+				goto end;
+			}
+
+			tv->value = _TIFFCheckMalloc(tif, tv->count, tv_size,
+			    "custom tag binary object");
+			if (!tv->value) {
+				status = 0;
+				goto end;
+			}
+
+			if (fip->field_tag == TIFFTAG_DOTRANGE 
+			    && strcmp(fip->field_name,"DotRange") == 0) {
+				/* TODO: This is an evil exception and should not have been
+				   handled this way ... likely best if we move it into
+				   the directory structure with an explicit field in 
+				   libtiff 4.1 and assign it a FIELD_ value */
+				uint16 v[2];
+				v[0] = (uint16)va_arg(ap, int);
+				v[1] = (uint16)va_arg(ap, int);
+				_TIFFmemcpy(tv->value, &v, 4);
+			}
+
+			else if (fip->field_passcount
+				  || fip->field_writecount == TIFF_VARIABLE
+				  || fip->field_writecount == TIFF_VARIABLE2
+				  || fip->field_writecount == TIFF_SPP
+				  || tv->count > 1) {
+				_TIFFmemcpy(tv->value, va_arg(ap, void *),
+				    tv->count * tv_size);
+			} else {
+				char *val = (char *)tv->value;
+				assert( tv->count == 1 );
+
+				switch (fip->field_type) {
+				case TIFF_BYTE:
+				case TIFF_UNDEFINED:
+					{
+						uint8 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_LONG8:
+				case TIFF_IFD8:
+					{
+						uint64 v = va_arg(ap, uint64);
+						_TIFFmemcpy(val, &v, tv_size);
+					}
+					break;
+				case TIFF_SLONG8:
+					{
+						int64 v = va_arg(ap, int64);
+						_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) {
+		const TIFFField* fip=TIFFFieldWithTag(tif,tag);
+		if (fip)                
+			TIFFSetFieldBit(tif, fip->field_bit);
+		tif->tif_flags |= TIFF_DIRTYDIRECT;
+	}
+
+end:
+	va_end(ap);
+	return (status);
+badvalue:
+        {
+		const TIFFField* fip=TIFFFieldWithTag(tif,tag);
+		TIFFErrorExt(tif->tif_clientdata, module,
+		     "%s: Bad value %u for \"%s\" tag",
+		     tif->tif_name, v,
+		     fip ? fip->field_name : "Unknown");
+		va_end(ap);
+        }
+	return (0);
+badvalue32:
+        {
+		const TIFFField* fip=TIFFFieldWithTag(tif,tag);
+		TIFFErrorExt(tif->tif_clientdata, module,
+		     "%s: Bad value %u for \"%s\" tag",
+		     tif->tif_name, v32,
+		     fip ? fip->field_name : "Unknown");
+		va_end(ap);
+        }
+	return (0);
+badvaluedouble:
+        {
+        const TIFFField* fip=TIFFFieldWithTag(tif,tag);
+        TIFFErrorExt(tif->tif_clientdata, module,
+             "%s: Bad value %f for \"%s\" tag",
+             tif->tif_name, dblval,
+             fip ? fip->field_name : "Unknown");
+        va_end(ap);
+        }
+    return (0);
+}
+
+/*
+ * Return 1/0 according to whether or not
+ * it is permissible to set the tag's value.
+ * Note that we allow ImageLength to be changed
+ * so that we can append and extend to images.
+ * Any other tag may not be altered once writing
+ * has commenced, unless its value has no effect
+ * on the format of the data that is written.
+ */
+static int
+OkToChangeTag(TIFF* tif, uint32 tag)
+{
+	const TIFFField* fip = TIFFFindField(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);
+}
+
+/*
+ * Record the value of a field in the
+ * internal directory structure.  The
+ * field will be written to the file
+ * when/if the directory structure is
+ * updated.
+ */
+int
+TIFFSetField(TIFF* tif, uint32 tag, ...)
+{
+	va_list ap;
+	int status;
+
+	va_start(ap, tag);
+	status = TIFFVSetField(tif, tag, ap);
+	va_end(ap);
+	return (status);
+}
+
+/*
+ * Clear the contents of the field in the internal structure.
+ */
+int
+TIFFUnsetField(TIFF* tif, uint32 tag)
+{
+    const TIFFField *fip =  TIFFFieldWithTag(tif, tag);
+    TIFFDirectory* td = &tif->tif_dir;
+
+    if( !fip )
+        return 0;
+
+    if( fip->field_bit != FIELD_CUSTOM )
+        TIFFClrFieldBit(tif, fip->field_bit);
+    else
+    {
+        TIFFTagValue *tv = NULL;
+        int i;
+
+        for (i = 0; i < td->td_customValueCount; i++) {
+                
+            tv = td->td_customValues + i;
+            if( tv->info->field_tag == tag )
+                break;
+        }
+
+        if( i < td->td_customValueCount )
+        {
+            _TIFFfree(tv->value);
+            for( ; i < td->td_customValueCount-1; i++) {
+                td->td_customValues[i] = td->td_customValues[i+1];
+            }
+            td->td_customValueCount--;
+        }
+    }
+        
+    tif->tif_flags |= TIFF_DIRTYDIRECT;
+
+    return (1);
+}
+
+/*
+ * Like TIFFSetField, but taking a varargs
+ * parameter list.  This routine is useful
+ * for building higher-level interfaces on
+ * top of the library.
+ */
+int
+TIFFVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	return OkToChangeTag(tif, tag) ?
+	    (*tif->tif_tagmethods.vsetfield)(tif, tag, ap) : 0;
+}
+
+static int
+_TIFFVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	TIFFDirectory* td = &tif->tif_dir;
+	int ret_val = 1;
+	uint32 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 (ie. EXIF) 
+	 */
+	if (fip->field_bit == FIELD_CUSTOM) {
+		standard_tag = 0;
+	}
+
+	switch (standard_tag) {
+		case TIFFTAG_SUBFILETYPE:
+			*va_arg(ap, uint32*) = td->td_subfiletype;
+			break;
+		case TIFFTAG_IMAGEWIDTH:
+			*va_arg(ap, uint32*) = td->td_imagewidth;
+			break;
+		case TIFFTAG_IMAGELENGTH:
+			*va_arg(ap, uint32*) = td->td_imagelength;
+			break;
+		case TIFFTAG_BITSPERSAMPLE:
+			*va_arg(ap, uint16*) = td->td_bitspersample;
+			break;
+		case TIFFTAG_COMPRESSION:
+			*va_arg(ap, uint16*) = td->td_compression;
+			break;
+		case TIFFTAG_PHOTOMETRIC:
+			*va_arg(ap, uint16*) = td->td_photometric;
+			break;
+		case TIFFTAG_THRESHHOLDING:
+			*va_arg(ap, uint16*) = td->td_threshholding;
+			break;
+		case TIFFTAG_FILLORDER:
+			*va_arg(ap, uint16*) = td->td_fillorder;
+			break;
+		case TIFFTAG_ORIENTATION:
+			*va_arg(ap, uint16*) = td->td_orientation;
+			break;
+		case TIFFTAG_SAMPLESPERPIXEL:
+			*va_arg(ap, uint16*) = td->td_samplesperpixel;
+			break;
+		case TIFFTAG_ROWSPERSTRIP:
+			*va_arg(ap, uint32*) = td->td_rowsperstrip;
+			break;
+		case TIFFTAG_MINSAMPLEVALUE:
+			*va_arg(ap, uint16*) = td->td_minsamplevalue;
+			break;
+		case TIFFTAG_MAXSAMPLEVALUE:
+			*va_arg(ap, uint16*) = td->td_maxsamplevalue;
+			break;
+		case TIFFTAG_SMINSAMPLEVALUE:
+			if (tif->tif_flags & TIFF_PERSAMPLE)
+				*va_arg(ap, double**) = td->td_sminsamplevalue;
+			else
+			{
+				/* libtiff historially treats this as a single value. */
+				uint16 i;
+				double v = td->td_sminsamplevalue[0];
+				for (i=1; i < td->td_samplesperpixel; ++i)
+					if( td->td_sminsamplevalue[i] < v )
+						v = td->td_sminsamplevalue[i];
+				*va_arg(ap, double*) = v;
+			}
+			break;
+		case TIFFTAG_SMAXSAMPLEVALUE:
+			if (tif->tif_flags & TIFF_PERSAMPLE)
+				*va_arg(ap, double**) = td->td_smaxsamplevalue;
+			else
+			{
+				/* libtiff historially treats this as a single value. */
+				uint16 i;
+				double v = td->td_smaxsamplevalue[0];
+				for (i=1; i < td->td_samplesperpixel; ++i)
+					if( td->td_smaxsamplevalue[i] > v )
+						v = td->td_smaxsamplevalue[i];
+				*va_arg(ap, double*) = v;
+			}
+			break;
+		case TIFFTAG_XRESOLUTION:
+			*va_arg(ap, float*) = td->td_xresolution;
+			break;
+		case TIFFTAG_YRESOLUTION:
+			*va_arg(ap, float*) = td->td_yresolution;
+			break;
+		case TIFFTAG_PLANARCONFIG:
+			*va_arg(ap, uint16*) = td->td_planarconfig;
+			break;
+		case TIFFTAG_XPOSITION:
+			*va_arg(ap, float*) = td->td_xposition;
+			break;
+		case TIFFTAG_YPOSITION:
+			*va_arg(ap, float*) = td->td_yposition;
+			break;
+		case TIFFTAG_RESOLUTIONUNIT:
+			*va_arg(ap, uint16*) = td->td_resolutionunit;
+			break;
+		case TIFFTAG_PAGENUMBER:
+			*va_arg(ap, uint16*) = td->td_pagenumber[0];
+			*va_arg(ap, uint16*) = td->td_pagenumber[1];
+			break;
+		case TIFFTAG_HALFTONEHINTS:
+			*va_arg(ap, uint16*) = td->td_halftonehints[0];
+			*va_arg(ap, uint16*) = 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];
+			break;
+		case TIFFTAG_STRIPOFFSETS:
+		case TIFFTAG_TILEOFFSETS:
+			_TIFFFillStriles( tif );
+			*va_arg(ap, uint64**) = td->td_stripoffset;
+			break;
+		case TIFFTAG_STRIPBYTECOUNTS:
+		case TIFFTAG_TILEBYTECOUNTS:
+			_TIFFFillStriles( tif );
+			*va_arg(ap, uint64**) = td->td_stripbytecount;
+			break;
+		case TIFFTAG_MATTEING:
+			*va_arg(ap, uint16*) =
+			    (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;
+			break;
+		case TIFFTAG_TILEWIDTH:
+			*va_arg(ap, uint32*) = td->td_tilewidth;
+			break;
+		case TIFFTAG_TILELENGTH:
+			*va_arg(ap, uint32*) = td->td_tilelength;
+			break;
+		case TIFFTAG_TILEDEPTH:
+			*va_arg(ap, uint32*) = td->td_tiledepth;
+			break;
+		case TIFFTAG_DATATYPE:
+			switch (td->td_sampleformat) {
+				case SAMPLEFORMAT_UINT:
+					*va_arg(ap, uint16*) = DATATYPE_UINT;
+					break;
+				case SAMPLEFORMAT_INT:
+					*va_arg(ap, uint16*) = DATATYPE_INT;
+					break;
+				case SAMPLEFORMAT_IEEEFP:
+					*va_arg(ap, uint16*) = DATATYPE_IEEEFP;
+					break;
+				case SAMPLEFORMAT_VOID:
+					*va_arg(ap, uint16*) = DATATYPE_VOID;
+					break;
+			}
+			break;
+		case TIFFTAG_SAMPLEFORMAT:
+			*va_arg(ap, uint16*) = td->td_sampleformat;
+			break;
+		case TIFFTAG_IMAGEDEPTH:
+			*va_arg(ap, uint32*) = td->td_imagedepth;
+			break;
+		case TIFFTAG_SUBIFD:
+			*va_arg(ap, uint16*) = td->td_nsubifd;
+			*va_arg(ap, uint64**) = td->td_subifd;
+			break;
+		case TIFFTAG_YCBCRPOSITIONING:
+			*va_arg(ap, uint16*) = td->td_ycbcrpositioning;
+			break;
+		case TIFFTAG_YCBCRSUBSAMPLING:
+			*va_arg(ap, uint16*) = td->td_ycbcrsubsampling[0];
+			*va_arg(ap, uint16*) = 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];
+			}
+			break;
+		case TIFFTAG_REFERENCEBLACKWHITE:
+			*va_arg(ap, float**) = td->td_refblackwhite;
+			break;
+		case TIFFTAG_INKNAMES:
+			*va_arg(ap, char**) = td->td_inknames;
+			break;
+		default:
+			{
+				int i;
+
+				/*
+				 * This can happen if multiple images are open
+				 * with different codecs which have private
+				 * tags.  The global tag information table may
+				 * then have tags that are valid for one file
+				 * but not the other. If the client tries to
+				 * get a tag that is not valid for the image's
+				 * codec then we'll arrive here.
+				 */
+				if( fip->field_bit != FIELD_CUSTOM )
+				{
+					TIFFErrorExt(tif->tif_clientdata, "_TIFFVGetField",
+					    "%s: Invalid %stag \"%s\" "
+					    "(not supported by codec)",
+					    tif->tif_name,
+					    isPseudoTag(tag) ? "pseudo-" : "",
+					    fip->field_name);
+					ret_val = 0;
+					break;
+				}
+
+				/*
+				 * Do we have a custom value?
+				 */
+				ret_val = 0;
+				for (i = 0; i < td->td_customValueCount; i++) {
+					TIFFTagValue *tv = td->td_customValues + i;
+
+					if (tv->info->field_tag != tag)
+						continue;
+
+					if (fip->field_passcount) {
+						if (fip->field_readcount == TIFF_VARIABLE2)
+							*va_arg(ap, uint32*) = (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_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*) = ((uint16 *)tv->value)[0];
+						*va_arg(ap, uint16*) = ((uint16 *)tv->value)[1];
+						ret_val = 1;
+					} else {
+						if (fip->field_type == TIFF_ASCII
+						    || fip->field_readcount == TIFF_VARIABLE
+						    || fip->field_readcount == TIFF_VARIABLE2
+						    || fip->field_readcount == TIFF_SPP
+						    || tv->count > 1) {
+							*va_arg(ap, void **) = tv->value;
+							ret_val = 1;
+						} else {
+							char *val = (char *)tv->value;
+							assert( tv->count == 1 );
+							switch (fip->field_type) {
+							case TIFF_BYTE:
+							case TIFF_UNDEFINED:
+								*va_arg(ap, uint8*) =
+									*(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_LONG8:
+							case TIFF_IFD8:
+								*va_arg(ap, uint64*) =
+									*(uint64 *)val;
+								ret_val = 1;
+								break;
+							case TIFF_SLONG8:
+								*va_arg(ap, int64*) =
+									*(int64 *)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;
+							}
+						}
+					}
+					break;
+				}
+			}
+	}
+	return(ret_val);
+}
+
+/*
+ * Return the value of a field in the
+ * internal directory structure.
+ */
+int
+TIFFGetField(TIFF* tif, uint32 tag, ...)
+{
+	int status;
+	va_list ap;
+
+	va_start(ap, tag);
+	status = TIFFVGetField(tif, tag, ap);
+	va_end(ap);
+	return (status);
+}
+
+/*
+ * Like TIFFGetField, but taking a varargs
+ * parameter list.  This routine is useful
+ * for building higher-level interfaces on
+ * top of the library.
+ */
+int
+TIFFVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY);
+	return (fip && (isPseudoTag(tag) || TIFFFieldSet(tif, fip->field_bit)) ?
+	    (*tif->tif_tagmethods.vgetfield)(tif, tag, ap) : 0);
+}
+
+#define	CleanupField(member) {		\
+    if (td->member) {			\
+	_TIFFfree(td->member);		\
+	td->member = 0;			\
+    }					\
+}
+
+/*
+ * Release storage associated with a directory.
+ */
+void
+TIFFFreeDirectory(TIFF* tif)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	int            i;
+
+	_TIFFmemset(td->td_fieldsset, 0, FIELD_SETLONGS);
+	CleanupField(td_sminsamplevalue);
+	CleanupField(td_smaxsamplevalue);
+	CleanupField(td_colormap[0]);
+	CleanupField(td_colormap[1]);
+	CleanupField(td_colormap[2]);
+	CleanupField(td_sampleinfo);
+	CleanupField(td_subifd);
+	CleanupField(td_inknames);
+	CleanupField(td_refblackwhite);
+	CleanupField(td_transferfunction[0]);
+	CleanupField(td_transferfunction[1]);
+	CleanupField(td_transferfunction[2]);
+	CleanupField(td_stripoffset);
+	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);
+
+#if defined(DEFER_STRILE_LOAD)
+        _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
+        _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));
+#endif        
+}
+#undef CleanupField
+
+/*
+ * Client Tag extension support (from Niles Ritter).
+ */
+static TIFFExtendProc _TIFFextender = (TIFFExtendProc) NULL;
+
+TIFFExtendProc
+TIFFSetTagExtender(TIFFExtendProc extender)
+{
+	TIFFExtendProc prev = _TIFFextender;
+	_TIFFextender = extender;
+	return (prev);
+}
+
+/*
+ * Setup for a new directory.  Should we automatically call
+ * TIFFWriteDirectory() if the current one is dirty?
+ *
+ * The newly created directory will not exist on the file till
+ * TIFFWriteDirectory(), TIFFFlush() or TIFFClose() is called.
+ */
+int
+TIFFCreateDirectory(TIFF* tif)
+{
+	TIFFDefaultDirectory(tif);
+	tif->tif_diroff = 0;
+	tif->tif_nextdiroff = 0;
+	tif->tif_curoff = 0;
+	tif->tif_row = (uint32) -1;
+	tif->tif_curstrip = (uint32) -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 irreversable
+	 * 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) -1;
+	tif->tif_curstrip = (uint32) -1;
+
+	return 0;
+}
+
+int
+TIFFCreateEXIFDirectory(TIFF* tif)
+{
+	const TIFFFieldArray* exifFieldArray;
+	exifFieldArray = _TIFFGetExifFields();
+	return TIFFCreateCustomDirectory(tif, exifFieldArray);
+}
+
+/*
+ * Setup a default directory structure.
+ */
+int
+TIFFDefaultDirectory(TIFF* tif)
+{
+	register TIFFDirectory* td = &tif->tif_dir;
+	const TIFFFieldArray* tiffFieldArray;
+
+	tiffFieldArray = _TIFFGetFields();
+	_TIFFSetupFields(tif, tiffFieldArray);   
+
+	_TIFFmemset(td, 0, sizeof (*td));
+	td->td_fillorder = FILLORDER_MSB2LSB;
+	td->td_bitspersample = 1;
+	td->td_threshholding = THRESHHOLD_BILEVEL;
+	td->td_orientation = ORIENTATION_TOPLEFT;
+	td->td_samplesperpixel = 1;
+	td->td_rowsperstrip = (uint32) -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,
+	 *  but do some prior cleanup first. (http://trac.osgeo.org/gdal/ticket/5054)
+	 */
+	if (tif->tif_nfieldscompat > 0) {
+		uint32 i;
+
+		for (i = 0; i < tif->tif_nfieldscompat; i++) {
+				if (tif->tif_fieldscompat[i].allocated_size)
+						_TIFFfree(tif->tif_fieldscompat[i].fields);
+		}
+		_TIFFfree(tif->tif_fieldscompat);
+		tif->tif_nfieldscompat = 0;
+		tif->tif_fieldscompat = NULL;
+	}
+	if (_TIFFextender)
+		(*_TIFFextender)(tif);
+	(void) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+	/*
+	 * NB: The directory is marked dirty as a result of setting
+	 * up the default compression scheme.  However, this really
+	 * isn't correct -- we want TIFF_DIRTYDIRECT to be set only
+	 * if the user does something.  We could just do the setup
+	 * by hand, but it seems better to use the normal mechanism
+	 * (i.e. TIFFSetField).
+	 */
+	tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+
+	/*
+	 * As per http://bugzilla.remotesensing.org/show_bug.cgi?id=19
+	 * we clear the ISTILED flag when setting up a new directory.
+	 * Should we also be clearing stuff like INSUBIFD?
+	 */
+	tif->tif_flags &= ~TIFF_ISTILED;
+
+	return (1);
+}
+
+static int
+TIFFAdvanceDirectory(TIFF* tif, uint64* nextdir, uint64* off)
+{
+	static const char module[] = "TIFFAdvanceDirectory";
+	if (isMapped(tif))
+	{
+		uint64 poff=*nextdir;
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			tmsize_t poffa,poffb,poffc,poffd;
+			uint16 dircount;
+			uint32 nextdir32;
+			poffa=(tmsize_t)poff;
+			poffb=poffa+sizeof(uint16);
+			if (((uint64)poffa!=poff)||(poffb<poffa)||(poffb<(tmsize_t)sizeof(uint16))||(poffb>tif->tif_size))
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count");
+                                  *nextdir=0;
+				return(0);
+			}
+			_TIFFmemcpy(&dircount,tif->tif_base+poffa,sizeof(uint16));
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabShort(&dircount);
+			poffc=poffb+dircount*12;
+			poffd=poffc+sizeof(uint32);
+			if ((poffc<poffb)||(poffc<dircount*12)||(poffd<poffc)||(poffd<(tmsize_t)sizeof(uint32))||(poffd>tif->tif_size))
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory link");
+				return(0);
+			}
+			if (off!=NULL)
+				*off=(uint64)poffc;
+			_TIFFmemcpy(&nextdir32,tif->tif_base+poffc,sizeof(uint32));
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong(&nextdir32);
+			*nextdir=nextdir32;
+		}
+		else
+		{
+			tmsize_t poffa,poffb,poffc,poffd;
+			uint64 dircount64;
+			uint16 dircount16;
+			poffa=(tmsize_t)poff;
+			poffb=poffa+sizeof(uint64);
+			if (((uint64)poffa!=poff)||(poffb<poffa)||(poffb<(tmsize_t)sizeof(uint64))||(poffb>tif->tif_size))
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count");
+				return(0);
+			}
+			_TIFFmemcpy(&dircount64,tif->tif_base+poffa,sizeof(uint64));
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8(&dircount64);
+			if (dircount64>0xFFFF)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Sanity check on directory count failed");
+				return(0);
+			}
+			dircount16=(uint16)dircount64;
+			poffc=poffb+dircount16*20;
+			poffd=poffc+sizeof(uint64);
+			if ((poffc<poffb)||(poffc<dircount16*20)||(poffd<poffc)||(poffd<(tmsize_t)sizeof(uint64))||(poffd>tif->tif_size))
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory link");
+				return(0);
+			}
+			if (off!=NULL)
+				*off=(uint64)poffc;
+			_TIFFmemcpy(nextdir,tif->tif_base+poffc,sizeof(uint64));
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8(nextdir);
+		}
+		return(1);
+	}
+	else
+	{
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			uint16 dircount;
+			uint32 nextdir32;
+			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*12, SEEK_CUR);
+			else
+				(void) TIFFSeekFile(tif,
+				    dircount*12, SEEK_CUR);
+			if (!ReadOK(tif, &nextdir32, sizeof (uint32))) {
+				TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link",
+				    tif->tif_name);
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong(&nextdir32);
+			*nextdir=nextdir32;
+		}
+		else
+		{
+			uint64 dircount64;
+			uint16 dircount16;
+			if (!SeekOK(tif, *nextdir) ||
+			    !ReadOK(tif, &dircount64, sizeof (uint64))) {
+				TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count",
+				    tif->tif_name);
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&dircount64);
+			if (dircount64>0xFFFF)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory count");
+				return(0);
+			}
+			dircount16 = (uint16)dircount64;
+			if (off != NULL)
+				*off = TIFFSeekFile(tif,
+				    dircount16*20, SEEK_CUR);
+			else
+				(void) TIFFSeekFile(tif,
+				    dircount16*20, SEEK_CUR);
+			if (!ReadOK(tif, nextdir, sizeof (uint64))) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+                                             "%s: Error fetching directory link",
+				    tif->tif_name);
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(nextdir);
+		}
+		return (1);
+	}
+}
+
+/*
+ * Count the number of directories in a file.
+ */
+uint16
+TIFFNumberOfDirectories(TIFF* tif)
+{
+	static const char module[] = "TIFFNumberOfDirectories";
+	uint64 nextdir;
+	uint16 n;
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+		nextdir = tif->tif_header.classic.tiff_diroff;
+	else
+		nextdir = tif->tif_header.big.tiff_diroff;
+	n = 0;
+	while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL))
+        {
+                if (n != 65535) {
+                        ++n;
+                }
+		else
+                {
+                        TIFFErrorExt(tif->tif_clientdata, module,
+                                     "Directory count exceeded 65535 limit,"
+                                     " giving up on counting.");
+                        return (65535);
+                }
+        }
+	return (n);
+}
+
+/*
+ * Set the n-th directory as the current directory.
+ * NB: Directories are numbered starting at 0.
+ */
+int
+TIFFSetDirectory(TIFF* tif, uint16 dirn)
+{
+	uint64 nextdir;
+	uint16 n;
+
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+		nextdir = tif->tif_header.classic.tiff_diroff;
+	else
+		nextdir = tif->tif_header.big.tiff_diroff;
+	for (n = dirn; n > 0 && nextdir != 0; n--)
+		if (!TIFFAdvanceDirectory(tif, &nextdir, NULL))
+			return (0);
+	tif->tif_nextdiroff = nextdir;
+	/*
+	 * Set curdir to the actual directory index.  The
+	 * -1 is because TIFFReadDirectory will increment
+	 * tif_curdir after successfully reading the directory.
+	 */
+	tif->tif_curdir = (dirn - n) - 1;
+	/*
+	 * Reset tif_dirnumber counter and start new list of seen directories.
+	 * We need this to prevent IFD loops.
+	 */
+	tif->tif_dirnumber = 0;
+	return (TIFFReadDirectory(tif));
+}
+
+/*
+ * Set the current directory to be the directory
+ * located at the specified file offset.  This interface
+ * is used mainly to access directories linked with
+ * the SubIFD tag (e.g. thumbnail images).
+ */
+int
+TIFFSetSubDirectory(TIFF* tif, uint64 diroff)
+{
+	tif->tif_nextdiroff = diroff;
+	/*
+	 * Reset tif_dirnumber counter and start new list of seen directories.
+	 * We need this to prevent IFD loops.
+	 */
+	tif->tif_dirnumber = 0;
+	return (TIFFReadDirectory(tif));
+}
+
+/*
+ * Return file offset of the current directory.
+ */
+uint64
+TIFFCurrentDirOffset(TIFF* tif)
+{
+	return (tif->tif_diroff);
+}
+
+/*
+ * Return an indication of whether or not we are
+ * at the last directory in the file.
+ */
+int
+TIFFLastDirectory(TIFF* tif)
+{
+	return (tif->tif_nextdiroff == 0);
+}
+
+/*
+ * Unlink the specified directory from the directory chain.
+ */
+int
+TIFFUnlinkDirectory(TIFF* tif, uint16 dirn)
+{
+	static const char module[] = "TIFFUnlinkDirectory";
+	uint64 nextdir;
+	uint64 off;
+	uint16 n;
+
+	if (tif->tif_mode == O_RDONLY) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+                             "Can not unlink directory in read-only file");
+		return (0);
+	}
+	/*
+	 * Go to the directory before the one we want
+	 * to unlink and nab the offset of the link
+	 * field we'll need to patch.
+	 */
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		nextdir = tif->tif_header.classic.tiff_diroff;
+		off = 4;
+	}
+	else
+	{
+		nextdir = tif->tif_header.big.tiff_diroff;
+		off = 8;
+	}
+	for (n = dirn-1; n > 0; n--) {
+		if (nextdir == 0) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Directory %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_BIGTIFF))
+	{
+		uint32 nextdir32;
+		nextdir32=(uint32)nextdir;
+		assert((uint64)nextdir32==nextdir);
+		if (tif->tif_flags & TIFF_SWAB)
+			TIFFSwabLong(&nextdir32);
+		if (!WriteOK(tif, &nextdir32, sizeof (uint32))) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link");
+			return (0);
+		}
+	}
+	else
+	{
+		if (tif->tif_flags & TIFF_SWAB)
+			TIFFSwabLong8(&nextdir);
+		if (!WriteOK(tif, &nextdir, sizeof (uint64))) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link");
+			return (0);
+		}
+	}
+	/*
+	 * Leave directory state setup safely.  We don't have
+	 * facilities for doing inserting and removing directories,
+	 * so it's safest to just invalidate everything.  This
+	 * means that the caller can only append to the directory
+	 * chain.
+	 */
+	(*tif->tif_cleanup)(tif);
+	if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) {
+		_TIFFfree(tif->tif_rawdata);
+		tif->tif_rawdata = NULL;
+		tif->tif_rawcc = 0;
+                tif->tif_rawdataoff = 0;
+                tif->tif_rawdataloaded = 0;
+	}
+	tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP|TIFF_POSTENCODE|TIFF_BUF4WRITE);
+	TIFFFreeDirectory(tif);
+	TIFFDefaultDirectory(tif);
+	tif->tif_diroff = 0;			/* force link on next write */
+	tif->tif_nextdiroff = 0;		/* next write must be at end */
+	tif->tif_curoff = 0;
+	tif->tif_row = (uint32) -1;
+	tif->tif_curstrip = (uint32) -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/third_party/libtiff/tif_dir.h b/third_party/libtiff/tif_dir.h
new file mode 100644
index 0000000..6af5f3d
--- /dev/null
+++ b/third_party/libtiff/tif_dir.h
@@ -0,0 +1,308 @@
+/* $Id: tif_dir.h,v 1.54 2011-02-18 20:53:05 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFDIR_
+#define	_TIFFDIR_
+/*
+ * ``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 tdir_tag;        /* see below */
+	uint16 tdir_type;       /* data type; see below */
+	uint64 tdir_count;      /* number of items; length in spec */
+	union {
+		uint16 toff_short;
+		uint32 toff_long;
+		uint64 toff_long8;
+	} tdir_offset;		/* either offset or the data itself if fits */
+} 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;
+	double* 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 */
+	uint32  td_stripsperimage;  
+	uint32  td_nstrips;              /* size of offset & bytecount arrays */
+	uint64* td_stripoffset;
+	uint64* td_stripbytecount;
+	int     td_stripbytecountsorted; /* is the bytecount array sorted ascending? */
+#if defined(DEFER_STRILE_LOAD)
+        TIFFDirEntry td_stripoffset_entry;    /* for deferred loading */
+        TIFFDirEntry td_stripbytecount_entry; /* for deferred loading */
+#endif
+	uint16  td_nsubifd;
+	uint64* td_subifd;
+	/* YCbCr parameters */
+	uint16  td_ycbcrsubsampling[2];
+	uint16  td_ycbcrpositioning;
+	/* Colorimetry parameters */
+	uint16* td_transferfunction[3];
+	float*	td_refblackwhite;
+	/* CMYK parameters */
+	int     td_inknameslen;
+	char*   td_inknames;
+
+	int     td_customValueCount;
+        TIFFTagValue *td_customValues;
+} TIFFDirectory;
+
+/*
+ * Field flags used to indicate fields that have been set in a directory, and
+ * to reference fields when manipulating a directory.
+ */
+
+/*
+ * FIELD_IGNORE is used to signify tags that are to be processed but otherwise
+ * ignored.  This permits antiquated tags to be quietly read and discarded.
+ * Note that a bit *is* allocated for ignored tags; this is understood by the
+ * directory reading logic which uses this fact to avoid special-case handling
+ */
+#define FIELD_IGNORE                   0
+
+/* multi-item fields */
+#define FIELD_IMAGEDIMENSIONS          1
+#define FIELD_TILEDIMENSIONS           2
+#define FIELD_RESOLUTION               3
+#define FIELD_POSITION                 4
+
+/* single-item fields */
+#define FIELD_SUBFILETYPE              5
+#define FIELD_BITSPERSAMPLE            6
+#define FIELD_COMPRESSION              7
+#define FIELD_PHOTOMETRIC              8
+#define FIELD_THRESHHOLDING            9
+#define FIELD_FILLORDER                10
+#define FIELD_ORIENTATION              15
+#define FIELD_SAMPLESPERPIXEL          16
+#define FIELD_ROWSPERSTRIP             17
+#define FIELD_MINSAMPLEVALUE           18
+#define FIELD_MAXSAMPLEVALUE           19
+#define FIELD_PLANARCONFIG             20
+#define FIELD_RESOLUTIONUNIT           22
+#define FIELD_PAGENUMBER               23
+#define FIELD_STRIPBYTECOUNTS          24
+#define FIELD_STRIPOFFSETS             25
+#define FIELD_COLORMAP                 26
+#define FIELD_EXTRASAMPLES             31
+#define FIELD_SAMPLEFORMAT             32
+#define FIELD_SMINSAMPLEVALUE          33
+#define FIELD_SMAXSAMPLEVALUE          34
+#define FIELD_IMAGEDEPTH               35
+#define FIELD_TILEDEPTH                36
+#define FIELD_HALFTONEHINTS            37
+#define FIELD_YCBCRSUBSAMPLING         39
+#define FIELD_YCBCRPOSITIONING         40
+#define	FIELD_REFBLACKWHITE            41
+#define FIELD_TRANSFERFUNCTION         44
+#define FIELD_INKNAMES                 46
+#define FIELD_SUBIFD                   49
+/*      FIELD_CUSTOM (see tiffio.h)    65 */
+/* end of support for well-known tags; codec-private tags follow */
+#define FIELD_CODEC                    66  /* base of codec-private tags */
+
+
+/*
+ * Pseudo-tags don't normally need field bits since they are not written to an
+ * output file (by definition). The library also has express logic to always
+ * query a codec for a pseudo-tag so allocating a field bit for one is a
+ * waste.   If codec wants to promote the notion of a pseudo-tag being ``set''
+ * or ``unset'' then it can do using internal state flags without polluting
+ * the field bit space defined for real tags.
+ */
+#define FIELD_PSEUDO			0
+
+#define FIELD_LAST			(32*FIELD_SETLONGS-1)
+
+#define BITn(n)				(((unsigned long)1L)<<((n)&0x1f))
+#define BITFIELDn(tif, n)		((tif)->tif_dir.td_fieldsset[(n)/32])
+#define TIFFFieldSet(tif, field)	(BITFIELDn(tif, field) & BITn(field))
+#define TIFFSetFieldBit(tif, field)	(BITFIELDn(tif, field) |= BITn(field))
+#define TIFFClrFieldBit(tif, field)	(BITFIELDn(tif, field) &= ~BITn(field))
+
+#define FieldSet(fields, f)		(fields[(f)/32] & BITn(f))
+#define ResetFieldBit(fields, f)	(fields[(f)/32] &= ~BITn(f))
+
+typedef enum {
+	TIFF_SETGET_UNDEFINED = 0,
+	TIFF_SETGET_ASCII = 1,
+	TIFF_SETGET_UINT8 = 2,
+	TIFF_SETGET_SINT8 = 3,
+	TIFF_SETGET_UINT16 = 4,
+	TIFF_SETGET_SINT16 = 5,
+	TIFF_SETGET_UINT32 = 6,
+	TIFF_SETGET_SINT32 = 7,
+	TIFF_SETGET_UINT64 = 8,
+	TIFF_SETGET_SINT64 = 9,
+	TIFF_SETGET_FLOAT = 10,
+	TIFF_SETGET_DOUBLE = 11,
+	TIFF_SETGET_IFD8 = 12,
+	TIFF_SETGET_INT = 13,
+	TIFF_SETGET_UINT16_PAIR = 14,
+	TIFF_SETGET_C0_ASCII = 15,
+	TIFF_SETGET_C0_UINT8 = 16,
+	TIFF_SETGET_C0_SINT8 = 17,
+	TIFF_SETGET_C0_UINT16 = 18,
+	TIFF_SETGET_C0_SINT16 = 19,
+	TIFF_SETGET_C0_UINT32 = 20,
+	TIFF_SETGET_C0_SINT32 = 21,
+	TIFF_SETGET_C0_UINT64 = 22,
+	TIFF_SETGET_C0_SINT64 = 23,
+	TIFF_SETGET_C0_FLOAT = 24,
+	TIFF_SETGET_C0_DOUBLE = 25,
+	TIFF_SETGET_C0_IFD8 = 26,
+	TIFF_SETGET_C16_ASCII = 27,
+	TIFF_SETGET_C16_UINT8 = 28,
+	TIFF_SETGET_C16_SINT8 = 29,
+	TIFF_SETGET_C16_UINT16 = 30,
+	TIFF_SETGET_C16_SINT16 = 31,
+	TIFF_SETGET_C16_UINT32 = 32,
+	TIFF_SETGET_C16_SINT32 = 33,
+	TIFF_SETGET_C16_UINT64 = 34,
+	TIFF_SETGET_C16_SINT64 = 35,
+	TIFF_SETGET_C16_FLOAT = 36,
+	TIFF_SETGET_C16_DOUBLE = 37,
+	TIFF_SETGET_C16_IFD8 = 38,
+	TIFF_SETGET_C32_ASCII = 39,
+	TIFF_SETGET_C32_UINT8 = 40,
+	TIFF_SETGET_C32_SINT8 = 41,
+	TIFF_SETGET_C32_UINT16 = 42,
+	TIFF_SETGET_C32_SINT16 = 43,
+	TIFF_SETGET_C32_UINT32 = 44,
+	TIFF_SETGET_C32_SINT32 = 45,
+	TIFF_SETGET_C32_UINT64 = 46,
+	TIFF_SETGET_C32_SINT64 = 47,
+	TIFF_SETGET_C32_FLOAT = 48,
+	TIFF_SETGET_C32_DOUBLE = 49,
+	TIFF_SETGET_C32_IFD8 = 50,
+	TIFF_SETGET_OTHER = 51
+} TIFFSetGetFieldType;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern const TIFFFieldArray* _TIFFGetFields(void);
+extern const TIFFFieldArray* _TIFFGetExifFields(void);
+extern void _TIFFSetupFields(TIFF* tif, const TIFFFieldArray* infoarray);
+extern void _TIFFPrintFieldInfo(TIFF*, FILE*);
+
+extern int _TIFFFillStriles(TIFF*);        
+
+typedef enum {
+	tfiatImage,
+	tfiatExif,
+	tfiatOther
+} TIFFFieldArrayType;
+
+struct _TIFFFieldArray {
+	TIFFFieldArrayType type;    /* array type, will be used to determine if IFD is image and such */
+	uint32 allocated_size;      /* 0 if array is constant, other if modified by future definition extension support */
+	uint32 count;               /* number of elements in fields array */
+	TIFFField* fields;          /* actual field info */
+};
+
+struct _TIFFField {
+	uint32 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 reserved;                        /* reserved for future extension */
+	TIFFSetGetFieldType set_field_type;     /* type to be passed to TIFFSetField */
+	TIFFSetGetFieldType get_field_type;     /* type to be passed to TIFFGetField */
+	unsigned short field_bit;               /* bit in fieldsset bit vector */
+	unsigned char field_oktochange;         /* if true, can change while writing */
+	unsigned char field_passcount;          /* if true, pass dir count on set */
+	char* field_name;                       /* ASCII name */
+	TIFFFieldArray* field_subfields;        /* if field points to child ifds, child ifd field definition array */
+};
+
+extern int _TIFFMergeFields(TIFF*, const TIFFField[], uint32);
+extern const TIFFField* _TIFFFindOrRegisterField(TIFF *, uint32, TIFFDataType);
+extern  TIFFField* _TIFFCreateAnonField(TIFF *, uint32, TIFFDataType);
+
+#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/third_party/libtiff/tif_dirinfo.c b/third_party/libtiff/tif_dirinfo.c
new file mode 100644
index 0000000..7db4bdb
--- /dev/null
+++ b/third_party/libtiff/tif_dirinfo.c
@@ -0,0 +1,959 @@
+/* $Id: tif_dirinfo.c,v 1.121 2014-05-07 01:58:46 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
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Core Directory Tag Support.
+ */
+#include "tiffiop.h"
+#include <stdlib.h>
+
+/*
+ * NOTE: THIS ARRAY IS ASSUMED TO BE SORTED BY TAG.
+ *
+ * NOTE: The second field (field_readcount) and third field (field_writecount)
+ *       sometimes use the values TIFF_VARIABLE (-1), TIFF_VARIABLE2 (-3)
+ *       and TIFF_SPP (-2). The macros should be used but would throw off
+ *       the formatting of the code, so please interprete the -1, -2 and -3
+ *       values accordingly.
+ */
+
+static TIFFFieldArray tiffFieldArray;
+static TIFFFieldArray exifFieldArray;
+
+static TIFFField
+tiffFields[] = {
+	{ TIFFTAG_SUBFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_SUBFILETYPE, 1, 0, "SubfileType", NULL },
+	{ TIFFTAG_OSUBFILETYPE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_SUBFILETYPE, 1, 0, "OldSubfileType", NULL },
+	{ TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDIMENSIONS, 0, 0, "ImageWidth", NULL },
+	{ TIFFTAG_IMAGELENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDIMENSIONS, 1, 0, "ImageLength", NULL },
+	{ TIFFTAG_BITSPERSAMPLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_BITSPERSAMPLE, 0, 0, "BitsPerSample", NULL },
+	{ TIFFTAG_COMPRESSION, -1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_COMPRESSION, 0, 0, "Compression", NULL },
+	{ TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_PHOTOMETRIC, 0, 0, "PhotometricInterpretation", NULL },
+	{ TIFFTAG_THRESHHOLDING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_THRESHHOLDING, 1, 0, "Threshholding", NULL },
+	{ TIFFTAG_CELLWIDTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "CellWidth", NULL },
+	{ TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_IGNORE, 1, 0, "CellLength", NULL },
+	{ TIFFTAG_FILLORDER, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_FILLORDER, 0, 0, "FillOrder", NULL },
+	{ TIFFTAG_DOCUMENTNAME, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "DocumentName", NULL },
+	{ TIFFTAG_IMAGEDESCRIPTION, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageDescription", NULL },
+	{ TIFFTAG_MAKE, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Make", NULL },
+	{ TIFFTAG_MODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Model", NULL },
+	{ TIFFTAG_STRIPOFFSETS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPOFFSETS, 0, 0, "StripOffsets", NULL },
+	{ TIFFTAG_ORIENTATION, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_ORIENTATION, 0, 0, "Orientation", NULL },
+	{ TIFFTAG_SAMPLESPERPIXEL, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLESPERPIXEL, 0, 0, "SamplesPerPixel", NULL },
+	{ TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_ROWSPERSTRIP, 0, 0, "RowsPerStrip", NULL },
+	{ TIFFTAG_STRIPBYTECOUNTS, -1, -1, TIFF_LONG8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_STRIPBYTECOUNTS, 0, 0, "StripByteCounts", NULL },
+	{ TIFFTAG_MINSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_MINSAMPLEVALUE, 1, 0, "MinSampleValue", NULL },
+	{ TIFFTAG_MAXSAMPLEVALUE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_MAXSAMPLEVALUE, 1, 0, "MaxSampleValue", NULL },
+	{ TIFFTAG_XRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_RESOLUTION, 1, 0, "XResolution", NULL },
+	{ TIFFTAG_YRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, 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_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_POSITION, 1, 0, "XPosition", NULL },
+	{ TIFFTAG_YPOSITION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, 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 },
+	{ TIFFTAG_INKSET, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InkSet", NULL },
+	{ TIFFTAG_INKNAMES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_C16_ASCII, TIFF_SETGET_UNDEFINED, FIELD_INKNAMES, 1, 1, "InkNames", NULL },
+	{ TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NumberOfInks", NULL },
+	{ TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DotRange", NULL },
+	{ TIFFTAG_TARGETPRINTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TargetPrinter", NULL },
+	{ TIFFTAG_EXTRASAMPLES, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 1, "ExtraSamples", NULL },
+	{ TIFFTAG_SAMPLEFORMAT, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLEFORMAT, 0, 0, "SampleFormat", NULL },
+	{ TIFFTAG_SMINSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_SMINSAMPLEVALUE, 1, 0, "SMinSampleValue", NULL },
+	{ TIFFTAG_SMAXSAMPLEVALUE, -2, -1, TIFF_ANY, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_SMAXSAMPLEVALUE, 1, 0, "SMaxSampleValue", NULL },
+	{ TIFFTAG_CLIPPATH, -1, -3, TIFF_BYTE, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ClipPath", NULL },
+	{ TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SLONG, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL },
+	{ TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SBYTE, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "XClipPathUnits", NULL },
+	{ TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SLONG, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "YClipPathUnits", NULL },
+	{ TIFFTAG_YCBCRCOEFFICIENTS, 3, 3, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "YCbCrCoefficients", NULL },
+	{ TIFFTAG_YCBCRSUBSAMPLING, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_YCBCRSUBSAMPLING, 0, 0, "YCbCrSubsampling", NULL },
+	{ TIFFTAG_YCBCRPOSITIONING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_YCBCRPOSITIONING, 0, 0, "YCbCrPositioning", NULL },
+	{ TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_REFBLACKWHITE, 1, 0, "ReferenceBlackWhite", NULL },
+	{ TIFFTAG_XMLPACKET, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "XMLPacket", NULL },
+	/* begin SGI tags */
+	{ TIFFTAG_MATTEING, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 0, "Matteing", NULL },
+	{ TIFFTAG_DATATYPE, -2, -1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_SAMPLEFORMAT, 0, 0, "DataType", NULL },
+	{ TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_IMAGEDEPTH, 0, 0, "ImageDepth", NULL },
+	{ TIFFTAG_TILEDEPTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_TILEDEPTH, 0, 0, "TileDepth", NULL },
+	/* end SGI tags */
+	/* begin Pixar tags */
+	{ TIFFTAG_PIXAR_IMAGEFULLWIDTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageFullWidth", NULL },
+	{ TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ImageFullLength", NULL },
+	{ TIFFTAG_PIXAR_TEXTUREFORMAT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TextureFormat", NULL },
+	{ TIFFTAG_PIXAR_WRAPMODES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TextureWrapModes", NULL },
+	{ TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FieldOfViewCotangent", NULL },
+	{ TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToScreen", NULL },
+	{ TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16, 16, TIFF_FLOAT, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MatrixWorldToCamera", NULL },
+	{ TIFFTAG_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED,	FIELD_CUSTOM, 0,	0,	"CFARepeatPatternDim", NULL },
+	{ TIFFTAG_CFAPATTERN,	4, 4,	TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0,	0,	"CFAPattern" , NULL},
+	{ TIFFTAG_COPYRIGHT, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Copyright", NULL },
+	/* end Pixar tags */
+	{ TIFFTAG_RICHTIFFIPTC, -3, -3, TIFF_LONG, 0, TIFF_SETGET_C32_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "RichTIFFIPTC", NULL },
+	{ TIFFTAG_PHOTOSHOP, -3, -3, TIFF_BYTE, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "Photoshop", NULL },
+	{ TIFFTAG_EXIFIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "EXIFIFDOffset", &exifFieldArray },
+	{ TIFFTAG_ICCPROFILE, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ICC Profile", NULL },
+	{ TIFFTAG_GPSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "GPSIFDOffset", NULL },
+	{ TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvParams", NULL },
+	{ TIFFTAG_FAXSUBADDRESS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxSubAddress", NULL },
+	{ TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_CUSTOM, TRUE, FALSE, "FaxRecvTime", NULL },
+	{ TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_ASCII, FIELD_CUSTOM, TRUE, FALSE, "FaxDcs", NULL },
+	{ TIFFTAG_STONITS, 1, 1, TIFF_DOUBLE, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "StoNits", NULL },
+	{ TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InteroperabilityIFDOffset", NULL },
+	/* begin DNG tags */
+	{ TIFFTAG_DNGVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DNGVersion", NULL },
+	{ TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DNGBackwardVersion", NULL },
+	{ TIFFTAG_UNIQUECAMERAMODEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "UniqueCameraModel", NULL },
+	{ TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "LocalizedCameraModel", NULL },
+	{ TIFFTAG_CFAPLANECOLOR, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CFAPlaneColor", NULL },
+	{ TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CFALayout", NULL },
+	{ TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "LinearizationTable", NULL },
+	{ TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BlackLevelRepeatDim", NULL },
+	{ TIFFTAG_BLACKLEVEL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevel", NULL },
+	{ TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevelDeltaH", NULL },
+	{ TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "BlackLevelDeltaV", NULL },
+	{ TIFFTAG_WHITELEVEL, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "WhiteLevel", NULL },
+	{ TIFFTAG_DEFAULTSCALE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultScale", NULL },
+	{ TIFFTAG_BESTQUALITYSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BestQualityScale", NULL },
+	{ TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultCropOrigin", NULL },
+	{ TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DefaultCropSize", NULL },
+	{ TIFFTAG_COLORMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ColorMatrix1", NULL },
+	{ TIFFTAG_COLORMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ColorMatrix2", NULL },
+	{ TIFFTAG_CAMERACALIBRATION1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CameraCalibration1", NULL },
+	{ TIFFTAG_CAMERACALIBRATION2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CameraCalibration2", NULL },
+	{ TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ReductionMatrix1", NULL },
+	{ TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ReductionMatrix2", NULL },
+	{ TIFFTAG_ANALOGBALANCE, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AnalogBalance", NULL },
+	{ TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_RATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotNeutral", NULL },
+	{ TIFFTAG_ASSHOTWHITEXY, 2, 2, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "AsShotWhiteXY", NULL },
+	{ TIFFTAG_BASELINEEXPOSURE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineExposure", NULL },
+	{ TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineNoise", NULL },
+	{ TIFFTAG_BASELINESHARPNESS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BaselineSharpness", NULL },
+	{ TIFFTAG_BAYERGREENSPLIT, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "BayerGreenSplit", NULL },
+	{ TIFFTAG_LINEARRESPONSELIMIT, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "LinearResponseLimit", NULL },
+	{ TIFFTAG_CAMERASERIALNUMBER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CameraSerialNumber", NULL },
+	{ TIFFTAG_LENSINFO, 4, 4, TIFF_RATIONAL, 0, TIFF_SETGET_C0_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "LensInfo", NULL },
+	{ TIFFTAG_CHROMABLURRADIUS, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ChromaBlurRadius", NULL },
+	{ TIFFTAG_ANTIALIASSTRENGTH, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "AntiAliasStrength", NULL },
+	{ TIFFTAG_SHADOWSCALE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ShadowScale", NULL },
+	{ TIFFTAG_DNGPRIVATEDATA, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "DNGPrivateData", NULL },
+	{ TIFFTAG_MAKERNOTESAFETY, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "MakerNoteSafety", NULL },
+	{ TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CalibrationIlluminant1", NULL },
+	{ TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CalibrationIlluminant2", NULL },
+	{ TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "RawDataUniqueID", NULL },
+	{ TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OriginalRawFileName", NULL },
+	{ TIFFTAG_ORIGINALRAWFILEDATA, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "OriginalRawFileData", NULL },
+	{ TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ActiveArea", NULL },
+	{ TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "MaskedAreas", NULL },
+	{ TIFFTAG_ASSHOTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotICCProfile", NULL },
+	{ TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "AsShotPreProfileMatrix", NULL },
+	{ TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CurrentICCProfile", NULL },
+	{ TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "CurrentPreProfileMatrix", NULL },
+	{ TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL},
+	/* end DNG tags */
+	/* begin TIFF/FX tags */
+        { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "Indexed", NULL },
+        { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "GlobalParametersIFD", NULL },
+        { TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ProfileType", NULL },
+        { TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "FaxProfile", NULL },
+        { TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "CodingMethods", NULL },
+        { TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "VersionYear", NULL },
+        { TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ModeNumber", NULL },
+        { TIFFTAG_DECODE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "Decode", NULL },
+        { TIFFTAG_IMAGEBASECOLOR, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "ImageBaseColor", NULL },
+        { TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "T82Options", NULL },
+        { TIFFTAG_STRIPROWCOUNTS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 1, "StripRowCounts", NULL },
+        { TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "ImageLayer", NULL },
+	/* end TIFF/FX tags */
+	/* begin pseudo tags */
+};
+
+static TIFFField
+exifFields[] = {
+	{ EXIFTAG_EXPOSURETIME, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureTime", NULL },
+	{ EXIFTAG_FNUMBER, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FNumber", NULL },
+	{ EXIFTAG_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureProgram", NULL },
+	{ EXIFTAG_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SpectralSensitivity", NULL },
+	{ EXIFTAG_ISOSPEEDRATINGS, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "ISOSpeedRatings", NULL },
+	{ EXIFTAG_OECF, -1, -1, TIFF_UNDEFINED, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "OptoelectricConversionFactor", NULL },
+	{ EXIFTAG_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_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_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "CompressedBitsPerPixel", NULL },
+	{ EXIFTAG_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ShutterSpeedValue", NULL },
+	{ EXIFTAG_APERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ApertureValue", NULL },
+	{ EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL },
+	{ EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL },
+	{ EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL },
+	{ EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, 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_DOUBLE, 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_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_DOUBLE, 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_DOUBLE, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "FocalPlaneXResolution", NULL },
+	{ EXIFTAG_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_DOUBLE, 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_DOUBLE, 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_DOUBLE, 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_DOUBLE, 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 }
+};
+
+static TIFFFieldArray
+tiffFieldArray = { tfiatImage, 0, TIFFArrayCount(tiffFields), tiffFields };
+static TIFFFieldArray
+exifFieldArray = { tfiatExif, 0, TIFFArrayCount(exifFields), exifFields };
+
+/*
+ *  We have our own local lfind() equivelent to avoid subtle differences
+ *  in types passed to lfind() on different systems. 
+ */
+
+static void *
+td_lfind(const void *key, const void *base, size_t *nmemb, size_t size,
+         int(*compar)(const void *, const void *))
+{
+    char *element, *end;
+
+    end = (char *)base + *nmemb * size;
+    for (element = (char *)base; element < end; element += size)
+        if (!compar(key, element))		/* key found */
+            return element;
+
+    return NULL;
+}
+
+const TIFFFieldArray*
+_TIFFGetFields(void)
+{
+	return(&tiffFieldArray);
+}
+
+const TIFFFieldArray*
+_TIFFGetExifFields(void)
+{
+	return(&exifFieldArray);
+}
+
+void
+_TIFFSetupFields(TIFF* tif, const TIFFFieldArray* fieldarray)
+{
+	if (tif->tif_fields && tif->tif_nfields > 0) {
+		uint32 i;
+
+		for (i = 0; i < tif->tif_nfields; i++) {
+			TIFFField *fld = tif->tif_fields[i];
+			if (fld->field_bit == FIELD_CUSTOM &&
+				strncmp("Tag ", fld->field_name, 4) == 0) {
+					_TIFFfree(fld->field_name);
+					_TIFFfree(fld);
+				}
+		}
+
+		_TIFFfree(tif->tif_fields);
+		tif->tif_fields = NULL;
+		tif->tif_nfields = 0;
+	}
+	if (!_TIFFMergeFields(tif, fieldarray->fields, fieldarray->count)) {
+		TIFFErrorExt(tif->tif_clientdata, "_TIFFSetupFields",
+			     "Setting up field info failed");
+	}
+}
+
+static int
+tagCompare(const void* a, const void* b)
+{
+	const TIFFField* ta = *(const TIFFField**) a;
+	const TIFFField* tb = *(const TIFFField**) b;
+	/* NB: be careful of return values for 16-bit platforms */
+	if (ta->field_tag != tb->field_tag)
+		return (int)ta->field_tag - (int)tb->field_tag;
+	else
+		return (ta->field_type == TIFF_ANY) ?
+			0 : ((int)tb->field_type - (int)ta->field_type);
+}
+
+static int
+tagNameCompare(const void* a, const void* b)
+{
+	const TIFFField* ta = *(const TIFFField**) a;
+	const TIFFField* tb = *(const TIFFField**) b;
+	int ret = strcmp(ta->field_name, tb->field_name);
+
+	if (ret)
+		return ret;
+	else
+		return (ta->field_type == TIFF_ANY) ?
+			0 : ((int)tb->field_type - (int)ta->field_type);
+}
+
+int
+_TIFFMergeFields(TIFF* tif, const TIFFField info[], uint32 n)
+{
+	static const char module[] = "_TIFFMergeFields";
+	static const char reason[] = "for fields array";
+	/* TIFFField** tp; */
+	uint32 i;
+
+        tif->tif_foundfield = NULL;
+
+	if (tif->tif_fields && tif->tif_nfields > 0) {
+		tif->tif_fields = (TIFFField**)
+			_TIFFCheckRealloc(tif, tif->tif_fields,
+					  (tif->tif_nfields + n),
+					  sizeof(TIFFField *), reason);
+	} else {
+		tif->tif_fields = (TIFFField **)
+			_TIFFCheckMalloc(tif, n, sizeof(TIFFField *),
+					 reason);
+	}
+	if (!tif->tif_fields) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Failed to allocate fields array");
+		return 0;
+	}
+
+	/* tp = tif->tif_fields + tif->tif_nfields; */
+	for (i = 0; i < n; i++) {
+		const TIFFField *fip =
+			TIFFFindField(tif, info[i].field_tag, TIFF_ANY);
+
+                /* only add definitions that aren't already present */
+		if (!fip) {
+                        tif->tif_fields[tif->tif_nfields] = (TIFFField *) (info+i);
+                        tif->tif_nfields++;
+                }
+	}
+
+        /* Sort the field info by tag number */
+	qsort(tif->tif_fields, tif->tif_nfields,
+	      sizeof(TIFFField *), tagCompare);
+
+	return n;
+}
+
+void
+_TIFFPrintFieldInfo(TIFF* tif, FILE* fd)
+{
+	uint32 i;
+
+	fprintf(fd, "%s: \n", tif->tif_name);
+	for (i = 0; i < tif->tif_nfields; i++) {
+		const TIFFField* fip = tif->tif_fields[i];
+		fprintf(fd, "field[%2d] %5lu, %2d, %2d, %d, %2d, %5s, %5s, %s\n"
+			, (int)i
+			, (unsigned long) fip->field_tag
+			, fip->field_readcount, fip->field_writecount
+			, fip->field_type
+			, fip->field_bit
+			, fip->field_oktochange ? "TRUE" : "FALSE"
+			, fip->field_passcount ? "TRUE" : "FALSE"
+			, fip->field_name
+		);
+	}
+}
+
+/*
+ * Return size of TIFFDataType in bytes
+ */
+int
+TIFFDataWidth(TIFFDataType type)
+{
+	switch(type)
+	{
+		case 0:  /* nothing */
+		case TIFF_BYTE:
+		case TIFF_ASCII:
+		case TIFF_SBYTE:
+		case TIFF_UNDEFINED:
+			return 1;
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+			return 2;
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_FLOAT:
+		case TIFF_IFD:
+			return 4;
+		case TIFF_RATIONAL:
+		case TIFF_SRATIONAL:
+		case TIFF_DOUBLE:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+		case TIFF_IFD8:
+			return 8;
+		default:
+			return 0; /* will return 0 for unknown types */
+	}
+}
+
+/*
+ * Return size of TIFFDataType in bytes.
+ *
+ * XXX: We need a separate function to determine the space needed
+ * to store the value. For TIFF_RATIONAL values TIFFDataWidth() returns 8,
+ * but we use 4-byte float to represent rationals.
+ */
+int
+_TIFFDataSize(TIFFDataType type)
+{
+	switch (type)
+	{
+		case TIFF_BYTE:
+		case TIFF_SBYTE:
+		case TIFF_ASCII:
+		case TIFF_UNDEFINED:
+		    return 1;
+		case TIFF_SHORT:
+		case TIFF_SSHORT:
+		    return 2;
+		case TIFF_LONG:
+		case TIFF_SLONG:
+		case TIFF_FLOAT:
+		case TIFF_IFD:
+		case TIFF_RATIONAL:
+		case TIFF_SRATIONAL:
+		    return 4;
+		case TIFF_DOUBLE:
+		case TIFF_LONG8:
+		case TIFF_SLONG8:
+		case TIFF_IFD8:
+		    return 8;
+		default:
+		    return 0;
+	}
+}
+
+const TIFFField*
+TIFFFindField(TIFF* tif, uint32 tag, TIFFDataType dt)
+{
+	TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, 0, NULL, NULL};
+	TIFFField* pkey = &key;
+	const TIFFField **ret;
+	if (tif->tif_foundfield && tif->tif_foundfield->field_tag == tag &&
+	    (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type))
+		return tif->tif_foundfield;
+
+	/* If we are invoked with no field information, then just return. */
+	if (!tif->tif_fields)
+		return NULL;
+
+	/* NB: use sorted search (e.g. binary search) */
+
+	key.field_tag = tag;
+	key.field_type = dt;
+
+	ret = (const TIFFField **) bsearch(&pkey, tif->tif_fields,
+					   tif->tif_nfields,
+					   sizeof(TIFFField *), tagCompare);
+	return tif->tif_foundfield = (ret ? *ret : NULL);
+}
+
+const TIFFField*
+_TIFFFindFieldByName(TIFF* tif, const char *field_name, TIFFDataType dt)
+{
+	TIFFField key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0, 0, 0, NULL, NULL};
+	TIFFField* pkey = &key;
+	const TIFFField **ret;
+	if (tif->tif_foundfield
+	    && streq(tif->tif_foundfield->field_name, field_name)
+	    && (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type))
+		return (tif->tif_foundfield);
+
+	/* If we are invoked with no field information, then just return. */
+	if (!tif->tif_fields)
+		return NULL;
+
+	/* NB: use linear search since list is sorted by key#, not name */
+
+	key.field_name = (char *)field_name;
+	key.field_type = dt;
+
+	ret = (const TIFFField **) 
+            td_lfind(&pkey, tif->tif_fields, &tif->tif_nfields,
+                     sizeof(TIFFField *), tagNameCompare);
+
+	return tif->tif_foundfield = (ret ? *ret : NULL);
+}
+
+const TIFFField*
+TIFFFieldWithTag(TIFF* tif, uint32 tag)
+{
+	const TIFFField* fip = TIFFFindField(tif, tag, TIFF_ANY);
+	if (!fip) {
+		TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithTag",
+			     "Internal error, unknown tag 0x%x",
+			     (unsigned int) tag);
+	}
+	return (fip);
+}
+
+const TIFFField*
+TIFFFieldWithName(TIFF* tif, const char *field_name)
+{
+	const TIFFField* fip =
+		_TIFFFindFieldByName(tif, field_name, TIFF_ANY);
+	if (!fip) {
+		TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithName",
+			     "Internal error, unknown tag %s", field_name);
+	}
+	return (fip);
+}
+
+uint32
+TIFFFieldTag(const TIFFField* fip)
+{
+	return fip->field_tag;
+}
+
+const char *
+TIFFFieldName(const TIFFField* fip)
+{
+	return fip->field_name;
+}
+
+TIFFDataType
+TIFFFieldDataType(const TIFFField* fip)
+{
+	return fip->field_type;
+}
+
+int
+TIFFFieldPassCount(const TIFFField* fip)
+{
+	return fip->field_passcount;
+}
+
+int
+TIFFFieldReadCount(const TIFFField* fip)
+{
+	return fip->field_readcount;
+}
+
+int
+TIFFFieldWriteCount(const TIFFField* fip)
+{
+	return fip->field_writecount;
+}
+
+const TIFFField*
+_TIFFFindOrRegisterField(TIFF *tif, uint32 tag, TIFFDataType dt)
+
+{
+	const TIFFField *fld;
+
+	fld = TIFFFindField(tif, tag, dt);
+	if (fld == NULL) {
+		fld = _TIFFCreateAnonField(tif, tag, dt);
+		if (!_TIFFMergeFields(tif, fld, 1))
+			return NULL;
+	}
+
+	return fld;
+}
+
+TIFFField*
+_TIFFCreateAnonField(TIFF *tif, uint32 tag, TIFFDataType field_type)
+{
+	TIFFField *fld;
+	(void) tif;
+
+	fld = (TIFFField *) _TIFFmalloc(sizeof (TIFFField));
+	if (fld == NULL)
+	    return NULL;
+	_TIFFmemset(fld, 0, sizeof(TIFFField));
+
+	fld->field_tag = tag;
+	fld->field_readcount = TIFF_VARIABLE2;
+	fld->field_writecount = TIFF_VARIABLE2;
+	fld->field_type = field_type;
+	fld->reserved = 0;
+	switch (field_type)
+	{
+		case TIFF_BYTE:
+		case TIFF_UNDEFINED:
+			fld->set_field_type = TIFF_SETGET_C32_UINT8;
+			fld->get_field_type = TIFF_SETGET_C32_UINT8;
+			break;
+		case TIFF_ASCII:
+			fld->set_field_type = TIFF_SETGET_C32_ASCII;
+			fld->get_field_type = TIFF_SETGET_C32_ASCII;
+			break;
+		case TIFF_SHORT:
+			fld->set_field_type = TIFF_SETGET_C32_UINT16;
+			fld->get_field_type = TIFF_SETGET_C32_UINT16;
+			break;
+		case TIFF_LONG:
+			fld->set_field_type = TIFF_SETGET_C32_UINT32;
+			fld->get_field_type = TIFF_SETGET_C32_UINT32;
+			break;
+		case TIFF_RATIONAL:
+		case TIFF_SRATIONAL:
+		case TIFF_FLOAT:
+			fld->set_field_type = TIFF_SETGET_C32_FLOAT;
+			fld->get_field_type = TIFF_SETGET_C32_FLOAT;
+			break;
+		case TIFF_SBYTE:
+			fld->set_field_type = TIFF_SETGET_C32_SINT8;
+			fld->get_field_type = TIFF_SETGET_C32_SINT8;
+			break;
+		case TIFF_SSHORT:
+			fld->set_field_type = TIFF_SETGET_C32_SINT16;
+			fld->get_field_type = TIFF_SETGET_C32_SINT16;
+			break;
+		case TIFF_SLONG:
+			fld->set_field_type = TIFF_SETGET_C32_SINT32;
+			fld->get_field_type = TIFF_SETGET_C32_SINT32;
+			break;
+		case TIFF_DOUBLE:
+			fld->set_field_type = TIFF_SETGET_C32_DOUBLE;
+			fld->get_field_type = TIFF_SETGET_C32_DOUBLE;
+			break;
+		case TIFF_IFD:
+		case TIFF_IFD8:
+			fld->set_field_type = TIFF_SETGET_C32_IFD8;
+			fld->get_field_type = TIFF_SETGET_C32_IFD8;
+			break;
+		case TIFF_LONG8:
+			fld->set_field_type = TIFF_SETGET_C32_UINT64;
+			fld->get_field_type = TIFF_SETGET_C32_UINT64;
+			break;
+		case TIFF_SLONG8:
+			fld->set_field_type = TIFF_SETGET_C32_SINT64;
+			fld->get_field_type = TIFF_SETGET_C32_SINT64;
+			break;
+		default:
+			fld->set_field_type = TIFF_SETGET_UNDEFINED;
+			fld->get_field_type = TIFF_SETGET_UNDEFINED;
+			break;
+	}
+	fld->field_bit = FIELD_CUSTOM;
+	fld->field_oktochange = TRUE;
+	fld->field_passcount = TRUE;
+	fld->field_name = (char *) _TIFFmalloc(32);
+	if (fld->field_name == NULL) {
+	    _TIFFfree(fld);
+	    return NULL;
+	}
+	fld->field_subfields = NULL;
+
+	/* 
+	 * note that this name is a special sign to TIFFClose() and
+	 * _TIFFSetupFields() to free the field
+	 */
+	snprintf(fld->field_name, 32, "Tag %d", (int) tag);
+
+	return fld;    
+}
+
+/****************************************************************************
+ *               O B S O L E T E D    I N T E R F A C E S
+ *
+ * Don't use this stuff in your applications, it may be removed in the future
+ * libtiff versions.
+ ****************************************************************************/
+
+static TIFFSetGetFieldType
+_TIFFSetGetType(TIFFDataType type, short count, unsigned char passcount)
+{
+	if (type == TIFF_ASCII && count == TIFF_VARIABLE && passcount == 0)
+		return TIFF_SETGET_ASCII;
+
+	else if (count == 1 && passcount == 0) {
+		switch (type)
+		{
+			case TIFF_BYTE:
+			case TIFF_UNDEFINED:
+				return TIFF_SETGET_UINT8;
+			case TIFF_ASCII:
+				return TIFF_SETGET_ASCII;
+			case TIFF_SHORT:
+				return TIFF_SETGET_UINT16;
+			case TIFF_LONG:
+				return TIFF_SETGET_UINT32;
+			case TIFF_RATIONAL:
+			case TIFF_SRATIONAL:
+			case TIFF_FLOAT:
+				return TIFF_SETGET_FLOAT;
+			case TIFF_SBYTE:
+				return TIFF_SETGET_SINT8;
+			case TIFF_SSHORT:
+				return TIFF_SETGET_SINT16;
+			case TIFF_SLONG:
+				return TIFF_SETGET_SINT32;
+			case TIFF_DOUBLE:
+				return TIFF_SETGET_DOUBLE;
+			case TIFF_IFD:
+			case TIFF_IFD8:
+				return TIFF_SETGET_IFD8;
+			case TIFF_LONG8:
+				return TIFF_SETGET_UINT64;
+			case TIFF_SLONG8:
+				return TIFF_SETGET_SINT64;
+			default:
+				return TIFF_SETGET_UNDEFINED;
+		}
+	}
+
+	else if (count >= 1 && passcount == 0) {
+		switch (type)
+		{
+			case TIFF_BYTE:
+			case TIFF_UNDEFINED:
+				return TIFF_SETGET_C0_UINT8;
+			case TIFF_ASCII:
+				return TIFF_SETGET_C0_ASCII;
+			case TIFF_SHORT:
+				return TIFF_SETGET_C0_UINT16;
+			case TIFF_LONG:
+				return TIFF_SETGET_C0_UINT32;
+			case TIFF_RATIONAL:
+			case TIFF_SRATIONAL:
+			case TIFF_FLOAT:
+				return TIFF_SETGET_C0_FLOAT;
+			case TIFF_SBYTE:
+				return TIFF_SETGET_C0_SINT8;
+			case TIFF_SSHORT:
+				return TIFF_SETGET_C0_SINT16;
+			case TIFF_SLONG:
+				return TIFF_SETGET_C0_SINT32;
+			case TIFF_DOUBLE:
+				return TIFF_SETGET_C0_DOUBLE;
+			case TIFF_IFD:
+			case TIFF_IFD8:
+				return TIFF_SETGET_C0_IFD8;
+			case TIFF_LONG8:
+				return TIFF_SETGET_C0_UINT64;
+			case TIFF_SLONG8:
+				return TIFF_SETGET_C0_SINT64;
+			default:
+				return TIFF_SETGET_UNDEFINED;
+		}
+	}
+
+	else if (count == TIFF_VARIABLE && passcount == 1) {
+		switch (type)
+		{
+			case TIFF_BYTE:
+			case TIFF_UNDEFINED:
+				return TIFF_SETGET_C16_UINT8;
+			case TIFF_ASCII:
+				return TIFF_SETGET_C16_ASCII;
+			case TIFF_SHORT:
+				return TIFF_SETGET_C16_UINT16;
+			case TIFF_LONG:
+				return TIFF_SETGET_C16_UINT32;
+			case TIFF_RATIONAL:
+			case TIFF_SRATIONAL:
+			case TIFF_FLOAT:
+				return TIFF_SETGET_C16_FLOAT;
+			case TIFF_SBYTE:
+				return TIFF_SETGET_C16_SINT8;
+			case TIFF_SSHORT:
+				return TIFF_SETGET_C16_SINT16;
+			case TIFF_SLONG:
+				return TIFF_SETGET_C16_SINT32;
+			case TIFF_DOUBLE:
+				return TIFF_SETGET_C16_DOUBLE;
+			case TIFF_IFD:
+			case TIFF_IFD8:
+				return TIFF_SETGET_C16_IFD8;
+			case TIFF_LONG8:
+				return TIFF_SETGET_C16_UINT64;
+			case TIFF_SLONG8:
+				return TIFF_SETGET_C16_SINT64;
+			default:
+				return TIFF_SETGET_UNDEFINED;
+		}
+	}
+
+	else if (count == TIFF_VARIABLE2 && passcount == 1) {
+		switch (type)
+		{
+			case TIFF_BYTE:
+			case TIFF_UNDEFINED:
+				return TIFF_SETGET_C32_UINT8;
+			case TIFF_ASCII:
+				return TIFF_SETGET_C32_ASCII;
+			case TIFF_SHORT:
+				return TIFF_SETGET_C32_UINT16;
+			case TIFF_LONG:
+				return TIFF_SETGET_C32_UINT32;
+			case TIFF_RATIONAL:
+			case TIFF_SRATIONAL:
+			case TIFF_FLOAT:
+				return TIFF_SETGET_C32_FLOAT;
+			case TIFF_SBYTE:
+				return TIFF_SETGET_C32_SINT8;
+			case TIFF_SSHORT:
+				return TIFF_SETGET_C32_SINT16;
+			case TIFF_SLONG:
+				return TIFF_SETGET_C32_SINT32;
+			case TIFF_DOUBLE:
+				return TIFF_SETGET_C32_DOUBLE;
+			case TIFF_IFD:
+			case TIFF_IFD8:
+				return TIFF_SETGET_C32_IFD8;
+			case TIFF_LONG8:
+				return TIFF_SETGET_C32_UINT64;
+			case TIFF_SLONG8:
+				return TIFF_SETGET_C32_SINT64;
+			default:
+				return TIFF_SETGET_UNDEFINED;
+		}
+	}
+
+	return TIFF_SETGET_UNDEFINED;
+}
+
+int
+TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], uint32 n)
+{
+	static const char module[] = "TIFFMergeFieldInfo";
+	static const char reason[] = "for fields array";
+	TIFFField *tp;
+	size_t nfields;
+	uint32 i;
+
+	if (tif->tif_nfieldscompat > 0) {
+		tif->tif_fieldscompat = (TIFFFieldArray *)
+			_TIFFCheckRealloc(tif, tif->tif_fieldscompat,
+					  tif->tif_nfieldscompat + 1,
+					  sizeof(TIFFFieldArray), reason);
+	} else {
+		tif->tif_fieldscompat = (TIFFFieldArray *)
+			_TIFFCheckMalloc(tif, 1, sizeof(TIFFFieldArray),
+					 reason);
+	}
+	if (!tif->tif_fieldscompat) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Failed to allocate fields array");
+		return -1;
+	}
+	nfields = tif->tif_nfieldscompat++;
+
+	tif->tif_fieldscompat[nfields].type = tfiatOther;
+	tif->tif_fieldscompat[nfields].allocated_size = n;
+	tif->tif_fieldscompat[nfields].count = n;
+	tif->tif_fieldscompat[nfields].fields =
+		(TIFFField *)_TIFFCheckMalloc(tif, n, sizeof(TIFFField),
+					      reason);
+	if (!tif->tif_fieldscompat[nfields].fields) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Failed to allocate fields array");
+		return -1;
+	}
+
+	tp = tif->tif_fieldscompat[nfields].fields;
+	for (i = 0; i < n; i++) {
+		tp->field_tag = info[i].field_tag;
+		tp->field_readcount = info[i].field_readcount;
+		tp->field_writecount = info[i].field_writecount;
+		tp->field_type = info[i].field_type;
+		tp->reserved = 0;
+		tp->set_field_type =
+		     _TIFFSetGetType(info[i].field_type,
+				info[i].field_readcount,
+				info[i].field_passcount);
+		tp->get_field_type =
+		     _TIFFSetGetType(info[i].field_type,
+				info[i].field_readcount,
+				info[i].field_passcount);
+		tp->field_bit = info[i].field_bit;
+		tp->field_oktochange = info[i].field_oktochange;
+		tp->field_passcount = info[i].field_passcount;
+		tp->field_name = info[i].field_name;
+		tp->field_subfields = NULL;
+		tp++;
+	}
+
+	if (!_TIFFMergeFields(tif, tif->tif_fieldscompat[nfields].fields, n)) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Setting up field info failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_dirread.c b/third_party/libtiff/tif_dirread.c
new file mode 100644
index 0000000..a0dc68b
--- /dev/null
+++ b/third_party/libtiff/tif_dirread.c
@@ -0,0 +1,5614 @@
+/* $Id: tif_dirread.c,v 1.191 2015-09-05 20:31: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
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Read Support Routines.
+ */
+
+/* Suggested pending improvements:
+ * - add a field 'ignore' to the TIFFDirEntry structure, to flag status,
+ *   eliminating current use of the IGNORE value, and therefore eliminating
+ *   current irrational behaviour on tags with tag id code 0
+ * - 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 "tiffiop.h"
+
+#define IGNORE 0          /* tag placeholder used below */
+#define FAILED_FII    ((uint32) -1)
+
+#ifdef HAVE_IEEEFP
+# define TIFFCvtIEEEFloatToNative(tif, n, fp)
+# define TIFFCvtIEEEDoubleToNative(tif, n, dp)
+#else
+extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*);
+extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, double*);
+#endif
+
+enum TIFFReadDirEntryErr {
+	TIFFReadDirEntryErrOk = 0,
+	TIFFReadDirEntryErrCount = 1,
+	TIFFReadDirEntryErrType = 2,
+	TIFFReadDirEntryErrIo = 3,
+	TIFFReadDirEntryErrRange = 4,
+	TIFFReadDirEntryErrPsdif = 5,
+	TIFFReadDirEntryErrSizesan = 6,
+	TIFFReadDirEntryErrAlloc = 7,
+};
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* 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* value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** 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** value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value);
+#if 0
+static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value);
+#endif
+
+static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value);
+static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8* value);
+static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value);
+static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16* value);
+static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value);
+static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSlong8(TIFF* tif, TIFFDirEntry* direntry, int64* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedSrational(TIFF* tif, TIFFDirEntry* direntry, double* value);
+static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong(uint32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongLong8(uint64 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlongSlong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sbyte(int8 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Sshort(int16 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong(int32 value);
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLong8Slong8(int64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value);
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryData(TIFF* tif, uint64 offset, tmsize_t size, void* dest);
+static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, const char* module, const char* tagname, int recover);
+
+static void TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16 dircount);
+static TIFFDirEntry* TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16 dircount, uint16 tagid);
+static void TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16 tagid, uint32* fii);
+
+static int EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount);
+static void MissingRequired(TIFF*, const char*);
+static int TIFFCheckDirOffset(TIFF* tif, uint64 diroff);
+static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32);
+static uint16 TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir, uint64* nextdiroff);
+static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*, int recover);
+static int TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp);
+static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*);
+static void ChopUpSingleUncompressedStrip(TIFF*);
+static uint64 TIFFReadUInt64(const uint8 *value);
+
+typedef union _UInt64Aligned_t
+{
+        double d;
+	uint64 l;
+	uint32 i[2];
+	uint16 s[4];
+	uint8  c[8];
+} UInt64Aligned_t;
+
+/*
+  Unaligned safe copy of a uint64 value from an octet array.
+*/
+static uint64 TIFFReadUInt64(const uint8 *value)
+{
+	UInt64Aligned_t result;
+
+	result.c[0]=value[0];
+	result.c[1]=value[1];
+	result.c[2]=value[2];
+	result.c[3]=value[3];
+	result.c[4]=value[4];
+	result.c[5]=value[5];
+	result.c[6]=value[6];
+	result.c[7]=value[7];
+
+	return result.l;
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			TIFFReadDirEntryCheckedByte(tif,direntry,value);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeByteSbyte(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			{
+				uint16 m;
+				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeByteShort(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeByteSshort(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeByteLong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeByteSlong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			{
+				uint64 m;
+				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeByteLong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG8:
+			{
+				int64 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeByteSlong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint8)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8 m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeShortSbyte(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			TIFFReadDirEntryCheckedShort(tif,direntry,value);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeShortSshort(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeShortLong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeShortSlong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			{
+				uint64 m;
+				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeShortLong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG8:
+			{
+				int64 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeShortSlong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint16)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8 m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLongSbyte(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			{
+				uint16 m;
+				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLongSshort(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			TIFFReadDirEntryCheckedLong(tif,direntry,value);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLongSlong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			{
+				uint64 m;
+				err=TIFFReadDirEntryCheckedLong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeLongLong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG8:
+			{
+				int64 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeLongSlong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint32)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8 m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLong8Sbyte(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			{
+				uint16 m;
+				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLong8Sshort(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				err=TIFFReadDirEntryCheckRangeLong8Slong(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			err=TIFFReadDirEntryCheckedLong8(tif,direntry,value);
+			return(err);
+		case TIFF_SLONG8:
+			{
+				int64 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				err=TIFFReadDirEntryCheckRangeLong8Slong8(m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryFloat(TIFF* tif, TIFFDirEntry* direntry, float* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8 m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			{
+				uint16 m;
+				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			{
+				uint64 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 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_RATIONAL:
+			{
+				double m;
+				err=TIFFReadDirEntryCheckedRational(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SRATIONAL:
+			{
+				double m;
+				err=TIFFReadDirEntryCheckedSrational(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_FLOAT:
+			TIFFReadDirEntryCheckedFloat(tif,direntry,value);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_DOUBLE:
+			{
+				double m;
+				err=TIFFReadDirEntryCheckedDouble(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(float)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryDouble(TIFF* tif, TIFFDirEntry* direntry, double* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8 m;
+				TIFFReadDirEntryCheckedByte(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			{
+				int8 m;
+				TIFFReadDirEntryCheckedSbyte(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SHORT:
+			{
+				uint16 m;
+				TIFFReadDirEntryCheckedShort(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			{
+				int16 m;
+				TIFFReadDirEntryCheckedSshort(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			{
+				int32 m;
+				TIFFReadDirEntryCheckedSlong(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+			{
+				uint64 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 m;
+				err=TIFFReadDirEntryCheckedSlong8(tif,direntry,&m);
+				if (err!=TIFFReadDirEntryErrOk)
+					return(err);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_RATIONAL:
+			err=TIFFReadDirEntryCheckedRational(tif,direntry,value);
+			return(err);
+		case TIFF_SRATIONAL:
+			err=TIFFReadDirEntryCheckedSrational(tif,direntry,value);
+			return(err);
+		case TIFF_FLOAT:
+			{
+				float m;
+				TIFFReadDirEntryCheckedFloat(tif,direntry,&m);
+				*value=(double)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_DOUBLE:
+			err=TIFFReadDirEntryCheckedDouble(tif,direntry,value);
+			return(err);
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* direntry, uint64* value)
+{
+	enum TIFFReadDirEntryErr err;
+	if (direntry->tdir_count!=1)
+		return(TIFFReadDirEntryErrCount);
+	switch (direntry->tdir_type)
+	{
+		case TIFF_LONG:
+		case TIFF_IFD:
+			{
+				uint32 m;
+				TIFFReadDirEntryCheckedLong(tif,direntry,&m);
+				*value=(uint64)m;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_LONG8:
+		case TIFF_IFD8:
+			err=TIFFReadDirEntryCheckedLong8(tif,direntry,value);
+			return(err);
+		default:
+			return(TIFFReadDirEntryErrType);
+	}
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value)
+{
+	int typesize;
+	uint32 datasize;
+	void* data;
+	typesize=TIFFDataWidth(direntry->tdir_type);
+	if ((direntry->tdir_count==0)||(typesize==0))
+	{
+		*value=0;
+		return(TIFFReadDirEntryErrOk);
+	}
+        (void) desttypesize;
+
+        /* 
+         * 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)(2147483647/typesize)<direntry->tdir_count)
+		return(TIFFReadDirEntryErrSizesan);
+	if ((uint64)(2147483647/desttypesize)<direntry->tdir_count)
+		return(TIFFReadDirEntryErrSizesan);
+
+	*count=(uint32)direntry->tdir_count;
+	datasize=(*count)*typesize;
+	assert((tmsize_t)datasize>0);
+	data=_TIFFCheckMalloc(tif, *count, typesize, "ReadDirEntryArray");
+	if (data==0)
+		return(TIFFReadDirEntryErrAlloc);
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		if (datasize<=4)
+			_TIFFmemcpy(data,&direntry->tdir_offset,datasize);
+		else
+		{
+			enum TIFFReadDirEntryErr err;
+			uint32 offset = direntry->tdir_offset.toff_long;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong(&offset);
+			err=TIFFReadDirEntryData(tif,(uint64)offset,(tmsize_t)datasize,data);
+			if (err!=TIFFReadDirEntryErrOk)
+			{
+				_TIFFfree(data);
+				return(err);
+			}
+		}
+	}
+	else
+	{
+		if (datasize<=8)
+			_TIFFmemcpy(data,&direntry->tdir_offset,datasize);
+		else
+		{
+			enum TIFFReadDirEntryErr err;
+			uint64 offset = direntry->tdir_offset.toff_long8;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8(&offset);
+			err=TIFFReadDirEntryData(tif,offset,(tmsize_t)datasize,data);
+			if (err!=TIFFReadDirEntryErrOk)
+			{
+				_TIFFfree(data);
+				return(err);
+			}
+		}
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	uint8* 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*)origdata;
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SBYTE:
+			{
+				int8* m;
+				uint32 n;
+				m=(int8*)origdata;
+				for (n=0; n<count; n++)
+				{
+					err=TIFFReadDirEntryCheckRangeByteSbyte(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(uint8*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+	}
+	data=(uint8*)_TIFFmalloc(count);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(uint16*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					err=TIFFReadDirEntryCheckRangeByteSshort(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(uint32*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					err=TIFFReadDirEntryCheckRangeByteSlong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(uint64*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				uint8* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeByteSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint8)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySbyteArray(TIFF* tif, TIFFDirEntry* direntry, int8** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	int8* 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* m;
+				uint32 n;
+				m=(uint8*)origdata;
+				for (n=0; n<count; n++)
+				{
+					err=TIFFReadDirEntryCheckRangeSbyteByte(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(int8*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SBYTE:
+			*value=(int8*)origdata;
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(int8*)_TIFFmalloc(count);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				int8* mb;
+				uint32 n;
+				ma=(uint16*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				int8* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					err=TIFFReadDirEntryCheckRangeSbyteSshort(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				int8* mb;
+				uint32 n;
+				ma=(uint32*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				int8* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					err=TIFFReadDirEntryCheckRangeSbyteSlong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int8)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				int8* mb;
+				uint32 n;
+				ma=(uint64*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				int8* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeSbyteSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int8)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryShortArray(TIFF* tif, TIFFDirEntry* direntry, uint16** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	uint16* 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*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfShort(*value,count);  
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SSHORT:
+			{
+				int16* m;
+				uint32 n;
+				m=(int16*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)m);
+					err=TIFFReadDirEntryCheckRangeShortSshort(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(uint16*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+	}
+	data=(uint16*)_TIFFmalloc(count*2);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(uint16)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					err=TIFFReadDirEntryCheckRangeShortSbyte(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint16)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(uint32*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					err=TIFFReadDirEntryCheckRangeShortSlong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint16)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(uint64*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				uint16* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeShortSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint16)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySshortArray(TIFF* tif, TIFFDirEntry* direntry, int16** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	int16* 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* m;
+				uint32 n;
+				m=(uint16*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(m);
+					err=TIFFReadDirEntryCheckRangeSshortShort(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(int16*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SSHORT:
+			*value=(int16*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfShort((uint16*)(*value),count);
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(int16*)_TIFFmalloc(count*2);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				int16* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int16)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				int16* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int16)(*ma++);
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				int16* mb;
+				uint32 n;
+				ma=(uint32*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				int16* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					err=TIFFReadDirEntryCheckRangeSshortSlong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int16)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				int16* mb;
+				uint32 n;
+				ma=(uint64*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				int16* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeSshortSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int16)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLongArray(TIFF* tif, TIFFDirEntry* direntry, uint32** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	uint32* 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*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong(*value,count);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SLONG:
+			{
+				int32* m;
+				uint32 n;
+				m=(int32*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)m);
+					err=TIFFReadDirEntryCheckRangeLongSlong(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(uint32*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+	}
+	data=(uint32*)_TIFFmalloc(count*4);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(uint32)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					err=TIFFReadDirEntryCheckRangeLongSbyte(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					*mb++=(uint32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					err=TIFFReadDirEntryCheckRangeLongSshort(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(uint64*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				uint32* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeLongSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint32)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEntry* direntry, int32** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	int32* 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* m;
+				uint32 n;
+				m=(uint32*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)m);
+					err=TIFFReadDirEntryCheckRangeSlongLong(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(int32*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG:
+			*value=(int32*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong((uint32*)(*value),count);
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(int32*)_TIFFmalloc(count*4);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				int32* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int32)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				int32* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int32)(*ma++);
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				int32* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					*mb++=(int32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				int32* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					*mb++=(int32)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				int32* mb;
+				uint32 n;
+				ma=(uint64*)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)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG8:
+			{
+				int64* ma;
+				int32* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					err=TIFFReadDirEntryCheckRangeSlongSlong8(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(int32)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	uint64* 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:
+			*value=(uint64*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong8(*value,count);
+			return(TIFFReadDirEntryErrOk);
+		case TIFF_SLONG8:
+			{
+				int64* m;
+				uint32 n;
+				m=(int64*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)m);
+					err=TIFFReadDirEntryCheckRangeLong8Slong8(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(uint64*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+	}
+	data=(uint64*)_TIFFmalloc(count*8);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(uint64)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					err=TIFFReadDirEntryCheckRangeLong8Sbyte(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					err=TIFFReadDirEntryCheckRangeLong8Sshort(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					err=TIFFReadDirEntryCheckRangeLong8Slong(*ma);
+					if (err!=TIFFReadDirEntryErrOk)
+						break;
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		_TIFFfree(data);
+		return(err);
+	}
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	int64* 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* m;
+				uint32 n;
+				m=(uint64*)origdata;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8(m);
+					err=TIFFReadDirEntryCheckRangeSlong8Long8(*m);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						_TIFFfree(origdata);
+						return(err);
+					}
+					m++;
+				}
+				*value=(int64*)origdata;
+				return(TIFFReadDirEntryErrOk);
+			}
+		case TIFF_SLONG8:
+			*value=(int64*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong8((uint64*)(*value),count);
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(int64*)_TIFFmalloc(count*8);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				int64* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int64)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				int64* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(int64)(*ma++);
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				int64* mb;
+				uint32 n;
+				ma=(uint16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort(ma);
+					*mb++=(int64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SSHORT:
+			{
+				int16* ma;
+				int64* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					*mb++=(int64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				int64* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					*mb++=(int64)(*ma++);
+				}
+			}
+			break;
+		case TIFF_SLONG:
+			{
+				int32* ma;
+				int64* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					*mb++=(int64)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryFloatArray(TIFF* tif, TIFFDirEntry* direntry, float** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 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*)origdata,count);  
+			TIFFCvtIEEEDoubleToNative(tif,count,(float*)origdata);
+			*value=(float*)origdata;
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(float*)_TIFFmalloc(count*sizeof(float));
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				float* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(float)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				float* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(float)(*ma++);
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				float* mb;
+				uint32 n;
+				ma=(uint16*)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* ma;
+				float* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					*mb++=(float)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				float* mb;
+				uint32 n;
+				ma=(uint32*)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* ma;
+				float* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					*mb++=(float)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				float* mb;
+				uint32 n;
+				ma=(uint64*)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* ma;
+				float* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					*mb++=(float)(*ma++);
+				}
+			}
+			break;
+		case TIFF_RATIONAL:
+			{
+				uint32* ma;
+				uint32 maa;
+				uint32 mab;
+				float* mb;
+				uint32 n;
+				ma=(uint32*)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* ma;
+				int32 maa;
+				uint32 mab;
+				float* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					maa=*(int32*)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 n;
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabArrayOfLong8((uint64*)origdata,count);
+				TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata);
+				ma=(double*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(float)(*ma++);
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryDoubleArray(TIFF* tif, TIFFDirEntry* direntry, double** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 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*)origdata,count);
+			TIFFCvtIEEEDoubleToNative(tif,count,(double*)origdata);
+			*value=(double*)origdata;
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(double*)_TIFFmalloc(count*sizeof(double));
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_BYTE:
+			{
+				uint8* ma;
+				double* mb;
+				uint32 n;
+				ma=(uint8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(double)(*ma++);
+			}
+			break;
+		case TIFF_SBYTE:
+			{
+				int8* ma;
+				double* mb;
+				uint32 n;
+				ma=(int8*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(double)(*ma++);
+			}
+			break;
+		case TIFF_SHORT:
+			{
+				uint16* ma;
+				double* mb;
+				uint32 n;
+				ma=(uint16*)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* ma;
+				double* mb;
+				uint32 n;
+				ma=(int16*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabShort((uint16*)ma);
+					*mb++=(double)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG:
+			{
+				uint32* ma;
+				double* mb;
+				uint32 n;
+				ma=(uint32*)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* ma;
+				double* mb;
+				uint32 n;
+				ma=(int32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong((uint32*)ma);
+					*mb++=(double)(*ma++);
+				}
+			}
+			break;
+		case TIFF_LONG8:
+			{
+				uint64* ma;
+				double* mb;
+				uint32 n;
+				ma=(uint64*)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* ma;
+				double* mb;
+				uint32 n;
+				ma=(int64*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong8((uint64*)ma);
+					*mb++=(double)(*ma++);
+				}
+			}
+			break;
+		case TIFF_RATIONAL:
+			{
+				uint32* ma;
+				uint32 maa;
+				uint32 mab;
+				double* mb;
+				uint32 n;
+				ma=(uint32*)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* ma;
+				int32 maa;
+				uint32 mab;
+				double* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					maa=*(int32*)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 n;
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabArrayOfLong((uint32*)origdata,count);  
+				TIFFCvtIEEEFloatToNative(tif,count,(float*)origdata);
+				ma=(float*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+					*mb++=(double)(*ma++);
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint32 count;
+	void* origdata;
+	uint64* 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*)origdata;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabArrayOfLong8(*value,count);
+			return(TIFFReadDirEntryErrOk);
+	}
+	data=(uint64*)_TIFFmalloc(count*8);
+	if (data==0)
+	{
+		_TIFFfree(origdata);
+		return(TIFFReadDirEntryErrAlloc);
+	}
+	switch (direntry->tdir_type)
+	{
+		case TIFF_LONG:
+		case TIFF_IFD:
+			{
+				uint32* ma;
+				uint64* mb;
+				uint32 n;
+				ma=(uint32*)origdata;
+				mb=data;
+				for (n=0; n<count; n++)
+				{
+					if (tif->tif_flags&TIFF_SWAB)
+						TIFFSwabLong(ma);
+					*mb++=(uint64)(*ma++);
+				}
+			}
+			break;
+	}
+	_TIFFfree(origdata);
+	*value=data;
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value)
+{
+	enum TIFFReadDirEntryErr err;
+	uint16* m;
+	uint16* na;
+	uint16 nb;
+	if (direntry->tdir_count<(uint64)tif->tif_dir.td_samplesperpixel)
+		return(TIFFReadDirEntryErrCount);
+	err=TIFFReadDirEntryShortArray(tif,direntry,&m);
+	if (err!=TIFFReadDirEntryErrOk)
+		return(err);
+	na=m;
+	nb=tif->tif_dir.td_samplesperpixel;
+	*value=*na++;
+	nb--;
+	while (nb>0)
+	{
+		if (*na++!=*value)
+		{
+			err=TIFFReadDirEntryErrPsdif;
+			break;
+		}
+		nb--;
+	}
+	_TIFFfree(m);
+	return(err);
+}
+
+#if 0
+static enum TIFFReadDirEntryErr TIFFReadDirEntryPersampleDouble(TIFF* tif, TIFFDirEntry* direntry, double* value)
+{
+	enum TIFFReadDirEntryErr err;
+	double* m;
+	double* na;
+	uint16 nb;
+	if (direntry->tdir_count<(uint64)tif->tif_dir.td_samplesperpixel)
+		return(TIFFReadDirEntryErrCount);
+	err=TIFFReadDirEntryDoubleArray(tif,direntry,&m);
+	if (err!=TIFFReadDirEntryErrOk)
+		return(err);
+	na=m;
+	nb=tif->tif_dir.td_samplesperpixel;
+	*value=*na++;
+	nb--;
+	while (nb>0)
+	{
+		if (*na++!=*value)
+		{
+			err=TIFFReadDirEntryErrPsdif;
+			break;
+		}
+		nb--;
+	}
+	_TIFFfree(m);
+	return(err);
+}
+#endif
+
+static void TIFFReadDirEntryCheckedByte(TIFF* tif, TIFFDirEntry* direntry, uint8* value)
+{
+	(void) tif;
+	*value=*(uint8*)(&direntry->tdir_offset);
+}
+
+static void TIFFReadDirEntryCheckedSbyte(TIFF* tif, TIFFDirEntry* direntry, int8* value)
+{
+	(void) tif;
+	*value=*(int8*)(&direntry->tdir_offset);
+}
+
+static void TIFFReadDirEntryCheckedShort(TIFF* tif, TIFFDirEntry* direntry, uint16* value)
+{
+	*value = direntry->tdir_offset.toff_short;
+	/* *value=*(uint16*)(&direntry->tdir_offset); */
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabShort(value);
+}
+
+static void TIFFReadDirEntryCheckedSshort(TIFF* tif, TIFFDirEntry* direntry, int16* value)
+{
+	*value=*(int16*)(&direntry->tdir_offset);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabShort((uint16*)value);
+}
+
+static void TIFFReadDirEntryCheckedLong(TIFF* tif, TIFFDirEntry* direntry, uint32* value)
+{
+	*value=*(uint32*)(&direntry->tdir_offset);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong(value);
+}
+
+static void TIFFReadDirEntryCheckedSlong(TIFF* tif, TIFFDirEntry* direntry, int32* value)
+{
+	*value=*(int32*)(&direntry->tdir_offset);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong((uint32*)value);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedLong8(TIFF* tif, TIFFDirEntry* direntry, uint64* value)
+{
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		enum TIFFReadDirEntryErr err;
+		uint32 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* value)
+{
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		enum TIFFReadDirEntryErr err;
+		uint32 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*)(&direntry->tdir_offset);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong8((uint64*)value);
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedRational(TIFF* tif, TIFFDirEntry* direntry, double* value)
+{
+	UInt64Aligned_t m;
+
+	assert(sizeof(double)==8);
+	assert(sizeof(uint64)==8);
+	assert(sizeof(uint32)==4);
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		enum TIFFReadDirEntryErr err;
+		uint32 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);
+	if (m.i[0]==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)==8);
+	assert(sizeof(int32)==4);
+	assert(sizeof(uint32)==4);
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		enum TIFFReadDirEntryErr err;
+		uint32 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);
+	if ((int32)m.i[0]==0)
+		*value=0.0;
+	else
+		*value=(double)((int32)m.i[0])/(double)m.i[1];
+	return(TIFFReadDirEntryErrOk);
+}
+
+static void TIFFReadDirEntryCheckedFloat(TIFF* tif, TIFFDirEntry* direntry, float* value)
+{
+         union
+	 {
+	   float  f;
+	   uint32 i;
+	 } float_union;
+	assert(sizeof(float)==4);
+	assert(sizeof(uint32)==4);
+	assert(sizeof(float_union)==4);
+	float_union.i=*(uint32*)(&direntry->tdir_offset);
+	*value=float_union.f;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong((uint32*)value);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckedDouble(TIFF* tif, TIFFDirEntry* direntry, double* value)
+{
+	assert(sizeof(double)==8);
+	assert(sizeof(uint64)==8);
+	assert(sizeof(UInt64Aligned_t)==8);
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		enum TIFFReadDirEntryErr err;
+		uint32 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*)value);
+	return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSbyte(int8 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteShort(uint16 value)
+{
+	if (value>0xFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSshort(int16 value)
+{
+	if ((value<0)||(value>0xFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong(uint32 value)
+{
+	if (value>0xFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong(int32 value)
+{
+	if ((value<0)||(value>0xFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteLong8(uint64 value)
+{
+	if (value>0xFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeByteSlong8(int64 value)
+{
+	if ((value<0)||(value>0xFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteByte(uint8 value)
+{
+	if (value>0x7F)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteShort(uint16 value)
+{
+	if (value>0x7F)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSshort(int16 value)
+{
+	if ((value<-0x80)||(value>0x7F))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong(uint32 value)
+{
+	if (value>0x7F)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong(int32 value)
+{
+	if ((value<-0x80)||(value>0x7F))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteLong8(uint64 value)
+{
+	if (value>0x7F)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSbyteSlong8(int64 value)
+{
+	if ((value<-0x80)||(value>0x7F))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSbyte(int8 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSshort(int16 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong(uint32 value)
+{
+	if (value>0xFFFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong(int32 value)
+{
+	if ((value<0)||(value>0xFFFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortLong8(uint64 value)
+{
+	if (value>0xFFFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeShortSlong8(int64 value)
+{
+	if ((value<0)||(value>0xFFFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortShort(uint16 value)
+{
+	if (value>0x7FFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong(uint32 value)
+{
+	if (value>0x7FFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong(int32 value)
+{
+	if ((value<-0x8000)||(value>0x7FFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortLong8(uint64 value)
+{
+	if (value>0x7FFF)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeSshortSlong8(int64 value)
+{
+	if ((value<-0x8000)||(value>0x7FFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSbyte(int8 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSshort(int16 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr TIFFReadDirEntryCheckRangeLongSlong(int32 value)
+{
+	if (value<0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+/*
+ * Largest 32-bit unsigned integer value.
+ */
+#define TIFF_UINT32_MAX 0xFFFFFFFFU
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLongLong8(uint64 value)
+{
+	if (value > TIFF_UINT32_MAX)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLongSlong8(int64 value)
+{
+	if ((value < 0) || (value > (int64) TIFF_UINT32_MAX))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+#undef TIFF_UINT32_MAX
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeSlongLong(uint32 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 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 value)
+{
+        if ((value < 0-((int64) 0x7FFFFFFF+1)) || (value > 0x7FFFFFFF))
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLong8Sbyte(int8 value)
+{
+	if (value < 0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLong8Sshort(int16 value)
+{
+	if (value < 0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLong8Slong(int32 value)
+{
+	if (value < 0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeLong8Slong8(int64 value)
+{
+	if (value < 0)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+/*
+ * Largest 64-bit signed integer value.
+ */
+#define TIFF_INT64_MAX ((int64)(((uint64) ~0) >> 1))
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryCheckRangeSlong8Long8(uint64 value)
+{
+	if (value > TIFF_INT64_MAX)
+		return(TIFFReadDirEntryErrRange);
+	else
+		return(TIFFReadDirEntryErrOk);
+}
+
+#undef TIFF_INT64_MAX
+
+static enum TIFFReadDirEntryErr
+TIFFReadDirEntryData(TIFF* tif, uint64 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;
+		mb=ma+size;
+		if (((uint64)ma!=offset)
+		    || (mb < ma)
+		    || (mb - ma != (size_t) size)
+		    || (mb < (size_t)size)
+		    || (mb > (size_t)tif->tif_size)
+		    )
+			return(TIFFReadDirEntryErrIo);
+		_TIFFmemcpy(dest,tif->tif_base+ma,size);
+	}
+	return(TIFFReadDirEntryErrOk);
+}
+
+static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, const char* module, const char* tagname, int recover)
+{
+	if (!recover) {
+		switch (err) {
+			case TIFFReadDirEntryErrCount:
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Incorrect count for \"%s\"",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrType:
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Incompatible type for \"%s\"",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrIo:
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "IO error during reading of \"%s\"",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrRange:
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Incorrect value for \"%s\"",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrPsdif:
+				TIFFErrorExt(tif->tif_clientdata, module,
+			"Cannot handle different values per sample for \"%s\"",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrSizesan:
+				TIFFErrorExt(tif->tif_clientdata, module,
+				"Sanity check on size of \"%s\" value failed",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrAlloc:
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Out of memory reading of \"%s\"",
+					     tagname);
+				break;
+			default:
+				assert(0);   /* we should never get here */
+				break;
+		}
+	} else {
+		switch (err) {
+			case TIFFReadDirEntryErrCount:
+				TIFFWarningExt(tif->tif_clientdata, module,
+				"Incorrect count for \"%s\"; tag ignored",
+					     tagname);
+				break;
+			case TIFFReadDirEntryErrType:
+				TIFFWarningExt(tif->tif_clientdata, module,
+				"Incompatible type for \"%s\"; tag ignored",
+					       tagname);
+				break;
+			case TIFFReadDirEntryErrIo:
+				TIFFWarningExt(tif->tif_clientdata, module,
+			"IO error during reading of \"%s\"; tag ignored",
+					       tagname);
+				break;
+			case TIFFReadDirEntryErrRange:
+				TIFFWarningExt(tif->tif_clientdata, module,
+				"Incorrect value for \"%s\"; tag ignored",
+					       tagname);
+				break;
+			case TIFFReadDirEntryErrPsdif:
+				TIFFWarningExt(tif->tif_clientdata, module,
+	"Cannot handle different values per sample for \"%s\"; tag ignored",
+					       tagname);
+				break;
+			case TIFFReadDirEntryErrSizesan:
+				TIFFWarningExt(tif->tif_clientdata, module,
+		"Sanity check on size of \"%s\" value failed; tag ignored",
+					       tagname);
+				break;
+			case TIFFReadDirEntryErrAlloc:
+				TIFFWarningExt(tif->tif_clientdata, module,
+				"Out of memory reading of \"%s\"; tag ignored",
+					       tagname);
+				break;
+			default:
+				assert(0);   /* we should never get here */
+				break;
+		}
+	}
+}
+
+/*
+ * 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 dircount;
+	TIFFDirEntry* dp;
+	uint16 di;
+	const TIFFField* fip;
+	uint32 fii=FAILED_FII;
+        toff_t nextdiroff;
+    int bitspersample_read = FALSE;
+
+	tif->tif_diroff=tif->tif_nextdiroff;
+	if (!TIFFCheckDirOffset(tif,tif->tif_nextdiroff))
+		return 0;           /* last offset or bad offset (IFD looping) */
+	(*tif->tif_cleanup)(tif);   /* cleanup any previous compression state */
+	tif->tif_curdir++;
+        nextdiroff = tif->tif_nextdiroff;
+	dircount=TIFFFetchDirectory(tif,nextdiroff,&dir,&tif->tif_nextdiroff);
+	if (!dircount)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,
+		    "Failed to read directory at offset " TIFF_UINT64_FORMAT,nextdiroff);
+		return 0;
+	}
+	TIFFReadDirectoryCheckOrder(tif,dir,dircount);
+
+        /*
+         * Mark duplicates of any tag to be ignored (bugzilla 1994)
+         * to avoid certain pathological problems.
+         */
+	{
+		TIFFDirEntry* ma;
+		uint16 mb;
+		for (ma=dir, mb=0; mb<dircount; ma++, mb++)
+		{
+			TIFFDirEntry* na;
+			uint16 nb;
+			for (na=ma+1, nb=mb+1; nb<dircount; na++, nb++)
+			{
+				if (ma->tdir_tag==na->tdir_tag)
+					na->tdir_tag=IGNORE;
+			}
+		}
+	}
+        
+	tif->tif_flags &= ~TIFF_BEENWRITING;    /* reset before new dir */
+	tif->tif_flags &= ~TIFF_BUF4WRITE;      /* reset before new 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);
+	/*
+	 * 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.
+	 * 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 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).
+	 */
+	dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_SAMPLESPERPIXEL);
+	if (dp)
+	{
+		if (!TIFFFetchNormalTag(tif,dp,0))
+			goto bad;
+		dp->tdir_tag=IGNORE;
+	}
+	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 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_tag=IGNORE;
+	}
+	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_tag!=IGNORE)
+		{
+			TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
+			if (fii == FAILED_FII)
+			{
+				TIFFWarningExt(tif->tif_clientdata, module,
+				    "Unknown field with tag %d (0x%x) encountered",
+				    dp->tdir_tag,dp->tdir_tag);
+                                /* the following knowingly leaks the 
+                                   anonymous field structure */
+				if (!_TIFFMergeFields(tif,
+					_TIFFCreateAnonField(tif,
+						dp->tdir_tag,
+						(TIFFDataType) dp->tdir_type),
+					1)) {
+					TIFFWarningExt(tif->tif_clientdata,
+					    module,
+					    "Registering anonymous field with tag %d (0x%x) failed",
+					    dp->tdir_tag,
+					    dp->tdir_tag);
+					dp->tdir_tag=IGNORE;
+				} else {
+					TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
+					assert(fii != FAILED_FII);
+				}
+			}
+		}
+		if (dp->tdir_tag!=IGNORE)
+		{
+			fip=tif->tif_fields[fii];
+			if (fip->field_bit==FIELD_IGNORE)
+				dp->tdir_tag=IGNORE;
+			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_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 ((tif->tif_dir.td_compression==COMPRESSION_OJPEG)&&
+	    (tif->tif_dir.td_planarconfig==PLANARCONFIG_SEPARATE))
+	{
+        if (!_TIFFFillStriles(tif))
+            goto bad;
+		dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,TIFFTAG_STRIPOFFSETS);
+		if ((dp!=0)&&(dp->tdir_count==1))
+		{
+			dp=TIFFReadDirectoryFindEntry(tif,dir,dircount,
+			    TIFFTAG_STRIPBYTECOUNTS);
+			if ((dp!=0)&&(dp->tdir_count==1))
+			{
+				tif->tif_dir.td_planarconfig=PLANARCONFIG_CONTIG;
+				TIFFWarningExt(tif->tif_clientdata,module,
+				    "Planarconfig tag value assumed incorrect, "
+				    "assuming data is contig instead of chunky");
+			}
+		}
+	}
+	/*
+	 * Allocate directory structure and setup defaults.
+	 */
+	if (!TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS))
+	{
+		MissingRequired(tif,"ImageLength");
+		goto bad;
+	}
+	/*
+	 * Setup appropriate structures (by strip or by tile)
+	 */
+	if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
+		tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif);  
+		tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth;
+		tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip;
+		tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth;
+		tif->tif_flags &= ~TIFF_ISTILED;
+	} else {
+		tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif);
+		tif->tif_flags |= TIFF_ISTILED;
+	}
+	if (!tif->tif_dir.td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Cannot handle zero number of %s",
+		    isTiled(tif) ? "tiles" : "strips");
+		goto bad;
+	}
+	tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips;
+	if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE)
+		tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel;
+	if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
+		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 {
+			MissingRequired(tif,
+				isTiled(tif) ? "TileOffsets" : "StripOffsets");
+			goto bad;
+		}
+	}
+	/*
+	 * Second pass: extract other information.
+	 */
+	for (di=0, dp=dir; di<dircount; di++, dp++)
+	{
+		switch (dp->tdir_tag)
+		{
+			case IGNORE:
+				break;
+			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 (yech). Other vendors write correct
+				 * value for NumberOfSamples, but incorrect one for
+				 * BitsPerSample and friends, and we will read this
+				 * too.
+				 */
+				{
+					uint16 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;
+					enum TIFFReadDirEntryErr err;
+					uint32 saved_flags;
+					int m;
+					if (dp->tdir_count != (uint64)tif->tif_dir.td_samplesperpixel)
+						err = TIFFReadDirEntryErrCount;
+					else
+						err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
+					if (err!=TIFFReadDirEntryErrOk)
+					{
+						fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+						TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
+						goto bad;
+					}
+					saved_flags = tif->tif_flags;
+					tif->tif_flags |= TIFF_PERSAMPLE;
+					m = TIFFSetField(tif,dp->tdir_tag,data);
+					tif->tif_flags = saved_flags;
+					_TIFFfree(data);
+					if (!m)
+						goto bad;
+				}
+				break;
+			case TIFFTAG_STRIPOFFSETS:
+			case TIFFTAG_TILEOFFSETS:
+#if defined(DEFER_STRILE_LOAD)
+                                _TIFFmemcpy( &(tif->tif_dir.td_stripoffset_entry),
+                                             dp, sizeof(TIFFDirEntry) );
+#else                          
+				if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripoffset))  
+					goto bad;
+#endif                                
+				break;
+			case TIFFTAG_STRIPBYTECOUNTS:
+			case TIFFTAG_TILEBYTECOUNTS:
+#if defined(DEFER_STRILE_LOAD)
+                                _TIFFmemcpy( &(tif->tif_dir.td_stripbytecount_entry),
+                                             dp, sizeof(TIFFDirEntry) );
+#else                          
+				if (!TIFFFetchStripThing(tif,dp,tif->tif_dir.td_nstrips,&tif->tif_dir.td_stripbytecount))  
+					goto bad;
+#endif                                
+				break;
+			case TIFFTAG_COLORMAP:
+			case TIFFTAG_TRANSFERFUNCTION:
+				{
+					enum TIFFReadDirEntryErr err;
+					uint32 countpersample;
+					uint32 countrequired;
+					uint32 incrementpersample;
+					uint16* value=NULL;
+                    /* It would be dangerous to instanciate those tag values */
+                    /* since if td_bitspersample has not yet been read (due to */
+                    /* unordered tags), it could be read afterwards with a */
+                    /* values greater than the default one (1), which may cause */
+                    /* crashes in user code */
+                    if( !bitspersample_read )
+                    {
+                        fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+                        TIFFWarningExt(tif->tif_clientdata,module,
+                                       "Ignoring %s since BitsPerSample tag not found",
+                                       fip ? fip->field_name : "unknown tagname");
+                        continue;
+                    }
+					countpersample=(1L<<tif->tif_dir.td_bitspersample);
+					if ((dp->tdir_tag==TIFFTAG_TRANSFERFUNCTION)&&(dp->tdir_count==(uint64)countpersample))
+					{
+						countrequired=countpersample;
+						incrementpersample=0;
+					}
+					else
+					{
+						countrequired=3*countpersample;
+						incrementpersample=countpersample;
+					}
+					if (dp->tdir_count!=(uint64)countrequired)
+						err=TIFFReadDirEntryErrCount;
+					else
+						err=TIFFReadDirEntryShortArray(tif,dp,&value);
+					if (err!=TIFFReadDirEntryErrOk)
+                    {
+						fip = TIFFFieldWithTag(tif,dp->tdir_tag);
+						TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",1);
+                    }
+					else
+					{
+						TIFFSetField(tif,dp->tdir_tag,value,value+incrementpersample,value+2*incrementpersample);
+						_TIFFfree(value);
+					}
+				}
+				break;
+/* BEGIN REV 4.0 COMPATIBILITY */
+			case TIFFTAG_OSUBFILETYPE:
+				{
+					uint16 valueo;
+					uint32 value;
+					if (TIFFReadDirEntryShort(tif,dp,&valueo)==TIFFReadDirEntryErrOk)
+					{
+						switch (valueo)
+						{
+							case OFILETYPE_REDUCEDIMAGE: value=FILETYPE_REDUCEDIMAGE; break;
+							case OFILETYPE_PAGE: value=FILETYPE_PAGE; break;
+							default: value=0; break;
+						}
+						if (value!=0)
+							TIFFSetField(tif,TIFFTAG_SUBFILETYPE,value);
+					}
+				}
+				break;
+/* END REV 4.0 COMPATIBILITY */
+			default:
+				(void) TIFFFetchNormalTag(tif, dp, TRUE);
+				break;
+		}
+	}
+	/*
+	 * OJPEG hack:
+	 * - If a) compression is OJPEG, and b) photometric tag is missing,
+	 * then we consistently find that photometric should be YCbCr
+	 * - If a) compression is OJPEG, and b) photometric tag says it's RGB,
+	 * then we consistently find that the buggy implementation of the
+	 * buggy compression scheme matches photometric YCbCr instead.
+	 * - If a) compression is OJPEG, and b) bitspersample tag is missing,
+	 * then we consistently find bitspersample should be 8.
+	 * - If a) compression is OJPEG, b) samplesperpixel tag is missing,
+	 * and c) photometric is RGB or YCbCr, then we consistently find
+	 * samplesperpixel should be 3
+	 * - If a) compression is OJPEG, b) samplesperpixel tag is missing,
+	 * and c) photometric is MINISWHITE or MINISBLACK, then we consistently
+	 * find samplesperpixel should be 3
+	 */
+	if (tif->tif_dir.td_compression==COMPRESSION_OJPEG)
+	{
+		if (!TIFFFieldSet(tif,FIELD_PHOTOMETRIC))
+		{
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Photometric tag is missing, assuming data is YCbCr");
+			if (!TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_YCBCR))
+				goto bad;
+		}
+		else if (tif->tif_dir.td_photometric==PHOTOMETRIC_RGB)
+		{
+			tif->tif_dir.td_photometric=PHOTOMETRIC_YCBCR;
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Photometric tag value assumed incorrect, "
+			    "assuming data is YCbCr instead of RGB");
+		}
+		if (!TIFFFieldSet(tif,FIELD_BITSPERSAMPLE))
+		{
+			TIFFWarningExt(tif->tif_clientdata,module,
+			    "BitsPerSample tag is missing, assuming 8 bits per sample");
+			if (!TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,8))
+				goto bad;
+		}
+		if (!TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL))
+		{
+			if (tif->tif_dir.td_photometric==PHOTOMETRIC_RGB)
+			{
+				TIFFWarningExt(tif->tif_clientdata,module,
+				    "SamplesPerPixel tag is missing, "
+				    "assuming correct SamplesPerPixel value is 3");
+				if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3))
+					goto bad;
+			}
+			if (tif->tif_dir.td_photometric==PHOTOMETRIC_YCBCR)
+			{
+				TIFFWarningExt(tif->tif_clientdata,module,
+				    "SamplesPerPixel tag is missing, "
+				    "applying correct SamplesPerPixel value of 3");
+				if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3))
+					goto bad;
+			}
+			else if ((tif->tif_dir.td_photometric==PHOTOMETRIC_MINISWHITE)
+				 || (tif->tif_dir.td_photometric==PHOTOMETRIC_MINISBLACK))
+			{
+				/*
+				 * SamplesPerPixel tag is missing, but is not required
+				 * by spec.  Assume correct SamplesPerPixel value of 1.
+				 */
+				if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,1))
+					goto bad;
+			}
+		}
+	}
+	/*
+	 * 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)tif->tif_dir.td_samplesperpixel)) {
+			    MissingRequired(tif, "StripByteCounts");
+			    goto bad;
+			}
+			TIFFWarningExt(tif->tif_clientdata, module,
+				"TIFF directory is missing required "
+				"\"StripByteCounts\" field, calculating from imagelength");
+			if (EstimateStripByteCounts(tif, dir, dircount) < 0)
+			    goto bad;
+		/*
+		 * 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 \
+		    ( (tif->tif_dir.td_stripbytecount[0] == 0 && tif->tif_dir.td_stripoffset[0] != 0) || \
+		      (tif->tif_dir.td_compression == COMPRESSION_NONE && \
+		       tif->tif_dir.td_stripbytecount[0] > TIFFGetFileSize(tif) - tif->tif_dir.td_stripoffset[0]) || \
+		      (tif->tif_mode == O_RDONLY && \
+		       tif->tif_dir.td_compression == COMPRESSION_NONE && \
+		       tif->tif_dir.td_stripbytecount[0] < TIFFScanlineSize64(tif) * tif->tif_dir.td_imagelength) )
+
+		} else if (tif->tif_dir.td_nstrips == 1
+                           && _TIFFFillStriles(tif)
+			   && tif->tif_dir.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,
+			    "Bogus \"StripByteCounts\" field, ignoring and calculating from imagelength");
+			if(EstimateStripByteCounts(tif, dir, dircount) < 0)
+			    goto bad;
+
+#if !defined(DEFER_STRILE_LOAD)
+		} else if (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG
+			   && tif->tif_dir.td_nstrips > 2
+			   && tif->tif_dir.td_compression == COMPRESSION_NONE
+			   && tif->tif_dir.td_stripbytecount[0] != tif->tif_dir.td_stripbytecount[1]
+			   && tif->tif_dir.td_stripbytecount[0] != 0
+			   && tif->tif_dir.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.
+                         *
+                         * We avoid this check if deferring strile loading
+                         * as it would always force us to load the strip/tile
+                         * information.
+			 */
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Wrong \"StripByteCounts\" field, ignoring and calculating from imagelength");
+			if (EstimateStripByteCounts(tif, dir, dircount) < 0)
+			    goto bad;
+#endif /* !defined(DEFER_STRILE_LOAD) */                        
+		}
+	}
+	if (dir)
+	{
+		_TIFFfree(dir);
+		dir=NULL;
+	}
+	if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE))
+	{
+		if (tif->tif_dir.td_bitspersample>=16)
+			tif->tif_dir.td_maxsamplevalue=0xFFFF;
+		else
+			tif->tif_dir.td_maxsamplevalue = (uint16)((1L<<tif->tif_dir.td_bitspersample)-1);
+	}
+	/*
+	 * 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 !defined(DEFER_STRILE_LOAD)        
+	if (tif->tif_dir.td_nstrips > 1) {
+		uint32 strip;
+
+		tif->tif_dir.td_stripbytecountsorted = 1;
+		for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) {
+			if (tif->tif_dir.td_stripoffset[strip - 1] >
+			    tif->tif_dir.td_stripoffset[strip]) {
+				tif->tif_dir.td_stripbytecountsorted = 0;
+				break;
+			}
+		}
+	}
+#endif /* !defined(DEFER_STRILE_LOAD) */
+        
+	/*
+	 * 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))
+    {
+        if ( !_TIFFFillStriles(tif) || !tif->tif_dir.td_stripbytecount )
+            return 0;
+		ChopUpSingleUncompressedStrip(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) -1;
+	tif->tif_curstrip = (uint32) -1;
+	tif->tif_col = (uint32) -1;
+	tif->tif_curtile = (uint32) -1;
+	tif->tif_tilesize = (tmsize_t) -1;
+
+	tif->tif_scanlinesize = TIFFScanlineSize(tif);
+	if (!tif->tif_scanlinesize) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Cannot handle zero scanline size");
+		return (0);
+	}
+
+	if (isTiled(tif)) {
+		tif->tif_tilesize = TIFFTileSize(tif);
+		if (!tif->tif_tilesize) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			     "Cannot handle zero tile size");
+			return (0);
+		}
+	} else {
+		if (!TIFFStripSize(tif)) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Cannot handle zero strip size");
+			return (0);
+		}
+	}
+	return (1);
+bad:
+	if (dir)
+		_TIFFfree(dir);
+	return (0);
+}
+
+static void
+TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
+{
+	static const char module[] = "TIFFReadDirectoryCheckOrder";
+	uint16 m;
+	uint16 n;
+	TIFFDirEntry* o;
+	m=0;
+	for (n=0, o=dir; n<dircount; n++, o++)
+	{
+		if (o->tdir_tag<m)
+		{
+			TIFFWarningExt(tif->tif_clientdata,module,
+			    "Invalid TIFF directory; tags are not sorted in ascending order");
+			break;
+		}
+		m=o->tdir_tag+1;
+	}
+}
+
+static TIFFDirEntry*
+TIFFReadDirectoryFindEntry(TIFF* tif, TIFFDirEntry* dir, uint16 dircount, uint16 tagid)
+{
+	TIFFDirEntry* m;
+	uint16 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 tagid, uint32* fii)
+{
+	int32 ma,mb,mc;
+	ma=-1;
+	mc=(int32)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)tagid)
+			break;
+		if (tif->tif_fields[mb]->field_tag<(uint32)tagid)
+			ma=mb;
+		else
+			mc=mb;
+	}
+	while (1)
+	{
+		if (mb==0)
+			break;
+		if (tif->tif_fields[mb-1]->field_tag!=(uint32)tagid)
+			break;
+		mb--;
+	}
+	*fii=mb;
+}
+
+/*
+ * Read custom directory from the arbitarry 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 dircount;
+	TIFFDirEntry* dp;
+	uint16 di;
+	const TIFFField* fip;
+	uint32 fii;
+	_TIFFSetupFields(tif, infoarray);
+	dircount=TIFFFetchDirectory(tif,diroff,&dir,NULL);
+	if (!dircount)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,
+		    "Failed to read custom directory at offset " TIFF_UINT64_FORMAT,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)
+		{
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Unknown field with tag %d (0x%x) encountered",
+			    dp->tdir_tag, dp->tdir_tag);
+			if (!_TIFFMergeFields(tif, _TIFFCreateAnonField(tif,
+						dp->tdir_tag,
+						(TIFFDataType) dp->tdir_type),
+					     1)) {
+				TIFFWarningExt(tif->tif_clientdata, module,
+				    "Registering anonymous field with tag %d (0x%x) failed",
+				    dp->tdir_tag, dp->tdir_tag);
+				dp->tdir_tag=IGNORE;
+			} else {
+				TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
+				assert( fii != FAILED_FII );
+			}
+		}
+		if (dp->tdir_tag!=IGNORE)
+		{
+			fip=tif->tif_fields[fii];
+			if (fip->field_bit==FIELD_IGNORE)
+				dp->tdir_tag=IGNORE;
+			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)dp->tdir_tag))
+					{
+						fii=0xFFFF;
+						break;
+					}
+					fip=tif->tif_fields[fii];
+				}
+				if (fii==0xFFFF)
+				{
+					TIFFWarningExt(tif->tif_clientdata, module,
+					    "Wrong data type %d for \"%s\"; tag ignored",
+					    dp->tdir_type,fip->field_name);
+					dp->tdir_tag=IGNORE;
+				}
+				else
+				{
+					/* check count if known in advance */
+					if ((fip->field_readcount!=TIFF_VARIABLE)&&
+					    (fip->field_readcount!=TIFF_VARIABLE2))
+					{
+						uint32 expected;
+						if (fip->field_readcount==TIFF_SPP)
+							expected=(uint32)tif->tif_dir.td_samplesperpixel;
+						else
+							expected=(uint32)fip->field_readcount;
+						if (!CheckDirCount(tif,dp,expected))
+							dp->tdir_tag=IGNORE;
+					}
+				}
+			}
+			switch (dp->tdir_tag)
+			{
+				case IGNORE:
+					break;
+				case EXIFTAG_SUBJECTDISTANCE:
+					(void) TIFFFetchSubjectDistance(tif,dp);
+					break;
+				default:
+					(void) TIFFFetchNormalTag(tif, dp, TRUE);
+					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)
+{
+	const TIFFFieldArray* exifFieldArray;
+	exifFieldArray = _TIFFGetExifFields();
+	return TIFFReadCustomDirectory(tif, diroff, exifFieldArray);  
+}
+
+static int
+EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
+{
+	static const char module[] = "EstimateStripByteCounts";
+
+	TIFFDirEntry *dp;
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 strip;
+
+    if( !_TIFFFillStriles( tif ) )
+        return -1;
+
+	if (td->td_stripbytecount)
+		_TIFFfree(td->td_stripbytecount);
+	td->td_stripbytecount = (uint64*)
+	    _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint64),
+		"for \"StripByteCounts\" array");
+        if( td->td_stripbytecount == NULL )
+            return -1;
+
+	if (td->td_compression != COMPRESSION_NONE) {
+		uint64 space;
+		uint64 filesize;
+		uint16 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 typewidth = TIFFDataWidth((TIFFDataType) dp->tdir_type);
+			uint64 datasize;
+			typewidth = TIFFDataWidth((TIFFDataType) dp->tdir_type);
+			if (typewidth == 0) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Cannot determine size of unknown tag type %d",
+				    dp->tdir_type);
+				return -1;
+			}
+			datasize=(uint64)typewidth*dp->tdir_count;
+			if (!(tif->tif_flags&TIFF_BIGTIFF))
+			{
+				if (datasize<=4)
+					datasize=0;
+			}
+			else
+			{
+				if (datasize<=8)
+					datasize=0;
+			}
+			space+=datasize;
+		}
+		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 (td->td_stripoffset[strip]+td->td_stripbytecount[strip] > filesize)
+			td->td_stripbytecount[strip] = filesize - td->td_stripoffset[strip];
+	} else if (isTiled(tif)) {
+		uint64 bytespertile = TIFFTileSize64(tif);
+
+		for (strip = 0; strip < td->td_nstrips; strip++)
+		    td->td_stripbytecount[strip] = bytespertile;
+	} else {
+		uint64 rowbytes = TIFFScanlineSize64(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,
+	    "TIFF directory is missing required \"%s\" field",
+	    tagname);
+}
+
+/*
+ * Check the directory offset against the list of already seen directory
+ * offsets. This is a trick to prevent IFD looping. The one can create TIFF
+ * file with looped directory pointers. We will maintain a list of already
+ * seen directories and check every IFD offset against that list.
+ */
+static int
+TIFFCheckDirOffset(TIFF* tif, uint64 diroff)
+{
+	uint16 n;
+
+	if (diroff == 0)			/* no more directories */
+		return 0;
+	if (tif->tif_dirnumber == 65535) {
+	    TIFFErrorExt(tif->tif_clientdata, "TIFFCheckDirOffset",
+			 "Cannot handle more than 65535 TIFF directories");
+	    return 0;
+	}
+
+	for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) {
+		if (tif->tif_dirlist[n] == diroff)
+			return 0;
+	}
+
+	tif->tif_dirnumber++;
+
+	if (tif->tif_dirnumber > tif->tif_dirlistsize) {
+		uint64* new_dirlist;
+
+		/*
+		 * XXX: Reduce memory allocation granularity of the dirlist
+		 * array.
+		 */
+		new_dirlist = (uint64*)_TIFFCheckRealloc(tif, tif->tif_dirlist,
+		    tif->tif_dirnumber, 2 * sizeof(uint64), "for IFD list");
+		if (!new_dirlist)
+			return 0;
+		if( tif->tif_dirnumber >= 32768 )
+		    tif->tif_dirlistsize = 65535;
+		else
+		    tif->tif_dirlistsize = 2 * tif->tif_dirnumber;
+		tif->tif_dirlist = new_dirlist;
+	}
+
+	tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff;
+
+	return 1;
+}
+
+/*
+ * Check the count field of a directory entry against a known value.  The
+ * caller is expected to skip/ignore the tag if there is a mismatch.
+ */
+static int
+CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count)
+{
+	if ((uint64)count > dir->tdir_count) {
+		const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag);
+		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+	"incorrect count for field \"%s\" (" TIFF_UINT64_FORMAT ", expecting %u); tag ignored",
+		    fip ? fip->field_name : "unknown tagname",
+		    dir->tdir_count, count);
+		return (0);
+	} else if ((uint64)count < dir->tdir_count) {
+		const TIFFField* fip = TIFFFieldWithTag(tif, dir->tdir_tag);
+		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+	"incorrect count for field \"%s\" (" TIFF_UINT64_FORMAT ", expecting %u); 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
+TIFFFetchDirectory(TIFF* tif, uint64 diroff, TIFFDirEntry** pdir,
+                   uint64 *nextdiroff)
+{
+	static const char module[] = "TIFFFetchDirectory";
+
+	void* origdir;
+	uint16 dircount16;
+	uint32 dirsize;
+	TIFFDirEntry* dir;
+	uint8* ma;
+	TIFFDirEntry* mb;
+	uint16 n;
+
+	assert(pdir);
+
+	tif->tif_diroff = diroff;
+	if (nextdiroff)
+		*nextdiroff = 0;
+	if (!isMapped(tif)) {
+		if (!SeekOK(tif, tif->tif_diroff)) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"%s: Seek error accessing TIFF directory",
+				tif->tif_name);
+			return 0;
+		}
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			if (!ReadOK(tif, &dircount16, sizeof (uint16))) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "%s: Can not read TIFF directory count",
+				    tif->tif_name);
+				return 0;
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabShort(&dircount16);
+			if (dircount16>4096)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Sanity check on directory count failed, this is probably not a valid IFD offset");
+				return 0;
+			}
+			dirsize = 12;
+		} else {
+			uint64 dircount64;
+			if (!ReadOK(tif, &dircount64, sizeof (uint64))) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					"%s: Can not read TIFF directory count",
+					tif->tif_name);
+				return 0;
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&dircount64);
+			if (dircount64>4096)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Sanity check on directory count failed, this is probably not a valid IFD offset");
+				return 0;
+			}
+			dircount16 = (uint16)dircount64;
+			dirsize = 20;
+		}
+		origdir = _TIFFCheckMalloc(tif, dircount16,
+		    dirsize, "to read TIFF directory");
+		if (origdir == NULL)
+			return 0;
+		if (!ReadOK(tif, origdir, (tmsize_t)(dircount16*dirsize))) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"%.100s: Can not read TIFF directory",
+				tif->tif_name);
+			_TIFFfree(origdir);
+			return 0;
+		}
+		/*
+		 * Read offset to next directory for sequential scans if
+		 * needed.
+		 */
+		if (nextdiroff)
+		{
+			if (!(tif->tif_flags&TIFF_BIGTIFF))
+			{
+				uint32 nextdiroff32;
+				if (!ReadOK(tif, &nextdiroff32, sizeof(uint32)))
+					nextdiroff32 = 0;
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabLong(&nextdiroff32);
+				*nextdiroff=nextdiroff32;
+			} else {
+				if (!ReadOK(tif, nextdiroff, sizeof(uint64)))
+					*nextdiroff = 0;
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabLong8(nextdiroff);
+			}
+		}
+	} else {
+		tmsize_t m;
+		tmsize_t off = (tmsize_t) tif->tif_diroff;
+		if ((uint64)off!=tif->tif_diroff)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Can not read TIFF directory count");
+			return(0);
+		}
+
+		/*
+		 * 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_flags&TIFF_BIGTIFF))
+		{
+			m=off+sizeof(uint16);
+			if ((m<off)||(m<(tmsize_t)sizeof(uint16))||(m>tif->tif_size)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					"Can not read TIFF directory count");
+				return 0;
+			} else {
+				_TIFFmemcpy(&dircount16, tif->tif_base + off,
+					    sizeof(uint16));
+			}
+			off += sizeof (uint16);
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabShort(&dircount16);
+			if (dircount16>4096)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Sanity check on directory count failed, this is probably not a valid IFD offset");
+				return 0;
+			}
+			dirsize = 12;
+		}
+		else
+		{
+			tmsize_t m;
+			uint64 dircount64;
+			m=off+sizeof(uint64);
+			if ((m<off)||(m<(tmsize_t)sizeof(uint64))||(m>tif->tif_size)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					"Can not read TIFF directory count");
+				return 0;
+			} else {
+				_TIFFmemcpy(&dircount64, tif->tif_base + off,
+					    sizeof(uint64));
+			}
+			off += sizeof (uint64);
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&dircount64);
+			if (dircount64>4096)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Sanity check on directory count failed, this is probably not a valid IFD offset");
+				return 0;
+			}
+			dircount16 = (uint16)dircount64;
+			dirsize = 20;
+		}
+		if (dircount16 == 0 )
+		{
+			TIFFErrorExt(tif->tif_clientdata, module,
+			             "Sanity check on directory count failed, zero tag directories not supported");
+			return 0;
+		}
+		origdir = _TIFFCheckMalloc(tif, dircount16,
+						dirsize,
+						"to read TIFF directory");
+		if (origdir == NULL)
+			return 0;
+		m=off+dircount16*dirsize;
+		if ((m<off)||(m<(tmsize_t)(dircount16*dirsize))||(m>tif->tif_size)) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+				     "Can not read TIFF directory");
+			_TIFFfree(origdir);
+			return 0;
+		} else {
+			_TIFFmemcpy(origdir, tif->tif_base + off,
+				    dircount16 * dirsize);
+		}
+		if (nextdiroff) {
+			off += dircount16 * dirsize;
+			if (!(tif->tif_flags&TIFF_BIGTIFF))
+			{
+				uint32 nextdiroff32;
+				m=off+sizeof(uint32);
+				if ((m<off)||(m<(tmsize_t)sizeof(uint32))||(m>tif->tif_size))
+					nextdiroff32 = 0;
+				else
+					_TIFFmemcpy(&nextdiroff32, tif->tif_base + off,
+						    sizeof (uint32));
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabLong(&nextdiroff32);
+				*nextdiroff = nextdiroff32;
+			}
+			else
+			{
+				m=off+sizeof(uint64);
+				if ((m<off)||(m<(tmsize_t)sizeof(uint64))||(m>tif->tif_size))
+					*nextdiroff = 0;
+				else
+					_TIFFmemcpy(nextdiroff, tif->tif_base + off,
+						    sizeof (uint64));
+				if (tif->tif_flags&TIFF_SWAB)
+					TIFFSwabLong8(nextdiroff);
+			}
+		}
+	}
+	dir = (TIFFDirEntry*)_TIFFCheckMalloc(tif, dircount16,
+						sizeof(TIFFDirEntry),
+						"to read TIFF directory");
+	if (dir==0)
+	{
+		_TIFFfree(origdir);
+		return 0;
+	}
+	ma=(uint8*)origdir;
+	mb=dir;
+	for (n=0; n<dircount16; n++)
+	{
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabShort((uint16*)ma);
+		mb->tdir_tag=*(uint16*)ma;
+		ma+=sizeof(uint16);
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabShort((uint16*)ma);
+		mb->tdir_type=*(uint16*)ma;
+		ma+=sizeof(uint16);
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong((uint32*)ma);
+			mb->tdir_count=(uint64)(*(uint32*)ma);
+			ma+=sizeof(uint32);
+			*(uint32*)(&mb->tdir_offset)=*(uint32*)ma;
+			ma+=sizeof(uint32);
+		}
+		else
+		{
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8((uint64*)ma);
+                        mb->tdir_count=TIFFReadUInt64(ma);
+			ma+=sizeof(uint64);
+			mb->tdir_offset.toff_long8=TIFFReadUInt64(ma);
+			ma+=sizeof(uint64);
+		}
+		mb++;
+	}
+	_TIFFfree(origdir);
+	*pdir = dir;
+	return dircount16;
+}
+
+/*
+ * Fetch a tag that is not handled by special case code.
+ */
+static int
+TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp, int recover)
+{
+	static const char module[] = "TIFFFetchNormalTag";
+	enum TIFFReadDirEntryErr err;
+	uint32 fii;
+	const TIFFField* fip = NULL;
+	TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
+        if( fii == FAILED_FII )
+        {
+            TIFFErrorExt(tif->tif_clientdata, "TIFFFetchNormalTag",
+                         "No definition found for tag %d",
+                         dp->tdir_tag);
+            return 0;
+        }
+	fip=tif->tif_fields[fii];
+	assert(fip != NULL); /* should not happen */
+	assert(fip->set_field_type!=TIFF_SETGET_OTHER);  /* if so, we shouldn't arrive here but deal with this in specialized code */
+	assert(fip->set_field_type!=TIFF_SETGET_INT);    /* if so, we shouldn't arrive here as this is only the case for pseudo-tags */
+	err=TIFFReadDirEntryErrOk;
+	switch (fip->set_field_type)
+	{
+		case TIFF_SETGET_UNDEFINED:
+			break;
+		case TIFF_SETGET_ASCII:
+			{
+				uint8* data;
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryByteArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					uint8* ma;
+					uint32 mb;
+					int n;
+					ma=data;
+					mb=0;
+					while (mb<(uint32)dp->tdir_count)
+					{
+						if (*ma==0)
+							break;
+						ma++;
+						mb++;
+					}
+					if (mb+1<(uint32)dp->tdir_count)
+						TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" contains null byte in value; value incorrectly truncated during reading due to implementation limitations",fip->field_name);
+					else if (mb+1>(uint32)dp->tdir_count)
+					{
+						uint8* o;
+						TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte",fip->field_name);
+						if ((uint32)dp->tdir_count+1!=dp->tdir_count+1)
+							o=NULL;
+						else
+							o=_TIFFmalloc((uint32)dp->tdir_count+1);
+						if (o==NULL)
+						{
+							if (data!=NULL)
+								_TIFFfree(data);
+							return(0);
+						}
+						_TIFFmemcpy(o,data,(uint32)dp->tdir_count);
+						o[(uint32)dp->tdir_count]=0;
+						if (data!=0)
+							_TIFFfree(data);
+						data=o;
+					}
+					n=TIFFSetField(tif,dp->tdir_tag,data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!n)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_UINT8:
+			{
+				uint8 data=0;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryByte(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_UINT16:
+			{
+				uint16 data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryShort(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_UINT32:
+			{
+				uint32 data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryLong(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_UINT64:
+			{
+				uint64 data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryLong8(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_FLOAT:
+			{
+				float data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryFloat(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_DOUBLE:
+			{
+				double data;
+				assert(fip->field_readcount==1);
+				assert(fip->field_passcount==0);
+				err=TIFFReadDirEntryDouble(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					if (!TIFFSetField(tif,dp->tdir_tag,data))
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_IFD8:
+			{
+				uint64 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* data;
+				assert(fip->field_readcount==2);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=2) {
+					TIFFWarningExt(tif->tif_clientdata,module,
+						       "incorrect count for field \"%s\", expected 2, got %d",
+						       fip->field_name,(int)dp->tdir_count);
+					return(0);
+				}
+				err=TIFFReadDirEntryShortArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,data[0],data[1]);
+					_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C0_UINT8:
+			{
+				uint8* data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=(uint64)fip->field_readcount) {
+					TIFFWarningExt(tif->tif_clientdata,module,
+						       "incorrect count for field \"%s\", expected %d, got %d",
+						       fip->field_name,(int) fip->field_readcount, (int)dp->tdir_count);
+					return 0;
+				}
+				else
+				{
+					err=TIFFReadDirEntryByteArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C0_UINT16:
+			{
+				uint16* data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=(uint64)fip->field_readcount)
+                                    /* corrupt file */;
+				else
+				{
+					err=TIFFReadDirEntryShortArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C0_UINT32:
+			{
+				uint32* data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=(uint64)fip->field_readcount)
+                                    /* corrupt file */;
+				else
+				{
+					err=TIFFReadDirEntryLongArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C0_FLOAT:
+			{
+				float* data;
+				assert(fip->field_readcount>=1);
+				assert(fip->field_passcount==0);
+				if (dp->tdir_count!=(uint64)fip->field_readcount)
+                                    /* corrupt file */;
+				else
+				{
+					err=TIFFReadDirEntryFloatArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_ASCII:
+			{
+				uint8* 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)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_UINT8:
+			{
+				uint8* 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)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_UINT16:
+			{
+				uint16* 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)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_UINT32:
+			{
+				uint32* 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)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_UINT64:
+			{
+				uint64* 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)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_FLOAT:
+			{
+				float* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntryFloatArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_DOUBLE:
+			{
+				double* data;
+				assert(fip->field_readcount==TIFF_VARIABLE);
+				assert(fip->field_passcount==1);
+				if (dp->tdir_count>0xFFFF)
+					err=TIFFReadDirEntryErrCount;
+				else
+				{
+					err=TIFFReadDirEntryDoubleArray(tif,dp,&data);
+					if (err==TIFFReadDirEntryErrOk)
+					{
+						int m;
+						m=TIFFSetField(tif,dp->tdir_tag,(uint16)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C16_IFD8:
+			{
+				uint64* 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)(dp->tdir_count),data);
+						if (data!=0)
+							_TIFFfree(data);
+						if (!m)
+							return(0);
+					}
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_ASCII:
+			{
+				uint8* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryByteArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_UINT8:
+			{
+				uint8* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryByteArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_SINT8:
+			{
+				int8* 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)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_UINT16:
+			{
+				uint16* 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)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_SINT16:
+			{
+				int16* 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)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_UINT32:
+			{
+				uint32* 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)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_SINT32:
+			{
+				int32* 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)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_UINT64:
+			{
+				uint64* 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)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_SINT64:
+			{
+				int64* 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)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_FLOAT:
+			{
+				float* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryFloatArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_DOUBLE:
+			{
+				double* data;
+				assert(fip->field_readcount==TIFF_VARIABLE2);
+				assert(fip->field_passcount==1);
+				err=TIFFReadDirEntryDoubleArray(tif,dp,&data);
+				if (err==TIFFReadDirEntryErrOk)
+				{
+					int m;
+					m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		case TIFF_SETGET_C32_IFD8:
+			{
+				uint64* 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)(dp->tdir_count),data);
+					if (data!=0)
+						_TIFFfree(data);
+					if (!m)
+						return(0);
+				}
+			}
+			break;
+		default:
+			assert(0);    /* we should never get here */
+			break;
+	}
+	if (err!=TIFFReadDirEntryErrOk)
+	{
+		TIFFReadDirEntryOutputErr(tif,err,module,fip->field_name,recover);
+		return(0);
+	}
+	return(1);
+}
+
+/*
+ * Fetch a set of offsets or lengths.
+ * While this routine says "strips", in fact it's also used for tiles.
+ */
+static int
+TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp)
+{
+	static const char module[] = "TIFFFetchStripThing";
+	enum TIFFReadDirEntryErr err;
+	uint64* data;
+	err=TIFFReadDirEntryLong8Array(tif,dir,&data);
+	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)nstrips)
+	{
+		uint64* resizeddata;
+		resizeddata=(uint64*)_TIFFCheckMalloc(tif,nstrips,sizeof(uint64),"for strip array");
+		if (resizeddata==0) {
+			_TIFFfree(data);
+			return(0);
+		}
+		if (dir->tdir_count<(uint64)nstrips)
+		{
+			_TIFFmemcpy(resizeddata,data,(uint32)dir->tdir_count*sizeof(uint64));
+			_TIFFmemset(resizeddata+(uint32)dir->tdir_count,0,(nstrips-(uint32)dir->tdir_count)*sizeof(uint64));
+		}
+		else
+			_TIFFmemcpy(resizeddata,data,nstrips*sizeof(uint64));
+		_TIFFfree(data);
+		data=resizeddata;
+	}
+	*lpp=data;
+	return(1);
+}
+
+/*
+ * Fetch and set the SubjectDistance EXIF tag.
+ */
+static int
+TIFFFetchSubjectDistance(TIFF* tif, TIFFDirEntry* dir)
+{
+	static const char module[] = "TIFFFetchSubjectDistance";
+	enum TIFFReadDirEntryErr err;
+	UInt64Aligned_t m;
+    m.l=0;
+	assert(sizeof(double)==8);
+	assert(sizeof(uint64)==8);
+	assert(sizeof(uint32)==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 offset;
+			offset=*(uint32*)(&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)
+			/*
+			 * 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);
+	}
+}
+
+/*
+ * 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 bytecount;
+	uint64 offset;
+	uint32 rowblock;
+	uint64 rowblockbytes;
+	uint64 stripbytes;
+	uint32 strip;
+	uint64 nstrips64;
+	uint32 nstrips32;
+	uint32 rowsperstrip;
+	uint64* newcounts;
+	uint64* newoffsets;
+
+	bytecount = td->td_stripbytecount[0];
+	offset = td->td_stripoffset[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 rowblocksperstrip;
+		rowblocksperstrip = (uint32) (STRIP_SIZE_DEFAULT / rowblockbytes);
+		rowsperstrip = rowblocksperstrip * rowblock;
+		stripbytes = rowblocksperstrip * rowblockbytes;
+	}
+	else
+	    return;
+
+	/*
+	 * never increase the number of strips in an image
+	 */
+	if (rowsperstrip >= td->td_rowsperstrip)
+		return;
+	nstrips64 = TIFFhowmany_64(bytecount, stripbytes);
+	if ((nstrips64==0)||(nstrips64>0xFFFFFFFF)) /* something is wonky, do nothing. */
+	    return;
+	nstrips32 = (uint32)nstrips64;
+
+	newcounts = (uint64*) _TIFFCheckMalloc(tif, nstrips32, sizeof (uint64),
+				"for chopped \"StripByteCounts\" array");
+	newoffsets = (uint64*) _TIFFCheckMalloc(tif, nstrips32, sizeof (uint64),
+				"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 < nstrips32; strip++) {
+		if (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 = nstrips32;
+	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;
+}
+
+int _TIFFFillStriles( TIFF *tif )
+{
+#if defined(DEFER_STRILE_LOAD)
+        register TIFFDirectory *td = &tif->tif_dir;
+        int return_value = 1;
+
+        if( td->td_stripoffset != NULL )
+                return 1;
+
+        if( td->td_stripoffset_entry.tdir_count == 0 )
+                return 0;
+
+        if (!TIFFFetchStripThing(tif,&(td->td_stripoffset_entry),
+                                 td->td_nstrips,&td->td_stripoffset))
+        {
+                return_value = 0;
+        }
+
+        if (!TIFFFetchStripThing(tif,&(td->td_stripbytecount_entry),
+                                 td->td_nstrips,&td->td_stripbytecount))
+        {
+                return_value = 0;
+        }
+
+        _TIFFmemset( &(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
+        _TIFFmemset( &(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));
+
+	if (tif->tif_dir.td_nstrips > 1 && return_value == 1 ) {
+		uint32 strip;
+
+		tif->tif_dir.td_stripbytecountsorted = 1;
+		for (strip = 1; strip < tif->tif_dir.td_nstrips; strip++) {
+			if (tif->tif_dir.td_stripoffset[strip - 1] >
+			    tif->tif_dir.td_stripoffset[strip]) {
+				tif->tif_dir.td_stripbytecountsorted = 0;
+				break;
+			}
+		}
+	}
+
+        return return_value;
+#else /* !defined(DEFER_STRILE_LOAD) */
+        (void) tif;
+        return 1;
+#endif 
+}
+
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_dirwrite.c b/third_party/libtiff/tif_dirwrite.c
new file mode 100644
index 0000000..a0fd8dc
--- /dev/null
+++ b/third_party/libtiff/tif_dirwrite.c
@@ -0,0 +1,2911 @@
+/* $Id: tif_dirwrite.c,v 1.78 2015-05-31 00:38:46 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
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Write Support Routines.
+ */
+#include "tiffiop.h"
+
+#ifdef HAVE_IEEEFP
+#define TIFFCvtNativeToIEEEFloat(tif, n, fp)
+#define TIFFCvtNativeToIEEEDouble(tif, n, dp)
+#else
+extern void TIFFCvtNativeToIEEEFloat(TIFF* tif, uint32 n, float* fp);
+extern void TIFFCvtNativeToIEEEDouble(TIFF* tif, uint32 n, double* dp);
+#endif
+
+static int TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff);
+
+static int TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value);
+#if 0
+static int TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+#endif
+
+static int TIFFWriteDirectoryTagAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value);
+static int TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value);
+#endif
+static int TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
+#if 0
+static int TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value);
+#endif
+#ifdef notdef
+static int TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value);
+#endif
+static int TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value);
+#if 0
+static int TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value);
+#endif
+static int TIFFWriteDirectoryTagShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value);
+static int TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value);
+static int TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value);
+#endif
+static int TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value);
+#if 0
+static int TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value);
+#endif
+static int TIFFWriteDirectoryTagLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
+static int TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
+#if 0
+static int TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
+#endif
+#ifdef notdef
+static int TIFFWriteDirectoryTagSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value);
+#endif
+static int TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value);
+#if 0
+static int TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value);
+#endif
+#ifdef notdef
+static int TIFFWriteDirectoryTagLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value);
+#endif
+static int TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value);
+#endif
+static int TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value);
+static int TIFFWriteDirectoryTagRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+static int TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+static int TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value);
+#endif
+static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+#if 0
+static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value);
+#endif
+#ifdef notdef
+static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+#endif
+static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value);
+#if 0
+static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+#endif
+static int TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+#endif
+static int TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
+static int TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+static int TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+#endif
+static int TIFFWriteDirectoryTagColormap(TIFF* tif, uint32* ndir, TIFFDirEntry* dir);
+static int TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32* ndir, TIFFDirEntry* dir);
+static int TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32* ndir, TIFFDirEntry* dir);
+
+static int TIFFWriteDirectoryTagCheckedAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value);
+static int TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value);
+static int TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value);
+static int TIFFWriteDirectoryTagCheckedShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value);
+static int TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value);
+static int TIFFWriteDirectoryTagCheckedLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value);
+#endif
+static int TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value);
+static int TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+static int TIFFWriteDirectoryTagCheckedRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+static int TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value);
+#endif
+static int TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value);
+#ifdef notdef
+static int TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value);
+#endif
+static int TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value);
+static int TIFFWriteDirectoryTagCheckedIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value);
+static int TIFFWriteDirectoryTagCheckedIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value);
+
+static int TIFFWriteDirectoryTagData(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 datatype, uint32 count, uint32 datalength, void* data);
+
+static int TIFFLinkDirectory(TIFF*);
+
+/*
+ * Write the contents of the current directory
+ * to the specified file.  This routine doesn't
+ * handle overwriting a directory with auxiliary
+ * storage that's been changed.
+ */
+int
+TIFFWriteDirectory(TIFF* tif)
+{
+	return TIFFWriteDirectorySec(tif,TRUE,TRUE,NULL);
+}
+
+/*
+ * Similar to TIFFWriteDirectory(), writes the directory out
+ * but leaves all data structures in memory so that it can be
+ * written again.  This will make a partially written TIFF file
+ * readable before it is successfully completed/closed.
+ */
+int
+TIFFCheckpointDirectory(TIFF* tif)
+{
+	int rc;
+	/* Setup the strips arrays, if they haven't already been. */
+	if (tif->tif_dir.td_stripoffset == NULL)
+	    (void) TIFFSetupStrips(tif);
+	rc = TIFFWriteDirectorySec(tif,TRUE,FALSE,NULL);
+	(void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END));
+	return rc;
+}
+
+int
+TIFFWriteCustomDirectory(TIFF* tif, uint64* pdiroff)
+{
+	return TIFFWriteDirectorySec(tif,FALSE,FALSE,pdiroff);
+}
+
+/*
+ * Similar to TIFFWriteDirectory(), but if the directory has already
+ * been written once, it is relocated to the end of the file, in case it
+ * has changed in size.  Note that this will result in the loss of the
+ * previously used directory space. 
+ */ 
+int
+TIFFRewriteDirectory( TIFF *tif )
+{
+	static const char module[] = "TIFFRewriteDirectory";
+
+	/* We don't need to do anything special if it hasn't been written. */
+	if( tif->tif_diroff == 0 )
+		return TIFFWriteDirectory( tif );
+
+	/*
+	 * Find and zero the pointer to this directory, so that TIFFLinkDirectory
+	 * will cause it to be added after this directories current pre-link.
+	 */
+
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		if (tif->tif_header.classic.tiff_diroff == tif->tif_diroff)
+		{
+			tif->tif_header.classic.tiff_diroff = 0;
+			tif->tif_diroff = 0;
+
+			TIFFSeekFile(tif,4,SEEK_SET);
+			if (!WriteOK(tif, &(tif->tif_header.classic.tiff_diroff),4))
+			{
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+				    "Error updating TIFF header");
+				return (0);
+			}
+		}
+		else
+		{
+			uint32 nextdir;
+			nextdir = tif->tif_header.classic.tiff_diroff;
+			while(1) {
+				uint16 dircount;
+				uint32 nextnextdir;
+
+				if (!SeekOK(tif, nextdir) ||
+				    !ReadOK(tif, &dircount, 2)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory count");
+					return (0);
+				}
+				if (tif->tif_flags & TIFF_SWAB)
+					TIFFSwabShort(&dircount);
+				(void) TIFFSeekFile(tif,
+				    nextdir+2+dircount*12, SEEK_SET);
+				if (!ReadOK(tif, &nextnextdir, 4)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory link");
+					return (0);
+				}
+				if (tif->tif_flags & TIFF_SWAB)
+					TIFFSwabLong(&nextnextdir);
+				if (nextnextdir==tif->tif_diroff)
+				{
+					uint32 m;
+					m=0;
+					(void) TIFFSeekFile(tif,
+					    nextdir+2+dircount*12, SEEK_SET);
+					if (!WriteOK(tif, &m, 4)) {
+						TIFFErrorExt(tif->tif_clientdata, module,
+						     "Error writing directory link");
+						return (0);
+					}
+					tif->tif_diroff=0;
+					break;
+				}
+				nextdir=nextnextdir;
+			}
+		}
+	}
+	else
+	{
+		if (tif->tif_header.big.tiff_diroff == tif->tif_diroff)
+		{
+			tif->tif_header.big.tiff_diroff = 0;
+			tif->tif_diroff = 0;
+
+			TIFFSeekFile(tif,8,SEEK_SET);
+			if (!WriteOK(tif, &(tif->tif_header.big.tiff_diroff),8))
+			{
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+				    "Error updating TIFF header");
+				return (0);
+			}
+		}
+		else
+		{
+			uint64 nextdir;
+			nextdir = tif->tif_header.big.tiff_diroff;
+			while(1) {
+				uint64 dircount64;
+				uint16 dircount;
+				uint64 nextnextdir;
+
+				if (!SeekOK(tif, nextdir) ||
+				    !ReadOK(tif, &dircount64, 8)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory count");
+					return (0);
+				}
+				if (tif->tif_flags & TIFF_SWAB)
+					TIFFSwabLong8(&dircount64);
+				if (dircount64>0xFFFF)
+				{
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Sanity check on tag count failed, likely corrupt TIFF");
+					return (0);
+				}
+				dircount=(uint16)dircount64;
+				(void) TIFFSeekFile(tif,
+				    nextdir+8+dircount*20, SEEK_SET);
+				if (!ReadOK(tif, &nextnextdir, 8)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory link");
+					return (0);
+				}
+				if (tif->tif_flags & TIFF_SWAB)
+					TIFFSwabLong8(&nextnextdir);
+				if (nextnextdir==tif->tif_diroff)
+				{
+					uint64 m;
+					m=0;
+					(void) TIFFSeekFile(tif,
+					    nextdir+8+dircount*20, SEEK_SET);
+					if (!WriteOK(tif, &m, 8)) {
+						TIFFErrorExt(tif->tif_clientdata, module,
+						     "Error writing directory link");
+						return (0);
+					}
+					tif->tif_diroff=0;
+					break;
+				}
+				nextdir=nextnextdir;
+			}
+		}
+	}
+
+	/*
+	 * Now use TIFFWriteDirectory() normally.
+	 */
+
+	return TIFFWriteDirectory( tif );
+}
+
+static int
+TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff)
+{
+	static const char module[] = "TIFFWriteDirectorySec";
+	uint32 ndir;
+	TIFFDirEntry* dir;
+	uint32 dirsize;
+	void* dirmem;
+	uint32 m;
+	if (tif->tif_mode == O_RDONLY)
+		return (1);
+
+        _TIFFFillStriles( tif );
+        
+	/*
+	 * Clear write state so that subsequent images with
+	 * different characteristics get the right buffers
+	 * setup for them.
+	 */
+	if (imagedone)
+	{
+		if (tif->tif_flags & TIFF_POSTENCODE)
+		{
+			tif->tif_flags &= ~TIFF_POSTENCODE;
+			if (!(*tif->tif_postencode)(tif))
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,
+				    "Error post-encoding before directory write");
+				return (0);
+			}
+		}
+		(*tif->tif_close)(tif);       /* shutdown encoder */
+		/*
+		 * Flush any data that might have been written
+		 * by the compression close+cleanup routines.  But
+                 * be careful not to write stuff if we didn't add data
+                 * in the previous steps as the "rawcc" data may well be
+                 * a previously read tile/strip in mixed read/write mode.
+		 */
+		if (tif->tif_rawcc > 0 
+		    && (tif->tif_flags & TIFF_BEENWRITING) != 0 )
+		{
+		    if( !TIFFFlushData1(tif) )
+                    {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Error flushing data before directory write");
+			return (0);
+                    }
+		}
+		if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
+		{
+			_TIFFfree(tif->tif_rawdata);
+			tif->tif_rawdata = NULL;
+			tif->tif_rawcc = 0;
+			tif->tif_rawdatasize = 0;
+                        tif->tif_rawdataoff = 0;
+                        tif->tif_rawdataloaded = 0;
+		}
+		tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP);
+	}
+	dir=NULL;
+	dirmem=NULL;
+	dirsize=0;
+	while (1)
+	{
+		ndir=0;
+		if (isimage)
+		{
+			if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS))
+			{
+				if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_IMAGEWIDTH,tif->tif_dir.td_imagewidth))
+					goto bad;
+				if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_IMAGELENGTH,tif->tif_dir.td_imagelength))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS))
+			{
+				if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_TILEWIDTH,tif->tif_dir.td_tilewidth))
+					goto bad;
+				if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_TILELENGTH,tif->tif_dir.td_tilelength))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_RESOLUTION))
+			{
+				if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_XRESOLUTION,tif->tif_dir.td_xresolution))
+					goto bad;
+				if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_YRESOLUTION,tif->tif_dir.td_yresolution))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_POSITION))
+			{
+				if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_XPOSITION,tif->tif_dir.td_xposition))
+					goto bad;
+				if (!TIFFWriteDirectoryTagRational(tif,&ndir,dir,TIFFTAG_YPOSITION,tif->tif_dir.td_yposition))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_SUBFILETYPE))
+			{
+				if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_SUBFILETYPE,tif->tif_dir.td_subfiletype))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE))
+			{
+				if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_BITSPERSAMPLE,tif->tif_dir.td_bitspersample))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_COMPRESSION))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_COMPRESSION,tif->tif_dir.td_compression))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_PHOTOMETRIC,tif->tif_dir.td_photometric))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_THRESHHOLDING))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_THRESHHOLDING,tif->tif_dir.td_threshholding))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_FILLORDER))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_FILLORDER,tif->tif_dir.td_fillorder))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_ORIENTATION))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_ORIENTATION,tif->tif_dir.td_orientation))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_SAMPLESPERPIXEL,tif->tif_dir.td_samplesperpixel))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP))
+			{
+				if (!TIFFWriteDirectoryTagShortLong(tif,&ndir,dir,TIFFTAG_ROWSPERSTRIP,tif->tif_dir.td_rowsperstrip))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE))
+			{
+				if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_MINSAMPLEVALUE,tif->tif_dir.td_minsamplevalue))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE))
+			{
+				if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_MAXSAMPLEVALUE,tif->tif_dir.td_maxsamplevalue))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_PLANARCONFIG))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_PLANARCONFIG,tif->tif_dir.td_planarconfig))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_RESOLUTIONUNIT,tif->tif_dir.td_resolutionunit))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_PAGENUMBER))
+			{
+				if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_PAGENUMBER,2,&tif->tif_dir.td_pagenumber[0]))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_STRIPBYTECOUNTS))
+			{
+				if (!isTiled(tif))
+				{
+					if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount))
+						goto bad;
+				}
+				else
+				{
+					if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEBYTECOUNTS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripbytecount))
+						goto bad;
+				}
+			}
+			if (TIFFFieldSet(tif,FIELD_STRIPOFFSETS))
+			{
+				if (!isTiled(tif))
+				{
+					if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_STRIPOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset))
+						goto bad;
+				}
+				else
+				{
+					if (!TIFFWriteDirectoryTagLongLong8Array(tif,&ndir,dir,TIFFTAG_TILEOFFSETS,tif->tif_dir.td_nstrips,tif->tif_dir.td_stripoffset))
+						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 na;
+					uint16* nb;
+					TIFFGetFieldDefaulted(tif,TIFFTAG_EXTRASAMPLES,&na,&nb);
+					if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_EXTRASAMPLES,na,nb))
+						goto bad;
+				}
+			}
+			if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT))
+			{
+				if (!TIFFWriteDirectoryTagShortPerSample(tif,&ndir,dir,TIFFTAG_SAMPLEFORMAT,tif->tif_dir.td_sampleformat))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE))
+			{
+				if (!TIFFWriteDirectoryTagSampleformatArray(tif,&ndir,dir,TIFFTAG_SMINSAMPLEVALUE,tif->tif_dir.td_samplesperpixel,tif->tif_dir.td_sminsamplevalue))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE))
+			{
+				if (!TIFFWriteDirectoryTagSampleformatArray(tif,&ndir,dir,TIFFTAG_SMAXSAMPLEVALUE,tif->tif_dir.td_samplesperpixel,tif->tif_dir.td_smaxsamplevalue))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH))
+			{
+				if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_IMAGEDEPTH,tif->tif_dir.td_imagedepth))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_TILEDEPTH))
+			{
+				if (!TIFFWriteDirectoryTagLong(tif,&ndir,dir,TIFFTAG_TILEDEPTH,tif->tif_dir.td_tiledepth))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS))
+			{
+				if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_HALFTONEHINTS,2,&tif->tif_dir.td_halftonehints[0]))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING))
+			{
+				if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,TIFFTAG_YCBCRSUBSAMPLING,2,&tif->tif_dir.td_ycbcrsubsampling[0]))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING))
+			{
+				if (!TIFFWriteDirectoryTagShort(tif,&ndir,dir,TIFFTAG_YCBCRPOSITIONING,tif->tif_dir.td_ycbcrpositioning))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_REFBLACKWHITE))
+			{
+				if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,TIFFTAG_REFERENCEBLACKWHITE,6,tif->tif_dir.td_refblackwhite))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION))
+			{
+				if (!TIFFWriteDirectoryTagTransferfunction(tif,&ndir,dir))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_INKNAMES))
+			{
+				if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,TIFFTAG_INKNAMES,tif->tif_dir.td_inknameslen,tif->tif_dir.td_inknames))
+					goto bad;
+			}
+			if (TIFFFieldSet(tif,FIELD_SUBIFD))
+			{
+				if (!TIFFWriteDirectoryTagSubifd(tif,&ndir,dir))
+					goto bad;
+			}
+			{
+				uint32 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 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)(strlen(pb));
+									if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,o->field_tag,pa,pb))
+										goto bad;
+								}
+								break;
+							case TIFF_SETGET_UINT16:
+								{
+									uint16 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,o->field_tag,p))
+										goto bad;
+								}
+								break;
+							case TIFF_SETGET_UINT32:
+								{
+									uint32 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,o->field_tag,p))
+										goto bad;
+								}
+								break;
+							case TIFF_SETGET_C32_UINT8:
+								{
+									uint32 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,o->field_tag,pa,pb))
+										goto bad;
+								}
+								break;
+							default:
+								assert(0);   /* we should never get here */
+								break;
+						}
+					}
+				}
+			}
+		}
+		for (m=0; m<(uint32)(tif->tif_dir.td_customValueCount); m++)
+		{
+			switch (tif->tif_dir.td_customValues[m].info->field_type)
+			{
+				case TIFF_ASCII:
+					if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_UNDEFINED:
+					if (!TIFFWriteDirectoryTagUndefinedArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_BYTE:
+					if (!TIFFWriteDirectoryTagByteArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SBYTE:
+					if (!TIFFWriteDirectoryTagSbyteArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SHORT:
+					if (!TIFFWriteDirectoryTagShortArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SSHORT:
+					if (!TIFFWriteDirectoryTagSshortArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_LONG:
+					if (!TIFFWriteDirectoryTagLongArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SLONG:
+					if (!TIFFWriteDirectoryTagSlongArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_LONG8:
+					if (!TIFFWriteDirectoryTagLong8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SLONG8:
+					if (!TIFFWriteDirectoryTagSlong8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_RATIONAL:
+					if (!TIFFWriteDirectoryTagRationalArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_SRATIONAL:
+					if (!TIFFWriteDirectoryTagSrationalArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_FLOAT:
+					if (!TIFFWriteDirectoryTagFloatArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_DOUBLE:
+					if (!TIFFWriteDirectoryTagDoubleArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_IFD:
+					if (!TIFFWriteDirectoryTagIfdArray(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				case TIFF_IFD8:
+					if (!TIFFWriteDirectoryTagIfdIfd8Array(tif,&ndir,dir,tif->tif_dir.td_customValues[m].info->field_tag,tif->tif_dir.td_customValues[m].count,tif->tif_dir.td_customValues[m].value))
+						goto bad;
+					break;
+				default:
+					assert(0);   /* we should never get here */
+					break;
+			}
+		}
+		if (dir!=NULL)
+			break;
+		dir=_TIFFmalloc(ndir*sizeof(TIFFDirEntry));
+		if (dir==NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+			goto bad;
+		}
+		if (isimage)
+		{
+			if ((tif->tif_diroff==0)&&(!TIFFLinkDirectory(tif)))
+				goto bad;
+		}
+		else
+			tif->tif_diroff=(TIFFSeekFile(tif,0,SEEK_END)+1)&(~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)tif->tif_dataoff;
+		if ((tif->tif_dataoff<tif->tif_diroff)||(tif->tif_dataoff<(uint64)dirsize))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Maximum TIFF file size exceeded");
+			goto bad;
+		}
+		if (tif->tif_dataoff&1)
+			tif->tif_dataoff++;
+		if (isimage)
+			tif->tif_curdir++;
+	}
+	if (isimage)
+	{
+		if (TIFFFieldSet(tif,FIELD_SUBIFD)&&(tif->tif_subifdoff==0))
+		{
+			uint32 na;
+			TIFFDirEntry* nb;
+			for (na=0, nb=dir; ; na++, nb++)
+			{
+				assert(na<ndir);
+				if (nb->tdir_tag==TIFFTAG_SUBIFD)
+					break;
+			}
+			if (!(tif->tif_flags&TIFF_BIGTIFF))
+				tif->tif_subifdoff=tif->tif_diroff+2+na*12+8;
+			else
+				tif->tif_subifdoff=tif->tif_diroff+8+na*20+12;
+		}
+	}
+	dirmem=_TIFFmalloc(dirsize);
+	if (dirmem==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		goto bad;
+	}
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		uint8* n;
+		uint32 nTmp;
+		TIFFDirEntry* o;
+		n=dirmem;
+		*(uint16*)n=ndir;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabShort((uint16*)n);
+		n+=2;
+		o=dir;
+		for (m=0; m<ndir; m++)
+		{
+			*(uint16*)n=o->tdir_tag;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabShort((uint16*)n);
+			n+=2;
+			*(uint16*)n=o->tdir_type;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabShort((uint16*)n);
+			n+=2;
+			nTmp = (uint32)o->tdir_count;
+			_TIFFmemcpy(n,&nTmp,4);
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong((uint32*)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)tif->tif_nextdiroff;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabLong(&nTmp);
+		_TIFFmemcpy(n,&nTmp,4);
+	}
+	else
+	{
+		uint8* n;
+		TIFFDirEntry* o;
+		n=dirmem;
+		*(uint64*)n=ndir;
+		if (tif->tif_flags&TIFF_SWAB)
+			TIFFSwabLong8((uint64*)n);
+		n+=8;
+		o=dir;
+		for (m=0; m<ndir; m++)
+		{
+			*(uint16*)n=o->tdir_tag;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabShort((uint16*)n);
+			n+=2;
+			*(uint16*)n=o->tdir_type;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabShort((uint16*)n);
+			n+=2;
+			_TIFFmemcpy(n,&o->tdir_count,8);
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8((uint64*)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*)n);
+	}
+	_TIFFfree(dir);
+	dir=NULL;
+	if (!SeekOK(tif,tif->tif_diroff))
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory");
+		goto bad;
+	}
+	if (!WriteOK(tif,dirmem,(tmsize_t)dirsize))
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"IO error writing directory");
+		goto bad;
+	}
+	_TIFFfree(dirmem);
+	if (imagedone)
+	{
+		TIFFFreeDirectory(tif);
+		tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+		tif->tif_flags &= ~TIFF_DIRTYSTRIP;
+		(*tif->tif_cleanup)(tif);
+		/*
+		* Reset directory-related state for subsequent
+		* directories.
+		*/
+		TIFFCreateDirectory(tif);
+	}
+	return(1);
+bad:
+	if (dir!=NULL)
+		_TIFFfree(dir);
+	if (dirmem!=NULL)
+		_TIFFfree(dirmem);
+	return(0);
+}
+
+static int
+TIFFWriteDirectoryTagSampleformatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagSampleformatArray";
+	void* conv;
+	uint32 i;
+	int ok;
+	conv = _TIFFmalloc(count*sizeof(double));
+	if (conv == NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Out of memory");
+		return (0);
+	}
+
+	switch (tif->tif_dir.td_sampleformat)
+	{
+		case SAMPLEFORMAT_IEEEFP:
+			if (tif->tif_dir.td_bitspersample<=32)
+			{
+				for (i = 0; i < count; ++i)
+					((float*)conv)[i] = (float)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*)conv)[i] = (int8)value[i];
+				ok = TIFFWriteDirectoryTagSbyteArray(tif,ndir,dir,tag,count,(int8*)conv);
+			}
+			else if (tif->tif_dir.td_bitspersample<=16)
+			{
+				for (i = 0; i < count; ++i)
+					((int16*)conv)[i] = (int16)value[i];
+				ok = TIFFWriteDirectoryTagSshortArray(tif,ndir,dir,tag,count,(int16*)conv);
+			}
+			else
+			{
+				for (i = 0; i < count; ++i)
+					((int32*)conv)[i] = (int32)value[i];
+				ok = TIFFWriteDirectoryTagSlongArray(tif,ndir,dir,tag,count,(int32*)conv);
+			}
+			break;
+		case SAMPLEFORMAT_UINT:
+			if (tif->tif_dir.td_bitspersample<=8)
+			{
+				for (i = 0; i < count; ++i)
+					((uint8*)conv)[i] = (uint8)value[i];
+				ok = TIFFWriteDirectoryTagByteArray(tif,ndir,dir,tag,count,(uint8*)conv);
+			}
+			else if (tif->tif_dir.td_bitspersample<=16)
+			{
+				for (i = 0; i < count; ++i)
+					((uint16*)conv)[i] = (uint16)value[i];
+				ok = TIFFWriteDirectoryTagShortArray(tif,ndir,dir,tag,count,(uint16*)conv);
+			}
+			else
+			{
+				for (i = 0; i < count; ++i)
+					((uint32*)conv)[i] = (uint32)value[i];
+				ok = TIFFWriteDirectoryTagLongArray(tif,ndir,dir,tag,count,(uint32*)conv);
+			}
+			break;
+		default:
+			ok = 0;
+	}
+
+	_TIFFfree(conv);
+	return (ok);
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagSampleformatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	switch (tif->tif_dir.td_sampleformat)
+	{
+		case SAMPLEFORMAT_IEEEFP:
+			if (tif->tif_dir.td_bitspersample<=32)
+				return(TIFFWriteDirectoryTagFloatPerSample(tif,ndir,dir,tag,(float)value));
+			else
+				return(TIFFWriteDirectoryTagDoublePerSample(tif,ndir,dir,tag,value));
+		case SAMPLEFORMAT_INT:
+			if (tif->tif_dir.td_bitspersample<=8)
+				return(TIFFWriteDirectoryTagSbytePerSample(tif,ndir,dir,tag,(int8)value));
+			else if (tif->tif_dir.td_bitspersample<=16)
+				return(TIFFWriteDirectoryTagSshortPerSample(tif,ndir,dir,tag,(int16)value));
+			else
+				return(TIFFWriteDirectoryTagSlongPerSample(tif,ndir,dir,tag,(int32)value));
+		case SAMPLEFORMAT_UINT:
+			if (tif->tif_dir.td_bitspersample<=8)
+				return(TIFFWriteDirectoryTagBytePerSample(tif,ndir,dir,tag,(uint8)value));
+			else if (tif->tif_dir.td_bitspersample<=16)
+				return(TIFFWriteDirectoryTagShortPerSample(tif,ndir,dir,tag,(uint16)value));
+			else
+				return(TIFFWriteDirectoryTagLongPerSample(tif,ndir,dir,tag,(uint32)value));
+		default:
+			return(1);
+	}
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagAscii(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedAscii(tif,ndir,dir,tag,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedUndefinedArray(tif,ndir,dir,tag,count,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedByte(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagBytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagBytePerSample";
+	uint8* m;
+	uint8* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint8));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedByteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSbyte(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagSbytePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagSbytePerSample";
+	int8* m;
+	int8* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int8));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedSbyteArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,value));
+}
+
+static int
+TIFFWriteDirectoryTagShortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagShortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagShortPerSample";
+	uint16* m;
+	uint16* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint16));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,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);
+	_TIFFfree(m);
+	return(o);
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSshort(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagSshortPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagSshortPerSample";
+	int16* m;
+	int16* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int16));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedSshortArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value));
+}
+
+static int
+TIFFWriteDirectoryTagLongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagLongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagLongPerSample";
+	uint32* m;
+	uint32* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(uint32));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSlong(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int
+TIFFWriteDirectoryTagSlongPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagSlongPerSample";
+	int32* m;
+	int32* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(int32));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedSlongArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedLong8(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSlong8(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSlong8Array(tif,ndir,dir,tag,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedRational(tif,ndir,dir,tag,value));
+}
+
+static int
+TIFFWriteDirectoryTagRationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedRationalArray(tif,ndir,dir,tag,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedSrationalArray(tif,ndir,dir,tag,count,value));
+}
+
+#ifdef notdef
+static int TIFFWriteDirectoryTagFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedFloat(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int TIFFWriteDirectoryTagFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int TIFFWriteDirectoryTagFloatPerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagFloatPerSample";
+	float* m;
+	float* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(float));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedFloatArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+#ifdef notdef
+static int TIFFWriteDirectoryTagDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedDouble(tif,ndir,dir,tag,value));
+}
+#endif
+
+static int TIFFWriteDirectoryTagDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, double* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,count,value));
+}
+
+#if 0
+static int TIFFWriteDirectoryTagDoublePerSample(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagDoublePerSample";
+	double* m;
+	double* na;
+	uint16 nb;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=_TIFFmalloc(tif->tif_dir.td_samplesperpixel*sizeof(double));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=m, nb=0; nb<tif->tif_dir.td_samplesperpixel; na++, nb++)
+		*na=value;
+	o=TIFFWriteDirectoryTagCheckedDoubleArray(tif,ndir,dir,tag,tif->tif_dir.td_samplesperpixel,m);
+	_TIFFfree(m);
+	return(o);
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagIfdArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	return(TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,tag,count,value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
+{
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	if (value<=0xFFFF)
+		return(TIFFWriteDirectoryTagCheckedShort(tif,ndir,dir,tag,(uint16)value));
+	else
+		return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value));
+}
+
+/************************************************************************/
+/*                TIFFWriteDirectoryTagLongLong8Array()                 */
+/*                                                                      */
+/*      Write out LONG8 array as LONG8 for BigTIFF or LONG for          */
+/*      Classic TIFF with some checking.                                */
+/************************************************************************/
+
+static int
+TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+    static const char module[] = "TIFFWriteDirectoryTagLongLong8Array";
+    uint64* ma;
+    uint32 mb;
+    uint32* p;
+    uint32* q;
+    int o;
+
+    /* is this just a counting pass? */
+    if (dir==NULL)
+    {
+        (*ndir)++;
+        return(1);
+    }
+
+    /* We always write LONG8 for BigTIFF, no checking needed. */
+    if( tif->tif_flags&TIFF_BIGTIFF )
+        return TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,
+                                                      tag,count,value);
+
+    /*
+    ** For classic tiff we want to verify everything is in range for LONG
+    ** and convert to long format.
+    */
+
+    p = _TIFFmalloc(count*sizeof(uint32));
+    if (p==NULL)
+    {
+        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+        return(0);
+    }
+
+    for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++)
+    {
+        if (*ma>0xFFFFFFFF)
+        {
+            TIFFErrorExt(tif->tif_clientdata,module,
+                         "Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file.");
+            _TIFFfree(p);
+            return(0);
+        }
+        *q= (uint32)(*ma);
+    }
+
+    o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p);
+    _TIFFfree(p);
+
+    return(o);
+}
+
+/************************************************************************/
+/*                 TIFFWriteDirectoryTagIfdIfd8Array()                  */
+/*                                                                      */
+/*      Write either IFD8 or IFD array depending on file type.          */
+/************************************************************************/
+
+static int
+TIFFWriteDirectoryTagIfdIfd8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+    static const char module[] = "TIFFWriteDirectoryTagIfdIfd8Array";
+    uint64* ma;
+    uint32 mb;
+    uint32* p;
+    uint32* q;
+    int o;
+
+    /* is this just a counting pass? */
+    if (dir==NULL)
+    {
+        (*ndir)++;
+        return(1);
+    }
+
+    /* We always write IFD8 for BigTIFF, no checking needed. */
+    if( tif->tif_flags&TIFF_BIGTIFF )
+        return TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,
+                                                     tag,count,value);
+
+    /*
+    ** For classic tiff we want to verify everything is in range for IFD
+    ** and convert to long format.
+    */
+
+    p = _TIFFmalloc(count*sizeof(uint32));
+    if (p==NULL)
+    {
+        TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+        return(0);
+    }
+
+    for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++)
+    {
+        if (*ma>0xFFFFFFFF)
+        {
+            TIFFErrorExt(tif->tif_clientdata,module,
+                         "Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file.");
+            _TIFFfree(p);
+            return(0);
+        }
+        *q= (uint32)(*ma);
+    }
+
+    o=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,tag,count,p);
+    _TIFFfree(p);
+
+    return(o);
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagShortLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagShortLongLong8Array";
+	uint64* ma;
+	uint32 mb;
+	uint8 n;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	n=0;
+	for (ma=value, mb=0; mb<count; ma++, mb++)
+	{
+		if ((n==0)&&(*ma>0xFFFF))
+			n=1;
+		if ((n==1)&&(*ma>0xFFFFFFFF))
+		{
+			n=2;
+			break;
+		}
+	}
+	if (n==0)
+	{
+		uint16* p;
+		uint16* q;
+		p=_TIFFmalloc(count*sizeof(uint16));
+		if (p==NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+			return(0);
+		}
+		for (ma=value, mb=0, q=p; mb<count; ma++, mb++, q++)
+			*q=(uint16)(*ma);
+		o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,p);
+		_TIFFfree(p);
+	}
+	else if (n==1)
+	{
+		uint32* p;
+		uint32* q;
+		p=_TIFFmalloc(count*sizeof(uint32));
+		if (p==NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+			return(0);
+		}
+		for (ma=value, mb=0, q=p; mb<count; ma++, mb++, q++)
+			*q=(uint32)(*ma);
+		o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p);
+		_TIFFfree(p);
+	}
+	else
+	{
+		assert(n==2);
+		o=TIFFWriteDirectoryTagCheckedLong8Array(tif,ndir,dir,tag,count,value);
+	}
+	return(o);
+}
+#endif
+static int
+TIFFWriteDirectoryTagColormap(TIFF* tif, uint32* ndir, TIFFDirEntry* dir)
+{
+	static const char module[] = "TIFFWriteDirectoryTagColormap";
+	uint32 m;
+	uint16* n;
+	int o;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=(1<<tif->tif_dir.td_bitspersample);
+	n=_TIFFmalloc(3*m*sizeof(uint16));
+	if (n==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	_TIFFmemcpy(&n[0],tif->tif_dir.td_colormap[0],m*sizeof(uint16));
+	_TIFFmemcpy(&n[m],tif->tif_dir.td_colormap[1],m*sizeof(uint16));
+	_TIFFmemcpy(&n[2*m],tif->tif_dir.td_colormap[2],m*sizeof(uint16));
+	o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_COLORMAP,3*m,n);
+	_TIFFfree(n);
+	return(o);
+}
+
+static int
+TIFFWriteDirectoryTagTransferfunction(TIFF* tif, uint32* ndir, TIFFDirEntry* dir)
+{
+	static const char module[] = "TIFFWriteDirectoryTagTransferfunction";
+	uint32 m;
+	uint16 n;
+	uint16* o;
+	int p;
+	if (dir==NULL)
+	{
+		(*ndir)++;
+		return(1);
+	}
+	m=(1<<tif->tif_dir.td_bitspersample);
+	n=tif->tif_dir.td_samplesperpixel-tif->tif_dir.td_extrasamples;
+	/*
+	 * Check if the table can be written as a single column,
+	 * or if it must be written as 3 columns.  Note that we
+	 * write a 3-column tag if there are 2 samples/pixel and
+	 * a single column of data won't suffice--hmm.
+	 */
+	if (n>3)
+		n=3;
+	if (n==3)
+	{
+		if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16)))
+			n=2;
+	}
+	if (n==2)
+	{
+		if (!_TIFFmemcmp(tif->tif_dir.td_transferfunction[0],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16)))
+			n=1;
+	}
+	if (n==0)
+		n=1;
+	o=_TIFFmalloc(n*m*sizeof(uint16));
+	if (o==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	_TIFFmemcpy(&o[0],tif->tif_dir.td_transferfunction[0],m*sizeof(uint16));
+	if (n>1)
+		_TIFFmemcpy(&o[m],tif->tif_dir.td_transferfunction[1],m*sizeof(uint16));
+	if (n>2)
+		_TIFFmemcpy(&o[2*m],tif->tif_dir.td_transferfunction[2],m*sizeof(uint16));
+	p=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,TIFFTAG_TRANSFERFUNCTION,n*m,o);
+	_TIFFfree(o);
+	return(p);
+}
+
+static int
+TIFFWriteDirectoryTagSubifd(TIFF* tif, uint32* ndir, TIFFDirEntry* dir)
+{
+	static const char module[] = "TIFFWriteDirectoryTagSubifd";
+	uint64 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* o;
+		uint64* pa;
+		uint32* pb;
+		uint16 p;
+		o=_TIFFmalloc(tif->tif_dir.td_nsubifd*sizeof(uint32));
+		if (o==NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+			return(0);
+		}
+		pa=tif->tif_dir.td_subifd;
+		pb=o;
+		for (p=0; p < tif->tif_dir.td_nsubifd; p++)
+		{
+                        assert(pa != 0);
+			assert(*pa <= 0xFFFFFFFFUL);
+			*pb++=(uint32)(*pa++);
+		}
+		n=TIFFWriteDirectoryTagCheckedIfdArray(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,o);
+		_TIFFfree(o);
+	}
+	else
+		n=TIFFWriteDirectoryTagCheckedIfd8Array(tif,ndir,dir,TIFFTAG_SUBIFD,tif->tif_dir.td_nsubifd,tif->tif_dir.td_subifd);
+	if (!n)
+		return(0);
+	/*
+	 * Total hack: if this directory includes a SubIFD
+	 * tag then force the next <n> 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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, char* value)
+{
+	assert(sizeof(char)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_ASCII,count,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedUndefinedArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
+{
+	assert(sizeof(uint8)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_UNDEFINED,count,count,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedByte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint8 value)
+{
+	assert(sizeof(uint8)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,1,1,&value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedByteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint8* value)
+{
+	assert(sizeof(uint8)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_BYTE,count,count,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedSbyte(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int8 value)
+{
+	assert(sizeof(int8)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,1,1,&value));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedSbyteArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int8* value)
+{
+	assert(sizeof(int8)==1);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SBYTE,count,count,value));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedShort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint16 value)
+{
+	uint16 m;
+	assert(sizeof(uint16)==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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint16* value)
+{
+	assert(count<0x80000000);
+	assert(sizeof(uint16)==2);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfShort(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SHORT,count,count*2,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedSshort(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int16 value)
+{
+	int16 m;
+	assert(sizeof(int16)==2);
+	m=value;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabShort((uint16*)(&m));
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,1,2,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedSshortArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int16* value)
+{
+	assert(count<0x80000000);
+	assert(sizeof(int16)==2);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfShort((uint16*)value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SSHORT,count,count*2,value));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 value)
+{
+	uint32 m;
+	assert(sizeof(uint32)==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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
+{
+	assert(count<0x40000000);
+	assert(sizeof(uint32)==4);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG,count,count*4,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedSlong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int32 value)
+{
+	int32 m;
+	assert(sizeof(int32)==4);
+	m=value;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong((uint32*)(&m));
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,1,4,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedSlongArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int32* value)
+{
+	assert(count<0x40000000);
+	assert(sizeof(int32)==4);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong((uint32*)value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG,count,count*4,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedLong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint64 value)
+{
+	uint64 m;
+	assert(sizeof(uint64)==8);
+	assert(tif->tif_flags&TIFF_BIGTIFF);
+	m=value;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong8(&m);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,1,8,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+	assert(count<0x20000000);
+	assert(sizeof(uint64)==8);
+	assert(tif->tif_flags&TIFF_BIGTIFF);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong8(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_LONG8,count,count*8,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedSlong8(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, int64 value)
+{
+	int64 m;
+	assert(sizeof(int64)==8);
+	assert(tif->tif_flags&TIFF_BIGTIFF);
+	m=value;
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabLong8((uint64*)(&m));
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,1,8,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedSlong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, int64* value)
+{
+	assert(count<0x20000000);
+	assert(sizeof(int64)==8);
+	assert(tif->tif_flags&TIFF_BIGTIFF);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong8((uint64*)value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SLONG8,count,count*8,value));
+}
+
+static int
+TIFFWriteDirectoryTagCheckedRational(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	uint32 m[2];
+	assert(value>=0.0);
+	assert(sizeof(uint32)==4);
+	if (value<=0.0)
+	{
+		m[0]=0;
+		m[1]=1;
+	}
+	else if (value==(double)(uint32)value)
+	{
+		m[0]=(uint32)value;
+		m[1]=1;
+	}
+	else if (value<1.0)
+	{
+		m[0]=(uint32)(value*0xFFFFFFFF);
+		m[1]=0xFFFFFFFF;
+	}
+	else
+	{
+		m[0]=0xFFFFFFFF;
+		m[1]=(uint32)(0xFFFFFFFF/value);
+	}
+	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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagCheckedRationalArray";
+	uint32* m;
+	float* na;
+	uint32* nb;
+	uint32 nc;
+	int o;
+	assert(sizeof(uint32)==4);
+	m=_TIFFmalloc(count*2*sizeof(uint32));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=value, nb=m, nc=0; nc<count; na++, nb+=2, nc++)
+	{
+		if (*na<=0.0)
+		{
+			nb[0]=0;
+			nb[1]=1;
+		}
+		else if (*na==(float)(uint32)(*na))
+		{
+			nb[0]=(uint32)(*na);
+			nb[1]=1;
+		}
+		else if (*na<1.0)
+		{
+			nb[0]=(uint32)((*na)*0xFFFFFFFF);
+			nb[1]=0xFFFFFFFF;
+		}
+		else
+		{
+			nb[0]=0xFFFFFFFF;
+			nb[1]=(uint32)(0xFFFFFFFF/(*na));
+		}
+	}
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong(m,count*2);
+	o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_RATIONAL,count,count*8,&m[0]);
+	_TIFFfree(m);
+	return(o);
+}
+
+static int
+TIFFWriteDirectoryTagCheckedSrationalArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	static const char module[] = "TIFFWriteDirectoryTagCheckedSrationalArray";
+	int32* m;
+	float* na;
+	int32* nb;
+	uint32 nc;
+	int o;
+	assert(sizeof(int32)==4);
+	m=_TIFFmalloc(count*2*sizeof(int32));
+	if (m==NULL)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	for (na=value, nb=m, nc=0; nc<count; na++, nb+=2, nc++)
+	{
+		if (*na<0.0)
+		{
+			if (*na==(int32)(*na))
+			{
+				nb[0]=(int32)(*na);
+				nb[1]=1;
+			}
+			else if (*na>-1.0)
+			{
+				nb[0]=-(int32)((-*na)*0x7FFFFFFF);
+				nb[1]=0x7FFFFFFF;
+			}
+			else
+			{
+				nb[0]=-0x7FFFFFFF;
+				nb[1]=(int32)(0x7FFFFFFF/(-*na));
+			}
+		}
+		else
+		{
+			if (*na==(int32)(*na))
+			{
+				nb[0]=(int32)(*na);
+				nb[1]=1;
+			}
+			else if (*na<1.0)
+			{
+				nb[0]=(int32)((*na)*0x7FFFFFFF);
+				nb[1]=0x7FFFFFFF;
+			}
+			else
+			{
+				nb[0]=0x7FFFFFFF;
+				nb[1]=(int32)(0x7FFFFFFF/(*na));
+			}
+		}
+	}
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfLong((uint32*)m,count*2);
+	o=TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_SRATIONAL,count,count*8,&m[0]);
+	_TIFFfree(m);
+	return(o);
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedFloat(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, float value)
+{
+	float m;
+	assert(sizeof(float)==4);
+	m=value;
+	TIFFCvtNativeToIEEEFloat(tif,1,&m);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabFloat(&m);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,1,4,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedFloatArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, float* value)
+{
+	assert(count<0x40000000);
+	assert(sizeof(float)==4);
+	TIFFCvtNativeToIEEEFloat(tif,count,&value);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabArrayOfFloat(value,count);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_FLOAT,count,count*4,value));
+}
+
+#ifdef notdef
+static int
+TIFFWriteDirectoryTagCheckedDouble(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, double value)
+{
+	double m;
+	assert(sizeof(double)==8);
+	m=value;
+	TIFFCvtNativeToIEEEDouble(tif,1,&m);
+	if (tif->tif_flags&TIFF_SWAB)
+		TIFFSwabDouble(&m);
+	return(TIFFWriteDirectoryTagData(tif,ndir,dir,tag,TIFF_DOUBLE,1,8,&m));
+}
+#endif
+
+static int
+TIFFWriteDirectoryTagCheckedDoubleArray(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint32* value)
+{
+	assert(count<0x40000000);
+	assert(sizeof(uint32)==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* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
+{
+	assert(count<0x20000000);
+	assert(sizeof(uint64)==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* ndir, TIFFDirEntry* dir, uint16 tag, uint16 datatype, uint32 count, uint32 datalength, void* data)
+{
+	static const char module[] = "TIFFWriteDirectoryTagData";
+	uint32 m;
+	m=0;
+	while (m<(*ndir))
+	{
+		assert(dir[m].tdir_tag!=tag);
+		if (dir[m].tdir_tag>tag)
+			break;
+		m++;
+	}
+	if (m<(*ndir))
+	{
+		uint32 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))
+		_TIFFmemcpy(&dir[m].tdir_offset,data,datalength);
+	else
+	{
+		uint64 na,nb;
+		na=tif->tif_dataoff;
+		nb=na+datalength;
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+			nb=(uint32)nb;
+		if ((nb<na)||(nb<datalength))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Maximum TIFF file size exceeded");
+			return(0);
+		}
+		if (!SeekOK(tif,na))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data");
+			return(0);
+		}
+		assert(datalength<0x80000000UL);
+		if (!WriteOK(tif,data,(tmsize_t)datalength))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"IO error writing tag data");
+			return(0);
+		}
+		tif->tif_dataoff=nb;
+		if (tif->tif_dataoff&1)
+			tif->tif_dataoff++;
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			uint32 o;
+			o=(uint32)na;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong(&o);
+			_TIFFmemcpy(&dir[m].tdir_offset,&o,4);
+		}
+		else
+		{
+			dir[m].tdir_offset.toff_long8 = na;
+			if (tif->tif_flags&TIFF_SWAB)
+				TIFFSwabLong8(&dir[m].tdir_offset.toff_long8);
+		}
+	}
+	(*ndir)++;
+	return(1);
+}
+
+/*
+ * Link the current directory into the directory chain for the file.
+ */
+static int
+TIFFLinkDirectory(TIFF* tif)
+{
+	static const char module[] = "TIFFLinkDirectory";
+
+	tif->tif_diroff = (TIFFSeekFile(tif,0,SEEK_END)+1) &~ 1;
+
+	/*
+	 * Handle SubIFDs
+	 */
+	if (tif->tif_flags & TIFF_INSUBIFD)
+	{
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			uint32 m;
+			m = (uint32)tif->tif_diroff;
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong(&m);
+			(void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
+			if (!WriteOK(tif, &m, 4)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				     "Error writing SubIFD directory link");
+				return (0);
+			}
+			/*
+			 * Advance to the next SubIFD or, if this is
+			 * the last one configured, revert back to the
+			 * normal directory linkage.
+			 */
+			if (--tif->tif_nsubifd)
+				tif->tif_subifdoff += 4;
+			else
+				tif->tif_flags &= ~TIFF_INSUBIFD;
+			return (1);
+		}
+		else
+		{
+			uint64 m;
+			m = tif->tif_diroff;
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&m);
+			(void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
+			if (!WriteOK(tif, &m, 8)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				     "Error writing SubIFD directory link");
+				return (0);
+			}
+			/*
+			 * Advance to the next SubIFD or, if this is
+			 * the last one configured, revert back to the
+			 * normal directory linkage.
+			 */
+			if (--tif->tif_nsubifd)
+				tif->tif_subifdoff += 8;
+			else
+				tif->tif_flags &= ~TIFF_INSUBIFD;
+			return (1);
+		}
+	}
+
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+	{
+		uint32 m;
+		uint32 nextdir;
+		m = (uint32)(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) tif->tif_diroff;
+			(void) TIFFSeekFile(tif,4, SEEK_SET);
+			if (!WriteOK(tif, &m, 4)) {
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+					     "Error writing TIFF header");
+				return (0);
+			}
+			return (1);
+		}
+		/*
+		 * Not the first directory, search to the last and append.
+		 */
+		nextdir = tif->tif_header.classic.tiff_diroff;
+		while(1) {
+			uint16 dircount;
+			uint32 nextnextdir;
+
+			if (!SeekOK(tif, nextdir) ||
+			    !ReadOK(tif, &dircount, 2)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory count");
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabShort(&dircount);
+			(void) TIFFSeekFile(tif,
+			    nextdir+2+dircount*12, SEEK_SET);
+			if (!ReadOK(tif, &nextnextdir, 4)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory link");
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong(&nextnextdir);
+			if (nextnextdir==0)
+			{
+				(void) TIFFSeekFile(tif,
+				    nextdir+2+dircount*12, SEEK_SET);
+				if (!WriteOK(tif, &m, 4)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error writing directory link");
+					return (0);
+				}
+				break;
+			}
+			nextdir=nextnextdir;
+		}
+	}
+	else
+	{
+		uint64 m;
+		uint64 nextdir;
+		m = tif->tif_diroff;
+		if (tif->tif_flags & TIFF_SWAB)
+			TIFFSwabLong8(&m);
+		if (tif->tif_header.big.tiff_diroff == 0) {
+			/*
+			 * First directory, overwrite offset in header.
+			 */
+			tif->tif_header.big.tiff_diroff = tif->tif_diroff;
+			(void) TIFFSeekFile(tif,8, SEEK_SET);
+			if (!WriteOK(tif, &m, 8)) {
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+					     "Error writing TIFF header");
+				return (0);
+			}
+			return (1);
+		}
+		/*
+		 * Not the first directory, search to the last and append.
+		 */
+		nextdir = tif->tif_header.big.tiff_diroff;
+		while(1) {
+			uint64 dircount64;
+			uint16 dircount;
+			uint64 nextnextdir;
+
+			if (!SeekOK(tif, nextdir) ||
+			    !ReadOK(tif, &dircount64, 8)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory count");
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&dircount64);
+			if (dircount64>0xFFFF)
+			{
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Sanity check on tag count failed, likely corrupt TIFF");
+				return (0);
+			}
+			dircount=(uint16)dircount64;
+			(void) TIFFSeekFile(tif,
+			    nextdir+8+dircount*20, SEEK_SET);
+			if (!ReadOK(tif, &nextnextdir, 8)) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error fetching directory link");
+				return (0);
+			}
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabLong8(&nextnextdir);
+			if (nextnextdir==0)
+			{
+				(void) TIFFSeekFile(tif,
+				    nextdir+8+dircount*20, SEEK_SET);
+				if (!WriteOK(tif, &m, 8)) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					     "Error writing directory link");
+					return (0);
+				}
+				break;
+			}
+			nextdir=nextnextdir;
+		}
+	}
+	return (1);
+}
+
+/************************************************************************/
+/*                          TIFFRewriteField()                          */
+/*                                                                      */
+/*      Rewrite a field in the directory on disk without regard to      */
+/*      updating the TIFF directory structure in memory.  Currently     */
+/*      only supported for field that already exist in the on-disk      */
+/*      directory.  Mainly used for updating stripoffset /              */
+/*      stripbytecount values after the directory is already on         */
+/*      disk.                                                           */
+/*                                                                      */
+/*      Returns zero on failure, and one on success.                    */
+/************************************************************************/
+
+int
+_TIFFRewriteField(TIFF* tif, uint16 tag, TIFFDataType in_datatype, 
+                  tmsize_t count, void* data)
+{
+    static const char module[] = "TIFFResetField";
+    /* const TIFFField* fip = NULL; */
+    uint16 dircount;
+    tmsize_t dirsize;
+    uint8 direntry_raw[20];
+    uint16 entry_tag = 0;
+    uint16 entry_type = 0;
+    uint64 entry_count = 0;
+    uint64 entry_offset = 0;
+    int    value_in_entry = 0;
+    uint64 read_offset;
+    uint8 *buf_to_write = NULL;
+    TIFFDataType datatype;
+
+/* -------------------------------------------------------------------- */
+/*      Find field definition.                                          */
+/* -------------------------------------------------------------------- */
+    /*fip =*/ TIFFFindField(tif, tag, TIFF_ANY);
+
+/* -------------------------------------------------------------------- */
+/*      Do some checking this is a straight forward case.               */
+/* -------------------------------------------------------------------- */
+    if( isMapped(tif) )
+    {
+        TIFFErrorExt( tif->tif_clientdata, module, 
+                      "Memory mapped files not currently supported for this operation." );
+        return 0;
+    }
+
+    if( tif->tif_diroff == 0 )
+    {
+        TIFFErrorExt( tif->tif_clientdata, module, 
+                      "Attempt to reset field on directory not already on disk." );
+        return 0;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Read the directory entry count.                                 */
+/* -------------------------------------------------------------------- */
+    if (!SeekOK(tif, tif->tif_diroff)) {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                     "%s: Seek error accessing TIFF directory",
+                     tif->tif_name);
+        return 0;
+    }
+
+    read_offset = tif->tif_diroff;
+
+    if (!(tif->tif_flags&TIFF_BIGTIFF))
+    {
+        if (!ReadOK(tif, &dircount, sizeof (uint16))) {
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "%s: Can not read TIFF directory count",
+                         tif->tif_name);
+            return 0;
+        }
+        if (tif->tif_flags & TIFF_SWAB)
+            TIFFSwabShort(&dircount);
+        dirsize = 12;
+        read_offset += 2;
+    } else {
+        uint64 dircount64;
+        if (!ReadOK(tif, &dircount64, sizeof (uint64))) {
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "%s: Can not read TIFF directory count",
+                         tif->tif_name);
+            return 0;
+        }
+        if (tif->tif_flags & TIFF_SWAB)
+            TIFFSwabLong8(&dircount64);
+        dircount = (uint16)dircount64;
+        dirsize = 20;
+        read_offset += 8;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Read through directory to find target tag.                      */
+/* -------------------------------------------------------------------- */
+    while( dircount > 0 )
+    {
+        if (!ReadOK(tif, direntry_raw, dirsize)) {
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "%s: Can not read TIFF directory entry.",
+                         tif->tif_name);
+            return 0;
+        }
+
+        memcpy( &entry_tag, direntry_raw + 0, sizeof(uint16) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabShort( &entry_tag );
+
+        if( entry_tag == tag )
+            break;
+
+        read_offset += dirsize;
+    }
+
+    if( entry_tag != tag )
+    {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                     "%s: Could not find tag %d.",
+                     tif->tif_name, tag );
+        return 0;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Extract the type, count and offset for this entry.              */
+/* -------------------------------------------------------------------- */
+    memcpy( &entry_type, direntry_raw + 2, sizeof(uint16) );
+    if (tif->tif_flags&TIFF_SWAB)
+        TIFFSwabShort( &entry_type );
+
+    if (!(tif->tif_flags&TIFF_BIGTIFF))
+    {
+        uint32 value;
+        
+        memcpy( &value, direntry_raw + 4, sizeof(uint32) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong( &value );
+        entry_count = value;
+
+        memcpy( &value, direntry_raw + 8, sizeof(uint32) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong( &value );
+        entry_offset = value;
+    }
+    else
+    {
+        memcpy( &entry_count, direntry_raw + 4, sizeof(uint64) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong8( &entry_count );
+
+        memcpy( &entry_offset, direntry_raw + 12, sizeof(uint64) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong8( &entry_offset );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      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 = 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 
+        datatype = in_datatype;
+
+/* -------------------------------------------------------------------- */
+/*      Prepare buffer of actual data to write.  This includes          */
+/*      swabbing as needed.                                             */
+/* -------------------------------------------------------------------- */
+    buf_to_write =
+	    (uint8 *)_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 *) buf_to_write)[i] = 
+                (int32) ((int64 *) data)[i];
+            if( (int64) ((int32 *) buf_to_write)[i] != ((int64 *) data)[i] )
+            {
+                _TIFFfree( buf_to_write );
+                TIFFErrorExt( tif->tif_clientdata, module, 
+                              "Value exceeds 32bit range of output type." );
+                return 0;
+            }
+        }
+    }
+    else if( (datatype == TIFF_LONG && in_datatype == TIFF_LONG8)
+             || (datatype == TIFF_IFD && in_datatype == TIFF_IFD8) )
+    {
+	tmsize_t i;
+
+        for( i = 0; i < count; i++ )
+        {
+            ((uint32 *) buf_to_write)[i] = 
+                (uint32) ((uint64 *) data)[i];
+            if( (uint64) ((uint32 *) buf_to_write)[i] != ((uint64 *) data)[i] )
+            {
+                _TIFFfree( buf_to_write );
+                TIFFErrorExt( tif->tif_clientdata, module, 
+                              "Value exceeds 32bit range of output type." );
+                return 0;
+            }
+        }
+    }
+
+    if( TIFFDataWidth(datatype) > 1 && (tif->tif_flags&TIFF_SWAB) )
+    {
+        if( TIFFDataWidth(datatype) == 2 )
+            TIFFSwabArrayOfShort( (uint16 *) buf_to_write, count );
+        else if( TIFFDataWidth(datatype) == 4 )
+            TIFFSwabArrayOfLong( (uint32 *) buf_to_write, count );
+        else if( TIFFDataWidth(datatype) == 8 )
+            TIFFSwabArrayOfLong8( (uint64 *) 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 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)count && entry_type == (uint16) datatype )
+    {
+        if (!SeekOK(tif, entry_offset)) {
+            _TIFFfree( buf_to_write );
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "%s: Seek error accessing TIFF directory",
+                         tif->tif_name);
+            return 0;
+        }
+        if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) {
+            _TIFFfree( buf_to_write );
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "Error writing directory link");
+            return (0);
+        }
+
+        _TIFFfree( buf_to_write );
+        return 1;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Otherwise, we write the new tag data at the end of the file.    */
+/* -------------------------------------------------------------------- */
+    if( !value_in_entry )
+    {
+        entry_offset = TIFFSeekFile(tif,0,SEEK_END);
+        
+        if (!WriteOK(tif, buf_to_write, count*TIFFDataWidth(datatype))) {
+            _TIFFfree( buf_to_write );
+            TIFFErrorExt(tif->tif_clientdata, module,
+                         "Error writing directory link");
+            return (0);
+        }
+    }
+    else
+    {
+        memcpy( &entry_offset, buf_to_write, count*TIFFDataWidth(datatype));
+    }
+
+    _TIFFfree( buf_to_write );
+    buf_to_write = 0;
+
+/* -------------------------------------------------------------------- */
+/*      Adjust the directory entry.                                     */
+/* -------------------------------------------------------------------- */
+    entry_type = datatype;
+    memcpy( direntry_raw + 2, &entry_type, sizeof(uint16) );
+    if (tif->tif_flags&TIFF_SWAB)
+        TIFFSwabShort( (uint16 *) (direntry_raw + 2) );
+
+    if (!(tif->tif_flags&TIFF_BIGTIFF))
+    {
+        uint32 value;
+
+        value = (uint32) entry_count;
+        memcpy( direntry_raw + 4, &value, sizeof(uint32) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong( (uint32 *) (direntry_raw + 4) );
+
+        value = (uint32) entry_offset;
+        memcpy( direntry_raw + 8, &value, sizeof(uint32) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong( (uint32 *) (direntry_raw + 8) );
+    }
+    else
+    {
+        memcpy( direntry_raw + 4, &entry_count, sizeof(uint64) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong8( (uint64 *) (direntry_raw + 4) );
+
+        memcpy( direntry_raw + 12, &entry_offset, sizeof(uint64) );
+        if (tif->tif_flags&TIFF_SWAB)
+            TIFFSwabLong8( (uint64 *) (direntry_raw + 12) );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Write the directory entry out to disk.                          */
+/* -------------------------------------------------------------------- */
+    if (!SeekOK(tif, read_offset )) {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                     "%s: Seek error accessing TIFF directory",
+                     tif->tif_name);
+        return 0;
+    }
+
+    if (!WriteOK(tif, direntry_raw,dirsize))
+    {
+        TIFFErrorExt(tif->tif_clientdata, module,
+                     "%s: Can not write TIFF directory entry.",
+                     tif->tif_name);
+        return 0;
+    }
+    
+    return 1;
+}
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_dumpmode.c b/third_party/libtiff/tif_dumpmode.c
new file mode 100644
index 0000000..a94cf0b
--- /dev/null
+++ b/third_party/libtiff/tif_dumpmode.c
@@ -0,0 +1,143 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_dumpmode.c,v 1.14 2011-04-02 20:54:09 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * "Null" Compression Algorithm Support.
+ */
+#include "tiffiop.h"
+
+static int
+DumpFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+/*
+ * Encode a hunk of pixels.
+ */
+static int
+DumpModeEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s)
+{
+	(void) s;
+	while (cc > 0) {
+		tmsize_t n;
+
+		n = cc;
+		if (tif->tif_rawcc + n > tif->tif_rawdatasize)
+			n = tif->tif_rawdatasize - tif->tif_rawcc;
+
+		assert( n > 0 );
+
+		/*
+		 * Avoid copy if client has setup raw
+		 * data buffer to avoid extra copy.
+		 */
+		if (tif->tif_rawcp != pp)
+			_TIFFmemcpy(tif->tif_rawcp, pp, n);
+		tif->tif_rawcp += n;
+		tif->tif_rawcc += n;
+		pp += n;
+		cc -= n;
+		if (tif->tif_rawcc >= tif->tif_rawdatasize &&
+		    !TIFFFlushData1(tif))
+			return (-1);
+	}
+	return (1);
+}
+
+/*
+ * Decode a hunk of pixels.
+ */
+static int
+DumpModeDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	static const char module[] = "DumpModeDecode";
+	(void) s;
+	if (tif->tif_rawcc < cc) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+"Not enough data for scanline %lu, expected a request for at most %I64d bytes, got a request for %I64d bytes",
+		             (unsigned long) tif->tif_row,
+		             (signed __int64) tif->tif_rawcc,
+		             (signed __int64) cc);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+"Not enough data for scanline %lu, expected a request for at most %lld bytes, got a request for %lld bytes",
+		             (unsigned long) tif->tif_row,
+		             (signed long long) tif->tif_rawcc,
+		             (signed long long) cc);
+#endif
+		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)
+{
+	tif->tif_rawcp += nrows * tif->tif_scanlinesize;
+	tif->tif_rawcc -= nrows * tif->tif_scanlinesize;
+	return (1);
+}
+
+/*
+ * Initialize dump mode.
+ */
+int
+TIFFInitDumpMode(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	tif->tif_fixuptags = DumpFixupTags;  
+	tif->tif_decoderow = DumpModeDecode;
+	tif->tif_decodestrip = DumpModeDecode;
+	tif->tif_decodetile = DumpModeDecode;
+	tif->tif_encoderow = DumpModeEncode;
+	tif->tif_encodestrip = DumpModeEncode;
+	tif->tif_encodetile = DumpModeEncode; 
+	tif->tif_seek = DumpModeSeek;
+	return (1);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_error.c b/third_party/libtiff/tif_error.c
new file mode 100644
index 0000000..0bc8b87
--- /dev/null
+++ b/third_party/libtiff/tif_error.c
@@ -0,0 +1,80 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_error.c,v 1.5 2010-03-10 18:56:48 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#include "tiffiop.h"
+
+TIFFErrorHandlerExt _TIFFerrorHandlerExt = NULL;
+
+TIFFErrorHandler
+TIFFSetErrorHandler(TIFFErrorHandler handler)
+{
+	TIFFErrorHandler prev = _TIFFerrorHandler;
+	_TIFFerrorHandler = handler;
+	return (prev);
+}
+
+TIFFErrorHandlerExt
+TIFFSetErrorHandlerExt(TIFFErrorHandlerExt handler)
+{
+	TIFFErrorHandlerExt prev = _TIFFerrorHandlerExt;
+	_TIFFerrorHandlerExt = handler;
+	return (prev);
+}
+
+void
+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);
+}
+
+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);
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_extension.c b/third_party/libtiff/tif_extension.c
new file mode 100644
index 0000000..10afd41
--- /dev/null
+++ b/third_party/libtiff/tif_extension.c
@@ -0,0 +1,118 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_extension.c,v 1.7 2010-03-10 18:56:48 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 
+ * 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.
+ *
+ * Various routines support external extension of the tag set, and other
+ * application extension capabilities. 
+ */
+
+#include "tiffiop.h"
+
+int TIFFGetTagListCount( TIFF *tif )
+
+{
+    TIFFDirectory* td = &tif->tif_dir;
+    
+    return td->td_customValueCount;
+}
+
+uint32 TIFFGetTagListEntry( TIFF *tif, int tag_index )
+
+{
+    TIFFDirectory* td = &tif->tif_dir;
+
+    if( tag_index < 0 || tag_index >= td->td_customValueCount )
+        return (uint32)(-1);
+    else
+        return td->td_customValues[tag_index].info->field_tag;
+}
+
+/*
+** This provides read/write access to the TIFFTagMethods within the TIFF
+** structure to application code without giving access to the private
+** TIFF structure.
+*/
+TIFFTagMethods *TIFFAccessTagMethods( TIFF *tif )
+
+{
+    return &(tif->tif_tagmethods);
+}
+
+void *TIFFGetClientInfo( TIFF *tif, const char *name )
+
+{
+    TIFFClientInfoLink *link = tif->tif_clientinfo;
+
+    while( link != NULL && strcmp(link->name,name) != 0 )
+        link = link->next;
+
+    if( link != NULL )
+        return link->data;
+    else
+        return NULL;
+}
+
+void TIFFSetClientInfo( TIFF *tif, void *data, const char *name )
+
+{
+    TIFFClientInfoLink *link = 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;
+
+    if( link != NULL )
+    {
+        link->data = data;
+        return;
+    }
+
+    /*
+    ** Create a new link.
+    */
+
+    link = (TIFFClientInfoLink *) _TIFFmalloc(sizeof(TIFFClientInfoLink));
+    assert (link != NULL);
+    link->next = tif->tif_clientinfo;
+    link->name = (char *) _TIFFmalloc((tmsize_t)(strlen(name)+1));
+    assert (link->name != NULL);
+    strcpy(link->name, name);
+    link->data = data;
+
+    tif->tif_clientinfo = link;
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_fax3.c b/third_party/libtiff/tif_fax3.c
new file mode 100644
index 0000000..bbe7255
--- /dev/null
+++ b/third_party/libtiff/tif_fax3.c
@@ -0,0 +1,1596 @@
+/* $Id: tif_fax3.c,v 1.75 2015-08-30 20:49:55 erouault 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef CCITT_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * CCITT Group 3 (T.4) and Group 4 (T.6) Compression Support.
+ *
+ * This file contains support for decoding and encoding TIFF
+ * compression algorithms 2, 3, 4, and 32771.
+ *
+ * Decoder support is derived, with permission, from the code
+ * in Frank Cringle's viewfax program;
+ *      Copyright (C) 1990, 1995  Frank D. Cringle.
+ */
+#include "tif_fax3.h"
+#define	G3CODES
+#include "t4.h"
+#include <stdio.h>
+
+/*
+ * Compression+decompression state blocks are
+ * derived from this ``base state'' block.
+ */
+typedef struct {
+	int      rw_mode;                /* O_RDONLY for decode, else encode */
+	int      mode;                   /* operating mode */
+	tmsize_t rowbytes;               /* bytes in a decoded scanline */
+	uint32   rowpixels;              /* pixels in a scanline */
+
+	uint16   cleanfaxdata;           /* CleanFaxData tag */
+	uint32   badfaxrun;              /* BadFaxRun tag */
+	uint32   badfaxlines;            /* BadFaxLines tag */
+	uint32   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;
+} Fax3CodecState;
+#define DecoderState(tif) ((Fax3CodecState*) Fax3State(tif))
+#define EncoderState(tif) ((Fax3CodecState*) Fax3State(tif))
+
+#define is2DEncoding(sp) (sp->b.groupoptions & GROUP3OPT_2DENCODING)
+#define isAligned(p,t) ((((size_t)(p)) & (sizeof (t)-1)) == 0)
+
+/*
+ * Group 3 and Group 4 Decoding.
+ */
+
+/*
+ * These macros glue the TIFF library state to
+ * the state expected by Frank's decoder.
+ */
+#define	DECLARE_STATE(tif, sp, mod)					\
+    static const char module[] = mod;					\
+    Fax3CodecState* sp = DecoderState(tif);				\
+    int a0;				/* reference element */		\
+    int lastx = sp->b.rowpixels;	/* last element in row */	\
+    uint32 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)
+/*
+ * Save state possibly changed during decoding.
+ */
+#define	UNCACHE_STATE(tif, sp) do {					\
+    sp->bit = BitsAvail;						\
+    sp->data = BitAcc;							\
+    sp->EOLcnt = EOLcnt;						\
+    tif->tif_rawcc -= (tmsize_t)((uint8*) cp - tif->tif_rawcp);		\
+    tif->tif_rawcp = (uint8*) cp;					\
+} while (0)
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+Fax3PreDecode(TIFF* tif, uint16 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);
+}
+
+/*
+ * Routine for handling various errors/conditions.
+ * Note how they are "glued into the decoder" by
+ * overriding the definitions used by the decoder.
+ */
+
+static void
+Fax3Unexpected(const char* module, TIFF* tif, uint32 line, uint32 a0)
+{
+	TIFFErrorExt(tif->tif_clientdata, module, "Bad code word at line %u of %s %u (x %u)",
+	    line, isTiled(tif) ? "tile" : "strip",
+	    (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+	    a0);
+}
+#define	unexpected(table, a0)	Fax3Unexpected(module, tif, sp->line, a0)
+
+static void
+Fax3Extension(const char* module, TIFF* tif, uint32 line, uint32 a0)
+{
+	TIFFErrorExt(tif->tif_clientdata, module,
+	    "Uncompressed data (not supported) at line %u of %s %u (x %u)",
+	    line, isTiled(tif) ? "tile" : "strip",
+	    (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+	    a0);
+}
+#define	extension(a0)	Fax3Extension(module, tif, sp->line, a0)
+
+static void
+Fax3BadLength(const char* module, TIFF* tif, uint32 line, uint32 a0, uint32 lastx)
+{
+	TIFFWarningExt(tif->tif_clientdata, module, "%s at line %u of %s %u (got %u, expected %u)",
+	    a0 < lastx ? "Premature EOL" : "Line length mismatch",
+	    line, isTiled(tif) ? "tile" : "strip",
+	    (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+	    a0, lastx);
+}
+#define	badlength(a0,lastx)	Fax3BadLength(module, tif, sp->line, a0, lastx)
+
+static void
+Fax3PrematureEOF(const char* module, TIFF* tif, uint32 line, uint32 a0)
+{
+	TIFFWarningExt(tif->tif_clientdata, module, "Premature EOF at line %u of %s %u (x %u)",
+	    line, isTiled(tif) ? "tile" : "strip",
+	    (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+	    a0);
+}
+#define	prematureEOF(a0)	Fax3PrematureEOF(module, tif, sp->line, a0)
+
+#define	Nop
+
+/*
+ * Decode the requested amount of G3 1D-encoded data.
+ */
+static int
+Fax3Decode1D(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	DECLARE_STATE(tif, sp, "Fax3Decode1D");
+	(void) s;
+	if (occ % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (-1);
+	}
+	CACHE_STATE(tif, sp);
+	thisrun = sp->curruns;
+	while (occ > 0) {
+		a0 = 0;
+		RunLength = 0;
+		pa = thisrun;
+#ifdef FAX3_DEBUG
+		printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail);
+		printf("-------------------- %d\n", tif->tif_row);
+		fflush(stdout);
+#endif
+		SYNC_EOL(EOF1D);
+		EXPAND1D(EOF1Da);
+		(*sp->fill)(buf, thisrun, pa, lastx);
+		buf += sp->b.rowbytes;
+		occ -= sp->b.rowbytes;
+		sp->line++;
+		continue;
+	EOF1D:				/* premature EOF */
+		CLEANUP_RUNS();
+	EOF1Da:				/* premature EOF */
+		(*sp->fill)(buf, thisrun, pa, lastx);
+		UNCACHE_STATE(tif, sp);
+		return (-1);
+	}
+	UNCACHE_STATE(tif, sp);
+	return (1);
+}
+
+#define	SWAP(t,a,b)	{ t x; x = (a); (a) = (b); (b) = x; }
+/*
+ * Decode the requested amount of G3 2D-encoded data.
+ */
+static int
+Fax3Decode2D(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	DECLARE_STATE_2D(tif, sp, "Fax3Decode2D");
+	int is1D;			/* current line is 1d/2d-encoded */
+	(void) s;
+	if (occ % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (-1);
+	}
+	CACHE_STATE(tif, sp);
+	while (occ > 0) {
+		a0 = 0;
+		RunLength = 0;
+		pa = thisrun = sp->curruns;
+#ifdef FAX3_DEBUG
+		printf("\nBitAcc=%08X, BitsAvail = %d EOLcnt = %d",
+		    BitAcc, BitsAvail, EOLcnt);
+#endif
+		SYNC_EOL(EOF2D);
+		NeedBits8(1, EOF2D);
+		is1D = GetBits(1);	/* 1D/2D-encoding tag bit */
+		ClrBits(1);
+#ifdef FAX3_DEBUG
+		printf(" %s\n-------------------- %d\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);
+}
+#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_UNSIGNED_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
+
+/*
+ * 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)
+{
+	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;
+		    }
+                    /* Explicit 0xff masking to make icc -check=conversions happy */
+		    if (run)
+			cp[0] = (unsigned char)((cp[0] | (0xff00 >> run))&0xff);
+		} else
+		    cp[0] |= _fillmasks[run]>>bx;
+		x += runs[1];
+	    }
+	}
+	assert(x == lastx);
+}
+#undef	ZERO
+#undef	FILL
+
+static int
+Fax3FixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+/*
+ * Setup G3/G4-related compression/decompression state
+ * before data is processed.  This routine is called once
+ * per image -- it sets up different state based on whether
+ * or not decoding or encoding is being done and whether
+ * 1D- or 2D-encoded data is involved.
+ */
+static int
+Fax3SetupState(TIFF* tif)
+{
+	static const char module[] = "Fax3SetupState";
+	TIFFDirectory* td = &tif->tif_dir;
+	Fax3BaseState* sp = Fax3State(tif);
+	int needsRefLine;
+	Fax3CodecState* dsp = (Fax3CodecState*) Fax3State(tif);
+	tmsize_t rowbytes;
+	uint32 rowpixels, nruns;
+
+	if (td->td_bitspersample != 1) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Bits/sample must be 1 for Group 3/4 encoding/decoding");
+		return (0);
+	}
+	/*
+	 * Calculate the scanline/tile widths.
+	 */
+	if (isTiled(tif)) {
+		rowbytes = TIFFTileRowSize(tif);
+		rowpixels = td->td_tilewidth;
+	} else {
+		rowbytes = TIFFScanlineSize(tif);
+		rowpixels = td->td_imagewidth;
+	}
+	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*) NULL;
+	nruns = TIFFroundup_32(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);
+	memset( dsp->runs, 0, TIFFSafeMultiply(uint32,nruns,2)*sizeof(uint32));
+	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, 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++ = (uint8) (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++ = (uint8) 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)
+{
+	Fax3CodecState* sp = EncoderState(tif);
+	unsigned int bit = sp->bit;
+	int data = sp->data;
+
+	_PutBits(tif, bits, length);
+
+	sp->data = data;
+	sp->bit = bit;
+}
+
+/*
+ * Write a code to the output stream.
+ */
+#define putcode(tif, te)	Fax3PutBits(tif, (te)->code, (te)->length)
+
+#ifdef FAX3_DEBUG
+#define	DEBUG_COLOR(w) (tab == TIFFFaxWhiteCodes ? w "W" : w "B")
+#define	DEBUG_PRINT(what,len) {						\
+    int t;								\
+    printf("%08X/%-2d: %s%5d\t", data, bit, DEBUG_COLOR(what), len);	\
+    for (t = length-1; t >= 0; t--)					\
+	putchar(code & (1<<t) ? '1' : '0');				\
+    putchar('\n');							\
+}
+#endif
+
+/*
+ * Write the sequence of codes that describes
+ * the specified span of zero's or one's.  The
+ * appropriate table that holds the make-up and
+ * terminating codes is supplied.
+ */
+static void
+putspan(TIFF* tif, int32 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;
+#ifdef FAX3_DEBUG
+		DEBUG_PRINT("MakeUp", te->runlen);
+#endif
+		_PutBits(tif, code, length);
+		span -= te->runlen;
+	}
+	if (span >= 64) {
+		const tableentry* te = &tab[63 + (span>>6)];
+		assert(te->runlen == 64*(span>>6));
+		code = te->code, length = te->length;
+#ifdef FAX3_DEBUG
+		DEBUG_PRINT("MakeUp", te->runlen);
+#endif
+		_PutBits(tif, code, length);
+		span -= te->runlen;
+	}
+	code = tab[span].code, length = tab[span].length;
+#ifdef FAX3_DEBUG
+	DEBUG_PRINT("  Term", tab[span].runlen);
+#endif
+	_PutBits(tif, code, length);
+
+	sp->data = data;
+	sp->bit = bit;
+}
+
+/*
+ * Write an EOL code to the output stream.  The zero-fill
+ * logic for byte-aligning encoded scanlines is handled
+ * here.  We also handle writing the tag bit for the next
+ * scanline when doing 2d encoding.
+ */
+static void
+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;
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+Fax3PreEncode(TIFF* tif, uint16 s)
+{
+	Fax3CodecState* sp = EncoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	sp->bit = 8;
+	sp->data = 0;
+	sp->tag = G3_1D;
+	/*
+	 * This is necessary for Group 4; otherwise it isn't
+	 * needed because the first scanline of each strip ends
+	 * up being copied into the refline.
+	 */
+	if (sp->refline)
+		_TIFFmemset(sp->refline, 0x00, sp->b.rowbytes);
+	if (is2DEncoding(sp)) {
+		float res = tif->tif_dir.td_yresolution;
+		/*
+		 * The CCITT spec says that when doing 2d encoding, you
+		 * should only do it on K consecutive scanlines, where K
+		 * depends on the resolution of the image being encoded
+		 * (2 for <= 200 lpi, 4 for > 200 lpi).  Since the directory
+		 * code initializes td_yresolution to 0, this code will
+		 * select a K of 2 unless the YResolution tag is set
+		 * appropriately.  (Note also that we fudge a little here
+		 * and use 150 lpi to avoid problems with units conversion.)
+		 */
+		if (tif->tif_dir.td_resolutionunit == RESUNIT_CENTIMETER)
+			res *= 2.54f;		/* convert to inches */
+		sp->maxk = (res > 150 ? 4 : 2);
+		sp->k = sp->maxk-1;
+	} else
+		sp->k = sp->maxk = 0;
+	sp->line = 0;
+	return (1);
+}
+
+static const unsigned char zeroruns[256] = {
+    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,	/* 0x00 - 0x0f */
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	/* 0x10 - 0x1f */
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0x20 - 0x2f */
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0x30 - 0x3f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x40 - 0x4f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x50 - 0x5f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x60 - 0x6f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x70 - 0x7f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x80 - 0x8f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x90 - 0x9f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xa0 - 0xaf */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xb0 - 0xbf */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xc0 - 0xcf */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xd0 - 0xdf */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xe0 - 0xef */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xf0 - 0xff */
+};
+static const unsigned char oneruns[256] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x00 - 0x0f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x10 - 0x1f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x20 - 0x2f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x30 - 0x3f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x40 - 0x4f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x50 - 0x5f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x60 - 0x6f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x70 - 0x7f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x80 - 0x8f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x90 - 0x9f */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0xa0 - 0xaf */
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0xb0 - 0xbf */
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0xc0 - 0xcf */
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0xd0 - 0xdf */
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	/* 0xe0 - 0xef */
+    4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,	/* 0xf0 - 0xff */
+};
+
+/*
+ * 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.
+ */
+inline static int32
+find0span(unsigned char* bp, int32 bs, int32 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);
+}
+
+inline static int32
+find1span(unsigned char* bp, int32 bs, int32 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);
+}
+
+/*
+ * Return the offset of the next bit in the range
+ * [bs..be] that is different from the specified
+ * color.  The end, be, is returned if no such bit
+ * exists.
+ */
+#define	finddiff(_cp, _bs, _be, _color)	\
+	(_bs + (_color ? find1span(_cp,_bs,_be) : find0span(_cp,_bs,_be)))
+/*
+ * Like finddiff, but also check the starting bit
+ * against the end in case start > end.
+ */
+#define	finddiff2(_cp, _bs, _be, _color) \
+	(_bs < _be ? finddiff(_cp,_bs,_be,_color) : _be)
+
+/*
+ * 1d-encode a row of pixels.  The encoding is
+ * a sequence of all-white or all-black spans
+ * of pixels encoded with Huffman codes.
+ */
+static int
+Fax3Encode1DRow(TIFF* tif, unsigned char* bp, uint32 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);
+}
+
+static const tableentry horizcode =
+    { 3, 0x1, 0 };	/* 001 */
+static const tableentry passcode =
+    { 4, 0x1, 0 };	/* 0001 */
+static const tableentry vcodes[7] = {
+    { 7, 0x03, 0 },	/* 0000 011 */
+    { 6, 0x03, 0 },	/* 0000 11 */
+    { 3, 0x03, 0 },	/* 011 */
+    { 1, 0x1, 0 },	/* 1 */
+    { 3, 0x2, 0 },	/* 010 */
+    { 6, 0x02, 0 },	/* 0000 10 */
+    { 7, 0x02, 0 }	/* 0000 010 */
+};
+
+/*
+ * 2d-encode a row of pixels.  Consult the CCITT
+ * documentation for the algorithm.
+ */
+static int
+Fax3Encode2DRow(TIFF* tif, unsigned char* bp, unsigned char* rp, uint32 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);
+#undef PIXEL
+}
+
+/*
+ * Encode a buffer of pixels.
+ */
+static int
+Fax3Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	static const char module[] = "Fax3Encode";
+	Fax3CodecState* sp = EncoderState(tif);
+	(void) s;
+	if (cc % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be written");
+		return (0);
+	}
+	while (cc > 0) {
+		if ((sp->b.mode & FAXMODE_NOEOL) == 0)
+			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 int
+Fax3PostEncode(TIFF* tif)
+{
+	Fax3CodecState* sp = EncoderState(tif);
+
+	if (sp->bit != 8)
+		Fax3FlushBits(tif, sp);
+	return (1);
+}
+
+static void
+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);
+	}
+}
+
+static void
+Fax3Cleanup(TIFF* tif)
+{
+	Fax3CodecState* sp = DecoderState(tif);
+	
+	assert(sp != 0);
+
+	tif->tif_tagmethods.vgetfield = sp->b.vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->b.vsetparent;
+	tif->tif_tagmethods.printdir = sp->b.printdir;
+
+	if (sp->runs)
+		_TIFFfree(sp->runs);
+	if (sp->refline)
+		_TIFFfree(sp->refline);
+
+	_TIFFfree(tif->tif_data);
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+#define	FIELD_BADFAXLINES	(FIELD_CODEC+0)
+#define	FIELD_CLEANFAXDATA	(FIELD_CODEC+1)
+#define	FIELD_BADFAXRUN		(FIELD_CODEC+2)
+
+#define	FIELD_OPTIONS		(FIELD_CODEC+7)
+
+static const TIFFField faxFields[] = {
+    { TIFFTAG_FAXMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "FaxMode", NULL },
+    { TIFFTAG_FAXFILLFUNC, 0, 0, TIFF_ANY, 0, TIFF_SETGET_OTHER, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "FaxFillFunc", NULL },
+    { TIFFTAG_BADFAXLINES, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_BADFAXLINES, TRUE, FALSE, "BadFaxLines", NULL },
+    { TIFFTAG_CLEANFAXDATA, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UINT16, FIELD_CLEANFAXDATA, TRUE, FALSE, "CleanFaxData", NULL },
+    { TIFFTAG_CONSECUTIVEBADFAXLINES, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_BADFAXRUN, TRUE, FALSE, "ConsecutiveBadFaxLines", NULL }};
+static const TIFFField fax3Fields[] = {
+    { TIFFTAG_GROUP3OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group3Options", NULL },
+};
+static const TIFFField fax4Fields[] = {
+    { TIFFTAG_GROUP4OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, FIELD_OPTIONS, FALSE, FALSE, "Group4Options", NULL },
+};
+
+static int
+Fax3VSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	Fax3BaseState* sp = Fax3State(tif);
+	const TIFFField* fip;
+
+	assert(sp != 0);
+	assert(sp->vsetparent != 0);
+
+	switch (tag) {
+	case TIFFTAG_FAXMODE:
+		sp->mode = (int) va_arg(ap, int);
+		return 1;			/* NB: pseudo tag */
+	case TIFFTAG_FAXFILLFUNC:
+		DecoderState(tif)->fill = va_arg(ap, TIFFFaxFillFunc);
+		return 1;			/* NB: pseudo tag */
+	case TIFFTAG_GROUP3OPTIONS:
+		/* XXX: avoid reading options if compression mismatches. */
+		if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX3)
+			sp->groupoptions = (uint32) 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 = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_BADFAXLINES:
+		sp->badfaxlines = (uint32) va_arg(ap, uint32);
+		break;
+	case TIFFTAG_CLEANFAXDATA:
+		sp->cleanfaxdata = (uint16) va_arg(ap, uint16_vap);
+		break;
+	case TIFFTAG_CONSECUTIVEBADFAXLINES:
+		sp->badfaxrun = (uint32) va_arg(ap, uint32);
+		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;
+}
+
+static int
+Fax3VGetField(TIFF* tif, uint32 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;
+	default:
+		return (*sp->vgetparent)(tif, tag, ap);
+	}
+	return (1);
+}
+
+static void
+Fax3PrintDir(TIFF* tif, FILE* fd, long flags)
+{
+	Fax3BaseState* sp = Fax3State(tif);
+
+	assert(sp != 0);
+
+	(void) flags;
+	if (TIFFFieldSet(tif,FIELD_OPTIONS)) {
+		const char* sep = " ";
+		if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) {
+			fprintf(fd, "  Group 4 Options:");
+			if (sp->groupoptions & GROUP4OPT_UNCOMPRESSED)
+				fprintf(fd, "%suncompressed data", sep);
+		} else {
+
+			fprintf(fd, "  Group 3 Options:");
+			if (sp->groupoptions & GROUP3OPT_2DENCODING)
+				fprintf(fd, "%s2-d encoding", sep), sep = "+";
+			if (sp->groupoptions & GROUP3OPT_FILLBITS)
+				fprintf(fd, "%sEOL padding", sep), sep = "+";
+			if (sp->groupoptions & GROUP3OPT_UNCOMPRESSED)
+				fprintf(fd, "%suncompressed data", sep);
+		}
+		fprintf(fd, " (%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 (sp->printdir)
+		(*sp->printdir)(tif, fd, flags);
+}
+
+static int
+InitCCITTFax3(TIFF* tif)
+{
+	static const char module[] = "InitCCITTFax3";
+	Fax3BaseState* sp;
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, faxFields, TIFFArrayCount(faxFields))) {
+		TIFFErrorExt(tif->tif_clientdata, "InitCCITTFax3",
+			"Merging common CCITT Fax codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*)
+		_TIFFmalloc(sizeof (Fax3CodecState));
+
+	if (tif->tif_data == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "No space for state block");
+		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;	
+
+	if (sp->rw_mode == O_RDONLY) /* FIXME: improve for in place update */
+		tif->tif_flags |= TIFF_NOBITREV; /* decoder does bit reversal */
+	DecoderState(tif)->runs = NULL;
+	TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, _TIFFFax3fillruns);
+	EncoderState(tif)->refline = NULL;
+
+	/*
+	 * Install codec methods.
+	 */
+	tif->tif_fixuptags = Fax3FixupTags;
+	tif->tif_setupdecode = Fax3SetupState;
+	tif->tif_predecode = Fax3PreDecode;
+	tif->tif_decoderow = Fax3Decode1D;
+	tif->tif_decodestrip = Fax3Decode1D;
+	tif->tif_decodetile = Fax3Decode1D;
+	tif->tif_setupencode = Fax3SetupState;
+	tif->tif_preencode = Fax3PreEncode;
+	tif->tif_postencode = Fax3PostEncode;
+	tif->tif_encoderow = Fax3Encode;
+	tif->tif_encodestrip = Fax3Encode;
+	tif->tif_encodetile = Fax3Encode;
+	tif->tif_close = Fax3Close;
+	tif->tif_cleanup = Fax3Cleanup;
+
+	return (1);
+}
+
+int
+TIFFInitCCITTFax3(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	if (InitCCITTFax3(tif)) {
+		/*
+		 * Merge codec-specific tag information.
+		 */
+		if (!_TIFFMergeFields(tif, fax3Fields,
+				      TIFFArrayCount(fax3Fields))) {
+			TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax3",
+			"Merging CCITT Fax 3 codec-specific tags failed");
+			return 0;
+		}
+
+		/*
+		 * The default format is Class/F-style w/o RTC.
+		 */
+		return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_CLASSF);
+	} else
+		return 01;
+}
+
+/*
+ * CCITT Group 4 (T.6) Facsimile-compatible
+ * Compression Scheme Support.
+ */
+
+#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; }
+/*
+ * Decode the requested amount of G4-encoded data.
+ */
+static int
+Fax4Decode(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	DECLARE_STATE_2D(tif, sp, "Fax4Decode");
+	(void) s;
+	if (occ % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (-1);
+	}
+	CACHE_STATE(tif, sp);
+	while (occ > 0) {
+		a0 = 0;
+		RunLength = 0;
+		pa = thisrun = sp->curruns;
+		pb = sp->refruns;
+		b1 = *pb++;
+#ifdef FAX3_DEBUG
+		printf("\nBitAcc=%08X, 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:
+#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);
+}
+#undef	SWAP
+
+/*
+ * Encode the requested amount of data.
+ */
+static int
+Fax4Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	static const char module[] = "Fax4Encode";
+	Fax3CodecState *sp = EncoderState(tif);
+	(void) s;
+	if (cc % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be written");
+		return (0);
+	}
+	while (cc > 0) {
+		if (!Fax3Encode2DRow(tif, bp, sp->refline, sp->b.rowpixels))
+			return (0);
+		_TIFFmemcpy(sp->refline, bp, sp->b.rowbytes);
+		bp += sp->b.rowbytes;
+		cc -= sp->b.rowbytes;
+	}
+	return (1);
+}
+
+static int
+Fax4PostEncode(TIFF* tif)
+{
+	Fax3CodecState *sp = EncoderState(tif);
+
+	/* terminate strip w/ EOFB */
+	Fax3PutBits(tif, EOL, 12);
+	Fax3PutBits(tif, EOL, 12);
+	if (sp->bit != 8)
+		Fax3FlushBits(tif, sp);
+	return (1);
+}
+
+int
+TIFFInitCCITTFax4(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	if (InitCCITTFax3(tif)) {		/* reuse G3 support */
+		/*
+		 * Merge codec-specific tag information.
+		 */
+		if (!_TIFFMergeFields(tif, fax4Fields,
+				      TIFFArrayCount(fax4Fields))) {
+			TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax4",
+			"Merging CCITT Fax 4 codec-specific tags failed");
+			return 0;
+		}
+
+		tif->tif_decoderow = Fax4Decode;
+		tif->tif_decodestrip = Fax4Decode;
+		tif->tif_decodetile = Fax4Decode;
+		tif->tif_encoderow = Fax4Encode;
+		tif->tif_encodestrip = Fax4Encode;
+		tif->tif_encodetile = Fax4Encode;
+		tif->tif_postencode = Fax4PostEncode;
+		/*
+		 * Suppress RTC at the end of each strip.
+		 */
+		return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_NORTC);
+	} else
+		return (0);
+}
+
+/*
+ * CCITT Group 3 1-D Modified Huffman RLE Compression Support.
+ * (Compression algorithms 2 and 32771)
+ */
+
+/*
+ * Decode the requested amount of RLE-encoded data.
+ */
+static int
+Fax3DecodeRLE(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	DECLARE_STATE(tif, sp, "Fax3DecodeRLE");
+	int mode = sp->b.mode;
+	(void) s;
+	if (occ % sp->b.rowbytes)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (-1);
+	}
+	CACHE_STATE(tif, sp);
+	thisrun = sp->curruns;
+	while (occ > 0) {
+		a0 = 0;
+		RunLength = 0;
+		pa = thisrun;
+#ifdef FAX3_DEBUG
+		printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail);
+		printf("-------------------- %d\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);
+}
+
+int
+TIFFInitCCITTRLE(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	if (InitCCITTFax3(tif)) {		/* reuse G3 support */
+		tif->tif_decoderow = Fax3DecodeRLE;
+		tif->tif_decodestrip = Fax3DecodeRLE;
+		tif->tif_decodetile = Fax3DecodeRLE;
+		/*
+		 * Suppress RTC+EOLs when encoding and byte-align data.
+		 */
+		return TIFFSetField(tif, TIFFTAG_FAXMODE,
+		    FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_BYTEALIGN);
+	} else
+		return (0);
+}
+
+int
+TIFFInitCCITTRLEW(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	if (InitCCITTFax3(tif)) {		/* reuse G3 support */
+		tif->tif_decoderow = Fax3DecodeRLE;
+		tif->tif_decodestrip = Fax3DecodeRLE;
+		tif->tif_decodetile = Fax3DecodeRLE;  
+		/*
+		 * Suppress RTC+EOLs when encoding and word-align data.
+		 */
+		return TIFFSetField(tif, TIFFTAG_FAXMODE,
+		    FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_WORDALIGN);
+	} else
+		return (0);
+}
+#endif /* CCITT_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_fax3.h b/third_party/libtiff/tif_fax3.h
new file mode 100644
index 0000000..b0f46c9
--- /dev/null
+++ b/third_party/libtiff/tif_fax3.h
@@ -0,0 +1,538 @@
+/* $Id: tif_fax3.h,v 1.9 2011-03-10 20:23:07 fwarmerdam 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _FAX3_
+#define	_FAX3_
+/*
+ * TIFF Library.
+ *
+ * CCITT Group 3 (T.4) and Group 4 (T.6) Decompression Support.
+ *
+ * Decoder support is derived, with permission, from the code
+ * in Frank Cringle's viewfax program;
+ *      Copyright (C) 1990, 1995  Frank D. Cringle.
+ */
+#include "tiff.h"
+
+/*
+ * To override the default routine used to image decoded
+ * spans one can use the pseduo tag TIFFTAG_FAXFILLFUNC.
+ * The routine must have the type signature given below;
+ * for example:
+ *
+ * fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
+ *
+ * where buf is place to set the bits, runs is the array of b&w run
+ * lengths (white then black), erun is the last run in the array, and
+ * lastx is the width of the row in pixels.  Fill routines can assume
+ * the run array has room for at least lastx runs and can overwrite
+ * data in the run array as needed (e.g. to append zero runs to bring
+ * the count up to a nice multiple).
+ */
+typedef void (*TIFFFaxFillFunc)(unsigned char*, uint32*, uint32*, uint32);
+
+/*
+ * The default run filler; made external for other decoders.
+ */
+#if defined(__cplusplus)
+extern "C" {
+#endif
+extern void _TIFFFax3fillruns(unsigned char*, uint32*, uint32*, uint32);
+#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
+
+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 */
+} TIFFFaxTabEnt;
+
+extern const TIFFFaxTabEnt TIFFFaxMainTable[];
+extern const TIFFFaxTabEnt TIFFFaxWhiteTable[];
+extern const TIFFFaxTabEnt TIFFFaxBlackTable[];
+
+/*
+ * The following macros define the majority of the G3/G4 decoder
+ * algorithm using the state tables defined elsewhere.  To build
+ * a decoder you need some setup code and some glue code. Note
+ * that you may also need/want to change the way the NeedBits*
+ * macros get input data if, for example, you know the data to be
+ * decoded is properly aligned and oriented (doing so before running
+ * the decoder can be a big performance win).
+ *
+ * Consult the decoder in the TIFF library for an idea of what you
+ * need to define and setup to make use of these definitions.
+ *
+ * NB: to enable a debugging version of these macros define FAX3_DEBUG
+ *     before including this file.  Trace output goes to stdout.
+ */
+
+#ifndef EndOfData
+#define EndOfData()	(cp >= ep)
+#endif
+/*
+ * Need <=8 or <=16 bits of input data.  Unlike viewfax we
+ * cannot use/assume a word-aligned, properly bit swizzled
+ * input data set because data may come from an arbitrarily
+ * aligned, read-only source such as a memory-mapped file.
+ * Note also that the viewfax decoder does not check for
+ * running off the end of the input data buffer.  This is
+ * possible for G3-encoded data because it prescans the input
+ * data to count EOL markers, but can cause problems for G4
+ * data.  In any event, we don't prescan and must watch for
+ * running out of data since we can't permit the library to
+ * scan past the end of the input data buffer.
+ *
+ * Finally, note that we must handle remaindered data at the end
+ * of a strip specially.  The coder asks for a fixed number of
+ * bits when scanning for the next code.  This may be more bits
+ * than are actually present in the data stream.  If we appear
+ * to run out of data but still have some number of valid bits
+ * remaining then we makeup the requested amount with zeros and
+ * return successfully.  If the returned data is incorrect then
+ * we should be called again and get a premature EOF error;
+ * otherwise we should get the right answer.
+ */
+#ifndef NeedBits8
+#define NeedBits8(n,eoflab) do {					\
+    if (BitsAvail < (n)) {						\
+	if (EndOfData()) {						\
+	    if (BitsAvail == 0)			/* no valid bits */	\
+		goto eoflab;						\
+	    BitsAvail = (n);			/* pad with zeros */	\
+	} else {							\
+	    BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail;		\
+	    BitsAvail += 8;						\
+	}								\
+    }									\
+} while (0)
+#endif
+#ifndef NeedBits16
+#define NeedBits16(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++])<<BitsAvail;		\
+	    if ((BitsAvail += 8) < (n)) {				\
+		if (EndOfData()) {					\
+		    /* NB: we know BitsAvail is non-zero here */	\
+		    BitsAvail = (n);		/* pad with zeros */	\
+		} else {						\
+		    BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail;	\
+		    BitsAvail += 8;					\
+		}							\
+	    }								\
+	}								\
+    }									\
+} while (0)
+#endif
+#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    ",
+};
+#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0')
+#define LOOKUP8(wid,tab,eoflab) do {					\
+    int t;								\
+    NeedBits8(wid,eoflab);						\
+    TabEnt = tab + GetBits(wid);					\
+    printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail,		\
+	   StateNames[TabEnt->State], TabEnt->Param);			\
+    for (t = 0; t < TabEnt->Width; t++)					\
+	DEBUG_SHOW;							\
+    putchar('\n');							\
+    fflush(stdout);							\
+    ClrBits(TabEnt->Width);						\
+} while (0)
+#define LOOKUP16(wid,tab,eoflab) do {					\
+    int t;								\
+    NeedBits16(wid,eoflab);						\
+    TabEnt = tab + GetBits(wid);					\
+    printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail,		\
+	   StateNames[TabEnt->State], TabEnt->Param);			\
+    for (t = 0; t < TabEnt->Width; t++)					\
+	DEBUG_SHOW;							\
+    putchar('\n');							\
+    fflush(stdout);							\
+    ClrBits(TabEnt->Width);						\
+} while (0)
+
+#define SETVALUE(x) do {							\
+    *pa++ = RunLength + (x);						\
+    printf("SETVALUE: %d\t%d\n", RunLength + (x), a0);			\
+    a0 += x;								\
+    RunLength = 0;							\
+} while (0)
+#else
+#define LOOKUP8(wid,tab,eoflab) do {					\
+    NeedBits8(wid,eoflab);						\
+    TabEnt = tab + GetBits(wid);					\
+    ClrBits(TabEnt->Width);						\
+} while (0)
+#define LOOKUP16(wid,tab,eoflab) do {					\
+    NeedBits16(wid,eoflab);						\
+    TabEnt = tab + GetBits(wid);					\
+    ClrBits(TabEnt->Width);						\
+} while (0)
+
+/*
+ * Append a run to the run length array for the
+ * current row and reset decoding state.
+ */
+#define SETVALUE(x) do {							\
+    *pa++ = RunLength + (x);						\
+    a0 += (x);								\
+    RunLength = 0;							\
+} while (0)
+#endif
+
+/*
+ * Synchronize input decoding at the start of each
+ * row by scanning for an EOL (if appropriate) and
+ * skipping any trash data that might be present
+ * after a decoding error.  Note that the decoding
+ * done elsewhere that recognizes an EOL only consumes
+ * 11 consecutive zero bits.  This means that if EOLcnt
+ * is non-zero then we still need to scan for the final flag
+ * bit that is part of the EOL code.
+ */
+#define	SYNC_EOL(eoflab) do {						\
+    if (EOLcnt == 0) {							\
+	for (;;) {							\
+	    NeedBits16(11,eoflab);					\
+	    if (GetBits(11) == 0)					\
+		break;							\
+	    ClrBits(1);							\
+	}								\
+    }									\
+    for (;;) {								\
+	NeedBits8(8,eoflab);						\
+	if (GetBits(8))							\
+	    break;							\
+	ClrBits(8);							\
+    }									\
+    while (GetBits(1) == 0)						\
+	ClrBits(1);							\
+    ClrBits(1);				/* EOL bit */			\
+    EOLcnt = 0;				/* reset EOL counter/flag */	\
+} while (0)
+
+/*
+ * Cleanup the array of runs after decoding a row.
+ * We adjust final runs to insure the user buffer is not
+ * overwritten and/or undecoded area is white filled.
+ */
+#define	CLEANUP_RUNS() do {						\
+    if (RunLength)							\
+	SETVALUE(0);							\
+    if (a0 != lastx) {							\
+	badlength(a0, lastx);						\
+	while (a0 > lastx && pa > thisrun)				\
+	    a0 -= *--pa;						\
+	if (a0 < lastx) {						\
+	    if (a0 < 0)							\
+		a0 = 0;							\
+	    if ((pa-thisrun)&1)						\
+		SETVALUE(0);						\
+	    SETVALUE(lastx - a0);						\
+	} else if (a0 > lastx) {					\
+	    SETVALUE(lastx);						\
+	    SETVALUE(0);							\
+	}								\
+    }									\
+} while (0)
+
+/*
+ * Decode a line of 1D-encoded data.
+ *
+ * The line expanders are written as macros so that they can be reused
+ * but still have direct access to the local variables of the "calling"
+ * function.
+ *
+ * Note that unlike the original version we have to explicitly test for
+ * a0 >= lastx after each black/white run is decoded.  This is because
+ * the original code depended on the input data being zero-padded to
+ * insure the decoder recognized an EOL before running out of data.
+ */
+#define EXPAND1D(eoflab) do {						\
+    for (;;) {								\
+	for (;;) {							\
+	    LOOKUP16(12, TIFFFaxWhiteTable, eof1d);			\
+	    switch (TabEnt->State) {					\
+	    case S_EOL:							\
+		EOLcnt = 1;						\
+		goto done1d;						\
+	    case S_TermW:						\
+		SETVALUE(TabEnt->Param);					\
+		goto doneWhite1d;					\
+	    case S_MakeUpW:						\
+	    case S_MakeUp:						\
+		a0 += TabEnt->Param;					\
+		RunLength += TabEnt->Param;				\
+		break;							\
+	    default:							\
+		unexpected("WhiteTable", a0);				\
+		goto done1d;						\
+	    }								\
+	}								\
+    doneWhite1d:							\
+	if (a0 >= lastx)						\
+	    goto done1d;						\
+	for (;;) {							\
+	    LOOKUP16(13, TIFFFaxBlackTable, eof1d);			\
+	    switch (TabEnt->State) {					\
+	    case S_EOL:							\
+		EOLcnt = 1;						\
+		goto done1d;						\
+	    case S_TermB:						\
+		SETVALUE(TabEnt->Param);					\
+		goto doneBlack1d;					\
+	    case S_MakeUpB:						\
+	    case S_MakeUp:						\
+		a0 += TabEnt->Param;					\
+		RunLength += TabEnt->Param;				\
+		break;							\
+	    default:							\
+		unexpected("BlackTable", a0);				\
+		goto done1d;						\
+	    }								\
+	}								\
+    doneBlack1d:							\
+	if (a0 >= lastx)						\
+	    goto done1d;						\
+        if( *(pa-1) == 0 && *(pa-2) == 0 )				\
+            pa -= 2;                                                    \
+    }									\
+eof1d:									\
+    prematureEOF(a0);							\
+    CLEANUP_RUNS();							\
+    goto eoflab;							\
+done1d:									\
+    CLEANUP_RUNS();							\
+} while (0)
+
+/*
+ * Update the value of b1 using the array
+ * of runs for the reference line.
+ */
+#define CHECK_b1 do {							\
+    if (pa != thisrun) while (b1 <= a0 && b1 < lastx) {			\
+	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;							\
+	    if (b1 <= (int) (a0 + TabEnt->Param)) {			\
+		if (b1 < (int) (a0 + TabEnt->Param) || pa != thisrun) {	\
+		    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/third_party/libtiff/tif_fax3sm.c b/third_party/libtiff/tif_fax3sm.c
new file mode 100644
index 0000000..822191e
--- /dev/null
+++ b/third_party/libtiff/tif_fax3sm.c
@@ -0,0 +1,1260 @@
+/* WARNING, this file was automatically generated by the
+    mkg3states program */
+#include "tiff.h"
+#include "tif_fax3.h"
+ const TIFFFaxTabEnt TIFFFaxMainTable[128] = {
+{12,7,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},
+{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{5,6,2},{3,1,0},{5,3,1},{3,1,0},
+{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},
+{4,3,1},{3,1,0},{5,7,3},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},
+{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{4,6,2},{3,1,0},
+{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},
+{2,3,0},{3,1,0},{4,3,1},{3,1,0},{6,7,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},
+{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},
+{5,6,2},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},
+{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},{4,7,3},{3,1,0},{5,3,1},{3,1,0},
+{2,3,0},{3,1,0},{4,3,1},{3,1,0},{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},
+{4,3,1},{3,1,0},{4,6,2},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0},
+{1,4,0},{3,1,0},{5,3,1},{3,1,0},{2,3,0},{3,1,0},{4,3,1},{3,1,0}
+};
+ const TIFFFaxTabEnt TIFFFaxWhiteTable[4096] = {
+{12,11,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},
+{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},
+{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},
+{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1792},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},
+{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},
+{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},
+{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},
+{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},
+{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},
+{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},
+{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},
+{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},
+{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},
+{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},
+{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1856},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},
+{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},
+{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},
+{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},
+{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},
+{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},
+{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},
+{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},
+{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},
+{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{11,12,2112},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},
+{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},
+{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},
+{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},
+{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},
+{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},
+{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},
+{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2368},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},
+{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},
+{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},
+{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},
+{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},
+{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},
+{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},
+{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},
+{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},
+{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},
+{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},
+{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},
+{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{11,12,1984},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},
+{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},
+{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},
+{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},
+{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},
+{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},
+{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},
+{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1920},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},
+{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},
+{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},
+{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},
+{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},
+{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},
+{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},
+{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},
+{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},
+{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},
+{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},
+{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2240},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},
+{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},
+{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},
+{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},
+{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},
+{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},
+{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},
+{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},
+{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},
+{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{11,12,2496},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},
+{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},
+{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},
+{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{12,11,0},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},
+{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},
+{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},
+{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},
+{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1792},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},
+{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},
+{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},
+{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},
+{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},
+{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},
+{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},
+{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},
+{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},
+{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},
+{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},
+{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},
+{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{11,11,1856},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},
+{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},
+{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},
+{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},
+{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},
+{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},
+{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},{7,8,31},{7,5,8},
+{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2176},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},
+{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},
+{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1600},{7,4,5},
+{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},
+{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},
+{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},
+{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},
+{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},{7,8,43},{7,6,17},
+{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},
+{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},
+{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,768},{7,4,6},
+{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2432},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},{7,7,19},{7,5,8},
+{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},
+{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},{9,9,1408},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},
+{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},
+{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},
+{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},
+{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},
+{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,960},{7,4,6},
+{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},
+{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{11,12,2048},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},
+{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},
+{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},{7,8,32},{7,5,8},
+{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},
+{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},
+{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1536},{7,4,5},
+{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},
+{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,11,1920},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},
+{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,896},{7,4,6},
+{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},
+{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},
+{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},{7,8,44},{7,6,17},
+{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},
+{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},
+{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},
+{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},
+{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},
+{7,8,55},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},
+{7,8,53},{7,5,9},{9,8,448},{7,4,6},{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1472},{7,4,5},{7,8,43},{7,6,17},{9,9,1216},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},
+{7,8,61},{7,4,4},{7,4,2},{7,4,7},{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},
+{9,9,960},{7,4,6},{7,8,31},{7,5,8},{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,9,704},{7,4,6},{7,8,37},{9,5,128},
+{7,7,25},{7,6,15},{9,8,320},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},
+{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{11,12,2304},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,7,20},{9,5,128},{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},
+{7,7,27},{7,4,5},{7,8,40},{7,6,16},{9,9,832},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},
+{9,8,512},{7,4,6},{7,8,36},{9,5,128},{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{9,9,1600},{7,4,5},{7,8,44},{7,6,17},{9,9,1344},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},
+{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},
+{7,4,2},{7,4,7},{7,8,48},{7,4,3},{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1088},{7,4,6},
+{7,8,32},{7,5,8},{7,8,58},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},
+{7,5,11},{7,4,5},{7,7,26},{7,5,9},{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},
+{9,8,384},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},
+{9,7,256},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{0,0,0},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},
+{7,7,24},{7,6,14},{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},
+{7,8,39},{7,6,16},{9,8,576},{7,4,6},{7,7,19},{7,5,8},{7,8,55},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,45},{7,4,3},{7,5,11},{7,4,5},{7,8,53},{7,5,9},{9,8,448},{7,4,6},
+{7,8,35},{9,5,128},{7,8,51},{7,6,15},{7,8,63},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},
+{9,9,1536},{7,4,5},{7,8,43},{7,6,17},{9,9,1280},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,8,29},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},
+{9,6,1664},{7,4,6},{7,8,33},{9,5,128},{7,8,49},{7,6,14},{7,8,61},{7,4,4},{7,4,2},{7,4,7},
+{7,8,47},{7,4,3},{7,8,59},{7,4,5},{7,8,41},{7,6,16},{9,9,1024},{7,4,6},{7,8,31},{7,5,8},
+{7,8,57},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},
+{7,7,26},{7,5,9},{9,9,768},{7,4,6},{7,8,37},{9,5,128},{7,7,25},{7,6,15},{9,8,320},{7,4,4},
+{7,4,2},{7,4,7},{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},
+{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},{11,12,2560},{7,4,3},
+{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},{7,7,20},{9,5,128},{7,7,24},{7,6,14},
+{7,7,28},{7,4,4},{7,4,2},{7,4,7},{7,7,23},{7,4,3},{7,7,27},{7,4,5},{7,8,40},{7,6,16},
+{9,9,896},{7,4,6},{7,7,19},{7,5,8},{7,8,56},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7},
+{7,8,46},{7,4,3},{7,5,11},{7,4,5},{7,8,54},{7,5,9},{9,8,512},{7,4,6},{7,8,36},{9,5,128},
+{7,8,52},{7,6,15},{7,8,0},{7,4,4},{7,4,2},{7,4,7},{7,6,13},{7,4,3},{9,9,1728},{7,4,5},
+{7,8,44},{7,6,17},{9,9,1408},{7,4,6},{7,6,1},{7,5,8},{9,6,192},{9,5,64},{7,5,10},{7,4,4},
+{7,4,2},{7,4,7},{7,8,30},{7,4,3},{7,5,11},{7,4,5},{7,6,12},{7,5,9},{9,6,1664},{7,4,6},
+{7,8,34},{9,5,128},{7,8,50},{7,6,14},{7,8,62},{7,4,4},{7,4,2},{7,4,7},{7,8,48},{7,4,3},
+{7,8,60},{7,4,5},{7,8,42},{7,6,16},{9,9,1152},{7,4,6},{7,8,32},{7,5,8},{7,8,58},{9,5,64},
+{7,5,10},{7,4,4},{7,4,2},{7,4,7},{7,7,22},{7,4,3},{7,5,11},{7,4,5},{7,7,26},{7,5,9},
+{9,8,640},{7,4,6},{7,8,38},{9,5,128},{7,7,25},{7,6,15},{9,8,384},{7,4,4},{7,4,2},{7,4,7},
+{7,6,13},{7,4,3},{7,7,18},{7,4,5},{7,7,21},{7,6,17},{9,7,256},{7,4,6},{7,6,1},{7,5,8},
+{9,6,192},{9,5,64},{7,5,10},{7,4,4},{7,4,2},{7,4,7}
+};
+ const TIFFFaxTabEnt TIFFFaxBlackTable[8192] = {
+{12,11,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,23},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,11,25},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,128},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,56},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,30},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,57},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,11,21},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,54},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,52},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,48},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,12,2112},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,44},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,36},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,384},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,28},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,60},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,40},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2368},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,12,1984},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,50},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,34},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1664},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,26},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1408},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,32},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,61},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,42},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,13,1024},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,13,768},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,62},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2240},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,46},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,38},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,512},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,19},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,12,2496},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,25},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,12,192},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1280},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,31},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,58},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,21},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,896},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,640},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,49},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2176},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,45},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,37},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,12,448},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,29},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,13,1536},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,41},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2432},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,12,2048},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,51},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,35},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,320},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,27},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,59},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,33},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,256},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,43},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,13,1152},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,55},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,63},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,12,2304},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,47},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,39},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,53},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2560},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,25},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,12,128},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,56},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,30},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,11,1856},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,57},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,21},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,54},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,52},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,48},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2112},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,44},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,36},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,12,384},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,28},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,60},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,40},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,12,2368},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,1984},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,50},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,34},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,13,1728},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,26},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,13,1472},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,32},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,61},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,42},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1088},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,832},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,62},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,12,2240},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,46},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,38},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,576},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2496},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{12,11,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,18},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,11,1792},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,23},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,20},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,25},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,192},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1344},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,31},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,11,1856},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,58},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,21},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{10,13,960},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,13,704},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,49},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2176},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,45},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,37},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,448},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,29},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1600},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,41},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{11,12,2432},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,18},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,17},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2048},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,51},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,35},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{10,12,320},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,27},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,59},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,33},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{11,11,1920},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,12,256},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,43},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,13,1216},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{0,0,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,8,13},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,9,15},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,55},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,63},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2304},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,12,47},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,12,39},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,12,53},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,12},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{0,0,0},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,8,13},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,11,19},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,11,24},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,11,22},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{11,12,2560},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,7,10},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,10,16},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2},{8,10,0},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},
+{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{10,10,64},{8,2,3},
+{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,9},{8,2,3},{8,3,1},{8,2,2},
+{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,11},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},
+{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},
+{8,8,14},{8,2,3},{8,3,1},{8,2,2},{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,6,8},{8,2,3},
+{8,3,1},{8,2,2},{8,4,5},{8,2,3},{8,3,4},{8,2,2},{8,7,12},{8,2,3},{8,3,1},{8,2,2},
+{8,4,6},{8,2,3},{8,3,4},{8,2,2},{8,5,7},{8,2,3},{8,3,1},{8,2,2},{8,4,5},{8,2,3},
+{8,3,4},{8,2,2}
+};
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_flush.c b/third_party/libtiff/tif_flush.c
new file mode 100644
index 0000000..fd14e4c
--- /dev/null
+++ b/third_party/libtiff/tif_flush.c
@@ -0,0 +1,118 @@
+/* $Id: tif_flush.c,v 1.9 2010-03-31 06:40:10 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#include "tiffiop.h"
+
+int
+TIFFFlush(TIFF* tif)
+{
+    if( tif->tif_mode == O_RDONLY )
+        return 1;
+
+    if (!TIFFFlushData(tif))
+        return (0);
+                
+    /* In update (r+) mode we try to detect the case where 
+       only the strip/tile map has been altered, and we try to 
+       rewrite only that portion of the directory without 
+       making any other changes */
+                
+    if( (tif->tif_flags & TIFF_DIRTYSTRIP)
+        && !(tif->tif_flags & TIFF_DIRTYDIRECT) 
+        && tif->tif_mode == O_RDWR )
+    {
+        uint64  *offsets=NULL, *sizes=NULL;
+
+        if( TIFFIsTiled(tif) )
+        {
+            if( TIFFGetField( tif, TIFFTAG_TILEOFFSETS, &offsets ) 
+                && TIFFGetField( tif, TIFFTAG_TILEBYTECOUNTS, &sizes ) 
+                && _TIFFRewriteField( tif, TIFFTAG_TILEOFFSETS, TIFF_LONG8, 
+                                      tif->tif_dir.td_nstrips, offsets )
+                && _TIFFRewriteField( tif, TIFFTAG_TILEBYTECOUNTS, TIFF_LONG8, 
+                                      tif->tif_dir.td_nstrips, sizes ) )
+            {
+                tif->tif_flags &= ~TIFF_DIRTYSTRIP;
+                tif->tif_flags &= ~TIFF_BEENWRITING;
+                return 1;
+            }
+        }
+        else
+        {
+            if( TIFFGetField( tif, TIFFTAG_STRIPOFFSETS, &offsets ) 
+                && TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &sizes ) 
+                && _TIFFRewriteField( tif, TIFFTAG_STRIPOFFSETS, TIFF_LONG8, 
+                                      tif->tif_dir.td_nstrips, offsets )
+                && _TIFFRewriteField( tif, TIFFTAG_STRIPBYTECOUNTS, TIFF_LONG8, 
+                                      tif->tif_dir.td_nstrips, sizes ) )
+            {
+                tif->tif_flags &= ~TIFF_DIRTYSTRIP;
+                tif->tif_flags &= ~TIFF_BEENWRITING;
+                return 1;
+            }
+        }
+    }
+
+    if ((tif->tif_flags & (TIFF_DIRTYDIRECT|TIFF_DIRTYSTRIP)) 
+        && !TIFFRewriteDirectory(tif))
+        return (0);
+
+    return (1);
+}
+
+/*
+ * Flush buffered data to the file.
+ *
+ * Frank Warmerdam'2000: I modified this to return 1 if TIFF_BEENWRITING
+ * is not set, so that TIFFFlush() will proceed to write out the directory.
+ * The documentation says returning 1 is an error indicator, but not having
+ * been writing isn't exactly a an error.  Hopefully this doesn't cause
+ * problems for other people. 
+ */
+int
+TIFFFlushData(TIFF* tif)
+{
+	if ((tif->tif_flags & TIFF_BEENWRITING) == 0)
+		return (1);
+	if (tif->tif_flags & TIFF_POSTENCODE) {
+		tif->tif_flags &= ~TIFF_POSTENCODE;
+		if (!(*tif->tif_postencode)(tif))
+			return (0);
+	}
+	return (TIFFFlushData1(tif));
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_getimage.c b/third_party/libtiff/tif_getimage.c
new file mode 100644
index 0000000..f49b73f
--- /dev/null
+++ b/third_party/libtiff/tif_getimage.c
@@ -0,0 +1,2928 @@
+/* $Id: tif_getimage.c,v 1.90 2015-06-17 01:34:08 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 
+ * 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
+ *
+ * Read and return a packed RGBA image.
+ */
+#include "tiffiop.h"
+#include <stdio.h>
+
+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 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
+
+/*
+ * Color conversion constants. We will define display types here.
+ */
+
+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 */
+};
+
+/*
+ * Check the image to see if TIFFReadRGBAImage can deal with it.
+ * 1/0 is returned according to whether or not the image can
+ * 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);
+			}
+			if( td->td_samplesperpixel != 3 )
+            {
+                sprintf(emsg,
+                        "Sorry, can not handle image with %s=%d",
+                        "Samples/pixel", td->td_samplesperpixel);
+                return 0;
+            }
+			break;
+		case PHOTOMETRIC_CIELAB:
+            if( td->td_samplesperpixel != 3 || td->td_bitspersample != 8 )
+            {
+                sprintf(emsg,
+                        "Sorry, can not handle image with %s=%d and %s=%d",
+                        "Samples/pixel", td->td_samplesperpixel,
+                        "Bits/sample", td->td_bitspersample);
+                return 0;
+            }
+			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->UaToAa)
+		_TIFFfree(img->UaToAa), img->UaToAa = NULL;
+	if (img->Bitdepth16To8)
+		_TIFFfree(img->Bitdepth16To8), img->Bitdepth16To8 = NULL;
+
+	if( img->redcmap ) {
+		_TIFFfree( img->redcmap );
+		_TIFFfree( img->greencmap );
+		_TIFFfree( img->bluecmap );
+                img->redcmap = img->greencmap = img->bluecmap = NULL;
+	}
+}
+
+static int
+isCCITTCompression(TIFF* tif)
+{
+    uint16 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);
+			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;
+	}
+#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);
+                                goto fail_return;
+		}
+	}
+	switch (img->photometric) {
+		case PHOTOMETRIC_PALETTE:
+			if (!TIFFGetField(tif, TIFFTAG_COLORMAP,
+			    &red_orig, &green_orig, &blue_orig)) {
+				sprintf(emsg, "Missing required \"Colormap\" tag");
+                                goto fail_return;
+			}
+
+			/* 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");
+                                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 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);
+                                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 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);
+                                goto fail_return;
+			}
+			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);
+                                        goto fail_return;
+				}
+				if (img->samplesperpixel < 4) {
+					sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
+					    "Samples/pixel", img->samplesperpixel);
+                                        goto fail_return;
+				}
+			}
+			break;
+		case PHOTOMETRIC_LOGL:
+			if (compress != COMPRESSION_SGILOG) {
+				sprintf(emsg, "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) {
+				sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d",
+				    "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24);
+                                goto fail_return;
+			}
+			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);
+                        goto fail_return;
+	}
+	img->Map = NULL;
+	img->BWmap = NULL;
+	img->PALmap = NULL;
+	img->ycbcr = NULL;
+	img->cielab = NULL;
+	img->UaToAa = NULL;
+	img->Bitdepth16To8 = NULL;
+	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)) {
+			sprintf(emsg, "Sorry, can not handle image");
+			goto fail_return;
+		}
+	} else {
+		if (!PickSeparateCase(img)) {
+			sprintf(emsg, "Sorry, can not handle image");
+			goto fail_return;
+		}
+	}
+	return 1;
+
+  fail_return:
+        _TIFFfree( img->redcmap );
+        _TIFFfree( img->greencmap );
+        _TIFFfree( img->bluecmap );
+        img->redcmap = img->greencmap = img->bluecmap = NULL;
+        return 0;
+}
+
+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);
+    }
+    return (*img->get)(img, raster, w, 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)
+{
+    char emsg[1024] = "";
+    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;
+    }
+    return (ok);
+}
+
+/*
+ * 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;
+	}
+}
+
+/*
+ * Get an tile-organized image that has
+ *	PlanarConfiguration contiguous if SamplesPerPixel > 1
+ * or
+ *	SamplesPerPixel == 1
+ */	
+static int
+gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+    TIFF* tif = img->tif;
+    tileContigRoutine put = img->put.contig;
+    uint32 col, row, y, rowstoread;
+    tmsize_t pos;
+    uint32 tw, th;
+    unsigned char* buf;
+    int32 fromskew, toskew;
+    uint32 nrow;
+    int ret = 1, flip;
+    uint32 this_tw, tocol;
+    int32 this_toskew, leftmost_toskew;
+    int32 leftmost_fromskew;
+    uint32 leftmost_tw;
+
+    buf = (unsigned char*) _TIFFmalloc(TIFFTileSize(tif));
+    if (buf == 0) {
+		TIFFErrorExt(tif->tif_clientdata, 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);
+    }
+    else {
+	    y = 0;
+	    toskew = -(int32)(tw - w);
+    }
+     
+    /*
+     *	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; 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 (TIFFReadTile(tif, buf, col,  
+			     row+img->row_offset, 0, 0)==(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;
+	    }
+	    (*put)(img, raster+y*w+tocol, 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);
+    }
+    _TIFFfree(buf);
+
+    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--;
+		    }
+	    }
+    }
+
+    return (ret);
+}
+
+/*
+ * Get an tile-organized image that has
+ *	 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;
+	tmsize_t pos;
+	uint32 tw, th;
+	unsigned char* buf;
+	unsigned char* p0;
+	unsigned char* p1;
+	unsigned char* p2;
+	unsigned char* pa;
+	tmsize_t tilesize;
+	tmsize_t bufsize;
+	int32 fromskew, toskew;
+	int alpha = img->alpha;
+	uint32 nrow;
+	int ret = 1, flip;
+        int colorchannels;
+	uint32 this_tw, tocol;
+	int32 this_toskew, leftmost_toskew;
+	int32 leftmost_fromskew;
+	uint32 leftmost_tw;
+
+	tilesize = TIFFTileSize(tif);  
+	bufsize = TIFFSafeMultiply(tmsize_t,alpha?4:3,tilesize);
+	if (bufsize == 0) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtTileSeparate");
+		return (0);
+	}
+	buf = (unsigned char*) _TIFFmalloc(bufsize);
+	if (buf == 0) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", "No space for tile buffer");
+		return (0);
+	}
+	_TIFFmemset(buf, 0, bufsize);
+	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);
+	}
+
+        switch( img->photometric )
+        {
+          case PHOTOMETRIC_MINISWHITE:
+          case PHOTOMETRIC_MINISBLACK:
+          case PHOTOMETRIC_PALETTE:
+            colorchannels = 1;
+            p2 = p1 = p0;
+            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; 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 (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;
+			}
+			(*put)(img, raster+y*w+tocol, 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) 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);
+}
+
+/*
+ * Get a strip-organized image that has
+ *	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;
+	tmsize_t pos;
+	unsigned char* buf;
+	uint32 rowsperstrip;
+	uint16 subsamplinghor,subsamplingver;
+	uint32 imagewidth = img->width;
+	tmsize_t scanline;
+	int32 fromskew, toskew;
+	int ret = 1, flip;
+
+	TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver);
+	if( subsamplingver == 0 ) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Invalid vertical YCbCr subsampling");
+		return (0);
+	}
+
+	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);
+
+	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);
+		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)==(tmsize_t)(-1)
+		    && img->stoponerr)
+		{
+			ret = 0;
+			break;
+		}
+
+		pos = ((row + img->row_offset) % rowsperstrip) * scanline + \
+			((tmsize_t) img->col_offset * img->samplesperpixel);
+		(*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);
+}
+
+/*
+ * Get a strip-organized image with
+ *	 SamplesPerPixel > 1
+ *	 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;
+	tmsize_t pos;
+	tmsize_t scanline;
+	uint32 rowsperstrip, offset_row;
+	uint32 imagewidth = img->width;
+	tmsize_t stripsize;
+	tmsize_t bufsize;
+	int32 fromskew, toskew;
+	int alpha = img->alpha;
+	int ret = 1, flip, colorchannels;
+
+	stripsize = TIFFStripSize(tif);  
+	bufsize = TIFFSafeMultiply(tmsize_t,alpha?4:3,stripsize);
+	if (bufsize == 0) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtStripSeparate");
+		return (0);
+	}
+	p0 = buf = (unsigned char *)_TIFFmalloc(bufsize);
+	if (buf == 0) {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+		return (0);
+	}
+	_TIFFmemset(buf, 0, bufsize);
+	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);
+	}
+
+        switch( img->photometric )
+        {
+          case PHOTOMETRIC_MINISWHITE:
+          case PHOTOMETRIC_MINISBLACK:
+          case PHOTOMETRIC_PALETTE:
+            colorchannels = 1;
+            p2 = p1 = p0;
+            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)
+	{
+		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)==(tmsize_t)(-1)
+		    && img->stoponerr)
+		{
+			ret = 0;
+			break;
+		}
+		if (colorchannels > 1 
+                    && TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1),
+                                            p1, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) == (tmsize_t)(-1)
+		    && img->stoponerr)
+		{
+			ret = 0;
+			break;
+		}
+		if (colorchannels > 1 
+                    && TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2),
+                                            p2, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) == (tmsize_t)(-1)
+		    && img->stoponerr)
+		{
+			ret = 0;
+			break;
+		}
+		if (alpha)
+		{
+			if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, colorchannels),
+			    pa, ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1)
+			    && img->stoponerr)
+			{
+				ret = 0;
+				break;
+			}
+		}
+
+		pos = ((row + img->row_offset) % rowsperstrip) * scanline + \
+			((tmsize_t) img->col_offset * img->samplesperpixel);
+		(*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);
+}
+
+/*
+ * The following routines move decoded data returned
+ * from the TIFF library into rasters filled with packed
+ * ABGR pixels (i.e. suitable for passing to lrecwrite.)
+ *
+ * The routines have been created according to the most
+ * important cases and optimized.  PickContigCase and
+ * 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)
+/* TODO: PACKW should have be made redundant in favor of Bitdepth16To8 LUT */
+#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 \
+)
+
+/*
+ * 8-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put8bitcmaptile)
+{
+    uint32** PALmap = img->PALmap;
+    int samplesperpixel = img->samplesperpixel;
+
+    (void) y;
+    while (h-- > 0) {
+	for (x = w; x-- > 0;)
+        {
+	    *cp++ = PALmap[*pp][0];
+            pp += samplesperpixel;
+        }
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 4-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put4bitcmaptile)
+{
+    uint32** PALmap = img->PALmap;
+
+    (void) x; (void) y;
+    fromskew /= 2;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 2-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put2bitcmaptile)
+{
+    uint32** PALmap = img->PALmap;
+
+    (void) x; (void) y;
+    fromskew /= 4;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 1-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put1bitcmaptile)
+{
+    uint32** PALmap = img->PALmap;
+
+    (void) x; (void) y;
+    fromskew /= 8;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 8-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(putgreytile)
+{
+    int samplesperpixel = img->samplesperpixel;
+    uint32** BWmap = img->BWmap;
+
+    (void) y;
+    while (h-- > 0) {
+	for (x = w; x-- > 0;)
+        {
+	    *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** BWmap = img->BWmap;
+
+    (void) y;
+    while (h-- > 0) {
+	for (x = w; x-- > 0;)
+        {
+            *cp++ = BWmap[*pp][0] & (*(pp+1) << 24 | ~A1);
+            pp += samplesperpixel;
+        }
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 16-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(put16bitbwtile)
+{
+    int samplesperpixel = img->samplesperpixel;
+    uint32** BWmap = img->BWmap;
+
+    (void) y;
+    while (h-- > 0) {
+        uint16 *wp = (uint16 *) pp;
+
+	for (x = w; x-- > 0;)
+        {
+            /* use high order byte of 16bit value */
+
+	    *cp++ = BWmap[*wp >> 8][0];
+            pp += 2 * samplesperpixel;
+            wp += samplesperpixel;
+        }
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 1-bit bilevel => colormap/RGB
+ */
+DECLAREContigPutFunc(put1bitbwtile)
+{
+    uint32** BWmap = img->BWmap;
+
+    (void) x; (void) y;
+    fromskew /= 8;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 2-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(put2bitbwtile)
+{
+    uint32** BWmap = img->BWmap;
+
+    (void) x; (void) y;
+    fromskew /= 4;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 4-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(put4bitbwtile)
+{
+    uint32** BWmap = img->BWmap;
+
+    (void) x; (void) y;
+    fromskew /= 2;
+    while (h-- > 0) {
+	uint32* bw;
+	UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++);
+	cp += toskew;
+	pp += fromskew;
+    }
+}
+
+/*
+ * 8-bit packed samples, no Map => RGB
+ */
+DECLAREContigPutFunc(putRGBcontig8bittile)
+{
+    int samplesperpixel = img->samplesperpixel;
+
+    (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;
+    }
+}
+
+/*
+ * 8-bit packed samples => RGBA w/ associated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBAAcontig8bittile)
+{
+    int samplesperpixel = img->samplesperpixel;
+
+    (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;
+    }
+}
+
+/*
+ * 8-bit packed samples => RGBA w/ unassociated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBUAcontig8bittile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	(void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		uint32 r, g, b, a;
+		uint8* m;
+		for (x = w; x-- > 0;) {
+			a = pp[3];
+			m = img->UaToAa+(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;
+	}
+}
+
+/*
+ * 16-bit packed samples => RGB
+ */
+DECLAREContigPutFunc(putRGBcontig16bittile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	uint16 *wp = (uint16 *)pp;
+	(void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		for (x = w; x-- > 0;) {
+			*cp++ = PACK(img->Bitdepth16To8[wp[0]],
+			    img->Bitdepth16To8[wp[1]],
+			    img->Bitdepth16To8[wp[2]]);
+			wp += samplesperpixel;
+		}
+		cp += toskew;
+		wp += fromskew;
+	}
+}
+
+/*
+ * 16-bit packed samples => RGBA w/ associated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBAAcontig16bittile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	uint16 *wp = (uint16 *)pp;
+	(void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		for (x = w; x-- > 0;) {
+			*cp++ = PACK4(img->Bitdepth16To8[wp[0]],
+			    img->Bitdepth16To8[wp[1]],
+			    img->Bitdepth16To8[wp[2]],
+			    img->Bitdepth16To8[wp[3]]);
+			wp += samplesperpixel;
+		}
+		cp += toskew;
+		wp += fromskew;
+	}
+}
+
+/*
+ * 16-bit packed samples => RGBA w/ unassociated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBUAcontig16bittile)
+{
+	int samplesperpixel = img->samplesperpixel;
+	uint16 *wp = (uint16 *)pp;
+	(void) y;
+	fromskew *= samplesperpixel;
+	while (h-- > 0) {
+		uint32 r,g,b,a;
+		uint8* m;
+		for (x = w; x-- > 0;) {
+			a = img->Bitdepth16To8[wp[3]];
+			m = img->UaToAa+(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;
+	}
+}
+
+/*
+ * 8-bit packed CMYK samples w/o Map => RGB
+ *
+ * NB: The conversion of CMYK->RGB is *very* crude.
+ */
+DECLAREContigPutFunc(putRGBcontig8bitCMYKtile)
+{
+    int samplesperpixel = img->samplesperpixel;
+    uint16 r, g, b, k;
+
+    (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;
+    }
+}
+
+/*
+ * 8-bit packed CMYK samples w/Map => RGB
+ *
+ * NB: The conversion of CMYK->RGB is *very* crude.
+ */
+DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile)
+{
+    int samplesperpixel = img->samplesperpixel;
+    TIFFRGBValue* Map = img->Map;
+    uint16 r, g, b, k;
+
+    (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\
+)
+
+/*
+ * 8-bit unpacked samples => RGB
+ */
+DECLARESepPutFunc(putRGBseparate8bittile)
+{
+    (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;
+    }
+}
+
+/*
+ * 8-bit unpacked samples => RGBA w/ associated alpha
+ */
+DECLARESepPutFunc(putRGBAAseparate8bittile)
+{
+	(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;
+	}
+}
+
+/*
+ * 8-bit unpacked CMYK samples => RGBA
+ */
+DECLARESepPutFunc(putCMYKseparate8bittile)
+{
+	(void) img; (void) y;
+	while (h-- > 0) {
+		uint32 rv, gv, bv, kv;
+		for (x = w; x-- > 0;) {
+			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;
+	}
+}
+
+/*
+ * 8-bit unpacked samples => RGBA w/ unassociated alpha
+ */
+DECLARESepPutFunc(putRGBUAseparate8bittile)
+{
+	(void) img; (void) y;
+	while (h-- > 0) {
+		uint32 rv, gv, bv, av;
+		uint8* m;
+		for (x = w; x-- > 0;) {
+			av = *a++;
+			m = img->UaToAa+(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;
+	}
+}
+
+/*
+ * 16-bit unpacked samples => RGB
+ */
+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++ = PACK(img->Bitdepth16To8[*wr++],
+			    img->Bitdepth16To8[*wg++],
+			    img->Bitdepth16To8[*wb++]);
+		SKEW(wr, wg, wb, fromskew);
+		cp += toskew;
+	}
+}
+
+/*
+ * 16-bit unpacked samples => RGBA w/ associated alpha
+ */
+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++ = PACK4(img->Bitdepth16To8[*wr++],
+			    img->Bitdepth16To8[*wg++],
+			    img->Bitdepth16To8[*wb++],
+			    img->Bitdepth16To8[*wa++]);
+		SKEW4(wr, wg, wb, wa, fromskew);
+		cp += toskew;
+	}
+}
+
+/*
+ * 16-bit unpacked samples => RGBA w/ unassociated alpha
+ */
+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;
+		uint8* m;
+		for (x = w; x-- > 0;) {
+			a = img->Bitdepth16To8[*wa++];
+			m = img->UaToAa+(a<<8);
+			r = m[img->Bitdepth16To8[*wr++]];
+			g = m[img->Bitdepth16To8[*wg++]];
+			b = m[img->Bitdepth16To8[*wb++]];
+			*cp++ = PACK4(r,g,b,a);
+		}
+		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;
+	}
+}
+
+/*
+ * YCbCr -> RGB conversion and packing routines.
+ */
+
+#define	YCbCrtoRGB(dst, Y) {						\
+	uint32 r, g, b;							\
+	TIFFYCbCrtoRGB(img->ycbcr, (Y), Cb, Cr, &r, &g, &b);		\
+	dst = PACK(r, g, b);						\
+}
+
+/*
+ * 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.
+ */
+#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;
+    }
+}
+#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;
+
+    (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]);
+                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;
+        }
+    } 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 */
+                }
+                if (x < 4) {
+                    cp += x; cp1 += x; cp2 += x; cp3 += x;
+                    x = 0;
+                }
+                else {
+                    cp += 4; cp1 += 4; cp2 += 4; cp3 += 4;
+                    x -= 4;
+                }
+                pp += 18;
+            }
+            if (h <= 4)
+                break;
+            h -= 4;
+            cp += incr, cp1 += incr, cp2 += incr, cp3 += incr;
+            pp += fromskew;
+        }
+    }
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 4,2 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr42tile)
+{
+    uint32* cp1 = cp+w+toskew;
+    int32 incr = 2*toskew+w;
+
+    (void) y;
+    fromskew = (fromskew * 10) / 4;
+    if ((w & 3) == 0 && (h & 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]);
+                YCbCrtoRGB(cp1[0], pp[4]);
+                YCbCrtoRGB(cp1[1], pp[5]);
+                YCbCrtoRGB(cp1[2], pp[6]);
+                YCbCrtoRGB(cp1[3], pp[7]);
+                
+                cp += 4, cp1 += 4;
+                pp += 10;
+            } while (--x);
+            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 */
+                }
+                if (x < 4) {
+                    cp += x; cp1 += x;
+                    x = 0;
+                }
+                else {
+                    cp += 4; cp1 += 4;
+                    x -= 4;
+                }
+                pp += 10;
+            }
+            if (h <= 2)
+                break;
+            h -= 2;
+            cp += incr, cp1 += incr;
+            pp += fromskew;
+        }
+    }
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 4,1 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr41tile)
+{
+    (void) y;
+    /* XXX adjust fromskew */
+    do {
+	x = w>>2;
+	while(x>0) {
+	    int32 Cb = pp[4];
+	    int32 Cr = pp[5];
+
+	    YCbCrtoRGB(cp [0], pp[0]);
+	    YCbCrtoRGB(cp [1], pp[1]);
+	    YCbCrtoRGB(cp [2], pp[2]);
+	    YCbCrtoRGB(cp [3], pp[3]);
+
+	    cp += 4;
+	    pp += 6;
+		x--;
+	}
+
+        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;
+            }
+
+            cp += (w&3);
+            pp += 6;
+        }
+
+	cp += toskew;
+	pp += fromskew;
+    } while (--h);
+
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr22tile)
+{
+	uint32* cp2;
+	int32 incr = 2*toskew+w;
+	(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 += incr;
+		cp2 += incr;
+		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]);
+		}
+	}
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 2,1 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr21tile)
+{
+	(void) y;
+	fromskew = (fromskew * 4) / 2;
+	do {
+		x = w>>1;
+		while(x>0) {
+			int32 Cb = pp[2];
+			int32 Cr = pp[3];
+
+			YCbCrtoRGB(cp[0], pp[0]);
+			YCbCrtoRGB(cp[1], pp[1]);
+
+			cp += 2;
+			pp += 4;
+			x --;
+		}
+
+		if( (w&1) != 0 )
+		{
+			int32 Cb = pp[2];
+			int32 Cr = pp[3];
+
+			YCbCrtoRGB(cp[0], pp[0]);
+
+			cp += 1;
+			pp += 4;
+		}
+
+		cp += toskew;
+		pp += fromskew;
+	} while (--h);
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 1,2 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr12tile)
+{
+	uint32* cp2;
+	int32 incr = 2*toskew+w;
+	(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 += incr;
+		cp2 += incr;
+		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);
+	}
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ no subsampling => RGB
+ */
+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];
+
+			YCbCrtoRGB(*cp++, pp[0]);
+
+			pp += 3;
+		} while (--x);
+		cp += toskew;
+		pp += fromskew;
+	} while (--h);
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ no subsampling => RGB
+ */
+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;
+	}
+}
+#undef YCbCrtoRGB
+
+static int
+initYCbCrConversion(TIFFRGBAImage* img)
+{
+	static const char module[] = "initYCbCrConversion";
+
+	float *luma, *refBlackWhite;
+
+	if (img->ycbcr == NULL) {
+		img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc(
+		    TIFFroundup_32(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 const 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;
+}
+
+/*
+ * Greyscale images with less than 8 bits/sample are handled
+ * with a table to avoid lots of shifts and masks.  The table
+ * is setup so that put*bwtile (below) can retrieve 8/bitspersample
+ * pixel values simply by indexing into the table with one
+ * number.
+ */
+static int
+makebwmap(TIFFRGBAImage* img)
+{
+    TIFFRGBValue* Map = img->Map;
+    int bitspersample = img->bitspersample;
+    int nsamples = 8 / bitspersample;
+    int i;
+    uint32* p;
+
+    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
+    }
+    return (1);
+}
+
+/*
+ * 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)
+{
+    int32 x, range;
+
+    range = (int32)((1L<<img->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 &&
+	(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;
+    }
+    return (1);
+}
+
+static int
+checkcmap(TIFFRGBAImage* img)
+{
+    uint16* r = img->redcmap;
+    uint16* g = img->greencmap;
+    uint16* b = img->bluecmap;
+    long n = 1L<<img->bitspersample;
+
+    while (n-- > 0)
+	if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
+	    return (16);
+    return (8);
+}
+
+static void
+cvtcmap(TIFFRGBAImage* img)
+{
+    uint16* r = img->redcmap;
+    uint16* g = img->greencmap;
+    uint16* b = img->bluecmap;
+    long i;
+
+    for (i = (1L<<img->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
+    }
+}
+
+/*
+ * Palette images with <= 8 bits/sample are handled
+ * with a table to avoid lots of shifts and masks.  The table
+ * is setup so that put*cmaptile (below) can retrieve 8/bitspersample
+ * pixel values simply by indexing into the table with one
+ * number.
+ */
+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;
+    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;
+	}
+#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;
+    }
+    return (1);
+}
+
+/*
+ * 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)
+					{
+						if (BuildMapUaToAa(img))
+							img->put.contig = putRGBUAcontig8bittile;
+					}
+					else
+						img->put.contig = putRGBcontig8bittile;
+					break;
+				case 16:
+					if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
+					{
+						if (BuildMapBitdepth16To8(img))
+							img->put.contig = putRGBAAcontig16bittile;
+					}
+					else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
+					{
+						if (BuildMapBitdepth16To8(img) &&
+						    BuildMapUaToAa(img))
+							img->put.contig = putRGBUAcontig16bittile;
+					}
+					else
+					{
+						if (BuildMapBitdepth16To8(img))
+							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:
+						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 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));
+}
+
+/*
+ * Select the appropriate conversion routine for unpacked data.
+ *
+ * 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_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 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* m;
+	uint16 na,nv;
+	assert(img->UaToAa==NULL);
+	img->UaToAa=_TIFFmalloc(65536);
+	if (img->UaToAa==NULL)
+	{
+		TIFFErrorExt(img->tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	m=img->UaToAa;
+	for (na=0; na<256; na++)
+	{
+		for (nv=0; nv<256; nv++)
+			*m++=(nv*na+127)/255;
+	}
+	return(1);
+}
+
+static int
+BuildMapBitdepth16To8(TIFFRGBAImage* img)
+{
+	static const char module[]="BuildMapBitdepth16To8";
+	uint8* m;
+	uint32 n;
+	assert(img->Bitdepth16To8==NULL);
+	img->Bitdepth16To8=_TIFFmalloc(65536);
+	if (img->Bitdepth16To8==NULL)
+	{
+		TIFFErrorExt(img->tif->tif_clientdata,module,"Out of memory");
+		return(0);
+	}
+	m=img->Bitdepth16To8;
+	for (n=0; n<65536; n++)
+		*m++=(n+128)/257;
+	return(1);
+}
+
+
+/*
+ * Read a whole strip off data from the file, and convert to RGBA form.
+ * If this is the last strip, then it will only contain the portion of
+ * the strip that is actually within the image space.  The result is
+ * organized in bottom to top form.
+ */
+
+
+int
+TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster )
+
+{
+    char 	emsg[1024] = "";
+    TIFFRGBAImage img;
+    int 	ok;
+    uint32	rowsperstrip, rows_to_read;
+
+    if( TIFFIsTiled( tif ) )
+    {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+                  "Can't use TIFFReadRGBAStrip() with tiled file.");
+	return (0);
+    }
+    
+    TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+    if( (row % rowsperstrip) != 0 )
+    {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+				"Row passed to TIFFReadRGBAStrip() must be first in a strip.");
+		return (0);
+    }
+
+    if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
+
+        img.row_offset = row;
+        img.col_offset = 0;
+
+        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;
+    }
+    
+    return (ok);
+}
+
+/*
+ * Read a whole tile off data from the file, and convert to RGBA form.
+ * The returned RGBA data is organized from bottom to top of tile,
+ * and may include zeroed areas if the tile extends off the image.
+ */
+
+int
+TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster)
+
+{
+    char 	emsg[1024] = "";
+    TIFFRGBAImage img;
+    int 	ok;
+    uint32	tile_xsize, tile_ysize;
+    uint32	read_xsize, read_ysize;
+    uint32	i_row;
+
+    /*
+     * Verify that our request is legal - on a tile file, and on a
+     * tile boundary.
+     */
+    
+    if( !TIFFIsTiled( tif ) )
+    {
+		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+				  "Can't use TIFFReadRGBATile() with stripped file.");
+		return (0);
+    }
+    
+    TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize);
+    TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize);
+    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);
+    }
+
+    /*
+     * Setup the RGBA reader.
+     */
+    
+    if (!TIFFRGBAImageOK(tif, emsg) 
+	|| !TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
+	    TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg);
+	    return( 0 );
+    }
+
+    /*
+     * The TIFFRGBAImageGet() function doesn't allow us to get off the
+     * edge of the image, even to fill an otherwise valid tile.  So we
+     * figure out how much we can read, and fix up the tile buffer to
+     * a full tile configuration afterwards.
+     */
+
+    if( row + tile_ysize > img.height )
+        read_ysize = img.height - row;
+    else
+        read_ysize = tile_ysize;
+    
+    if( col + tile_xsize > img.width )
+        read_xsize = img.width - col;
+    else
+        read_xsize = tile_xsize;
+
+    /*
+     * Read the chunk of imagery.
+     */
+    
+    img.row_offset = row;
+    img.col_offset = col;
+
+    ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize );
+        
+    TIFFRGBAImageEnd(&img);
+
+    /*
+     * If our read was incomplete we will need to fix up the tile by
+     * 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. 
+     */
+
+    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 = read_ysize; i_row < tile_ysize; i_row++ ) {
+        _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize,
+                     0, sizeof(uint32) * 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/third_party/libtiff/tif_jpeg.c b/third_party/libtiff/tif_jpeg.c
new file mode 100644
index 0000000..6659909
--- /dev/null
+++ b/third_party/libtiff/tif_jpeg.c
@@ -0,0 +1,2429 @@
+/* $Id: tif_jpeg.c,v 1.119 2015-08-15 20:13:07 bfriesen 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#define VC_EXTRALEAN
+
+#include "tiffiop.h"
+#ifdef JPEG_SUPPORT
+
+/*
+ * TIFF Library
+ *
+ * JPEG Compression support per TIFF Technical Note #2
+ * (*not* per the original TIFF 6.0 spec).
+ *
+ * This file is simply an interface to the libjpeg library written by
+ * the Independent JPEG Group.  You need release 5 or later of the IJG
+ * code, which you can find on the Internet at ftp.uu.net:/graphics/jpeg/.
+ *
+ * Contributed by Tom Lane <tgl@sss.pgh.pa.us>.
+ */
+#include <setjmp.h>
+
+int TIFFFillStrip(TIFF* tif, uint32 strip);
+int TIFFFillTile(TIFF* tif, uint32 tile);
+int TIFFReInitJPEG_12( TIFF *tif, int scheme, int is_encode );
+
+/* 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 conficting typedef given the headers which are included.
+*/
+#if defined(__BORLANDC__) || defined(__MINGW32__)
+# define XMD_H 1
+#endif
+
+/*
+   The windows RPCNDR.H file defines boolean, but defines it with the
+   unsigned char size.  You should compile JPEG library using appropriate
+   definitions in jconfig.h header, but many users compile library in wrong
+   way. That causes errors of the following type:
+
+   "JPEGLib: JPEG parameter struct mismatch: library thinks size is 432,
+   caller expects 464"
+
+   For such users we wil fix the problem here. See install.doc file from
+   the JPEG library distribution for details.
+*/
+
+/* Define "boolean" as unsigned char, not int, per Windows custom. */
+#if defined(__WIN32__) && !defined(__MINGW32__)
+# ifndef __RPCNDR_H__            /* don't conflict if rpcndr.h already read */
+   typedef unsigned char boolean;
+# endif
+# define HAVE_BOOLEAN            /* prevent jmorecfg.h from redefining it */
+#endif
+
+#if defined(USE_SYSTEM_LIBJPEG)
+#include <jerror.h>
+#include <jpeglib.h>
+#elif defined(USE_LIBJPEG_TURBO)
+#include "third_party/libjpeg_turbo/jerror.h"
+#include "third_party/libjpeg_turbo/jpeglib.h"
+#else
+#include "third_party/libjpeg/jerror.h"
+#include "third_party/libjpeg/jpeglib.h"
+#endif
+
+/* 
+ * Do we want to do special processing suitable for when JSAMPLE is a
+ * 16bit value?  
+ */
+
+#if defined(JPEG_LIB_MK1)
+#  define JPEG_LIB_MK1_OR_12BIT 1
+#elif BITS_IN_JSAMPLE == 12
+#  define JPEG_LIB_MK1_OR_12BIT 1
+#endif
+
+/*
+ * We are using width_in_blocks which is supposed to be private to
+ * libjpeg. Unfortunately, the libjpeg delivered with Cygwin has
+ * renamed this member to width_in_data_units.  Since the header has
+ * also renamed a define, use that unique define name in order to
+ * detect the problem header and adjust to suit.
+ */
+#if defined(D_MAX_DATA_UNITS_IN_MCU)
+#define width_in_blocks width_in_data_units
+#endif
+
+/*
+ * On some machines it may be worthwhile to use _setjmp or sigsetjmp
+ * in place of plain setjmp.  These macros will make it easier.
+ */
+#define SETJMP(jbuf)		setjmp(jbuf)
+#define LONGJMP(jbuf,code)	longjmp(jbuf,code)
+#define JMP_BUF			jmp_buf
+
+typedef struct jpeg_destination_mgr jpeg_destination_mgr;
+typedef struct jpeg_source_mgr jpeg_source_mgr;
+typedef struct jpeg_error_mgr jpeg_error_mgr;
+
+/*
+ * State block for each open TIFF file using
+ * libjpeg to do JPEG compression/decompression.
+ *
+ * libjpeg's visible state is either a jpeg_compress_struct
+ * or jpeg_decompress_struct depending on which way we
+ * are going.  comm can be used to refer to the fields
+ * which are common to both.
+ *
+ * NB: cinfo is required to be the first member of JPEGState,
+ *     so we can safely cast JPEGState* -> jpeg_xxx_struct*
+ *     and vice versa!
+ */
+typedef struct {
+	union {
+		struct jpeg_compress_struct c;
+		struct jpeg_decompress_struct d;
+		struct jpeg_common_struct comm;
+	} cinfo;			/* NB: must be first */
+	int             cinfo_initialized;
+
+	jpeg_error_mgr	err;		/* libjpeg error manager */
+	JMP_BUF		exit_jmpbuf;	/* for catching libjpeg failures */
+	/*
+	 * 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;
+	tmsize_t   	bytesperline;	/* decompressed bytes per scanline */
+	/* pointers to intermediate buffers when processing downsampled data */
+	JSAMPARRAY	ds_buffer[MAX_COMPONENTS];
+	int		scancount;	/* number of "scanlines" accumulated */
+	int		samplesperclump;
+
+	TIFFVGetMethod	vgetparent;	/* super-class method */
+	TIFFVSetMethod	vsetparent;	/* super-class method */
+	TIFFPrintMethod printdir;	/* super-class method */
+	TIFFStripMethod	defsparent;	/* super-class method */
+	TIFFTileMethod	deftparent;	/* super-class method */
+					/* pseudo-tag fields */
+	void*		jpegtables;	/* JPEGTables tag value, or NULL */
+	uint32		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;
+} JPEGState;
+
+#define	JState(tif)	((JPEGState*)(tif)->tif_data)
+
+static int JPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int JPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int JPEGEncodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int JPEGInitializeLibJPEG(TIFF * tif, int decode );
+static int DecodeRowError(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+
+#define	FIELD_JPEGTABLES	(FIELD_CODEC+0)
+
+static const TIFFField jpegFields[] = {
+    { TIFFTAG_JPEGTABLES, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_C32_UINT8, FIELD_JPEGTABLES, FALSE, TRUE, "JPEGTables", NULL },
+    { TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL },
+    { TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL },
+    { TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL }
+};
+
+/*
+ * libjpeg interface layer.
+ *
+ * We use setjmp/longjmp to return control to libtiff
+ * when a fatal error is encountered within the JPEG
+ * library.  We also direct libjpeg error and warning
+ * messages through the appropriate libtiff handlers.
+ */
+
+/*
+ * Error handling routines (these replace corresponding
+ * IJG routines from jerror.c).  These are used for both
+ * compression and decompression.
+ */
+static void
+TIFFjpeg_error_exit(j_common_ptr cinfo)
+{
+	JPEGState *sp = (JPEGState *) cinfo;	/* NB: cinfo assumed first */
+	char buffer[JMSG_LENGTH_MAX];
+
+	(*cinfo->err->format_message) (cinfo, buffer);
+	TIFFErrorExt(sp->tif->tif_clientdata, "JPEGLib", "%s", buffer);		/* display the error message */
+	jpeg_abort(cinfo);			/* clean up libjpeg state */
+	LONGJMP(sp->exit_jmpbuf, 1);		/* return to libtiff caller */
+}
+
+/*
+ * This routine is invoked only for warning messages,
+ * since error_exit does its own thing and trace_level
+ * is never set > 0.
+ */
+static void
+TIFFjpeg_output_message(j_common_ptr cinfo)
+{
+	char buffer[JMSG_LENGTH_MAX];
+
+	(*cinfo->err->format_message) (cinfo, buffer);
+	TIFFWarningExt(((JPEGState *) cinfo)->tif->tif_clientdata, "JPEGLib", "%s", buffer);
+}
+
+/*
+ * Interface routines.  This layer of routines exists
+ * primarily to limit side-effects from using setjmp.
+ * Also, normal/error returns are converted into return
+ * values per libtiff practice.
+ */
+#define	CALLJPEG(sp, fail, op)	(SETJMP((sp)->exit_jmpbuf) ? (fail) : (op))
+#define	CALLVJPEG(sp, op)	CALLJPEG(sp, 0, ((op),1))
+
+static int
+TIFFjpeg_create_compress(JPEGState* sp)
+{
+	/* initialize JPEG error handling */
+	sp->cinfo.c.err = jpeg_std_error(&sp->err);
+	sp->err.error_exit = TIFFjpeg_error_exit;
+	sp->err.output_message = TIFFjpeg_output_message;
+
+	/* set client_data to avoid UMR warning from tools like Purify */
+	sp->cinfo.c.client_data = NULL;
+
+	return CALLVJPEG(sp, jpeg_create_compress(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_create_decompress(JPEGState* sp)
+{
+	/* initialize JPEG error handling */
+	sp->cinfo.d.err = jpeg_std_error(&sp->err);
+	sp->err.error_exit = TIFFjpeg_error_exit;
+	sp->err.output_message = TIFFjpeg_output_message;
+
+	/* set client_data to avoid UMR warning from tools like Purify */
+	sp->cinfo.d.client_data = NULL;
+
+	return CALLVJPEG(sp, jpeg_create_decompress(&sp->cinfo.d));
+}
+
+static int
+TIFFjpeg_set_defaults(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_set_defaults(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_set_colorspace(JPEGState* sp, J_COLOR_SPACE colorspace)
+{
+	return CALLVJPEG(sp, jpeg_set_colorspace(&sp->cinfo.c, colorspace));
+}
+
+static int
+TIFFjpeg_set_quality(JPEGState* sp, int quality, boolean force_baseline)
+{
+	return CALLVJPEG(sp,
+	    jpeg_set_quality(&sp->cinfo.c, quality, force_baseline));
+}
+
+static int
+TIFFjpeg_suppress_tables(JPEGState* sp, boolean suppress)
+{
+	return CALLVJPEG(sp, jpeg_suppress_tables(&sp->cinfo.c, suppress));
+}
+
+static int
+TIFFjpeg_start_compress(JPEGState* sp, boolean write_all_tables)
+{
+	return CALLVJPEG(sp,
+	    jpeg_start_compress(&sp->cinfo.c, write_all_tables));
+}
+
+static int
+TIFFjpeg_write_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int num_lines)
+{
+	return CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c,
+	    scanlines, (JDIMENSION) num_lines));
+}
+
+static int
+TIFFjpeg_write_raw_data(JPEGState* sp, JSAMPIMAGE data, int num_lines)
+{
+	return CALLJPEG(sp, -1, (int) jpeg_write_raw_data(&sp->cinfo.c,
+	    data, (JDIMENSION) num_lines));
+}
+
+static int
+TIFFjpeg_finish_compress(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_finish_compress(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_write_tables(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_write_tables(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_read_header(JPEGState* sp, boolean require_image)
+{
+	return CALLJPEG(sp, -1, jpeg_read_header(&sp->cinfo.d, require_image));
+}
+
+static int
+TIFFjpeg_start_decompress(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d));
+}
+
+static int
+TIFFjpeg_read_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int max_lines)
+{
+	return CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d,
+	    scanlines, (JDIMENSION) max_lines));
+}
+
+static int
+TIFFjpeg_read_raw_data(JPEGState* sp, JSAMPIMAGE data, int max_lines)
+{
+	return CALLJPEG(sp, -1, (int) jpeg_read_raw_data(&sp->cinfo.d,
+	    data, (JDIMENSION) max_lines));
+}
+
+static int
+TIFFjpeg_finish_decompress(JPEGState* sp)
+{
+	return CALLJPEG(sp, -1, (int) jpeg_finish_decompress(&sp->cinfo.d));
+}
+
+static int
+TIFFjpeg_abort(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_abort(&sp->cinfo.comm));
+}
+
+static int
+TIFFjpeg_destroy(JPEGState* sp)
+{
+	return CALLVJPEG(sp, jpeg_destroy(&sp->cinfo.comm));
+}
+
+static JSAMPARRAY
+TIFFjpeg_alloc_sarray(JPEGState* sp, int pool_id,
+		      JDIMENSION samplesperrow, JDIMENSION numrows)
+{
+	return CALLJPEG(sp, (JSAMPARRAY) NULL,
+	    (*sp->cinfo.comm.mem->alloc_sarray)
+		(&sp->cinfo.comm, pool_id, samplesperrow, numrows));
+}
+
+/*
+ * JPEG library destination data manager.
+ * These routines direct compressed data from libjpeg into the
+ * libtiff output buffer.
+ */
+
+static void
+std_init_destination(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+	TIFF* tif = sp->tif;
+
+	sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata;
+	sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize;
+}
+
+static boolean
+std_empty_output_buffer(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+	TIFF* tif = sp->tif;
+
+	/* the entire buffer has been filled */
+	tif->tif_rawcc = tif->tif_rawdatasize;
+
+#ifdef IPPJ_HUFF
+       /*
+        * The Intel IPP performance library does not necessarily fill up
+        * the whole output buffer on each pass, so only dump out the parts
+        * that have been filled.
+        *   http://trac.osgeo.org/gdal/wiki/JpegIPP
+        */
+       if ( sp->dest.free_in_buffer >= 0 ) {
+               tif->tif_rawcc = tif->tif_rawdatasize - sp->dest.free_in_buffer;
+       }
+#endif
+
+	TIFFFlushData1(tif);
+	sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata;
+	sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize;
+
+	return (TRUE);
+}
+
+static void
+std_term_destination(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+	TIFF* tif = sp->tif;
+
+	tif->tif_rawcp = (uint8*) sp->dest.next_output_byte;
+	tif->tif_rawcc =
+	    tif->tif_rawdatasize - (tmsize_t) sp->dest.free_in_buffer;
+	/* NB: libtiff does the final buffer flush */
+}
+
+static void
+TIFFjpeg_data_dest(JPEGState* sp, TIFF* tif)
+{
+	(void) tif;
+	sp->cinfo.c.dest = &sp->dest;
+	sp->dest.init_destination = std_init_destination;
+	sp->dest.empty_output_buffer = std_empty_output_buffer;
+	sp->dest.term_destination = std_term_destination;
+}
+
+/*
+ * Alternate destination manager for outputting to JPEGTables field.
+ */
+
+static void
+tables_init_destination(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+
+	/* while building, jpegtables_length is allocated buffer size */
+	sp->dest.next_output_byte = (JOCTET*) sp->jpegtables;
+	sp->dest.free_in_buffer = (size_t) sp->jpegtables_length;
+}
+
+static boolean
+tables_empty_output_buffer(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+	void* newbuf;
+
+	/* the entire buffer has been filled; enlarge it by 1000 bytes */
+	newbuf = _TIFFrealloc((void*) sp->jpegtables,
+			      (tmsize_t) (sp->jpegtables_length + 1000));
+	if (newbuf == NULL)
+		ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 100);
+	sp->dest.next_output_byte = (JOCTET*) newbuf + sp->jpegtables_length;
+	sp->dest.free_in_buffer = (size_t) 1000;
+	sp->jpegtables = newbuf;
+	sp->jpegtables_length += 1000;
+	return (TRUE);
+}
+
+static void
+tables_term_destination(j_compress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+
+	/* set tables length to number of bytes actually emitted */
+	sp->jpegtables_length -= (uint32) sp->dest.free_in_buffer;
+}
+
+static int
+TIFFjpeg_tables_dest(JPEGState* sp, TIFF* tif)
+{
+	(void) tif;
+	/*
+	 * Allocate a working buffer for building tables.
+	 * Initial size is 1000 bytes, which is usually adequate.
+	 */
+	if (sp->jpegtables)
+		_TIFFfree(sp->jpegtables);
+	sp->jpegtables_length = 1000;
+	sp->jpegtables = (void*) _TIFFmalloc((tmsize_t) sp->jpegtables_length);
+	if (sp->jpegtables == NULL) {
+		sp->jpegtables_length = 0;
+		TIFFErrorExt(sp->tif->tif_clientdata, "TIFFjpeg_tables_dest", "No space for JPEGTables");
+		return (0);
+	}
+	sp->cinfo.c.dest = &sp->dest;
+	sp->dest.init_destination = tables_init_destination;
+	sp->dest.empty_output_buffer = tables_empty_output_buffer;
+	sp->dest.term_destination = tables_term_destination;
+	return (1);
+}
+
+/*
+ * JPEG library source data manager.
+ * These routines supply compressed data to libjpeg.
+ */
+
+static void
+std_init_source(j_decompress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+	TIFF* tif = sp->tif;
+
+	sp->src.next_input_byte = (const JOCTET*) tif->tif_rawdata;
+	sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc;
+}
+
+static boolean
+std_fill_input_buffer(j_decompress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState* ) cinfo;
+	static const JOCTET dummy_EOI[2] = { 0xFF, JPEG_EOI };
+
+#ifdef IPPJ_HUFF
+        /*
+         * The Intel IPP performance library does not necessarily read the whole
+         * input buffer in one pass, so it is possible to get here with data
+         * yet to read. 
+         * 
+         * We just return without doing anything, until the entire buffer has
+         * been read.  
+         * http://trac.osgeo.org/gdal/wiki/JpegIPP
+         */
+        if( sp->src.bytes_in_buffer > 0 ) {
+            return (TRUE);
+        }
+#endif
+
+	/*
+         * Normally the whole strip/tile is read and so we don't need to do
+         * a fill.  In the case of CHUNKY_STRIP_READ_SUPPORT we might not have
+         * all the data, but the rawdata is refreshed between scanlines and
+         * we push this into the io machinery in JPEGDecode(). 	 
+         * http://trac.osgeo.org/gdal/ticket/3894
+	 */
+        
+	WARNMS(cinfo, JWRN_JPEG_EOF);
+	/* insert a fake EOI marker */
+	sp->src.next_input_byte = dummy_EOI;
+	sp->src.bytes_in_buffer = 2;
+	return (TRUE);
+}
+
+static void
+std_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+
+	if (num_bytes > 0) {
+		if ((size_t)num_bytes > sp->src.bytes_in_buffer) {
+			/* oops, buffer overrun */
+			(void) std_fill_input_buffer(cinfo);
+		} else {
+			sp->src.next_input_byte += (size_t) num_bytes;
+			sp->src.bytes_in_buffer -= (size_t) num_bytes;
+		}
+	}
+}
+
+static void
+std_term_source(j_decompress_ptr cinfo)
+{
+	/* No work necessary here */
+	(void) cinfo;
+}
+
+static void
+TIFFjpeg_data_src(JPEGState* sp, TIFF* tif)
+{
+	(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;
+}
+
+/*
+ * Alternate source manager for reading from JPEGTables.
+ * We can share all the code except for the init routine.
+ */
+
+static void
+tables_init_source(j_decompress_ptr cinfo)
+{
+	JPEGState* sp = (JPEGState*) cinfo;
+
+	sp->src.next_input_byte = (const JOCTET*) sp->jpegtables;
+	sp->src.bytes_in_buffer = (size_t) sp->jpegtables_length;
+}
+
+static void
+TIFFjpeg_tables_src(JPEGState* sp, TIFF* tif)
+{
+	TIFFjpeg_data_src(sp, tif);
+	sp->src.init_source = tables_init_source;
+}
+
+/*
+ * Allocate downsampled-data buffers needed for downsampled I/O.
+ * We use values computed in jpeg_start_compress or jpeg_start_decompress.
+ * We use libjpeg's allocator so that buffers will be released automatically
+ * when done with strip/tile.
+ * This is also a handy place to compute samplesperclump, bytesperline.
+ */
+static int
+alloc_downsampled_buffers(TIFF* tif, jpeg_component_info* comp_info,
+			  int num_components)
+{
+	JPEGState* sp = JState(tif);
+	int ci;
+	jpeg_component_info* compptr;
+	JSAMPARRAY buf;
+	int samples_per_clump = 0;
+
+	for (ci = 0, compptr = comp_info; ci < num_components;
+	     ci++, compptr++) {
+		samples_per_clump += compptr->h_samp_factor *
+			compptr->v_samp_factor;
+		buf = TIFFjpeg_alloc_sarray(sp, JPOOL_IMAGE,
+				compptr->width_in_blocks * DCTSIZE,
+				(JDIMENSION) (compptr->v_samp_factor*DCTSIZE));
+		if (buf == NULL)
+			return (0);
+		sp->ds_buffer[ci] = buf;
+	}
+	sp->samplesperclump = samples_per_clump;
+	return (1);
+}
+
+
+/*
+ * JPEG Decoding.
+ */
+
+#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING
+
+#define JPEG_MARKER_SOF0 0xC0
+#define JPEG_MARKER_SOF1 0xC1
+#define JPEG_MARKER_SOF2 0xC2
+#define JPEG_MARKER_SOF9 0xC9
+#define JPEG_MARKER_SOF10 0xCA
+#define JPEG_MARKER_DHT 0xC4
+#define JPEG_MARKER_SOI 0xD8
+#define JPEG_MARKER_SOS 0xDA
+#define JPEG_MARKER_DQT 0xDB
+#define JPEG_MARKER_DRI 0xDD
+#define JPEG_MARKER_APP0 0xE0
+#define JPEG_MARKER_COM 0xFE
+struct JPEGFixupTagsSubsamplingData
+{
+	TIFF* tif;
+	void* buffer;
+	uint32 buffersize;
+	uint8* buffercurrentbyte;
+	uint32 bufferbytesleft;
+	uint64 fileoffset;
+	uint64 filebytesleft;
+	uint8 filepositioned;
+};
+static void JPEGFixupTagsSubsampling(TIFF* tif);
+static int JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData* data);
+static int JPEGFixupTagsSubsamplingReadByte(struct JPEGFixupTagsSubsamplingData* data, uint8* result);
+static int JPEGFixupTagsSubsamplingReadWord(struct JPEGFixupTagsSubsamplingData* data, uint16* result);
+static void JPEGFixupTagsSubsamplingSkip(struct JPEGFixupTagsSubsamplingData* data, uint16 skiplength);
+
+#endif
+
+static int
+JPEGFixupTags(TIFF* tif)
+{
+#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING
+	if ((tif->tif_dir.td_photometric==PHOTOMETRIC_YCBCR)&&
+	    (tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)&&
+	    (tif->tif_dir.td_samplesperpixel==3))
+		JPEGFixupTagsSubsampling(tif);
+#endif
+        
+	return(1);
+}
+
+#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING
+
+static void
+JPEGFixupTagsSubsampling(TIFF* tif)
+{
+	/*
+	 * Some JPEG-in-TIFF produces do not emit the YCBCRSUBSAMPLING values in
+	 * the TIFF tags, but still use non-default (2,2) values within the jpeg
+	 * data stream itself.  In order for TIFF applications to work properly
+	 * - for instance to get the strip buffer size right - it is imperative
+	 * that the subsampling be available before we start reading the image
+	 * data normally.  This function will attempt to analyze the first strip in
+	 * order to get the sampling values from the jpeg data stream.
+	 *
+	 * Note that JPEGPreDeocode() will produce a fairly loud warning when the
+	 * discovered sampling does not match the default sampling (2,2) or whatever
+	 * was actually in the tiff tags.
+	 *
+	 * See the bug in bugzilla for details:
+	 *
+	 * http://bugzilla.remotesensing.org/show_bug.cgi?id=168
+	 *
+	 * Frank Warmerdam, July 2002
+	 * Joris Van Damme, May 2007
+	 */
+	static const char module[] = "JPEGFixupTagsSubsampling";
+	struct JPEGFixupTagsSubsamplingData m;
+
+        _TIFFFillStriles( tif );
+        
+        if( tif->tif_dir.td_stripbytecount == NULL
+            || tif->tif_dir.td_stripoffset == NULL
+            || tif->tif_dir.td_stripbytecount[0] == 0 )
+        {
+            /* Do not even try to check if the first strip/tile does not
+               yet exist, as occurs when GDAL has created a new NULL file
+               for instance. */
+            return;
+        }
+
+	m.tif=tif;
+	m.buffersize=2048;
+	m.buffer=_TIFFmalloc(m.buffersize);
+	if (m.buffer==NULL)
+	{
+		TIFFWarningExt(tif->tif_clientdata,module,
+		    "Unable to allocate memory for auto-correcting of subsampling values; auto-correcting skipped");
+		return;
+	}
+	m.buffercurrentbyte=NULL;
+	m.bufferbytesleft=0;
+	m.fileoffset=tif->tif_dir.td_stripoffset[0];
+	m.filepositioned=0;
+	m.filebytesleft=tif->tif_dir.td_stripbytecount[0];
+	if (!JPEGFixupTagsSubsamplingSec(&m))
+		TIFFWarningExt(tif->tif_clientdata,module,
+		    "Unable to auto-correct subsampling values, likely corrupt JPEG compressed data in first strip/tile; auto-correcting skipped");
+	_TIFFfree(m.buffer);
+}
+
+static int
+JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData* data)
+{
+	static const char module[] = "JPEGFixupTagsSubsamplingSec";
+	uint8 m;
+	while (1)
+	{
+		while (1)
+		{
+			if (!JPEGFixupTagsSubsamplingReadByte(data,&m))
+				return(0);
+			if (m==255)
+				break;
+		}
+		while (1)
+		{
+			if (!JPEGFixupTagsSubsamplingReadByte(data,&m))
+				return(0);
+			if (m!=255)
+				break;
+		}
+		switch (m)
+		{
+			case JPEG_MARKER_SOI:
+				/* this type of marker has no data and should be skipped */
+				break;
+			case JPEG_MARKER_COM:
+			case JPEG_MARKER_APP0:
+			case JPEG_MARKER_APP0+1:
+			case JPEG_MARKER_APP0+2:
+			case JPEG_MARKER_APP0+3:
+			case JPEG_MARKER_APP0+4:
+			case JPEG_MARKER_APP0+5:
+			case JPEG_MARKER_APP0+6:
+			case JPEG_MARKER_APP0+7:
+			case JPEG_MARKER_APP0+8:
+			case JPEG_MARKER_APP0+9:
+			case JPEG_MARKER_APP0+10:
+			case JPEG_MARKER_APP0+11:
+			case JPEG_MARKER_APP0+12:
+			case JPEG_MARKER_APP0+13:
+			case JPEG_MARKER_APP0+14:
+			case JPEG_MARKER_APP0+15:
+			case JPEG_MARKER_DQT:
+			case JPEG_MARKER_SOS:
+			case JPEG_MARKER_DHT:
+			case JPEG_MARKER_DRI:
+				/* this type of marker has data, but it has no use to us and should be skipped */
+				{
+					uint16 n;
+					if (!JPEGFixupTagsSubsamplingReadWord(data,&n))
+						return(0);
+					if (n<2)
+						return(0);
+					n-=2;
+					if (n>0)
+						JPEGFixupTagsSubsamplingSkip(data,n);
+				}
+				break;
+			case JPEG_MARKER_SOF0: /* Baseline sequential Huffman */
+			case JPEG_MARKER_SOF1: /* Extended sequential Huffman */
+			case JPEG_MARKER_SOF2: /* Progressive Huffman: normally not allowed by TechNote, but that doesn't hurt supporting it */
+			case JPEG_MARKER_SOF9: /* Extended sequential arithmetic */
+			case JPEG_MARKER_SOF10: /* Progressive arithmetic: normally not allowed by TechNote, but that doesn't hurt supporting it */
+				/* this marker contains the subsampling factors we're scanning for */
+				{
+					uint16 n;
+					uint16 o;
+					uint8 p;
+					uint8 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++)
+					{
+						JPEGFixupTagsSubsamplingSkip(data,1);
+						if (!JPEGFixupTagsSubsamplingReadByte(data,&p))
+							return(0);
+						if (p!=0x11)
+						{
+							TIFFWarningExt(data->tif->tif_clientdata,module,
+							    "Subsampling values inside JPEG compressed data have no TIFF equivalent, auto-correction of TIFF subsampling values failed");
+							return(1);
+						}
+						JPEGFixupTagsSubsamplingSkip(data,1);
+					}
+					if (((ph!=1)&&(ph!=2)&&(ph!=4))||((pv!=1)&&(pv!=2)&&(pv!=4)))
+					{
+						TIFFWarningExt(data->tif->tif_clientdata,module,
+						    "Subsampling values inside JPEG compressed data have no TIFF equivalent, auto-correction of TIFF subsampling values failed");
+						return(1);
+					}
+					if ((ph!=data->tif->tif_dir.td_ycbcrsubsampling[0])||(pv!=data->tif->tif_dir.td_ycbcrsubsampling[1]))
+					{
+						TIFFWarningExt(data->tif->tif_clientdata,module,
+						    "Auto-corrected former TIFF subsampling values [%d,%d] to match subsampling values inside JPEG compressed data [%d,%d]",
+						    (int)data->tif->tif_dir.td_ycbcrsubsampling[0],
+						    (int)data->tif->tif_dir.td_ycbcrsubsampling[1],
+						    (int)ph,(int)pv);
+						data->tif->tif_dir.td_ycbcrsubsampling[0]=ph;
+						data->tif->tif_dir.td_ycbcrsubsampling[1]=pv;
+					}
+				}
+				return(1);
+			default:
+				return(0);
+		}
+	}
+}
+
+static int
+JPEGFixupTagsSubsamplingReadByte(struct JPEGFixupTagsSubsamplingData* data, uint8* result)
+{
+	if (data->bufferbytesleft==0)
+	{
+		uint32 m;
+		if (data->filebytesleft==0)
+			return(0);
+		if (!data->filepositioned)
+		{
+			TIFFSeekFile(data->tif,data->fileoffset,SEEK_SET);
+			data->filepositioned=1;
+		}
+		m=data->buffersize;
+		if ((uint64)m>data->filebytesleft)
+			m=(uint32)data->filebytesleft;
+		assert(m<0x80000000UL);
+		if (TIFFReadFile(data->tif,data->buffer,(tmsize_t)m)!=(tmsize_t)m)
+			return(0);
+		data->buffercurrentbyte=data->buffer;
+		data->bufferbytesleft=m;
+		data->fileoffset+=m;
+		data->filebytesleft-=m;
+	}
+	*result=*data->buffercurrentbyte;
+	data->buffercurrentbyte++;
+	data->bufferbytesleft--;
+	return(1);
+}
+
+static int
+JPEGFixupTagsSubsamplingReadWord(struct JPEGFixupTagsSubsamplingData* data, uint16* result)
+{
+	uint8 ma;
+	uint8 mb;
+	if (!JPEGFixupTagsSubsamplingReadByte(data,&ma))
+		return(0);
+	if (!JPEGFixupTagsSubsamplingReadByte(data,&mb))
+		return(0);
+	*result=(ma<<8)|mb;
+	return(1);
+}
+
+static void
+JPEGFixupTagsSubsamplingSkip(struct JPEGFixupTagsSubsamplingData* data, uint16 skiplength)
+{
+	if ((uint32)skiplength<=data->bufferbytesleft)
+	{
+		data->buffercurrentbyte+=skiplength;
+		data->bufferbytesleft-=skiplength;
+	}
+	else
+	{
+		uint16 m;
+		m=skiplength-data->bufferbytesleft;
+		if (m<=data->filebytesleft)
+		{
+			data->bufferbytesleft=0;
+			data->fileoffset+=m;
+			data->filebytesleft-=m;
+			data->filepositioned=0;
+		}
+		else
+		{
+			data->bufferbytesleft=0;
+			data->filebytesleft=0;
+		}
+	}
+}
+
+#endif
+
+
+static int
+JPEGSetupDecode(TIFF* tif)
+{
+	JPEGState* sp = JState(tif);
+	TIFFDirectory *td = &tif->tif_dir;
+
+#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFInitJPEG)
+        if( tif->tif_dir.td_bitspersample == 12 )
+            return TIFFReInitJPEG_12( tif, COMPRESSION_JPEG, 0 );
+#endif
+
+	JPEGInitializeLibJPEG( tif, TRUE );
+
+	assert(sp != NULL);
+	assert(sp->cinfo.comm.is_decompressor);
+
+	/* Read JPEGTables if it is present */
+	if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) {
+		TIFFjpeg_tables_src(sp, 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);
+}
+
+/*
+ * Set up for decoding a strip or tile.
+ */
+/*ARGSUSED*/ static int
+JPEGPreDecode(TIFF* tif, uint16 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);
+  
+	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*) sp->src.next_input_byte;
+        tif->tif_rawcc = sp->src.bytes_in_buffer;
+
+	/*
+	 * 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 = TIFFScanlineSize(tif);
+	}
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) {
+		/*
+		 * For PC 2, scale down the expected strip/tile size
+		 * to match a downsampled component
+		 */
+		segment_width = TIFFhowmany_32(segment_width, sp->h_sampling);
+		segment_height = TIFFhowmany_32(segment_height, sp->v_sampling);
+	}
+	if (sp->cinfo.d.image_width < segment_width ||
+	    sp->cinfo.d.image_height < segment_height) {
+		TIFFWarningExt(tif->tif_clientdata, module,
+			       "Improper JPEG strip/tile size, "
+			       "expected %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);
+	}
+#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) {
+			TIFFErrorExt(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);
+			return (0);
+		}
+		/* Rest should have sampling factors 1,1 */
+		for (ci = 1; ci < sp->cinfo.d.num_components; ci++) {
+			if (sp->cinfo.d.comp_info[ci].h_samp_factor != 1 ||
+			    sp->cinfo.d.comp_info[ci].v_samp_factor != 1) {
+				TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors");
+				return (0);
+			}
+		}
+	} else {
+		/* PC 2's single component should have sampling factors 1,1 */
+		if (sp->cinfo.d.comp_info[0].h_samp_factor != 1 ||
+		    sp->cinfo.d.comp_info[0].v_samp_factor != 1) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors");
+			return (0);
+		}
+	}
+	downsampled_output = FALSE;
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
+	    sp->photometric == PHOTOMETRIC_YCBCR &&
+	    sp->jpegcolormode == JPEGCOLORMODE_RGB) {
+		/* Convert YCbCr to RGB */
+		sp->cinfo.d.jpeg_color_space = JCS_YCbCr;
+		sp->cinfo.d.out_color_space = JCS_RGB;
+	} else {
+		/* Suppress colorspace handling */
+		sp->cinfo.d.jpeg_color_space = JCS_UNKNOWN;
+		sp->cinfo.d.out_color_space = JCS_UNKNOWN;
+		if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
+		    (sp->h_sampling != 1 || sp->v_sampling != 1))
+			downsampled_output = TRUE;
+		/* XXX what about up-sampling? */
+	}
+	if (downsampled_output) {
+		/* Need to use raw-data interface to libjpeg */
+		sp->cinfo.d.raw_data_out = TRUE;
+#if JPEG_LIB_VERSION >= 70
+		sp->cinfo.d.do_fancy_upsampling = FALSE;
+#endif /* JPEG_LIB_VERSION >= 70 */
+		tif->tif_decoderow = DecodeRowError;
+		tif->tif_decodestrip = JPEGDecodeRaw;
+		tif->tif_decodetile = JPEGDecodeRaw;
+	} else {
+		/* Use normal interface to libjpeg */
+		sp->cinfo.d.raw_data_out = FALSE;
+		tif->tif_decoderow = JPEGDecode;
+		tif->tif_decodestrip = JPEGDecode;
+		tif->tif_decodetile = JPEGDecode;  
+	}
+	/* Start JPEG decompressor */
+	if (!TIFFjpeg_start_decompress(sp))
+		return (0);
+	/* Allocate downsampled-data buffers if needed */
+	if (downsampled_output) {
+		if (!alloc_downsampled_buffers(tif, sp->cinfo.d.comp_info,
+					       sp->cinfo.d.num_components))
+			return (0);
+		sp->scancount = DCTSIZE;	/* mark buffer empty */
+	}
+	return (1);
+}
+
+/*
+ * Decode a chunk of pixels.
+ * "Standard" case: returned data is not downsampled.
+ */
+#if !JPEG_LIB_MK1_OR_12BIT
+static int
+JPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	tmsize_t nrows;
+	(void) s;
+
+        /*
+        ** Update available information, buffer may have been refilled
+        ** between decode requests
+        */
+	sp->src.next_input_byte = (const JOCTET*) tif->tif_rawcp;
+	sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc;
+
+        if( sp->bytesperline == 0 )
+                return 0;
+        
+	nrows = cc / sp->bytesperline;
+	if (cc % sp->bytesperline)
+		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+                               "fractional scanline not read");
+
+	if( nrows > (tmsize_t) sp->cinfo.d.image_height )
+		nrows = sp->cinfo.d.image_height;
+
+	/* data is expected to be read in multiples of a scanline */
+	if (nrows)
+        {
+                do
+                {
+                        /*
+                         * In the libjpeg6b-9a 8bit case.  We read directly into
+                         * the TIFF buffer.
+                         */
+                        JSAMPROW bufptr = (JSAMPROW)buf;
+
+                        if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1)
+                                return (0);
+
+                        ++tif->tif_row;
+                        buf += sp->bytesperline;
+                        cc -= sp->bytesperline;
+                } while (--nrows > 0);
+        }
+
+        /* Update information on consumed data */
+        tif->tif_rawcp = (uint8*) 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* buf, tmsize_t cc, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	tmsize_t nrows;
+	(void) s;
+
+        /*
+        ** Update available information, buffer may have been refilled
+        ** between decode requests
+        */
+	sp->src.next_input_byte = (const JOCTET*) tif->tif_rawcp;
+	sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc;
+
+        if( sp->bytesperline == 0 )
+                return 0;
+        
+	nrows = cc / sp->bytesperline;
+	if (cc % sp->bytesperline)
+		TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+                               "fractional scanline not read");
+
+	if( nrows > (tmsize_t) sp->cinfo.d.image_height )
+		nrows = sp->cinfo.d.image_height;
+
+	/* data is expected to be read in multiples of a scanline */
+	if (nrows)
+        {
+                JSAMPROW line_work_buf = NULL;
+
+                /*
+                 * For 6B, only use temporary buffer for 12 bit imagery.
+                 * For Mk1 always use it.
+                 */
+                if( sp->cinfo.d.data_precision == 12 )
+                {
+                        line_work_buf = (JSAMPROW)
+                                _TIFFmalloc(sizeof(short) * sp->cinfo.d.output_width
+                                            * sp->cinfo.d.num_components );
+                }
+
+               do
+               {
+                       if( line_work_buf != NULL )
+                       {
+                               /*
+                                * In the MK1 case, we 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 )
+                               {
+                                       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);
+                                       }
+                               }
+                               else if( sp->cinfo.d.data_precision == 8 )
+                               {
+                                       int value_count = (sp->cinfo.d.output_width
+                                                          * sp->cinfo.d.num_components);
+                                       int iValue;
+
+                                       for( iValue = 0; iValue < value_count; iValue++ )
+                                       {
+                                               ((unsigned char *) buf)[iValue] =
+                                                       line_work_buf[iValue] & 0xff;
+                                       }
+                               }
+                       }
+
+                       ++tif->tif_row;
+                       buf += sp->bytesperline;
+                       cc -= sp->bytesperline;
+               } while (--nrows > 0);
+
+               if( line_work_buf != NULL )
+                       _TIFFfree( line_work_buf );
+        }
+
+        /* Update information on consumed data */
+        tif->tif_rawcp = (uint8*) 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* buf, tmsize_t cc, uint16 s)
+
+{
+    (void) buf;
+    (void) cc;
+    (void) s;
+
+    TIFFErrorExt(tif->tif_clientdata, "TIFFReadScanline",
+                 "scanline oriented access is not supported for downsampled JPEG compressed images, consider enabling TIFF_JPEGCOLORMODE as JPEGCOLORMODE_RGB." );
+    return 0;
+}
+
+/*
+ * Decode a chunk of pixels.
+ * Returned data is downsampled per sampling factors.
+ */
+/*ARGSUSED*/ static int
+JPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	tmsize_t nrows;
+	(void) s;
+
+	/* 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;
+
+#if defined(JPEG_LIB_MK1_OR_12BIT)
+		unsigned short* tmpbuf = _TIFFmalloc(sizeof(unsigned short) *
+						     sp->cinfo.d.output_width *
+						     sp->cinfo.d.num_components);
+		if(tmpbuf==NULL) {
+                        TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw",
+				     "Out of memory");
+			return 0;
+                }
+#endif
+
+		do {
+			jpeg_component_info *compptr;
+			int ci, clumpoffset;
+
+                        if( cc < sp->bytesperline ) {
+				TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw",
+					     "application buffer not large enough for all data.");
+				return 0;
+                        }
+
+			/* Reload downsampled-data buffer if needed */
+			if (sp->scancount >= DCTSIZE) {
+				int n = sp->cinfo.d.max_v_samp_factor * DCTSIZE;
+				if (TIFFjpeg_read_raw_data(sp, sp->ds_buffer, n) != n)
+					return (0);
+				sp->scancount = 0;
+			}
+			/*
+			 * Fastest way to unseparate data is to make one pass
+			 * over the scanline for each row of each component.
+			 */
+			clumpoffset = 0;    /* first sample in clump */
+			for (ci = 0, compptr = sp->cinfo.d.comp_info;
+			     ci < sp->cinfo.d.num_components;
+			     ci++, compptr++) {
+				int hsamp = compptr->h_samp_factor;
+				int vsamp = compptr->v_samp_factor;
+				int ypos;
+
+				for (ypos = 0; ypos < vsamp; ypos++) {
+					JSAMPLE *inptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos];
+					JDIMENSION nclump;
+#if defined(JPEG_LIB_MK1_OR_12BIT)
+					JSAMPLE *outptr = (JSAMPLE*)tmpbuf + clumpoffset;
+#else
+					JSAMPLE *outptr = (JSAMPLE*)buf + clumpoffset;
+					if (cc < (tmsize_t) (clumpoffset + samples_per_clump*(clumps_per_line-1) + hsamp)) {
+						TIFFErrorExt(tif->tif_clientdata, "JPEGDecodeRaw",
+							     "application buffer not large enough for all data, possible subsampling issue");
+						return 0;
+					}
+#endif
+
+					if (hsamp == 1) {
+						/* fast path for at least Cb and Cr */
+						for (nclump = clumps_per_line; nclump-- > 0; ) {
+							outptr[0] = *inptr++;
+							outptr += samples_per_clump;
+						}
+					} else {
+						int xpos;
+
+						/* general case */
+						for (nclump = clumps_per_line; nclump-- > 0; ) {
+							for (xpos = 0; xpos < hsamp; xpos++)
+								outptr[xpos] = *inptr++;
+							outptr += samples_per_clump;
+						}
+					}
+					clumpoffset += hsamp;
+				}
+			}
+
+#if defined(JPEG_LIB_MK1_OR_12BIT)
+			{
+				if (sp->cinfo.d.data_precision == 8)
+				{
+					int i=0;
+					int len = sp->cinfo.d.output_width * sp->cinfo.d.num_components;
+					for (i=0; 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] = (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);
+					}
+				}
+			}
+#endif
+
+			sp->scancount ++;
+			tif->tif_row += sp->v_sampling;
+
+			buf += sp->bytesperline;
+			cc -= sp->bytesperline;
+
+			nrows -= sp->v_sampling;
+		} while (nrows > 0);
+
+#if defined(JPEG_LIB_MK1_OR_12BIT)
+		_TIFFfree(tmpbuf);
+#endif
+
+	}
+
+	/* Close down the decompressor if done. */
+	return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height
+		|| TIFFjpeg_finish_decompress(sp);
+}
+
+
+/*
+ * JPEG Encoding.
+ */
+
+static void
+unsuppress_quant_table (JPEGState* sp, int tblno)
+{
+	JQUANT_TBL* qtbl;
+
+	if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL)
+		qtbl->sent_table = FALSE;
+}
+
+static void
+suppress_quant_table (JPEGState* sp, int tblno)
+{
+	JQUANT_TBL* qtbl;
+
+	if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL)
+		qtbl->sent_table = TRUE;
+}
+
+static void
+unsuppress_huff_table (JPEGState* sp, int tblno)
+{
+	JHUFF_TBL* htbl;
+
+	if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL)
+		htbl->sent_table = FALSE;
+	if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL)
+		htbl->sent_table = FALSE;
+}
+
+static void
+suppress_huff_table (JPEGState* sp, int tblno)
+{
+	JHUFF_TBL* htbl;
+
+	if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL)
+		htbl->sent_table = TRUE;
+	if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL)
+		htbl->sent_table = TRUE;
+}
+
+static int
+prepare_JPEGTables(TIFF* tif)
+{
+	JPEGState* sp = JState(tif);
+
+	/* Initialize quant tables for current quality setting */
+	if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE))
+		return (0);
+	/* Mark only the tables we want for output */
+	/* NB: chrominance tables are currently used only with YCbCr */
+	if (!TIFFjpeg_suppress_tables(sp, TRUE))
+		return (0);
+	if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) {
+		unsuppress_quant_table(sp, 0);
+		if (sp->photometric == PHOTOMETRIC_YCBCR)
+			unsuppress_quant_table(sp, 1);
+	}
+	if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) {
+		unsuppress_huff_table(sp, 0);
+		if (sp->photometric == PHOTOMETRIC_YCBCR)
+			unsuppress_huff_table(sp, 1);
+	}
+	/* Direct libjpeg output into jpegtables */
+	if (!TIFFjpeg_tables_dest(sp, tif))
+		return (0);
+	/* Emit tables-only datastream */
+	if (!TIFFjpeg_write_tables(sp))
+		return (0);
+
+	return (1);
+}
+
+static int
+JPEGSetupEncode(TIFF* tif)
+{
+	JPEGState* sp = JState(tif);
+	TIFFDirectory *td = &tif->tif_dir;
+	static const char module[] = "JPEGSetupEncode";
+
+#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFInitJPEG)
+        if( tif->tif_dir.td_bitspersample == 12 )
+            return TIFFReInitJPEG_12( tif, COMPRESSION_JPEG, 1 );
+#endif
+
+        JPEGInitializeLibJPEG( tif, FALSE );
+
+	assert(sp != NULL);
+	assert(!sp->cinfo.comm.is_decompressor);
+
+	sp->photometric = td->td_photometric;
+
+	/*
+	 * Initialize all JPEG parameters to default values.
+	 * Note that jpeg_set_defaults needs legal values for
+	 * in_color_space and input_components.
+	 */
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+		sp->cinfo.c.input_components = td->td_samplesperpixel;
+		if (sp->photometric == PHOTOMETRIC_YCBCR) {
+			if (sp->jpegcolormode == JPEGCOLORMODE_RGB) {
+				sp->cinfo.c.in_color_space = JCS_RGB;
+			} else {
+				sp->cinfo.c.in_color_space = JCS_YCbCr;
+			}
+		} else {
+			if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1)
+				sp->cinfo.c.in_color_space = JCS_GRAYSCALE;
+			else if (td->td_photometric == PHOTOMETRIC_RGB && td->td_samplesperpixel == 3)
+				sp->cinfo.c.in_color_space = JCS_RGB;
+			else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4)
+				sp->cinfo.c.in_color_space = JCS_CMYK;
+			else
+				sp->cinfo.c.in_color_space = JCS_UNKNOWN;
+		}
+	} else {
+		sp->cinfo.c.input_components = 1;
+		sp->cinfo.c.in_color_space = JCS_UNKNOWN;
+	}
+	if (!TIFFjpeg_set_defaults(sp))
+		return (0);
+	/* Set per-file parameters */
+	switch (sp->photometric) {
+	case PHOTOMETRIC_YCBCR:
+		sp->h_sampling = td->td_ycbcrsubsampling[0];
+		sp->v_sampling = td->td_ycbcrsubsampling[1];
+		/*
+		 * 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);
+	}
+
+	/* 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 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);
+  
+	if (sp->cinfo.comm.is_decompressor == 1)
+	{
+		tif->tif_setupencode( tif );
+	}
+  
+	assert(!sp->cinfo.comm.is_decompressor);
+	/*
+	 * Set encoding parameters for this strip/tile.
+	 */
+	if (isTiled(tif)) {
+		segment_width = td->td_tilewidth;
+		segment_height = td->td_tilelength;
+		sp->bytesperline = TIFFTileRowSize(tif);
+	} else {
+		segment_width = td->td_imagewidth;
+		segment_height = td->td_imagelength - tif->tif_row;
+		if (segment_height > td->td_rowsperstrip)
+			segment_height = td->td_rowsperstrip;
+		sp->bytesperline = TIFFScanlineSize(tif);
+	}
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) {
+		/* for PC 2, scale down the strip/tile size
+		 * to match a downsampled component
+		 */
+		segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); 
+		segment_height = TIFFhowmany_32(segment_height, sp->v_sampling);
+	}
+	if (segment_width > 65535 || segment_height > 65535) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Strip/tile too large for JPEG");
+		return (0);
+	}
+	sp->cinfo.c.image_width = segment_width;
+	sp->cinfo.c.image_height = segment_height;
+	downsampled_input = FALSE;
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+		sp->cinfo.c.input_components = td->td_samplesperpixel;
+		if (sp->photometric == PHOTOMETRIC_YCBCR) {
+			if (sp->jpegcolormode != JPEGCOLORMODE_RGB) {
+				if (sp->h_sampling != 1 || sp->v_sampling != 1)
+					downsampled_input = TRUE;
+			}
+			if (!TIFFjpeg_set_colorspace(sp, JCS_YCbCr))
+				return (0);
+			/*
+			 * Set Y sampling factors;
+			 * we assume jpeg_set_colorspace() set the rest to 1
+			 */
+			sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling;
+			sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling;
+		} else {
+			if (!TIFFjpeg_set_colorspace(sp, sp->cinfo.c.in_color_space))
+				return (0);
+			/* jpeg_set_colorspace set all sampling factors to 1 */
+		}
+	} else {
+		if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN))
+			return (0);
+		sp->cinfo.c.comp_info[0].component_id = s;
+		/* jpeg_set_colorspace() set sampling factors to 1 */
+		if (sp->photometric == PHOTOMETRIC_YCBCR && s > 0) {
+			sp->cinfo.c.comp_info[0].quant_tbl_no = 1;
+			sp->cinfo.c.comp_info[0].dc_tbl_no = 1;
+			sp->cinfo.c.comp_info[0].ac_tbl_no = 1;
+		}
+	}
+	/* ensure libjpeg won't write any extraneous markers */
+	sp->cinfo.c.write_JFIF_header = FALSE;
+	sp->cinfo.c.write_Adobe_marker = FALSE;
+	/* set up table handling correctly */
+	/* calling TIFFjpeg_set_quality() causes quantization tables to be flagged */
+	/* as being to be emitted, which we don't want in the JPEGTABLESMODE_QUANT */
+	/* mode, so we must manually suppress them. However TIFFjpeg_set_quality() */
+	/* should really be called when dealing with files with directories with */
+	/* mixed qualities. see http://trac.osgeo.org/gdal/ticket/3539 */
+	if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE))
+		return (0);
+	if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) {
+		suppress_quant_table(sp, 0);
+		suppress_quant_table(sp, 1);
+	}
+	else {
+		unsuppress_quant_table(sp, 0);
+		unsuppress_quant_table(sp, 1);
+	}
+	if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF)
+	{
+		/* Explicit suppression is only needed if we did not go through the */
+		/* prepare_JPEGTables() code path, which may be the case if updating */
+		/* an existing file */
+		suppress_huff_table(sp, 0);
+		suppress_huff_table(sp, 1);
+		sp->cinfo.c.optimize_coding = FALSE;
+	}
+	else
+		sp->cinfo.c.optimize_coding = TRUE;
+	if (downsampled_input) {
+		/* Need to use raw-data interface to libjpeg */
+		sp->cinfo.c.raw_data_in = TRUE;
+		tif->tif_encoderow = JPEGEncodeRaw;
+		tif->tif_encodestrip = JPEGEncodeRaw;
+		tif->tif_encodetile = JPEGEncodeRaw;
+	} else {
+		/* Use normal interface to libjpeg */
+		sp->cinfo.c.raw_data_in = FALSE;
+		tif->tif_encoderow = JPEGEncode;
+		tif->tif_encodestrip = JPEGEncode;
+		tif->tif_encodetile = JPEGEncode;
+	}
+	/* Start JPEG compressor */
+	if (!TIFFjpeg_start_compress(sp, FALSE))
+		return (0);
+	/* Allocate downsampled-data buffers if needed */
+	if (downsampled_input) {
+		if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info,
+					       sp->cinfo.c.num_components))
+			return (0);
+	}
+	sp->scancount = 0;
+
+	return (1);
+}
+
+/*
+ * Encode a chunk of pixels.
+ * "Standard" case: incoming data is not downsampled.
+ */
+static int
+JPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	tmsize_t nrows;
+	JSAMPROW bufptr[1];
+        short *line16 = NULL;
+        int    line16_count = 0;
+
+	(void) s;
+	assert(sp != NULL);
+	/* data is expected to be supplied in multiples of a scanline */
+	nrows = cc / sp->bytesperline;
+	if (cc % sp->bytesperline)
+            TIFFWarningExt(tif->tif_clientdata, tif->tif_name, 
+                           "fractional scanline discarded");
+
+        /* The last strip will be limited to image size */
+        if( !isTiled(tif) && tif->tif_row+nrows > tif->tif_dir.td_imagelength )
+            nrows = tif->tif_dir.td_imagelength - tif->tif_row;
+
+        if( sp->cinfo.c.data_precision == 12 )
+        {
+            line16_count = (sp->bytesperline * 2) / 3;
+            line16 = (short *) _TIFFmalloc(sizeof(short) * line16_count);
+            if (!line16)
+            {
+                TIFFErrorExt(tif->tif_clientdata,
+			     "JPEGEncode",
+                             "Failed to allocate memory");
+
+                return 0;
+            }
+        }
+            
+	while (nrows-- > 0) {
+
+            if( sp->cinfo.c.data_precision == 12 )
+            {
+
+                int value_pairs = line16_count / 2;
+                int iPair;
+
+		bufptr[0] = (JSAMPROW) line16;
+
+                for( iPair = 0; iPair < value_pairs; iPair++ )
+                {
+                    unsigned char *in_ptr =
+                        ((unsigned char *) buf) + iPair * 3;
+                    JSAMPLE *out_ptr = (JSAMPLE *) (line16 + iPair * 2);
+
+                    out_ptr[0] = (in_ptr[0] << 4) | ((in_ptr[1] & 0xf0) >> 4);
+                    out_ptr[1] = ((in_ptr[1] & 0x0f) << 8) | in_ptr[2];
+                }
+            }
+            else
+            {
+		bufptr[0] = (JSAMPROW) buf;
+            }
+            if (TIFFjpeg_write_scanlines(sp, bufptr, 1) != 1)
+                return (0);
+            if (nrows > 0)
+                tif->tif_row++;
+            buf += sp->bytesperline;
+	}
+
+        if( sp->cinfo.c.data_precision == 12 )
+        {
+            _TIFFfree( line16 );
+        }
+            
+	return (1);
+}
+
+/*
+ * Encode a chunk of pixels.
+ * Incoming data is expected to be downsampled per sampling factors.
+ */
+static int
+JPEGEncodeRaw(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	JPEGState *sp = JState(tif);
+	JSAMPLE* inptr;
+	JSAMPLE* outptr;
+	tmsize_t nrows;
+	JDIMENSION clumps_per_line, nclump;
+	int clumpoffset, ci, xpos, ypos;
+	jpeg_component_info* compptr;
+	int samples_per_clump = sp->samplesperclump;
+	tmsize_t bytesperclumpline;
+
+	(void) s;
+	assert(sp != NULL);
+	/* data is expected to be supplied in multiples of a clumpline */
+	/* a clumpline is equivalent to v_sampling desubsampled scanlines */
+	/* TODO: the following calculation of bytesperclumpline, should substitute calculation of sp->bytesperline, except that it is per v_sampling lines */
+	bytesperclumpline = (((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 += bytesperclumpline;
+		nrows -= sp->v_sampling;
+	}
+	return (1);
+}
+
+/*
+ * Finish up at the end of a strip or tile.
+ */
+static int
+JPEGPostEncode(TIFF* tif)
+{
+	JPEGState *sp = JState(tif);
+
+	if (sp->scancount > 0) {
+		/*
+		 * Need to emit a partial bufferload of downsampled data.
+		 * Pad the data vertically.
+		 */
+		int ci, ypos, n;
+		jpeg_component_info* compptr;
+
+		for (ci = 0, compptr = sp->cinfo.c.comp_info;
+		     ci < sp->cinfo.c.num_components;
+		     ci++, compptr++) {
+			int vsamp = compptr->v_samp_factor;
+			tmsize_t row_width = compptr->width_in_blocks * DCTSIZE
+				* sizeof(JSAMPLE);
+			for (ypos = sp->scancount * vsamp;
+			     ypos < DCTSIZE * vsamp; ypos++) {
+				_TIFFmemcpy((void*)sp->ds_buffer[ci][ypos],
+					    (void*)sp->ds_buffer[ci][ypos-1],
+					    row_width);
+
+			}
+		}
+		n = sp->cinfo.c.max_v_samp_factor * DCTSIZE;
+		if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n)
+			return (0);
+	}
+
+	return (TIFFjpeg_finish_compress(JState(tif)));
+}
+
+static void
+JPEGCleanup(TIFF* tif)
+{
+	JPEGState *sp = JState(tif);
+	
+	assert(sp != 0);
+
+	tif->tif_tagmethods.vgetfield = sp->vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->vsetparent;
+	tif->tif_tagmethods.printdir = sp->printdir;
+        if( sp->cinfo_initialized )
+                TIFFjpeg_destroy(sp);	/* release libjpeg resources */
+        if (sp->jpegtables)		/* tag value */
+                _TIFFfree(sp->jpegtables);
+	_TIFFfree(tif->tif_data);	/* release local state */
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+static void 
+JPEGResetUpsampled( TIFF* tif )
+{
+	JPEGState* sp = JState(tif);
+	TIFFDirectory* td = &tif->tif_dir;
+
+	/*
+	 * Mark whether returned data is up-sampled or not so TIFFStripSize
+	 * and TIFFTileSize return values that reflect the true amount of
+	 * data.
+	 */
+	tif->tif_flags &= ~TIFF_UPSAMPLED;
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+		if (td->td_photometric == PHOTOMETRIC_YCBCR &&
+		    sp->jpegcolormode == JPEGCOLORMODE_RGB) {
+			tif->tif_flags |= TIFF_UPSAMPLED;
+		} else {
+#ifdef notdef
+			if (td->td_ycbcrsubsampling[0] != 1 ||
+			    td->td_ycbcrsubsampling[1] != 1)
+				; /* XXX what about up-sampling? */
+#endif
+		}
+	}
+
+	/*
+	 * Must recalculate cached tile size in case sampling state changed.
+	 * Should we really be doing this now if image size isn't set? 
+	 */
+        if( tif->tif_tilesize > 0 )
+            tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t)(-1);   
+        if( tif->tif_scanlinesize > 0 )
+            tif->tif_scanlinesize = TIFFScanlineSize(tif); 
+}
+
+static int
+JPEGVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	JPEGState* sp = JState(tif);
+	const TIFFField* fip;
+	uint32 v32;
+
+	assert(sp != NULL);
+
+	switch (tag) {
+	case TIFFTAG_JPEGTABLES:
+		v32 = (uint32) 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 = (int) va_arg(ap, int);
+		return (1);			/* pseudo tag */
+	case TIFFTAG_JPEGCOLORMODE:
+		sp->jpegcolormode = (int) va_arg(ap, int);
+		JPEGResetUpsampled( tif );
+		return (1);			/* pseudo tag */
+	case TIFFTAG_PHOTOMETRIC:
+	{
+		int ret_value = (*sp->vsetparent)(tif, tag, ap);
+		JPEGResetUpsampled( tif );
+		return ret_value;
+	}
+	case TIFFTAG_JPEGTABLESMODE:
+		sp->jpegtablesmode = (int) va_arg(ap, int);
+		return (1);			/* pseudo tag */
+	case TIFFTAG_YCBCRSUBSAMPLING:
+		/* mark the fact that we have a real ycbcrsubsampling! */
+		sp->ycbcrsampling_fetched = 1;
+		/* should we be recomputing upsampling info here? */
+		return (*sp->vsetparent)(tif, tag, ap);
+	default:
+		return (*sp->vsetparent)(tif, tag, ap);
+	}
+
+	if ((fip = TIFFFieldWithTag(tif, tag))) {
+		TIFFSetFieldBit(tif, fip->field_bit);
+	} else {
+		return (0);
+	}
+
+	tif->tif_flags |= TIFF_DIRTYDIRECT;
+	return (1);
+}
+
+static int
+JPEGVGetField(TIFF* tif, uint32 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;
+		default:
+			return (*sp->vgetparent)(tif, tag, ap);
+	}
+	return (1);
+}
+
+static void
+JPEGPrintDir(TIFF* tif, FILE* fd, long flags)
+{
+	JPEGState* sp = JState(tif);
+
+	assert(sp != NULL);
+	(void) flags;
+
+        if( sp != NULL ) {
+		if (TIFFFieldSet(tif,FIELD_JPEGTABLES))
+			fprintf(fd, "  JPEG Tables: (%lu bytes)\n",
+				(unsigned long) sp->jpegtables_length);
+		if (sp->printdir)
+			(*sp->printdir)(tif, fd, flags);
+	}
+}
+
+static uint32
+JPEGDefaultStripSize(TIFF* tif, uint32 s)
+{
+	JPEGState* sp = JState(tif);
+	TIFFDirectory *td = &tif->tif_dir;
+
+	s = (*sp->defsparent)(tif, s);
+	if (s < td->td_imagelength)
+		s = TIFFroundup_32(s, td->td_ycbcrsubsampling[1] * DCTSIZE);
+	return (s);
+}
+
+static void
+JPEGDefaultTileSize(TIFF* tif, uint32* tw, uint32* th)
+{
+	JPEGState* sp = JState(tif);
+	TIFFDirectory *td = &tif->tif_dir;
+
+	(*sp->deftparent)(tif, tw, th);
+	*tw = TIFFroundup_32(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE);
+	*th = TIFFroundup_32(*th, td->td_ycbcrsubsampling[1] * DCTSIZE);
+}
+
+/*
+ * The JPEG library initialized used to be done in TIFFInitJPEG(), but
+ * now that we allow a TIFF file to be opened in update mode it is necessary
+ * to have some way of deciding whether compression or decompression is
+ * desired other than looking at tif->tif_mode.  We accomplish this by 
+ * examining {TILE/STRIP}BYTECOUNTS to see if there is a non-zero entry.
+ * If so, we assume decompression is desired. 
+ *
+ * This is tricky, because TIFFInitJPEG() is called while the directory is
+ * being read, and generally speaking the BYTECOUNTS tag won't have been read
+ * at that point.  So we try to defer jpeg library initialization till we
+ * do have that tag ... basically any access that might require the compressor
+ * or decompressor that occurs after the reading of the directory. 
+ *
+ * In an ideal world compressors or decompressors would be setup
+ * at the point where a single tile or strip was accessed (for read or write)
+ * so that stuff like update of missing tiles, or replacement of tiles could
+ * be done. However, we aren't trying to crack that nut just yet ...
+ *
+ * NFW, Feb 3rd, 2003.
+ */
+
+static int JPEGInitializeLibJPEG( TIFF * tif, int decompress )
+{
+    JPEGState* sp = JState(tif);
+
+    if(sp->cinfo_initialized)
+    {
+        if( !decompress && sp->cinfo.comm.is_decompressor )
+            TIFFjpeg_destroy( sp );
+        else if( decompress && !sp->cinfo.comm.is_decompressor )
+            TIFFjpeg_destroy( sp );
+        else
+            return 1;
+
+        sp->cinfo_initialized = 0;
+    }
+
+    /*
+     * Initialize libjpeg.
+     */
+    if ( decompress ) {
+        if (!TIFFjpeg_create_decompress(sp))
+            return (0);
+    } else {
+        if (!TIFFjpeg_create_compress(sp))
+            return (0);
+    }
+
+    sp->cinfo_initialized = TRUE;
+
+    return 1;
+}
+
+int
+TIFFInitJPEG(TIFF* tif, int scheme)
+{
+	JPEGState* sp;
+
+	assert(scheme == COMPRESSION_JPEG);
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, jpegFields, TIFFArrayCount(jpegFields))) {
+		TIFFErrorExt(tif->tif_clientdata,
+			     "TIFFInitJPEG",
+			     "Merging JPEG codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*) _TIFFmalloc(sizeof (JPEGState));
+
+	if (tif->tif_data == NULL) {
+		TIFFErrorExt(tif->tif_clientdata,
+			     "TIFFInitJPEG", "No space for JPEG state block");
+		return 0;
+	}
+        _TIFFmemset(tif->tif_data, 0, sizeof(JPEGState));
+
+	sp = JState(tif);
+	sp->tif = tif;				/* back link */
+
+	/*
+	 * Override parent get/set field methods.
+	 */
+	sp->vgetparent = tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield = JPEGVGetField; /* hook for codec tags */
+	sp->vsetparent = tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield = JPEGVSetField; /* hook for codec tags */
+	sp->printdir = tif->tif_tagmethods.printdir;
+	tif->tif_tagmethods.printdir = JPEGPrintDir;   /* hook for codec tags */
+
+	/* Default values for codec-specific fields */
+	sp->jpegtables = NULL;
+	sp->jpegtables_length = 0;
+	sp->jpegquality = 75;			/* Default IJG quality */
+	sp->jpegcolormode = JPEGCOLORMODE_RAW;
+	sp->jpegtablesmode = JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF;
+        sp->ycbcrsampling_fetched = 0;
+
+	/*
+	 * Install codec methods.
+	 */
+	tif->tif_fixuptags = JPEGFixupTags;
+	tif->tif_setupdecode = JPEGSetupDecode;
+	tif->tif_predecode = JPEGPreDecode;
+	tif->tif_decoderow = JPEGDecode;
+	tif->tif_decodestrip = JPEGDecode;
+	tif->tif_decodetile = JPEGDecode;
+	tif->tif_setupencode = JPEGSetupEncode;
+	tif->tif_preencode = JPEGPreEncode;
+	tif->tif_postencode = JPEGPostEncode;
+	tif->tif_encoderow = JPEGEncode;
+	tif->tif_encodestrip = JPEGEncode;
+	tif->tif_encodetile = JPEGEncode;  
+	tif->tif_cleanup = JPEGCleanup;
+	sp->defsparent = tif->tif_defstripsize;
+	tif->tif_defstripsize = JPEGDefaultStripSize;
+	sp->deftparent = tif->tif_deftilesize;
+	tif->tif_deftilesize = JPEGDefaultTileSize;
+	tif->tif_flags |= TIFF_NOBITREV;	/* no bit reversal, please */
+
+        sp->cinfo_initialized = FALSE;
+
+	/*
+        ** Create a JPEGTables field if no directory has yet been created. 
+        ** We do this just to ensure that sufficient space is reserved for
+        ** the JPEGTables field.  It will be properly created the right
+        ** size later. 
+        */
+        if( tif->tif_diroff == 0 )
+        {
+#define SIZE_OF_JPEGTABLES 2000
+/*
+The following line assumes incorrectly that all JPEG-in-TIFF files will have
+a JPEGTABLES tag generated and causes null-filled JPEGTABLES tags to be written
+when the JPEG data is placed with TIFFWriteRawStrip.  The field bit should be 
+set, anyway, later when actual JPEGTABLES header is generated, so removing it 
+here hopefully is harmless.
+            TIFFSetFieldBit(tif, FIELD_JPEGTABLES);
+*/
+            sp->jpegtables_length = SIZE_OF_JPEGTABLES;
+            sp->jpegtables = (void *) _TIFFmalloc(sp->jpegtables_length);
+            if (sp->jpegtables)
+            {
+                _TIFFmemset(sp->jpegtables, 0, SIZE_OF_JPEGTABLES);
+            }
+            else
+            {
+                TIFFErrorExt(tif->tif_clientdata,
+			     "TIFFInitJPEG",
+                             "Failed to allocate memory for JPEG tables");
+                return 0;
+            }
+#undef SIZE_OF_JPEGTABLES
+        }
+
+	return 1;
+}
+#endif /* JPEG_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_luv.c b/third_party/libtiff/tif_luv.c
new file mode 100644
index 0000000..4e328ba
--- /dev/null
+++ b/third_party/libtiff/tif_luv.c
@@ -0,0 +1,1697 @@
+/* $Id: tif_luv.c,v 1.40 2015-06-21 01:09:09 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler, Greg Larson and Silicon Graphics may not be used in any
+ * advertising or publicity relating to the software without the specific,
+ * prior written permission of Sam Leffler, Greg Larson and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER, GREG LARSON OR SILICON GRAPHICS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef LOGLUV_SUPPORT
+
+/*
+ * TIFF Library.
+ * LogLuv compression support for high dynamic range images.
+ *
+ * Contributed by Greg Larson.
+ *
+ * LogLuv image support uses the TIFF library to store 16 or 10-bit
+ * log luminance values with 8 bits each of u and v or a 14-bit index.
+ *
+ * The codec can take as input and produce as output 32-bit IEEE float values 
+ * as well as 16-bit integer values.  A 16-bit luminance is interpreted
+ * as a sign bit followed by a 15-bit integer that is converted
+ * to and from a linear magnitude using the transformation:
+ *
+ *	L = 2^( (Le+.5)/256 - 64 )		# real from 15-bit
+ *
+ *	Le = floor( 256*(log2(L) + 64) )	# 15-bit from real
+ *
+ * The actual conversion to world luminance units in candelas per sq. meter
+ * requires an additional multiplier, which is stored in the TIFFTAG_STONITS.
+ * This value is usually set such that a reasonable exposure comes from
+ * clamping decoded luminances above 1 to 1 in the displayed image.
+ *
+ * The 16-bit values for u and v may be converted to real values by dividing
+ * each by 32768.  (This allows for negative values, which aren't useful as
+ * far as we know, but are left in case of future improvements in human
+ * color vision.)
+ *
+ * Conversion from (u,v), which is actually the CIE (u',v') system for
+ * you color scientists, is accomplished by the following transformation:
+ *
+ *	u = 4*x / (-2*x + 12*y + 3)
+ *	v = 9*y / (-2*x + 12*y + 3)
+ *
+ *	x = 9*u / (6*u - 16*v + 12)
+ *	y = 4*v / (6*u - 16*v + 12)
+ *
+ * This process is greatly simplified by passing 32-bit IEEE floats
+ * for each of three CIE XYZ coordinates.  The codec then takes care
+ * of conversion to and from LogLuv, though the application is still
+ * responsible for interpreting the TIFFTAG_STONITS calibration factor.
+ *
+ * By definition, a CIE XYZ vector of [1 1 1] corresponds to a neutral white
+ * point of (x,y)=(1/3,1/3).  However, most color systems assume some other
+ * white point, such as D65, and an absolute color conversion to XYZ then
+ * to another color space with a different white point may introduce an
+ * unwanted color cast to the image.  It is often desirable, therefore, to
+ * perform a white point conversion that maps the input white to [1 1 1]
+ * in XYZ, then record the original white point using the TIFFTAG_WHITEPOINT
+ * tag value.  A decoder that demands absolute color calibration may use
+ * this white point tag to get back the original colors, but usually it
+ * will be ignored and the new white point will be used instead that
+ * matches the output color space.
+ *
+ * Pixel information is compressed into one of two basic encodings, depending
+ * on the setting of the compression tag, which is one of COMPRESSION_SGILOG
+ * or COMPRESSION_SGILOG24.  For COMPRESSION_SGILOG, greyscale data is
+ * stored as:
+ *
+ *	 1       15
+ *	|-+---------------|
+ *
+ * COMPRESSION_SGILOG color data is stored as:
+ *
+ *	 1       15           8        8
+ *	|-+---------------|--------+--------|
+ *	 S       Le           ue       ve
+ *
+ * For the 24-bit COMPRESSION_SGILOG24 color format, the data is stored as:
+ *
+ *	     10           14
+ *	|----------|--------------|
+ *	     Le'          Ce
+ *
+ * There is no sign bit in the 24-bit case, and the (u,v) chromaticity is
+ * encoded as an index for optimal color resolution.  The 10 log bits are
+ * defined by the following conversions:
+ *
+ *	L = 2^((Le'+.5)/64 - 12)		# real from 10-bit
+ *
+ *	Le' = floor( 64*(log2(L) + 12) )	# 10-bit from real
+ *
+ * The 10 bits of the smaller format may be converted into the 15 bits of
+ * the larger format by multiplying by 4 and adding 13314.  Obviously,
+ * a smaller range of magnitudes is covered (about 5 orders of magnitude
+ * instead of 38), and the lack of a sign bit means that negative luminances
+ * are not allowed.  (Well, they aren't allowed in the real world, either,
+ * but they are useful for certain types of image processing.)
+ *
+ * The desired user format is controlled by the setting the internal
+ * pseudo tag TIFFTAG_SGILOGDATAFMT to one of:
+ *  SGILOGDATAFMT_FLOAT       = IEEE 32-bit float XYZ values
+ *  SGILOGDATAFMT_16BIT	      = 16-bit integer encodings of logL, u and v
+ * Raw data i/o is also possible using:
+ *  SGILOGDATAFMT_RAW         = 32-bit unsigned integer with encoded pixel
+ * In addition, the following decoding is provided for ease of display:
+ *  SGILOGDATAFMT_8BIT        = 8-bit default RGB gamma-corrected values
+ *
+ * For grayscale images, we provide the following data formats:
+ *  SGILOGDATAFMT_FLOAT       = IEEE 32-bit float Y values
+ *  SGILOGDATAFMT_16BIT       = 16-bit integer w/ encoded luminance
+ *  SGILOGDATAFMT_8BIT        = 8-bit gray monitor values
+ *
+ * Note that the COMPRESSION_SGILOG applies a simple run-length encoding
+ * scheme by separating the logL, u and v bytes for each row and applying
+ * a PackBits type of compression.  Since the 24-bit encoding is not
+ * adaptive, the 32-bit color format takes less space in many cases.
+ *
+ * Further control is provided over the conversion from higher-resolution
+ * formats to final encoded values through the pseudo tag
+ * TIFFTAG_SGILOGENCODE:
+ *  SGILOGENCODE_NODITHER     = do not dither encoded values
+ *  SGILOGENCODE_RANDITHER    = apply random dithering during encoding
+ *
+ * The default value of this tag is SGILOGENCODE_NODITHER for
+ * COMPRESSION_SGILOG to maximize run-length encoding and
+ * SGILOGENCODE_RANDITHER for COMPRESSION_SGILOG24 to turn
+ * quantization errors into noise.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+/*
+ * State block for each open TIFF
+ * file using LogLuv compression/decompression.
+ */
+typedef struct logLuvState LogLuvState;
+
+struct logLuvState {
+	int                     user_datafmt;   /* user data format */
+	int                     encode_meth;    /* encoding method */
+	int                     pixel_size;     /* bytes per pixel */
+
+	uint8*                  tbuf;           /* translation buffer */
+	tmsize_t                tbuflen;        /* buffer length */
+	void (*tfunc)(LogLuvState*, uint8*, tmsize_t);
+
+	TIFFVSetMethod          vgetparent;     /* super-class method */
+	TIFFVSetMethod          vsetparent;     /* super-class method */
+};
+
+#define DecoderState(tif)	((LogLuvState*) (tif)->tif_data)
+#define EncoderState(tif)	((LogLuvState*) (tif)->tif_data)
+
+#define SGILOGDATAFMT_UNKNOWN -1
+
+#define MINRUN 4 /* minimum run length */
+
+/*
+ * Decode a string of 16-bit gray pixels.
+ */
+static int
+LogL16Decode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "LogL16Decode";
+	LogLuvState* sp = DecoderState(tif);
+	int shft;
+	tmsize_t i;
+	tmsize_t npixels;
+	unsigned char* bp;
+	int16* tp;
+	int16 b;
+	tmsize_t cc;
+	int 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((void*) 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);   /* TODO: potential input buffer overrun when decoding corrupt or truncated data */
+				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) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Not enough data at row %lu (short %I64d pixels)",
+				     (unsigned long) tif->tif_row,
+				     (unsigned __int64) (npixels - i));
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Not enough data at row %lu (short %llu pixels)",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long long) (npixels - i));
+#endif
+			tif->tif_rawcp = (uint8*) bp;
+			tif->tif_rawcc = cc;
+			return (0);
+		}
+	}
+	(*sp->tfunc)(sp, op, npixels);
+	tif->tif_rawcp = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	return (1);
+}
+
+/*
+ * Decode a string of 24-bit pixels.
+ */
+static int
+LogLuvDecode24(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "LogLuvDecode24";
+	LogLuvState* sp = DecoderState(tif);
+	tmsize_t cc;
+	tmsize_t i;
+	tmsize_t 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 = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	if (i != npixels) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at row %lu (short %I64d pixels)",
+			     (unsigned long) tif->tif_row,
+			     (unsigned __int64) (npixels - i));
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at row %lu (short %llu pixels)",
+			     (unsigned long) tif->tif_row,
+			     (unsigned long long) (npixels - i));
+#endif
+		return (0);
+	}
+	(*sp->tfunc)(sp, op, npixels);
+	return (1);
+}
+
+/*
+ * Decode a string of 32-bit pixels.
+ */
+static int
+LogLuvDecode32(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "LogLuvDecode32";
+	LogLuvState* sp;
+	int shft;
+	tmsize_t i;
+	tmsize_t npixels;
+	unsigned char* bp;
+	uint32* tp;
+	uint32 b;
+	tmsize_t cc;
+	int 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((void*) 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;                /* TODO: potential input buffer overrun when decoding corrupt or truncated data */
+				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) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at row %lu (short %I64d pixels)",
+				     (unsigned long) tif->tif_row,
+				     (unsigned __int64) (npixels - i));
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at row %lu (short %llu pixels)",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long long) (npixels - i));
+#endif
+			tif->tif_rawcp = (uint8*) bp;
+			tif->tif_rawcc = cc;
+			return (0);
+		}
+	}
+	(*sp->tfunc)(sp, op, npixels);
+	tif->tif_rawcp = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	return (1);
+}
+
+/*
+ * Decode a strip of pixels.  We break it into rows to
+ * maintain synchrony with the encode algorithm, which
+ * is row by row.
+ */
+static int
+LogLuvDecodeStrip(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	tmsize_t rowlen = TIFFScanlineSize(tif);
+
+        if (rowlen == 0)
+                return 0;
+
+	assert(cc%rowlen == 0);
+	while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s))
+		bp += rowlen, cc -= rowlen;
+	return (cc == 0);
+}
+
+/*
+ * Decode a tile of pixels.  We break it into rows to
+ * maintain synchrony with the encode algorithm, which
+ * is row by row.
+ */
+static int
+LogLuvDecodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	tmsize_t rowlen = TIFFTileRowSize(tif);
+
+        if (rowlen == 0)
+                return 0;
+
+	assert(cc%rowlen == 0);
+	while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s))
+		bp += rowlen, cc -= rowlen;
+	return (cc == 0);
+}
+
+/*
+ * Encode a row of 16-bit pixels.
+ */
+static int
+LogL16Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	LogLuvState* sp = EncoderState(tif);
+	int shft;
+	tmsize_t i;
+	tmsize_t j;
+	tmsize_t npixels;
+	uint8* op;
+	int16* tp;
+	int16 b;
+	tmsize_t occ;
+	int rc=0, mask;
+	tmsize_t 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++ = (uint8)(128-2+j-i);
+						*op++ = (uint8)(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++ = (uint8) j; occ--;
+				while (j--) {
+					*op++ = (uint8) (tp[i++] >> shft & 0xff);
+					occ--;
+				}
+			}
+			if (rc >= MINRUN) {		/* write out run */
+				*op++ = (uint8) (128-2+rc);
+				*op++ = (uint8) (tp[beg] >> shft & 0xff);
+				occ -= 2;
+			} else
+				rc = 0;
+		}
+	tif->tif_rawcp = op;
+	tif->tif_rawcc = tif->tif_rawdatasize - occ;
+
+	return (1);
+}
+
+/*
+ * Encode a row of 24-bit pixels.
+ */
+static int
+LogLuvEncode24(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	LogLuvState* sp = EncoderState(tif);
+	tmsize_t i;
+	tmsize_t npixels;
+	tmsize_t occ;
+	uint8* 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++ = (uint8)(*tp >> 16);
+		*op++ = (uint8)(*tp >> 8 & 0xff);
+		*op++ = (uint8)(*tp++ & 0xff);
+		occ -= 3;
+	}
+	tif->tif_rawcp = op;
+	tif->tif_rawcc = tif->tif_rawdatasize - occ;
+
+	return (1);
+}
+
+/*
+ * Encode a row of 32-bit pixels.
+ */
+static int
+LogLuvEncode32(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	LogLuvState* sp = EncoderState(tif);
+	int shft;
+	tmsize_t i;
+	tmsize_t j;
+	tmsize_t npixels;
+	uint8* op;
+	uint32* tp;
+	uint32 b;
+	tmsize_t occ;
+	int rc=0, mask;
+	tmsize_t 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++ = (uint8)(128-2+j-i);
+						*op++ = (uint8)(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++ = (uint8) j; occ--;
+				while (j--) {
+					*op++ = (uint8)(tp[i++] >> shft & 0xff);
+					occ--;
+				}
+			}
+			if (rc >= MINRUN) {		/* write out run */
+				*op++ = (uint8) (128-2+rc);
+				*op++ = (uint8)(tp[beg] >> shft & 0xff);
+				occ -= 2;
+			} else
+				rc = 0;
+		}
+	tif->tif_rawcp = op;
+	tif->tif_rawcc = tif->tif_rawdatasize - occ;
+
+	return (1);
+}
+
+/*
+ * Encode a strip of pixels.  We break it into rows to
+ * avoid encoding runs across row boundaries.
+ */
+static int
+LogLuvEncodeStrip(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	tmsize_t rowlen = TIFFScanlineSize(tif);
+
+        if (rowlen == 0)
+                return 0;
+
+	assert(cc%rowlen == 0);
+	while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1)
+		bp += rowlen, cc -= rowlen;
+	return (cc == 0);
+}
+
+/*
+ * Encode a tile of pixels.  We break it into rows to
+ * avoid encoding runs across row boundaries.
+ */
+static int
+LogLuvEncodeTile(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	tmsize_t rowlen = TIFFTileRowSize(tif);
+
+        if (rowlen == 0)
+                return 0;
+
+	assert(cc%rowlen == 0);
+	while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1)
+		bp += rowlen, cc -= rowlen;
+	return (cc == 0);
+}
+
+/*
+ * Encode/Decode functions for converting to and from user formats.
+ */
+
+#include "uvcode.h"
+
+#ifndef UVSCALE
+#define U_NEU		0.210526316
+#define V_NEU		0.473684211
+#define UVSCALE		410.
+#endif
+
+#ifndef	M_LN2
+#define M_LN2		0.69314718055994530942
+#endif
+#ifndef M_PI
+#define M_PI		3.14159265358979323846
+#endif
+#undef log2 /* Conflict with C'99 function */
+#define log2(x)		((1./M_LN2)*log(x))
+#undef exp2  /* Conflict with C'99 function */
+#define exp2(x)		exp(M_LN2*(x))
+
+#define itrunc(x,m)	((m)==SGILOGENCODE_NODITHER ? \
+				(int)(x) : \
+				(int)((x) + rand()*(1./RAND_MAX) - .5))
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+double
+LogL16toY(int p16)		/* compute luminance from 16-bit LogL */
+{
+	int	Le = p16 & 0x7fff;
+	double	Y;
+
+	if (!Le)
+		return (0.);
+	Y = exp(M_LN2/256.*(Le+.5) - M_LN2*64.);
+	return (!(p16 & 0x8000) ? Y : -Y);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+LogL16fromY(double Y, int em)	/* get 16-bit LogL from Y */
+{
+	if (Y >= 1.8371976e19)
+		return (0x7fff);
+	if (Y <= -1.8371976e19)
+		return (0xffff);
+	if (Y > 5.4136769e-20)
+		return itrunc(256.*(log2(Y) + 64.), em);
+	if (Y < -5.4136769e-20)
+		return (~0x7fff | itrunc(256.*(log2(-Y) + 64.), em));
+	return (0);
+}
+
+static void
+L16toY(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	int16* l16 = (int16*) sp->tbuf;
+	float* yp = (float*) op;
+
+	while (n-- > 0)
+		*yp++ = (float)LogL16toY(*l16++);
+}
+
+static void
+L16toGry(LogLuvState* sp, uint8* 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)));
+	}
+}
+
+static void
+L16fromY(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	int16* l16 = (int16*) sp->tbuf;
+	float* yp = (float*) op;
+
+	while (n-- > 0)
+		*l16++ = (int16) (LogL16fromY(*yp++, sp->encode_meth));
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+void
+XYZtoRGB24(float xyz[3], uint8 rgb[3])
+{
+	double	r, g, b;
+					/* assume CCIR-709 primaries */
+	r =  2.690*xyz[0] + -1.276*xyz[1] + -0.414*xyz[2];
+	g = -1.022*xyz[0] +  1.978*xyz[1] +  0.044*xyz[2];
+	b =  0.061*xyz[0] + -0.224*xyz[1] +  1.163*xyz[2];
+					/* assume 2.0 gamma for speed */
+	/* could use integer sqrt approx., but this is probably faster */
+	rgb[0] = (uint8)((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)));
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+double
+LogL10toY(int p10)		/* compute luminance from 10-bit LogL */
+{
+	if (p10 == 0)
+		return (0.);
+	return (exp(M_LN2/64.*(p10+.5) - M_LN2*12.));
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+LogL10fromY(double Y, int em)	/* get 10-bit LogL from Y */
+{
+	if (Y >= 15.742)
+		return (0x3ff);
+	else if (Y <= .00024283)
+		return (0);
+	else
+		return itrunc(64.*(log2(Y) + 12.), em);
+}
+
+#define NANGLES		100
+#define uv2ang(u, v)	( (NANGLES*.499999999/M_PI) \
+				* atan2((v)-V_NEU,(u)-U_NEU) + .5*NANGLES )
+
+static int
+oog_encode(double u, double v)		/* encode out-of-gamut chroma */
+{
+	static int	oog_table[NANGLES];
+	static int	initialized = 0;
+	register int	i;
+
+	if (!initialized) {		/* set up perimeter table */
+		double	eps[NANGLES], ua, va, ang, epsa;
+		int	ui, vi, ustep;
+		for (i = NANGLES; i--; )
+			eps[i] = 2.;
+		for (vi = UV_NVS; vi--; ) {
+			va = UV_VSTART + (vi+.5)*UV_SQSIZ;
+			ustep = uv_row[vi].nus-1;
+			if (vi == UV_NVS-1 || vi == 0 || ustep <= 0)
+				ustep = 1;
+			for (ui = uv_row[vi].nus-1; ui >= 0; ui -= ustep) {
+				ua = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ;
+				ang = uv2ang(ua, va);
+				i = (int) ang;
+				epsa = fabs(ang - (i+.5));
+				if (epsa < eps[i]) {
+					oog_table[i] = uv_row[vi].ncum + ui;
+					eps[i] = epsa;
+				}
+			}
+		}
+		for (i = NANGLES; i--; )	/* fill any holes */
+			if (eps[i] > 1.5) {
+				int	i1, i2;
+				for (i1 = 1; i1 < NANGLES/2; i1++)
+					if (eps[(i+i1)%NANGLES] < 1.5)
+						break;
+				for (i2 = 1; i2 < NANGLES/2; i2++)
+					if (eps[(i+NANGLES-i2)%NANGLES] < 1.5)
+						break;
+				if (i1 < i2)
+					oog_table[i] =
+						oog_table[(i+i1)%NANGLES];
+				else
+					oog_table[i] =
+						oog_table[(i+NANGLES-i2)%NANGLES];
+			}
+		initialized = 1;
+	}
+	i = (int) uv2ang(u, v);		/* look up hue angle */
+	return (oog_table[i]);
+}
+
+#undef uv2ang
+#undef NANGLES
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+uv_encode(double u, double v, int em)	/* encode (u',v') coordinates */
+{
+	register int	vi, ui;
+
+	if (v < UV_VSTART)
+		return oog_encode(u, v);
+	vi = 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);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+uv_decode(double *up, double *vp, int c)	/* decode (u',v') index */
+{
+	int	upper, lower;
+	register int	ui, vi;
+
+	if (c < 0 || c >= UV_NDIVS)
+		return (-1);
+	lower = 0;				/* binary search */
+	upper = UV_NVS;
+	while (upper - lower > 1) {
+		vi = (lower + upper) >> 1;
+		ui = c - uv_row[vi].ncum;
+		if (ui > 0)
+			lower = vi;
+		else if (ui < 0)
+			upper = vi;
+		else {
+			lower = vi;
+			break;
+		}
+	}
+	vi = lower;
+	ui = c - uv_row[vi].ncum;
+	*up = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ;
+	*vp = UV_VSTART + (vi+.5)*UV_SQSIZ;
+	return (0);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+void
+LogLuv24toXYZ(uint32 p, float XYZ[3])
+{
+	int	Ce;
+	double	L, u, v, s, x, y;
+					/* decode luminance */
+	L = LogL10toY(p>>14 & 0x3ff);
+	if (L <= 0.) {
+		XYZ[0] = XYZ[1] = XYZ[2] = 0.;
+		return;
+	}
+					/* decode color */
+	Ce = p & 0x3fff;
+	if (uv_decode(&u, &v, Ce) < 0) {
+		u = U_NEU; v = V_NEU;
+	}
+	s = 1./(6.*u - 16.*v + 12.);
+	x = 9.*u * s;
+	y = 4.*v * s;
+					/* convert to XYZ */
+	XYZ[0] = (float)(x/y * L);
+	XYZ[1] = (float)L;
+	XYZ[2] = (float)((1.-x-y)/y * L);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+uint32
+LogLuv24fromXYZ(float XYZ[3], int em)
+{
+	int	Le, Ce;
+	double	u, v, s;
+					/* encode luminance */
+	Le = LogL10fromY(XYZ[1], em);
+					/* encode color */
+	s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2];
+	if (!Le || s <= 0.) {
+		u = U_NEU;
+		v = V_NEU;
+	} else {
+		u = 4.*XYZ[0] / s;
+		v = 9.*XYZ[1] / s;
+	}
+	Ce = uv_encode(u, v, em);
+	if (Ce < 0)			/* never happens */
+		Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER);
+					/* combine encodings */
+	return (Le << 14 | Ce);
+}
+
+static void
+Luv24toXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	float* xyz = (float*) op;
+
+	while (n-- > 0) {
+		LogLuv24toXYZ(*luv, xyz);
+		xyz += 3;
+		luv++;
+	}
+}
+
+static void
+Luv24toLuv48(LogLuvState* sp, uint8* 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++;
+	}
+}
+
+static void
+Luv24toRGB(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	uint8* rgb = (uint8*) op;
+
+	while (n-- > 0) {
+		float xyz[3];
+
+		LogLuv24toXYZ(*luv++, xyz);
+		XYZtoRGB24(xyz, rgb);
+		rgb += 3;
+	}
+}
+
+static void
+Luv24fromXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	float* xyz = (float*) op;
+
+	while (n-- > 0) {
+		*luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth);
+		xyz += 3;
+	}
+}
+
+static void
+Luv24fromLuv48(LogLuvState* sp, uint8* 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;
+	}
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+void
+LogLuv32toXYZ(uint32 p, float XYZ[3])
+{
+	double	L, u, v, s, x, y;
+					/* decode luminance */
+	L = LogL16toY((int)p >> 16);
+	if (L <= 0.) {
+		XYZ[0] = XYZ[1] = XYZ[2] = 0.;
+		return;
+	}
+					/* decode color */
+	u = 1./UVSCALE * ((p>>8 & 0xff) + .5);
+	v = 1./UVSCALE * ((p & 0xff) + .5);
+	s = 1./(6.*u - 16.*v + 12.);
+	x = 9.*u * s;
+	y = 4.*v * s;
+					/* convert to XYZ */
+	XYZ[0] = (float)(x/y * L);
+	XYZ[1] = (float)L;
+	XYZ[2] = (float)((1.-x-y)/y * L);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+uint32
+LogLuv32fromXYZ(float XYZ[3], int em)
+{
+	unsigned int	Le, ue, ve;
+	double	u, v, s;
+					/* encode luminance */
+	Le = (unsigned int)LogL16fromY(XYZ[1], em);
+					/* encode color */
+	s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2];
+	if (!Le || s <= 0.) {
+		u = U_NEU;
+		v = V_NEU;
+	} else {
+		u = 4.*XYZ[0] / s;
+		v = 9.*XYZ[1] / s;
+	}
+	if (u <= 0.) ue = 0;
+	else ue = 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);
+}
+
+static void
+Luv32toXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	float* xyz = (float*) op;
+
+	while (n-- > 0) {
+		LogLuv32toXYZ(*luv++, xyz);
+		xyz += 3;
+	}
+}
+
+static void
+Luv32toLuv48(LogLuvState* sp, uint8* 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++;
+	}
+}
+
+static void
+Luv32toRGB(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	uint8* rgb = (uint8*) op;
+
+	while (n-- > 0) {
+		float xyz[3];
+
+		LogLuv32toXYZ(*luv++, xyz);
+		XYZtoRGB24(xyz, rgb);
+		rgb += 3;
+	}
+}
+
+static void
+Luv32fromXYZ(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	uint32* luv = (uint32*) sp->tbuf;  
+	float* xyz = (float*) op;
+
+	while (n-- > 0) {
+		*luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth);
+		xyz += 3;
+	}
+}
+
+static void
+Luv32fromLuv48(LogLuvState* sp, uint8* 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;
+	}
+}
+
+static void
+_logLuvNop(LogLuvState* sp, uint8* op, tmsize_t n)
+{
+	(void) sp; (void) op; (void) n;
+}
+
+static int
+LogL16GuessDataFmt(TIFFDirectory *td)
+{
+#define	PACK(s,b,f)	(((b)<<6)|((s)<<3)|(f))
+	switch (PACK(td->td_samplesperpixel, td->td_bitspersample, td->td_sampleformat)) {
+	case PACK(1, 32, SAMPLEFORMAT_IEEEFP):
+		return (SGILOGDATAFMT_FLOAT);
+	case PACK(1, 16, SAMPLEFORMAT_VOID):
+	case PACK(1, 16, SAMPLEFORMAT_INT):
+	case PACK(1, 16, SAMPLEFORMAT_UINT):
+		return (SGILOGDATAFMT_16BIT);
+	case PACK(1,  8, SAMPLEFORMAT_VOID):
+	case PACK(1,  8, SAMPLEFORMAT_UINT):
+		return (SGILOGDATAFMT_8BIT);
+	}
+#undef PACK
+	return (SGILOGDATAFMT_UNKNOWN);
+}
+
+static tmsize_t
+multiply_ms(tmsize_t m1, tmsize_t m2)
+{
+	tmsize_t bytes = m1 * m2;
+
+	if (m1 && bytes / m1 != m2)
+		bytes = 0;
+
+	return bytes;
+}
+
+static int
+LogL16InitState(TIFF* tif)
+{
+	static const char module[] = "LogL16InitState";
+	TIFFDirectory *td = &tif->tif_dir;
+	LogLuvState* sp = DecoderState(tif);
+
+	assert(sp != NULL);
+	assert(td->td_photometric == PHOTOMETRIC_LOGL);
+
+	/* 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, 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
+            sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_rowsperstrip);
+	if (multiply_ms(sp->tbuflen, sizeof (int16)) == 0 ||
+	    (sp->tbuf = (uint8*) _TIFFmalloc(sp->tbuflen * sizeof (int16))) == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, module, "No space for SGILog translation buffer");
+		return (0);
+	}
+	return (1);
+}
+
+static int
+LogLuvGuessDataFmt(TIFFDirectory *td)
+{
+	int guess;
+
+	/*
+	 * If the user didn't tell us their datafmt,
+	 * take our best guess from the bitspersample.
+	 */
+#define	PACK(a,b)	(((a)<<3)|(b))
+	switch (PACK(td->td_bitspersample, td->td_sampleformat)) {
+	case PACK(32, SAMPLEFORMAT_IEEEFP):
+		guess = SGILOGDATAFMT_FLOAT;
+		break;
+	case PACK(32, SAMPLEFORMAT_VOID):
+	case PACK(32, SAMPLEFORMAT_UINT):
+	case PACK(32, SAMPLEFORMAT_INT):
+		guess = SGILOGDATAFMT_RAW;
+		break;
+	case PACK(16, SAMPLEFORMAT_VOID):
+	case PACK(16, SAMPLEFORMAT_INT):
+	case PACK(16, SAMPLEFORMAT_UINT):
+		guess = SGILOGDATAFMT_16BIT;
+		break;
+	case PACK( 8, SAMPLEFORMAT_VOID):
+	case PACK( 8, SAMPLEFORMAT_UINT):
+		guess = SGILOGDATAFMT_8BIT;
+		break;
+	default:
+		guess = SGILOGDATAFMT_UNKNOWN;
+		break;
+#undef PACK
+	}
+	/*
+	 * Double-check samples per pixel.
+	 */
+	switch (td->td_samplesperpixel) {
+	case 1:
+		if (guess != SGILOGDATAFMT_RAW)
+			guess = SGILOGDATAFMT_UNKNOWN;
+		break;
+	case 3:
+		if (guess == SGILOGDATAFMT_RAW)
+			guess = SGILOGDATAFMT_UNKNOWN;
+		break;
+	default:
+		guess = SGILOGDATAFMT_UNKNOWN;
+		break;
+	}
+	return (guess);
+}
+
+static int
+LogLuvInitState(TIFF* tif)
+{
+	static const char module[] = "LogLuvInitState";
+	TIFFDirectory* td = &tif->tif_dir;
+	LogLuvState* sp = DecoderState(tif);
+
+	assert(sp != NULL);
+	assert(td->td_photometric == PHOTOMETRIC_LOGLUV);
+
+	/* for some reason, we can't do this in TIFFInitLogLuv */
+	if (td->td_planarconfig != PLANARCONFIG_CONTIG) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "SGILog compression cannot handle non-contiguous data");
+		return (0);
+	}
+	if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN)
+		sp->user_datafmt = LogLuvGuessDataFmt(td);
+	switch (sp->user_datafmt) {
+	case SGILOGDATAFMT_FLOAT:
+		sp->pixel_size = 3*sizeof (float);
+		break;
+	case SGILOGDATAFMT_16BIT:
+		sp->pixel_size = 3*sizeof (int16);
+		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, 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
+            sp->tbuflen = multiply_ms(td->td_imagewidth, td->td_rowsperstrip);
+	if (multiply_ms(sp->tbuflen, sizeof (uint32)) == 0 ||
+	    (sp->tbuf = (uint8*) _TIFFmalloc(sp->tbuflen * sizeof (uint32))) == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, module, "No space for SGILog translation buffer");
+		return (0);
+	}
+	return (1);
+}
+
+static int
+LogLuvFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+static int
+LogLuvSetupDecode(TIFF* tif)
+{
+	static const char module[] = "LogLuvSetupDecode";
+	LogLuvState* sp = DecoderState(tif);
+	TIFFDirectory* td = &tif->tif_dir;
+
+	tif->tif_postdecode = _TIFFNoPostDecode;
+	switch (td->td_photometric) {
+	case PHOTOMETRIC_LOGLUV:
+		if (!LogLuvInitState(tif))
+			break;
+		if (td->td_compression == COMPRESSION_SGILOG24) {
+			tif->tif_decoderow = LogLuvDecode24;
+			switch (sp->user_datafmt) {
+			case SGILOGDATAFMT_FLOAT:
+				sp->tfunc = Luv24toXYZ;  
+				break;
+			case SGILOGDATAFMT_16BIT:
+				sp->tfunc = Luv24toLuv48;  
+				break;
+			case SGILOGDATAFMT_8BIT:
+				sp->tfunc = Luv24toRGB;
+				break;
+			}
+		} else {
+			tif->tif_decoderow = LogLuvDecode32;
+			switch (sp->user_datafmt) {
+			case SGILOGDATAFMT_FLOAT:
+				sp->tfunc = Luv32toXYZ;
+				break;
+			case SGILOGDATAFMT_16BIT:
+				sp->tfunc = Luv32toLuv48;
+				break;
+			case SGILOGDATAFMT_8BIT:
+				sp->tfunc = Luv32toRGB;
+				break;
+			}
+		}
+		return (1);
+	case PHOTOMETRIC_LOGL:
+		if (!LogL16InitState(tif))
+			break;
+		tif->tif_decoderow = LogL16Decode;
+		switch (sp->user_datafmt) {
+		case SGILOGDATAFMT_FLOAT:
+			sp->tfunc = L16toY;
+			break;
+		case SGILOGDATAFMT_8BIT:
+			sp->tfunc = L16toGry;
+			break;
+		}
+		return (1);
+	default:
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Inappropriate photometric interpretation %d 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))
+			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, module,
+		    "Inappropriate photometric interpretation %d for SGILog compression; %s",
+		    td->td_photometric, "must be either LogLUV or LogL");
+		break;
+	}
+	return (1);
+notsupported:
+	TIFFErrorExt(tif->tif_clientdata, module,
+	    "SGILog compression supported only for %s, or raw data",
+	    td->td_photometric == PHOTOMETRIC_LOGL ? "Y, L" : "XYZ, Luv");
+	return (0);
+}
+
+static void
+LogLuvClose(TIFF* tif)
+{
+	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;
+}
+
+static void
+LogLuvCleanup(TIFF* tif)
+{
+	LogLuvState* sp = (LogLuvState *)tif->tif_data;
+
+	assert(sp != 0);
+
+	tif->tif_tagmethods.vgetfield = sp->vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+	if (sp->tbuf)
+		_TIFFfree(sp->tbuf);
+	_TIFFfree(sp);
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+static int
+LogLuvVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	static const char module[] = "LogLuvVSetField";
+	LogLuvState* sp = DecoderState(tif);
+	int bps, fmt;
+
+	switch (tag) {
+	case TIFFTAG_SGILOGDATAFMT:
+		sp->user_datafmt = (int) va_arg(ap, int);
+		/*
+		 * Tweak the TIFF header so that the rest of libtiff knows what
+		 * size of data will be passed between app and library, and
+		 * assume that the app knows what it is doing and is not
+		 * confused by these header manipulations...
+		 */
+		switch (sp->user_datafmt) {
+		case SGILOGDATAFMT_FLOAT:
+			bps = 32, fmt = SAMPLEFORMAT_IEEEFP;
+			break;
+		case SGILOGDATAFMT_16BIT:
+			bps = 16, fmt = SAMPLEFORMAT_INT;
+			break;
+		case SGILOGDATAFMT_RAW:
+			bps = 32, fmt = SAMPLEFORMAT_UINT;
+			TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+			break;
+		case SGILOGDATAFMT_8BIT:
+			bps = 8, fmt = SAMPLEFORMAT_UINT;
+			break;
+		default:
+			TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			    "Unknown data format %d for LogLuv compression",
+			    sp->user_datafmt);
+			return (0);
+		}
+		TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps);
+		TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, fmt);
+		/*
+		 * Must recalculate sizes should bits/sample change.
+		 */
+		tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t) -1;
+		tif->tif_scanlinesize = TIFFScanlineSize(tif);
+		return (1);
+	case TIFFTAG_SGILOGENCODE:
+		sp->encode_meth = (int) va_arg(ap, int);
+		if (sp->encode_meth != SGILOGENCODE_NODITHER &&
+		    sp->encode_meth != SGILOGENCODE_RANDITHER) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Unknown encoding %d for LogLuv compression",
+			    sp->encode_meth);
+			return (0);
+		}
+		return (1);
+	default:
+		return (*sp->vsetparent)(tif, tag, ap);
+	}
+}
+
+static int
+LogLuvVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	LogLuvState *sp = (LogLuvState *)tif->tif_data;
+
+	switch (tag) {
+	case TIFFTAG_SGILOGDATAFMT:
+		*va_arg(ap, int*) = sp->user_datafmt;
+		return (1);
+	default:
+		return (*sp->vgetparent)(tif, tag, ap);
+	}
+}
+
+static const TIFFField LogLuvFields[] = {
+    { TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogDataFmt", NULL},
+    { TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "SGILogEncode", NULL}
+};
+
+int
+TIFFInitSGILog(TIFF* tif, int scheme)
+{
+	static const char module[] = "TIFFInitSGILog";
+	LogLuvState* sp;
+
+	assert(scheme == COMPRESSION_SGILOG24 || scheme == COMPRESSION_SGILOG);
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, LogLuvFields,
+			      TIFFArrayCount(LogLuvFields))) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Merging SGILog codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*) _TIFFmalloc(sizeof (LogLuvState));
+	if (tif->tif_data == NULL)
+		goto bad;
+	sp = (LogLuvState*) tif->tif_data;
+	_TIFFmemset((void*)sp, 0, sizeof (*sp));
+	sp->user_datafmt = SGILOGDATAFMT_UNKNOWN;
+	sp->encode_meth = (scheme == COMPRESSION_SGILOG24) ?
+	    SGILOGENCODE_RANDITHER : SGILOGENCODE_NODITHER;
+	sp->tfunc = _logLuvNop;
+
+	/*
+	 * Install codec methods.
+	 * NB: tif_decoderow & tif_encoderow are filled
+	 *     in at setup time.
+	 */
+	tif->tif_fixuptags = LogLuvFixupTags;  
+	tif->tif_setupdecode = LogLuvSetupDecode;
+	tif->tif_decodestrip = LogLuvDecodeStrip;
+	tif->tif_decodetile = LogLuvDecodeTile;
+	tif->tif_setupencode = LogLuvSetupEncode;
+	tif->tif_encodestrip = LogLuvEncodeStrip;  
+	tif->tif_encodetile = LogLuvEncodeTile;
+	tif->tif_close = LogLuvClose;
+	tif->tif_cleanup = LogLuvCleanup;
+
+	/*
+	 * Override parent get/set field methods.
+	 */
+	sp->vgetparent = tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield = LogLuvVGetField;   /* hook for codec tags */
+	sp->vsetparent = tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield = LogLuvVSetField;   /* hook for codec tags */
+
+	return (1);
+bad:
+	TIFFErrorExt(tif->tif_clientdata, module,
+		     "%s: No space for LogLuv state block", tif->tif_name);
+	return (0);
+}
+#endif /* LOGLUV_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_lzw.c b/third_party/libtiff/tif_lzw.c
new file mode 100644
index 0000000..9b76dd0
--- /dev/null
+++ b/third_party/libtiff/tif_lzw.c
@@ -0,0 +1,1178 @@
+/* $Id: tif_lzw.c,v 1.49 2015-08-30 21:07:44 erouault 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef LZW_SUPPORT
+/*
+ * TIFF Library.  
+ * Rev 5.0 Lempel-Ziv & Welch Compression Support
+ *
+ * This code is derived from the compress program whose code is
+ * derived from software contributed to Berkeley by James A. Woods,
+ * derived from original work by Spencer Thomas and Joseph Orost.
+ *
+ * The original Berkeley copyright notice appears below in its entirety.
+ */
+#include "tif_predict.h"
+
+#include <stdio.h>
+
+/*
+ * NB: The 5.0 spec describes a different algorithm than Aldus
+ *     implements.  Specifically, Aldus does code length transitions
+ *     one code earlier than should be done (for real LZW).
+ *     Earlier versions of this library implemented the correct
+ *     LZW algorithm, but emitted codes in a bit order opposite
+ *     to the TIFF spec.  Thus, to maintain compatibility w/ Aldus
+ *     we interpret MSB-LSB ordered codes to be images written w/
+ *     old versions of this library, but otherwise adhere to the
+ *     Aldus "off by one" algorithm.
+ *
+ * Future revisions to the TIFF spec are expected to "clarify this issue".
+ */
+#define LZW_COMPAT              /* include backwards compatibility code */
+/*
+ * Each strip of data is supposed to be terminated by a CODE_EOI.
+ * If the following #define is included, the decoder will also
+ * check for end-of-strip w/o seeing this code.  This makes the
+ * library more robust, but also slower.
+ */
+#define LZW_CHECKEOS            /* include checks for strips w/o EOI code */
+
+#define MAXCODE(n)	((1L<<(n))-1)
+/*
+ * The TIFF spec specifies that encoded bit
+ * strings range from 9 to 12 bits.
+ */
+#define BITS_MIN        9               /* start with 9 bits */
+#define BITS_MAX        12              /* max of 12 bit strings */
+/* predefined codes */
+#define CODE_CLEAR      256             /* code to clear string table */
+#define CODE_EOI        257             /* end-of-information code */
+#define CODE_FIRST      258             /* first free code entry */
+#define CODE_MAX        MAXCODE(BITS_MAX)
+#define HSIZE           9001L           /* 91% occupancy */
+#define HSHIFT          (13-8)
+#ifdef LZW_COMPAT
+/* NB: +1024 is for compatibility with old files */
+#define CSIZE           (MAXCODE(BITS_MAX)+1024L)
+#else
+#define CSIZE           (MAXCODE(BITS_MAX)+1L)
+#endif
+
+/*
+ * State block for each open TIFF file using LZW
+ * compression/decompression.  Note that the predictor
+ * state block must be first in this data structure.
+ */
+typedef struct {
+	TIFFPredictorState predict;     /* predictor super class */
+
+	unsigned short  nbits;          /* # of bits/code */
+	unsigned short  maxcode;        /* maximum code for lzw_nbits */
+	unsigned short  free_ent;       /* next free entry in hash table */
+	unsigned long   nextdata;       /* next bits of i/o */
+	long            nextbits;       /* # of valid bits in lzw_nextdata */
+
+	int             rw_mode;        /* preserve rw_mode from init */
+} LZWBaseState;
+
+#define lzw_nbits       base.nbits
+#define lzw_maxcode     base.maxcode
+#define lzw_free_ent    base.free_ent
+#define lzw_nextdata    base.nextdata
+#define lzw_nextbits    base.nextbits
+
+/*
+ * Encoding-specific state.
+ */
+typedef uint16 hcode_t;			/* codes fit in 16 bits */
+typedef struct {
+	long	hash;
+	hcode_t	code;
+} hash_t;
+
+/*
+ * Decoding-specific state.
+ */
+typedef struct code_ent {
+	struct code_ent *next;
+	unsigned short	length;		/* string len, including this token */
+	unsigned char	value;		/* data value */
+	unsigned char	firstchar;	/* first token of string */
+} code_t;
+
+typedef int (*decodeFunc)(TIFF*, uint8*, tmsize_t, uint16);
+
+typedef struct {
+	LZWBaseState base;
+
+	/* Decoding specific data */
+	long    dec_nbitsmask;		/* lzw_nbits 1 bits, right adjusted */
+	long    dec_restart;		/* restart count */
+#ifdef LZW_CHECKEOS
+	uint64  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 */
+	uint8*  enc_rawlimit;		/* bound on tif_rawdata buffer */
+	hash_t* enc_hashtab;		/* kept separate for small machines */
+} LZWCodecState;
+
+#define LZWState(tif)		((LZWBaseState*) (tif)->tif_data)
+#define DecoderState(tif)	((LZWCodecState*) LZWState(tif))
+#define EncoderState(tif)	((LZWCodecState*) LZWState(tif))
+
+static int LZWDecode(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s);
+#ifdef LZW_COMPAT
+static int LZWDecodeCompat(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s);
+#endif
+static void cl_hash(LZWCodecState*);
+
+/*
+ * LZW Decoder.
+ */
+
+#ifdef LZW_CHECKEOS
+/*
+ * This check shouldn't be necessary because each
+ * strip is suppose to be terminated with CODE_EOI.
+ */
+#define	NextCode(_tif, _sp, _bp, _code, _get) {				\
+	if ((_sp)->dec_bitsleft < (uint64)nbits) {			\
+		TIFFWarningExt(_tif->tif_clientdata, module,		\
+		    "LZWDecode: Strip %d not terminated with EOI code", \
+		    _tif->tif_curstrip);				\
+		_code = CODE_EOI;					\
+	} else {							\
+		_get(_sp,_bp,_code);					\
+		(_sp)->dec_bitsleft -= nbits;				\
+	}								\
+}
+#else
+#define	NextCode(tif, sp, bp, code, get) get(sp, bp, code)
+#endif
+
+static int
+LZWFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+static int
+LZWSetupDecode(TIFF* tif)
+{
+	static const char module[] = "LZWSetupDecode";
+	LZWCodecState* sp = DecoderState(tif);
+	int code;
+
+	if( sp == NULL )
+	{
+		/*
+		 * Allocate state block so tag methods have storage to record
+		 * values.
+		*/
+		tif->tif_data = (uint8*) _TIFFmalloc(sizeof(LZWCodecState));
+		if (tif->tif_data == NULL)
+		{
+			TIFFErrorExt(tif->tif_clientdata, module, "No space for LZW state block");
+			return (0);
+		}
+
+		DecoderState(tif)->dec_codetab = NULL;
+		DecoderState(tif)->dec_decode = NULL;
+
+		/*
+		 * Setup predictor setup.
+		 */
+		(void) TIFFPredictorInit(tif);
+
+		sp = DecoderState(tif);
+	}
+
+	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);
+}
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+LZWPreDecode(TIFF* tif, uint16 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_rawdata[0] == 0 && (tif->tif_rawdata[1] & 0x1)) {
+#ifdef LZW_COMPAT
+		if (!sp->dec_decode) {
+			TIFFWarningExt(tif->tif_clientdata, module,
+			    "Old-style LZW codes, convert file");
+			/*
+			 * Override default decoding methods with
+			 * ones that deal with the old coding.
+			 * Otherwise the predictor versions set
+			 * above will call the compatibility routines
+			 * through the dec_decode method.
+			 */
+			tif->tif_decoderow = LZWDecodeCompat;
+			tif->tif_decodestrip = LZWDecodeCompat;
+			tif->tif_decodetile = LZWDecodeCompat;
+			/*
+			 * If doing horizontal differencing, must
+			 * re-setup the predictor logic since we
+			 * switched the basic decoder methods...
+			 */
+			(*tif->tif_setupdecode)(tif);
+			sp->dec_decode = LZWDecodeCompat;
+		}
+		sp->lzw_maxcode = MAXCODE(BITS_MIN);
+#else /* !LZW_COMPAT */
+		if (!sp->dec_decode) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Old-style LZW codes not supported");
+			sp->dec_decode = LZWDecode;
+		}
+		return (0);
+#endif/* !LZW_COMPAT */
+	} else {
+		sp->lzw_maxcode = MAXCODE(BITS_MIN)-1;
+		sp->dec_decode = LZWDecode;
+	}
+	sp->lzw_nbits = BITS_MIN;
+	sp->lzw_nextbits = 0;
+	sp->lzw_nextdata = 0;
+
+	sp->dec_restart = 0;
+	sp->dec_nbitsmask = MAXCODE(BITS_MIN);
+#ifdef LZW_CHECKEOS
+	sp->dec_bitsleft = ((uint64)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);
+}
+
+/*
+ * Decode a "hunk of data".
+ */
+#define	GetNextCode(sp, bp, code) {				\
+	nextdata = (nextdata<<8) | *(bp)++;			\
+	nextbits += 8;						\
+	if (nextbits < nbits) {					\
+		nextdata = (nextdata<<8) | *(bp)++;		\
+		nextbits += 8;					\
+	}							\
+	code = (hcode_t)((nextdata >> (nextbits-nbits)) & nbitsmask);	\
+	nextbits -= nbits;					\
+}
+
+static void
+codeLoop(TIFF* tif, const char* module)
+{
+	TIFFErrorExt(tif->tif_clientdata, module,
+	    "Bogus encoding, loop in the code table; scanline %d",
+	    tif->tif_row);
+}
+
+static int
+LZWDecode(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s)
+{
+	static const char module[] = "LZWDecode";
+	LZWCodecState *sp = DecoderState(tif);
+	char *op = (char*) op0;
+	long occ = (long) occ0;
+	char *tp;
+	unsigned char *bp;
+	hcode_t code;
+	int len;
+	long nbits, nextbits, nbitsmask;
+        unsigned long nextdata;
+	code_t *codep, *free_entp, *maxcodep, *oldcodep;
+
+	(void) s;
+	assert(sp != NULL);
+        assert(sp->dec_codetab != NULL);
+
+	/*
+	  Fail if value does not fit in long.
+	*/
+	if ((tmsize_t) occ != occ0)
+	        return (0);
+	/*
+	 * Restart interrupted output operation.
+	 */
+	if (sp->dec_restart) {
+		long residue;
+
+		codep = sp->dec_codep;
+		residue = codep->length - sp->dec_restart;
+		if (residue > occ) {
+			/*
+			 * Residue from previous decode is sufficient
+			 * to satisfy decode request.  Skip to the
+			 * start of the decoded string, place decoded
+			 * values in the output buffer, and return.
+			 */
+			sp->dec_restart += occ;
+			do {
+				codep = codep->next;
+			} while (--residue > occ && codep);
+			if (codep) {
+				tp = op + occ;
+				do {
+					*--tp = codep->value;
+					codep = codep->next;
+				} while (--occ && codep);
+			}
+			return (1);
+		}
+		/*
+		 * Residue satisfies only part of the decode request.
+		 */
+		op += residue, occ -= residue;
+		tp = op;
+		do {
+			int t;
+			--tp;
+			t = codep->value;
+			codep = codep->next;
+			*tp = 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) {
+			do {
+				free_entp = sp->dec_codetab + CODE_FIRST;
+				_TIFFmemset(free_entp, 0,
+					    (CSIZE - CODE_FIRST) * sizeof (code_t));
+				nbits = BITS_MIN;
+				nbitsmask = MAXCODE(BITS_MIN);
+				maxcodep = sp->dec_codetab + nbitsmask-1;
+				NextCode(tif, sp, bp, code, GetNextCode);
+			} while (code == CODE_CLEAR);	/* consecutive CODE_CLEAR codes */
+			if (code == CODE_EOI)
+				break;
+			if (code > CODE_CLEAR) {
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+				"LZWDecode: Corrupted LZW table at scanline %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, module,
+			    "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, module,
+			    "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, module,
+				    "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 = (long)occ;
+					tp = op + occ;
+					do  {
+						*--tp = codep->value;
+						codep = codep->next;
+					}  while (--occ && codep);
+					if (codep)
+						codeLoop(tif, module);
+				}
+				break;
+			}
+			len = codep->length;
+			tp = op + len;
+			do {
+				int t;
+				--tp;
+				t = codep->value;
+				codep = codep->next;
+				*tp = t;
+			} while (codep && tp > op);
+			if (codep) {
+			    codeLoop(tif, module);
+			    break;
+			}
+			assert(occ >= len);
+			op += len, occ -= len;
+		} else
+			*op++ = (char)code, occ--;
+	}
+
+	tif->tif_rawcp = (uint8*) 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) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at scanline %d (short %I64d bytes)",
+			     tif->tif_row, (unsigned __int64) occ);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at scanline %d (short %llu bytes)",
+			     tif->tif_row, (unsigned long long) occ);
+#endif
+		return (0);
+	}
+	return (1);
+}
+
+#ifdef LZW_COMPAT
+/*
+ * Decode a "hunk of data" for old images.
+ */
+#define	GetNextCodeCompat(sp, bp, code) {			\
+	nextdata |= (unsigned long) *(bp)++ << nextbits;	\
+	nextbits += 8;						\
+	if (nextbits < nbits) {					\
+		nextdata |= (unsigned long) *(bp)++ << nextbits;\
+		nextbits += 8;					\
+	}							\
+	code = (hcode_t)(nextdata & nbitsmask);			\
+	nextdata >>= nbits;					\
+	nextbits -= nbits;					\
+}
+
+static int
+LZWDecodeCompat(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s)
+{
+	static const char module[] = "LZWDecodeCompat";
+	LZWCodecState *sp = DecoderState(tif);
+	char *op = (char*) op0;
+	long occ = (long) occ0;
+	char *tp;
+	unsigned char *bp;
+	int code, nbits;
+	long nextbits, nextdata, nbitsmask;
+	code_t *codep, *free_entp, *maxcodep, *oldcodep;
+
+	(void) s;
+	assert(sp != NULL);
+
+	/*
+	  Fail if value does not fit in long.
+	*/
+	if ((tmsize_t) occ != occ0)
+	        return (0);
+
+	/*
+	 * Restart interrupted output operation.
+	 */
+	if (sp->dec_restart) {
+		long residue;
+
+		codep = sp->dec_codep;
+		residue = codep->length - sp->dec_restart;
+		if (residue > occ) {
+			/*
+			 * Residue from previous decode is sufficient
+			 * to satisfy decode request.  Skip to the
+			 * start of the decoded string, place decoded
+			 * values in the output buffer, and return.
+			 */
+			sp->dec_restart += occ;
+			do {
+				codep = codep->next;
+			} while (--residue > occ);
+			tp = op + occ;
+			do {
+				*--tp = codep->value;
+				codep = codep->next;
+			} while (--occ);
+			return (1);
+		}
+		/*
+		 * Residue satisfies only part of the decode request.
+		 */
+		op += residue, occ -= residue;
+		tp = op;
+		do {
+			*--tp = codep->value;
+			codep = codep->next;
+		} while (--residue);
+		sp->dec_restart = 0;
+	}
+
+	bp = (unsigned char *)tif->tif_rawcp;
+	nbits = sp->lzw_nbits;
+	nextdata = sp->lzw_nextdata;
+	nextbits = sp->lzw_nextbits;
+	nbitsmask = sp->dec_nbitsmask;
+	oldcodep = sp->dec_oldcodep;
+	free_entp = sp->dec_free_entp;
+	maxcodep = sp->dec_maxcodep;
+
+	while (occ > 0) {
+		NextCode(tif, sp, bp, code, GetNextCodeCompat);
+		if (code == CODE_EOI)
+			break;
+		if (code == CODE_CLEAR) {
+			do {
+				free_entp = sp->dec_codetab + CODE_FIRST;
+				_TIFFmemset(free_entp, 0,
+					    (CSIZE - CODE_FIRST) * sizeof (code_t));
+				nbits = BITS_MIN;
+				nbitsmask = MAXCODE(BITS_MIN);
+				maxcodep = sp->dec_codetab + nbitsmask;
+				NextCode(tif, sp, bp, code, GetNextCodeCompat);
+			} while (code == CODE_CLEAR);	/* consecutive CODE_CLEAR codes */
+			if (code == CODE_EOI)
+				break;
+			if (code > CODE_CLEAR) {
+				TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+				"LZWDecode: Corrupted LZW table at scanline %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, module,
+			    "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, module,
+			    "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) {
+			/*
+			 * Code maps to a string, copy string
+			 * value to output (written in reverse).
+			 */
+			if(codep->length == 0) {
+				TIFFErrorExt(tif->tif_clientdata, module,
+				    "Wrong length of decoded "
+				    "string: data probably corrupted at scanline %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;
+			}
+			assert(occ >= codep->length);
+			op += codep->length, occ -= codep->length;
+			tp = op;
+			do {
+				*--tp = codep->value;
+			} while( (codep = codep->next) != NULL );
+		} else
+			*op++ = code, occ--;
+	}
+
+	tif->tif_rawcp = (uint8*) 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) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at scanline %d (short %I64d bytes)",
+			     tif->tif_row, (unsigned __int64) occ);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"Not enough data at scanline %d (short %llu bytes)",
+			     tif->tif_row, (unsigned long long) occ);
+#endif
+		return (0);
+	}
+	return (1);
+}
+#endif /* LZW_COMPAT */
+
+/*
+ * LZW Encoding.
+ */
+
+static int
+LZWSetupEncode(TIFF* tif)
+{
+	static const char module[] = "LZWSetupEncode";
+	LZWCodecState* sp = EncoderState(tif);
+
+	assert(sp != NULL);
+	sp->enc_hashtab = (hash_t*) _TIFFmalloc(HSIZE*sizeof (hash_t));
+	if (sp->enc_hashtab == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "No space for LZW hash table");
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+LZWPreEncode(TIFF* tif, uint16 s)
+{
+	LZWCodecState *sp = EncoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+
+	if( sp->enc_hashtab == NULL )
+        {
+            tif->tif_setupencode( tif );
+        }
+
+	sp->lzw_nbits = BITS_MIN;
+	sp->lzw_maxcode = MAXCODE(BITS_MIN);
+	sp->lzw_free_ent = CODE_FIRST;
+	sp->lzw_nextbits = 0;
+	sp->lzw_nextdata = 0;
+	sp->enc_checkpoint = CHECK_GAP;
+	sp->enc_ratio = 0;
+	sp->enc_incount = 0;
+	sp->enc_outcount = 0;
+	/*
+	 * The 4 here insures there is space for 2 max-sized
+	 * codes in LZWEncode and LZWPostDecode.
+	 */
+	sp->enc_rawlimit = tif->tif_rawdata + tif->tif_rawdatasize-1 - 4;
+	cl_hash(sp);		/* clear hash table */
+	sp->enc_oldcode = (hcode_t) -1;	/* generates CODE_CLEAR in LZWEncode */
+	return (1);
+}
+
+#define	CALCRATIO(sp, rat) {					\
+	if (incount > 0x007fffff) { /* NB: shift will overflow */\
+		rat = outcount >> 8;				\
+		rat = (rat == 0 ? 0x7fffffff : incount/rat);	\
+	} else							\
+		rat = (incount<<8) / outcount;			\
+}
+
+/* Explicit 0xff masking to make icc -check=conversions happy */
+#define	PutNextCode(op, c) {					\
+	nextdata = (nextdata << nbits) | c;			\
+	nextbits += nbits;					\
+	*op++ = (unsigned char)((nextdata >> (nextbits-8))&0xff);		\
+	nextbits -= 8;						\
+	if (nextbits >= 8) {					\
+		*op++ = (unsigned char)((nextdata >> (nextbits-8))&0xff);	\
+		nextbits -= 8;					\
+	}							\
+	outcount += nbits;					\
+}
+
+/*
+ * Encode a chunk of pixels.
+ *
+ * Uses an open addressing double hashing (no chaining) on the 
+ * prefix code/next character combination.  We do a variant of
+ * Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's
+ * relatively-prime secondary probe.  Here, the modular division
+ * first probe is gives way to a faster exclusive-or manipulation. 
+ * Also do block compression with an adaptive reset, whereby the
+ * code table is cleared when the compression ratio decreases,
+ * but after the table fills.  The variable-length output codes
+ * are re-sized at this point, and a CODE_CLEAR is generated
+ * for the decoder. 
+ */
+static int
+LZWEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	register LZWCodecState *sp = EncoderState(tif);
+	register long fcode;
+	register hash_t *hp;
+	register int h, c;
+	hcode_t ent;
+	long disp;
+	long incount, outcount, checkpoint;
+	unsigned long nextdata;
+        long nextbits;
+	int free_ent, maxcode, nbits;
+	uint8* op;
+	uint8* 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 */
+#ifdef _WINDOWS
+		/*
+		 * Check hash index for an overflow.
+		 */
+		if (h >= HSIZE)
+			h -= HSIZE;
+#endif
+		hp = &sp->enc_hashtab[h];
+		if (hp->hash == fcode) {
+			ent = hp->code;
+			continue;
+		}
+		if (hp->hash >= 0) {
+			/*
+			 * Primary hash failed, check secondary hash.
+			 */
+			disp = HSIZE - h;
+			if (h == 0)
+				disp = 1;
+			do {
+				/*
+				 * Avoid pointer arithmetic '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 = (tmsize_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);
+}
+
+/*
+ * Finish off an encoded strip by flushing the last
+ * string and tacking on an End Of Information code.
+ */
+static int
+LZWPostEncode(TIFF* tif)
+{
+	register LZWCodecState *sp = EncoderState(tif);
+	uint8* op = tif->tif_rawcp;
+	long nextbits = sp->lzw_nextbits;
+	unsigned long nextdata = sp->lzw_nextdata;
+	long outcount = sp->enc_outcount;
+	int nbits = sp->lzw_nbits;
+
+	if (op > sp->enc_rawlimit) {
+		tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata);
+		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);
+        /* Explicit 0xff masking to make icc -check=conversions happy */
+	if (nextbits > 0) 
+		*op++ = (unsigned char)((nextdata << (8-nextbits))&0xff);
+	tif->tif_rawcc = (tmsize_t)(op - tif->tif_rawdata);
+	return (1);
+}
+
+/*
+ * Reset encoding hash table.
+ */
+static void
+cl_hash(LZWCodecState* sp)
+{
+	register hash_t *hp = &sp->enc_hashtab[HSIZE-1];
+	register long i = HSIZE-8;
+
+	do {
+		i -= 8;
+		hp[-7].hash = -1;
+		hp[-6].hash = -1;
+		hp[-5].hash = -1;
+		hp[-4].hash = -1;
+		hp[-3].hash = -1;
+		hp[-2].hash = -1;
+		hp[-1].hash = -1;
+		hp[ 0].hash = -1;
+		hp -= 8;
+	} while (i >= 0);
+	for (i += 8; i > 0; i--, hp--)
+		hp->hash = -1;
+}
+
+static void
+LZWCleanup(TIFF* tif)
+{
+	(void)TIFFPredictorCleanup(tif);
+
+	assert(tif->tif_data != 0);
+
+	if (DecoderState(tif)->dec_codetab)
+		_TIFFfree(DecoderState(tif)->dec_codetab);
+
+	if (EncoderState(tif)->enc_hashtab)
+		_TIFFfree(EncoderState(tif)->enc_hashtab);
+
+	_TIFFfree(tif->tif_data);
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+int
+TIFFInitLZW(TIFF* tif, int scheme)
+{
+	static const char module[] = "TIFFInitLZW";
+	assert(scheme == COMPRESSION_LZW);
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*) _TIFFmalloc(sizeof (LZWCodecState));
+	if (tif->tif_data == NULL)
+		goto bad;
+	DecoderState(tif)->dec_codetab = NULL;
+	DecoderState(tif)->dec_decode = NULL;
+	EncoderState(tif)->enc_hashtab = NULL;
+        LZWState(tif)->rw_mode = tif->tif_mode;
+
+	/*
+	 * Install codec methods.
+	 */
+	tif->tif_fixuptags = LZWFixupTags; 
+	tif->tif_setupdecode = LZWSetupDecode;
+	tif->tif_predecode = LZWPreDecode;
+	tif->tif_decoderow = LZWDecode;
+	tif->tif_decodestrip = LZWDecode;
+	tif->tif_decodetile = LZWDecode;
+	tif->tif_setupencode = LZWSetupEncode;
+	tif->tif_preencode = LZWPreEncode;
+	tif->tif_postencode = LZWPostEncode;
+	tif->tif_encoderow = LZWEncode;
+	tif->tif_encodestrip = LZWEncode;
+	tif->tif_encodetile = LZWEncode;
+	tif->tif_cleanup = LZWCleanup;
+	/*
+	 * Setup predictor setup.
+	 */
+	(void) TIFFPredictorInit(tif);
+	return (1);
+bad:
+	TIFFErrorExt(tif->tif_clientdata, module, 
+		     "No space for LZW state block");
+	return (0);
+}
+
+/*
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods, derived from original work by Spencer Thomas
+ * and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY 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/third_party/libtiff/tif_next.c b/third_party/libtiff/tif_next.c
new file mode 100644
index 0000000..17e0311
--- /dev/null
+++ b/third_party/libtiff/tif_next.c
@@ -0,0 +1,181 @@
+/* $Id: tif_next.c,v 1.16 2014-12-29 12:09:11 erouault 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef NEXT_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * NeXT 2-bit Grey Scale Compression Algorithm Support
+ */
+
+#define SETPIXEL(op, v) {			\
+	switch (npixels++ & 3) {		\
+	case 0:	op[0]  = (unsigned char) ((v) << 6); break;	\
+	case 1:	op[0] |= (v) << 4; break;	\
+	case 2:	op[0] |= (v) << 2; break;	\
+	case 3:	*op++ |= (v);	   break;	\
+	}					\
+}
+
+#define LITERALROW	0x00
+#define LITERALSPAN	0x40
+#define WHITE   	((1<<2)-1)
+
+static int
+NeXTDecode(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "NeXTDecode";
+	unsigned char *bp, *op;
+	tmsize_t cc;
+	uint8* row;
+	tmsize_t scanline, n;
+
+	(void) s;
+	/*
+	 * Each scanline is assumed to start off as all
+	 * white (we assume a PhotometricInterpretation
+	 * of ``min-is-black'').
+	 */
+	for (op = (unsigned char*) buf, cc = occ; cc-- > 0;)
+		*op++ = 0xff;
+
+	bp = (unsigned char *)tif->tif_rawcp;
+	cc = tif->tif_rawcc;
+	scanline = tif->tif_scanlinesize;
+	if (occ % scanline)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (0);
+	}
+	for (row = buf; cc > 0 && occ > 0; occ -= scanline, row += scanline) {
+		n = *bp++, cc--;
+		switch (n) {
+		case LITERALROW:
+			/*
+			 * The entire scanline is given as literal values.
+			 */
+			if (cc < scanline)
+				goto bad;
+			_TIFFmemcpy(row, bp, scanline);
+			bp += scanline;
+			cc -= scanline;
+			break;
+		case LITERALSPAN: {
+			tmsize_t off;
+			/*
+			 * The scanline has a literal span that begins at some
+			 * offset.
+			 */
+			if( cc < 4 )
+				goto bad;
+			off = (bp[0] * 256) + bp[1];
+			n = (bp[2] * 256) + bp[3];
+			if (cc < 4+n || off+n > scanline)
+				goto bad;
+			_TIFFmemcpy(row+off, bp+4, n);
+			bp += 4+n;
+			cc -= 4+n;
+			break;
+		}
+		default: {
+			uint32 npixels = 0, grey;
+			uint32 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
+			 * <color><npixels> until we've filled the scanline.
+			 */
+			op = row;
+			for (;;) {
+				grey = (uint32)((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 = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	return (1);
+bad:
+	TIFFErrorExt(tif->tif_clientdata, module, "Not enough data for scanline %ld",
+	    (long) tif->tif_row);
+	return (0);
+}
+
+static int
+NeXTPreDecode(TIFF* tif, uint16 s)
+{
+	static const char module[] = "NeXTPreDecode";
+	TIFFDirectory *td = &tif->tif_dir;
+	(void)s;
+
+	if( td->td_bitspersample != 2 )
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Unsupported BitsPerSample = %d",
+					 td->td_bitspersample);
+		return (0);
+	}
+	return (1);
+}
+	
+int
+TIFFInitNeXT(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	tif->tif_predecode = NeXTPreDecode;  
+	tif->tif_decoderow = NeXTDecode;  
+	tif->tif_decodestrip = NeXTDecode;  
+	tif->tif_decodetile = NeXTDecode;
+	return (1);
+}
+#endif /* NEXT_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_ojpeg.c b/third_party/libtiff/tif_ojpeg.c
new file mode 100644
index 0000000..cc5449c
--- /dev/null
+++ b/third_party/libtiff/tif_ojpeg.c
@@ -0,0 +1,2516 @@
+/* $Id: tif_ojpeg.c,v 1.60 2015-05-31 00:38:46 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
+   still present on some users' computer systems. It will never be extended
+   to write such files. Writing new-style JPEG compressed TIFFs is implemented
+   in tif_jpeg.c.
+
+   The code is carefully crafted to robustly read all gathered JPEG-in-TIFF
+   testfiles, and anticipate as much as possible all other... But still, it may
+   fail on some. If you encounter problems, please report them on the TIFF
+   mailing list and/or to Joris Van Damme <info@awaresystems.be>.
+
+   Please read the file called "TIFF Technical Note #2" if you need to be
+   convinced this compression scheme is bad and breaks TIFF. That document
+   is linked to from the LibTiff site <http://www.remotesensing.org/libtiff/>
+   and from AWare Systems' TIFF section
+   <http://www.awaresystems.be/imaging/tiff.html>. It is also absorbed
+   in Adobe's specification supplements, marked "draft" up to this day, but
+   supported by the TIFF community.
+
+   This file interfaces with Release 6B of the JPEG Library written by the
+   Independent JPEG Group. Previous versions of this file required a hack inside
+   the LibJpeg library. This version no longer requires that. Remember to
+   remove the hack if you update from the old version.
+
+   Copyright (c) Joris Van Damme <info@awaresystems.be>
+   Copyright (c) AWare Systems <http://www.awaresystems.be/>
+
+   The licence agreement for this file is the same as the rest of the LibTiff
+   library.
+
+   IN NO EVENT SHALL JORIS VAN DAMME OR AWARE SYSTEMS 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.
+
+   Joris Van Damme and/or AWare Systems may be available for custom
+   development. If you like what you see, and need anything similar or related,
+   contact <info@awaresystems.be>.
+*/
+
+/* 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
+   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
+   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.
+*/
+
+#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 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. 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 SETJMP(jbuf) setjmp(jbuf)
+#define LONGJMP(jbuf,code) longjmp(jbuf,code)
+#define JMP_BUF jmp_buf
+#define OJPEG_BUFFER 2048
+/* define EGYPTIANWALK */
+
+#define JPEG_MARKER_SOF0 0xC0
+#define JPEG_MARKER_SOF1 0xC1
+#define JPEG_MARKER_SOF3 0xC3
+#define JPEG_MARKER_DHT 0xC4
+#define JPEG_MARKER_RST0 0XD0
+#define JPEG_MARKER_SOI 0xD8
+#define JPEG_MARKER_EOI 0xD9
+#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
+
+#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 <setjmp.h>
+#endif
+
+/* 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 conficting 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
+
+#if defined(USE_SYSTEM_LIBJPEG)
+#include <jerror.h>
+#include <jpeglib.h>
+#elif defined(USE_LIBJPEG_TURBO)
+#include "third_party/libjpeg_turbo/jerror.h"
+#include "third_party/libjpeg_turbo/jpeglib.h"
+#else
+#include "third_party/libjpeg/jerror.h"
+#include "third_party/libjpeg/jpeglib.h"
+#endif
+
+
+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
+} OJPEGStateInBufferSource;
+
+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;
+	TIFFPrintMethod printdir;
+	uint64 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;
+	uint64 jpeg_interchange_format;
+	uint64 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;
+	uint64 qtable_offset[3];
+	uint64 dctable_offset[3];
+	uint64 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;
+		uint32 in_buffer_next_strile;
+		uint64 in_buffer_file_pos;
+		uint64 in_buffer_file_togo;
+	} sos_end[3];
+	uint8 readheader_done;
+	uint8 writeheader_done;
+	uint16 write_cursample;
+	uint32 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;
+	uint32 in_buffer_next_strile;
+	uint32 in_buffer_strile_count;
+	uint64 in_buffer_file_pos;
+	uint8 in_buffer_file_pos_log;
+	uint64 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;
+} OJPEGState;
+
+static int OJPEGVGetField(TIFF* tif, uint32 tag, va_list ap);
+static int OJPEGVSetField(TIFF* tif, uint32 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 s);
+static int OJPEGPreDecodeSkipRaw(TIFF* tif);
+static int OJPEGPreDecodeSkipScanlines(TIFF* tif);
+static int OJPEGDecode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s);
+static int OJPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc);
+static int OJPEGDecodeScanlines(TIFF* tif, uint8* buf, tmsize_t cc);
+static void OJPEGPostDecode(TIFF* tif, uint8* buf, tmsize_t cc);
+static int OJPEGSetupEncode(TIFF* tif);
+static int OJPEGPreEncode(TIFF* tif, uint16 s);
+static int OJPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 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 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);
+
+#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);
+#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);
+#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 (!_TIFFMergeFields(tif, ojpegFields, TIFFArrayCount(ojpegFields))) {
+		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_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*)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 tag, va_list ap)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	switch(tag)
+	{
+		case TIFFTAG_JPEGIFOFFSET:
+			*va_arg(ap,uint64*)=(uint64)sp->jpeg_interchange_format;
+			break;
+		case TIFFTAG_JPEGIFBYTECOUNT:
+			*va_arg(ap,uint64*)=(uint64)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 tag, va_list ap)
+{
+	static const char module[]="OJPEGVSetField";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint32 ma;
+	uint64* mb;
+	uint32 n;
+	const TIFFField* fip;
+
+	switch(tag)
+	{
+		case TIFFTAG_JPEGIFOFFSET:
+			sp->jpeg_interchange_format=(uint64)va_arg(ap,uint64);
+			break;
+		case TIFFTAG_JPEGIFBYTECOUNT:
+			sp->jpeg_interchange_format_length=(uint64)va_arg(ap,uint64);
+			break;
+		case TIFFTAG_YCBCRSUBSAMPLING:
+			sp->subsampling_tag=1;
+			sp->subsampling_hor=(uint8)va_arg(ap,uint16_vap);
+			sp->subsampling_ver=(uint8)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)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=(uint64*)va_arg(ap,uint64*);
+				for (n=0; n<ma; n++)
+					sp->qtable_offset[n]=mb[n];
+			}
+			break;
+		case TIFFTAG_JPEGDCTABLES:
+			ma=(uint32)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=(uint64*)va_arg(ap,uint64*);
+				for (n=0; n<ma; n++)
+					sp->dctable_offset[n]=mb[n];
+			}
+			break;
+		case TIFFTAG_JPEGACTABLES:
+			ma=(uint32)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=(uint64*)va_arg(ap,uint64*);
+				for (n=0; n<ma; n++)
+					sp->actable_offset[n]=mb[n];
+			}
+			break;
+		case TIFFTAG_JPEGPROC:
+			sp->jpeg_proc=(uint8)va_arg(ap,uint16_vap);
+			break;
+		case TIFFTAG_JPEGRESTARTINTERVAL:
+			sp->restart_interval=(uint16)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 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: " TIFF_UINT64_FORMAT "\n",(TIFF_UINT64_T)sp->jpeg_interchange_format);  
+	if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH))
+		fprintf(fd,"  JpegInterchangeFormatLength: " TIFF_UINT64_FORMAT "\n",(TIFF_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," " TIFF_UINT64_FORMAT,(TIFF_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," " TIFF_UINT64_FORMAT,(TIFF_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," " TIFF_UINT64_FORMAT,(TIFF_UINT64_T)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);
+	if (sp->printdir)
+		(*sp->printdir)(tif, fd, flags);
+}
+
+static int
+OJPEGFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return(1);
+}
+
+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 int
+OJPEGPreDecode(TIFF* tif, uint16 s)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint32 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)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++;
+	}
+	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
+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; 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, uint8* buf, tmsize_t cc, uint16 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
+OJPEGDecodeRaw(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+	static const char module[]="OJPEGDecodeRaw";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8* m;
+	tmsize_t 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; 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, uint8* buf, tmsize_t cc)
+{
+	static const char module[]="OJPEGDecodeScanlines";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8* m;
+	tmsize_t 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 void
+OJPEGPostDecode(TIFF* tif, uint8* buf, tmsize_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 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 int
+OJPEGPreEncode(TIFF* tif, uint16 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 int
+OJPEGEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 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 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 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)
+			_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
+OJPEGSubsamplingCorrect(TIFF* tif)
+{
+	static const char module[]="OJPEGSubsamplingCorrect";
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	uint8 mh;
+	uint8 mv;
+        _TIFFFillStriles( tif );
+        
+	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_hor<sp->subsampling_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 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;
+	}
+	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)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"SamplesPerPixel %d 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->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
+OJPEGReadSecondarySos(TIFF* tif, uint16 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_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;
+	/* 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;
+#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; 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-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);
+}
+
+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;
+}
+
+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; 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
+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) {
+				_TIFFfree(nb);
+				return(0);
+			}
+			o=nb[sizeof(uint32)+4]&15;
+			if (3<o)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data");
+				_TIFFfree(nb);
+				return(0);
+			}
+			if (sp->qtable[o]!=0)
+				_TIFFfree(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) {
+                        _TIFFfree(nb);
+			return(0);
+                }
+		o=nb[sizeof(uint32)+4];
+		if ((o&240)==0)
+		{
+			if (3<o)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data");
+                                _TIFFfree(nb);
+				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");
+                                _TIFFfree(nb);
+				return(0);
+			}
+			o&=15;
+			if (3<o)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data");
+                                _TIFFfree(nb);
+				return(0);
+			}
+			if (sp->actable[o]!=0)
+				_TIFFfree(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
+	{
+		/* Y: Number of lines */
+		if (OJPEGReadWord(sp,&p)==0)
+			return(0);
+		if (((uint32)p<sp->image_length) && ((uint32)p<sp->strile_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 (((uint32)p<sp->image_width) && ((uint32)p<sp->strile_width))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected width");
+			return(0);
+		}
+		if ((uint32)p>sp->strile_width)
+		{
+			TIFFErrorExt(tif->tif_clientdata,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)
+			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; 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))
+					{
+						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
+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; 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; 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])
+				{
+					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
+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; 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])
+				{
+					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
+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; 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])
+				{
+					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
+OJPEGReadBufferFill(OJPEGState* sp)
+{
+	uint16 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)m>sp->in_buffer_file_togo)
+				m=(uint16)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)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;
+                                break;
+			case osibsStrile:
+				if (!_TIFFFillStriles( sp->tif ) 
+				    || sp->tif->tif_dir.td_stripoffset == NULL
+				    || sp->tif->tif_dir.td_stripbytecount == NULL)
+					return 0;
+
+				if (sp->in_buffer_next_strile==sp->in_buffer_strile_count)
+					sp->in_buffer_source=osibsEof;
+				else
+				{
+					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 if (sp->tif->tif_dir.td_stripbytecount==NULL)
+							sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos;
+						else
+						{
+							if (sp->tif->tif_dir.td_stripbytecount == 0) {
+								TIFFErrorExt(sp->tif->tif_clientdata,sp->tif->tif_name,"Strip byte counts are missing");
+								return(0);
+							}
+							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
+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
+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 void
+OJPEGReadByteAdvance(OJPEGState* sp)
+{
+	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
+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 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 ((uint64)n>sp->in_buffer_file_togo)
+			n=(uint16)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 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
+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
+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
+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
+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
+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; 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; 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_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
+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;
+}
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo)
+{
+	return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_create_decompress(cinfo),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image)
+{
+	return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_header(cinfo,require_image),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo)
+{
+	return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_start_decompress(cinfo),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines)
+{
+	return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_scanlines(cinfo,scanlines,max_lines),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines)
+{
+	return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_raw_data(cinfo,data,max_lines),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static void
+jpeg_encap_unwind(TIFF* tif)
+{
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	LONGJMP(sp->exit_jmpbuf,1);
+}
+#endif
+
+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);
+}
+
+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));
+}
+
+static void
+OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* 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=0U;
+	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);
+}
+
+static void
+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);
+}
+
+static boolean
+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);
+}
+
+static void
+OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo)
+{
+	(void)cinfo;
+}
+
+#endif
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_open.c b/third_party/libtiff/tif_open.c
new file mode 100644
index 0000000..8c88328
--- /dev/null
+++ b/third_party/libtiff/tif_open.c
@@ -0,0 +1,725 @@
+/* $Id: tif_open.c,v 1.46 2010-12-06 16:54:54 faxguy 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#include "tiffiop.h"
+
+/*
+ * Dummy functions to fill the omitted client procedures.
+ */
+static int
+_tiffDummyMapProc(thandle_t fd, void** pbase, toff_t* psize)
+{
+	(void) fd; (void) pbase; (void) psize;
+	return (0);
+}
+
+static void
+_tiffDummyUnmapProc(thandle_t fd, void* base, toff_t size)
+{
+	(void) fd; (void) base; (void) size;
+}
+
+int
+_TIFFgetMode(const char* mode, const char* module)
+{
+	int m = -1;
+
+	switch (mode[0]) {
+	case 'r':
+		m = O_RDONLY;
+		if (mode[1] == '+')
+			m = O_RDWR;
+		break;
+	case 'w':
+	case 'a':
+		m = O_RDWR|O_CREAT;
+		if (mode[0] == 'w')
+			m |= O_TRUNC;
+		break;
+	default:
+		TIFFErrorExt(0, module, "\"%s\": Bad mode", mode);
+		break;
+	}
+	return (m);
+}
+
+TIFF*
+TIFFClientOpen(
+	const char* name, const char* mode,
+	thandle_t clientdata,
+	TIFFReadWriteProc readproc,
+	TIFFReadWriteProc writeproc,
+	TIFFSeekProc seekproc,
+	TIFFCloseProc closeproc,
+	TIFFSizeProc sizeproc,
+	TIFFMapFileProc mapproc,
+	TIFFUnmapFileProc unmapproc
+)
+{
+	static const char module[] = "TIFFClientOpen";
+	TIFF *tif;
+	int m;
+	const char* cp;
+
+	/* The following are configuration checks. They should be redundant, but should not
+	 * compile to any actual code in an optimised release build anyway. If any of them
+	 * fail, (makefile-based or other) configuration is not correct */
+	assert(sizeof(uint8)==1);
+	assert(sizeof(int8)==1);
+	assert(sizeof(uint16)==2);
+	assert(sizeof(int16)==2);
+	assert(sizeof(uint32)==4);
+	assert(sizeof(int32)==4);
+	assert(sizeof(uint64)==8);
+	assert(sizeof(int64)==8);
+	assert(sizeof(tmsize_t)==sizeof(void*));
+	{
+		union{
+			uint8 a8[2];
+			uint16 a16;
+		} n;
+		n.a8[0]=1;
+		n.a8[1]=0;
+		#ifdef WORDS_BIGENDIAN
+		assert(n.a16==256);
+		#else
+		assert(n.a16==1);
+		#endif
+	}
+
+	m = _TIFFgetMode(mode, module);
+	if (m == -1)
+		goto bad2;
+	tif = (TIFF *)_TIFFmalloc((tmsize_t)(sizeof (TIFF) + strlen(name) + 1));
+	if (tif == NULL) {
+		TIFFErrorExt(clientdata, module, "%s: Out of memory (TIFF structure)", name);
+		goto bad2;
+	}
+	_TIFFmemset(tif, 0, sizeof (*tif));
+	tif->tif_name = (char *)tif + sizeof (TIFF);
+	strcpy(tif->tif_name, name);
+	tif->tif_mode = m &~ (O_CREAT|O_TRUNC);
+	tif->tif_curdir = (uint16) -1;		/* non-existent directory */
+	tif->tif_curoff = 0;
+	tif->tif_curstrip = (uint32) -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;
+
+	#ifdef STRIPCHOP_DEFAULT
+	if (m == O_RDONLY || m == O_RDWR)
+		tif->tif_flags |= STRIPCHOP_DEFAULT;
+	#endif
+
+	/*
+	 * Process library-specific flags in the open mode string.
+	 * The following flags may be used to control intrinsic library
+	 * 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
+	 * '4' ClassicTIFF for creating a file (default)
+	 * '8' BigTIFF for creating a file
+	 *
+	 * 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':
+				#ifndef WORDS_BIGENDIAN
+				if (m&O_CREAT)
+					tif->tif_flags |= TIFF_SWAB;
+				#endif
+				break;
+			case 'l':
+				#ifdef WORDS_BIGENDIAN
+				if ((m&O_CREAT))
+					tif->tif_flags |= TIFF_SWAB;
+				#endif
+				break;
+			case 'B':
+				tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
+				    FILLORDER_MSB2LSB;
+				break;
+			case 'L':
+				tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
+				    FILLORDER_LSB2MSB;
+				break;
+			case 'H':
+				tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
+				    HOST_FILLORDER;
+				break;
+			case 'M':
+				if (m == O_RDONLY)
+					tif->tif_flags |= TIFF_MAPPED;
+				break;
+			case 'm':
+				if (m == O_RDONLY)
+					tif->tif_flags &= ~TIFF_MAPPED;
+				break;
+			case 'C':
+				if (m == O_RDONLY)
+					tif->tif_flags |= TIFF_STRIPCHOP;
+				break;
+			case 'c':
+				if (m == O_RDONLY)
+					tif->tif_flags &= ~TIFF_STRIPCHOP;
+				break;
+			case 'h':
+				tif->tif_flags |= TIFF_HEADERONLY;
+				break;
+			case '8':
+				if (m&O_CREAT)
+					tif->tif_flags |= TIFF_BIGTIFF;
+				break;
+		}
+	/*
+	 * Read in TIFF header.
+	 */
+	if ((m & O_TRUNC) ||
+	    !ReadOK(tif, &tif->tif_header, sizeof (TIFFHeaderClassic))) {
+		if (tif->tif_mode == O_RDONLY) {
+			TIFFErrorExt(tif->tif_clientdata, name,
+			    "Cannot read TIFF header");
+			goto bad;
+		}
+		/*
+		 * Setup header and write.
+		 */
+		#ifdef WORDS_BIGENDIAN
+		tif->tif_header.common.tiff_magic = tif->tif_flags & TIFF_SWAB
+		    ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN;
+		#else
+		tif->tif_header.common.tiff_magic = tif->tif_flags & TIFF_SWAB
+		    ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN;
+		#endif
+		if (!(tif->tif_flags&TIFF_BIGTIFF))
+		{
+			tif->tif_header.common.tiff_version = TIFF_VERSION_CLASSIC;
+			tif->tif_header.classic.tiff_diroff = 0;
+			if (tif->tif_flags & TIFF_SWAB)
+				TIFFSwabShort(&tif->tif_header.common.tiff_version);
+			tif->tif_header_size = sizeof(TIFFHeaderClassic);
+		}
+		else
+		{
+			tif->tif_header.common.tiff_version = TIFF_VERSION_BIG;
+			tif->tif_header.big.tiff_offsetsize = 8;
+			tif->tif_header.big.tiff_unused = 0;
+			tif->tif_header.big.tiff_diroff = 0;
+			if (tif->tif_flags & TIFF_SWAB)
+			{
+				TIFFSwabShort(&tif->tif_header.common.tiff_version);
+				TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize);
+			}
+			tif->tif_header_size = sizeof (TIFFHeaderBig);
+		}
+		/*
+		 * The doc for "fopen" for some STD_C_LIBs says that if you
+		 * open a file for modify ("+"), then you must fseek (or
+		 * fflush?) between any freads and fwrites.  This is not
+		 * necessary on most systems, but has been shown to be needed
+		 * on Solaris.
+		 */
+		TIFFSeekFile( tif, 0, SEEK_SET );
+		if (!WriteOK(tif, &tif->tif_header, (tmsize_t)(tif->tif_header_size))) {
+			TIFFErrorExt(tif->tif_clientdata, name,
+			    "Error writing TIFF header");
+			goto bad;
+		}
+		/*
+		 * Setup the byte order handling.
+		 */
+		if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) {
+			#ifndef WORDS_BIGENDIAN
+			tif->tif_flags |= TIFF_SWAB;
+			#endif
+		} else {
+			#ifdef WORDS_BIGENDIAN
+			tif->tif_flags |= TIFF_SWAB;
+			#endif
+		}
+		/*
+		 * Setup default directory.
+		 */
+		if (!TIFFDefaultDirectory(tif))
+			goto bad;
+		tif->tif_diroff = 0;
+		tif->tif_dirlist = NULL;
+		tif->tif_dirlistsize = 0;
+		tif->tif_dirnumber = 0;
+		return (tif);
+	}
+	/*
+	 * Setup the byte order handling.
+	 */
+	if (tif->tif_header.common.tiff_magic != TIFF_BIGENDIAN &&
+	    tif->tif_header.common.tiff_magic != TIFF_LITTLEENDIAN
+	    #if MDI_SUPPORT
+	    &&
+	    #if HOST_BIGENDIAN
+	    tif->tif_header.common.tiff_magic != MDI_BIGENDIAN
+	    #else
+	    tif->tif_header.common.tiff_magic != MDI_LITTLEENDIAN
+	    #endif
+	    ) {
+		TIFFErrorExt(tif->tif_clientdata, name,
+		    "Not a TIFF or MDI file, bad magic number %d (0x%x)",
+	    #else
+	    ) {
+		TIFFErrorExt(tif->tif_clientdata, name,
+		    "Not a TIFF file, bad magic number %d (0x%x)",
+	    #endif
+		    tif->tif_header.common.tiff_magic,
+		    tif->tif_header.common.tiff_magic);
+		goto bad;
+	}
+	if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) {
+		#ifndef WORDS_BIGENDIAN
+		tif->tif_flags |= TIFF_SWAB;
+		#endif
+	} else {
+		#ifdef WORDS_BIGENDIAN
+		tif->tif_flags |= TIFF_SWAB;
+		#endif
+	}
+	if (tif->tif_flags & TIFF_SWAB) 
+		TIFFSwabShort(&tif->tif_header.common.tiff_version);
+	if ((tif->tif_header.common.tiff_version != TIFF_VERSION_CLASSIC)&&
+	    (tif->tif_header.common.tiff_version != TIFF_VERSION_BIG)) {
+		TIFFErrorExt(tif->tif_clientdata, name,
+		    "Not a TIFF file, bad version number %d (0x%x)",
+		    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*)(&tif->tif_header) + sizeof(TIFFHeaderClassic)), (sizeof(TIFFHeaderBig)-sizeof(TIFFHeaderClassic))))
+		{
+			TIFFErrorExt(tif->tif_clientdata, name,
+			    "Cannot read TIFF header");
+			goto bad;
+		}
+		if (tif->tif_flags & TIFF_SWAB)
+		{
+			TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize);
+			TIFFSwabLong8(&tif->tif_header.big.tiff_diroff);
+		}
+		if (tif->tif_header.big.tiff_offsetsize != 8)
+		{
+			TIFFErrorExt(tif->tif_clientdata, name,
+			    "Not a TIFF file, bad BigTIFF offsetsize %d (0x%x)",
+			    tif->tif_header.big.tiff_offsetsize,
+			    tif->tif_header.big.tiff_offsetsize);
+			goto bad;
+		}
+		if (tif->tif_header.big.tiff_unused != 0)
+		{
+			TIFFErrorExt(tif->tif_clientdata, name,
+			    "Not a TIFF file, bad BigTIFF unused %d (0x%x)",
+			    tif->tif_header.big.tiff_unused,
+			    tif->tif_header.big.tiff_unused);
+			goto bad;
+		}
+		tif->tif_header_size = sizeof(TIFFHeaderBig);
+		tif->tif_flags |= TIFF_BIGTIFF;
+	}
+	tif->tif_flags |= TIFF_MYBUFFER;
+	tif->tif_rawcp = tif->tif_rawdata = 0;
+	tif->tif_rawdatasize = 0;
+        tif->tif_rawdataoff = 0;
+        tif->tif_rawdataloaded = 0;
+
+	switch (mode[0]) {
+		case 'r':
+			if (!(tif->tif_flags&TIFF_BIGTIFF))
+				tif->tif_nextdiroff = tif->tif_header.classic.tiff_diroff;
+			else
+				tif->tif_nextdiroff = tif->tif_header.big.tiff_diroff;
+			/*
+			 * Try to use a memory-mapped file if the client
+			 * has not explicitly suppressed usage with the
+			 * 'm' flag in the open mode (see above).
+			 */
+			if (tif->tif_flags & TIFF_MAPPED)
+			{
+				toff_t n;
+				if (TIFFMapFileContents(tif,(void**)(&tif->tif_base),&n))
+				{
+					tif->tif_size=(tmsize_t)n;
+					assert((toff_t)tif->tif_size==n);
+				}
+				else
+					tif->tif_flags &= ~TIFF_MAPPED;
+			}
+			/*
+			 * Sometimes we do not want to read the first directory (for example,
+			 * it may be broken) and want to proceed to other directories. I this
+			 * case we use the TIFF_HEADERONLY flag to open file and return
+			 * immediately after reading TIFF header.
+			 */
+			if (tif->tif_flags & TIFF_HEADERONLY)
+				return (tif);
+
+			/*
+			 * Setup initial directory.
+			 */
+			if (TIFFReadDirectory(tif)) {
+				tif->tif_rawcc = (tmsize_t)-1;
+				tif->tif_flags |= TIFF_BUFFERSETUP;
+				return (tif);
+			}
+			break;
+		case 'a':
+			/*
+			 * New directories are automatically append
+			 * to the end of the directory chain when they
+			 * are written out (see TIFFWriteDirectory).
+			 */
+			if (!TIFFDefaultDirectory(tif))
+				goto bad;
+			return (tif);
+	}
+bad:
+	tif->tif_mode = O_RDONLY;	/* XXX avoid flush */
+        TIFFCleanup(tif);
+bad2:
+	return ((TIFF*)0);
+}
+
+/*
+ * Query functions to access private data.
+ */
+
+/*
+ * Return open file's name.
+ */
+const char *
+TIFFFileName(TIFF* tif)
+{
+	return (tif->tif_name);
+}
+
+/*
+ * Set the file name.
+ */
+const char *
+TIFFSetFileName(TIFF* tif, const char *name)
+{
+	const char* old_name = tif->tif_name;
+	tif->tif_name = (char *)name;
+	return (old_name);
+}
+
+/*
+ * Return open file's I/O descriptor.
+ */
+int
+TIFFFileno(TIFF* tif)
+{
+	return (tif->tif_fd);
+}
+
+/*
+ * Set open file's I/O descriptor, and return previous value.
+ */
+int
+TIFFSetFileno(TIFF* tif, int fd)
+{
+        int old_fd = tif->tif_fd;
+	tif->tif_fd = fd;
+	return old_fd;
+}
+
+/*
+ * Return open file's clientdata.
+ */
+thandle_t
+TIFFClientdata(TIFF* tif)
+{
+	return (tif->tif_clientdata);
+}
+
+/*
+ * Set open file's clientdata, and return previous value.
+ */
+thandle_t
+TIFFSetClientdata(TIFF* tif, thandle_t newvalue)
+{
+	thandle_t m = tif->tif_clientdata;
+	tif->tif_clientdata = newvalue;
+	return m;
+}
+
+/*
+ * Return read/write mode.
+ */
+int
+TIFFGetMode(TIFF* tif)
+{
+	return (tif->tif_mode);
+}
+
+/*
+ * Return read/write mode.
+ */
+int
+TIFFSetMode(TIFF* tif, int mode)
+{
+	int old_mode = tif->tif_mode;
+	tif->tif_mode = mode;
+	return (old_mode);
+}
+
+/*
+ * Return nonzero if file is organized in
+ * tiles; zero if organized as strips.
+ */
+int
+TIFFIsTiled(TIFF* tif)
+{
+	return (isTiled(tif));
+}
+
+/*
+ * Return current row being read/written.
+ */
+uint32
+TIFFCurrentRow(TIFF* tif)
+{
+	return (tif->tif_row);
+}
+
+/*
+ * Return index of the current directory.
+ */
+uint16
+TIFFCurrentDirectory(TIFF* tif)
+{
+	return (tif->tif_curdir);
+}
+
+/*
+ * Return current strip.
+ */
+uint32
+TIFFCurrentStrip(TIFF* tif)
+{
+	return (tif->tif_curstrip);
+}
+
+/*
+ * Return current tile.
+ */
+uint32
+TIFFCurrentTile(TIFF* tif)
+{
+	return (tif->tif_curtile);
+}
+
+/*
+ * Return nonzero if the file has byte-swapped data.
+ */
+int
+TIFFIsByteSwapped(TIFF* tif)
+{
+	return ((tif->tif_flags & TIFF_SWAB) != 0);
+}
+
+/*
+ * Return nonzero if the data is returned up-sampled.
+ */
+int
+TIFFIsUpSampled(TIFF* tif)
+{
+	return (isUpSampled(tif));
+}
+
+/*
+ * Return nonzero if the data is returned in MSB-to-LSB bit order.
+ */
+int
+TIFFIsMSB2LSB(TIFF* tif)
+{
+	return (isFillOrder(tif, FILLORDER_MSB2LSB));
+}
+
+/*
+ * Return nonzero if given file was written in big-endian order.
+ */
+int
+TIFFIsBigEndian(TIFF* tif)
+{
+	return (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN);
+}
+
+/*
+ * Return pointer to file read method.
+ */
+TIFFReadWriteProc
+TIFFGetReadProc(TIFF* tif)
+{
+	return (tif->tif_readproc);
+}
+
+/*
+ * Return pointer to file write method.
+ */
+TIFFReadWriteProc
+TIFFGetWriteProc(TIFF* tif)
+{
+	return (tif->tif_writeproc);
+}
+
+/*
+ * Return pointer to file seek method.
+ */
+TIFFSeekProc
+TIFFGetSeekProc(TIFF* tif)
+{
+	return (tif->tif_seekproc);
+}
+
+/*
+ * Return pointer to file close method.
+ */
+TIFFCloseProc
+TIFFGetCloseProc(TIFF* tif)
+{
+	return (tif->tif_closeproc);
+}
+
+/*
+ * Return pointer to file size requesting method.
+ */
+TIFFSizeProc
+TIFFGetSizeProc(TIFF* tif)
+{
+	return (tif->tif_sizeproc);
+}
+
+/*
+ * Return pointer to memory mapping method.
+ */
+TIFFMapFileProc
+TIFFGetMapFileProc(TIFF* tif)
+{
+	return (tif->tif_mapproc);
+}
+
+/*
+ * Return pointer to memory unmapping method.
+ */
+TIFFUnmapFileProc
+TIFFGetUnmapFileProc(TIFF* tif)
+{
+	return (tif->tif_unmapproc);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_packbits.c b/third_party/libtiff/tif_packbits.c
new file mode 100644
index 0000000..9e77190
--- /dev/null
+++ b/third_party/libtiff/tif_packbits.c
@@ -0,0 +1,300 @@
+/* $Id: tif_packbits.c,v 1.22 2012-06-20 05:25:33 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef PACKBITS_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * PackBits Compression Algorithm Support
+ */
+#include <stdio.h>
+
+static int
+PackBitsPreEncode(TIFF* tif, uint16 s)
+{
+	(void) s;
+
+	if (!(tif->tif_data = (uint8*)_TIFFmalloc(sizeof(tmsize_t))))
+		return (0);
+	/*
+	 * Calculate the scanline/tile-width size in bytes.
+	 */
+	if (isTiled(tif))
+		*(tmsize_t*)tif->tif_data = TIFFTileRowSize(tif);
+	else
+		*(tmsize_t*)tif->tif_data = TIFFScanlineSize(tif);
+	return (1);
+}
+
+static int
+PackBitsPostEncode(TIFF* tif)
+{
+        if (tif->tif_data)
+            _TIFFfree(tif->tif_data);
+	return (1);
+}
+
+/*
+ * Encode a run of pixels.
+ */
+static int
+PackBitsEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
+{
+	unsigned char* bp = (unsigned char*) buf;
+	uint8* op;
+	uint8* ep;
+	uint8* lastliteral;
+	long n, slop;
+	int b;
+	enum { BASE, LITERAL, RUN, LITERAL_RUN } state;
+
+	(void) s;
+	op = tif->tif_rawcp;
+	ep = tif->tif_rawdata + tif->tif_rawdatasize;
+	state = BASE;
+	lastliteral = 0;
+	while (cc > 0) {
+		/*
+		 * Find the longest string of identical bytes.
+		 */
+		b = *bp++, cc--, n = 1;
+		for (; cc > 0 && b == *bp; cc--, bp++)
+			n++;
+	again:
+		if (op + 2 >= ep) {		/* insure space for new data */
+			/*
+			 * Be careful about writing the last
+			 * literal.  Must write up to that point
+			 * and then copy the remainder to the
+			 * front of the buffer.
+			 */
+			if (state == LITERAL || state == LITERAL_RUN) {
+				slop = (long)(op - lastliteral);
+				tif->tif_rawcc += (tmsize_t)(lastliteral - tif->tif_rawcp);
+				if (!TIFFFlushData1(tif))
+					return (-1);
+				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 (-1);
+				op = tif->tif_rawcp;
+			}
+		}
+		switch (state) {
+		case BASE:		/* initial state, set run/literal */
+			if (n > 1) {
+				state = RUN;
+				if (n > 128) {
+					*op++ = (uint8) -127;
+					*op++ = (uint8) b;
+					n -= 128;
+					goto again;
+				}
+				*op++ = (uint8)(-(n-1));
+				*op++ = (uint8) b;
+			} else {
+				lastliteral = op;
+				*op++ = 0;
+				*op++ = (uint8) b;
+				state = LITERAL;
+			}
+			break;
+		case LITERAL:		/* last object was literal string */
+			if (n > 1) {
+				state = LITERAL_RUN;
+				if (n > 128) {
+					*op++ = (uint8) -127;
+					*op++ = (uint8) b;
+					n -= 128;
+					goto again;
+				}
+				*op++ = (uint8)(-(n-1));	/* encode run */
+				*op++ = (uint8) b;
+			} else {			/* extend literal */
+				if (++(*lastliteral) == 127)
+					state = BASE;
+				*op++ = (uint8) b;
+			}
+			break;
+		case RUN:		/* last object was run */
+			if (n > 1) {
+				if (n > 128) {
+					*op++ = (uint8) -127;
+					*op++ = (uint8) b;
+					n -= 128;
+					goto again;
+				}
+				*op++ = (uint8)(-(n-1));
+				*op++ = (uint8) b;
+			} else {
+				lastliteral = op;
+				*op++ = 0;
+				*op++ = (uint8) 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) -1 &&
+			    *lastliteral < 126) {
+				state = (((*lastliteral) += 2) == 127 ?
+				    BASE : LITERAL);
+				op[-2] = op[-1];	/* replicate */
+			} else
+				state = RUN;
+			goto again;
+		}
+	}
+	tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
+	tif->tif_rawcp = op;
+	return (1);
+}
+
+/*
+ * Encode a rectangular chunk of pixels.  We break it up
+ * into row-sized pieces to insure that encoded runs do
+ * not span rows.  Otherwise, there can be problems with
+ * the decoder if data is read, for example, by scanlines
+ * when it was encoded by strips.
+ */
+static int
+PackBitsEncodeChunk(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	tmsize_t rowsize = *(tmsize_t*)tif->tif_data;
+
+	while (cc > 0) {
+		tmsize_t chunk = rowsize;
+		
+		if( cc < chunk )
+		    chunk = cc;
+
+		if (PackBitsEncode(tif, bp, chunk, s) < 0)
+		    return (-1);
+		bp += chunk;
+		cc -= chunk;
+	}
+	return (1);
+}
+
+static int
+PackBitsDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "PackBitsDecode";
+	char *bp;
+	tmsize_t cc;
+	long n;
+	int b;
+
+	(void) s;
+	bp = (char*) tif->tif_rawcp;
+	cc = tif->tif_rawcc;
+	while (cc > 0 && occ > 0) {
+		n = (long) *bp++, cc--;
+		/*
+		 * Watch out for compilers that
+		 * don't sign extend chars...
+		 */
+		if (n >= 128)
+			n -= 256;
+		if (n < 0) {		/* replicate next byte -n+1 times */
+			if (n == -128)	/* nop */
+				continue;
+			n = -n + 1;
+			if( occ < (tmsize_t)n )
+			{
+				TIFFWarningExt(tif->tif_clientdata, module,
+				    "Discarding %lu bytes to avoid buffer overrun",
+				    (unsigned long) ((tmsize_t)n - occ));
+				n = (long)occ;
+			}
+			occ -= n;
+			b = *bp++, cc--;
+			while (n-- > 0)
+				*op++ = (uint8) b;
+		} else {		/* copy next n+1 bytes literally */
+			if (occ < (tmsize_t)(n + 1))
+			{
+				TIFFWarningExt(tif->tif_clientdata, module,
+				    "Discarding %lu bytes to avoid buffer overrun",
+				    (unsigned long) ((tmsize_t)n - occ + 1));
+				n = (long)occ - 1;
+			}
+			if (cc < (tmsize_t) (n+1)) 
+			{
+				TIFFWarningExt(tif->tif_clientdata, module,
+					       "Terminating PackBitsDecode due to lack of data.");
+				break;
+			}
+			_TIFFmemcpy(op, bp, ++n);
+			op += n; occ -= n;
+			bp += n; cc -= n;
+		}
+	}
+	tif->tif_rawcp = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	if (occ > 0) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Not enough data for scanline %lu",
+		    (unsigned long) tif->tif_row);
+		return (0);
+	}
+	return (1);
+}
+
+int
+TIFFInitPackBits(TIFF* tif, int scheme)
+{
+	(void) scheme;
+	tif->tif_decoderow = PackBitsDecode;
+	tif->tif_decodestrip = PackBitsDecode;
+	tif->tif_decodetile = PackBitsDecode;
+	tif->tif_preencode = PackBitsPreEncode;
+	tif->tif_postencode = PackBitsPostEncode;
+	tif->tif_encoderow = PackBitsEncode;
+	tif->tif_encodestrip = PackBitsEncodeChunk;
+	tif->tif_encodetile = PackBitsEncodeChunk;
+	return (1);
+}
+#endif /* PACKBITS_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_pixarlog.c b/third_party/libtiff/tif_pixarlog.c
new file mode 100644
index 0000000..b93b4c7
--- /dev/null
+++ b/third_party/libtiff/tif_pixarlog.c
@@ -0,0 +1,1442 @@
+/* $Id: tif_pixarlog.c,v 1.39 2012-12-10 17:27:13 tgl Exp $ */
+
+/*
+ * Copyright (c) 1996-1997 Sam Leffler
+ * Copyright (c) 1996 Pixar
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Pixar, Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Pixar, Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL PIXAR, SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef PIXARLOG_SUPPORT
+
+/*
+ * TIFF Library.
+ * PixarLog Compression Support
+ *
+ * Contributed by Dan McCoy.
+ *
+ * PixarLog film support uses the TIFF library to store companded
+ * 11 bit values into a tiff file, which are compressed using the 
+ * zip compressor.  
+ *
+ * The codec can take as input and produce as output 32-bit IEEE float values 
+ * as well as 16-bit or 8-bit unsigned integer values.
+ *
+ * On writing any of the above are converted into the internal
+ * 11-bit log format.   In the case of  8 and 16 bit values, the
+ * input is assumed to be unsigned linear color values that represent
+ * the range 0-1.  In the case of IEEE values, the 0-1 range is assumed to
+ * be the normal linear color range, in addition over 1 values are
+ * accepted up to a value of about 25.0 to encode "hot" hightlights 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.
+ *
+ * On reading the internal format is converted to the desired output format.
+ * The program can request which format it desires by setting the internal
+ * pseudo tag TIFFTAG_PIXARLOGDATAFMT to one of these possible values:
+ *  PIXARLOGDATAFMT_FLOAT     = provide IEEE float values.
+ *  PIXARLOGDATAFMT_16BIT     = provide unsigned 16-bit integer values
+ *  PIXARLOGDATAFMT_8BIT      = provide unsigned 8-bit integer values
+ *
+ * alternately PIXARLOGDATAFMT_8BITABGR provides unsigned 8-bit integer
+ * values with the difference that if there are exactly three or four channels
+ * (rgb or rgba) it swaps the channel order (bgr or abgr).
+ *
+ * PIXARLOGDATAFMT_11BITLOG provides the internal encoding directly
+ * packed in 16-bit values.   However no tools are supplied for interpreting
+ * these values.
+ *
+ * "hot" (over 1.0) areas written in floating point get clamped to
+ * 1.0 in the integer data types.
+ *
+ * When the file is closed after writing, the bit depth and sample format
+ * are set always to appear as if 8-bit data has been written into it.
+ * That way a naive program unaware of the particulars of the encoding
+ * gets the format it is most likely able to handle.
+ *
+ * The codec does it's own horizontal differencing step on the coded
+ * values so the libraries predictor stuff should be turned off.
+ * The codec also handle byte swapping the encoded values as necessary
+ * since the library does not have the information necessary
+ * to know the bit depth of the raw unencoded buffer.
+ *
+ * NOTE: This decoder does not appear to update tif_rawcp, and tif_rawcc.
+ * This can cause problems with the implementation of CHUNKY_STRIP_READ_SUPPORT
+ * as noted in http://trac.osgeo.org/gdal/ticket/3894.   FrankW - Jan'11
+ */
+
+#include "tif_predict.h"
+#include "../zlib_v128/zlib.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+/* Tables for converting to/from 11 bit coded values */
+
+#define  TSIZE	 2048		/* decode table size (11-bit tokens) */
+#define  TSIZEP1 2049		/* Plus one for slop */
+#define  ONE	 1250		/* token value of 1.0 exactly */
+#define  RATIO	 1.004		/* nominal ratio for log part */
+
+#define CODE_MASK 0x7ff         /* 11 bits. */
+
+static float  Fltsize;
+static float  LogK1, LogK2;
+
+#define REPEAT(n, op)   { int i; i=n; do { i--; op; } while (i>0); }
+
+static void
+horizontalAccumulateF(uint16 *wp, int n, int stride, float *op,
+	float *ToLinearF)
+{
+    register unsigned int  cr, cg, cb, ca, mask;
+    register float  t0, t1, t2, t3;
+
+    if (n >= stride) {
+	mask = CODE_MASK;
+	if (stride == 3) {
+	    t0 = ToLinearF[cr = (wp[0] & mask)];
+	    t1 = ToLinearF[cg = (wp[1] & mask)];
+	    t2 = ToLinearF[cb = (wp[2] & mask)];
+	    op[0] = t0;
+	    op[1] = t1;
+	    op[2] = t2;
+	    n -= 3;
+	    while (n > 0) {
+		wp += 3;
+		op += 3;
+		n -= 3;
+		t0 = ToLinearF[(cr += wp[0]) & mask];
+		t1 = ToLinearF[(cg += wp[1]) & mask];
+		t2 = ToLinearF[(cb += wp[2]) & mask];
+		op[0] = t0;
+		op[1] = t1;
+		op[2] = t2;
+	    }
+	} else if (stride == 4) {
+	    t0 = ToLinearF[cr = (wp[0] & mask)];
+	    t1 = ToLinearF[cg = (wp[1] & mask)];
+	    t2 = ToLinearF[cb = (wp[2] & mask)];
+	    t3 = ToLinearF[ca = (wp[3] & mask)];
+	    op[0] = t0;
+	    op[1] = t1;
+	    op[2] = t2;
+	    op[3] = t3;
+	    n -= 4;
+	    while (n > 0) {
+		wp += 4;
+		op += 4;
+		n -= 4;
+		t0 = ToLinearF[(cr += wp[0]) & mask];
+		t1 = ToLinearF[(cg += wp[1]) & mask];
+		t2 = ToLinearF[(cb += wp[2]) & mask];
+		t3 = ToLinearF[(ca += wp[3]) & mask];
+		op[0] = t0;
+		op[1] = t1;
+		op[2] = t2;
+		op[3] = t3;
+	    }
+	} else {
+	    REPEAT(stride, *op = ToLinearF[*wp&mask]; wp++; op++)
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride,
+		    wp[stride] += *wp; *op = ToLinearF[*wp&mask]; wp++; op++)
+		n -= stride;
+	    }
+	}
+    }
+}
+
+static void
+horizontalAccumulate12(uint16 *wp, int n, int stride, int16 *op,
+	float *ToLinearF)
+{
+    register unsigned int  cr, cg, cb, ca, mask;
+    register float  t0, t1, t2, t3;
+
+#define SCALE12 2048.0F
+#define CLAMP12(t) (((t) < 3071) ? (uint16) (t) : 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)
+{
+    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)
+{
+    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;
+	    }
+	}
+    }
+}
+
+static void
+horizontalAccumulate8(uint16 *wp, int n, int stride, unsigned char *op,
+	unsigned char *ToLinear8)
+{
+    register unsigned int  cr, cg, cb, ca, mask;
+
+    if (n >= stride) {
+	mask = CODE_MASK;
+	if (stride == 3) {
+	    op[0] = ToLinear8[cr = (wp[0] & mask)];
+	    op[1] = ToLinear8[cg = (wp[1] & mask)];
+	    op[2] = ToLinear8[cb = (wp[2] & mask)];
+	    n -= 3;
+	    while (n > 0) {
+		n -= 3;
+		wp += 3;
+		op += 3;
+		op[0] = ToLinear8[(cr += wp[0]) & mask];
+		op[1] = ToLinear8[(cg += wp[1]) & mask];
+		op[2] = ToLinear8[(cb += wp[2]) & mask];
+	    }
+	} else if (stride == 4) {
+	    op[0] = ToLinear8[cr = (wp[0] & mask)];
+	    op[1] = ToLinear8[cg = (wp[1] & mask)];
+	    op[2] = ToLinear8[cb = (wp[2] & mask)];
+	    op[3] = ToLinear8[ca = (wp[3] & mask)];
+	    n -= 4;
+	    while (n > 0) {
+		n -= 4;
+		wp += 4;
+		op += 4;
+		op[0] = ToLinear8[(cr += wp[0]) & mask];
+		op[1] = ToLinear8[(cg += wp[1]) & mask];
+		op[2] = ToLinear8[(cb += wp[2]) & mask];
+		op[3] = ToLinear8[(ca += wp[3]) & mask];
+	    }
+	} else {
+	    REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++)
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride,
+		    wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++)
+		n -= stride;
+	    }
+	}
+    }
+}
+
+
+static void
+horizontalAccumulate8abgr(uint16 *wp, int n, int stride, unsigned char *op,
+	unsigned char *ToLinear8)
+{
+    register unsigned int  cr, cg, cb, ca, mask;
+    register unsigned char  t0, t1, t2, t3;
+
+    if (n >= stride) {
+	mask = CODE_MASK;
+	if (stride == 3) {
+	    op[0] = 0;
+	    t1 = ToLinear8[cb = (wp[2] & mask)];
+	    t2 = ToLinear8[cg = (wp[1] & mask)];
+	    t3 = ToLinear8[cr = (wp[0] & mask)];
+	    op[1] = t1;
+	    op[2] = t2;
+	    op[3] = t3;
+	    n -= 3;
+	    while (n > 0) {
+		n -= 3;
+		wp += 3;
+		op += 4;
+		op[0] = 0;
+		t1 = ToLinear8[(cb += wp[2]) & mask];
+		t2 = ToLinear8[(cg += wp[1]) & mask];
+		t3 = ToLinear8[(cr += wp[0]) & mask];
+		op[1] = t1;
+		op[2] = t2;
+		op[3] = t3;
+	    }
+	} else if (stride == 4) {
+	    t0 = ToLinear8[ca = (wp[3] & mask)];
+	    t1 = ToLinear8[cb = (wp[2] & mask)];
+	    t2 = ToLinear8[cg = (wp[1] & mask)];
+	    t3 = ToLinear8[cr = (wp[0] & mask)];
+	    op[0] = t0;
+	    op[1] = t1;
+	    op[2] = t2;
+	    op[3] = t3;
+	    n -= 4;
+	    while (n > 0) {
+		n -= 4;
+		wp += 4;
+		op += 4;
+		t0 = ToLinear8[(ca += wp[3]) & mask];
+		t1 = ToLinear8[(cb += wp[2]) & mask];
+		t2 = ToLinear8[(cg += wp[1]) & mask];
+		t3 = ToLinear8[(cr += wp[0]) & mask];
+		op[0] = t0;
+		op[1] = t1;
+		op[2] = t2;
+		op[3] = t3;
+	    }
+	} else {
+	    REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++)
+	    n -= stride;
+	    while (n > 0) {
+		REPEAT(stride,
+		    wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++)
+		n -= stride;
+	    }
+	}
+    }
+}
+
+/*
+ * State block for each open TIFF
+ * file using PixarLog compression/decompression.
+ */
+typedef	struct {
+	TIFFPredictorState	predict;
+	z_stream		stream;
+	uint16			*tbuf; 
+	uint16			stride;
+	int			state;
+	int			user_datafmt;
+	int			quality;
+#define PLSTATE_INIT 1
+
+	TIFFVSetMethod		vgetparent;	/* super-class method */
+	TIFFVSetMethod		vsetparent;	/* super-class method */
+
+	float *ToLinearF;
+	uint16 *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)
+{
+
+/*
+ *    We make several tables here to convert between various external
+ *    representations (float, 16-bit, and 8-bit) and the internal
+ *    11-bit companded representation.  The 11-bit representation has two
+ *    distinct regions.  A linear bottom end up through .018316 in steps
+ *    of about .000073, and a region of constant ratio up to about 25.
+ *    These floating point numbers are stored in the main table ToLinearF. 
+ *    All other tables are derived from this one.  The tables (and the
+ *    ratios) are continuous at the internal seam.
+ */
+
+    int  nlin, lt2size;
+    int  i, j;
+    double  b, c, linstep, v;
+    float *ToLinearF;
+    uint16 *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;
+    }
+
+    j = 0;
+
+    for (i = 0; i < nlin; i++)  {
+	v = i * linstep;
+	ToLinearF[j++] = (float)v;
+    }
+
+    for (i = nlin; i < TSIZE; i++)
+	ToLinearF[j++] = (float)(b*exp(c*i));
+
+    ToLinearF[2048] = ToLinearF[2047];
+
+    for (i = 0; i < TSIZEP1; i++)  {
+	v = ToLinearF[i]*65535.0 + 0.5;
+	ToLinear16[i] = (v > 65535.0) ? 65535 : (uint16)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;
+    }
+
+    /*
+     * Since we lose info anyway on 16-bit data, we set up a 14-bit
+     * table and shift 16-bit values down two bits on input.
+     * saves a little table space.
+     */
+    j = 0;
+    for (i = 0; i < 16384; i++)  {
+	while ((i/16383.)*(i/16383.) > ToLinearF[j]*ToLinearF[j+1])
+	    j++;
+	From14[i] = j;
+    }
+
+    j = 0;
+    for (i = 0; i < 256; i++)  {
+	while ((i/255.)*(i/255.) > ToLinearF[j]*ToLinearF[j+1])
+	    j++;
+	From8[i] = j;
+    }
+
+    Fltsize = (float)(lt2size/2);
+
+    sp->ToLinearF = ToLinearF;
+    sp->ToLinear16 = ToLinear16;
+    sp->ToLinear8 = ToLinear8;
+    sp->FromLT2 = FromLT2;
+    sp->From14 = From14;
+    sp->From8 = From8;
+
+    return 1;
+}
+
+#define DecoderState(tif)	((PixarLogState*) (tif)->tif_data)
+#define EncoderState(tif)	((PixarLogState*) (tif)->tif_data)
+
+static int PixarLogEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s);
+static int PixarLogDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s);
+
+#define PIXARLOGDATAFMT_UNKNOWN	-1
+
+static int
+PixarLogGuessDataFmt(TIFFDirectory *td)
+{
+	int guess = PIXARLOGDATAFMT_UNKNOWN;
+	int format = td->td_sampleformat;
+
+	/* If the user didn't tell us his datafmt,
+	 * take our best guess from the bitspersample.
+	 */
+	switch (td->td_bitspersample) {
+	 case 32:
+		if (format == SAMPLEFORMAT_IEEEFP)
+			guess = PIXARLOGDATAFMT_FLOAT;
+		break;
+	 case 16:
+		if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
+			guess = PIXARLOGDATAFMT_16BIT;
+		break;
+	 case 12:
+		if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_INT)
+			guess = PIXARLOGDATAFMT_12BITPICIO;
+		break;
+	 case 11:
+		if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
+			guess = PIXARLOGDATAFMT_11BITLOG;
+		break;
+	 case 8:
+		if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
+			guess = PIXARLOGDATAFMT_8BIT;
+		break;
+	}
+
+	return guess;
+}
+
+static tmsize_t
+multiply_ms(tmsize_t m1, tmsize_t m2)
+{
+	tmsize_t bytes = m1 * m2;
+
+	if (m1 && bytes / m1 != m2)
+		bytes = 0;
+
+	return bytes;
+}
+
+static tmsize_t
+add_ms(tmsize_t m1, tmsize_t m2)
+{
+	tmsize_t bytes = m1 + m2;
+
+	/* if either input is zero, assume overflow already occurred */
+	if (m1 == 0 || m2 == 0)
+		bytes = 0;
+	else if (bytes <= m1 || bytes <= m2)
+		bytes = 0;
+
+	return bytes;
+}
+
+static int
+PixarLogFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+static int
+PixarLogSetupDecode(TIFF* tif)
+{
+	static const char module[] = "PixarLogSetupDecode";
+	TIFFDirectory *td = &tif->tif_dir;
+	PixarLogState* sp = DecoderState(tif);
+	tmsize_t tbuf_size;
+
+	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_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth),
+				      td->td_rowsperstrip), sizeof(uint16));
+	/* add one more stride in case input ends mid-stride */
+	tbuf_size = add_ms(tbuf_size, sizeof(uint16) * sp->stride);
+	if (tbuf_size == 0)
+		return (0);   /* TODO: this is an error return without error report through TIFFErrorExt */
+	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", sp->stream.msg);
+		return (0);
+	} else {
+		sp->state |= PLSTATE_INIT;
+		return (1);
+	}
+}
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+PixarLogPreDecode(TIFF* tif, uint16 s)
+{
+	static const char module[] = "PixarLogPreDecode";
+	PixarLogState* sp = DecoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	sp->stream.next_in = tif->tif_rawdata;
+	assert(sizeof(sp->stream.avail_in)==4);  /* if this assert gets raised,
+	    we need to simplify this code to reflect a ZLib that is likely updated
+	    to deal with 8byte memory sizes, though this code will respond
+	    apropriately even before we simplify it */
+	sp->stream.avail_in = (uInt) tif->tif_rawcc;
+	if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	return (inflateReset(&sp->stream) == Z_OK);
+}
+
+static int
+PixarLogDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "PixarLogDecode";
+	TIFFDirectory *td = &tif->tif_dir;
+	PixarLogState* sp = DecoderState(tif);
+	tmsize_t i;
+	tmsize_t nsamples;
+	int 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, module,
+			"%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;
+	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
+	    apropriately even before we simplify it */
+	sp->stream.avail_out = (uInt) (nsamples * sizeof(uint16));
+	if (sp->stream.avail_out != nsamples * sizeof(uint16))
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	do {
+		int state = inflate(&sp->stream, Z_PARTIAL_FLUSH);
+		if (state == Z_STREAM_END) {
+			break;			/* XXX */
+		}
+		if (state == Z_DATA_ERROR) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Decoding error at scanline %lu, %s",
+			    (unsigned long) tif->tif_row, sp->stream.msg);
+			if (inflateSync(&sp->stream) != Z_OK)
+				return (0);
+			continue;
+		}
+		if (state != Z_OK) {
+			TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
+			    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,
+		    "Not enough data at scanline %lu (short " TIFF_UINT64_FORMAT " bytes)",
+		    (unsigned long) tif->tif_row, (TIFF_UINT64_T) 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,
+			"stride %lu is not a multiple of sample count, "
+			"%lu, data truncated.", (unsigned long) llen, (unsigned long) 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, module,
+				  "Unsupported bits/sample: %d",
+				  td->td_bitspersample);
+			return (0);
+		}
+	}
+
+	return (1);
+}
+
+static int
+PixarLogSetupEncode(TIFF* tif)
+{
+	static const char module[] = "PixarLogSetupEncode";
+	TIFFDirectory *td = &tif->tif_dir;
+	PixarLogState* sp = EncoderState(tif);
+	tmsize_t tbuf_size;
+
+	assert(sp != NULL);
+
+	/* for some reason, we can't do this in TIFFInitPixarLog */
+
+	sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ?
+	    td->td_samplesperpixel : 1);
+	tbuf_size = multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth),
+				      td->td_rowsperstrip), sizeof(uint16));
+	if (tbuf_size == 0)
+		return (0);  /* TODO: this is an error return without error report through TIFFErrorExt */
+	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", sp->stream.msg);
+		return (0);
+	} else {
+		sp->state |= PLSTATE_INIT;
+		return (1);
+	}
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+PixarLogPreEncode(TIFF* tif, uint16 s)
+{
+	static const char module[] = "PixarLogPreEncode";
+	PixarLogState *sp = EncoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	sp->stream.next_out = tif->tif_rawdata;
+	assert(sizeof(sp->stream.avail_out)==4);  /* if this assert gets raised,
+	    we need to simplify this code to reflect a ZLib that is likely updated
+	    to deal with 8byte memory sizes, though this code will respond
+	    apropriately even before we simplify it */
+	sp->stream.avail_out = tif->tif_rawdatasize;
+	if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	return (deflateReset(&sp->stream) == Z_OK);
+}
+
+static void
+horizontalDifferenceF(float *ip, int n, int stride, uint16 *wp, uint16 *FromLT2)
+{
+    int32 r1, g1, b1, a1, r2, g2, b2, a2, mask;
+    float fltsize = Fltsize;
+
+#define  CLAMP(v) ( (v<(float)0.)   ? 0				\
+		  : (v<(float)2.)   ? FromLT2[(int)(v*fltsize)]	\
+		  : (v>(float)24.2) ? 2047			\
+		  : LogK1*log(v*LogK2) + 0.5 )
+
+    mask = CODE_MASK;
+    if (n >= stride) {
+	if (stride == 3) {
+	    r2 = wp[0] = (uint16) 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--)
+	}
+    }
+}
+
+static void
+horizontalDifference16(unsigned short *ip, int n, int stride, 
+	unsigned short *wp, uint16 *From14)
+{
+    register int  r1, g1, b1, a1, r2, g2, b2, a2, mask;
+
+/* assumption is unsigned pixel values */
+#undef   CLAMP
+#define  CLAMP(v) From14[(v) >> 2]
+
+    mask = CODE_MASK;
+    if (n >= stride) {
+	if (stride == 3) {
+	    r2 = wp[0] = CLAMP(ip[0]);  g2 = wp[1] = CLAMP(ip[1]);
+	    b2 = wp[2] = CLAMP(ip[2]);
+	    n -= 3;
+	    while (n > 0) {
+		n -= 3;
+		wp += 3;
+		ip += 3;
+		r1 = CLAMP(ip[0]); wp[0] = (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--)
+	}
+    }
+}
+
+
+static void
+horizontalDifference8(unsigned char *ip, int n, int stride, 
+	unsigned short *wp, uint16 *From8)
+{
+    register int  r1, g1, b1, a1, r2, g2, b2, a2, mask;
+
+#undef	 CLAMP
+#define  CLAMP(v) (From8[(v)])
+
+    mask = CODE_MASK;
+    if (n >= stride) {
+	if (stride == 3) {
+	    r2 = wp[0] = CLAMP(ip[0]);  g2 = wp[1] = CLAMP(ip[1]);
+	    b2 = wp[2] = CLAMP(ip[2]);
+	    n -= 3;
+	    while (n > 0) {
+		n -= 3;
+		r1 = CLAMP(ip[3]); wp[3] = (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--)
+	}
+    }
+}
+
+/*
+ * Encode a chunk of pixels.
+ */
+static int
+PixarLogEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	static const char module[] = "PixarLogEncode";
+	TIFFDirectory *td = &tif->tif_dir;
+	PixarLogState *sp = EncoderState(tif);
+	tmsize_t i;
+	tmsize_t n;
+	int llen;
+	unsigned short * up;
+
+	(void) s;
+
+	switch (sp->user_datafmt) {
+	case PIXARLOGDATAFMT_FLOAT:
+		n = cc / sizeof(float);		/* XXX float == 32 bits */
+		break;
+	case PIXARLOGDATAFMT_16BIT:
+	case PIXARLOGDATAFMT_12BITPICIO:
+	case PIXARLOGDATAFMT_11BITLOG:
+		n = cc / sizeof(uint16);	/* XXX uint16 == 16 bits */
+		break;
+	case PIXARLOGDATAFMT_8BIT:
+	case PIXARLOGDATAFMT_8BITABGR:
+		n = cc;
+		break;
+	default:
+		TIFFErrorExt(tif->tif_clientdata, module,
+			"%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, module,
+				"%d 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
+	    apropriately even before we simplify it */
+	sp->stream.avail_in = (uInt) (n * sizeof(uint16));
+	if ((sp->stream.avail_in / sizeof(uint16)) != (uInt) n)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+
+	do {
+		if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) {
+			TIFFErrorExt(tif->tif_clientdata, module, "Encoder error: %s",
+			    sp->stream.msg);
+			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 = (uInt) tif->tif_rawdatasize;  /* this is a safe typecast, as check is made already in PixarLogPreEncode */
+		}
+	} while (sp->stream.avail_in > 0);
+	return (1);
+}
+
+/*
+ * Finish off an encoded strip by flushing the last
+ * string and tacking on an End Of Information code.
+ */
+
+static int
+PixarLogPostEncode(TIFF* tif)
+{
+	static const char module[] = "PixarLogPostEncode";
+	PixarLogState *sp = EncoderState(tif);
+	int state;
+
+	sp->stream.avail_in = 0;
+
+	do {
+		state = deflate(&sp->stream, Z_FINISH);
+		switch (state) {
+		case Z_STREAM_END:
+		case Z_OK:
+		    if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize) {
+			    tif->tif_rawcc =
+				tif->tif_rawdatasize - sp->stream.avail_out;
+			    TIFFFlushData1(tif);
+			    sp->stream.next_out = tif->tif_rawdata;
+			    sp->stream.avail_out = (uInt) tif->tif_rawdatasize;  /* this is a safe typecast, as check is made already in PixarLogPreEncode */
+		    }
+		    break;
+		default:
+			TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
+			sp->stream.msg);
+		    return (0);
+		}
+	} while (state != Z_STREAM_END);
+	return (1);
+}
+
+static void
+PixarLogClose(TIFF* tif)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+	/* In a really sneaky (and really incorrect, and untruthfull, 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.
+	 */
+	td->td_bitspersample = 8;
+	td->td_sampleformat = SAMPLEFORMAT_UINT;
+}
+
+static void
+PixarLogCleanup(TIFF* tif)
+{
+	PixarLogState* sp = (PixarLogState*) tif->tif_data;
+
+	assert(sp != 0);
+
+	(void)TIFFPredictorCleanup(tif);
+
+	tif->tif_tagmethods.vgetfield = sp->vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+	if (sp->FromLT2) _TIFFfree(sp->FromLT2);
+	if (sp->From14) _TIFFfree(sp->From14);
+	if (sp->From8) _TIFFfree(sp->From8);
+	if (sp->ToLinearF) _TIFFfree(sp->ToLinearF);
+	if (sp->ToLinear16) _TIFFfree(sp->ToLinear16);
+	if (sp->ToLinear8) _TIFFfree(sp->ToLinear8);
+	if (sp->state&PLSTATE_INIT) {
+		if (tif->tif_mode == O_RDONLY)
+			inflateEnd(&sp->stream);
+		else
+			deflateEnd(&sp->stream);
+	}
+	if (sp->tbuf)
+		_TIFFfree(sp->tbuf);
+	_TIFFfree(sp);
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+static int
+PixarLogVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+    static const char module[] = "PixarLogVSetField";
+    PixarLogState *sp = (PixarLogState *)tif->tif_data;
+    int result;
+
+    switch (tag) {
+     case TIFFTAG_PIXARLOGQUALITY:
+		sp->quality = (int) va_arg(ap, int);
+		if (tif->tif_mode != O_RDONLY && (sp->state&PLSTATE_INIT)) {
+			if (deflateParams(&sp->stream,
+			    sp->quality, Z_DEFAULT_STRATEGY) != Z_OK) {
+				TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
+					sp->stream.msg);
+				return (0);
+			}
+		}
+		return (1);
+     case TIFFTAG_PIXARLOGDATAFMT:
+	sp->user_datafmt = (int) va_arg(ap, int);
+	/* Tweak the TIFF header so that the rest of libtiff knows what
+	 * size of data will be passed between app and library, and
+	 * assume that the app knows what it is doing and is not
+	 * confused by these header manipulations...
+	 */
+	switch (sp->user_datafmt) {
+	 case PIXARLOGDATAFMT_8BIT:
+	 case PIXARLOGDATAFMT_8BITABGR:
+	    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+	    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+	    break;
+	 case PIXARLOGDATAFMT_11BITLOG:
+	    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
+	    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+	    break;
+	 case PIXARLOGDATAFMT_12BITPICIO:
+	    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
+	    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
+	    break;
+	 case PIXARLOGDATAFMT_16BIT:
+	    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
+	    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+	    break;
+	 case PIXARLOGDATAFMT_FLOAT:
+	    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
+	    TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
+	    break;
+	}
+	/*
+	 * Must recalculate sizes should bits/sample change.
+	 */
+	tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tmsize_t)(-1);
+	tif->tif_scanlinesize = TIFFScanlineSize(tif);
+	result = 1;		/* NB: pseudo tag */
+	break;
+     default:
+	result = (*sp->vsetparent)(tif, tag, ap);
+    }
+    return (result);
+}
+
+static int
+PixarLogVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+    PixarLogState *sp = (PixarLogState *)tif->tif_data;
+
+    switch (tag) {
+     case TIFFTAG_PIXARLOGQUALITY:
+	*va_arg(ap, int*) = sp->quality;
+	break;
+     case TIFFTAG_PIXARLOGDATAFMT:
+	*va_arg(ap, int*) = sp->user_datafmt;
+	break;
+     default:
+	return (*sp->vgetparent)(tif, tag, ap);
+    }
+    return (1);
+}
+
+static const TIFFField pixarlogFields[] = {
+    {TIFFTAG_PIXARLOGDATAFMT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL},
+    {TIFFTAG_PIXARLOGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL}
+};
+
+int
+TIFFInitPixarLog(TIFF* tif, int scheme)
+{
+	static const char module[] = "TIFFInitPixarLog";
+
+	PixarLogState* sp;
+
+	assert(scheme == COMPRESSION_PIXARLOG);
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, pixarlogFields,
+			      TIFFArrayCount(pixarlogFields))) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Merging PixarLog codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*) _TIFFmalloc(sizeof (PixarLogState));
+	if (tif->tif_data == NULL)
+		goto bad;
+	sp = (PixarLogState*) tif->tif_data;
+	_TIFFmemset(sp, 0, sizeof (*sp));
+	sp->stream.data_type = Z_BINARY;
+	sp->user_datafmt = PIXARLOGDATAFMT_UNKNOWN;
+
+	/*
+	 * Install codec methods.
+	 */
+	tif->tif_fixuptags = PixarLogFixupTags; 
+	tif->tif_setupdecode = PixarLogSetupDecode;
+	tif->tif_predecode = PixarLogPreDecode;
+	tif->tif_decoderow = PixarLogDecode;
+	tif->tif_decodestrip = PixarLogDecode;  
+	tif->tif_decodetile = PixarLogDecode;
+	tif->tif_setupencode = PixarLogSetupEncode;
+	tif->tif_preencode = PixarLogPreEncode;
+	tif->tif_postencode = PixarLogPostEncode;
+	tif->tif_encoderow = PixarLogEncode;  
+	tif->tif_encodestrip = PixarLogEncode;
+	tif->tif_encodetile = PixarLogEncode;  
+	tif->tif_close = PixarLogClose;
+	tif->tif_cleanup = PixarLogCleanup;
+
+	/* Override SetField so we can handle our private pseudo-tag */
+	sp->vgetparent = tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield = PixarLogVGetField;   /* hook for codec tags */
+	sp->vsetparent = tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield = PixarLogVSetField;   /* hook for codec tags */
+
+	/* Default values for codec-specific fields */
+	sp->quality = Z_DEFAULT_COMPRESSION; /* default comp. level */
+	sp->state = 0;
+
+	/* we don't wish to use the predictor, 
+	 * the default is none, which predictor value 1
+	 */
+	(void) TIFFPredictorInit(tif);
+
+	/*
+	 * build the companding tables 
+	 */
+	PixarLogMakeTables(sp);
+
+	return (1);
+bad:
+	TIFFErrorExt(tif->tif_clientdata, module,
+		     "No space for PixarLog state block");
+	return (0);
+}
+#endif /* PIXARLOG_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_predict.c b/third_party/libtiff/tif_predict.c
new file mode 100644
index 0000000..1388dde
--- /dev/null
+++ b/third_party/libtiff/tif_predict.c
@@ -0,0 +1,794 @@
+/* $Id: tif_predict.c,v 1.35 2015-08-31 15:05:57 erouault 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Predictor Tag Support (used by multiple codecs).
+ */
+#include "tiffiop.h"
+#include "tif_predict.h"
+
+#define	PredictorState(tif)	((TIFFPredictorState*) (tif)->tif_data)
+
+static void horAcc8(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void horAcc16(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void horAcc32(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void swabHorAcc16(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void swabHorAcc32(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void horDiff8(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void horDiff16(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void horDiff32(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void swabHorDiff16(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void swabHorDiff32(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void fpAcc(TIFF* tif, uint8* cp0, tmsize_t cc);
+static void fpDiff(TIFF* tif, uint8* cp0, tmsize_t cc);
+static int PredictorDecodeRow(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s);
+static int PredictorDecodeTile(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s);
+static int PredictorEncodeRow(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s);
+static int PredictorEncodeTile(TIFF* tif, uint8* bp0, tmsize_t cc0, uint16 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);
+	if (sp->rowsize == 0)
+		return 0;
+
+	return 1;
+}
+
+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;
+}
+
+static int
+PredictorSetupEncode(TIFF* tif)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+	TIFFDirectory* td = &tif->tif_dir;
+
+	if (!(*sp->setupencode)(tif) || !PredictorSetup(tif))
+		return 0;
+
+	if (sp->predictor == 2) {
+		switch (td->td_bitspersample) {
+			case 8:  sp->encodepfunc = horDiff8; break;
+			case 16: sp->encodepfunc = horDiff16; break;
+			case 32: sp->encodepfunc = horDiff32; break;
+		}
+		/*
+		 * Override default encoding method with one that does the
+		 * predictor stuff.
+		 */
+                if( tif->tif_encoderow != PredictorEncodeRow )
+                {
+                    sp->encoderow = tif->tif_encoderow;
+                    tif->tif_encoderow = PredictorEncodeRow;
+                    sp->encodestrip = tif->tif_encodestrip;
+                    tif->tif_encodestrip = PredictorEncodeTile;
+                    sp->encodetile = tif->tif_encodetile;
+                    tif->tif_encodetile = PredictorEncodeTile;
+                }
+
+                /*
+                 * If the data is horizontally differenced 16-bit data that
+                 * requires byte-swapping, then it must be byte swapped after
+                 * the differenciation step.  We do this with a special-purpose
+                 * routine and override the normal post decoding logic that
+                 * the library setup when the directory was read.
+                 */
+                if (tif->tif_flags & TIFF_SWAB) {
+                    if (sp->encodepfunc == horDiff16) {
+                            sp->encodepfunc = swabHorDiff16;
+                            tif->tif_postdecode = _TIFFNoPostDecode;
+                    } else if (sp->encodepfunc == horDiff32) {
+                            sp->encodepfunc = swabHorDiff32;
+                            tif->tif_postdecode = _TIFFNoPostDecode;
+                    }
+                }
+        }
+
+	else if (sp->predictor == 3) {
+		sp->encodepfunc = fpDiff;
+		/*
+		 * Override default encoding method with one that does the
+		 * predictor stuff.
+		 */
+                if( tif->tif_encoderow != PredictorEncodeRow )
+                {
+                    sp->encoderow = tif->tif_encoderow;
+                    tif->tif_encoderow = PredictorEncodeRow;
+                    sp->encodestrip = tif->tif_encodestrip;
+                    tif->tif_encodestrip = PredictorEncodeTile;
+                    sp->encodetile = tif->tif_encodetile;
+                    tif->tif_encodetile = PredictorEncodeTile;
+                }
+	}
+
+	return 1;
+}
+
+#define REPEAT4(n, op)		\
+    switch (n) {		\
+    default: { tmsize_t i; for (i = n-4; i > 0; i--) { op; } } \
+    case 4:  op;		\
+    case 3:  op;		\
+    case 2:  op;		\
+    case 1:  op;		\
+    case 0:  ;			\
+    }
+
+/* Remarks related to C standard compliance in all below functions : */
+/* - to avoid any undefined behaviour, we only operate on unsigned types */
+/*   since the behaviour 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) */
+
+static void
+horAcc8(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+
+	unsigned char* cp = (unsigned char*) cp0;
+	assert((cc%stride)==0);
+	if (cc > stride) {
+		/*
+		 * Pipeline the most common cases.
+		 */
+		if (stride == 3)  {
+			unsigned int cr = cp[0];
+			unsigned int cg = cp[1];
+			unsigned int cb = cp[2];
+			cc -= 3;
+			cp += 3;
+			while (cc>0) {
+				cp[0] = (unsigned char) ((cr += cp[0]) & 0xff);
+				cp[1] = (unsigned char) ((cg += cp[1]) & 0xff);
+				cp[2] = (unsigned char) ((cb += cp[2]) & 0xff);
+				cc -= 3;
+				cp += 3;
+			}
+		} else if (stride == 4)  {
+			unsigned int cr = cp[0];
+			unsigned int cg = cp[1];
+			unsigned int cb = cp[2];
+			unsigned int ca = cp[3];
+			cc -= 4;
+			cp += 4;
+			while (cc>0) {
+				cp[0] = (unsigned char) ((cr += cp[0]) & 0xff);
+				cp[1] = (unsigned char) ((cg += cp[1]) & 0xff);
+				cp[2] = (unsigned char) ((cb += cp[2]) & 0xff);
+				cp[3] = (unsigned char) ((ca += cp[3]) & 0xff);
+				cc -= 4;
+				cp += 4;
+			}
+		} else  {
+			cc -= stride;
+			do {
+				REPEAT4(stride, cp[stride] =
+					(unsigned char) ((cp[stride] + *cp) & 0xff); cp++)
+				cc -= stride;
+			} while (cc>0);
+		}
+	}
+}
+
+static void
+swabHorAcc16(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	uint16* wp = (uint16*) cp0;
+	tmsize_t wc = cc / 2;
+
+        TIFFSwabArrayOfShort(wp, wc);
+        horAcc16(tif, cp0, cc);
+}
+
+static void
+horAcc16(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+	uint16* wp = (uint16*) cp0;
+	tmsize_t wc = cc / 2;
+
+	assert((cc%(2*stride))==0);
+
+	if (wc > stride) {
+		wc -= stride;
+		do {
+			REPEAT4(stride, wp[stride] = (uint16)(((unsigned int)wp[stride] + (unsigned int)wp[0]) & 0xffff); wp++)
+			wc -= stride;
+		} while (wc > 0);
+	}
+}
+
+static void
+swabHorAcc32(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	uint32* wp = (uint32*) cp0;
+	tmsize_t wc = cc / 4;
+
+        TIFFSwabArrayOfLong(wp, wc);
+	horAcc32(tif, cp0, cc);
+}
+
+static void
+horAcc32(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+	uint32* wp = (uint32*) cp0;
+	tmsize_t wc = cc / 4;
+
+	assert((cc%(4*stride))==0);
+
+	if (wc > stride) {
+		wc -= stride;
+		do {
+			REPEAT4(stride, wp[stride] += wp[0]; wp++)
+			wc -= stride;
+		} while (wc > 0);
+	}
+}
+
+/*
+ * Floating point predictor accumulation routine.
+ */
+static void
+fpAcc(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+	uint32 bps = tif->tif_dir.td_bitspersample / 8;
+	tmsize_t wc = cc / bps;
+	tmsize_t count = cc;
+	uint8 *cp = (uint8 *) cp0;
+	uint8 *tmp = (uint8 *)_TIFFmalloc(cc);
+
+	assert((cc%(bps*stride))==0);
+
+	if (!tmp)
+		return;
+
+	while (count > stride) {
+		REPEAT4(stride, cp[stride] =
+                        (unsigned char) ((cp[stride] + cp[0]) & 0xff); cp++)
+		count -= stride;
+	}
+
+	_TIFFmemcpy(tmp, cp0, cc);
+	cp = (uint8 *) cp0;
+	for (count = 0; count < wc; count++) {
+		uint32 byte;
+		for (byte = 0; byte < bps; byte++) {
+			#if WORDS_BIGENDIAN
+			cp[bps * count + byte] = tmp[byte * wc + count];
+			#else
+			cp[bps * count + byte] =
+				tmp[(bps - byte - 1) * wc + count];
+			#endif
+		}
+	}
+	_TIFFfree(tmp);
+}
+
+/*
+ * Decode a scanline and apply the predictor routine.
+ */
+static int
+PredictorDecodeRow(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 s)
+{
+	TIFFPredictorState *sp = PredictorState(tif);
+
+	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;
+}
+
+/*
+ * Decode a tile/strip and apply the predictor routine.
+ * Note that horizontal differencing must be done on a
+ * row-by-row basis.  The width of a "row" has already
+ * been calculated at pre-decode time according to the
+ * strip/tile dimensions.
+ */
+static int
+PredictorDecodeTile(TIFF* tif, uint8* op0, tmsize_t occ0, uint16 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);
+		assert((occ0%rowsize)==0);
+		assert(sp->decodepfunc != NULL);
+		while (occ0 > 0) {
+			(*sp->decodepfunc)(tif, op0, rowsize);
+			occ0 -= rowsize;
+			op0 += rowsize;
+		}
+		return 1;
+	} else
+		return 0;
+}
+
+static void
+horDiff8(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+	tmsize_t stride = sp->stride;
+	unsigned char* cp = (unsigned char*) cp0;
+
+	assert((cc%stride)==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);
+		}
+	}
+}
+
+static void
+horDiff16(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+	tmsize_t stride = sp->stride;
+	uint16 *wp = (uint16*) cp0;
+	tmsize_t wc = cc/2;
+
+	assert((cc%(2*stride))==0);
+
+	if (wc > stride) {
+		wc -= stride;
+		wp += wc - 1;
+		do {
+			REPEAT4(stride, wp[stride] = (uint16)(((unsigned int)wp[stride] - (unsigned int)wp[0]) & 0xffff); wp--)
+			wc -= stride;
+		} while (wc > 0);
+	}
+}
+
+static void
+swabHorDiff16(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+    uint16* wp = (uint16*) cp0;
+    tmsize_t wc = cc / 2;
+
+    horDiff16(tif, cp0, cc);
+
+    TIFFSwabArrayOfShort(wp, wc);
+}
+
+static void
+horDiff32(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+	tmsize_t stride = sp->stride;
+	uint32 *wp = (uint32*) cp0;
+	tmsize_t wc = cc/4;
+
+	assert((cc%(4*stride))==0);
+
+	if (wc > stride) {
+		wc -= stride;
+		wp += wc - 1;
+		do {
+			REPEAT4(stride, wp[stride] -= wp[0]; wp--)
+			wc -= stride;
+		} while (wc > 0);
+	}
+}
+
+static void
+swabHorDiff32(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+    uint32* wp = (uint32*) cp0;
+    tmsize_t wc = cc / 4;
+
+    horDiff32(tif, cp0, cc);
+
+    TIFFSwabArrayOfLong(wp, wc);
+}
+
+/*
+ * Floating point predictor differencing routine.
+ */
+static void
+fpDiff(TIFF* tif, uint8* cp0, tmsize_t cc)
+{
+	tmsize_t stride = PredictorState(tif)->stride;
+	uint32 bps = tif->tif_dir.td_bitspersample / 8;
+	tmsize_t wc = cc / bps;
+	tmsize_t count;
+	uint8 *cp = (uint8 *) cp0;
+	uint8 *tmp = (uint8 *)_TIFFmalloc(cc);
+
+	assert((cc%(bps*stride))==0);
+
+	if (!tmp)
+		return;
+
+	_TIFFmemcpy(tmp, cp0, cc);
+	for (count = 0; count < wc; count++) {
+		uint32 byte;
+		for (byte = 0; byte < bps; byte++) {
+			#if WORDS_BIGENDIAN
+			cp[byte * wc + count] = tmp[bps * count + byte];
+			#else
+			cp[(bps - byte - 1) * wc + count] =
+				tmp[bps * count + byte];
+			#endif
+		}
+	}
+	_TIFFfree(tmp);
+
+	cp = (uint8 *) cp0;
+	cp += cc - stride - 1;
+	for (count = cc; count > stride; count -= stride)
+		REPEAT4(stride, cp[stride] = (unsigned char)((cp[stride] - cp[0])&0xff); cp--)
+}
+
+static int
+PredictorEncodeRow(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	TIFFPredictorState *sp = PredictorState(tif);
+
+	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);
+}
+
+static int
+PredictorEncodeTile(TIFF* tif, uint8* bp0, tmsize_t cc0, uint16 s)
+{
+	static const char module[] = "PredictorEncodeTile";
+	TIFFPredictorState *sp = PredictorState(tif);
+        uint8 *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*) _TIFFmalloc(cc0);
+        if( working_copy == NULL )
+        {
+            TIFFErrorExt(tif->tif_clientdata, module, 
+                         "Out of memory allocating " TIFF_SSIZE_FORMAT " 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;
+}
+
+#define	FIELD_PREDICTOR	(FIELD_CODEC+0)		/* XXX */
+
+static const TIFFField predictFields[] = {
+    { TIFFTAG_PREDICTOR, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UINT16, FIELD_PREDICTOR, FALSE, FALSE, "Predictor", NULL },
+};
+
+static int
+PredictorVSetField(TIFF* tif, uint32 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, uint16_vap);
+		TIFFSetFieldBit(tif, FIELD_PREDICTOR);
+		break;
+	default:
+		return (*sp->vsetparent)(tif, tag, ap);
+	}
+	tif->tif_flags |= TIFF_DIRTYDIRECT;
+	return 1;
+}
+
+static int
+PredictorVGetField(TIFF* tif, uint32 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;
+}
+
+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);
+}
+
+int
+TIFFPredictorInit(TIFF* tif)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+
+	assert(sp != 0);
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, predictFields,
+			      TIFFArrayCount(predictFields))) {
+		TIFFErrorExt(tif->tif_clientdata, "TIFFPredictorInit",
+		    "Merging Predictor codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Override parent get/set field methods.
+	 */
+	sp->vgetparent = tif->tif_tagmethods.vgetfield;
+	tif->tif_tagmethods.vgetfield =
+            PredictorVGetField;/* hook for predictor tag */
+	sp->vsetparent = tif->tif_tagmethods.vsetfield;
+	tif->tif_tagmethods.vsetfield =
+	    PredictorVSetField;/* hook for predictor tag */
+	sp->printdir = tif->tif_tagmethods.printdir;
+	tif->tif_tagmethods.printdir =
+            PredictorPrintDir;	/* hook for predictor tag */
+
+	sp->setupdecode = tif->tif_setupdecode;
+	tif->tif_setupdecode = PredictorSetupDecode;
+	sp->setupencode = tif->tif_setupencode;
+	tif->tif_setupencode = PredictorSetupEncode;
+
+	sp->predictor = 1;			/* default value */
+	sp->encodepfunc = NULL;			/* no predictor routine */
+	sp->decodepfunc = NULL;			/* no predictor routine */
+	return 1;
+}
+
+int
+TIFFPredictorCleanup(TIFF* tif)
+{
+	TIFFPredictorState* sp = PredictorState(tif);
+
+	assert(sp != 0);
+
+	tif->tif_tagmethods.vgetfield = sp->vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->vsetparent;
+	tif->tif_tagmethods.printdir = sp->printdir;
+	tif->tif_setupdecode = sp->setupdecode;
+	tif->tif_setupencode = sp->setupencode;
+
+	return 1;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_predict.h b/third_party/libtiff/tif_predict.h
new file mode 100644
index 0000000..dc7144c
--- /dev/null
+++ b/third_party/libtiff/tif_predict.h
@@ -0,0 +1,77 @@
+/* $Id: tif_predict.h,v 1.8 2010-03-10 18:56:49 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
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFPREDICT_
+#define	_TIFFPREDICT_
+/*
+ * ``Library-private'' Support for the Predictor Tag
+ */
+
+/*
+ * Codecs that want to support the Predictor tag must place
+ * this structure first in their private state block so that
+ * the predictor code can cast tif_data to find its state.
+ */
+typedef struct {
+	int             predictor;	/* predictor tag value */
+	tmsize_t        stride;		/* sample stride over data */
+	tmsize_t        rowsize;	/* tile/strip row size */
+
+	TIFFCodeMethod  encoderow;	/* parent codec encode/decode row */
+	TIFFCodeMethod  encodestrip;	/* parent codec encode/decode strip */
+	TIFFCodeMethod  encodetile;	/* parent codec encode/decode tile */ 
+	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 */
+
+	TIFFVGetMethod  vgetparent;	/* super-class method */
+	TIFFVSetMethod  vsetparent;	/* super-class method */
+	TIFFPrintMethod printdir;	/* super-class method */
+	TIFFBoolMethod  setupdecode;	/* super-class method */
+	TIFFBoolMethod  setupencode;	/* super-class method */
+} TIFFPredictorState;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+extern int TIFFPredictorInit(TIFF*);
+extern int TIFFPredictorCleanup(TIFF*);
+#if defined(__cplusplus)
+}
+#endif
+#endif /* _TIFFPREDICT_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_print.c b/third_party/libtiff/tif_print.c
new file mode 100644
index 0000000..7b1a422
--- /dev/null
+++ b/third_party/libtiff/tif_print.c
@@ -0,0 +1,716 @@
+/* $Id: tif_print.c,v 1.62 2015-08-19 02:31:04 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Printing Support
+ */
+#include "tiffiop.h"
+#include <stdio.h>
+
+#include <ctype.h>
+
+static void
+_TIFFprintAsciiBounded(FILE* fd, const char* cp, size_t max_chars);
+
+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 */
+    "7 (0x7)",
+    "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]))
+
+static const char *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 */
+};
+#define	NORIENTNAMES	(sizeof (orientNames) / sizeof (orientNames[0]))
+
+static void
+_TIFFPrintField(FILE* fd, const TIFFField *fip,
+		uint32 value_count, void *raw_data)
+{
+	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_IFD)
+			fprintf(fd, "0x%lx",
+				(unsigned long)((uint32 *) 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_LONG8)
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			fprintf(fd, "%I64u",
+			    (unsigned __int64)((uint64 *) raw_data)[j]);
+#else
+			fprintf(fd, "%llu",
+			    (unsigned long long)((uint64 *) raw_data)[j]);
+#endif
+		else if(fip->field_type == TIFF_SLONG8)
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			fprintf(fd, "%I64d", (__int64)((int64 *) raw_data)[j]);
+#else
+			fprintf(fd, "%lld", (long long)((int64 *) raw_data)[j]);
+#endif
+		else if(fip->field_type == TIFF_IFD8)
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			fprintf(fd, "0x%I64x",
+				(unsigned __int64)((uint64 *) raw_data)[j]);
+#else
+			fprintf(fd, "0x%llx",
+				(unsigned long long)((uint64 *) raw_data)[j]);
+#endif
+		else if(fip->field_type == TIFF_FLOAT)
+			fprintf(fd, "%f", ((float *)raw_data)[j]);
+		else if(fip->field_type == TIFF_DOUBLE)
+			fprintf(fd, "%f", ((double *) raw_data)[j]);
+		else if(fip->field_type == TIFF_ASCII) {
+			fprintf(fd, "%s", (char *) raw_data);
+			break;
+		}
+		else {
+			fprintf(fd, "<unsupported data type in TIFFPrint>");
+			break;
+		}
+
+		if(j < value_count - 1)
+			fprintf(fd, ",");
+	}
+
+	fprintf(fd, "\n");
+}
+
+static int
+_TIFFPrettyPrintField(TIFF* tif, const TIFFField *fip, FILE* fd, uint32 tag,
+		      uint32 value_count, void *raw_data)
+{
+        (void) tif;
+
+	/* do not try to pretty print auto-defined fields */
+	if (strncmp(fip->field_name,"Tag ", 4) == 0) {
+		return 0;
+	}
+        
+	switch (tag)
+	{
+		case TIFFTAG_INKSET:
+			if (value_count == 2 && fip->field_type == TIFF_SHORT) {
+				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;
+			}
+			return 0;
+
+		case TIFFTAG_DOTRANGE:
+			if (value_count == 2 && fip->field_type == TIFF_SHORT) {
+				fprintf(fd, "  Dot Range: %u-%u\n",
+					((uint16*)raw_data)[0], ((uint16*)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 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: <present>, %lu bytes\n",
+			    (unsigned long) value_count * 4);
+			return 1;
+
+		case TIFFTAG_PHOTOSHOP:
+			fprintf(fd, "  Photoshop Data: <present>, %lu bytes\n",
+			    (unsigned long) value_count);
+			return 1;
+
+		case TIFFTAG_ICCPROFILE:
+			fprintf(fd, "  ICC Profile: <present>, %lu bytes\n",
+			    (unsigned long) value_count);
+			return 1;
+
+		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)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	char *sep;
+	uint16 i;
+	long l, n;
+
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+	fprintf(fd, "TIFF Directory at offset 0x%I64x (%I64u)\n",
+		(unsigned __int64) tif->tif_diroff,
+		(unsigned __int64) tif->tif_diroff);
+#else
+	fprintf(fd, "TIFF Directory at offset 0x%llx (%llu)\n",
+		(unsigned long long) tif->tif_diroff,
+		(unsigned long long) tif->tif_diroff);
+#endif
+	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 < 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 = ", ";
+		}
+                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))
+        {
+		fprintf(fd, "  YCbCr Subsampling: %u, %u\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, "%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)) {
+		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 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, "%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->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_REFBLACKWHITE)) {
+		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++) {
+				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++)
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			fprintf(fd, " %5I64u",
+				(unsigned __int64) td->td_subifd[i]);
+#else
+			fprintf(fd, " %5llu",
+				(unsigned long long) td->td_subifd[i]);
+#endif
+		fputc('\n', fd);
+	}
+
+	/*
+	** Custom tag support.
+	*/
+	{
+		int  i;
+		short count;
+
+		count = (short) TIFFGetTagListCount(tif);
+		for(i = 0; i < count; i++) {
+			uint32 tag = TIFFGetTagListEntry(tif, i);
+			const TIFFField *fip;
+			uint32 value_count;
+			int mem_alloc = 0;
+			void *raw_data;
+
+			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 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 */
+					static uint16 dotrange[2];
+					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 {
+					raw_data = _TIFFmalloc(
+					    _TIFFDataSize(fip->field_type)
+					    * value_count);
+					mem_alloc = 1;
+					if(TIFFGetField(tif, tag, raw_data) != 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, fip, fd, tag, value_count, raw_data))
+				_TIFFPrintField(fd, fip, value_count, raw_data);
+
+			if(mem_alloc)
+				_TIFFfree(raw_data);
+		}
+	}
+        
+	if (tif->tif_tagmethods.printdir)
+		(*tif->tif_tagmethods.printdir)(tif, fd, flags);
+
+        _TIFFFillStriles( tif );
+        
+	if ((flags & TIFFPRINT_STRIPS) &&
+	    TIFFFieldSet(tif,FIELD_STRIPOFFSETS)) {
+		uint32 s;
+
+		fprintf(fd, "  %lu %s:\n",
+		    (long) td->td_nstrips,
+		    isTiled(tif) ? "Tiles" : "Strips");
+		for (s = 0; s < td->td_nstrips; s++)
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			fprintf(fd, "    %3lu: [%8I64u, %8I64u]\n",
+			    (unsigned long) s,
+			    (unsigned __int64) td->td_stripoffset[s],
+			    (unsigned __int64) td->td_stripbytecount[s]);
+#else
+			fprintf(fd, "    %3lu: [%8llu, %8llu]\n",
+			    (unsigned long) s,
+			    (unsigned long long) td->td_stripoffset[s],
+			    (unsigned long long) td->td_stripbytecount[s]);
+#endif
+	}
+}
+
+void
+_TIFFprintAscii(FILE* fd, const char* cp)
+{
+	_TIFFprintAsciiBounded( fd, cp, strlen(cp));
+}
+
+static void
+_TIFFprintAsciiBounded(FILE* fd, const char* cp, size_t max_chars)
+{
+	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);
+	}
+}
+
+void
+_TIFFprintAsciiTag(FILE* fd, const char* name, const char* value)
+{
+	fprintf(fd, "  %s: \"", name);
+	_TIFFprintAscii(fd, value);
+	fprintf(fd, "\"\n");
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_read.c b/third_party/libtiff/tif_read.c
new file mode 100644
index 0000000..5cb419b
--- /dev/null
+++ b/third_party/libtiff/tif_read.c
@@ -0,0 +1,1094 @@
+/* $Id: tif_read.c,v 1.45 2015-06-07 22:35:40 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ * Scanline-oriented Read Support
+ */
+#include "tiffiop.h"
+#include <stdio.h>
+
+int TIFFFillStrip(TIFF* tif, uint32 strip);
+int TIFFFillTile(TIFF* tif, uint32 tile);
+static int TIFFStartStrip(TIFF* tif, uint32 strip);
+static int TIFFStartTile(TIFF* tif, uint32 tile);
+static int TIFFCheckRead(TIFF*, int);
+static tmsize_t
+TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size,const char* module);
+
+#define NOSTRIP ((uint32)(-1))       /* undefined state */
+#define NOTILE ((uint32)(-1))         /* undefined state */
+
+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 read_offset;
+        tmsize_t cc, to_read;
+        /* tmsize_t bytecountm; */
+        
+        if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+            return 0;
+        
+        /*
+         * 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) td->td_stripbytecount[strip]; */
+        if (read_ahead*2 > tif->tif_rawdatasize) {
+                assert( restart );
+                
+                tif->tif_curstrip = NOSTRIP;
+                if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
+                        TIFFErrorExt(tif->tif_clientdata, module,
+                                     "Data buffer too small to hold part of strip %lu",
+                                     (unsigned long) strip);
+                        return (0);
+                }
+                if (!TIFFReadBufferSetup(tif, 0, read_ahead*2))
+                        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 = td->td_stripoffset[strip]
+                + tif->tif_rawdataoff + tif->tif_rawdataloaded;
+
+        if (!SeekOK(tif, read_offset)) {
+                TIFFErrorExt(tif->tif_clientdata, module,
+                             "Seek error at scanline %lu, strip %lu",
+                             (unsigned long) tif->tif_row, (unsigned long) strip);
+                return 0;
+        }
+
+        /*
+        ** How much do we want to read?
+        */
+        to_read = tif->tif_rawdatasize - unused_data;
+        if( (uint64) to_read > td->td_stripbytecount[strip] 
+            - tif->tif_rawdataoff - tif->tif_rawdataloaded )
+        {
+                to_read = (tmsize_t) td->td_stripbytecount[strip]
+                        - tif->tif_rawdataoff - tif->tif_rawdataloaded;
+        }
+
+	assert((tif->tif_flags&TIFF_BUFFERMMAP)==0);
+        cc = TIFFReadFile(tif, tif->tif_rawdata + unused_data, to_read);
+
+        if (cc != to_read) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+                TIFFErrorExt(tif->tif_clientdata, module,
+                             "Read error at scanline %lu; got %I64u bytes, expected %I64u",
+                             (unsigned long) tif->tif_row,
+                             (unsigned __int64) cc,
+                             (unsigned __int64) to_read);
+#else
+                TIFFErrorExt(tif->tif_clientdata, module,
+                             "Read error at scanline %lu; got %llu bytes, expected %llu",
+                             (unsigned long) tif->tif_row,
+                             (unsigned long long) cc,
+                             (unsigned long long) to_read);
+#endif
+                return 0;
+        }
+        
+        tif->tif_rawdataoff = tif->tif_rawdataoff + tif->tif_rawdataloaded - unused_data ;
+        tif->tif_rawdataloaded = unused_data + to_read;
+
+        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 )
+                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, uint16 sample )
+{
+	register TIFFDirectory *td = &tif->tif_dir;
+	uint32 strip;
+        int    whole_strip;
+	tmsize_t read_ahead = 0;
+
+        /*
+        ** Establish what strip we are working from.
+        */
+	if (row >= td->td_imagelength) {	/* out of range */
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		    "%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 = (uint32)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)
+        if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+            return 0;
+        whole_strip = tif->tif_dir.td_stripbytecount[strip] < 10
+                || isMapped(tif);
+#else
+        whole_strip = 1;
+#endif
+        
+        if( !whole_strip )
+        {
+                read_ahead = tif->tif_scanlinesize * 16 + 5000;
+        }
+
+        /*
+         * 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) tif->tif_rawdataoff+tif->tif_rawdataloaded < td->td_stripbytecount[strip] )
+                {
+                        if( !TIFFFillStripPartial(tif,strip,read_ahead,0) )
+                                return 0;
+                }
+        }
+
+        if (row < tif->tif_row) {
+		/*
+		 * Moving backwards within the same strip: backup
+		 * to the start and then decode forward (below).
+		 *
+		 * NB: If you're planning on lots of random access within a
+		 * strip, it's better to just read and decode the entire
+		 * strip, and then access the decoded data in a random fashion.
+		 */
+
+                if( tif->tif_rawdataoff != 0 )
+                {
+                        if( !TIFFFillStripPartial(tif,strip,read_ahead,1) )
+                                return 0;
+                }
+                else
+                {
+                        if (!TIFFStartStrip(tif, strip))
+                                return (0);
+                }
+	}
+        
+	if (row != tif->tif_row) {
+		/*
+		 * Seek forward to the desired row.
+		 */
+
+                /* TODO: Will this really work with partial buffers? */
+                
+		if (!(*tif->tif_seek)(tif, row - tif->tif_row))
+			return (0);
+		tif->tif_row = row;
+	}
+
+	return (1);
+}
+
+int
+TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample)
+{
+	int e;
+
+	if (!TIFFCheckRead(tif, 0))
+		return (-1);
+	if( (e = TIFFSeek(tif, row, sample)) != 0) {
+		/*
+		 * Decompress desired row into user buffer.
+		 */
+		e = (*tif->tif_decoderow)
+		    (tif, (uint8*) 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*) buf,
+			    tif->tif_scanlinesize);  
+	}
+	return (e > 0 ? 1 : -1);
+}
+
+/*
+ * Read a strip of data and decompress the specified
+ * amount into the user-supplied buffer.
+ */
+tmsize_t
+TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
+{
+	static const char module[] = "TIFFReadEncodedStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 rowsperstrip;
+	uint32 stripsperplane;
+	uint32 stripinplane;
+	uint16 plane;
+	uint32 rows;
+	tmsize_t stripsize;
+	if (!TIFFCheckRead(tif,0))
+		return((tmsize_t)(-1));
+	if (strip>=td->td_nstrips)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,
+		    "%lu: Strip out of range, max %lu",(unsigned long)strip,
+		    (unsigned long)td->td_nstrips);
+		return((tmsize_t)(-1));
+	}
+	/*
+	 * Calculate the strip size according to the number of
+	 * rows in the strip (check for truncated last strip on any
+	 * of the separations).
+	 */
+	rowsperstrip=td->td_rowsperstrip;
+	if (rowsperstrip>td->td_imagelength)
+		rowsperstrip=td->td_imagelength;
+	stripsperplane=((td->td_imagelength+rowsperstrip-1)/rowsperstrip);
+	stripinplane=(strip%stripsperplane);
+	plane=(strip/stripsperplane);
+	rows=td->td_imagelength-stripinplane*rowsperstrip;
+	if (rows>rowsperstrip)
+		rows=rowsperstrip;
+	stripsize=TIFFVStripSize(tif,rows);
+	if (stripsize==0)
+		return((tmsize_t)(-1));
+	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 tmsize_t
+TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size,
+    const char* module)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ))
+        return ((tmsize_t)(-1));
+        
+	assert((tif->tif_flags&TIFF_NOREADRAW)==0);
+	if (!isMapped(tif)) {
+		tmsize_t cc;
+
+		if (!SeekOK(tif, td->td_stripoffset[strip])) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Seek error at scanline %lu, strip %lu",
+			    (unsigned long) tif->tif_row, (unsigned long) strip);
+			return ((tmsize_t)(-1));
+		}
+		cc = TIFFReadFile(tif, buf, size);
+		if (cc != size) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+		"Read error at scanline %lu; got %I64u bytes, expected %I64u",
+				     (unsigned long) tif->tif_row,
+				     (unsigned __int64) cc,
+				     (unsigned __int64) size);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+		"Read error at scanline %lu; got %llu bytes, expected %llu",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long long) cc,
+				     (unsigned long long) size);
+#endif
+			return ((tmsize_t)(-1));
+		}
+	} else {
+		tmsize_t ma,mb;
+		tmsize_t n;
+		ma=(tmsize_t)td->td_stripoffset[strip];
+		mb=ma+size;
+		if (((uint64)ma!=td->td_stripoffset[strip])||(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) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+	"Read error at scanline %lu, strip %lu; got %I64u bytes, expected %I64u",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) strip,
+				     (unsigned __int64) n,
+				     (unsigned __int64) size);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+	"Read error at scanline %lu, strip %lu; got %llu bytes, expected %llu",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) strip,
+				     (unsigned long long) n,
+				     (unsigned long long) size);
+#endif
+			return ((tmsize_t)(-1));
+		}
+		_TIFFmemcpy(buf, tif->tif_base + ma,
+			    size);
+	}
+	return (size);
+}
+
+/*
+ * Read a strip of data from the file.
+ */
+tmsize_t
+TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
+{
+	static const char module[] = "TIFFReadRawStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 bytecount;
+	tmsize_t bytecountm;
+
+	if (!TIFFCheckRead(tif, 0))
+		return ((tmsize_t)(-1));
+	if (strip >= td->td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		     "%lu: Strip out of range, max %lu",
+		     (unsigned long) strip,
+		     (unsigned long) td->td_nstrips);
+		return ((tmsize_t)(-1));
+	}
+	if (tif->tif_flags&TIFF_NOREADRAW)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Compression scheme does not support access to raw uncompressed data");
+		return ((tmsize_t)(-1));
+	}
+	bytecount = td->td_stripbytecount[strip];
+	if ((int64)bytecount <= 0) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%I64u: Invalid strip byte count, strip %lu",
+			     (unsigned __int64) bytecount,
+			     (unsigned long) strip);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%llu: Invalid strip byte count, strip %lu",
+			     (unsigned long long) bytecount,
+			     (unsigned long) strip);
+#endif
+		return ((tmsize_t)(-1));
+	}
+	bytecountm = (tmsize_t)bytecount;
+	if ((uint64)bytecountm!=bytecount) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Integer overflow");
+		return ((tmsize_t)(-1));
+	}
+	if (size != (tmsize_t)(-1) && size < bytecountm)
+		bytecountm = size;
+	return (TIFFReadRawStrip1(tif, strip, buf, bytecountm, module));
+}
+
+/*
+ * Read the specified strip and setup for decoding. The data buffer is
+ * expanded, as necessary, to hold the strip's data.
+ */
+int
+TIFFFillStrip(TIFF* tif, uint32 strip)
+{
+	static const char module[] = "TIFFFillStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+        return 0;
+        
+	if ((tif->tif_flags&TIFF_NOREADRAW)==0)
+	{
+		uint64 bytecount = td->td_stripbytecount[strip];
+		if ((int64)bytecount <= 0) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"Invalid strip byte count %I64u, strip %lu",
+				     (unsigned __int64) bytecount,
+				     (unsigned long) strip);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"Invalid strip byte count %llu, strip %lu",
+				     (unsigned long long) bytecount,
+				     (unsigned long) strip);
+#endif
+			return (0);
+		}
+		if (isMapped(tif) &&
+		    (isFillOrder(tif, td->td_fillorder)
+		    || (tif->tif_flags & TIFF_NOBITREV))) {
+			/*
+			 * The image is mapped into memory and we either don't
+			 * need to flip bits or the compression routine is
+			 * going to handle this operation itself.  In this
+			 * case, avoid copying the raw data and instead just
+			 * reference the data from the memory mapped file
+			 * image.  This assumes that the decompression
+			 * routines do not modify the contents of the raw data
+			 * buffer (if they try to, the application will get a
+			 * fault since the file is mapped read-only).
+			 */
+			if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) {
+				_TIFFfree(tif->tif_rawdata);
+				tif->tif_rawdata = NULL;
+				tif->tif_rawdatasize = 0;
+			}
+			tif->tif_flags &= ~TIFF_MYBUFFER;
+			/*
+			 * 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 > (uint64)tif->tif_size ||
+			    td->td_stripoffset[strip] > (uint64)tif->tif_size - bytecount) {
+				/*
+				 * This error message might seem strange, but
+				 * it's what would happen if a read were done
+				 * instead.
+				 */
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+				TIFFErrorExt(tif->tif_clientdata, module,
+
+					"Read error on strip %lu; "
+					"got %I64u bytes, expected %I64u",
+					(unsigned long) strip,
+					(unsigned __int64) tif->tif_size - td->td_stripoffset[strip],
+					(unsigned __int64) bytecount);
+#else
+				TIFFErrorExt(tif->tif_clientdata, module,
+
+					"Read error on strip %lu; "
+					"got %llu bytes, expected %llu",
+					(unsigned long) strip,
+					(unsigned long long) tif->tif_size - td->td_stripoffset[strip],
+					(unsigned long long) bytecount);
+#endif
+				tif->tif_curstrip = NOSTRIP;
+				return (0);
+			}
+			tif->tif_rawdatasize = (tmsize_t)bytecount;
+			tif->tif_rawdata = tif->tif_base + (tmsize_t)td->td_stripoffset[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)bytecountm!=bytecount)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+				return(0);
+			}
+			if (bytecountm > tif->tif_rawdatasize) {
+				tif->tif_curstrip = NOSTRIP;
+				if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					    "Data buffer too small to hold strip %lu",
+					    (unsigned long) strip);
+					return (0);
+				}
+				if (!TIFFReadBufferSetup(tif, 0, bytecountm))
+					return (0);
+			}
+			if (tif->tif_flags&TIFF_BUFFERMMAP) {
+				tif->tif_curstrip = NOSTRIP;
+				if (!TIFFReadBufferSetup(tif, 0, bytecountm))
+					return (0);
+			}
+			if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata,
+				bytecountm, module) != bytecountm)
+				return (0);
+
+                        tif->tif_rawdataoff = 0;
+                        tif->tif_rawdataloaded = bytecountm;
+                        
+			if (!isFillOrder(tif, td->td_fillorder) &&
+			    (tif->tif_flags & TIFF_NOBITREV) == 0)
+				TIFFReverseBits(tif->tif_rawdata, bytecountm);
+                }
+	}
+	return (TIFFStartStrip(tif, strip));
+}
+
+/*
+ * Tile-oriented Read Support
+ * Contributed by Nancy Cam (Silicon Graphics).
+ */
+
+/*
+ * Read and decompress a tile of data.  The
+ * tile is selected by the (x,y,z,s) coordinates.
+ */
+tmsize_t
+TIFFReadTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s)
+{
+	if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s))
+		return ((tmsize_t)(-1));
+	return (TIFFReadEncodedTile(tif,
+	    TIFFComputeTile(tif, x, y, z, s), buf, (tmsize_t)(-1)));
+}
+
+/*
+ * Read a tile of data and decompress the specified
+ * amount into the user-supplied buffer.
+ */
+tmsize_t
+TIFFReadEncodedTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size)
+{
+	static const char module[] = "TIFFReadEncodedTile";
+	TIFFDirectory *td = &tif->tif_dir;
+	tmsize_t tilesize = tif->tif_tilesize;
+
+	if (!TIFFCheckRead(tif, 1))
+		return ((tmsize_t)(-1));
+	if (tile >= td->td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "%lu: Tile out of range, max %lu",
+		    (unsigned long) tile, (unsigned long) td->td_nstrips);
+		return ((tmsize_t)(-1));
+	}
+	if (size == (tmsize_t)(-1))
+		size = tilesize;
+	else if (size > tilesize)
+		size = tilesize;
+	if (TIFFFillTile(tif, tile) && (*tif->tif_decodetile)(tif,
+	    (uint8*) buf, size, (uint16)(tile/td->td_stripsperimage))) {
+		(*tif->tif_postdecode)(tif, (uint8*) buf, size);
+		return (size);
+	} else
+		return ((tmsize_t)(-1));
+}
+
+static tmsize_t
+TIFFReadRawTile1(TIFF* tif, uint32 tile, void* buf, tmsize_t size, const char* module)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ))
+        return ((tmsize_t)(-1));
+
+	assert((tif->tif_flags&TIFF_NOREADRAW)==0);
+	if (!isMapped(tif)) {
+		tmsize_t cc;
+
+		if (!SeekOK(tif, td->td_stripoffset[tile])) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Seek error at row %lu, col %lu, tile %lu",
+			    (unsigned long) tif->tif_row,
+			    (unsigned long) tif->tif_col,
+			    (unsigned long) tile);
+			return ((tmsize_t)(-1));
+		}
+		cc = TIFFReadFile(tif, buf, size);
+		if (cc != size) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+	"Read error at row %lu, col %lu; got %I64u bytes, expected %I64u",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) tif->tif_col,
+				     (unsigned __int64) cc,
+				     (unsigned __int64) size);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+	"Read error at row %lu, col %lu; got %llu bytes, expected %llu",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) tif->tif_col,
+				     (unsigned long long) cc,
+				     (unsigned long long) size);
+#endif
+			return ((tmsize_t)(-1));
+		}
+	} else {
+		tmsize_t ma,mb;
+		tmsize_t n;
+		ma=(tmsize_t)td->td_stripoffset[tile];
+		mb=ma+size;
+		if (((uint64)ma!=td->td_stripoffset[tile])||(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) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+"Read error at row %lu, col %lu, tile %lu; got %I64u bytes, expected %I64u",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) tif->tif_col,
+				     (unsigned long) tile,
+				     (unsigned __int64) n,
+				     (unsigned __int64) size);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+"Read error at row %lu, col %lu, tile %lu; got %llu bytes, expected %llu",
+				     (unsigned long) tif->tif_row,
+				     (unsigned long) tif->tif_col,
+				     (unsigned long) tile,
+				     (unsigned long long) n,
+				     (unsigned long long) size);
+#endif
+			return ((tmsize_t)(-1));
+		}
+		_TIFFmemcpy(buf, tif->tif_base + ma, size);
+	}
+	return (size);
+}
+
+/*
+ * Read a tile of data from the file.
+ */
+tmsize_t
+TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size)
+{
+	static const char module[] = "TIFFReadRawTile";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 bytecount64;
+	tmsize_t bytecountm;
+
+	if (!TIFFCheckRead(tif, 1))
+		return ((tmsize_t)(-1));
+	if (tile >= td->td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "%lu: Tile out of range, max %lu",
+		    (unsigned long) tile, (unsigned long) td->td_nstrips);
+		return ((tmsize_t)(-1));
+	}
+	if (tif->tif_flags&TIFF_NOREADRAW)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module,
+		"Compression scheme does not support access to raw uncompressed data");
+		return ((tmsize_t)(-1));
+	}
+	bytecount64 = td->td_stripbytecount[tile];
+	if (size != (tmsize_t)(-1) && (uint64)size < bytecount64)
+		bytecount64 = (uint64)size;
+	bytecountm = (tmsize_t)bytecount64;
+	if ((uint64)bytecountm!=bytecount64)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		return ((tmsize_t)(-1));
+	}
+	return (TIFFReadRawTile1(tif, tile, buf, bytecountm, module));
+}
+
+/*
+ * Read the specified tile and setup for decoding. The data buffer is
+ * expanded, as necessary, to hold the tile's data.
+ */
+int
+TIFFFillTile(TIFF* tif, uint32 tile)
+{
+	static const char module[] = "TIFFFillTile";
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+        return 0;
+        
+	if ((tif->tif_flags&TIFF_NOREADRAW)==0)
+	{
+		uint64 bytecount = td->td_stripbytecount[tile];
+		if ((int64)bytecount <= 0) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"%I64u: Invalid tile byte count, tile %lu",
+				     (unsigned __int64) bytecount,
+				     (unsigned long) tile);
+#else
+			TIFFErrorExt(tif->tif_clientdata, module,
+				"%llu: Invalid tile byte count, tile %lu",
+				     (unsigned long long) bytecount,
+				     (unsigned long) tile);
+#endif
+			return (0);
+		}
+		if (isMapped(tif) &&
+		    (isFillOrder(tif, td->td_fillorder)
+		     || (tif->tif_flags & TIFF_NOBITREV))) {
+			/*
+			 * The image is mapped into memory and we either don't
+			 * need to flip bits or the compression routine is
+			 * going to handle this operation itself.  In this
+			 * case, avoid copying the raw data and instead just
+			 * reference the data from the memory mapped file
+			 * image.  This assumes that the decompression
+			 * routines do not modify the contents of the raw data
+			 * buffer (if they try to, the application will get a
+			 * fault since the file is mapped read-only).
+			 */
+			if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) {
+				_TIFFfree(tif->tif_rawdata);
+				tif->tif_rawdata = NULL;
+				tif->tif_rawdatasize = 0;
+			}
+			tif->tif_flags &= ~TIFF_MYBUFFER;
+			/*
+			 * 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 > (uint64)tif->tif_size ||
+			    td->td_stripoffset[tile] > (uint64)tif->tif_size - bytecount) {
+				tif->tif_curtile = NOTILE;
+				return (0);
+			}
+			tif->tif_rawdatasize = (tmsize_t)bytecount;
+			tif->tif_rawdata =
+				tif->tif_base + (tmsize_t)td->td_stripoffset[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)bytecountm!=bytecount)
+			{
+				TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+				return(0);
+			}
+			if (bytecountm > tif->tif_rawdatasize) {
+				tif->tif_curtile = NOTILE;
+				if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
+					TIFFErrorExt(tif->tif_clientdata, module,
+					    "Data buffer too small to hold tile %lu",
+					    (unsigned long) tile);
+					return (0);
+				}
+				if (!TIFFReadBufferSetup(tif, 0, bytecountm))
+					return (0);
+			}
+			if (tif->tif_flags&TIFF_BUFFERMMAP) {
+				tif->tif_curtile = NOTILE;
+				if (!TIFFReadBufferSetup(tif, 0, bytecountm))
+					return (0);
+			}
+
+			if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata,
+			    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,
+                                                tif->tif_rawdataloaded);
+		}
+	}
+	return (TIFFStartTile(tif, tile));
+}
+
+/*
+ * Setup the raw data buffer in preparation for
+ * reading a strip of raw data.  If the buffer
+ * is specified as zero, then a buffer of appropriate
+ * size is allocated by the library.  Otherwise,
+ * the client must guarantee that the buffer is
+ * large enough to hold any individual strip of
+ * raw data.
+ */
+int
+TIFFReadBufferSetup(TIFF* tif, void* bp, tmsize_t size)
+{
+	static const char module[] = "TIFFReadBufferSetup";
+
+	assert((tif->tif_flags&TIFF_NOREADRAW)==0);
+	tif->tif_flags &= ~TIFF_BUFFERMMAP;
+
+	if (tif->tif_rawdata) {
+		if (tif->tif_flags & TIFF_MYBUFFER)
+			_TIFFfree(tif->tif_rawdata);
+		tif->tif_rawdata = NULL;
+		tif->tif_rawdatasize = 0;
+	}
+	if (bp) {
+		tif->tif_rawdatasize = size;
+		tif->tif_rawdata = (uint8*) bp;
+		tif->tif_flags &= ~TIFF_MYBUFFER;
+	} else {
+		tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64((uint64)size, 1024);
+		if (tif->tif_rawdatasize==0) {
+		    TIFFErrorExt(tif->tif_clientdata, module,
+				 "Invalid buffer size");
+		    return (0);
+		}
+		tif->tif_rawdata = (uint8*) _TIFFmalloc(tif->tif_rawdatasize);
+		tif->tif_flags |= TIFF_MYBUFFER;
+	}
+	if (tif->tif_rawdata == NULL) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "No space for data buffer at scanline %lu",
+		    (unsigned long) tif->tif_row);
+		tif->tif_rawdatasize = 0;
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * Set state to appear as if a
+ * strip has just been read in.
+ */
+static int
+TIFFStartStrip(TIFF* tif, uint32 strip)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+    if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+        return 0;
+
+	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;
+		tif->tif_rawcc = (tmsize_t)td->td_stripbytecount[strip];
+	}
+	return ((*tif->tif_predecode)(tif,
+			(uint16)(strip / td->td_stripsperimage)));
+}
+
+/*
+ * Set state to appear as if a
+ * tile has just been read in.
+ */
+static int
+TIFFStartTile(TIFF* tif, uint32 tile)
+{
+        static const char module[] = "TIFFStartTile";
+	TIFFDirectory *td = &tif->tif_dir;
+        uint32 howmany32;
+
+        if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount)
+                return 0;
+
+	if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+		if (!(*tif->tif_setupdecode)(tif))
+			return (0);
+		tif->tif_flags |= TIFF_CODERSETUP;
+	}
+	tif->tif_curtile = tile;
+        howmany32=TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth);
+        if (howmany32 == 0) {
+                 TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles");
+                return 0;
+        }
+	tif->tif_row = (tile % howmany32) * td->td_tilelength;
+        howmany32=TIFFhowmany_32(td->td_imagelength, td->td_tilelength);
+        if (howmany32 == 0) {
+                TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles");
+                return 0;
+        }
+	tif->tif_col = (tile % howmany32) * td->td_tilewidth;
+        tif->tif_flags &= ~TIFF_BUF4WRITE;
+	if (tif->tif_flags&TIFF_NOREADRAW)
+	{
+		tif->tif_rawcp = NULL;
+		tif->tif_rawcc = 0;
+	}
+	else
+	{
+		tif->tif_rawcp = tif->tif_rawdata;
+		tif->tif_rawcc = (tmsize_t)td->td_stripbytecount[tile];
+	}
+	return ((*tif->tif_predecode)(tif,
+			(uint16)(tile/td->td_stripsperimage)));
+}
+
+static int
+TIFFCheckRead(TIFF* tif, int tiles)
+{
+	if (tif->tif_mode == O_WRONLY) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "File not open for reading");
+		return (0);
+	}
+	if (tiles ^ isTiled(tif)) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, tiles ?
+		    "Can not read tiles from a stripped image" :
+		    "Can not read scanlines from a tiled image");
+		return (0);
+	}
+	return (1);
+}
+
+void
+_TIFFNoPostDecode(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+    (void) tif; (void) buf; (void) cc;
+}
+
+void
+_TIFFSwab16BitData(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+    (void) tif;
+    assert((cc & 1) == 0);
+    TIFFSwabArrayOfShort((uint16*) buf, cc/2);
+}
+
+void
+_TIFFSwab24BitData(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+    (void) tif;
+    assert((cc % 3) == 0);
+    TIFFSwabArrayOfTriples((uint8*) buf, cc/3);
+}
+
+void
+_TIFFSwab32BitData(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+    (void) tif;
+    assert((cc & 3) == 0);
+    TIFFSwabArrayOfLong((uint32*) buf, cc/4);
+}
+
+void
+_TIFFSwab64BitData(TIFF* tif, uint8* buf, tmsize_t cc)
+{
+    (void) tif;
+    assert((cc & 7) == 0);
+    TIFFSwabArrayOfDouble((double*) buf, cc/8);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_strip.c b/third_party/libtiff/tif_strip.c
new file mode 100644
index 0000000..6cac71d
--- /dev/null
+++ b/third_party/libtiff/tif_strip.c
@@ -0,0 +1,389 @@
+/* $Id: tif_strip.c,v 1.36 2015-06-07 22:35:40 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Strip-organized Image Support Routines.
+ */
+#include "tiffiop.h"
+
+/*
+ * Compute which strip a (row,sample) value is in.
+ */
+uint32
+TIFFComputeStrip(TIFF* tif, uint32 row, uint16 sample)
+{
+	static const char module[] = "TIFFComputeStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 strip;
+
+	strip = row / td->td_rowsperstrip;
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+		if (sample >= td->td_samplesperpixel) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "%lu: Sample out of range, max %lu",
+			    (unsigned long) sample, (unsigned long) td->td_samplesperpixel);
+			return (0);
+		}
+		strip += (uint32)sample*td->td_stripsperimage;
+	}
+	return (strip);
+}
+
+/*
+ * Compute how many strips are in an image.
+ */
+uint32
+TIFFNumberOfStrips(TIFF* tif)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 nstrips;
+
+	nstrips = (td->td_rowsperstrip == (uint32) -1 ? 1 :
+	     TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip));
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+		nstrips = _TIFFMultiply32(tif, nstrips, (uint32)td->td_samplesperpixel,
+		    "TIFFNumberOfStrips");
+	return (nstrips);
+}
+
+/*
+ * Compute the # bytes in a variable height, row-aligned strip.
+ */
+uint64
+TIFFVStripSize64(TIFF* tif, uint32 nrows)
+{
+	static const char module[] = "TIFFVStripSize64";
+	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];
+		uint16 samplingblock_samples;
+		uint32 samplingblocks_hor;
+		uint32 samplingblocks_ver;
+		uint64 samplingrow_samples;
+		uint64 samplingrow_size;
+		if(td->td_samplesperpixel!=3)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,
+			    "Invalid td_samplesperpixel value");
+			return 0;
+		}
+		TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,ycbcrsubsampling+0,
+		    ycbcrsubsampling+1);
+		if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4)
+		    ||(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && ycbcrsubsampling[1] != 4))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,
+				     "Invalid YCbCr subsampling (%dx%d)", 
+				     ycbcrsubsampling[0], 
+				     ycbcrsubsampling[1] );
+			return 0;
+		}
+		samplingblock_samples=ycbcrsubsampling[0]*ycbcrsubsampling[1]+2;
+		samplingblocks_hor=TIFFhowmany_32(td->td_imagewidth,ycbcrsubsampling[0]);
+		samplingblocks_ver=TIFFhowmany_32(nrows,ycbcrsubsampling[1]);
+		samplingrow_samples=_TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module);
+		samplingrow_size=TIFFhowmany8_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module));
+		return(_TIFFMultiply64(tif,samplingrow_size,samplingblocks_ver,module));
+	}
+	else
+		return(_TIFFMultiply64(tif,nrows,TIFFScanlineSize64(tif),module));
+}
+tmsize_t
+TIFFVStripSize(TIFF* tif, uint32 nrows)
+{
+	static const char module[] = "TIFFVStripSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFVStripSize64(tif,nrows);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Compute the # bytes in a raw strip.
+ */
+uint64
+TIFFRawStripSize64(TIFF* tif, uint32 strip)
+{
+	static const char module[] = "TIFFRawStripSize64";
+	TIFFDirectory* td = &tif->tif_dir;
+	uint64 bytecount = td->td_stripbytecount[strip];
+
+	if (bytecount == 0)
+	{
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%I64u: Invalid strip byte count, strip %lu",
+			     (unsigned __int64) bytecount,
+			     (unsigned long) strip);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%llu: Invalid strip byte count, strip %lu",
+			     (unsigned long long) bytecount,
+			     (unsigned long) strip);
+#endif
+		bytecount = (uint64) -1;
+	}
+
+	return bytecount;
+}
+tmsize_t
+TIFFRawStripSize(TIFF* tif, uint32 strip)
+{
+	static const char module[] = "TIFFRawStripSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFRawStripSize64(tif,strip);
+	if (m==(uint64)(-1))
+		n=(tmsize_t)(-1);
+	else
+	{
+		n=(tmsize_t)m;
+		if ((uint64)n!=m)
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+			n=0;
+		}
+	}
+	return(n);
+}
+
+/*
+ * Compute the # bytes in a (row-aligned) strip.
+ *
+ * Note that if RowsPerStrip is larger than the
+ * recorded ImageLength, then the strip size is
+ * truncated to reflect the actual space required
+ * to hold the strip.
+ */
+uint64
+TIFFStripSize64(TIFF* tif)
+{
+	TIFFDirectory* td = &tif->tif_dir;
+	uint32 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 m;
+	tmsize_t n;
+	m=TIFFStripSize64(tif);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Compute a default strip size based on the image
+ * characteristics and a requested value.  If the
+ * request is <1 then we choose a strip size according
+ * to certain heuristics.
+ */
+uint32
+TIFFDefaultStripSize(TIFF* tif, uint32 request)
+{
+	return (*tif->tif_defstripsize)(tif, request);
+}
+
+uint32
+_TIFFDefaultStripSize(TIFF* tif, uint32 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.
+		 */
+		uint64 scanlinesize;
+		uint64 rows;
+		scanlinesize=TIFFScanlineSize64(tif);
+		if (scanlinesize==0)
+			scanlinesize=1;
+		rows=(uint64)STRIP_SIZE_DEFAULT/scanlinesize;
+		if (rows==0)
+			rows=1;
+		else if (rows>0xFFFFFFFF)
+			rows=0xFFFFFFFF;
+		s=(uint32)rows;
+	}
+	return (s);
+}
+
+/*
+ * Return the number of bytes to read/write in a call to
+ * one of the scanline-oriented i/o routines.  Note that
+ * this number may be 1/samples-per-pixel if data is
+ * stored as separate planes.
+ * The ScanlineSize in case of YCbCrSubsampling is defined as the
+ * strip size divided by the strip height, i.e. the size of a pack of vertical
+ * subsampling lines divided by vertical subsampling. It should thus make
+ * sense when multiplied by a multiple of vertical subsampling.
+ */
+uint64
+TIFFScanlineSize64(TIFF* tif)
+{
+	static const char module[] = "TIFFScanlineSize64";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 scanline_size;
+	if (td->td_planarconfig==PLANARCONFIG_CONTIG)
+	{
+		if ((td->td_photometric==PHOTOMETRIC_YCBCR)&&
+		    (td->td_samplesperpixel==3)&&
+		    (!isUpSampled(tif)))
+		{
+			uint16 ycbcrsubsampling[2];
+			uint16 samplingblock_samples;
+			uint32 samplingblocks_hor;
+			uint64 samplingrow_samples;
+			uint64 samplingrow_size;
+			if(td->td_samplesperpixel!=3)
+			{
+                            TIFFErrorExt(tif->tif_clientdata,module,
+                                         "Invalid td_samplesperpixel value");
+                            return 0;
+			}
+			TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,
+                                              ycbcrsubsampling+0,
+                                              ycbcrsubsampling+1);
+			if (((ycbcrsubsampling[0]!=1)&&(ycbcrsubsampling[0]!=2)&&(ycbcrsubsampling[0]!=4)) ||
+			    ((ycbcrsubsampling[1]!=1)&&(ycbcrsubsampling[1]!=2)&&(ycbcrsubsampling[1]!=4)))
+			{
+                            TIFFErrorExt(tif->tif_clientdata,module,
+                                         "Invalid YCbCr subsampling");
+                            return 0;
+			}
+			samplingblock_samples = ycbcrsubsampling[0]*ycbcrsubsampling[1]+2;
+			samplingblocks_hor = TIFFhowmany_32(td->td_imagewidth,ycbcrsubsampling[0]);
+			samplingrow_samples = _TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module);
+			samplingrow_size = TIFFhowmany_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module),8);
+			scanline_size = (samplingrow_size/ycbcrsubsampling[1]);
+		}
+		else
+		{
+			uint64 scanline_samples;
+			scanline_samples=_TIFFMultiply64(tif,td->td_imagewidth,td->td_samplesperpixel,module);
+			scanline_size=TIFFhowmany_64(_TIFFMultiply64(tif,scanline_samples,td->td_bitspersample,module),8);
+		}
+	}
+	else
+        {
+		scanline_size=TIFFhowmany_64(_TIFFMultiply64(tif,td->td_imagewidth,td->td_bitspersample,module),8);
+        }
+        if (scanline_size == 0)
+        {
+                TIFFErrorExt(tif->tif_clientdata,module,"Computed scanline size is zero");
+                return 0;
+        }
+	return(scanline_size);
+}
+tmsize_t
+TIFFScanlineSize(TIFF* tif)
+{
+	static const char module[] = "TIFFScanlineSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFScanlineSize64(tif);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m) {
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer arithmetic overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Return the number of bytes required to store a complete
+ * decoded and packed raster scanline (as opposed to the
+ * I/O size returned by TIFFScanlineSize which may be less
+ * if data is store as separate planes).
+ */
+uint64
+TIFFRasterScanlineSize64(TIFF* tif)
+{
+	static const char module[] = "TIFFRasterScanlineSize64";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 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 m;
+	tmsize_t n;
+	m=TIFFRasterScanlineSize64(tif);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer arithmetic overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_swab.c b/third_party/libtiff/tif_swab.c
new file mode 100644
index 0000000..f37e33f
--- /dev/null
+++ b/third_party/libtiff/tif_swab.c
@@ -0,0 +1,310 @@
+/* $Id: tif_swab.c,v 1.13 2010-03-10 18:56:49 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library Bit & Byte Swapping Support.
+ *
+ * XXX We assume short = 16-bits and long = 32-bits XXX
+ */
+#include "tiffiop.h"
+
+#ifndef TIFFSwabShort
+void
+TIFFSwabShort(uint16* wp)
+{
+	register unsigned char* cp = (unsigned char*) wp;
+	unsigned char t;
+	assert(sizeof(uint16)==2);
+	t = cp[1]; cp[1] = cp[0]; cp[0] = t;
+}
+#endif
+
+#ifndef TIFFSwabLong
+void
+TIFFSwabLong(uint32* lp)
+{
+	register unsigned char* cp = (unsigned char*) lp;
+	unsigned char t;
+	assert(sizeof(uint32)==4);
+	t = cp[3]; cp[3] = cp[0]; cp[0] = t;
+	t = cp[2]; cp[2] = cp[1]; cp[1] = t;
+}
+#endif
+
+#ifndef TIFFSwabLong8
+void
+TIFFSwabLong8(uint64* lp)
+{
+	register unsigned char* cp = (unsigned char*) lp;
+	unsigned char t;
+	assert(sizeof(uint64)==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 TIFFSwabArrayOfShort
+void
+TIFFSwabArrayOfShort(register uint16* wp, tmsize_t n)
+{
+	register unsigned char* cp;
+	register unsigned char t;
+	assert(sizeof(uint16)==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 TIFFSwabArrayOfTriples
+void
+TIFFSwabArrayOfTriples(register uint8* tp, tmsize_t n)
+{
+	unsigned char* cp;
+	unsigned char t;
+
+	/* XXX unroll loop some */
+	while (n-- > 0) {
+		cp = (unsigned char*) tp;
+		t = cp[2]; cp[2] = cp[0]; cp[0] = t;
+		tp += 3;
+	}
+}
+#endif
+
+#ifndef TIFFSwabArrayOfLong
+void
+TIFFSwabArrayOfLong(register uint32* lp, tmsize_t n)
+{
+	register unsigned char *cp;
+	register unsigned char t;
+	assert(sizeof(uint32)==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 TIFFSwabArrayOfLong8
+void
+TIFFSwabArrayOfLong8(register uint64* lp, tmsize_t n)
+{
+	register unsigned char *cp;
+	register unsigned char t;
+	assert(sizeof(uint64)==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 TIFFSwabFloat
+void
+TIFFSwabFloat(float* fp)
+{
+	register unsigned char* cp = (unsigned char*) fp;
+	unsigned char t;
+	assert(sizeof(float)==4);
+	t = cp[3]; cp[3] = cp[0]; cp[0] = t;
+	t = cp[2]; cp[2] = cp[1]; cp[1] = t;
+}
+#endif
+
+#ifndef 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
+
+#ifndef 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, tmsize_t n)
+{
+	register unsigned char *cp;
+	register unsigned char t;
+	assert(sizeof(double)==8);
+	/* XXX unroll loop some */
+	while (n-- > 0) {
+		cp = (unsigned char *)dp;
+		t = cp[7]; cp[7] = cp[0]; cp[0] = t;
+		t = cp[6]; cp[6] = cp[1]; cp[1] = t;
+		t = cp[5]; cp[5] = cp[2]; cp[2] = t;
+		t = cp[4]; cp[4] = cp[3]; cp[3] = t;
+		dp++;
+	}
+}
+#endif
+
+/*
+ * Bit reversal tables.  TIFFBitRevTable[<byte>] gives
+ * the bit reversed value of <byte>.  Used in various
+ * places in the library when the FillOrder requires
+ * bit reversal of byte values (e.g. CCITT Fax 3
+ * encoding/decoding).  TIFFNoBitRevTable is provided
+ * for algorithms that want an equivalent table that
+ * do not reverse bit values.
+ */
+static const unsigned char TIFFBitRevTable[256] = {
+    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+static const unsigned char TIFFNoBitRevTable[256] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 
+    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
+    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
+    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 
+    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 
+    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 
+    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 
+    0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 
+    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
+    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 
+    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
+    0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 
+    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 
+    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 
+    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 
+    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 
+    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 
+    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 
+    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 
+    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 
+    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 
+    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 
+};
+
+const unsigned char*
+TIFFGetBitRevTable(int reversed)
+{
+	return (reversed ? TIFFBitRevTable : TIFFNoBitRevTable);
+}
+
+void
+TIFFReverseBits(uint8* cp, tmsize_t n)  
+{
+	for (; n > 8; n -= 8) {
+		cp[0] = TIFFBitRevTable[cp[0]];
+		cp[1] = TIFFBitRevTable[cp[1]];
+		cp[2] = TIFFBitRevTable[cp[2]];
+		cp[3] = TIFFBitRevTable[cp[3]];
+		cp[4] = TIFFBitRevTable[cp[4]];
+		cp[5] = TIFFBitRevTable[cp[5]];
+		cp[6] = TIFFBitRevTable[cp[6]];
+		cp[7] = TIFFBitRevTable[cp[7]];
+		cp += 8;
+	}
+	while (n-- > 0)
+		*cp = TIFFBitRevTable[*cp], cp++;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_thunder.c b/third_party/libtiff/tif_thunder.c
new file mode 100644
index 0000000..390891c
--- /dev/null
+++ b/third_party/libtiff/tif_thunder.c
@@ -0,0 +1,207 @@
+/* $Id: tif_thunder.c,v 1.12 2011-04-02 20:54:09 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#include <assert.h>
+#ifdef THUNDER_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * ThunderScan 4-bit Compression Algorithm Support
+ */
+
+/*
+ * ThunderScan uses an encoding scheme designed for
+ * 4-bit pixel values.  Data is encoded in bytes, with
+ * each byte split into a 2-bit code word and a 6-bit
+ * data value.  The encoding gives raw data, runs of
+ * pixels, or pixel values encoded as a delta from the
+ * previous pixel value.  For the latter, either 2-bit
+ * or 3-bit delta values are used, with the deltas packed
+ * into a single byte.
+ */
+#define	THUNDER_DATA		0x3f	/* mask for 6-bit data */
+#define	THUNDER_CODE		0xc0	/* mask for 2-bit code word */
+/* code values */
+#define	THUNDER_RUN		0x00	/* run of pixels w/ encoded count */
+#define	THUNDER_2BITDELTAS	0x40	/* 3 pixels w/ encoded 2-bit deltas */
+#define	    DELTA2_SKIP		2	/* skip code for 2-bit deltas */
+#define	THUNDER_3BITDELTAS	0x80	/* 2 pixels w/ encoded 3-bit deltas */
+#define	    DELTA3_SKIP		4	/* skip code for 3-bit deltas */
+#define	THUNDER_RAW		0xc0	/* raw data encoded */
+
+static const int twobitdeltas[4] = { 0, 1, 0, -1 };
+static const int threebitdeltas[8] = { 0, 1, 2, 3, 0, -3, -2, -1 };
+
+#define	SETPIXEL(op, v) {                     \
+	lastpixel = (v) & 0xf;                \
+        if ( npixels < maxpixels )         \
+        {                                     \
+	  if (npixels++ & 1)                  \
+	    *op++ |= lastpixel;               \
+	  else                                \
+	    op[0] = (uint8) (lastpixel << 4); \
+        }                                     \
+}
+
+static int
+ThunderSetupDecode(TIFF* tif)
+{
+	static const char module[] = "ThunderSetupDecode";
+
+        if( tif->tif_dir.td_bitspersample != 4 )
+        {
+                TIFFErrorExt(tif->tif_clientdata, module,
+                             "Wrong bitspersample value (%d), Thunder decoder only supports 4bits per sample.",
+                             (int) tif->tif_dir.td_bitspersample );
+                return 0;
+        }
+        
+
+	return (1);
+}
+
+static int
+ThunderDecode(TIFF* tif, uint8* op, tmsize_t maxpixels)
+{
+	static const char module[] = "ThunderDecode";
+	register unsigned char *bp;
+	register tmsize_t cc;
+	unsigned int lastpixel;
+	tmsize_t npixels;
+
+	bp = (unsigned char *)tif->tif_rawcp;
+	cc = tif->tif_rawcc;
+	lastpixel = 0;
+	npixels = 0;
+	while (cc > 0 && npixels < maxpixels) {
+		int n, delta;
+
+		n = *bp++, cc--;
+		switch (n & THUNDER_CODE) {
+		case THUNDER_RUN:		/* pixel run */
+			/*
+			 * Replicate the last pixel n times,
+			 * where n is the lower-order 6 bits.
+			 */
+			if (npixels & 1) {
+				op[0] |= lastpixel;
+				lastpixel = *op++; npixels++; n--;
+			} else
+				lastpixel |= lastpixel << 4;
+			npixels += n;
+			if (npixels < maxpixels) {
+				for (; n > 0; n -= 2)
+					*op++ = (uint8) 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 = (uint8*) bp;
+	tif->tif_rawcc = cc;
+	if (npixels != maxpixels) {
+#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%s data at scanline %lu (%I64u != %I64u)",
+			     npixels < maxpixels ? "Not enough" : "Too much",
+			     (unsigned long) tif->tif_row,
+			     (unsigned __int64) npixels,
+			     (unsigned __int64) maxpixels);
+#else
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "%s data at scanline %lu (%llu != %llu)",
+			     npixels < maxpixels ? "Not enough" : "Too much",
+			     (unsigned long) tif->tif_row,
+			     (unsigned long long) npixels,
+			     (unsigned long long) maxpixels);
+#endif
+		return (0);
+	}
+
+        return (1);
+}
+
+static int
+ThunderDecodeRow(TIFF* tif, uint8* buf, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "ThunderDecodeRow";
+	uint8* row = buf;
+	
+	(void) s;
+	if (occ % tif->tif_scanlinesize)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Fractional scanlines cannot be read");
+		return (0);
+	}
+	while (occ > 0) {
+		if (!ThunderDecode(tif, row, tif->tif_dir.td_imagewidth))
+			return (0);
+		occ -= tif->tif_scanlinesize;
+		row += tif->tif_scanlinesize;
+	}
+	return (1);
+}
+
+int
+TIFFInitThunderScan(TIFF* tif, int scheme)
+{
+	(void) scheme;
+
+        tif->tif_setupdecode = ThunderSetupDecode;
+	tif->tif_decoderow = ThunderDecodeRow;
+	tif->tif_decodestrip = ThunderDecodeRow; 
+	return (1);
+}
+#endif /* THUNDER_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_tile.c b/third_party/libtiff/tif_tile.c
new file mode 100644
index 0000000..388e168
--- /dev/null
+++ b/third_party/libtiff/tif_tile.c
@@ -0,0 +1,322 @@
+/* $Id: tif_tile.c,v 1.24 2015-06-07 22:35:40 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Tiled Image Support Routines.
+ */
+#include "tiffiop.h"
+
+/*
+ * Compute which tile an (x,y,z,s) value is in.
+ */
+uint32
+TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 dx = td->td_tilewidth;
+	uint32 dy = td->td_tilelength;
+	uint32 dz = td->td_tiledepth;
+	uint32 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_32(td->td_imagewidth, dx);
+		uint32 ypt = TIFFhowmany_32(td->td_imagelength, dy);
+		uint32 zpt = TIFFhowmany_32(td->td_imagedepth, dz);
+
+		if (td->td_planarconfig == PLANARCONFIG_SEPARATE) 
+			tile = (xpt*ypt*zpt)*s +
+			     (xpt*ypt)*(z/dz) +
+			     xpt*(y/dy) +
+			     x/dx;
+		else
+			tile = (xpt*ypt)*(z/dz) + xpt*(y/dy) + x/dx;
+	}
+	return (tile);
+}
+
+/*
+ * Check an (x,y,z,s) coordinate
+ * against the image bounds.
+ */
+int
+TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+
+	if (x >= td->td_imagewidth) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%lu: Col out of range, max %lu",
+			     (unsigned long) x,
+			     (unsigned long) (td->td_imagewidth - 1));
+		return (0);
+	}
+	if (y >= td->td_imagelength) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%lu: Row out of range, max %lu",
+			     (unsigned long) y,
+			     (unsigned long) (td->td_imagelength - 1));
+		return (0);
+	}
+	if (z >= td->td_imagedepth) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%lu: Depth out of range, max %lu",
+			     (unsigned long) z,
+			     (unsigned long) (td->td_imagedepth - 1));
+		return (0);
+	}
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE &&
+	    s >= td->td_samplesperpixel) {
+		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			     "%lu: Sample out of range, max %lu",
+			     (unsigned long) s,
+			     (unsigned long) (td->td_samplesperpixel - 1));
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * Compute how many tiles are in an image.
+ */
+uint32
+TIFFNumberOfTiles(TIFF* tif)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	uint32 dx = td->td_tilewidth;
+	uint32 dy = td->td_tilelength;
+	uint32 dz = td->td_tiledepth;
+	uint32 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 :
+	    _TIFFMultiply32(tif, _TIFFMultiply32(tif, TIFFhowmany_32(td->td_imagewidth, dx),
+	    TIFFhowmany_32(td->td_imagelength, dy),
+	    "TIFFNumberOfTiles"),
+	    TIFFhowmany_32(td->td_imagedepth, dz), "TIFFNumberOfTiles");
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+		ntiles = _TIFFMultiply32(tif, ntiles, td->td_samplesperpixel,
+		    "TIFFNumberOfTiles");
+	return (ntiles);
+}
+
+/*
+ * Compute the # bytes in each row of a tile.
+ */
+uint64
+TIFFTileRowSize64(TIFF* tif)
+{
+        static const char module[] = "TIFFTileRowSize64";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 rowsize;
+	uint64 tilerowsize;
+
+	if (td->td_tilelength == 0)
+        {
+                TIFFErrorExt(tif->tif_clientdata,module,"Tile length is zero");
+                return 0;
+        }
+        if (td->td_tilewidth == 0)
+        {
+                TIFFErrorExt(tif->tif_clientdata,module,"Tile width is zero");
+		return (0);
+        }
+	rowsize = _TIFFMultiply64(tif, td->td_bitspersample, td->td_tilewidth,
+	    "TIFFTileRowSize");
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG)
+        {
+                if (td->td_samplesperpixel == 0)
+                {
+                        TIFFErrorExt(tif->tif_clientdata,module,"Samples per pixel is zero");
+                        return 0;
+                }
+		rowsize = _TIFFMultiply64(tif, rowsize, td->td_samplesperpixel,
+		    "TIFFTileRowSize");
+        }
+        tilerowsize=TIFFhowmany8_64(rowsize);
+        if (tilerowsize == 0)
+        {
+                TIFFErrorExt(tif->tif_clientdata,module,"Computed tile row size is zero");
+                return 0;
+        }
+	return (tilerowsize);
+}
+tmsize_t
+TIFFTileRowSize(TIFF* tif)
+{
+	static const char module[] = "TIFFTileRowSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFTileRowSize64(tif);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Compute the # bytes in a variable length, row-aligned tile.
+ */
+uint64
+TIFFVTileSize64(TIFF* tif, uint32 nrows)
+{
+	static const char module[] = "TIFFVTileSize64";
+	TIFFDirectory *td = &tif->tif_dir;
+	if (td->td_tilelength == 0 || td->td_tilewidth == 0 ||
+	    td->td_tiledepth == 0)
+		return (0);
+	if ((td->td_planarconfig==PLANARCONFIG_CONTIG)&&
+	    (td->td_photometric==PHOTOMETRIC_YCBCR)&&
+	    (td->td_samplesperpixel==3)&&
+	    (!isUpSampled(tif)))
+	{
+		/*
+		 * Packed YCbCr data contain one Cb+Cr for every
+		 * HorizontalSampling*VerticalSampling Y values.
+		 * Must also roundup width and height when calculating
+		 * since images that are not a multiple of the
+		 * horizontal/vertical subsampling area include
+		 * YCbCr data for the extended image.
+		 */
+		uint16 ycbcrsubsampling[2];
+		uint16 samplingblock_samples;
+		uint32 samplingblocks_hor;
+		uint32 samplingblocks_ver;
+		uint64 samplingrow_samples;
+		uint64 samplingrow_size;
+		TIFFGetFieldDefaulted(tif,TIFFTAG_YCBCRSUBSAMPLING,ycbcrsubsampling+0,
+		    ycbcrsubsampling+1);
+		if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4)
+		    ||(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && ycbcrsubsampling[1] != 4))
+		{
+			TIFFErrorExt(tif->tif_clientdata,module,
+				     "Invalid YCbCr subsampling (%dx%d)", 
+				     ycbcrsubsampling[0], 
+				     ycbcrsubsampling[1] );
+			return 0;
+		}
+		samplingblock_samples=ycbcrsubsampling[0]*ycbcrsubsampling[1]+2;
+		samplingblocks_hor=TIFFhowmany_32(td->td_tilewidth,ycbcrsubsampling[0]);
+		samplingblocks_ver=TIFFhowmany_32(nrows,ycbcrsubsampling[1]);
+		samplingrow_samples=_TIFFMultiply64(tif,samplingblocks_hor,samplingblock_samples,module);
+		samplingrow_size=TIFFhowmany8_64(_TIFFMultiply64(tif,samplingrow_samples,td->td_bitspersample,module));
+		return(_TIFFMultiply64(tif,samplingrow_size,samplingblocks_ver,module));
+	}
+	else
+		return(_TIFFMultiply64(tif,nrows,TIFFTileRowSize64(tif),module));
+}
+tmsize_t
+TIFFVTileSize(TIFF* tif, uint32 nrows)
+{
+	static const char module[] = "TIFFVTileSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFVTileSize64(tif,nrows);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Compute the # bytes in a row-aligned tile.
+ */
+uint64
+TIFFTileSize64(TIFF* tif)
+{
+	return (TIFFVTileSize64(tif, tif->tif_dir.td_tilelength));
+}
+tmsize_t
+TIFFTileSize(TIFF* tif)
+{
+	static const char module[] = "TIFFTileSize";
+	uint64 m;
+	tmsize_t n;
+	m=TIFFTileSize64(tif);
+	n=(tmsize_t)m;
+	if ((uint64)n!=m)
+	{
+		TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+		n=0;
+	}
+	return(n);
+}
+
+/*
+ * Compute a default tile size based on the image
+ * characteristics and a requested value.  If a
+ * request is <1 then we choose a size according
+ * to certain heuristics.
+ */
+void
+TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th)
+{
+	(*tif->tif_deftilesize)(tif, tw, th);
+}
+
+void
+_TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* 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_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/third_party/libtiff/tif_version.c b/third_party/libtiff/tif_version.c
new file mode 100644
index 0000000..f92c843
--- /dev/null
+++ b/third_party/libtiff/tif_version.c
@@ -0,0 +1,40 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_version.c,v 1.3 2010-03-10 18:56:49 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 
+ * 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"
+
+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:
+ */
diff --git a/third_party/libtiff/tif_warning.c b/third_party/libtiff/tif_warning.c
new file mode 100644
index 0000000..423b636
--- /dev/null
+++ b/third_party/libtiff/tif_warning.c
@@ -0,0 +1,81 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_warning.c,v 1.3 2010-03-10 18:56:49 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#include "tiffiop.h"
+
+TIFFErrorHandlerExt _TIFFwarningHandlerExt = NULL;
+
+TIFFErrorHandler
+TIFFSetWarningHandler(TIFFErrorHandler handler)
+{
+	TIFFErrorHandler prev = _TIFFwarningHandler;
+	_TIFFwarningHandler = handler;
+	return (prev);
+}
+
+TIFFErrorHandlerExt
+TIFFSetWarningHandlerExt(TIFFErrorHandlerExt handler)
+{
+	TIFFErrorHandlerExt prev = _TIFFwarningHandlerExt;
+	_TIFFwarningHandlerExt = handler;
+	return (prev);
+}
+
+void
+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);
+}
+
+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);
+}
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_write.c b/third_party/libtiff/tif_write.c
new file mode 100644
index 0000000..7996c31
--- /dev/null
+++ b/third_party/libtiff/tif_write.c
@@ -0,0 +1,793 @@
+/* $Id: tif_write.c,v 1.42 2015-06-07 23:00:23 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
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Scanline-oriented Write Support
+ */
+#include "tiffiop.h"
+#include <stdio.h>
+
+#define STRIPINCR	20		/* expansion factor on strip array */
+
+#define WRITECHECKSTRIPS(tif, module)				\
+	(((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),0,module))
+#define WRITECHECKTILES(tif, module)				\
+	(((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),1,module))
+#define BUFFERCHECK(tif)					\
+	((((tif)->tif_flags & TIFF_BUFFERSETUP) && tif->tif_rawdata) ||	\
+	    TIFFWriteBufferSetup((tif), NULL, (tmsize_t) -1))
+
+static int TIFFGrowStrips(TIFF* tif, uint32 delta, const char* module);
+static int TIFFAppendToStrip(TIFF* tif, uint32 strip, uint8* data, tmsize_t cc);
+
+int
+TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample)
+{
+	static const char module[] = "TIFFWriteScanline";
+	register TIFFDirectory *td;
+	int status, imagegrew = 0;
+	uint32 strip;
+
+	if (!WRITECHECKSTRIPS(tif, module))
+		return (-1);
+	/*
+	 * Handle delayed allocation of data buffer.  This
+	 * permits it to be sized more intelligently (using
+	 * directory information).
+	 */
+	if (!BUFFERCHECK(tif))
+		return (-1);
+        tif->tif_flags |= TIFF_BUF4WRITE; /* not strictly sure this is right*/
+
+	td = &tif->tif_dir;
+	/*
+	 * Extend image length if needed
+	 * (but only for PlanarConfig=1).
+	 */
+	if (row >= td->td_imagelength) {	/* extend image */
+		if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Can not change \"ImageLength\" when using separate planes");
+			return (-1);
+		}
+		td->td_imagelength = row+1;
+		imagegrew = 1;
+	}
+	/*
+	 * Calculate strip and check for crossings.
+	 */
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+		if (sample >= td->td_samplesperpixel) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "%lu: Sample out of range, max %lu",
+			    (unsigned long) sample, (unsigned long) td->td_samplesperpixel);
+			return (-1);
+		}
+		strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip;
+	} else
+		strip = row / td->td_rowsperstrip;
+	/*
+	 * Check strip array to make sure there's space. We don't support
+	 * dynamically growing files that have data organized in separate
+	 * bitplanes because it's too painful.  In that case we require that
+	 * the imagelength be set properly before the first write (so that the
+	 * strips array will be fully allocated above).
+	 */
+	if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module))
+		return (-1);
+	if (strip != tif->tif_curstrip) {
+		/*
+		 * Changing strips -- flush any data present.
+		 */
+		if (!TIFFFlushData(tif))
+			return (-1);
+		tif->tif_curstrip = strip;
+		/*
+		 * Watch out for a growing image.  The value of strips/image
+		 * will initially be 1 (since it can't be deduced until the
+		 * imagelength is known).
+		 */
+		if (strip >= td->td_stripsperimage && imagegrew)
+			td->td_stripsperimage =
+			    TIFFhowmany_32(td->td_imagelength,td->td_rowsperstrip);
+                if (td->td_stripsperimage == 0) {
+                        TIFFErrorExt(tif->tif_clientdata, module, "Zero strips per image");
+                        return (-1);
+                }
+		tif->tif_row =
+		    (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+		if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+			if (!(*tif->tif_setupencode)(tif))
+				return (-1);
+			tif->tif_flags |= TIFF_CODERSETUP;
+		}
+        
+		tif->tif_rawcc = 0;
+		tif->tif_rawcp = tif->tif_rawdata;
+
+		if( td->td_stripbytecount[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, (uint8*) buf, tif->tif_scanlinesize );
+
+	status = (*tif->tif_encoderow)(tif, (uint8*) buf,
+	    tif->tif_scanlinesize, sample);
+
+        /* we are now poised at the beginning of the next row */
+	tif->tif_row = row + 1;
+	return (status);
+}
+
+/*
+ * Encode the supplied data and write it to the
+ * specified strip.
+ *
+ * NB: Image length must be setup before writing.
+ */
+tmsize_t
+TIFFWriteEncodedStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc)
+{
+	static const char module[] = "TIFFWriteEncodedStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint16 sample;
+
+	if (!WRITECHECKSTRIPS(tif, module))
+		return ((tmsize_t) -1);
+	/*
+	 * Check strip array to make sure there's space.
+	 * We don't support dynamically growing files that
+	 * have data organized in separate bitplanes because
+	 * it's too painful.  In that case we require that
+	 * the imagelength be set properly before the first
+	 * write (so that the strips array will be fully
+	 * allocated above).
+	 */
+	if (strip >= td->td_nstrips) {
+		if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Can not grow image by strips when using separate planes");
+			return ((tmsize_t) -1);
+		}
+		if (!TIFFGrowStrips(tif, 1, module))
+			return ((tmsize_t) -1);
+		td->td_stripsperimage =
+		    TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip);  
+	}
+	/*
+	 * Handle delayed allocation of data buffer.  This
+	 * permits it to be sized according to the directory
+	 * info.
+	 */
+	if (!BUFFERCHECK(tif))
+		return ((tmsize_t) -1);
+
+        tif->tif_flags |= TIFF_BUF4WRITE;
+	tif->tif_curstrip = strip;
+
+        if (td->td_stripsperimage == 0) {
+                TIFFErrorExt(tif->tif_clientdata, module, "Zero strips per image");
+                return ((tmsize_t) -1);
+        }
+
+	tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+	if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+		if (!(*tif->tif_setupencode)(tif))
+			return ((tmsize_t) -1);
+		tif->tif_flags |= TIFF_CODERSETUP;
+	}
+
+	if( td->td_stripbytecount[strip] > 0 )
+        {
+            /* Make sure that at the first attempt of rewriting the tile, 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) */
+            if( tif->tif_rawdatasize <= (tmsize_t)td->td_stripbytecount[strip] )
+            {
+                if( !(TIFFWriteBufferSetup(tif, NULL,
+                    (tmsize_t)TIFFroundup_64((uint64)(td->td_stripbytecount[strip] + 1), 1024))) )
+                    return ((tmsize_t)(-1));
+            }
+
+	    /* Force TIFFAppendToStrip() to consider placing data at end
+               of file. */
+            tif->tif_curoff = 0;
+        }
+
+    tif->tif_rawcc = 0;
+    tif->tif_rawcp = tif->tif_rawdata;
+
+	tif->tif_flags &= ~TIFF_POSTENCODE;
+	sample = (uint16)(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*) data, cc );
+
+	if (!(*tif->tif_encodestrip)(tif, (uint8*) data, cc, sample))
+		return (0);
+	if (!(*tif->tif_postencode)(tif))
+		return ((tmsize_t) -1);
+	if (!isFillOrder(tif, td->td_fillorder) &&
+	    (tif->tif_flags & TIFF_NOBITREV) == 0)
+		TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc);
+	if (tif->tif_rawcc > 0 &&
+	    !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc))
+		return ((tmsize_t) -1);
+	tif->tif_rawcc = 0;
+	tif->tif_rawcp = tif->tif_rawdata;
+	return (cc);
+}
+
+/*
+ * Write the supplied data to the specified strip.
+ *
+ * NB: Image length must be setup before writing.
+ */
+tmsize_t
+TIFFWriteRawStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc)
+{
+	static const char module[] = "TIFFWriteRawStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+
+	if (!WRITECHECKSTRIPS(tif, module))
+		return ((tmsize_t) -1);
+	/*
+	 * Check strip array to make sure there's space.
+	 * We don't support dynamically growing files that
+	 * have data organized in separate bitplanes because
+	 * it's too painful.  In that case we require that
+	 * the imagelength be set properly before the first
+	 * write (so that the strips array will be fully
+	 * allocated above).
+	 */
+	if (strip >= td->td_nstrips) {
+		if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Can not grow image by strips when using separate planes");
+			return ((tmsize_t) -1);
+		}
+		/*
+		 * Watch out for a growing image.  The value of
+		 * strips/image will initially be 1 (since it
+		 * can't be deduced until the imagelength is known).
+		 */
+		if (strip >= td->td_stripsperimage)
+			td->td_stripsperimage =
+			    TIFFhowmany_32(td->td_imagelength,td->td_rowsperstrip);
+		if (!TIFFGrowStrips(tif, 1, module))
+			return ((tmsize_t) -1);
+	}
+	tif->tif_curstrip = strip;
+        if (td->td_stripsperimage == 0) {
+                TIFFErrorExt(tif->tif_clientdata, module,"Zero strips per image");
+                return ((tmsize_t) -1);
+        }
+	tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+	return (TIFFAppendToStrip(tif, strip, (uint8*) data, cc) ?
+	    cc : (tmsize_t) -1);
+}
+
+/*
+ * Write and compress a tile of data.  The
+ * tile is selected by the (x,y,z,s) coordinates.
+ */
+tmsize_t
+TIFFWriteTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s)
+{
+	if (!TIFFCheckTile(tif, x, y, z, s))
+		return ((tmsize_t)(-1));
+	/*
+	 * NB: A tile size of -1 is used instead of tif_tilesize knowing
+	 *     that TIFFWriteEncodedTile will clamp this to the tile size.
+	 *     This is done because the tile size may not be defined until
+	 *     after the output buffer is setup in TIFFWriteBufferSetup.
+	 */
+	return (TIFFWriteEncodedTile(tif,
+	    TIFFComputeTile(tif, x, y, z, s), buf, (tmsize_t)(-1)));
+}
+
+/*
+ * Encode the supplied data and write it to the
+ * specified tile.  There must be space for the
+ * data.  The function clamps individual writes
+ * to a tile to the tile size, but does not (and
+ * can not) check that multiple writes to the same
+ * tile do not write more than tile size data.
+ *
+ * NB: Image length must be setup before writing; this
+ *     interface does not support automatically growing
+ *     the image on each write (as TIFFWriteScanline does).
+ */
+tmsize_t
+TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc)
+{
+	static const char module[] = "TIFFWriteEncodedTile";
+	TIFFDirectory *td;
+	uint16 sample;
+        uint32 howmany32;
+
+	if (!WRITECHECKTILES(tif, module))
+		return ((tmsize_t)(-1));
+	td = &tif->tif_dir;
+	if (tile >= td->td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Tile %lu out of range, max %lu",
+		    (unsigned long) tile, (unsigned long) td->td_nstrips);
+		return ((tmsize_t)(-1));
+	}
+	/*
+	 * Handle delayed allocation of data buffer.  This
+	 * permits it to be sized more intelligently (using
+	 * directory information).
+	 */
+	if (!BUFFERCHECK(tif))
+		return ((tmsize_t)(-1));
+
+        tif->tif_flags |= TIFF_BUF4WRITE;
+	tif->tif_curtile = tile;
+
+	if( td->td_stripbytecount[tile] > 0 )
+        {
+            /* Make sure that at the first attempt of rewriting the tile, 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) */
+            if( tif->tif_rawdatasize <= (tmsize_t) td->td_stripbytecount[tile] )
+            {
+                if( !(TIFFWriteBufferSetup(tif, NULL,
+                    (tmsize_t)TIFFroundup_64((uint64)(td->td_stripbytecount[tile] + 1), 1024))) )
+                    return ((tmsize_t)(-1));
+            }
+
+	    /* Force TIFFAppendToStrip() to consider placing data at end
+               of file. */
+            tif->tif_curoff = 0;
+        }
+
+	tif->tif_rawcc = 0;
+	tif->tif_rawcp = tif->tif_rawdata;
+
+	/* 
+	 * Compute tiles per row & per column to compute
+	 * current row and column
+	 */
+        howmany32=TIFFhowmany_32(td->td_imagelength, td->td_tilelength);
+        if (howmany32 == 0) {
+                 TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles");
+                return ((tmsize_t)(-1));
+        }
+	tif->tif_row = (tile % howmany32) * td->td_tilelength;
+        howmany32=TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth);
+        if (howmany32 == 0) {
+                 TIFFErrorExt(tif->tif_clientdata,module,"Zero tiles");
+                return ((tmsize_t)(-1));
+        }
+	tif->tif_col = (tile % howmany32) * td->td_tilewidth;
+
+	if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+		if (!(*tif->tif_setupencode)(tif))
+			return ((tmsize_t)(-1));
+		tif->tif_flags |= TIFF_CODERSETUP;
+	}
+	tif->tif_flags &= ~TIFF_POSTENCODE;
+	sample = (uint16)(tile/td->td_stripsperimage);
+	if (!(*tif->tif_preencode)(tif, sample))
+		return ((tmsize_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;
+
+        /* swab if needed - note that source buffer will be altered */
+	tif->tif_postdecode( tif, (uint8*) data, cc );
+
+	if (!(*tif->tif_encodetile)(tif, (uint8*) data, cc, sample))
+		return (0);
+	if (!(*tif->tif_postencode)(tif))
+		return ((tmsize_t)(-1));
+	if (!isFillOrder(tif, td->td_fillorder) &&
+	    (tif->tif_flags & TIFF_NOBITREV) == 0)
+		TIFFReverseBits((uint8*)tif->tif_rawdata, tif->tif_rawcc);
+	if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile,
+	    tif->tif_rawdata, tif->tif_rawcc))
+		return ((tmsize_t)(-1));
+	tif->tif_rawcc = 0;
+	tif->tif_rawcp = tif->tif_rawdata;
+	return (cc);
+}
+
+/*
+ * Write the supplied data to the specified strip.
+ * There must be space for the data; we don't check
+ * if strips overlap!
+ *
+ * NB: Image length must be setup before writing; this
+ *     interface does not support automatically growing
+ *     the image on each write (as TIFFWriteScanline does).
+ */
+tmsize_t
+TIFFWriteRawTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc)
+{
+	static const char module[] = "TIFFWriteRawTile";
+
+	if (!WRITECHECKTILES(tif, module))
+		return ((tmsize_t)(-1));
+	if (tile >= tif->tif_dir.td_nstrips) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Tile %lu out of range, max %lu",
+		    (unsigned long) tile,
+		    (unsigned long) tif->tif_dir.td_nstrips);
+		return ((tmsize_t)(-1));
+	}
+	return (TIFFAppendToStrip(tif, tile, (uint8*) data, cc) ?
+	    cc : (tmsize_t)(-1));
+}
+
+#define	isUnspecified(tif, f) \
+    (TIFFFieldSet(tif,f) && (tif)->tif_dir.td_imagelength == 0)
+
+int
+TIFFSetupStrips(TIFF* tif)
+{
+	TIFFDirectory* td = &tif->tif_dir;
+
+	if (isTiled(tif))
+		td->td_stripsperimage =
+		    isUnspecified(tif, FIELD_TILEDIMENSIONS) ?
+			td->td_samplesperpixel : TIFFNumberOfTiles(tif);
+	else
+		td->td_stripsperimage =
+		    isUnspecified(tif, FIELD_ROWSPERSTRIP) ?
+			td->td_samplesperpixel : TIFFNumberOfStrips(tif);
+	td->td_nstrips = td->td_stripsperimage;
+	if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+		td->td_stripsperimage /= td->td_samplesperpixel;
+	td->td_stripoffset = (uint64 *)
+	    _TIFFmalloc(td->td_nstrips * sizeof (uint64));
+	td->td_stripbytecount = (uint64 *)
+	    _TIFFmalloc(td->td_nstrips * sizeof (uint64));
+	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 (uint64));
+	_TIFFmemset(td->td_stripbytecount, 0, td->td_nstrips*sizeof (uint64));
+	TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
+	TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
+	return (1);
+}
+#undef isUnspecified
+
+/*
+ * Verify file is writable and that the directory
+ * information is setup properly.  In doing the latter
+ * we also "freeze" the state of the directory so
+ * that important information is not changed.
+ */
+int
+TIFFWriteCheck(TIFF* tif, int tiles, const char* module)
+{
+	if (tif->tif_mode == O_RDONLY) {
+		TIFFErrorExt(tif->tif_clientdata, module, "File not open for writing");
+		return (0);
+	}
+	if (tiles ^ isTiled(tif)) {
+		TIFFErrorExt(tif->tif_clientdata, module, tiles ?
+		    "Can not write tiles to a stripped image" :
+		    "Can not write scanlines to a tiled image");
+		return (0);
+	}
+
+        _TIFFFillStriles( tif );
+        
+	/*
+	 * On the first write verify all the required information
+	 * has been setup and initialize any data structures that
+	 * had to wait until directory information was set.
+	 * Note that a lot of our work is assumed to remain valid
+	 * because we disallow any of the important parameters
+	 * from changing after we start writing (i.e. once
+	 * TIFF_BEENWRITING is set, TIFFSetField will only allow
+	 * the image's length to be changed).
+	 */
+	if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Must set \"ImageWidth\" before writing data");
+		return (0);
+	}
+	if (tif->tif_dir.td_samplesperpixel == 1) {
+		/* 
+		 * Planarconfiguration is irrelevant in case of single band
+		 * images and need not be included. We will set it anyway,
+		 * because this field is used in other parts of library even
+		 * in the single band case.
+		 */
+		if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG))
+                    tif->tif_dir.td_planarconfig = PLANARCONFIG_CONTIG;
+	} else {
+		if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) {
+			TIFFErrorExt(tif->tif_clientdata, module,
+			    "Must set \"PlanarConfiguration\" before writing data");
+			return (0);
+		}
+	}
+	if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) {
+		tif->tif_dir.td_nstrips = 0;
+		TIFFErrorExt(tif->tif_clientdata, module, "No space for %s arrays",
+		    isTiled(tif) ? "tile" : "strip");
+		return (0);
+	}
+	if (isTiled(tif))
+	{
+		tif->tif_tilesize = TIFFTileSize(tif);
+		if (tif->tif_tilesize == 0)
+			return (0);
+	}
+	else
+		tif->tif_tilesize = (tmsize_t)(-1);
+	tif->tif_scanlinesize = TIFFScanlineSize(tif);
+	if (tif->tif_scanlinesize == 0)
+		return (0);
+	tif->tif_flags |= TIFF_BEENWRITING;
+	return (1);
+}
+
+/*
+ * Setup the raw data buffer used for encoding.
+ */
+int
+TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size)
+{
+	static const char module[] = "TIFFWriteBufferSetup";
+
+	if (tif->tif_rawdata) {
+		if (tif->tif_flags & TIFF_MYBUFFER) {
+			_TIFFfree(tif->tif_rawdata);
+			tif->tif_flags &= ~TIFF_MYBUFFER;
+		}
+		tif->tif_rawdata = NULL;
+	}
+	if (size == (tmsize_t)(-1)) {
+		size = (isTiled(tif) ?
+		    tif->tif_tilesize : TIFFStripSize(tif));
+		/*
+		 * Make raw data buffer at least 8K
+		 */
+		if (size < 8*1024)
+			size = 8*1024;
+		bp = NULL;			/* NB: force malloc */
+	}
+	if (bp == NULL) {
+		bp = _TIFFmalloc(size);
+		if (bp == NULL) {
+			TIFFErrorExt(tif->tif_clientdata, module, "No space for output buffer");
+			return (0);
+		}
+		tif->tif_flags |= TIFF_MYBUFFER;
+	} else
+		tif->tif_flags &= ~TIFF_MYBUFFER;
+	tif->tif_rawdata = (uint8*) bp;
+	tif->tif_rawdatasize = size;
+	tif->tif_rawcc = 0;
+	tif->tif_rawcp = tif->tif_rawdata;
+	tif->tif_flags |= TIFF_BUFFERSETUP;
+	return (1);
+}
+
+/*
+ * Grow the strip data structures by delta strips.
+ */
+static int
+TIFFGrowStrips(TIFF* tif, uint32 delta, const char* module)
+{
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64* new_stripoffset;
+	uint64* new_stripbytecount;
+
+	assert(td->td_planarconfig == PLANARCONFIG_CONTIG);
+	new_stripoffset = (uint64*)_TIFFrealloc(td->td_stripoffset,
+		(td->td_nstrips + delta) * sizeof (uint64));
+	new_stripbytecount = (uint64*)_TIFFrealloc(td->td_stripbytecount,
+		(td->td_nstrips + delta) * sizeof (uint64));
+	if (new_stripoffset == NULL || new_stripbytecount == NULL) {
+		if (new_stripoffset)
+			_TIFFfree(new_stripoffset);
+		if (new_stripbytecount)
+			_TIFFfree(new_stripbytecount);
+		td->td_nstrips = 0;
+		TIFFErrorExt(tif->tif_clientdata, module, "No space to expand strip arrays");
+		return (0);
+	}
+	td->td_stripoffset = new_stripoffset;
+	td->td_stripbytecount = new_stripbytecount;
+	_TIFFmemset(td->td_stripoffset + td->td_nstrips,
+		    0, delta*sizeof (uint64));
+	_TIFFmemset(td->td_stripbytecount + td->td_nstrips,
+		    0, delta*sizeof (uint64));
+	td->td_nstrips += delta;
+        tif->tif_flags |= TIFF_DIRTYDIRECT;
+
+	return (1);
+}
+
+/*
+ * Append the data to the specified strip.
+ */
+static int
+TIFFAppendToStrip(TIFF* tif, uint32 strip, uint8* data, tmsize_t cc)
+{
+	static const char module[] = "TIFFAppendToStrip";
+	TIFFDirectory *td = &tif->tif_dir;
+	uint64 m;
+        int64 old_byte_count = -1;
+
+	if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) {
+            assert(td->td_nstrips > 0);
+
+            if( td->td_stripbytecount[strip] != 0 
+                && td->td_stripoffset[strip] != 0 
+                && td->td_stripbytecount[strip] >= (uint64) 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[strip])) {
+                    TIFFErrorExt(tif->tif_clientdata, module,
+                                 "Seek error at scanline %lu",
+                                 (unsigned long)tif->tif_row);
+                    return (0);
+                }
+            }
+            else
+            {
+                /* 
+                 * Seek to end of file, and set that as our location to 
+                 * write this strip.
+                 */
+                td->td_stripoffset[strip] = TIFFSeekFile(tif, 0, SEEK_END);
+                tif->tif_flags |= TIFF_DIRTYSTRIP;
+            }
+
+            tif->tif_curoff = td->td_stripoffset[strip];
+
+            /*
+             * We are starting a fresh strip/tile, so set the size to zero.
+             */
+            old_byte_count = td->td_stripbytecount[strip];
+            td->td_stripbytecount[strip] = 0;
+	}
+
+	m = tif->tif_curoff+cc;
+	if (!(tif->tif_flags&TIFF_BIGTIFF))
+		m = (uint32)m;
+	if ((m<tif->tif_curoff)||(m<(uint64)cc))
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "Maximum TIFF file size exceeded");
+		return (0);
+	}
+	if (!WriteOK(tif, data, cc)) {
+		TIFFErrorExt(tif->tif_clientdata, module, "Write error at scanline %lu",
+		    (unsigned long) tif->tif_row);
+		    return (0);
+	}
+	tif->tif_curoff = m;
+	td->td_stripbytecount[strip] += cc;
+
+        if( (int64) td->td_stripbytecount[strip] != old_byte_count )
+            tif->tif_flags |= TIFF_DIRTYSTRIP;
+            
+	return (1);
+}
+
+/*
+ * Internal version of TIFFFlushData that can be
+ * called by ``encodestrip routines'' w/o concern
+ * for infinite recursion.
+ */
+int
+TIFFFlushData1(TIFF* tif)
+{
+	if (tif->tif_rawcc > 0 && tif->tif_flags & TIFF_BUF4WRITE ) {
+		if (!isFillOrder(tif, tif->tif_dir.td_fillorder) &&
+		    (tif->tif_flags & TIFF_NOBITREV) == 0)
+			TIFFReverseBits((uint8*)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);
+}
+
+/*
+ * Set the current write offset.  This should only be
+ * used to set the offset to a known previous location
+ * (very carefully), or to 0 so that the next write gets
+ * appended to the end of the file.
+ */
+void
+TIFFSetWriteOffset(TIFF* tif, toff_t off)
+{
+	tif->tif_curoff = off;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tif_zip.c b/third_party/libtiff/tif_zip.c
new file mode 100644
index 0000000..b3ac9b9
--- /dev/null
+++ b/third_party/libtiff/tif_zip.c
@@ -0,0 +1,472 @@
+/* $Id: tif_zip.c,v 1.33 2014-12-25 18:29:11 erouault 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef ZIP_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * ZIP (aka Deflate) Compression Support
+ *
+ * This file is simply 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 suppressing 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.
+ *
+ * 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.
+ */
+#include "tif_predict.h"
+#include "../zlib_v128/zlib.h"
+
+#include <stdio.h>
+
+/*
+ * Sigh, ZLIB_VERSION is defined as a string so there's no
+ * way to do a proper check here.  Instead we guess based
+ * on the presence of #defines that were added between the
+ * 0.95 and 1.0 distributions.
+ */
+#if !defined(Z_NO_COMPRESSION) || !defined(Z_DEFLATED)
+#error "Antiquated ZLIB software; you must use version 1.0 or later"
+#endif
+
+#define SAFE_MSG(sp)   ((sp)->stream.msg == NULL ? "" : (sp)->stream.msg)
+
+/*
+ * State block for each open TIFF
+ * file using ZIP compression/decompression.
+ */
+typedef struct {
+	TIFFPredictorState predict;
+        z_stream        stream;
+	int             zipquality;            /* compression level */
+	int             state;                 /* state flags */
+#define ZSTATE_INIT_DECODE 0x01
+#define ZSTATE_INIT_ENCODE 0x02
+
+	TIFFVGetMethod  vgetparent;            /* super-class method */
+	TIFFVSetMethod  vsetparent;            /* super-class method */
+} ZIPState;
+
+#define ZState(tif)             ((ZIPState*) (tif)->tif_data)
+#define DecoderState(tif)       ZState(tif)
+#define EncoderState(tif)       ZState(tif)
+
+static int ZIPEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s);
+static int ZIPDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s);
+
+static int
+ZIPFixupTags(TIFF* tif)
+{
+	(void) tif;
+	return (1);
+}
+
+static int
+ZIPSetupDecode(TIFF* tif)
+{
+	static const char module[] = "ZIPSetupDecode";
+	ZIPState* sp = DecoderState(tif);
+
+	assert(sp != NULL);
+        
+        /* if we were last encoding, terminate this mode */
+	if (sp->state & ZSTATE_INIT_ENCODE) {
+	    deflateEnd(&sp->stream);
+	    sp->state = 0;
+	}
+
+	if (inflateInit(&sp->stream) != Z_OK) {
+		TIFFErrorExt(tif->tif_clientdata, module, "%s", SAFE_MSG(sp));
+		return (0);
+	} else {
+		sp->state |= ZSTATE_INIT_DECODE;
+		return (1);
+	}
+}
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+ZIPPreDecode(TIFF* tif, uint16 s)
+{
+	static const char module[] = "ZIPPreDecode";
+	ZIPState* sp = DecoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+
+	if( (sp->state & ZSTATE_INIT_DECODE) == 0 )
+            tif->tif_setupdecode( tif );
+
+	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
+	    apropriately even before we simplify it */
+	sp->stream.avail_in = (uInt) tif->tif_rawcc;
+	if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	return (inflateReset(&sp->stream) == Z_OK);
+}
+
+static int
+ZIPDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+	static const char module[] = "ZIPDecode";
+	ZIPState* sp = DecoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	assert(sp->state == ZSTATE_INIT_DECODE);
+
+        sp->stream.next_in = tif->tif_rawcp;
+	sp->stream.avail_in = (uInt) tif->tif_rawcc;
+        
+	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
+	    apropriately even before we simplify it */
+	sp->stream.avail_out = (uInt) occ;
+	if ((tmsize_t)sp->stream.avail_out != occ)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	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,
+			    "Decoding error at scanline %lu, %s",
+			     (unsigned long) tif->tif_row, SAFE_MSG(sp));
+			if (inflateSync(&sp->stream) != Z_OK)
+				return (0);
+			continue;
+		}
+		if (state != Z_OK) {
+			TIFFErrorExt(tif->tif_clientdata, module, 
+				     "ZLib error: %s", SAFE_MSG(sp));
+			return (0);
+		}
+	} while (sp->stream.avail_out > 0);
+	if (sp->stream.avail_out != 0) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+		    "Not enough data at scanline %lu (short " TIFF_UINT64_FORMAT " bytes)",
+		    (unsigned long) tif->tif_row, (TIFF_UINT64_T) sp->stream.avail_out);
+		return (0);
+	}
+
+        tif->tif_rawcp = sp->stream.next_in;
+        tif->tif_rawcc = sp->stream.avail_in;
+
+	return (1);
+}
+
+static int
+ZIPSetupEncode(TIFF* tif)
+{
+	static const char module[] = "ZIPSetupEncode";
+	ZIPState* sp = EncoderState(tif);
+
+	assert(sp != NULL);
+	if (sp->state & ZSTATE_INIT_DECODE) {
+		inflateEnd(&sp->stream);
+		sp->state = 0;
+	}
+
+	if (deflateInit(&sp->stream, sp->zipquality) != Z_OK) {
+		TIFFErrorExt(tif->tif_clientdata, module, "%s", SAFE_MSG(sp));
+		return (0);
+	} else {
+		sp->state |= ZSTATE_INIT_ENCODE;
+		return (1);
+	}
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+ZIPPreEncode(TIFF* tif, uint16 s)
+{
+	static const char module[] = "ZIPPreEncode";
+	ZIPState *sp = EncoderState(tif);
+
+	(void) s;
+	assert(sp != NULL);
+	if( sp->state != ZSTATE_INIT_ENCODE )
+            tif->tif_setupencode( tif );
+
+	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
+	    apropriately even before we simplify it */
+	sp->stream.avail_out = tif->tif_rawdatasize;
+	if ((tmsize_t)sp->stream.avail_out != tif->tif_rawdatasize)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	return (deflateReset(&sp->stream) == Z_OK);
+}
+
+/*
+ * Encode a chunk of pixels.
+ */
+static int
+ZIPEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+	static const char module[] = "ZIPEncode";
+	ZIPState *sp = EncoderState(tif);
+
+	assert(sp != NULL);
+	assert(sp->state == ZSTATE_INIT_ENCODE);
+
+	(void) s;
+	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
+	    apropriately even before we simplify it */
+	sp->stream.avail_in = (uInt) cc;
+	if ((tmsize_t)sp->stream.avail_in != cc)
+	{
+		TIFFErrorExt(tif->tif_clientdata, module, "ZLib cannot deal with buffers this size");
+		return (0);
+	}
+	do {
+		if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) {
+			TIFFErrorExt(tif->tif_clientdata, module, 
+				     "Encoder error: %s",
+				     SAFE_MSG(sp));
+			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 = (uInt) tif->tif_rawdatasize;  /* this is a safe typecast, as check is made already in ZIPPreEncode */
+		}
+	} 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
+ZIPPostEncode(TIFF* tif)
+{
+	static const char module[] = "ZIPPostEncode";
+	ZIPState *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;
+				TIFFFlushData1(tif);
+				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 ZIPPreEncode */
+			}
+			break;
+		default:
+			TIFFErrorExt(tif->tif_clientdata, module, 
+				     "ZLib error: %s", SAFE_MSG(sp));
+			return (0);
+		}
+	} while (state != Z_STREAM_END);
+	return (1);
+}
+
+static void
+ZIPCleanup(TIFF* tif)
+{
+	ZIPState* sp = ZState(tif);
+
+	assert(sp != 0);
+
+	(void)TIFFPredictorCleanup(tif);
+
+	tif->tif_tagmethods.vgetfield = sp->vgetparent;
+	tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+	if (sp->state & ZSTATE_INIT_ENCODE) {
+		deflateEnd(&sp->stream);
+		sp->state = 0;
+	} else if( sp->state & ZSTATE_INIT_DECODE) {
+		inflateEnd(&sp->stream);
+		sp->state = 0;
+	}
+	_TIFFfree(sp);
+	tif->tif_data = NULL;
+
+	_TIFFSetDefaultCompressionState(tif);
+}
+
+static int
+ZIPVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+	static const char module[] = "ZIPVSetField";
+	ZIPState* sp = ZState(tif);
+
+	switch (tag) {
+	case TIFFTAG_ZIPQUALITY:
+		sp->zipquality = (int) va_arg(ap, int);
+		if ( sp->state&ZSTATE_INIT_ENCODE ) {
+			if (deflateParams(&sp->stream,
+			    sp->zipquality, Z_DEFAULT_STRATEGY) != Z_OK) {
+				TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
+					     SAFE_MSG(sp));
+				return (0);
+			}
+		}
+		return (1);
+	default:
+		return (*sp->vsetparent)(tif, tag, ap);
+	}
+	/*NOTREACHED*/
+}
+
+static int
+ZIPVGetField(TIFF* tif, uint32 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);
+}
+
+static const TIFFField zipFields[] = {
+    { TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL },
+};
+
+int
+TIFFInitZIP(TIFF* tif, int scheme)
+{
+	static const char module[] = "TIFFInitZIP";
+	ZIPState* sp;
+
+	assert( (scheme == COMPRESSION_DEFLATE)
+		|| (scheme == COMPRESSION_ADOBE_DEFLATE));
+
+	/*
+	 * Merge codec-specific tag information.
+	 */
+	if (!_TIFFMergeFields(tif, zipFields, TIFFArrayCount(zipFields))) {
+		TIFFErrorExt(tif->tif_clientdata, module,
+			     "Merging Deflate codec-specific tags failed");
+		return 0;
+	}
+
+	/*
+	 * Allocate state block so tag methods have storage to record values.
+	 */
+	tif->tif_data = (uint8*) _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_fixuptags = ZIPFixupTags; 
+	tif->tif_setupdecode = ZIPSetupDecode;
+	tif->tif_predecode = ZIPPreDecode;
+	tif->tif_decoderow = ZIPDecode;
+	tif->tif_decodestrip = ZIPDecode;
+	tif->tif_decodetile = ZIPDecode;  
+	tif->tif_setupencode = ZIPSetupEncode;
+	tif->tif_preencode = ZIPPreEncode;
+	tif->tif_postencode = ZIPPostEncode;
+	tif->tif_encoderow = ZIPEncode;
+	tif->tif_encodestrip = ZIPEncode;
+	tif->tif_encodetile = ZIPEncode;
+	tif->tif_cleanup = ZIPCleanup;
+	/*
+	 * Setup predictor setup.
+	 */
+	(void) TIFFPredictorInit(tif);
+	return (1);
+bad:
+	TIFFErrorExt(tif->tif_clientdata, module,
+		     "No space for ZIP state block");
+	return (0);
+}
+#endif /* ZIP_SUPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tiff.h b/third_party/libtiff/tiff.h
new file mode 100644
index 0000000..bc46acd
--- /dev/null
+++ b/third_party/libtiff/tiff.h
@@ -0,0 +1,681 @@
+/* $Id: tiff.h,v 1.69 2014-04-02 17:23:06 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFF_
+#define	_TIFF_
+
+#include "tiffconf.h"
+
+/*
+ * Tag Image File Format (TIFF)
+ *
+ * Based on Rev 6.0 from:
+ *    Developer's Desk
+ *    Aldus Corporation
+ *    411 First Ave. South
+ *    Suite 200
+ *    Seattle, WA  98104
+ *    206-622-5500
+ *
+ *    (http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf)
+ *
+ * For BigTIFF design notes see the following links
+ *    http://www.remotesensing.org/libtiff/bigtiffdesign.html
+ *    http://www.awaresystems.be/imaging/tiff/bigtiff.html
+ */
+
+#define TIFF_VERSION_CLASSIC 42
+#define TIFF_VERSION_BIG 43
+
+#define TIFF_BIGENDIAN      0x4d4d
+#define TIFF_LITTLEENDIAN   0x4949
+#define MDI_LITTLEENDIAN    0x5045
+#define MDI_BIGENDIAN       0x4550
+
+/*
+ * Intrinsic data types required by the file format:
+ *
+ * 8-bit quantities     int8/uint8
+ * 16-bit quantities    int16/uint16
+ * 32-bit quantities    int32/uint32
+ * 64-bit quantities    int64/uint64
+ * strings              unsigned char*
+ */
+
+typedef TIFF_INT8_T   int8;
+typedef TIFF_UINT8_T  uint8;
+
+typedef TIFF_INT16_T  int16;
+typedef TIFF_UINT16_T uint16;
+
+typedef TIFF_INT32_T  int32;
+typedef TIFF_UINT32_T uint32;
+
+typedef TIFF_INT64_T  int64;
+typedef TIFF_UINT64_T uint64;
+
+/*
+ * Some types as promoted in a variable argument list
+ * We use uint16_vap rather then directly using int, because this way
+ * we document the type we actually want to pass through, conceptually,
+ * rather then confusing the issue by merely stating the type it gets
+ * promoted to
+ */
+
+typedef int uint16_vap;
+
+/*
+ * TIFF header.
+ */
+typedef struct {
+	uint16 tiff_magic;      /* magic number (defines byte order) */
+	uint16 tiff_version;    /* TIFF version number */
+} TIFFHeaderCommon;
+typedef struct {
+	uint16 tiff_magic;      /* magic number (defines byte order) */
+	uint16 tiff_version;    /* TIFF version number */
+	uint32 tiff_diroff;     /* byte offset to first directory */
+} TIFFHeaderClassic;
+typedef struct {
+	uint16 tiff_magic;      /* magic number (defines byte order) */
+	uint16 tiff_version;    /* TIFF version number */
+	uint16 tiff_offsetsize; /* size of offsets, should be 8 */
+	uint16 tiff_unused;     /* unused word, should be 0 */
+	uint64 tiff_diroff;     /* byte offset to first directory */
+} TIFFHeaderBig;
+
+
+/*
+ * NB: In the comments below,
+ *  - items marked with a + are obsoleted by revision 5.0,
+ *  - items marked with a ! are introduced in revision 6.0.
+ *  - items marked with a % are introduced post revision 6.0.
+ *  - items marked with a $ are obsoleted by revision 6.0.
+ *  - items marked with a & are introduced by Adobe DNG specification.
+ */
+
+/*
+ * Tag data type information.
+ *
+ * Note: RATIONALs are the ratio of two 32-bit integer values.
+ */
+typedef enum {
+	TIFF_NOTYPE = 0,      /* placeholder */
+	TIFF_BYTE = 1,        /* 8-bit unsigned integer */
+	TIFF_ASCII = 2,       /* 8-bit bytes w/ last byte null */
+	TIFF_SHORT = 3,       /* 16-bit unsigned integer */
+	TIFF_LONG = 4,        /* 32-bit unsigned integer */
+	TIFF_RATIONAL = 5,    /* 64-bit unsigned fraction */
+	TIFF_SBYTE = 6,       /* !8-bit signed integer */
+	TIFF_UNDEFINED = 7,   /* !8-bit untyped data */
+	TIFF_SSHORT = 8,      /* !16-bit signed integer */
+	TIFF_SLONG = 9,       /* !32-bit signed integer */
+	TIFF_SRATIONAL = 10,  /* !64-bit signed fraction */
+	TIFF_FLOAT = 11,      /* !32-bit IEEE floating point */
+	TIFF_DOUBLE = 12,     /* !64-bit IEEE floating point */
+	TIFF_IFD = 13,        /* %32-bit unsigned integer (offset) */
+	TIFF_LONG8 = 16,      /* BigTIFF 64-bit unsigned integer */
+	TIFF_SLONG8 = 17,     /* BigTIFF 64-bit signed integer */
+	TIFF_IFD8 = 18        /* BigTIFF 64-bit unsigned integer (offset) */
+} TIFFDataType;
+
+/*
+ * TIFF Tag Definitions.
+ */
+#define	TIFFTAG_SUBFILETYPE		254	/* subfile data descriptor */
+#define	    FILETYPE_REDUCEDIMAGE	0x1	/* reduced resolution version */
+#define	    FILETYPE_PAGE		0x2	/* one page of many */
+#define	    FILETYPE_MASK		0x4	/* transparency mask */
+#define	TIFFTAG_OSUBFILETYPE		255	/* +kind of data in subfile */
+#define	    OFILETYPE_IMAGE		1	/* full resolution image data */
+#define	    OFILETYPE_REDUCEDIMAGE	2	/* reduced size image data */
+#define	    OFILETYPE_PAGE		3	/* one page of many */
+#define	TIFFTAG_IMAGEWIDTH		256	/* image width in pixels */
+#define	TIFFTAG_IMAGELENGTH		257	/* image height in pixels */
+#define	TIFFTAG_BITSPERSAMPLE		258	/* bits per channel (sample) */
+#define	TIFFTAG_COMPRESSION		259	/* data compression technique */
+#define	    COMPRESSION_NONE		1	/* dump mode */
+#define	    COMPRESSION_CCITTRLE	2	/* CCITT modified Huffman RLE */
+#define	    COMPRESSION_CCITTFAX3	3	/* CCITT Group 3 fax encoding */
+#define     COMPRESSION_CCITT_T4        3       /* CCITT T.4 (TIFF 6 name) */
+#define	    COMPRESSION_CCITTFAX4	4	/* CCITT Group 4 fax encoding */
+#define     COMPRESSION_CCITT_T6        4       /* CCITT T.6 (TIFF 6 name) */
+#define	    COMPRESSION_LZW		5       /* Lempel-Ziv  & Welch */
+#define	    COMPRESSION_OJPEG		6	/* !6.0 JPEG */
+#define	    COMPRESSION_JPEG		7	/* %JPEG DCT compression */
+#define     COMPRESSION_T85			9	/* !TIFF/FX T.85 JBIG compression */
+#define     COMPRESSION_T43			10	/* !TIFF/FX T.43 colour by layered JBIG compression */
+#define	    COMPRESSION_NEXT		32766	/* NeXT 2-bit RLE */
+#define	    COMPRESSION_CCITTRLEW	32771	/* #1 w/ word alignment */
+#define	    COMPRESSION_PACKBITS	32773	/* Macintosh RLE */
+#define	    COMPRESSION_THUNDERSCAN	32809	/* ThunderScan RLE */
+/* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT <dkelly@apago.com) */
+#define	    COMPRESSION_IT8CTPAD	32895   /* IT8 CT w/padding */
+#define	    COMPRESSION_IT8LW		32896   /* IT8 Linework RLE */
+#define	    COMPRESSION_IT8MP		32897   /* IT8 Monochrome picture */
+#define	    COMPRESSION_IT8BL		32898   /* IT8 Binary line art */
+/* compression codes 32908-32911 are reserved for Pixar */
+#define     COMPRESSION_PIXARFILM	32908   /* Pixar companded 10bit LZW */
+#define	    COMPRESSION_PIXARLOG	32909   /* Pixar companded 11bit ZIP */
+#define	    COMPRESSION_DEFLATE		32946	/* Deflate compression */
+#define     COMPRESSION_ADOBE_DEFLATE   8       /* Deflate compression,
+						   as recognized by Adobe */
+/* compression code 32947 is reserved for Oceana Matrix <dev@oceana.com> */
+#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_LZMA		34925	/* LZMA2 */
+#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 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] */
+/* 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_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] */
+/* tags 32952-32956 are private tags registered to Island Graphics */
+#define TIFFTAG_REFPTS			32953	/* image reference points */
+#define TIFFTAG_REGIONTACKPOINT		32954	/* region-xform tack point */
+#define TIFFTAG_REGIONWARPCORNERS	32955	/* warp quadrilateral */
+#define TIFFTAG_REGIONAFFINE		32956	/* affine transformation mat */
+/* tags 32995-32999 are private tags registered to SGI */
+#define	TIFFTAG_MATTEING		32995	/* $use ExtraSamples */
+#define	TIFFTAG_DATATYPE		32996	/* $use SampleFormat */
+#define	TIFFTAG_IMAGEDEPTH		32997	/* z depth of image */
+#define	TIFFTAG_TILEDEPTH		32998	/* z depth/data tile */
+/* tags 33300-33309 are private tags registered to Pixar */
+/*
+ * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH
+ * are set when an image has been cropped out of a larger image.  
+ * They reflect the size of the original uncropped image.
+ * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used
+ * to determine the position of the smaller image in the larger one.
+ */
+#define TIFFTAG_PIXAR_IMAGEFULLWIDTH    33300   /* full image size in x */
+#define TIFFTAG_PIXAR_IMAGEFULLLENGTH   33301   /* full image size in y */
+ /* Tags 33302-33306 are used to identify special image modes and data
+  * used by Pixar's texture formats.
+  */
+#define TIFFTAG_PIXAR_TEXTUREFORMAT	33302	/* texture map format */
+#define TIFFTAG_PIXAR_WRAPMODES		33303	/* s & t wrap modes */
+#define TIFFTAG_PIXAR_FOVCOT		33304	/* cotan(fov) for env. maps */
+#define TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN 33305
+#define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306
+/* tag 33405 is a private tag registered to Eastman Kodak */
+#define TIFFTAG_WRITERSERIALNUMBER      33405   /* device serial number */
+#define TIFFTAG_CFAREPEATPATTERNDIM	33421	/* dimensions of CFA pattern */
+#define TIFFTAG_CFAPATTERN		33422	/* color filter array pattern */
+/* tag 33432 is listed in the 6.0 spec w/ unknown ownership */
+#define	TIFFTAG_COPYRIGHT		33432	/* copyright string */
+/* IPTC TAG from RichTIFF specifications */
+#define TIFFTAG_RICHTIFFIPTC		33723
+/* 34016-34029 are reserved for ANSI IT8 TIFF/IT <dkelly@apago.com) */
+#define TIFFTAG_IT8SITE			34016	/* site name */
+#define TIFFTAG_IT8COLORSEQUENCE	34017	/* color seq. [RGB,CMYK,etc] */
+#define TIFFTAG_IT8HEADER		34018	/* DDES Header */
+#define TIFFTAG_IT8RASTERPADDING	34019	/* raster scanline padding */
+#define TIFFTAG_IT8BITSPERRUNLENGTH	34020	/* # of bits in short run */
+#define TIFFTAG_IT8BITSPEREXTENDEDRUNLENGTH 34021/* # of bits in long run */
+#define TIFFTAG_IT8COLORTABLE		34022	/* LW colortable */
+#define TIFFTAG_IT8IMAGECOLORINDICATOR	34023	/* BP/BL image color switch */
+#define TIFFTAG_IT8BKGCOLORINDICATOR	34024	/* BP/BL bg color switch */
+#define TIFFTAG_IT8IMAGECOLORVALUE	34025	/* BP/BL image color value */
+#define TIFFTAG_IT8BKGCOLORVALUE	34026	/* BP/BL bg color value */
+#define TIFFTAG_IT8PIXELINTENSITYRANGE	34027	/* MP pixel intensity value */
+#define TIFFTAG_IT8TRANSPARENCYINDICATOR 34028	/* HC transparency switch */
+#define TIFFTAG_IT8COLORCHARACTERIZATION 34029	/* color character. table */
+#define TIFFTAG_IT8HCUSAGE		34030	/* HC usage indicator */
+#define TIFFTAG_IT8TRAPINDICATOR	34031	/* Trapping indicator
+						   (untrapped=0, trapped=1) */
+#define TIFFTAG_IT8CMYKEQUIVALENT	34032	/* CMYK color equivalents */
+/* tags 34232-34236 are private tags registered to Texas Instruments */
+#define TIFFTAG_FRAMECOUNT              34232   /* Sequence Frame Count */
+/* tag 34377 is private tag registered to Adobe for PhotoShop */
+#define TIFFTAG_PHOTOSHOP		34377 
+/* tags 34665, 34853 and 40965 are documented in EXIF specification */
+#define TIFFTAG_EXIFIFD			34665	/* Pointer to EXIF private directory */
+/* tag 34750 is a private tag registered to Adobe? */
+#define TIFFTAG_ICCPROFILE		34675	/* ICC profile data */
+#define TIFFTAG_IMAGELAYER		34732	/* !TIFF/FX image layer information */
+/* tag 34750 is a private tag registered to Pixel Magic */
+#define	TIFFTAG_JBIGOPTIONS		34750	/* JBIG options */
+#define TIFFTAG_GPSIFD			34853	/* Pointer to GPS private directory */
+/* tags 34908-34914 are private tags registered to SGI */
+#define	TIFFTAG_FAXRECVPARAMS		34908	/* encoded Class 2 ses. parms */
+#define	TIFFTAG_FAXSUBADDRESS		34909	/* received SubAddr string */
+#define	TIFFTAG_FAXRECVTIME		34910	/* receive time (secs) */
+#define	TIFFTAG_FAXDCS			34911	/* encoded fax ses. params, Table 2/T.30 */
+/* tags 37439-37443 are registered to SGI <gregl@sgi.com> */
+#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 */
+/* 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	/* & */
+/* tag 65535 is an undefined tag used by Eastman Kodak */
+#define TIFFTAG_DCSHUESHIFTVALUES       65535   /* hue shift correction data */
+
+/*
+ * The following are ``pseudo tags'' that can be used to control
+ * codec-specific functionality.  These tags are not written to file.
+ * Note that these values start at 0xffff+1 so that they'll never
+ * collide with Aldus-assigned tags.
+ *
+ * If you want your private pseudo tags ``registered'' (i.e. added to
+ * this file), please post a bug report via the tracking system at
+ * http://www.remotesensing.org/libtiff/bugs.html with the appropriate
+ * C definitions to add.
+ */
+#define	TIFFTAG_FAXMODE			65536	/* Group 3/4 format control */
+#define	    FAXMODE_CLASSIC	0x0000		/* default, include RTC */
+#define	    FAXMODE_NORTC	0x0001		/* no RTC at end of data */
+#define	    FAXMODE_NOEOL	0x0002		/* no EOL code at end of row */
+#define	    FAXMODE_BYTEALIGN	0x0004		/* byte align row */
+#define	    FAXMODE_WORDALIGN	0x0008		/* word align row */
+#define	    FAXMODE_CLASSF	FAXMODE_NORTC	/* TIFF Class F */
+#define	TIFFTAG_JPEGQUALITY		65537	/* Compression quality level */
+/* Note: quality level is on the IJG 0-100 scale.  Default value is 75 */
+#define	TIFFTAG_JPEGCOLORMODE		65538	/* Auto RGB<=>YCbCr convert? */
+#define	    JPEGCOLORMODE_RAW	0x0000		/* no conversion (default) */
+#define	    JPEGCOLORMODE_RGB	0x0001		/* do auto conversion */
+#define	TIFFTAG_JPEGTABLESMODE		65539	/* What to put in JPEGTables */
+#define	    JPEGTABLESMODE_QUANT 0x0001		/* include quantization tbls */
+#define	    JPEGTABLESMODE_HUFF	0x0002		/* include Huffman tbls */
+/* Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF */
+#define	TIFFTAG_FAXFILLFUNC		65540	/* G3/G4 fill function */
+#define	TIFFTAG_PIXARLOGDATAFMT		65549	/* PixarLogCodec I/O data sz */
+#define	    PIXARLOGDATAFMT_8BIT	0	/* regular u_char samples */
+#define	    PIXARLOGDATAFMT_8BITABGR	1	/* ABGR-order u_chars */
+#define	    PIXARLOGDATAFMT_11BITLOG	2	/* 11-bit log-encoded (raw) */
+#define	    PIXARLOGDATAFMT_12BITPICIO	3	/* as per PICIO (1.0==2048) */
+#define	    PIXARLOGDATAFMT_16BIT	4	/* signed short samples */
+#define	    PIXARLOGDATAFMT_FLOAT	5	/* IEEE float samples */
+/* 65550-65556 are allocated to Oceana Matrix <dev@oceana.com> */
+#define TIFFTAG_DCSIMAGERTYPE           65550   /* imager model & filter */
+#define     DCSIMAGERMODEL_M3           0       /* M3 chip (1280 x 1024) */
+#define     DCSIMAGERMODEL_M5           1       /* M5 chip (1536 x 1024) */
+#define     DCSIMAGERMODEL_M6           2       /* M6 chip (3072 x 2048) */
+#define     DCSIMAGERFILTER_IR          0       /* infrared filter */
+#define     DCSIMAGERFILTER_MONO        1       /* monochrome filter */
+#define     DCSIMAGERFILTER_CFA         2       /* color filter array */
+#define     DCSIMAGERFILTER_OTHER       3       /* other filter */
+#define TIFFTAG_DCSINTERPMODE           65551   /* interpolation mode */
+#define     DCSINTERPMODE_NORMAL        0x0     /* whole image, default */
+#define     DCSINTERPMODE_PREVIEW       0x1     /* preview of image (384x256) */
+#define TIFFTAG_DCSBALANCEARRAY         65552   /* color balance values */
+#define TIFFTAG_DCSCORRECTMATRIX        65553   /* color correction values */
+#define TIFFTAG_DCSGAMMA                65554   /* gamma value */
+#define TIFFTAG_DCSTOESHOULDERPTS       65555   /* toe & shoulder points */
+#define TIFFTAG_DCSCALIBRATIONFD        65556   /* calibration file desc */
+/* Note: quality level is on the ZLIB 1-9 scale. Default value is -1 */
+#define	TIFFTAG_ZIPQUALITY		65557	/* compression quality level */
+#define	TIFFTAG_PIXARLOGQUALITY		65558	/* PixarLog uses same scale */
+/* 65559 is allocated to Oceana Matrix <dev@oceana.com> */
+#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 */
+
+/*
+ * 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 */
+
+#endif /* _TIFF_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/third_party/libtiff/tiffconf.h b/third_party/libtiff/tiffconf.h
new file mode 100644
index 0000000..fab7e0d
--- /dev/null
+++ b/third_party/libtiff/tiffconf.h
@@ -0,0 +1,252 @@
+/* libtiff/tiffconf.h.  Generated by configure.  */
+/*
+  Configuration defines for installed libtiff.
+  This file maintained for backward compatibility. Do not use definitions
+  from this file in your programs.
+*/
+#ifndef _TIFFCONF_
+#define _TIFFCONF_
+
+#ifndef _FX_SYSTEM_H_
+# include "../../core/include/fxcrt/fx_system.h"
+#endif
+
+//NOTE: The tiff codec requires an ANSI C compiler environment for building and 
+//		presumes an ANSI C environment for use.
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+/* Define to 1 if you have the <sys/types.h> header file. */
+#if _FX_OS_ == _FX_WIN32_MOBILE_
+# define O_RDONLY       0x0000  /* open for reading only */
+# define O_WRONLY       0x0001  /* open for writing only */
+# define O_RDWR         0x0002  /* open for reading and writing */
+# define O_CREAT        0x0100  /* create and open file */
+# define O_TRUNC        0x0200  /* open and truncate */
+#else
+# define HAVE_SYS_TYPES_H 1
+# define HAVE_FCNTL_H 1
+#endif
+
+/* Compatibility stuff. */
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define as 0 or 1 according to the floating point format suported by the
+   machine */
+#define HAVE_IEEEFP 1
+
+/* Define to 1 if you have the <string.h> header file. */
+//#define HAVE_STRING_H 1
+//fx_system.h already include the string.h in ANSIC
+
+/* Define to 1 if you have the <search.h> header file. */
+/*#define HAVE_SEARCH_H 1 */
+
+/* The size of a `int', as computed by sizeof. */
+/* According typedef int	int32_t; in the fx_system.h*/
+#define SIZEOF_INT 4
+
+/* Sunliang.Liu 20110325. We should config the correct long size for tif 
+   fax4decode optimize in tif_fax3.c  -- Linux64 decode issue. 
+   TESTDOC: Bug #23661 - z1.tif. */
+#if _FX_CPU_ == _FX_WIN64_ || _FX_CPU_ == _FX_X64_ || _FX_CPU_ == _FX_IA64_
+/* The size of `unsigned long', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_LONG 8
+#else
+#define SIZEOF_UNSIGNED_LONG 4
+#endif
+
+#define HAVE_SNPRINTF 1
+
+/* Signed 8-bit type */
+#define TIFF_INT8_T signed char
+
+/* Unsigned 8-bit type */
+#define TIFF_UINT8_T unsigned char
+
+/* Signed 16-bit type */
+#define TIFF_INT16_T signed short
+
+/* Unsigned 16-bit type */
+#define TIFF_UINT16_T unsigned short
+
+/* Signed 32-bit type */
+#define TIFF_INT32_T signed int
+
+/* Unsigned 32-bit type */
+#define TIFF_UINT32_T unsigned int
+
+/* Signed 32-bit type formatter */
+#define TIFF_INT32_FORMAT "%d"
+
+/* Unsigned 32-bit type formatter */
+#define TIFF_UINT32_FORMAT "%u"
+
+#ifdef _MSC_VER		// windows
+
+/* Signed 64-bit type formatter */
+#define TIFF_INT64_FORMAT "%I64d"
+
+/* Unsigned 64-bit type formatter */
+#define TIFF_UINT64_FORMAT "%I64u"
+
+/* Signed 64-bit type */
+#define TIFF_INT64_T signed __int64
+
+/* Unsigned 64-bit type */
+#define TIFF_UINT64_T unsigned __int64
+
+#else						// linux/unix
+
+#if 0 //_FX_CPU_ == _FX_X64_	// linux/unix 64
+
+/* Signed 64-bit type formatter */
+#define TIFF_INT64_FORMAT "%ld"
+
+/* Unsigned 64-bit type formatter */
+#define TIFF_UINT64_FORMAT "%lu"
+
+/* Signed 64-bit type */
+#define TIFF_INT64_T signed long
+
+#else						// linux/unix 32
+
+/* Signed 64-bit type formatter */
+#define TIFF_INT64_FORMAT "%lld"
+
+/* Unsigned 64-bit type formatter */
+#define TIFF_UINT64_FORMAT "%llu"
+
+/* Signed 64-bit type */
+#define TIFF_INT64_T signed long long
+
+#endif						// end _FX_CPU_
+
+/* Unsigned 64-bit type */
+#define TIFF_UINT64_T unsigned long long
+
+#endif
+
+
+/* Signed size type */
+#ifdef _MSC_VER
+
+#if defined(_WIN64)
+#define TIFF_SSIZE_T signed __int64
+#else
+#define TIFF_SSIZE_T signed int
+#endif
+
+#else
+
+#define TIFF_SSIZE_T signed long
+
+#endif
+
+/* Signed size type formatter */
+#if defined(_WIN64)
+#define TIFF_SSIZE_FORMAT "%I64d"
+#else
+#define TIFF_SSIZE_FORMAT "%ld"
+#endif
+
+/* Pointer difference type */
+#ifdef _MSC_VER
+#define TIFF_PTRDIFF_T long
+#else
+#define TIFF_PTRDIFF_T ptrdiff_t
+#endif
+
+/* Signed 64-bit type */
+/*#define TIFF_INT64_T signed __int64*/
+
+/* Unsigned 64-bit type */
+/*#define TIFF_UINT64_T unsigned __int64*/
+
+/* 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
+# endif
+#endif
+
+#define lfind _lfind
+
+#define BSDTYPES
+
+/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */
+#define HOST_FILLORDER FILLORDER_LSB2MSB
+
+/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
+   (Intel) */
+#if _FX_ENDIAN_ == _FX_BIG_ENDIAN_
+# define HOST_BIGENDIAN 1
+#else
+# define HOST_BIGENDIAN 0
+#endif
+
+/* Support CCITT Group 3 & 4 algorithms */
+#define CCITT_SUPPORT 1
+
+/* Support JPEG compression (requires IJG JPEG library) */
+#define JPEG_SUPPORT 1
+
+/* Support LogLuv high dynamic range encoding */
+#define LOGLUV_SUPPORT 1
+
+/* Support LZW algorithm */
+#define LZW_SUPPORT 1
+
+/* Support NeXT 2-bit RLE algorithm */
+#define NEXT_SUPPORT 1
+
+/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation
+   fails with unpatched IJG JPEG library) */
+#define  OJPEG_SUPPORT	1
+
+/* Support Macintosh PackBits algorithm */
+#define PACKBITS_SUPPORT 1
+
+/* Support Pixar log-format algorithm (requires Zlib) */
+#define PIXARLOG_SUPPORT 1
+
+/* Support ThunderScan 4-bit RLE algorithm */
+#define THUNDER_SUPPORT 1
+
+/* Support Deflate compression */
+#define ZIP_SUPPORT 1
+
+/* Support strip chopping (whether or not to convert single-strip uncompressed
+   images to mutiple strips of ~8Kb to reduce memory usage) */
+#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP
+
+/* Enable SubIFD tag (330) support */
+#define SUBIFD_SUPPORT 1
+
+/* Treat extra sample as alpha (default enabled). The RGBA interface will
+   treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many
+   packages produce RGBA files but don't mark the alpha properly. */
+#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1
+
+/* Pick up YCbCr subsampling info from the JPEG data stream to support files
+   lacking the tag (default enabled). */
+#define CHECK_JPEG_YCBCR_SUBSAMPLING 1
+
+/* Support MS MDI magic number files as TIFF */
+#define MDI_SUPPORT 1
+
+/*
+ * Feature support definitions.
+ * XXX: These macros are obsoleted. Don't use them in your apps!
+ * Macros stays here for backward compatibility and should be always defined.
+ */
+#define COLORIMETRY_SUPPORT
+#define YCBCR_SUPPORT
+#define CMYK_SUPPORT
+#define ICC_SUPPORT
+#define PHOTOSHOP_SUPPORT
+#define IPTC_SUPPORT
+
+#endif /* _TIFFCONF_ */
diff --git a/third_party/libtiff/tiffio.h b/third_party/libtiff/tiffio.h
new file mode 100644
index 0000000..038b670
--- /dev/null
+++ b/third_party/libtiff/tiffio.h
@@ -0,0 +1,557 @@
+/* $Id: tiffio.h,v 1.91 2012-07-29 15:45:29 tgl 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
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFIO_
+#define	_TIFFIO_
+
+/*
+ * TIFF I/O Library Definitions.
+ */
+#include "tiff.h"
+#include "tiffvers.h"
+
+/*
+ * TIFF is defined as an incomplete type to hide the
+ * library's internal data structures from clients.
+ */
+typedef struct tiff TIFF;
+
+/*
+ * The following typedefs define the intrinsic size of
+ * data types used in the *exported* interfaces.  These
+ * definitions depend on the proper definition of types
+ * in tiff.h.  Note also that the varargs interface used
+ * to pass tag types and values uses the types defined in
+ * tiff.h directly.
+ *
+ * NB: ttag_t is unsigned int and not unsigned short because
+ *     ANSI C requires that the type before the ellipsis be a
+ *     promoted type (i.e. one of int, unsigned int, pointer,
+ *     or double) and because we defined pseudo-tags that are
+ *     outside the range of legal Aldus-assigned tags.
+ * NB: tsize_t is int32 and not uint32 because some functions
+ *     return -1.
+ * NB: toff_t is not off_t for many reasons; TIFFs max out at
+ *     32-bit file offsets, and BigTIFF maxes out at 64-bit
+ *     offsets being the most important, and to ensure use of
+ *     a consistently unsigned type across architectures.
+ *     Prior to libtiff 4.0, this was an unsigned 32 bit type.
+ */
+/*
+ * this is the machine addressing size type, only it's signed, so make it
+ * int32 on 32bit machines, int64 on 64bit machines
+ */
+typedef TIFF_SSIZE_T tmsize_t;
+typedef uint64 toff_t;          /* file offset */
+/* the following are deprecated and should be replaced by their defining
+   counterparts */
+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 tmsize_t tsize_t;       /* i/o size in bytes */
+typedef void* tdata_t;          /* image data ref */
+
+#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32))
+#define __WIN32__
+#endif
+
+/*
+ * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c
+ * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c).
+ *
+ * By default tif_unix.c is assumed.
+ */
+
+#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows)
+#  if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILEIO)
+#    define AVOID_WIN32_FILEIO
+#  endif
+#endif
+
+#if defined(USE_WIN32_FILEIO)
+# define VC_EXTRALEAN
+# include <windows.h>
+# ifdef __WIN32__
+DECLARE_HANDLE(thandle_t);     /* Win32 file handle */
+# else
+typedef HFILE thandle_t;       /* client data handle */
+# endif /* __WIN32__ */
+#else
+typedef void* thandle_t;       /* client data handle */
+#endif /* USE_WIN32_FILEIO */
+
+/*
+ * Flags to pass to TIFFPrintDirectory to control
+ * printing of data structures that are potentially
+ * very large.   Bit-or these flags to enable printing
+ * multiple items.
+ */
+#define TIFFPRINT_NONE	       0x0    /* no extra info */
+#define TIFFPRINT_STRIPS       0x1    /* strips/tiles info */
+#define TIFFPRINT_CURVES       0x2    /* color/gray response curves */
+#define TIFFPRINT_COLORMAP     0x4    /* colormap */
+#define TIFFPRINT_JPEGQTABLES  0x100  /* JPEG Q matrices */
+#define TIFFPRINT_JPEGACTABLES 0x200  /* JPEG AC tables */
+#define TIFFPRINT_JPEGDCTABLES 0x200  /* JPEG DC tables */
+
+/* 
+ * Colour conversion stuff
+ */
+
+/* reference white */
+#define D65_X0 (95.0470F)
+#define D65_Y0 (100.0F)
+#define D65_Z0 (108.8827F)
+
+#define D50_X0 (96.4250F)
+#define D50_Y0 (100.0F)
+#define D50_Z0 (82.4680F)
+
+/* Structure for holding information about a display device. */
+
+typedef unsigned char TIFFRGBValue;               /* 8-bit samples */
+
+typedef struct {
+	float d_mat[3][3];                        /* XYZ -> luminance matrix */
+	float d_YCR;                              /* Light o/p for reference white */
+	float d_YCG;
+	float d_YCB;
+	uint32 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;
+} 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;
+} TIFFYCbCrToRGB;
+
+typedef struct {                                  /* CIE Lab 1976->RGB support */
+	int range;                                /* Size of conversion table */
+#define CIELABTORGB_TABLE_RANGE 1500
+	float rstep, gstep, bstep;
+	float X0, Y0, Z0;                         /* Reference white point */
+	TIFFDisplay display;
+	float Yr2r[CIELABTORGB_TABLE_RANGE + 1];  /* Conversion of Yr to r */
+	float Yg2g[CIELABTORGB_TABLE_RANGE + 1];  /* Conversion of Yg to g */
+	float Yb2b[CIELABTORGB_TABLE_RANGE + 1];  /* Conversion of Yb to b */
+} TIFFCIELabToRGB;
+
+/*
+ * RGBA-style image support.
+ */
+typedef struct _TIFFRGBAImage TIFFRGBAImage;
+/*
+ * The image reading and conversion routines invoke
+ * ``put routines'' to copy/image/whatever tiles of
+ * raw image data.  A default set of routines are 
+ * provided to convert/copy raw image data to 8-bit
+ * packed ABGR format rasters.  Applications can supply
+ * alternate routines that unpack the data into a
+ * different format or, for example, unpack the data
+ * and draw the unpacked raster on the display.
+ */
+typedef void (*tileContigRoutine)
+    (TIFFRGBAImage*, uint32*, 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*);
+/*
+ * 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 */
+
+	uint8* UaToAa;                          /* Unassociated alpha to associated alpha convertion LUT */
+	uint8* Bitdepth16To8;                   /* LUT for conversion from 16bit to 8bit values */
+
+	int row_offset;
+	int col_offset;
+};
+
+/*
+ * Macros for extracting components from the
+ * packed ABGR form returned by TIFFReadRGBAImage.
+ */
+#define TIFFGetR(abgr) ((abgr) & 0xff)
+#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff)
+#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff)
+#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff)
+
+/*
+ * A CODEC is a software package that implements decoding,
+ * encoding, or decoding+encoding of a compression algorithm.
+ * The library provides a collection of builtin codecs.
+ * More codecs may be registered through calls to the library
+ * and/or the builtin implementations may be overridden.
+ */
+typedef int (*TIFFInitMethod)(TIFF*, int);
+typedef struct {
+	char* name;
+	uint16 scheme;
+	TIFFInitMethod init;
+} TIFFCodec;
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* share internal LogLuv conversion routines? */
+#ifndef LOGLUV_PUBLIC
+#define LOGLUV_PUBLIC 1
+#endif
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+#  define __attribute__(x) /*nothing*/
+#endif
+
+#if defined(c_plusplus) || defined(__cplusplus)
+extern "C" {
+#endif
+typedef void (*TIFFErrorHandler)(const char*, const char*, va_list);
+typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list);
+typedef tmsize_t (*TIFFReadWriteProc)(thandle_t, void*, tmsize_t);
+typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int);
+typedef int (*TIFFCloseProc)(thandle_t);
+typedef toff_t (*TIFFSizeProc)(thandle_t);
+typedef int (*TIFFMapFileProc)(thandle_t, void** base, toff_t* size);
+typedef void (*TIFFUnmapFileProc)(thandle_t, void* base, toff_t size);
+typedef void (*TIFFExtendProc)(TIFF*);
+
+extern const char* TIFFGetVersion(void);
+
+extern const TIFFCodec* TIFFFindCODEC(uint16);
+extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod);
+extern void TIFFUnRegisterCODEC(TIFFCodec*);
+extern int TIFFIsCODECConfigured(uint16);
+extern TIFFCodec* TIFFGetConfiguredCODECs(void);
+
+/*
+ * Auxiliary functions.
+ */
+
+extern void* _TIFFmalloc(tmsize_t s);
+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 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 _TIFFField TIFFField;
+typedef struct _TIFFFieldArray TIFFFieldArray;
+
+extern const TIFFField* TIFFFindField(TIFF *, uint32, TIFFDataType);
+extern const TIFFField* TIFFFieldWithTag(TIFF*, uint32);
+extern const TIFFField* TIFFFieldWithName(TIFF*, const char *);
+
+extern uint32 TIFFFieldTag(const TIFFField*);
+extern const char* TIFFFieldName(const TIFFField*);
+extern TIFFDataType TIFFFieldDataType(const TIFFField*);
+extern int TIFFFieldPassCount(const TIFFField*);
+extern int TIFFFieldReadCount(const TIFFField*);
+extern int TIFFFieldWriteCount(const TIFFField*);
+
+typedef int (*TIFFVSetMethod)(TIFF*, uint32, va_list);
+typedef int (*TIFFVGetMethod)(TIFF*, uint32, 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 tag, ...);
+extern int TIFFVGetField(TIFF* tif, uint32 tag, va_list ap);
+extern int TIFFGetFieldDefaulted(TIFF* tif, uint32 tag, ...);
+extern int TIFFVGetFieldDefaulted(TIFF* tif, uint32 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 uint64 TIFFScanlineSize64(TIFF* tif);
+extern tmsize_t TIFFScanlineSize(TIFF* tif);
+extern uint64 TIFFRasterScanlineSize64(TIFF* tif);
+extern tmsize_t TIFFRasterScanlineSize(TIFF* tif);
+extern uint64 TIFFStripSize64(TIFF* tif);
+extern tmsize_t TIFFStripSize(TIFF* tif);
+extern uint64 TIFFRawStripSize64(TIFF* tif, uint32 strip);
+extern tmsize_t TIFFRawStripSize(TIFF* tif, uint32 strip);
+extern uint64 TIFFVStripSize64(TIFF* tif, uint32 nrows);
+extern tmsize_t TIFFVStripSize(TIFF* tif, uint32 nrows);
+extern uint64 TIFFTileRowSize64(TIFF* tif);
+extern tmsize_t TIFFTileRowSize(TIFF* tif);
+extern uint64 TIFFTileSize64(TIFF* tif);
+extern tmsize_t TIFFTileSize(TIFF* tif);
+extern uint64 TIFFVTileSize64(TIFF* tif, uint32 nrows);
+extern tmsize_t TIFFVTileSize(TIFF* tif, uint32 nrows);
+extern uint32 TIFFDefaultStripSize(TIFF* tif, uint32 request);
+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 uint16 TIFFCurrentDirectory(TIFF*);
+extern uint16 TIFFNumberOfDirectories(TIFF*);
+extern uint64 TIFFCurrentDirOffset(TIFF*);
+extern uint32 TIFFCurrentStrip(TIFF*);
+extern uint32 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 TIFFLastDirectory(TIFF*);
+extern int TIFFSetDirectory(TIFF*, uint16);
+extern int TIFFSetSubDirectory(TIFF*, uint64);
+extern int TIFFUnlinkDirectory(TIFF*, uint16);
+extern int TIFFSetField(TIFF*, uint32, ...);
+extern int TIFFVSetField(TIFF*, uint32, va_list);
+extern int TIFFUnsetField(TIFF*, uint32);
+extern int TIFFWriteDirectory(TIFF *);
+extern int TIFFWriteCustomDirectory(TIFF *, uint64 *);
+extern int TIFFCheckpointDirectory(TIFF *);
+extern int TIFFRewriteDirectory(TIFF *);
+
+#if defined(c_plusplus) || defined(__cplusplus)
+extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0);
+extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0);
+extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0);
+extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0);
+extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*,
+    int = ORIENTATION_BOTLEFT, int = 0);
+#else
+extern void TIFFPrintDirectory(TIFF*, FILE*, long);
+extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample);
+extern int TIFFWriteScanline(TIFF* tif, void* buf, uint32 row, uint16 sample);
+extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int);
+extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, int, int);
+#endif
+
+extern int TIFFReadRGBAStrip(TIFF*, uint32, 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 uint32 TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s);
+extern int TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, uint16 s);
+extern uint32 TIFFNumberOfTiles(TIFF*);
+extern tmsize_t TIFFReadTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s);  
+extern tmsize_t TIFFWriteTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s);
+extern uint32 TIFFComputeStrip(TIFF*, uint32, uint16);
+extern uint32 TIFFNumberOfStrips(TIFF*);
+extern tmsize_t TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size);
+extern tmsize_t TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size);  
+extern tmsize_t TIFFReadEncodedTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size);  
+extern tmsize_t TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size);  
+extern tmsize_t TIFFWriteEncodedStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc);
+extern tmsize_t TIFFWriteRawStrip(TIFF* tif, uint32 strip, void* data, tmsize_t cc);  
+extern tmsize_t TIFFWriteEncodedTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc);  
+extern tmsize_t TIFFWriteRawTile(TIFF* tif, uint32 tile, void* data, tmsize_t cc);  
+extern int TIFFDataWidth(TIFFDataType);    /* table of tag datatype widths */
+extern void TIFFSetWriteOffset(TIFF* tif, toff_t off);
+extern void TIFFSwabShort(uint16*);
+extern void TIFFSwabLong(uint32*);
+extern void TIFFSwabLong8(uint64*);
+extern void TIFFSwabFloat(float*);
+extern void TIFFSwabDouble(double*);
+extern void TIFFSwabArrayOfShort(uint16* wp, tmsize_t n);
+extern void TIFFSwabArrayOfTriples(uint8* tp, tmsize_t n);
+extern void TIFFSwabArrayOfLong(uint32* lp, tmsize_t n);
+extern void TIFFSwabArrayOfLong8(uint64* lp, tmsize_t n);
+extern void TIFFSwabArrayOfFloat(float* fp, tmsize_t n);
+extern void TIFFSwabArrayOfDouble(double* dp, tmsize_t n);
+extern void TIFFReverseBits(uint8* cp, tmsize_t n);
+extern const unsigned char* TIFFGetBitRevTable(int);
+
+#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*);
+#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);
+#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);
+#endif
+#endif /* LOGLUV_PUBLIC */
+
+extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, const 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 *);
+
+/****************************************************************************
+ *               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);
+        
+#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/third_party/libtiff/tiffiop.h b/third_party/libtiff/tiffiop.h
new file mode 100644
index 0000000..c647b8d
--- /dev/null
+++ b/third_party/libtiff/tiffiop.h
@@ -0,0 +1,420 @@
+/* $Id: tiffiop.h,v 1.87 2015-08-23 17:49:01 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 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFIOP_
+#define	_TIFFIOP_
+/*
+ * ``Library-private'' definitions.
+ */
+
+#include "tiffconf.h"
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+#ifdef HAVE_ASSERT_H
+# include <assert.h>
+#else
+# define assert(x) 
+#endif
+
+#ifdef HAVE_SEARCH_H
+# include <search.h>
+#else
+extern void *lfind(const void *, const void *, size_t *, size_t,
+		   int (*)(const void *, const void *));
+#endif
+
+#if !defined(HAVE_SNPRINTF) && !defined(HAVE__SNPRINTF)
+#undef snprintf
+#define snprintf _TIFF_snprintf_f
+extern int snprintf(char* str, size_t size, const char* format, ...);
+#endif
+
+#include "tiffio.h"
+
+#include "tif_dir.h"
+
+#ifndef STRIP_SIZE_DEFAULT
+# define STRIP_SIZE_DEFAULT 8192
+#endif
+
+#define    streq(a,b)      (strcmp(a,b) == 0)
+
+#ifndef TRUE
+#define	TRUE	1
+#define	FALSE	0
+#endif
+
+typedef struct client_info {
+    struct client_info *next;
+    void *data;
+    char *name;
+} TIFFClientInfoLink;
+
+/*
+ * Typedefs for ``method pointers'' used internally.
+ * these are depriciated and provided only for backwards compatibility
+ */
+typedef unsigned char tidataval_t;    /* internal image data value type */
+typedef tidataval_t* tidata_t;        /* reference to internal image data */
+
+typedef void (*TIFFVoidMethod)(TIFF*);
+typedef int (*TIFFBoolMethod)(TIFF*);
+typedef int (*TIFFPreMethod)(TIFF*, uint16);
+typedef int (*TIFFCodeMethod)(TIFF* tif, uint8* buf, tmsize_t size, uint16 sample);
+typedef int (*TIFFSeekMethod)(TIFF*, uint32);
+typedef void (*TIFFPostMethod)(TIFF* tif, uint8* buf, tmsize_t size);
+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 */
+	#define TIFF_BIGTIFF     0x80000 /* read/write bigtiff */
+        #define TIFF_BUF4WRITE  0x100000 /* rawcc bytes are for writing */
+        #define TIFF_DIRTYSTRIP 0x200000 /* stripoffsets/stripbytecount dirty*/
+        #define TIFF_PERSAMPLE  0x400000 /* get/set per sample tags as arrays */
+        #define TIFF_BUFFERMMAP 0x800000 /* read buffer (tif_rawdata) points into mmap() memory */
+	uint64               tif_diroff;       /* file offset of current directory */
+	uint64               tif_nextdiroff;   /* file offset of following directory */
+	uint64*              tif_dirlist;      /* list of offsets to already seen directories to prevent IFD looping */
+	uint16               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 */
+	union {
+		TIFFHeaderCommon common;
+		TIFFHeaderClassic classic;
+		TIFFHeaderBig big;
+	} tif_header;
+	uint16               tif_header_size;  /* file's header block and its length */
+	uint32               tif_row;          /* current scanline */
+	uint16               tif_curdir;       /* current directory (index) */
+	uint32               tif_curstrip;     /* current strip for read/write */
+	uint64               tif_curoff;       /* current offset for read/write */
+	uint64               tif_dataoff;      /* current offset for writing dir */
+	/* SubIFD support */
+	uint16               tif_nsubifd;      /* remaining subifds to write */
+	uint64               tif_subifdoff;    /* offset for patching SubIFD link */
+	/* tiling support */
+	uint32               tif_col;          /* current column (offset by row too) */
+	uint32               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*               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*               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*               tif_rawcp;        /* current spot in raw buffer */
+	tmsize_t             tif_rawcc;        /* bytes unread from raw buffer */
+	/* memory-mapped file support */
+	uint8*               tif_base;         /* base of mapped file */
+	tmsize_t             tif_size;         /* size of mapped file region (bytes, thus tmsize_t) */
+	TIFFMapFileProc      tif_mapproc;      /* map file method */
+	TIFFUnmapFileProc    tif_unmapproc;    /* unmap file method */
+	/* input/output callback methods */
+	thandle_t            tif_clientdata;   /* callback parameter */
+	TIFFReadWriteProc    tif_readproc;     /* read method */
+	TIFFReadWriteProc    tif_writeproc;    /* write method */
+	TIFFSeekProc         tif_seekproc;     /* lseek method */
+	TIFFCloseProc        tif_closeproc;    /* close method */
+	TIFFSizeProc         tif_sizeproc;     /* filesize method */
+	/* post-decoding support */
+	TIFFPostMethod       tif_postdecode;   /* post decoding routine */
+	/* tag support */
+	TIFFField**          tif_fields;       /* sorted table of registered tags */
+	size_t               tif_nfields;      /* # entries in registered tag table */
+	const TIFFField*     tif_foundfield;   /* cached pointer to already found tag */
+	TIFFTagMethods       tif_tagmethods;   /* tag get/set/print routines */
+	TIFFClientInfoLink*  tif_clientinfo;   /* extra client information. */
+	/* Backward compatibility stuff. We need these two fields for
+	 * setting up an old tag extension scheme. */
+	TIFFFieldArray*      tif_fieldscompat;
+	size_t               tif_nfieldscompat;
+};
+
+#define isPseudoTag(t) (t > 0xffff)            /* is tag value normal or pseudo */
+
+#define isTiled(tif) (((tif)->tif_flags & TIFF_ISTILED) != 0)
+#define isMapped(tif) (((tif)->tif_flags & TIFF_MAPPED) != 0)
+#define isFillOrder(tif, o) (((tif)->tif_flags & (o)) != 0)
+#define isUpSampled(tif) (((tif)->tif_flags & TIFF_UPSAMPLED) != 0)
+#define TIFFReadFile(tif, buf, size) \
+	((*(tif)->tif_readproc)((tif)->tif_clientdata,(buf),(size)))
+#define TIFFWriteFile(tif, buf, size) \
+	((*(tif)->tif_writeproc)((tif)->tif_clientdata,(buf),(size)))
+#define TIFFSeekFile(tif, off, whence) \
+	((*(tif)->tif_seekproc)((tif)->tif_clientdata,(off),(whence)))
+#define TIFFCloseFile(tif) \
+	((*(tif)->tif_closeproc)((tif)->tif_clientdata))
+#define TIFFGetFileSize(tif) \
+	((*(tif)->tif_sizeproc)((tif)->tif_clientdata))
+#define TIFFMapFileContents(tif, paddr, psize) \
+	((*(tif)->tif_mapproc)((tif)->tif_clientdata,(paddr),(psize)))
+#define TIFFUnmapFileContents(tif, addr, size) \
+	((*(tif)->tif_unmapproc)((tif)->tif_clientdata,(addr),(size)))
+
+/*
+ * Default Read/Seek/Write definitions.
+ */
+#ifndef ReadOK
+#define ReadOK(tif, buf, size) \
+	(TIFFReadFile((tif),(buf),(size))==(size))
+#endif
+#ifndef SeekOK
+#define SeekOK(tif, off) \
+	(TIFFSeekFile((tif),(off),SEEK_SET)==(off))
+#endif
+#ifndef WriteOK
+#define WriteOK(tif, buf, size) \
+	(TIFFWriteFile((tif),(buf),(size))==(size))
+#endif
+
+/* NB: the uint32 casts are to silence certain ANSI-C compilers */
+#define TIFFhowmany_32(x, y) (((uint32)x < (0xffffffff - (uint32)(y-1))) ? \
+			   ((((uint32)(x))+(((uint32)(y))-1))/((uint32)(y))) : \
+			   0U)
+#define TIFFhowmany8_32(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
+#define TIFFroundup_32(x, y) (TIFFhowmany_32(x,y)*(y))
+#define TIFFhowmany_64(x, y) ((((uint64)(x))+(((uint64)(y))-1))/((uint64)(y)))
+#define TIFFhowmany8_64(x) (((x)&0x07)?((uint64)(x)>>3)+1:(uint64)(x)>>3)
+#define TIFFroundup_64(x, y) (TIFFhowmany_64(x,y)*(y))
+
+/* 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)
+
+#define TIFFmax(A,B) ((A)>(B)?(A):(B))
+#define TIFFmin(A,B) ((A)<(B)?(A):(B))
+
+#define TIFFArrayCount(a) (sizeof (a) / sizeof ((a)[0]))
+
+/*
+  Support for large files.
+
+  Windows read/write APIs support only 'unsigned int' rather than 'size_t'.
+  Windows off_t is only 32-bit, even in 64-bit builds.
+*/
+#if defined(HAVE_FSEEKO)
+/*
+  Use fseeko() and ftello() if they are available since they use
+  'off_t' rather than 'long'.  It is wrong to use fseeko() and
+  ftello() only on systems with special LFS support since some systems
+  (e.g. FreeBSD) support a 64-bit off_t by default.
+
+  For MinGW, __MSVCRT_VERSION__ must be at least 0x800 to expose these
+  interfaces. The MinGW compiler must support the requested version.  MinGW
+  does not distribute the CRT (it is supplied by Microsoft) so the correct CRT
+  must be available on the target computer in order for the program to run.
+*/
+#if defined(HAVE_FSEEKO)
+#  define fseek(stream,offset,whence)  fseeko(stream,offset,whence)
+#  define ftell(stream,offset,whence)  ftello(stream,offset,whence)
+#endif
+#endif
+#if defined(__WIN32__) && \
+        !(defined(_MSC_VER) && _MSC_VER < 1400) && \
+        !(defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x800)
+typedef unsigned int TIFFIOSize_t;
+#define _TIFF_lseek_f(fildes,offset,whence)  _lseeki64(fildes,/* __int64 */ offset,whence)
+/* #define _TIFF_tell_f(fildes) /\* __int64 *\/ _telli64(fildes) */
+#define _TIFF_fseek_f(stream,offset,whence) _fseeki64(stream,/* __int64 */ offset,whence)
+#define _TIFF_fstat_f(fildes,stat_buff) _fstati64(fildes,/* struct _stati64 */ stat_buff)
+/* #define _TIFF_ftell_f(stream) /\* __int64 *\/ _ftelli64(stream) */
+/* #define _TIFF_stat_f(path,stat_buff) _stati64(path,/\* struct _stati64 *\/ stat_buff) */
+#define _TIFF_stat_s struct _stati64
+#define _TIFF_off_t __int64
+#else
+typedef size_t TIFFIOSize_t;
+#define _TIFF_lseek_f(fildes,offset,whence) lseek(fildes,offset,whence)
+/* #define _TIFF_tell_f(fildes) (_TIFF_lseek_f(fildes,0,SEEK_CUR)) */
+#define _TIFF_fseek_f(stream,offset,whence) fseek(stream,offset,whence)
+#define _TIFF_fstat_f(fildes,stat_buff) fstat(fildes,stat_buff)
+/* #define _TIFF_ftell_f(stream) ftell(stream) */
+/* #define _TIFF_stat_f(path,stat_buff) stat(path,stat_buff) */
+#define _TIFF_stat_s struct stat
+#define _TIFF_off_t off_t
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+extern int _TIFFgetMode(const char* mode, const char* module);
+extern int _TIFFNoRowEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s);
+extern int _TIFFNoStripEncode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s);
+extern int _TIFFNoTileEncode(TIFF*, uint8* pp, tmsize_t cc, uint16 s);
+extern int _TIFFNoRowDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s);
+extern int _TIFFNoStripDecode(TIFF* tif, uint8* pp, tmsize_t cc, uint16 s);
+extern int _TIFFNoTileDecode(TIFF*, uint8* pp, tmsize_t cc, uint16 s);
+extern void _TIFFNoPostDecode(TIFF* tif, uint8* buf, tmsize_t cc);
+extern int _TIFFNoPreCode(TIFF* tif, uint16 s);
+extern int _TIFFNoSeek(TIFF* tif, uint32 off);
+extern void _TIFFSwab16BitData(TIFF* tif, uint8* buf, tmsize_t cc);
+extern void _TIFFSwab24BitData(TIFF* tif, uint8* buf, tmsize_t cc);
+extern void _TIFFSwab32BitData(TIFF* tif, uint8* buf, tmsize_t cc);
+extern void _TIFFSwab64BitData(TIFF* tif, uint8* buf, tmsize_t cc);
+extern int TIFFFlushData1(TIFF* tif);
+extern int TIFFDefaultDirectory(TIFF* tif);
+extern void _TIFFSetDefaultCompressionState(TIFF* tif);
+extern int _TIFFRewriteField(TIFF *, uint16, TIFFDataType, tmsize_t, void *);
+extern int TIFFSetCompressionScheme(TIFF* tif, int scheme);
+extern int TIFFSetDefaultCompressionState(TIFF* tif);
+extern uint32 _TIFFDefaultStripSize(TIFF* tif, uint32 s);
+extern void _TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th);
+extern int _TIFFDataSize(TIFFDataType type);
+
+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 uint32 _TIFFMultiply32(TIFF*, uint32, uint32, const char*);
+extern uint64 _TIFFMultiply64(TIFF*, uint64, uint64, 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);
+extern float _TIFFUInt64ToFloat(uint64);
+
+extern int TIFFInitDumpMode(TIFF*, int);
+#ifdef PACKBITS_SUPPORT
+extern int TIFFInitPackBits(TIFF*, int);
+#endif
+#ifdef CCITT_SUPPORT
+extern int TIFFInitCCITTRLE(TIFF*, int), TIFFInitCCITTRLEW(TIFF*, int);
+extern int TIFFInitCCITTFax3(TIFF*, int), TIFFInitCCITTFax4(TIFF*, int);
+#endif
+#ifdef THUNDER_SUPPORT
+extern int TIFFInitThunderScan(TIFF*, int);
+#endif
+#ifdef NEXT_SUPPORT
+extern int TIFFInitNeXT(TIFF*, int);
+#endif
+#ifdef LZW_SUPPORT
+extern int TIFFInitLZW(TIFF*, int);
+#endif
+#ifdef OJPEG_SUPPORT
+extern int TIFFInitOJPEG(TIFF*, int);
+#endif
+#ifdef JPEG_SUPPORT
+extern int TIFFInitJPEG(TIFF*, int);
+#endif
+#ifdef JBIG_SUPPORT
+extern int TIFFInitJBIG(TIFF*, int);
+#endif
+#ifdef ZIP_SUPPORT
+extern int TIFFInitZIP(TIFF*, int);
+#endif
+#ifdef PIXARLOG_SUPPORT
+extern int TIFFInitPixarLog(TIFF*, int);
+#endif
+#ifdef LOGLUV_SUPPORT
+extern int TIFFInitSGILog(TIFF*, int);
+#endif
+#ifdef LZMA_SUPPORT
+extern int TIFFInitLZMA(TIFF*, int);
+#endif
+#ifdef VMS
+extern const TIFFCodec _TIFFBuiltinCODECS[];
+#else
+extern TIFFCodec _TIFFBuiltinCODECS[];
+#endif
+
+#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/third_party/libtiff/uvcode.h b/third_party/libtiff/uvcode.h
new file mode 100644
index 0000000..50f11d7
--- /dev/null
+++ b/third_party/libtiff/uvcode.h
@@ -0,0 +1,180 @@
+/* Version 1.0 generated April 7, 1997 by Greg Ward Larson, SGI */
+#define UV_SQSIZ	(float)0.003500
+#define UV_NDIVS	16289
+#define UV_VSTART	(float)0.016940
+#define UV_NVS		163
+static 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:
+ */