summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/dosdjgpp/Makefile.lib2
-rw-r--r--contrib/dosdjgpp/Makefile.tools2
-rw-r--r--contrib/dosdjgpp/Makefile.top2
-rw-r--r--contrib/mfs/README37
-rw-r--r--contrib/mfs/mfs_file.c579
-rw-r--r--contrib/pds/README90
-rw-r--r--contrib/pds/tif_imageiter.c518
-rw-r--r--contrib/pds/tif_imageiter.h57
-rw-r--r--contrib/pds/tif_pdsdirread.c1124
-rw-r--r--contrib/pds/tif_pdsdirwrite.c964
-rw-r--r--contrib/ras/README10
-rw-r--r--contrib/winnt/README.console182
12 files changed, 3564 insertions, 3 deletions
diff --git a/contrib/dosdjgpp/Makefile.lib b/contrib/dosdjgpp/Makefile.lib
index fd4fa764..f0ccff3f 100644
--- a/contrib/dosdjgpp/Makefile.lib
+++ b/contrib/dosdjgpp/Makefile.lib
@@ -1,4 +1,4 @@
-# $Header: /usr/people/sam/tiff/libtiff/RCS/Makefile.in,v 1.28 1996/02/09 05:55:00 sam Exp $
+# $Header: /d1/sam/tiff/contrib/dosdjgpp/RCS/Makefile.lib,v 1.1 1997/08/27 22:39:50 sam Exp $
#
# manually derived from Makefile.in for DJGPP v2.x (GNU C for DOS/386).
#
diff --git a/contrib/dosdjgpp/Makefile.tools b/contrib/dosdjgpp/Makefile.tools
index 68869b77..d4928d62 100644
--- a/contrib/dosdjgpp/Makefile.tools
+++ b/contrib/dosdjgpp/Makefile.tools
@@ -1,4 +1,4 @@
-# $Header: /usr/people/sam/tiff/tools/RCS/Makefile.in,v 1.17 1996/02/09 05:55:00 sam Exp $
+# $Header: /d1/sam/tiff/contrib/dosdjgpp/RCS/Makefile.tools,v 1.1 1997/08/27 22:39:50 sam Exp $
#
# manually derived from Makefile.in for DJGPP v2.x (GNU C for DOS/386).
#
diff --git a/contrib/dosdjgpp/Makefile.top b/contrib/dosdjgpp/Makefile.top
index 1d60696e..d6bcee4c 100644
--- a/contrib/dosdjgpp/Makefile.top
+++ b/contrib/dosdjgpp/Makefile.top
@@ -1,5 +1,5 @@
#! smake
-# $Header: /usr/people/sam/tiff/RCS/Makefile.in,v 1.44 1996/02/09 21:29:19 sam Exp $
+# $Header: /d1/sam/tiff/contrib/dosdjgpp/RCS/Makefile.top,v 1.1 1997/08/27 22:39:50 sam Exp $
#
# manually derived from Makefile.in (though basically nothing remains)
# for DJGPP v2.x (GNU C for DOS/386).
diff --git a/contrib/mfs/README b/contrib/mfs/README
new file mode 100644
index 00000000..6f9befbc
--- /dev/null
+++ b/contrib/mfs/README
@@ -0,0 +1,37 @@
+Date: Mon, 23 Jun 1997 13:30:48 +0200
+To: <sam@cthulhu.engr.sgi.com>
+
+From: "Mike Johnson" <mikehunt@swipnet.se>
+Subject: libtiff - Thanks
+
+Return-Path: mikehunt@swipnet.se
+Delivery-Date: Mon, 23 Jun 1997 06:53:39 -0700
+
+Hi Sam,
+
+I noticed in the README from libtiff that you would like to know about
+what people have done with libtiff, so I thought I would drop you a
+line.
+
+We have used libtiff to create and convert TIFF images of financial
+documents which are sent from and to major document processing systems
+in Sweden and Denmark.
+
+I would like to express my deep gratitude to yourself and Sillicon
+Graphics for making this excellent library available for public use.
+There is obviously a lot of work that has gone in to libtiff and the
+quality of the code and documentation is an example to others.
+
+One thing that libtiff did not do was work on a memory area rather than
+files. In my applications I had already read a TIFF or other format
+file in to memory and did not want to waste I/O writing it out again
+for libtiff's benefit. I therefore constructed a set of functions to
+pass up to TIFFClientOpen to simulate a file in memory. I have attached
+my mfs (memory file system) source code for you to use or junk, as you
+see fit. :-)
+
+Once again, thanks very much for making my life simpler.
+
+Best Regards,
+
+Mike Johnson.
diff --git a/contrib/mfs/mfs_file.c b/contrib/mfs/mfs_file.c
new file mode 100644
index 00000000..fa408dab
--- /dev/null
+++ b/contrib/mfs/mfs_file.c
@@ -0,0 +1,579 @@
+/*
+--------------------------------------------------------------------------------
+- Module : mem_file.c
+- Description : A general purpose library for manipulating a memory area
+- as if it were a file.
+- mfs_ stands for memory file system.
+- Author : Mike Johnson - Banctec AB 03/07/96
+-
+--------------------------------------------------------------------------------
+*/
+
+/*
+
+Copyright (c) 1996 Mike Johnson
+Copyright (c) 1996 BancTec AB
+
+Permission to use, copy, modify, distribute, and sell this software
+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
+Mike Johnson and BancTec may not be used in any advertising or
+publicity relating to the software.
+
+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 MIKE JOHNSON OR BANCTEC 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.
+
+*/
+
+
+/*
+--------------------------------------------------------------------------------
+- Includes
+--------------------------------------------------------------------------------
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+--------------------------------------------------------------------------------
+- Definitions
+--------------------------------------------------------------------------------
+*/
+
+#define MAX_BUFFS 20
+#define FALSE 0
+#define TRUE 1
+
+/*
+--------------------------------------------------------------------------------
+- Globals
+--------------------------------------------------------------------------------
+*/
+
+static char *buf[MAX_BUFFS]; /* Memory for each open buf */
+static long buf_off[MAX_BUFFS]; /* File pointer for each buf */
+static long buf_size[MAX_BUFFS]; /* Count of bytes allocated for each buf */
+static long fds[MAX_BUFFS]; /* File descriptor status */
+static int buf_mode[MAX_BUFFS]; /* Mode of buffer (r, w, a) */
+
+static int library_init_done = FALSE;
+
+
+/*
+--------------------------------------------------------------------------------
+- Function prototypes
+--------------------------------------------------------------------------------
+*/
+
+int mfs_open (void *ptr, int size, char *mode);
+int mfs_lseek (int fd, int offset, int whence);
+int mfs_read (int fd, void *buf, int size);
+int mfs_write (int fd, void *buf, int size);
+int mfs_size (int fd);
+int mfs_map (int fd, char **addr, size_t *len);
+int mfs_unmap (int fd);
+int mfs_close (int fd);
+static int extend_mem_file (int fd, int size);
+static void mem_init ();
+
+/*
+--------------------------------------------------------------------------------
+- Function code
+--------------------------------------------------------------------------------
+*/
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_open ()
+-
+- Arguments : Pointer to allocated buffer, initial size of buffer,
+- mode spec (r, w, a)
+-
+- Returns : File descriptor or -1 if error.
+-
+- Description : Register this area of memory (which has been allocated
+- and has a file read into it) under the mem_file library.
+- A file descriptor is returned which can the be passed
+- back to TIFFClientOpen and used as if it was a disk
+- based fd.
+- If the call is for mode 'w' then pass (void *)NULL as
+- the buffer and zero size and the library will
+- allocate memory for you.
+- If the mode is append then pass (void *)NULL and size
+- zero or with a valid address.
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_open (void *buffer, int size, char *mode)
+{
+ int ret, i;
+ void *tmp;
+
+ if (library_init_done == FALSE)
+ {
+ mem_init ();
+ library_init_done = TRUE;
+ }
+
+ ret = -1;
+
+ /* Find a free fd */
+
+ for (i = 0; i < MAX_BUFFS; i++)
+ {
+ if (fds[i] == -1)
+ {
+ ret = i;
+ break;
+ }
+ }
+
+ if (i == MAX_BUFFS) /* No more free descriptors */
+ {
+ ret = -1;
+ errno = EMFILE;
+ }
+
+ if (ret >= 0 && *mode == 'r')
+ {
+ if (buffer == (void *)NULL)
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+ else
+ {
+ buf[ret] = (char *)buffer;
+ buf_size[ret] = size;
+ buf_off[ret] = 0;
+ }
+ }
+ else if (ret >= 0 && *mode == 'w')
+ {
+
+ if (buffer != (void *)NULL)
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+
+ else
+ {
+ tmp = malloc (0); /* Get a pointer */
+ if (tmp == (void *)NULL)
+ {
+ ret = -1;
+ errno = EDQUOT;
+ }
+ else
+ {
+ buf[ret] = (char *)tmp;
+ buf_size[ret] = 0;
+ buf_off[ret] = 0;
+ }
+ }
+ }
+ else if (ret >= 0 && *mode == 'a')
+ {
+ if (buffer == (void *) NULL) /* Create space for client */
+ {
+ tmp = malloc (0); /* Get a pointer */
+ if (tmp == (void *)NULL)
+ {
+ ret = -1;
+ errno = EDQUOT;
+ }
+ else
+ {
+ buf[ret] = (char *)tmp;
+ buf_size[ret] = 0;
+ buf_off[ret] = 0;
+ }
+ }
+ else /* Client has file read in already */
+ {
+ buf[ret] = (char *)buffer;
+ buf_size[ret] = size;
+ buf_off[ret] = 0;
+ }
+ }
+ else /* Some other invalid combination of parameters */
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+
+ if (ret != -1)
+ {
+ fds[ret] = 0;
+ buf_mode[ret] = *mode;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_lseek ()
+-
+- Arguments : File descriptor, offset, whence
+-
+- Returns : as per man lseek (2)
+-
+- Description : Does the same as lseek (2) except on a memory based file.
+- Note: the memory area will be extended if the caller
+- attempts to seek past the current end of file (memory).
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_lseek (int fd, int offset, int whence)
+{
+ int ret;
+ long test_off;
+
+ if (fds[fd] == -1) /* Not open */
+ {
+ ret = -1;
+ errno = EBADF;
+ }
+ else if (offset < 0 && whence == SEEK_SET)
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+ else
+ {
+ switch (whence)
+ {
+ case SEEK_SET:
+ if (offset > buf_size[fd])
+ extend_mem_file (fd, offset);
+ buf_off[fd] = offset;
+ ret = offset;
+ break;
+
+ case SEEK_CUR:
+ test_off = buf_off[fd] + offset;
+
+ if (test_off < 0)
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+ else
+ {
+ if (test_off > buf_size[fd])
+ extend_mem_file (fd, test_off);
+ buf_off[fd] = test_off;
+ ret = test_off;
+ }
+ break;
+
+ case SEEK_END:
+ test_off = buf_size[fd] + offset;
+
+ if (test_off < 0)
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+ else
+ {
+ if (test_off > buf_size[fd])
+ extend_mem_file (fd, test_off);
+ buf_off[fd] = test_off;
+ ret = test_off;
+ }
+ break;
+
+ default:
+ errno = EINVAL;
+ ret = -1;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_read ()
+-
+- Arguments : File descriptor, buffer, size
+-
+- Returns : as per man read (2)
+-
+- Description : Does the same as read (2) except on a memory based file.
+- Note: An attempt to read past the end of memory currently
+- allocated to the file will return 0 (End Of File)
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_read (int fd, void *clnt_buf, int size)
+{
+ int ret;
+
+ if (fds[fd] == -1 || buf_mode[fd] != 'r')
+ {
+ /* File is either not open, or not opened for read */
+
+ ret = -1;
+ errno = EBADF;
+ }
+ else if (buf_off[fd] + size > buf_size[fd])
+ {
+ ret = 0; /* EOF */
+ }
+ else
+ {
+ memcpy (clnt_buf, (void *) (buf[fd] + buf_off[fd]), size);
+ buf_off[fd] = buf_off[fd] + size;
+ ret = size;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_write ()
+-
+- Arguments : File descriptor, buffer, size
+-
+- Returns : as per man write (2)
+-
+- Description : Does the same as write (2) except on a memory based file.
+- Note: the memory area will be extended if the caller
+- attempts to write past the current end of file (memory).
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_write (int fd, void *clnt_buf, int size)
+{
+ int ret;
+
+ if (fds[fd] == -1 || buf_mode[fd] == 'r')
+ {
+ /* Either the file is not open or it is opened for reading only */
+
+ ret = -1;
+ errno = EBADF;
+ }
+ else if (buf_mode[fd] == 'w')
+ {
+ /* Write */
+
+ if (buf_off[fd] + size > buf_size[fd])
+ {
+ extend_mem_file (fd, buf_off[fd] + size);
+ buf_size[fd] = (buf_off[fd] + size);
+ }
+
+ memcpy ((buf[fd] + buf_off[fd]), clnt_buf, size);
+ buf_off[fd] = buf_off[fd] + size;
+
+ ret = size;
+ }
+ else
+ {
+ /* Append */
+
+ if (buf_off[fd] != buf_size[fd])
+ buf_off[fd] = buf_size[fd];
+
+ extend_mem_file (fd, buf_off[fd] + size);
+ buf_size[fd] += size;
+
+ memcpy ((buf[fd] + buf_off[fd]), clnt_buf, size);
+ buf_off[fd] = buf_off[fd] + size;
+
+ ret = size;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_size ()
+-
+- Arguments : File descriptor
+-
+- Returns : integer file size
+-
+- Description : This function returns the current size of the file in bytes.
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_size (int fd)
+{
+ int ret;
+
+ if (fds[fd] == -1) /* Not open */
+ {
+ ret = -1;
+ errno = EBADF;
+ }
+ else
+ ret = buf_size[fd];
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_map ()
+-
+- Arguments : File descriptor, ptr to address, ptr to length
+-
+- Returns : Map status (succeeded or otherwise)
+-
+- Description : This function tells the client where the file is mapped
+- in memory and what size the mapped area is. It is provided
+- to satisfy the MapProc function in libtiff. It pretends
+- that the file has been mmap (2)ped.
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_map (int fd, char **addr, size_t *len)
+{
+ int ret;
+
+ if (fds[fd] == -1) /* Not open */
+ {
+ ret = -1;
+ errno = EBADF;
+ }
+ else
+ {
+ *addr = buf[fd];
+ *len = buf_size[fd];
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_unmap ()
+-
+- Arguments : File descriptor
+-
+- Returns : UnMap status (succeeded or otherwise)
+-
+- Description : This function does nothing as the file is always
+- in memory.
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_unmap (int fd)
+{
+ return (0);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_close ()
+-
+- Arguments : File descriptor
+-
+- Returns : close status (succeeded or otherwise)
+-
+- Description : Close the open memory file. (Make fd available again.)
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_close (int fd)
+{
+ int ret;
+
+ if (fds[fd] == -1) /* Not open */
+ {
+ ret = -1;
+ errno = EBADF;
+ }
+ else
+ {
+ fds[fd] = -1;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : extend_mem_file ()
+-
+- Arguments : File descriptor, length to extend to.
+-
+- Returns : 0 - All OK, -1 - realloc () failed.
+-
+- Description : Increase the amount of memory allocated to a file.
+-
+--------------------------------------------------------------------------------
+*/
+
+static int extend_mem_file (int fd, int size)
+{
+ void *new_mem;
+ int ret;
+
+ if ((new_mem = realloc (buf[fd], size)) == (void *) NULL)
+ ret = -1;
+ else
+ {
+ buf[fd] = (char *) new_mem;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mem_init ()
+-
+- Arguments : None
+-
+- Returns : void
+-
+- Description : Initialise the library.
+-
+--------------------------------------------------------------------------------
+*/
+
+static void mem_init ()
+{
+ int i;
+
+ for (i = 0; i < MAX_BUFFS; i++)
+ {
+ fds[i] = -1;
+ buf[i] = (char *)NULL;
+ buf_size[i] = 0;
+ buf_off[i] = 0;
+ }
+}
+
diff --git a/contrib/pds/README b/contrib/pds/README
new file mode 100644
index 00000000..b9abc6b3
--- /dev/null
+++ b/contrib/pds/README
@@ -0,0 +1,90 @@
+Date: Fri, 01 Aug 1997 20:14:52 MDT
+To: Sam Leffler <sam@cthulhu.engr.sgi.com>
+
+From: "Conrad J. Poelman (WSAT)" <poelmanc@plk.af.mil>
+Subject: Potential TIFF library additions
+
+Delivery-Date: Fri, 01 Aug 1997 19:21:06 -0700
+
+Sam,
+
+You probably don't remember me, but I sent in a couple of bug fixes
+regarding the TIFF library about a 16 months ago or so...
+
+I just wanted to send you two other additions that I have made to our
+local version of the TIFF library in hopes that you will want to
+incorporate them into your next major release of the TIFF library.
+(These additions are based on TIFF version 3.4beta31, but they sit on
+top of the library so they shouldn't be much trouble to incorporate them
+into any more recent version.) They are internally documented to a
+reasonable extent and we've been successfully using them in our code
+here for over a year. If you think they would make good additions to the
+TIFF library, I'd be happy to clean them up more, document them more,
+and/or integrate them with the latest version of the TIFF library, but I
+figured I'd see if you were interested in using them before I went to
+all that trouble.
+
+TIFF Image Iterator
+-------------------
+Your ReadRGBA() routine works well for reading many different formats
+(TILED, STIP, compressed or not, etc.) of the most basic types of data
+(RGB, 8-bit greyscale, 8-bit colormapped) into an SGI-style data array,
+and serves as a good template for users with other needs. I used it as
+an exmaple of how to make an iterator which, rather than fill a data
+array, calls an arbitrary user-supplied callback function for each
+"chunk" of data - that "chunk" might be a strip or a tile, and might
+have one sample-per-pixel or two, and might be 8-bit data or 16-bit or
+24-bit. The callback function can do whatever it wants with the data -
+store it in a big array, convert it to RGBA, or draw it directly to the
+screen. I was able to use this iterator to read 16-bit greyscale and 32-
+and 64-bit floating point data, which wasn't possible with ReadRGBA().
+
+I have tested this routine with 8- and 16-bit greyscale data as well as
+with 32- and 64-bit floating point data. I believe nearly all of our
+data is organized in strips, so actually I'd appreciate it if you had
+some tiled images that I could test it with.
+
+It should certainly be possible and would be cleanest to reimplement
+ReadRGBA() in terms of the image iterator, but I haven't done that.
+
+
+Private Sub-Directory Read/Write
+--------------------------------
+TIFF-PL is a Phillips Laboratory extension to the TIFF tags that allows
+us to store satellite imaging-specific information in a TIFF format,
+such as the satellite's trajectory, the imaging time, etc. In order to
+give us the flexibility to modify the tag definitions without getting
+approval from the TIFF committee every time, we were given only three
+TIFF tags - a PL signature, a PL version number, and PL directory
+offset, which lists the position in the file at which to find a private
+sub-directory of tags-value pairs. So I wrote two routines:
+TIFFWritePrivateDataSubDirectory(), which takes a list of tags and a
+"get" function and writes the tag values into the TIFF file, returning
+the offset within the file at which it wrote the directory; and
+TIFFReadPrivateDataSubDirectory(), which takes an offset, a list of
+tags, and a "set" function and reads all the data from the private
+directory. The functions themselves are pretty simple. (The files are
+huge because I had to basically copy all of the tif_dirread.c and
+tif_dirwrite.c files in order to access the various fetching routines
+which were all declared static and therefore inaccessible in the TIFF
+library.)
+
+
+I'm including the four source files (tif_imgiter.h, tif_imgiter.c,
+tif_pdsdirread.c, tif_pdsdirwrite.c) in case you want to take a look at
+them. I can also send you some sample code that uses them if you like.
+If you're interested in having them incorporated into the standard TIFF
+library, I'd be happy to do that integration and clean up and document
+the routines. (For example, I've already realized that instead of
+limiting the SEP callback function to three bands (R,G,B) it should take
+an array to enable the handling of n-banded multi-spectral data...) If
+not, I'll just leave them as they are, since they work fine for us now.
+
+Holler if you have any questions.
+
+-- Conrad
+__________________________________________________________________
+ Capt Conrad J. Poelman PL/WSAT (Phillips Laboratory)
+ 505-846-4347 3550 Aberdeen Ave SE
+ (FAX) 505-846-4374 Kirtland AFB, NM 87117-5776
+
diff --git a/contrib/pds/tif_imageiter.c b/contrib/pds/tif_imageiter.c
new file mode 100644
index 00000000..9c6c4370
--- /dev/null
+++ b/contrib/pds/tif_imageiter.c
@@ -0,0 +1,518 @@
+/* $Header: /d1/sam/tiff/contrib/pds/RCS/tif_imageiter.c,v 1.1 1997/08/29 23:12:56 sam Exp $ */
+
+/*
+ * Copyright (c) 1991-1996 Sam Leffler
+ * Copyright (c) 1991-1996 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
+ *
+ * Written by Conrad J. Poelman, PL/WSAT, Kirtland AFB, NM on 26 Mar 96.
+ *
+ * This file contains code to allow a calling program to "iterate" over each
+ * pixels in an image as it is read from the file. The iterator takes care of
+ * reading strips versus (possibly clipped) tiles, decoding the information
+ * according to the decoding method, and so on, so that calling program can
+ * ignore those details. The calling program does, however, need to be
+ * conscious of the type of the pixel data that it is receiving.
+ *
+ * For reasons of efficiency, the callback function actually gets called for
+ * "blocks" of pixels rather than for individual pixels. The format of the
+ * callback arguments is given below.
+ *
+ * This code was taken from TIFFReadRGBAImage() in tif_getimage.c of the original
+ * TIFF distribution, and simplified and generalized to provide this general
+ * iteration capability. Those routines could certainly be re-implemented in terms
+ * of a TIFFImageIter if desired.
+ *
+ */
+#include "tiffiop.h"
+#include "tif_imgiter.h"
+#include <assert.h>
+#include <stdio.h>
+
+static int gtTileContig(TIFFImageIter*, void *udata, uint32, uint32);
+static int gtTileSeparate(TIFFImageIter*, void *udata, uint32, uint32);
+static int gtStripContig(TIFFImageIter*, void *udata, uint32, uint32);
+static int gtStripSeparate(TIFFImageIter*, void *udata, uint32, uint32);
+
+static const char photoTag[] = "PhotometricInterpretation";
+
+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
+TIFFImageIterBegin(TIFFImageIter* img, TIFF* tif, int stop, char emsg[1024])
+{
+ uint16* sampleinfo;
+ uint16 extrasamples;
+ uint16 planarconfig;
+ int colorchannels;
+
+ img->tif = tif;
+ img->stoponerr = stop;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample);
+ img->alpha = 0;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,
+ &extrasamples, &sampleinfo);
+ if (extrasamples == 1)
+ switch (sampleinfo[0]) {
+ case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */
+ case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */
+ img->alpha = sampleinfo[0];
+ break;
+ }
+ colorchannels = img->samplesperpixel - extrasamples;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
+ if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) {
+ switch (colorchannels) {
+ case 1:
+ if (isCCITTCompression(tif))
+ img->photometric = PHOTOMETRIC_MINISWHITE;
+ else
+ img->photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 3:
+ img->photometric = PHOTOMETRIC_RGB;
+ break;
+ default:
+ sprintf(emsg, "Missing needed %s tag", photoTag);
+ return (0);
+ }
+ }
+ switch (img->photometric) {
+ case PHOTOMETRIC_PALETTE:
+ if (!TIFFGetField(tif, TIFFTAG_COLORMAP,
+ &img->redcmap, &img->greencmap, &img->bluecmap)) {
+ TIFFError(TIFFFileName(tif), "Missing required \"Colormap\" tag");
+ return (0);
+ }
+ /* fall thru... */
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+/* This should work now so skip the check - BSR
+ if (planarconfig == PLANARCONFIG_CONTIG && img->samplesperpixel != 1) {
+ sprintf(emsg,
+ "Sorry, can not handle contiguous data with %s=%d, and %s=%d",
+ photoTag, img->photometric,
+ "Samples/pixel", img->samplesperpixel);
+ return (0);
+ }
+ */
+ break;
+ case PHOTOMETRIC_YCBCR:
+ if (planarconfig != PLANARCONFIG_CONTIG) {
+ sprintf(emsg, "Sorry, can not handle YCbCr images with %s=%d",
+ "Planarconfiguration", planarconfig);
+ return (0);
+ }
+ /* It would probably be nice to have a reality check here. */
+ { uint16 compress;
+ TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
+ if (compress == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) {
+ /* can rely on libjpeg to convert to RGB */
+ /* XXX should restore current state on exit */
+ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ img->photometric = PHOTOMETRIC_RGB;
+ }
+ }
+ break;
+ case PHOTOMETRIC_RGB:
+ if (colorchannels < 3) {
+ sprintf(emsg, "Sorry, can not handle RGB image with %s=%d",
+ "Color channels", colorchannels);
+ return (0);
+ }
+ break;
+ case PHOTOMETRIC_SEPARATED: {
+ uint16 inkset;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
+ if (inkset != INKSET_CMYK) {
+ sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
+ "InkSet", inkset);
+ return (0);
+ }
+ if (img->samplesperpixel != 4) {
+ sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
+ "Samples/pixel", img->samplesperpixel);
+ return (0);
+ }
+ break;
+ }
+ default:
+ sprintf(emsg, "Sorry, can not handle image with %s=%d",
+ photoTag, img->photometric);
+ return (0);
+ }
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height);
+
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation);
+ switch (img->orientation) {
+ case ORIENTATION_BOTRIGHT:
+ case ORIENTATION_RIGHTBOT: /* XXX */
+ case ORIENTATION_LEFTBOT: /* XXX */
+ TIFFWarning(TIFFFileName(tif), "using bottom-left orientation");
+ img->orientation = ORIENTATION_BOTLEFT;
+ /* fall thru... */
+ case ORIENTATION_BOTLEFT:
+ break;
+ case ORIENTATION_TOPRIGHT:
+ case ORIENTATION_RIGHTTOP: /* XXX */
+ case ORIENTATION_LEFTTOP: /* XXX */
+ default:
+ TIFFWarning(TIFFFileName(tif), "using top-left orientation");
+ img->orientation = ORIENTATION_TOPLEFT;
+ /* fall thru... */
+ case ORIENTATION_TOPLEFT:
+ break;
+ }
+
+ img->isContig =
+ !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1);
+ if (img->isContig) {
+ img->get = TIFFIsTiled(tif) ? gtTileContig : gtStripContig;
+ } else {
+ img->get = TIFFIsTiled(tif) ? gtTileSeparate : gtStripSeparate;
+ }
+ return (1);
+}
+
+int
+TIFFImageIterGet(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
+{
+ if (img->get == NULL) {
+ TIFFError(TIFFFileName(img->tif), "No \"get\" routine setup");
+ return (0);
+ }
+ if (img->callback.any == NULL) {
+ TIFFError(TIFFFileName(img->tif),
+ "No \"put\" routine setupl; probably can not handle image format");
+ return (0);
+ }
+ return (*img->get)(img, udata, w, h);
+}
+
+TIFFImageIterEnd(TIFFImageIter* img)
+{
+ /* Nothing to free... ? */
+}
+
+/*
+ * Read the specified image into an ABGR-format raster.
+ */
+int
+TIFFReadImageIter(TIFF* tif,
+ uint32 rwidth, uint32 rheight, uint8* raster, int stop)
+{
+ char emsg[1024];
+ TIFFImageIter img;
+ int ok;
+
+ if (TIFFImageIterBegin(&img, tif, stop, emsg)) {
+ /* XXX verify rwidth and rheight against width and height */
+ ok = TIFFImageIterGet(&img, raster, rwidth, img.height);
+ TIFFImageIterEnd(&img);
+ } else {
+ TIFFError(TIFFFileName(tif), emsg);
+ ok = 0;
+ }
+ return (ok);
+}
+
+
+/*
+ * Get an tile-organized image that has
+ * PlanarConfiguration contiguous if SamplesPerPixel > 1
+ * or
+ * SamplesPerPixel == 1
+ */
+static int
+gtTileContig(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ ImageIterTileContigRoutine callback = img->callback.contig;
+ uint16 orientation;
+ uint32 col, row;
+ uint32 tw, th;
+ u_char* buf;
+ int32 fromskew;
+ uint32 nrow;
+
+ buf = (u_char*) _TIFFmalloc(TIFFTileSize(tif));
+ if (buf == 0) {
+ TIFFError(TIFFFileName(tif), "No space for tile buffer");
+ return (0);
+ }
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+ orientation = img->orientation;
+ for (row = 0; row < h; row += th) {
+ nrow = (row + th > h ? h - row : th);
+ for (col = 0; col < w; col += tw) {
+ if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0 && img->stoponerr)
+ break;
+ if (col + tw > w) {
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ uint32 npix = w - col;
+ fromskew = tw - npix;
+ (*callback)(img, udata, col, row, npix, nrow, fromskew, buf);
+ } else {
+ (*callback)(img, udata, col, row, tw, nrow, 0, buf);
+ }
+ }
+ }
+ _TIFFfree(buf);
+ return (1);
+}
+
+/*
+ * Get an tile-organized image that has
+ * SamplesPerPixel > 1
+ * PlanarConfiguration separated
+ * We assume that all such images are RGB.
+ */
+static int
+gtTileSeparate(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ ImageIterTileSeparateRoutine callback = img->callback.separate;
+ uint16 orientation;
+ uint32 col, row;
+ uint32 tw, th;
+ u_char* buf;
+ u_char* r;
+ u_char* g;
+ u_char* b;
+ u_char* a;
+ tsize_t tilesize;
+ int32 fromskew;
+ int alpha = img->alpha;
+ uint32 nrow;
+
+ tilesize = TIFFTileSize(tif);
+ buf = (u_char*) _TIFFmalloc(4*tilesize);
+ if (buf == 0) {
+ TIFFError(TIFFFileName(tif), "No space for tile buffer");
+ return (0);
+ }
+ r = buf;
+ g = r + tilesize;
+ b = g + tilesize;
+ a = b + tilesize;
+ if (!alpha)
+ memset(a, 0xff, tilesize);
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+ orientation = img->orientation;
+ for (row = 0; row < h; row += th) {
+ nrow = (row + th > h ? h - row : th);
+ for (col = 0; col < w; col += tw) {
+ if (TIFFReadTile(tif, r, col, row,0,0) < 0 && img->stoponerr)
+ break;
+ if (TIFFReadTile(tif, g, col, row,0,1) < 0 && img->stoponerr)
+ break;
+ if (TIFFReadTile(tif, b, col, row,0,2) < 0 && img->stoponerr)
+ break;
+ if (alpha && TIFFReadTile(tif,a,col,row,0,3) < 0 && img->stoponerr)
+ break;
+ if (col + tw > w) {
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ uint32 npix = w - col;
+ fromskew = tw - npix;
+ (*callback)(img, udata, col, row, npix, nrow, fromskew, r, g, b, a);
+ } else {
+ (*callback)(img, udata, col, row, tw, nrow, 0, r, g, b, a);
+ }
+ }
+ }
+ _TIFFfree(buf);
+ return (1);
+}
+
+/*
+ * Get a strip-organized image that has
+ * PlanarConfiguration contiguous if SamplesPerPixel > 1
+ * or
+ * SamplesPerPixel == 1
+ */
+static int
+gtStripContig(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ ImageIterTileContigRoutine callback = img->callback.contig;
+ uint16 orientation;
+ uint32 row, nrow;
+ u_char* buf;
+ uint32 rowsperstrip;
+ uint32 imagewidth = img->width;
+ tsize_t scanline;
+ int32 fromskew;
+
+ buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif));
+ if (buf == 0) {
+ TIFFError(TIFFFileName(tif), "No space for strip buffer");
+ return (0);
+ }
+ orientation = img->orientation;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ scanline = TIFFScanlineSize(tif);
+ fromskew = (w < imagewidth ? imagewidth - w : 0);
+ for (row = 0; row < h; row += rowsperstrip) {
+ nrow = (row + rowsperstrip > h ? h - row : rowsperstrip);
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0),
+ buf, nrow*scanline) < 0 && img->stoponerr)
+ break;
+ (*callback)(img, udata, 0, row, w, nrow, fromskew, buf);
+ }
+ _TIFFfree(buf);
+ return (1);
+}
+
+/*
+ * Get a strip-organized image with
+ * SamplesPerPixel > 1
+ * PlanarConfiguration separated
+ * We assume that all such images are RGB.
+ */
+static int
+gtStripSeparate(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ ImageIterTileSeparateRoutine callback = img->callback.separate;
+ uint16 orientation;
+ u_char *buf;
+ u_char *r, *g, *b, *a;
+ uint32 row, nrow;
+ tsize_t scanline;
+ uint32 rowsperstrip;
+ uint32 imagewidth = img->width;
+ tsize_t stripsize;
+ int32 fromskew;
+ int alpha = img->alpha;
+
+ stripsize = TIFFStripSize(tif);
+ r = buf = (u_char *)_TIFFmalloc(4*stripsize);
+ if (buf == 0) {
+ TIFFError(TIFFFileName(tif), "No space for tile buffer");
+ return (0);
+ }
+ g = r + stripsize;
+ b = g + stripsize;
+ a = b + stripsize;
+ if (!alpha)
+ memset(a, 0xff, stripsize);
+ orientation = img->orientation;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ scanline = TIFFScanlineSize(tif);
+ fromskew = (w < imagewidth ? imagewidth - w : 0);
+ for (row = 0; row < h; row += rowsperstrip) {
+ nrow = (row + rowsperstrip > h ? h - row : rowsperstrip);
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0),
+ r, nrow*scanline) < 0 && img->stoponerr)
+ break;
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 1),
+ g, nrow*scanline) < 0 && img->stoponerr)
+ break;
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 2),
+ b, nrow*scanline) < 0 && img->stoponerr)
+ break;
+ if (alpha &&
+ (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 3),
+ a, nrow*scanline) < 0 && img->stoponerr))
+ break;
+ (*callback)(img, udata, 0, row, w, nrow, fromskew, r, g, b, a);
+ }
+ _TIFFfree(buf);
+ return (1);
+}
+
+DECLAREContigCallbackFunc(TestContigCallback)
+{
+ printf("Contig Callback called with x = %d, y = %d, w = %d, h = %d, fromskew = %d\n",
+ x, y, w, h, fromskew);
+}
+
+
+DECLARESepCallbackFunc(TestSepCallback)
+{
+ printf("Sep Callback called with x = %d, y = %d, w = %d, h = %d, fromskew = %d\n",
+ x, y, w, h, fromskew);
+}
+
+
+#ifdef MAIN
+main(int argc, char **argv)
+{
+ char emsg[1024];
+ TIFFImageIter img;
+ int ok;
+ int stop = 1;
+
+ TIFF *tif;
+ unsigned long nx, ny;
+ unsigned short BitsPerSample, SamplesPerPixel;
+ int isColorMapped, isPliFile;
+ unsigned char *ColorMap;
+ unsigned char *data;
+
+ if (argc < 2) {
+ fprintf(stderr,"usage: %s tiff_file\n",argv[0]);
+ exit(1);
+ }
+ tif = (TIFF *)PLIGetImage(argv[1], (void *) &data, &ColorMap,
+ &nx, &ny, &BitsPerSample, &SamplesPerPixel,
+ &isColorMapped, &isPliFile);
+ if (tif != NULL) {
+
+ if (TIFFImageIterBegin(&img, tif, stop, emsg)) {
+ /* Here need to set data and callback function! */
+ if (img.isContig) {
+ img.callback = TestContigCallback;
+ } else {
+ img.callback = TestSepCallback;
+ }
+ ok = TIFFImageIterGet(&img, NULL, img.width, img.height);
+ TIFFImageIterEnd(&img);
+ } else {
+ TIFFError(TIFFFileName(tif), emsg);
+ }
+ }
+
+}
+#endif
diff --git a/contrib/pds/tif_imageiter.h b/contrib/pds/tif_imageiter.h
new file mode 100644
index 00000000..5b7ea40a
--- /dev/null
+++ b/contrib/pds/tif_imageiter.h
@@ -0,0 +1,57 @@
+typedef struct _TIFFImageIter TIFFImageIter;
+
+/* The callback function is called for each "block" of image pixel data after
+ it has been read from the file and decoded. This image pixel data is in the
+ buffer pp, and this data represents the image pixels from (x,y) to
+ (x+w,y+h). It is stored in pixel format, so each pixel contains
+ img->samplesperpixel consecutive samples each containing img->bitspersample
+ bits of data. The array pp is ordered in h consecutive rows of w+fromskew
+ pixels each. */
+typedef void (*ImageIterTileContigRoutine)
+ (TIFFImageIter*, void *, uint32, uint32, uint32, uint32, int32,
+ unsigned char*);
+#define DECLAREContigCallbackFunc(name) \
+static void name(\
+ TIFFImageIter* img, \
+ void* user_data, \
+ uint32 x, uint32 y, \
+ uint32 w, uint32 h, \
+ int32 fromskew, \
+ u_char* pp \
+)
+
+typedef void (*ImageIterTileSeparateRoutine)
+ (TIFFImageIter*, void *, uint32, uint32, uint32, uint32, int32,
+ unsigned char*, unsigned char*, unsigned char*, unsigned char*);
+#define DECLARESepCallbackFunc(name) \
+static void name(\
+ TIFFImageIter* img, \
+ void* user_data, \
+ uint32 x, uint32 y, \
+ uint32 w, uint32 h,\
+ int32 fromskew, \
+ u_char* r, u_char* g, u_char* b, u_char* a\
+)
+
+struct _TIFFImageIter {
+ 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 photometric; /* image photometric interp */
+ uint16* redcmap; /* colormap pallete */
+ uint16* greencmap;
+ uint16* bluecmap;
+ /* get image data routine */
+ int (*get)(TIFFImageIter*, void *udata, uint32, uint32);
+ union {
+ void (*any)(TIFFImageIter*);
+ ImageIterTileContigRoutine contig;
+ ImageIterTileSeparateRoutine separate;
+ } callback; /* fn to exec for each block */
+};
diff --git a/contrib/pds/tif_pdsdirread.c b/contrib/pds/tif_pdsdirread.c
new file mode 100644
index 00000000..87ea11e3
--- /dev/null
+++ b/contrib/pds/tif_pdsdirread.c
@@ -0,0 +1,1124 @@
+/* $Header: /d1/sam/tiff/contrib/pds/RCS/tif_pdsdirread.c,v 1.1 1997/08/29 23:12:56 sam Exp $ */
+
+/*
+ * Copyright (c) 1988-1996 Sam Leffler
+ * Copyright (c) 1991-1996 Silicon Graphics, Inc.
+ * Copyright (c( 1996 USAF Phillips Laboratory
+ *
+ * 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.
+ *
+ * These routines written by Conrad J. Poelman on a single late-night of
+ * March 20-21, 1996.
+ *
+ * The entire purpose of this file is to provide a single external function,
+ * TIFFReadPrivateDataSubDirectory(). This function is intended for use in reading a
+ * private subdirectory from a TIFF file into a private structure. The
+ * actual writing of data into the structure is handled by the setFieldFn(),
+ * which is passed to TIFFReadPrivateDataSubDirectory() as a parameter. The idea is to
+ * enable any application wishing to store private subdirectories to do so
+ * easily using this function, without modifying the TIFF library.
+ *
+ * The astute observer will notice that only two functions are at all different
+ * from the original tif_dirread.c file: TIFFReadPrivateDataSubDirectory() and
+ * TIFFFetchNormalSubTag(). All the other stuff that makes this file so huge
+ * is only necessary because all of those functions are declared static in
+ * tif_dirread.c, so we have to totally duplicate them in order to use them.
+ *
+ * Oh, also note the bug fix in TIFFFetchFloat().
+ *
+ */
+
+#include "tiffiop.h"
+
+#define IGNORE 0 /* tag placeholder used below */
+
+#if 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
+
+static void EstimateStripByteCounts(TIFF*, TIFFDirEntry*, uint16);
+static void MissingRequired(TIFF*, const char*);
+static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32);
+static tsize_t TIFFFetchData(TIFF*, TIFFDirEntry*, char*);
+static tsize_t TIFFFetchString(TIFF*, TIFFDirEntry*, char*);
+static float TIFFFetchRational(TIFF*, TIFFDirEntry*);
+static int TIFFFetchNormalSubTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*,
+ int (*getFieldFn)(TIFF *tif,ttag_t tag,...));
+static int TIFFFetchPerSampleShorts(TIFF*, TIFFDirEntry*, int*);
+static int TIFFFetchPerSampleAnys(TIFF*, TIFFDirEntry*, double*);
+static int TIFFFetchShortArray(TIFF*, TIFFDirEntry*, uint16*);
+static int TIFFFetchStripThing(TIFF*, TIFFDirEntry*, long, uint32**);
+static int TIFFFetchExtraSamples(TIFF*, TIFFDirEntry*);
+static int TIFFFetchRefBlackWhite(TIFF*, TIFFDirEntry*);
+static float TIFFFetchFloat(TIFF*, TIFFDirEntry*);
+static int TIFFFetchFloatArray(TIFF*, TIFFDirEntry*, float*);
+static int TIFFFetchDoubleArray(TIFF*, TIFFDirEntry*, double*);
+static int TIFFFetchAnyArray(TIFF*, TIFFDirEntry*, double*);
+static int TIFFFetchShortPair(TIFF*, TIFFDirEntry*);
+#if STRIPCHOP_SUPPORT
+static void ChopUpSingleUncompressedStrip(TIFF*);
+#endif
+
+static char *
+CheckMalloc(TIFF* tif, tsize_t n, const char* what)
+{
+ char *cp = (char*)_TIFFmalloc(n);
+ if (cp == NULL)
+ TIFFError(tif->tif_name, "No space %s", what);
+ return (cp);
+}
+
+/* Just as was done with TIFFWritePrivateDataSubDirectory(), here we implement
+ TIFFReadPrivateDataSubDirectory() which takes an offset into the TIFF file,
+ a TIFFFieldInfo structure specifying the types of the various tags,
+ and a function to use to set individual tags when they are encountered.
+ The data is read from the file, translated using the TIFF library's
+ built-in machine-independent conversion functions, and filled into
+ private subdirectory structure.
+
+ This code was written by copying the original TIFFReadDirectory() function
+ from tif_dirread.c and paring it down to what is needed for this.
+
+ It is the caller's responsibility to allocate and initialize the internal
+ structure that setFieldFn() will be writing into. If this function is being
+ called more than once before closing the file, the caller also must be
+ careful to free data in the structure before re-initializing.
+
+ It is also the caller's responsibility to verify the presence of
+ any required fields after reading the directory in.
+*/
+
+
+int
+TIFFReadPrivateDataSubDirectory(TIFF* tif, toff_t pdir_offset,
+ TIFFFieldInfo *field_info,
+ int (*setFieldFn)(TIFF *tif, ttag_t tag, ...))
+{
+ register TIFFDirEntry* dp;
+ register int n;
+ register TIFFDirectory* td;
+ TIFFDirEntry* dir;
+ int iv;
+ long v;
+ double dv;
+ const TIFFFieldInfo* fip;
+ int fix;
+ uint16 dircount;
+ uint32 nextdiroff;
+ char* cp;
+ int diroutoforderwarning = 0;
+
+ /* Skipped part about checking for directories or compression data. */
+
+ if (!isMapped(tif)) {
+ if (!SeekOK(tif, pdir_offset)) {
+ TIFFError(tif->tif_name,
+ "Seek error accessing TIFF private subdirectory");
+ return (0);
+ }
+ if (!ReadOK(tif, &dircount, sizeof (uint16))) {
+ TIFFError(tif->tif_name,
+ "Can not read TIFF private subdirectory count");
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ dir = (TIFFDirEntry *)CheckMalloc(tif,
+ dircount * sizeof (TIFFDirEntry), "to read TIFF private subdirectory");
+ if (dir == NULL)
+ return (0);
+ if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) {
+ TIFFError(tif->tif_name, "Can not read TIFF private subdirectory");
+ goto bad;
+ }
+ /*
+ * Read offset to next directory for sequential scans.
+ */
+ (void) ReadOK(tif, &nextdiroff, sizeof (uint32));
+ } else {
+ toff_t off = pdir_offset;
+
+ if (off + sizeof (short) > tif->tif_size) {
+ TIFFError(tif->tif_name,
+ "Can not read TIFF private subdirectory count");
+ return (0);
+ } else
+ _TIFFmemcpy(&dircount, tif->tif_base + off, sizeof (uint16));
+ off += sizeof (uint16);
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ dir = (TIFFDirEntry *)CheckMalloc(tif,
+ dircount * sizeof (TIFFDirEntry), "to read TIFF private subdirectory");
+ if (dir == NULL)
+ return (0);
+ if (off + dircount*sizeof (TIFFDirEntry) > tif->tif_size) {
+ TIFFError(tif->tif_name, "Can not read TIFF private subdirectory");
+ goto bad;
+ } else
+ _TIFFmemcpy(dir, tif->tif_base + off,
+ dircount*sizeof (TIFFDirEntry));
+ off += dircount* sizeof (TIFFDirEntry);
+ if (off + sizeof (uint32) < tif->tif_size)
+ _TIFFmemcpy(&nextdiroff, tif->tif_base+off, sizeof (uint32));
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&nextdiroff);
+
+ /*
+ * Setup default value and then make a pass over
+ * the fields to check type and tag information,
+ * and to extract info required to size data
+ * structures. A second pass is made afterwards
+ * to read in everthing not taken in the first pass.
+ */
+ td = &tif->tif_dir;
+
+ for (fip = field_info, dp = dir, n = dircount;
+ n > 0; n--, dp++) {
+ if (tif->tif_flags & TIFF_SWAB) {
+ TIFFSwabArrayOfShort(&dp->tdir_tag, 2);
+ TIFFSwabArrayOfLong(&dp->tdir_count, 2);
+ }
+ /*
+ * Find the field information entry for this tag.
+ */
+ /*
+ * Silicon Beach (at least) writes unordered
+ * directory tags (violating the spec). Handle
+ * it here, but be obnoxious (maybe they'll fix it?).
+ */
+ if (dp->tdir_tag < fip->field_tag) {
+ if (!diroutoforderwarning) {
+ TIFFWarning(tif->tif_name,
+ "invalid TIFF private subdirectory; tags are not sorted in ascending order");
+ diroutoforderwarning = 1;
+ }
+ fip = field_info; /* O(n^2) */
+ }
+
+ while (fip->field_tag && fip->field_tag < dp->tdir_tag)
+ fip++;
+ if (!fip->field_tag || fip->field_tag != dp->tdir_tag) {
+ TIFFWarning(tif->tif_name,
+ "unknown field with tag %d (0x%x) in private subdirectory ignored",
+ dp->tdir_tag, dp->tdir_tag);
+ dp->tdir_tag = IGNORE;
+ fip = field_info;/* restart search */
+ continue;
+ }
+ /*
+ * Null out old tags that we ignore.
+ */
+
+ /* Not implemented yet, since FIELD_IGNORE is specific to
+ the main directories. Could pass this in too... */
+ if (0 /* && fip->field_bit == FIELD_IGNORE */) {
+ ignore:
+ dp->tdir_tag = IGNORE;
+ continue;
+ }
+
+ /*
+ * Check data type.
+ */
+
+ while (dp->tdir_type != (u_short)fip->field_type) {
+ if (fip->field_type == TIFF_ANY) /* wildcard */
+ break;
+ fip++;
+ if (!fip->field_tag || fip->field_tag != dp->tdir_tag) {
+ TIFFWarning(tif->tif_name,
+ "wrong data type %d for \"%s\"; tag ignored",
+ dp->tdir_type, fip[-1].field_name);
+ goto ignore;
+ }
+ }
+ /*
+ * Check count if known in advance.
+ */
+ if (fip->field_readcount != TIFF_VARIABLE) {
+ uint32 expected = (fip->field_readcount == TIFF_SPP) ?
+ (uint32) td->td_samplesperpixel :
+ (uint32) fip->field_readcount;
+ if (!CheckDirCount(tif, dp, expected))
+ goto ignore;
+ }
+
+ /* Now read in and process data from field. */
+ if (!TIFFFetchNormalSubTag(tif, dp, fip, setFieldFn))
+ goto bad;
+
+ }
+
+ if (dir)
+ _TIFFfree(dir);
+ return (1);
+bad:
+ if (dir)
+ _TIFFfree(dir);
+ return (0);
+}
+
+static void
+EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
+{
+ register TIFFDirEntry *dp;
+ register TIFFDirectory *td = &tif->tif_dir;
+ uint16 i;
+
+ if (td->td_stripbytecount)
+ _TIFFfree(td->td_stripbytecount);
+ td->td_stripbytecount = (uint32*)
+ CheckMalloc(tif, td->td_nstrips * sizeof (uint32),
+ "for \"StripByteCounts\" array");
+ if (td->td_compression != COMPRESSION_NONE) {
+ uint32 space = (uint32)(sizeof (TIFFHeader)
+ + sizeof (uint16)
+ + (dircount * sizeof (TIFFDirEntry))
+ + sizeof (uint32));
+ toff_t filesize = TIFFGetFileSize(tif);
+ uint16 n;
+
+ /* calculate amount of space used by indirect values */
+ for (dp = dir, n = dircount; n > 0; n--, dp++) {
+ uint32 cc = dp->tdir_count*tiffDataWidth[dp->tdir_type];
+ if (cc > sizeof (uint32))
+ space += cc;
+ }
+ space = (filesize - space) / td->td_samplesperpixel;
+ for (i = 0; i < td->td_nstrips; i++)
+ td->td_stripbytecount[i] = 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.
+ */
+ i--;
+ if (td->td_stripoffset[i] + td->td_stripbytecount[i] > filesize)
+ td->td_stripbytecount[i] =
+ filesize - td->td_stripoffset[i];
+ } else {
+ uint32 rowbytes = TIFFScanlineSize(tif);
+ uint32 rowsperstrip = td->td_imagelength / td->td_nstrips;
+ for (i = 0; i < td->td_nstrips; i++)
+ td->td_stripbytecount[i] = rowbytes*rowsperstrip;
+ }
+ TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
+ if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP))
+ td->td_rowsperstrip = td->td_imagelength;
+}
+
+static void
+MissingRequired(TIFF* tif, const char* tagname)
+{
+ TIFFError(tif->tif_name,
+ "TIFF directory is missing required \"%s\" field", tagname);
+}
+
+/*
+ * Check the count field of a directory
+ * entry against a known value. The caller
+ * is expected to skip/ignore the tag if
+ * there is a mismatch.
+ */
+static int
+CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count)
+{
+ if (count != dir->tdir_count) {
+ TIFFWarning(tif->tif_name,
+ "incorrect count for field \"%s\" (%lu, expecting %lu); tag ignored",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,
+ dir->tdir_count, count);
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Fetch a contiguous directory item.
+ */
+static tsize_t
+TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ int w = tiffDataWidth[dir->tdir_type];
+ tsize_t cc = dir->tdir_count * w;
+
+ if (!isMapped(tif)) {
+ if (!SeekOK(tif, dir->tdir_offset))
+ goto bad;
+ if (!ReadOK(tif, cp, cc))
+ goto bad;
+ } else {
+ if (dir->tdir_offset + cc > tif->tif_size)
+ goto bad;
+ _TIFFmemcpy(cp, tif->tif_base + dir->tdir_offset, cc);
+ }
+ if (tif->tif_flags & TIFF_SWAB) {
+ switch (dir->tdir_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count);
+ break;
+ case TIFF_DOUBLE:
+ TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count);
+ break;
+ }
+ }
+ return (cc);
+bad:
+ TIFFError(tif->tif_name, "Error fetching data for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ return ((tsize_t) 0);
+}
+
+/*
+ * Fetch an ASCII item from the file.
+ */
+static tsize_t
+TIFFFetchString(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ if (dir->tdir_count <= 4) {
+ uint32 l = dir->tdir_offset;
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&l);
+ _TIFFmemcpy(cp, &l, dir->tdir_count);
+ return (1);
+ }
+ return (TIFFFetchData(tif, dir, cp));
+}
+
+/*
+ * Convert numerator+denominator to float.
+ */
+static int
+cvtRational(TIFF* tif, TIFFDirEntry* dir, uint32 num, uint32 denom, float* rv)
+{
+ if (denom == 0) {
+ TIFFError(tif->tif_name,
+ "%s: Rational with zero denominator (num = %lu)",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, num);
+ return (0);
+ } else {
+ if (dir->tdir_type == TIFF_RATIONAL)
+ *rv = ((float)num / (float)denom);
+ else
+ *rv = ((float)(int32)num / (float)(int32)denom);
+ return (1);
+ }
+}
+
+/*
+ * Fetch a rational item from the file
+ * at offset off and return the value
+ * as a floating point number.
+ */
+static float
+TIFFFetchRational(TIFF* tif, TIFFDirEntry* dir)
+{
+ uint32 l[2];
+ float v;
+
+ return (!TIFFFetchData(tif, dir, (char *)l) ||
+ !cvtRational(tif, dir, l[0], l[1], &v) ? 1.0f : v);
+}
+
+/*
+ * Fetch a single floating point value
+ * from the offset field and return it
+ * as a native float.
+ */
+static float
+TIFFFetchFloat(TIFF* tif, TIFFDirEntry* dir)
+{
+ /* This appears to be a flagrant bug in the TIFF library, yet I
+ actually don't understand how it could have ever worked the old
+ way. Look at the comments in my new code and you'll understand. */
+#if (0)
+ float v = (float)
+ TIFFExtractData(tif, dir->tdir_type, dir->tdir_offset);
+ TIFFCvtIEEEFloatToNative(tif, 1, &v);
+#else
+ float v;
+ /* This is a little bit tricky - if we just cast the uint32 to a float,
+ C will perform a numerical conversion, which is not what we want.
+ We want to take the actual bit pattern in the uint32 and interpret
+ it as a float. Thus we cast a uint32 * into a float * and then
+ dereference to get v. */
+ uint32 l = (uint32)
+ TIFFExtractData(tif, dir->tdir_type, dir->tdir_offset);
+ v = * (float *) &l;
+ TIFFCvtIEEEFloatToNative(tif, 1, &v);
+#endif
+ return (v);
+
+}
+
+/*
+ * Fetch an array of BYTE or SBYTE values.
+ */
+static int
+TIFFFetchByteArray(TIFF* tif, TIFFDirEntry* dir, uint16* v)
+{
+ if (dir->tdir_count <= 4) {
+ /*
+ * Extract data from offset field.
+ */
+ if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+ switch (dir->tdir_count) {
+ case 4: v[3] = dir->tdir_offset & 0xff;
+ case 3: v[2] = (dir->tdir_offset >> 8) & 0xff;
+ case 2: v[1] = (dir->tdir_offset >> 16) & 0xff;
+ case 1: v[0] = dir->tdir_offset >> 24;
+ }
+ } else {
+ switch (dir->tdir_count) {
+ case 4: v[3] = dir->tdir_offset >> 24;
+ case 3: v[2] = (dir->tdir_offset >> 16) & 0xff;
+ case 2: v[1] = (dir->tdir_offset >> 8) & 0xff;
+ case 1: v[0] = dir->tdir_offset & 0xff;
+ }
+ }
+ return (1);
+ } else
+ return (TIFFFetchData(tif, dir, (char*) v) != 0); /* XXX */
+}
+
+/*
+ * Fetch an array of SHORT or SSHORT values.
+ */
+static int
+TIFFFetchShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v)
+{
+ if (dir->tdir_count <= 2) {
+ if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+ switch (dir->tdir_count) {
+ case 2: v[1] = dir->tdir_offset & 0xffff;
+ case 1: v[0] = dir->tdir_offset >> 16;
+ }
+ } else {
+ switch (dir->tdir_count) {
+ case 2: v[1] = dir->tdir_offset >> 16;
+ case 1: v[0] = dir->tdir_offset & 0xffff;
+ }
+ }
+ return (1);
+ } else
+ return (TIFFFetchData(tif, dir, (char *)v) != 0);
+}
+
+/*
+ * Fetch a pair of SHORT or BYTE values.
+ */
+static int
+TIFFFetchShortPair(TIFF* tif, TIFFDirEntry* dir)
+{
+ uint16 v[2];
+ int ok = 0;
+
+ switch (dir->tdir_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ ok = TIFFFetchShortArray(tif, dir, v);
+ break;
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ ok = TIFFFetchByteArray(tif, dir, v);
+ break;
+ }
+ if (ok)
+ TIFFSetField(tif, dir->tdir_tag, v[0], v[1]);
+ return (ok);
+}
+
+/*
+ * Fetch an array of LONG or SLONG values.
+ */
+static int
+TIFFFetchLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v)
+{
+ if (dir->tdir_count == 1) {
+ v[0] = dir->tdir_offset;
+ return (1);
+ } else
+ return (TIFFFetchData(tif, dir, (char*) v) != 0);
+}
+
+/*
+ * Fetch an array of RATIONAL or SRATIONAL values.
+ */
+static int
+TIFFFetchRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v)
+{
+ int ok = 0;
+ uint32* l;
+
+ l = (uint32*)CheckMalloc(tif,
+ dir->tdir_count*tiffDataWidth[dir->tdir_type],
+ "to fetch array of rationals");
+ if (l) {
+ if (TIFFFetchData(tif, dir, (char *)l)) {
+ uint32 i;
+ for (i = 0; i < dir->tdir_count; i++) {
+ ok = cvtRational(tif, dir,
+ l[2*i+0], l[2*i+1], &v[i]);
+ if (!ok)
+ break;
+ }
+ }
+ _TIFFfree((char *)l);
+ }
+ return (ok);
+}
+
+/*
+ * Fetch an array of FLOAT values.
+ */
+static int
+TIFFFetchFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v)
+{
+
+ if (dir->tdir_count == 1) {
+ v[0] = *(float*) &dir->tdir_offset;
+ TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v);
+ return (1);
+ } else if (TIFFFetchData(tif, dir, (char*) v)) {
+ TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v);
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * Fetch an array of DOUBLE values.
+ */
+static int
+TIFFFetchDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v)
+{
+ if (TIFFFetchData(tif, dir, (char*) v)) {
+ TIFFCvtIEEEDoubleToNative(tif, dir->tdir_count, v);
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * Fetch an array of ANY values. The actual values are
+ * returned as doubles which should be able hold all the
+ * types. Yes, there really should be an tany_t to avoid
+ * this potential non-portability ... Note in particular
+ * that we assume that the double return value vector is
+ * large enough to read in any fundamental type. We use
+ * that vector as a buffer to read in the base type vector
+ * and then convert it in place to double (from end
+ * to front of course).
+ */
+static int
+TIFFFetchAnyArray(TIFF* tif, TIFFDirEntry* dir, double* v)
+{
+ int i;
+
+ switch (dir->tdir_type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ if (!TIFFFetchByteArray(tif, dir, (uint16*) v))
+ return (0);
+ if (dir->tdir_type == TIFF_BYTE) {
+ uint16* vp = (uint16*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ } else {
+ int16* vp = (int16*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ if (!TIFFFetchShortArray(tif, dir, (uint16*) v))
+ return (0);
+ if (dir->tdir_type == TIFF_SHORT) {
+ uint16* vp = (uint16*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ } else {
+ int16* vp = (int16*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ if (!TIFFFetchLongArray(tif, dir, (uint32*) v))
+ return (0);
+ if (dir->tdir_type == TIFF_LONG) {
+ uint32* vp = (uint32*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ } else {
+ int32* vp = (int32*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ if (!TIFFFetchRationalArray(tif, dir, (float*) v))
+ return (0);
+ { float* vp = (float*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_FLOAT:
+ if (!TIFFFetchFloatArray(tif, dir, (float*) v))
+ return (0);
+ { float* vp = (float*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_DOUBLE:
+ return (TIFFFetchDoubleArray(tif, dir, (double*) v));
+ default:
+ /* TIFF_NOTYPE */
+ /* TIFF_ASCII */
+ /* TIFF_UNDEFINED */
+ TIFFError(tif->tif_name,
+ "Cannot read TIFF_ANY type %d for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ return (0);
+ }
+ return (1);
+}
+
+
+/*
+ * Fetch a tag that is not handled by special case code.
+ */
+/* The standard function TIFFFetchNormalTag() could definitely be replaced
+ with a simple call to this function, just adding TIFFSetField() as the
+ last argument. */
+static int
+TIFFFetchNormalSubTag(TIFF* tif, TIFFDirEntry* dp, const TIFFFieldInfo* fip,
+ int (*setFieldFn)(TIFF *tif, ttag_t tag, ...))
+{
+ static char mesg[] = "to fetch tag value";
+ int ok = 0;
+
+ if (dp->tdir_count > 1) { /* array of values */
+ char* cp = NULL;
+
+ switch (dp->tdir_type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ /* NB: always expand BYTE values to shorts */
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (uint16), mesg);
+ ok = cp && TIFFFetchByteArray(tif, dp, (uint16*) cp);
+ break;
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (uint16), mesg);
+ ok = cp && TIFFFetchShortArray(tif, dp, (uint16*) cp);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (uint32), mesg);
+ ok = cp && TIFFFetchLongArray(tif, dp, (uint32*) cp);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (float), mesg);
+ ok = cp && TIFFFetchRationalArray(tif, dp, (float*) cp);
+ break;
+ case TIFF_FLOAT:
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (float), mesg);
+ ok = cp && TIFFFetchFloatArray(tif, dp, (float*) cp);
+ break;
+ case TIFF_DOUBLE:
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (double), mesg);
+ ok = cp && TIFFFetchDoubleArray(tif, dp, (double*) cp);
+ break;
+ case TIFF_ASCII:
+ case TIFF_UNDEFINED: /* bit of a cheat... */
+ /*
+ * Some vendors write strings w/o the trailing
+ * NULL byte, so always append one just in case.
+ */
+ cp = CheckMalloc(tif, dp->tdir_count+1, mesg);
+ if (ok = (cp && TIFFFetchString(tif, dp, cp)))
+ cp[dp->tdir_count] = '\0'; /* XXX */
+ break;
+ }
+ if (ok) {
+ ok = (fip->field_passcount ?
+ (*setFieldFn)(tif, dp->tdir_tag, dp->tdir_count, cp)
+ : (*setFieldFn)(tif, dp->tdir_tag, cp));
+ }
+ if (cp != NULL)
+ _TIFFfree(cp);
+ } else if (CheckDirCount(tif, dp, 1)) { /* singleton value */
+ switch (dp->tdir_type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ /*
+ * If the tag is also acceptable as a LONG or SLONG
+ * then (*setFieldFn) will expect an uint32 parameter
+ * passed to it (through varargs). Thus, for machines
+ * where sizeof (int) != sizeof (uint32) we must do
+ * a careful check here. It's hard to say if this
+ * is worth optimizing.
+ *
+ * NB: We use TIFFFieldWithTag here knowing that
+ * it returns us the first entry in the table
+ * for the tag and that that entry is for the
+ * widest potential data type the tag may have.
+ */
+ { TIFFDataType type = fip->field_type;
+ if (type != TIFF_LONG && type != TIFF_SLONG) {
+ uint16 v = (uint16)
+ TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset);
+ ok = (fip->field_passcount ?
+ (*setFieldFn)(tif, dp->tdir_tag, 1, &v)
+ : (*setFieldFn)(tif, dp->tdir_tag, v));
+ break;
+ }
+ }
+ /* fall thru... */
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ { uint32 v32 =
+ TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset);
+ ok = (fip->field_passcount ?
+ (*setFieldFn)(tif, dp->tdir_tag, 1, &v32)
+ : (*setFieldFn)(tif, dp->tdir_tag, v32));
+ }
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ case TIFF_FLOAT:
+ { float v = (dp->tdir_type == TIFF_FLOAT ?
+ TIFFFetchFloat(tif, dp)
+ : TIFFFetchRational(tif, dp));
+ ok = (fip->field_passcount ?
+ (*setFieldFn)(tif, dp->tdir_tag, 1, &v)
+ : (*setFieldFn)(tif, dp->tdir_tag, v));
+ }
+ break;
+ case TIFF_DOUBLE:
+ { double v;
+ ok = (TIFFFetchDoubleArray(tif, dp, &v) &&
+ (fip->field_passcount ?
+ (*setFieldFn)(tif, dp->tdir_tag, 1, &v)
+ : (*setFieldFn)(tif, dp->tdir_tag, v))
+ );
+ }
+ break;
+ case TIFF_ASCII:
+ case TIFF_UNDEFINED: /* bit of a cheat... */
+ { char c[2];
+ if (ok = (TIFFFetchString(tif, dp, c) != 0)) {
+ c[1] = '\0'; /* XXX paranoid */
+ ok = (*setFieldFn)(tif, dp->tdir_tag, c);
+ }
+ }
+ break;
+ }
+ }
+ return (ok);
+}
+
+/* Everything after this is exactly duplicated from the standard tif_dirread.c
+ file, necessitated by the fact that they are declared static there so
+ we can't call them!
+*/
+#define NITEMS(x) (sizeof (x) / sizeof (x[0]))
+/*
+ * Fetch samples/pixel short values for
+ * the specified tag and verify that
+ * all values are the same.
+ */
+static int
+TIFFFetchPerSampleShorts(TIFF* tif, TIFFDirEntry* dir, int* pl)
+{
+ int samples = tif->tif_dir.td_samplesperpixel;
+ int status = 0;
+
+ if (CheckDirCount(tif, dir, (uint32) samples)) {
+ uint16 buf[10];
+ uint16* v = buf;
+
+ if (samples > NITEMS(buf))
+ v = (uint16*) _TIFFmalloc(samples * sizeof (uint16));
+ if (TIFFFetchShortArray(tif, dir, v)) {
+ int i;
+ for (i = 1; i < samples; i++)
+ if (v[i] != v[0]) {
+ TIFFError(tif->tif_name,
+ "Cannot handle different per-sample values for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ goto bad;
+ }
+ *pl = v[0];
+ status = 1;
+ }
+ bad:
+ if (v != buf)
+ _TIFFfree((char*) v);
+ }
+ return (status);
+}
+
+/*
+ * Fetch samples/pixel ANY values for
+ * the specified tag and verify that
+ * all values are the same.
+ */
+static int
+TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* pl)
+{
+ int samples = (int) tif->tif_dir.td_samplesperpixel;
+ int status = 0;
+
+ if (CheckDirCount(tif, dir, (uint32) samples)) {
+ double buf[10];
+ double* v = buf;
+
+ if (samples > NITEMS(buf))
+ v = (double*) _TIFFmalloc(samples * sizeof (double));
+ if (TIFFFetchAnyArray(tif, dir, v)) {
+ int i;
+ for (i = 1; i < samples; i++)
+ if (v[i] != v[0]) {
+ TIFFError(tif->tif_name,
+ "Cannot handle different per-sample values for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ goto bad;
+ }
+ *pl = v[0];
+ status = 1;
+ }
+ bad:
+ if (v != buf)
+ _TIFFfree(v);
+ }
+ return (status);
+}
+#undef NITEMS
+
+/*
+ * Fetch a set of offsets or lengths.
+ * While this routine says "strips",
+ * in fact it's also used for tiles.
+ */
+static int
+TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, long nstrips, uint32** lpp)
+{
+ register uint32* lp;
+ int status;
+
+ if (!CheckDirCount(tif, dir, (uint32) nstrips))
+ return (0);
+ /*
+ * Allocate space for strip information.
+ */
+ if (*lpp == NULL &&
+ (*lpp = (uint32 *)CheckMalloc(tif,
+ nstrips * sizeof (uint32), "for strip array")) == NULL)
+ return (0);
+ lp = *lpp;
+ if (dir->tdir_type == (int)TIFF_SHORT) {
+ /*
+ * Handle uint16->uint32 expansion.
+ */
+ uint16* dp = (uint16*) CheckMalloc(tif,
+ dir->tdir_count* sizeof (uint16), "to fetch strip tag");
+ if (dp == NULL)
+ return (0);
+ if (status = TIFFFetchShortArray(tif, dir, dp)) {
+ register uint16* wp = dp;
+ while (nstrips-- > 0)
+ *lp++ = *wp++;
+ }
+ _TIFFfree((char*) dp);
+ } else
+ status = TIFFFetchLongArray(tif, dir, lp);
+ return (status);
+}
+
+#define NITEMS(x) (sizeof (x) / sizeof (x[0]))
+/*
+ * Fetch and set the ExtraSamples tag.
+ */
+static int
+TIFFFetchExtraSamples(TIFF* tif, TIFFDirEntry* dir)
+{
+ uint16 buf[10];
+ uint16* v = buf;
+ int status;
+
+ if (dir->tdir_count > NITEMS(buf))
+ v = (uint16*) _TIFFmalloc(dir->tdir_count * sizeof (uint16));
+ if (dir->tdir_type == TIFF_BYTE)
+ status = TIFFFetchByteArray(tif, dir, v);
+ else
+ status = TIFFFetchShortArray(tif, dir, v);
+ if (status)
+ status = TIFFSetField(tif, dir->tdir_tag, dir->tdir_count, v);
+ if (v != buf)
+ _TIFFfree((char*) v);
+ return (status);
+}
+#undef NITEMS
+
+#ifdef COLORIMETRY_SUPPORT
+/*
+ * Fetch and set the RefBlackWhite tag.
+ */
+static int
+TIFFFetchRefBlackWhite(TIFF* tif, TIFFDirEntry* dir)
+{
+ static char mesg[] = "for \"ReferenceBlackWhite\" array";
+ char* cp;
+ int ok;
+
+ if (dir->tdir_type == TIFF_RATIONAL)
+ return (1/*TIFFFetchNormalTag(tif, dir) just so linker won't complain - this part of the code is never used anyway */);
+ /*
+ * Handle LONG's for backward compatibility.
+ */
+ cp = CheckMalloc(tif, dir->tdir_count * sizeof (uint32), mesg);
+ if (ok = (cp && TIFFFetchLongArray(tif, dir, (uint32*) cp))) {
+ float* fp = (float*)
+ CheckMalloc(tif, dir->tdir_count * sizeof (float), mesg);
+ if (ok = (fp != NULL)) {
+ uint32 i;
+ for (i = 0; i < dir->tdir_count; i++)
+ fp[i] = (float)((uint32*) cp)[i];
+ ok = TIFFSetField(tif, dir->tdir_tag, fp);
+ _TIFFfree((char*) fp);
+ }
+ }
+ if (cp)
+ _TIFFfree(cp);
+ return (ok);
+}
+#endif
+
+#if STRIPCHOP_SUPPORT
+/*
+ * Replace a single strip (tile) of uncompressed data by
+ * multiple strips (tiles), each approximately 8Kbytes.
+ * This is useful for dealing with large images or
+ * for dealing with machines with a limited amount
+ * memory.
+ */
+static void
+ChopUpSingleUncompressedStrip(TIFF* tif)
+{
+ register TIFFDirectory *td = &tif->tif_dir;
+ uint32 bytecount = td->td_stripbytecount[0];
+ uint32 offset = td->td_stripoffset[0];
+ tsize_t rowbytes = TIFFVTileSize(tif, 1), stripbytes;
+ tstrip_t strip, nstrips, rowsperstrip;
+ uint32* newcounts;
+ uint32* newoffsets;
+
+ /*
+ * Make the rows hold at least one
+ * scanline, but fill 8k if possible.
+ */
+ if (rowbytes > 8192) {
+ stripbytes = rowbytes;
+ rowsperstrip = 1;
+ } else {
+ rowsperstrip = 8192 / rowbytes;
+ stripbytes = rowbytes * rowsperstrip;
+ }
+ /* never increase the number of strips in an image */
+ if (rowsperstrip >= td->td_rowsperstrip)
+ return;
+ nstrips = (tstrip_t) TIFFhowmany(bytecount, stripbytes);
+ newcounts = (uint32*) CheckMalloc(tif, nstrips * sizeof (uint32),
+ "for chopped \"StripByteCounts\" array");
+ newoffsets = (uint32*) CheckMalloc(tif, nstrips * sizeof (uint32),
+ "for chopped \"StripOffsets\" array");
+ if (newcounts == NULL || newoffsets == NULL) {
+ /*
+ * Unable to allocate new strip information, give
+ * up and use the original one strip information.
+ */
+ if (newcounts != NULL)
+ _TIFFfree(newcounts);
+ if (newoffsets != NULL)
+ _TIFFfree(newoffsets);
+ return;
+ }
+ /*
+ * Fill the strip information arrays with
+ * new bytecounts and offsets that reflect
+ * the broken-up format.
+ */
+ for (strip = 0; strip < nstrips; strip++) {
+ if (stripbytes > bytecount)
+ stripbytes = bytecount;
+ newcounts[strip] = stripbytes;
+ newoffsets[strip] = offset;
+ offset += stripbytes;
+ bytecount -= stripbytes;
+ }
+ /*
+ * Replace old single strip info with multi-strip info.
+ */
+ td->td_stripsperimage = td->td_nstrips = nstrips;
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+ _TIFFfree(td->td_stripbytecount);
+ _TIFFfree(td->td_stripoffset);
+ td->td_stripbytecount = newcounts;
+ td->td_stripoffset = newoffsets;
+}
+#endif /* STRIPCHOP_SUPPORT */
diff --git a/contrib/pds/tif_pdsdirwrite.c b/contrib/pds/tif_pdsdirwrite.c
new file mode 100644
index 00000000..73dbd9ce
--- /dev/null
+++ b/contrib/pds/tif_pdsdirwrite.c
@@ -0,0 +1,964 @@
+/* $Header: /d1/sam/tiff/contrib/pds/RCS/tif_pdsdirwrite.c,v 1.1 1997/08/29 23:12:56 sam Exp $ */
+
+/* When writing data to TIFF files, it is often useful to store application-
+ specific data in a private TIFF directory so that the tags don't need to
+ be registered and won't conflict with other people's user-defined tags.
+ One needs to have a registered public tag which contains some amount of
+ raw data. That raw data, however, is interpreted at an independent,
+ separate, private tiff directory. This file provides some routines which
+ will be useful for converting that data from its raw binary form into
+ the proper form for your application.
+*/
+
+/*
+ * Copyright (c) 1988-1996 Sam Leffler
+ * Copyright (c) 1991-1996 Silicon Graphics, Inc.
+ * Copyright (c( 1996 USAF Phillips Laboratory
+ *
+ * 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.
+ *
+ * These routines written by Conrad J. Poelman on a single late-night of
+ * March 20-21, 1996.
+ *
+ * The entire purpose of this file is to provide a single external function,
+ * TIFFWritePrivateDataSubDirectory(). This function is intended for use
+ * in writing a private subdirectory structure into a TIFF file. The
+ * actual reading of data from the structure is handled by the getFieldFn(),
+ * which is passed to TIFFWritePrivateDataSubDirectory() as a parameter. The
+ * idea is to enable any application wishing to read private subdirectories to
+ * do so easily using this function, without modifying the TIFF library.
+ *
+ * The astute observer will notice that only two functions are at all different
+ * from the original tif_dirwrite.c file: TIFFWritePrivateDataSubDirectory()and
+ * TIFFWriteNormalSubTag(). All the other stuff that makes this file so huge
+ * is only necessary because all of those functions are declared static in
+ * tif_dirwrite.c, so we have to totally duplicate them in order to use them.
+ *
+ * Oh, also please note the bug-fix in the routine TIFFWriteNormalSubTag(),
+ * which equally should be applied to TIFFWriteNormalTag().
+ *
+ */
+#include "tiffiop.h"
+
+#if HAVE_IEEEFP
+#define TIFFCvtNativeToIEEEFloat(tif, n, fp)
+#define TIFFCvtNativeToIEEEDouble(tif, n, dp)
+#else
+extern void TIFFCvtNativeToIEEEFloat(TIFF*, uint32, float*);
+extern void TIFFCvtNativeToIEEEDouble(TIFF*, uint32, double*);
+#endif
+
+static int TIFFWriteNormalTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*);
+static int TIFFWriteNormalSubTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*,
+ int (*getFieldFn)(TIFF *tif,ttag_t tag,...));
+static void TIFFSetupShortLong(TIFF*, ttag_t, TIFFDirEntry*, uint32);
+static int TIFFSetupShortPair(TIFF*, ttag_t, TIFFDirEntry*);
+static int TIFFWritePerSampleShorts(TIFF*, ttag_t, TIFFDirEntry*);
+static int TIFFWritePerSampleAnys(TIFF*, TIFFDataType, ttag_t, TIFFDirEntry*);
+static int TIFFWriteShortTable(TIFF*, ttag_t, TIFFDirEntry*, uint32, uint16**);
+static int TIFFWriteShortArray(TIFF*,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, uint16*);
+static int TIFFWriteLongArray(TIFF *,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, uint32*);
+static int TIFFWriteRationalArray(TIFF *,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, float*);
+static int TIFFWriteFloatArray(TIFF *,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, float*);
+static int TIFFWriteDoubleArray(TIFF *,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, double*);
+static int TIFFWriteByteArray(TIFF*, TIFFDirEntry*, char*);
+static int TIFFWriteAnyArray(TIFF*,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, double*);
+#ifdef COLORIMETRY_SUPPORT
+static int TIFFWriteTransferFunction(TIFF*, TIFFDirEntry*);
+#endif
+static int TIFFWriteData(TIFF*, TIFFDirEntry*, char*);
+static int TIFFLinkDirectory(TIFF*);
+
+#define WriteRationalPair(type, tag1, v1, tag2, v2) { \
+ if (!TIFFWriteRational(tif, type, tag1, dir, v1)) \
+ goto bad; \
+ if (!TIFFWriteRational(tif, type, tag2, dir+1, v2)) \
+ goto bad; \
+ dir++; \
+}
+#define TIFFWriteRational(tif, type, tag, dir, v) \
+ TIFFWriteRationalArray((tif), (type), (tag), (dir), 1, &(v))
+#ifndef TIFFWriteRational
+static int TIFFWriteRational(TIFF*,
+ TIFFDataType, ttag_t, TIFFDirEntry*, float);
+#endif
+
+/* This function will write an entire directory to the disk, and return the
+ offset value indicating where in the file it wrote the beginning of the
+ directory structure. This is NOT the same as the offset value before
+ calling this function, because some of the fields may have caused various
+ data items to be written out BEFORE writing the directory structure.
+
+ This code was basically written by ripping of the TIFFWriteDirectory()
+ code and generalizing it, using RPS's TIFFWritePliIfd() code for
+ inspiration. My original goal was to make this code general enough that
+ the original TIFFWriteDirectory() could be rewritten to just call this
+ function with the appropriate field and field-accessing arguments.
+
+ However, now I realize that there's a lot of code that gets executed for
+ the main, standard TIFF directories that does not apply to special
+ private subdirectories, so such a reimplementation for the sake of
+ eliminating redundant or duplicate code is probably not possible,
+ unless we also pass in a Main flag to indiciate which type of handling
+ to do, which would be kind of a hack. I've marked those places where I
+ changed or ripped out code which would have to be re-inserted to
+ generalize this function. If it can be done in a clean and graceful way,
+ it would be a great way to generalize the TIFF library. Otherwise, I'll
+ just leave this code here where it duplicates but remains on top of and
+ hopefully mostly independent of the main TIFF library.
+
+ The caller will probably want to free the sub directory structure after
+ returning from this call, since otherwise once written out, the user
+ is likely to forget about it and leave data lying around.
+*/
+toff_t
+TIFFWritePrivateDataSubDirectory(TIFF* tif,
+ uint32 pdir_fieldsset[], int pdir_fields_last,
+ TIFFFieldInfo *field_info,
+ int (*getFieldFn)(TIFF *tif, ttag_t tag, ...))
+{
+ uint16 dircount;
+ uint32 diroff, nextdiroff;
+ ttag_t tag;
+ uint32 nfields;
+ tsize_t dirsize;
+ char* data;
+ TIFFDirEntry* dir;
+ u_long b, *fields, fields_size;
+ toff_t directory_offset;
+ TIFFFieldInfo* fip;
+
+ /*
+ * Deleted out all of the encoder flushing and such code from here -
+ * not necessary for subdirectories.
+ */
+
+ /* Finish writing out any image data. */
+ TIFFFlushData(tif);
+
+ /*
+ * Size the directory so that we can calculate
+ * offsets for the data items that aren't kept
+ * in-place in each field.
+ */
+ nfields = 0;
+ for (b = 0; b <= pdir_fields_last; b++)
+ if (FieldSet(pdir_fieldsset, b))
+ /* Deleted code to make size of first 4 tags 2
+ instead of 1. */
+ nfields += 1;
+ dirsize = nfields * sizeof (TIFFDirEntry);
+ data = (char*) _TIFFmalloc(dirsize);
+ if (data == NULL) {
+ TIFFError(tif->tif_name,
+ "Cannot write private subdirectory, out of space");
+ return (0);
+ }
+ /*
+ * Place directory in data section of the file. If there isn't one
+ * yet, place it at the end of the file. The directory is treated as
+ * data, so we don't link it into the directory structure at all.
+ */
+ if (tif->tif_dataoff == 0)
+ tif->tif_dataoff =(TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
+ diroff = tif->tif_dataoff;
+ tif->tif_dataoff = (toff_t)(
+ diroff + sizeof (uint16) + dirsize + sizeof (toff_t));
+ if (tif->tif_dataoff & 1)
+ tif->tif_dataoff++;
+ (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
+ /*tif->tif_curdir++;*/
+ dir = (TIFFDirEntry*) data;
+ /*
+ * Setup external form of directory
+ * entries and write data items.
+ */
+ /*
+ * We make a local copy of the fieldsset here so that we don't mess
+ * up the original one when we call ResetFieldBit(). But I'm not sure
+ * why the original code calls ResetFieldBit(), since we're already
+ * going through the fields in order...
+ *
+ * fields_size is the number of uint32's we will need to hold the
+ * bit-mask for all of the fields. If our highest field number is
+ * 100, then we'll need 100 / (8*4)+1 == 4 uint32's to hold the
+ * fieldset.
+ *
+ * Unlike the original code, we allocate fields dynamically based
+ * on the requested pdir_fields_last value, allowing private
+ * data subdirectories to contain more than the built-in code's limit
+ * of 95 tags in a directory.
+ */
+ fields_size = pdir_fields_last / (8*sizeof(uint32)) + 1;
+ fields = _TIFFmalloc(fields_size*sizeof(uint32));
+ _TIFFmemcpy(fields, pdir_fieldsset, fields_size * sizeof(uint32));
+
+ /* Deleted "write out extra samples tag" code here. */
+
+ /* Deleted code for checking a billion little special cases for the
+ * standard TIFF tags. Should add a general mechanism for overloading
+ * write function for each field, just like Brian kept telling me!!!
+ */
+ for (fip = field_info; fip->field_tag; fip++) {
+ /* Deleted code to check for FIELD_IGNORE!! */
+ if (/* fip->field_bit == FIELD_IGNORE || */
+ !FieldSet(fields, fip->field_bit))
+ continue;
+ if (!TIFFWriteNormalSubTag(tif, dir, fip, getFieldFn))
+ goto bad;
+ dir++;
+ ResetFieldBit(fields, fip->field_bit);
+ }
+
+ /* Now we've written all of the referenced data, and are about to
+ write the main directory structure, so grab the tif_dataoff value
+ now so we can remember where we wrote the directory. */
+ directory_offset = tif->tif_dataoff;
+
+ /*
+ * Write directory.
+ */
+ dircount = (uint16) nfields;
+ /* Deleted code to link to the next directory - we set it to zero! */
+ nextdiroff = 0;
+ if (tif->tif_flags & TIFF_SWAB) {
+ /*
+ * The file's byte order is opposite to the
+ * native machine architecture. We overwrite
+ * the directory information with impunity
+ * because it'll be released below after we
+ * write it to the file. Note that all the
+ * other tag construction routines assume that
+ * we do this byte-swapping; i.e. they only
+ * byte-swap indirect data.
+ */
+ for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) {
+ TIFFSwabArrayOfShort(&dir->tdir_tag, 2);
+ TIFFSwabArrayOfLong(&dir->tdir_count, 2);
+ }
+ dircount = (uint16) nfields;
+ TIFFSwabShort(&dircount);
+ TIFFSwabLong(&nextdiroff);
+ }
+
+ (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
+ if (!WriteOK(tif, &dircount, sizeof (dircount))) {
+ TIFFError(tif->tif_name, "Error writing private subdirectory count");
+ goto bad;
+ }
+ if (!WriteOK(tif, data, dirsize)) {
+ TIFFError(tif->tif_name, "Error writing private subdirectory contents");
+ goto bad;
+ }
+ if (!WriteOK(tif, &nextdiroff, sizeof (nextdiroff))) {
+ TIFFError(tif->tif_name, "Error writing private subdirectory link");
+ goto bad;
+ }
+ tif->tif_dataoff += sizeof(dircount) + dirsize + sizeof(nextdiroff);
+
+ _TIFFfree(data);
+ _TIFFfree(fields);
+ tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+
+#if (0)
+ /* This stuff commented out because I don't think we want it for
+ subdirectories, but I could be wrong. */
+ (*tif->tif_cleanup)(tif);
+
+ /*
+ * Reset directory-related state for subsequent
+ * directories.
+ */
+ TIFFDefaultDirectory(tif);
+ tif->tif_curoff = 0;
+ tif->tif_row = (uint32) -1;
+ tif->tif_curstrip = (tstrip_t) -1;
+#endif
+
+ return (directory_offset);
+bad:
+ _TIFFfree(data);
+ _TIFFfree(fields);
+ return (0);
+}
+#undef WriteRationalPair
+
+/*
+ * Process tags that are not special cased.
+ */
+/* The standard function TIFFWriteNormalTag() could definitely be replaced
+ with a simple call to this function, just adding TIFFGetField() as the
+ last argument. */
+static int
+TIFFWriteNormalSubTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip,
+ int (*getFieldFn)(TIFF *tif, ttag_t tag, ...))
+{
+ u_short wc = (u_short) fip->field_writecount;
+
+ dir->tdir_tag = fip->field_tag;
+ dir->tdir_type = (u_short) fip->field_type;
+ dir->tdir_count = wc;
+#define WRITEF(x,y) x(tif, fip->field_type, fip->field_tag, dir, wc, y)
+ switch (fip->field_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ if (wc > 1) {
+ uint16* wp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &wp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &wp);
+ if (!WRITEF(TIFFWriteShortArray, wp))
+ return (0);
+ } else {
+ uint16 sv;
+ (*getFieldFn)(tif, fip->field_tag, &sv);
+ dir->tdir_offset =
+ TIFFInsertData(tif, dir->tdir_type, sv);
+ }
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ if (wc > 1) {
+ uint32* lp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &lp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &lp);
+ if (!WRITEF(TIFFWriteLongArray, lp))
+ return (0);
+ } else {
+ /* XXX handle LONG->SHORT conversion */
+ (*getFieldFn)(tif, fip->field_tag, &dir->tdir_offset);
+ }
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ if (wc > 1) {
+ float* fp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &fp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &fp);
+ if (!WRITEF(TIFFWriteRationalArray, fp))
+ return (0);
+ } else {
+ float fv;
+ (*getFieldFn)(tif, fip->field_tag, &fv);
+ if (!WRITEF(TIFFWriteRationalArray, &fv))
+ return (0);
+ }
+ break;
+ case TIFF_FLOAT:
+ if (wc > 1) {
+ float* fp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &fp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &fp);
+ if (!WRITEF(TIFFWriteFloatArray, fp))
+ return (0);
+ } else {
+ float fv;
+ (*getFieldFn)(tif, fip->field_tag, &fv);
+ if (!WRITEF(TIFFWriteFloatArray, &fv))
+ return (0);
+ }
+ break;
+ case TIFF_DOUBLE:
+ /* Hey - I think this is a bug, or at least a "gross
+ inconsistency", in the TIFF library. Look at the original
+ TIFF library code below within the "#if (0) ... #else".
+ Just from the type of *dp, you can see that this code
+ expects TIFFGetField() to be handed a double ** for
+ any TIFF_DOUBLE tag, even for the constant wc==1 case.
+ This is totally inconsistent with other fields (like
+ TIFF_FLOAT, above) and is also inconsistent with the
+ TIFFSetField() function for TIFF_DOUBLEs, which expects
+ to be passed a single double by value for the wc==1 case.
+ (See the handling of TIFFFetchNormalTag() in tif_dirread.c
+ for an example.) Maybe this function was written before
+ TIFFWriteDoubleArray() was written, not that that's an
+ excuse. Anyway, the new code below is a trivial modification
+ of the TIFF_FLOAT code above. The fact that even single
+ doubles get written out in the data segment and get an
+ offset value stored is irrelevant here - that is all
+ handled by TIFFWriteDoubleArray(). */
+#if (0)
+ { double* dp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &dp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &dp);
+ TIFFCvtNativeToIEEEDouble(tif, wc, dp);
+ if (!TIFFWriteData(tif, dir, (char*) dp))
+ return (0);
+ }
+#else
+ if (wc > 1) {
+ double* dp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &dp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &dp);
+ if (!WRITEF(TIFFWriteDoubleArray, dp))
+ return (0);
+ } else {
+ double dv;
+ (*getFieldFn)(tif, fip->field_tag, &dv);
+ if (!WRITEF(TIFFWriteDoubleArray, &dv))
+ return (0);
+ }
+#endif
+ break;
+ case TIFF_ASCII:
+ { char* cp;
+ (*getFieldFn)(tif, fip->field_tag, &cp);
+ dir->tdir_count = (uint32) (strlen(cp) + 1);
+ if (!TIFFWriteByteArray(tif, dir, cp))
+ return (0);
+ }
+ break;
+ case TIFF_UNDEFINED:
+ { char* cp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &cp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &cp);
+ if (!TIFFWriteByteArray(tif, dir, cp))
+ return (0);
+ }
+ break;
+ }
+ return (1);
+}
+#undef WRITEF
+
+/* Everything after this is exactly duplicated from the standard tif_dirwrite.c
+ file, necessitated by the fact that they are declared static there so
+ we can't call them!
+*/
+/*
+ * Setup a directory entry with either a SHORT
+ * or LONG type according to the value.
+ */
+static void
+TIFFSetupShortLong(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint32 v)
+{
+ dir->tdir_tag = tag;
+ dir->tdir_count = 1;
+ if (v > 0xffffL) {
+ dir->tdir_type = (short) TIFF_LONG;
+ dir->tdir_offset = v;
+ } else {
+ dir->tdir_type = (short) TIFF_SHORT;
+ dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v);
+ }
+}
+#undef MakeShortDirent
+
+#ifndef TIFFWriteRational
+/*
+ * Setup a RATIONAL directory entry and
+ * write the associated indirect value.
+ */
+static int
+TIFFWriteRational(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, float v)
+{
+ return (TIFFWriteRationalArray(tif, type, tag, dir, 1, &v));
+}
+#endif
+
+#define NITEMS(x) (sizeof (x) / sizeof (x[0]))
+/*
+ * Setup a directory entry that references a
+ * samples/pixel array of SHORT values and
+ * (potentially) write the associated indirect
+ * values.
+ */
+static int
+TIFFWritePerSampleShorts(TIFF* tif, ttag_t tag, TIFFDirEntry* dir)
+{
+ uint16 buf[10], v;
+ uint16* w = buf;
+ int i, status, samples = tif->tif_dir.td_samplesperpixel;
+
+ if (samples > NITEMS(buf))
+ w = (uint16*) _TIFFmalloc(samples * sizeof (uint16));
+ TIFFGetField(tif, tag, &v);
+ for (i = 0; i < samples; i++)
+ w[i] = v;
+ status = TIFFWriteShortArray(tif, TIFF_SHORT, tag, dir, samples, w);
+ if (w != buf)
+ _TIFFfree((char*) w);
+ return (status);
+}
+
+/*
+ * Setup a directory entry that references a samples/pixel array of ``type''
+ * values and (potentially) write the associated indirect values. The source
+ * data from TIFFGetField() for the specified tag must be returned as double.
+ */
+static int
+TIFFWritePerSampleAnys(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir)
+{
+ double buf[10], v;
+ double* w = buf;
+ int i, status;
+ int samples = (int) tif->tif_dir.td_samplesperpixel;
+
+ if (samples > NITEMS(buf))
+ w = (double*) _TIFFmalloc(samples * sizeof (double));
+ TIFFGetField(tif, tag, &v);
+ for (i = 0; i < samples; i++)
+ w[i] = v;
+ status = TIFFWriteAnyArray(tif, type, tag, dir, samples, w);
+ if (w != buf)
+ _TIFFfree(w);
+ return (status);
+}
+#undef NITEMS
+
+/*
+ * Setup a pair of shorts that are returned by
+ * value, rather than as a reference to an array.
+ */
+static int
+TIFFSetupShortPair(TIFF* tif, ttag_t tag, TIFFDirEntry* dir)
+{
+ uint16 v[2];
+
+ TIFFGetField(tif, tag, &v[0], &v[1]);
+ return (TIFFWriteShortArray(tif, TIFF_SHORT, tag, dir, 2, v));
+}
+
+/*
+ * Setup a directory entry for an NxM table of shorts,
+ * where M is known to be 2**bitspersample, and write
+ * the associated indirect data.
+ */
+static int
+TIFFWriteShortTable(TIFF* tif,
+ ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16** table)
+{
+ uint32 i, off;
+
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) TIFF_SHORT;
+ /* XXX -- yech, fool TIFFWriteData */
+ dir->tdir_count = (uint32) (1L<<tif->tif_dir.td_bitspersample);
+ off = tif->tif_dataoff;
+ for (i = 0; i < n; i++)
+ if (!TIFFWriteData(tif, dir, (char *)table[i]))
+ return (0);
+ dir->tdir_count *= n;
+ dir->tdir_offset = off;
+ return (1);
+}
+
+/*
+ * Write/copy data associated with an ASCII or opaque tag value.
+ */
+static int
+TIFFWriteByteArray(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ if (dir->tdir_count > 4) {
+ if (!TIFFWriteData(tif, dir, cp))
+ return (0);
+ } else
+ _TIFFmemcpy(&dir->tdir_offset, cp, dir->tdir_count);
+ return (1);
+}
+
+/*
+ * Setup a directory entry of an array of SHORT
+ * or SSHORT and write the associated indirect values.
+ */
+static int
+TIFFWriteShortArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16* v)
+{
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ if (n <= 2) {
+ if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+ dir->tdir_offset = (uint32) ((long) v[0] << 16);
+ if (n == 2)
+ dir->tdir_offset |= v[1] & 0xffff;
+ } else {
+ dir->tdir_offset = v[0] & 0xffff;
+ if (n == 2)
+ dir->tdir_offset |= (long) v[1] << 16;
+ }
+ return (1);
+ } else
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Setup a directory entry of an array of LONG
+ * or SLONG and write the associated indirect values.
+ */
+static int
+TIFFWriteLongArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, uint32* v)
+{
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ if (n == 1) {
+ dir->tdir_offset = v[0];
+ return (1);
+ } else
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Setup a directory entry of an array of RATIONAL
+ * or SRATIONAL and write the associated indirect values.
+ */
+static int
+TIFFWriteRationalArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, float* v)
+{
+ uint32 i;
+ uint32* t;
+ int status;
+
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ t = (uint32*) _TIFFmalloc(2*n * sizeof (uint32));
+ for (i = 0; i < n; i++) {
+ float fv = v[i];
+ int sign = 1;
+ uint32 den;
+
+ if (fv < 0) {
+ if (type == TIFF_RATIONAL) {
+ TIFFWarning(tif->tif_name,
+ "\"%s\": Information lost writing value (%g) as (unsigned) RATIONAL",
+ _TIFFFieldWithTag(tif,tag)->field_name, v);
+ fv = 0;
+ } else
+ fv = -fv, sign = -1;
+ }
+ den = 1L;
+ if (fv > 0) {
+ while (fv < 1L<<(31-3) && den < 1L<<(31-3))
+ fv *= 1<<3, den *= 1L<<3;
+ }
+ t[2*i+0] = sign * (fv + 0.5);
+ t[2*i+1] = den;
+ }
+ status = TIFFWriteData(tif, dir, (char *)t);
+ _TIFFfree((char*) t);
+ return (status);
+}
+
+static int
+TIFFWriteFloatArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, float* v)
+{
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ TIFFCvtNativeToIEEEFloat(tif, n, v);
+ if (n == 1) {
+ dir->tdir_offset = *(uint32*) &v[0];
+ return (1);
+ } else
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+static int
+TIFFWriteDoubleArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v)
+{
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ TIFFCvtNativeToIEEEDouble(tif, n, v);
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Write an array of ``type'' values for a specified tag (i.e. this is a tag
+ * which is allowed to have different types, e.g. SMaxSampleType).
+ * Internally the data values are represented as double since a double can
+ * hold any of the TIFF tag types (yes, this should really be an abstract
+ * type tany_t for portability). The data is converted into the specified
+ * type in a temporary buffer and then handed off to the appropriate array
+ * writer.
+ */
+static int
+TIFFWriteAnyArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v)
+{
+ char buf[10 * sizeof(double)];
+ char* w = buf;
+ int i, status = 0;
+
+ if (n * tiffDataWidth[type] > sizeof buf)
+ w = (char*) _TIFFmalloc(n * tiffDataWidth[type]);
+ switch (type) {
+ case TIFF_BYTE:
+ { unsigned char* bp = (unsigned char*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (unsigned char) v[i];
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ if (!TIFFWriteByteArray(tif, dir, (char*) bp))
+ goto out;
+ }
+ break;
+ case TIFF_SBYTE:
+ { signed char* bp = (signed char*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (signed char) v[i];
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ if (!TIFFWriteByteArray(tif, dir, (char*) bp))
+ goto out;
+ }
+ break;
+ case TIFF_SHORT:
+ { uint16* bp = (uint16*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (uint16) v[i];
+ if (!TIFFWriteShortArray(tif, type, tag, dir, n, (uint16*)bp))
+ goto out;
+ }
+ break;
+ case TIFF_SSHORT:
+ { int16* bp = (int16*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (int16) v[i];
+ if (!TIFFWriteShortArray(tif, type, tag, dir, n, (uint16*)bp))
+ goto out;
+ }
+ break;
+ case TIFF_LONG:
+ { uint32* bp = (uint32*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (uint32) v[i];
+ if (!TIFFWriteLongArray(tif, type, tag, dir, n, bp))
+ goto out;
+ }
+ break;
+ case TIFF_SLONG:
+ { int32* bp = (int32*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (int32) v[i];
+ if (!TIFFWriteLongArray(tif, type, tag, dir, n, (uint32*) bp))
+ goto out;
+ }
+ break;
+ case TIFF_FLOAT:
+ { float* bp = (float*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (float) v[i];
+ if (!TIFFWriteFloatArray(tif, type, tag, dir, n, bp))
+ goto out;
+ }
+ break;
+ case TIFF_DOUBLE:
+ return (TIFFWriteDoubleArray(tif, type, tag, dir, n, v));
+ default:
+ /* TIFF_NOTYPE */
+ /* TIFF_ASCII */
+ /* TIFF_UNDEFINED */
+ /* TIFF_RATIONAL */
+ /* TIFF_SRATIONAL */
+ goto out;
+ }
+ status = 1;
+ out:
+ if (w != buf)
+ _TIFFfree(w);
+ return (status);
+}
+
+#ifdef COLORIMETRY_SUPPORT
+static int
+TIFFWriteTransferFunction(TIFF* tif, TIFFDirEntry* dir)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+ tsize_t n = (1L<<td->td_bitspersample) * sizeof (uint16);
+ uint16** tf = td->td_transferfunction;
+ int ncols;
+
+ /*
+ * Check if the table can be written as a single column,
+ * or if it must be written as 3 columns. Note that we
+ * write a 3-column tag if there are 2 samples/pixel and
+ * a single column of data won't suffice--hmm.
+ */
+ switch (td->td_samplesperpixel - td->td_extrasamples) {
+ default: if (_TIFFmemcmp(tf[0], tf[2], n)) { ncols = 3; break; }
+ case 2: if (_TIFFmemcmp(tf[0], tf[1], n)) { ncols = 3; break; }
+ case 1: case 0: ncols = 1;
+ }
+ return (TIFFWriteShortTable(tif,
+ TIFFTAG_TRANSFERFUNCTION, dir, ncols, tf));
+}
+#endif
+
+/*
+ * Write a contiguous directory item.
+ */
+static int
+TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ tsize_t cc;
+
+ if (tif->tif_flags & TIFF_SWAB) {
+ switch (dir->tdir_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count);
+ break;
+ case TIFF_DOUBLE:
+ TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count);
+ break;
+ }
+ }
+ dir->tdir_offset = tif->tif_dataoff;
+ cc = dir->tdir_count * tiffDataWidth[dir->tdir_type];
+ if (SeekOK(tif, dir->tdir_offset) &&
+ WriteOK(tif, cp, cc)) {
+ tif->tif_dataoff += (cc + 1) & ~1;
+ return (1);
+ }
+ TIFFError(tif->tif_name, "Error writing data for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ return (0);
+}
+
+/*
+ * Link the current directory into the
+ * directory chain for the file.
+ */
+static int
+TIFFLinkDirectory(TIFF* tif)
+{
+ static const char module[] = "TIFFLinkDirectory";
+ uint32 nextdir;
+ uint32 diroff;
+
+ tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
+ diroff = (uint32) tif->tif_diroff;
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&diroff);
+#if SUBIFD_SUPPORT
+ if (tif->tif_flags & TIFF_INSUBIFD) {
+ (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
+ if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+ TIFFError(module,
+ "%s: Error writing SubIFD directory link",
+ tif->tif_name);
+ return (0);
+ }
+ /*
+ * Advance to the next SubIFD or, if this is
+ * the last one configured, revert back to the
+ * normal directory linkage.
+ */
+ if (--tif->tif_nsubifd)
+ tif->tif_subifdoff += sizeof (diroff);
+ else
+ tif->tif_flags &= ~TIFF_INSUBIFD;
+ return (1);
+ }
+#endif
+ if (tif->tif_header.tiff_diroff == 0) {
+ /*
+ * First directory, overwrite offset in header.
+ */
+ tif->tif_header.tiff_diroff = (uint32) tif->tif_diroff;
+#define HDROFF(f) ((toff_t) &(((TIFFHeader*) 0)->f))
+ (void) TIFFSeekFile(tif, HDROFF(tiff_diroff), SEEK_SET);
+ if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+ TIFFError(tif->tif_name, "Error writing TIFF header");
+ return (0);
+ }
+ return (1);
+ }
+ /*
+ * Not the first directory, search to the last and append.
+ */
+ nextdir = tif->tif_header.tiff_diroff;
+ do {
+ uint16 dircount;
+
+ if (!SeekOK(tif, nextdir) ||
+ !ReadOK(tif, &dircount, sizeof (dircount))) {
+ TIFFError(module, "Error fetching directory count");
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ (void) TIFFSeekFile(tif,
+ dircount * sizeof (TIFFDirEntry), SEEK_CUR);
+ if (!ReadOK(tif, &nextdir, sizeof (nextdir))) {
+ TIFFError(module, "Error fetching directory link");
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&nextdir);
+ } while (nextdir != 0);
+ (void) TIFFSeekFile(tif, -(toff_t) sizeof (nextdir), SEEK_CUR);
+ if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+ TIFFError(module, "Error writing directory link");
+ return (0);
+ }
+ return (1);
+}
diff --git a/contrib/ras/README b/contrib/ras/README
new file mode 100644
index 00000000..f87bfde0
--- /dev/null
+++ b/contrib/ras/README
@@ -0,0 +1,10 @@
+Sun May 19 22:28:16 PDT 1991
+
+These programs are from Patrick Naughton (naughton@wind.sun.com).
+I've tried to update them to reflect changes to the library, but
+I am unable to verify that they operate properly, because they
+require the Sun pixrect library.
+
+Please contact Patrick directly if you have questions/problems.
+
+ Sam
diff --git a/contrib/winnt/README.console b/contrib/winnt/README.console
new file mode 100644
index 00000000..05d7dd58
--- /dev/null
+++ b/contrib/winnt/README.console
@@ -0,0 +1,182 @@
+Date: Fri, 18 Apr 1997 09:25:09 EDT
+To: "'sam@cthulhu.engr.sgi.com'" <sam@cthulhu.engr.sgi.com>
+cc: "'tiff@sgi.engr.sgi.com'" <tiff@sgi.engr.sgi.com>
+
+From: xingong chang <xingong@feith1.FEITH.COM>
+Subject: Contribution: libtiff for Windows-nt console applications
+
+Return-Path: xingong@feith1.FEITH.COM
+Delivery-Date: Fri, 18 Apr 1997 06:37:38 -0700
+Return-Path: xingong@feith1.FEITH.COM
+MIME-Version: 1.0
+
+Hi,
+I built the libtiff under WINNT 4.0 as a 32-bit library for pure
+console applications. I made the makefile.nt based on Philippe
+Tenenhaus' makefile.w95 file. Since I want my stuff to be a pure
+console application running on WinNT, Dave Dyer's makefile for WINNT is
+not good for me since it is for Windows applications.
+
+I used the tif_msdos.c file instead of the tif_win32.c in the $(OBJS)
+list because tif_win32.c is not a pure console program, it includes
+some function calls such as MessageBox etc which requires windows
+application library ($winslib as defined in <ntwin32.mak>).
+
+unlike Philippe Tenenhaus' makefile.w95 file, this makefile.nt does
+support fax3 stuff. And to make the mkg3states.exe,the getopt.obj is
+needed. "getopt" package is ATT public domain source for getopt(3).
+Also you need to inlcude the g3states.h in tif_fax.c fileand modify the
+tif_fax3.h to delete the external declaration of FFFaxMainTable,
+TIFFFaxWhileTable and TIFFFaxBlackTable
+
+
+libtiff version: TIFFLIB_VERSION 19960307
+
+Hardware you are using: i386
+
+Operating system you are using: Windows NT 4.0
+
+C compiler : Microsoft Visual C++ 4.1
+
+NMAKE : Microsoft nmake 1.61
+
+
+Here is the makefile.nt I used:
+---------------------------------------------------------
+
+# makefile.nt for the tiff library
+# Tag Image File Format Library
+#
+# Copyright (c) 1988, 1989, 1990, 1991, 1992 Sam Leffler
+# Copyright (c) 1991, 1992 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.
+#
+# This Makefile is for use with microsoft nmake version 1.61
+#
+
+!include <ntwin32.mak>
+
+DEFS = -DBSDTYPES -DO_RDONLY=S_IREAD -DO_RDWR=S_IWRITE
+
+INCS= tiff.h tiffio.h
+SRCS= tif_aux.c \
+ tif_close.c \
+ tif_codec.c \
+ tif_compress.c \
+ tif_dir.c \
+ tif_dirinfo.c \
+ tif_dirread.c \
+ tif_dirwrite.c \
+ tif_dumpmode.c \
+ tif_error.c \
+ tif_getimage.c \
+ tif_jpeg.c \
+ tif_flush.c \
+ tif_lzw.c \
+ tif_next.c \
+ tif_open.c \
+ tif_packbits.c \
+ tif_predict \
+ tif_print.c \
+ tif_read.c \
+ tif_swab.c \
+ tif_strip.c \
+ tif_thunder.c \
+ tif_tile.c \
+ tif_version.c \
+ tif_warning.c \
+ tif_write.c \
+ tif_msdos.c \
+ tif_fax3.c
+
+
+OBJS= tif_aux.obj \
+ tif_close.obj \
+ tif_codec.obj \
+ tif_compress.obj \
+ tif_dir.obj \
+ tif_dirinfo.obj \
+ tif_dirread.obj \
+ tif_dirwrite.obj \
+ tif_dumpmode.obj \
+ tif_error.obj \
+ tif_getimage.obj \
+ tif_jpeg.obj \
+ tif_flush.obj \
+ tif_lzw.obj \
+ tif_next.obj \
+ tif_open.obj \
+ tif_packbits.obj \
+ tif_predict.obj \
+ tif_print.obj \
+ tif_read.obj \
+ tif_swab.obj \
+ tif_strip.obj \
+ tif_thunder.obj \
+ tif_tile.obj \
+ tif_version.obj \
+ tif_warning.obj \
+ tif_write.obj \
+ tif_msdos.obj \
+ tif_fax3.obj
+
+#To make the mkg3states.exe,the getopt.obj is needed. getopt package is
+# ATT public domain source for getopt(3).
+EXTRA_OBJS = getopt.obj
+
+all: libtiff.lib
+
+libtiff.lib: $(OBJS)
+ del libtiff.lib
+ lib -out:libtiff.lib $(OBJS)
+
+.c.obj:
+ $(cc) $(DEFS) $(cdebug) $(cflags) $(cvarsmt) $*.c
+
+
+#To include fax3 support, we did this modification
+#add to the build script : tif_fax3.c and tif_fax3.obj
+#define CCITT_SUPPORT in the file tifconf.h
+#inlcude the g3states.h in tif_fax.c file
+#modify the tif_fax3.h to delete the TIFFFaxMainTable,TIFFFaxWhileTable
+# TIFFFaxBlackTable etc external declaration
+#mkg3states.exe without any command line options will produce the g3states.h
+
+$(OBJS): tiffio.h tiff.h tiffcomp.h tiffiop.h tiffconf.h
+tif_fax3.obj: tif_fax3.c g3states.h t4.h tif_fax3.h
+
+g3states.h: mkg3states.obj t4.h
+ $(link) $(ldebug) $(conslflags) -out:mkg3states.exe mkg3states.obj \
+ $(EXTRA_OBJS)
+ mkg3states.exe
+
+clean:
+ del *.obj
+ del g3states.h
+
+clobber:
+ del libtiff.lib
+ del *.obj
+ del g3states.h
+
+
+
+