892 lines
27 KiB
C
892 lines
27 KiB
C
/*
|
|
* Copyright (c) 1988-1997 Sam Leffler
|
|
* Copyright (c) 1991-1997 Silicon Graphics, Inc.
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and
|
|
* its documentation for any purpose is hereby granted without fee, provided
|
|
* that (i) the above copyright notices and this permission notice appear in
|
|
* all copies of the software and related documentation, and (ii) the names of
|
|
* Sam Leffler and Silicon Graphics may not be used in any advertising or
|
|
* publicity relating to the software without the specific, prior written
|
|
* permission of Sam Leffler and Silicon Graphics.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
|
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
|
|
* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
|
|
* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
|
|
* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
* OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include "libport.h"
|
|
#include "tif_config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "tiffiop.h"
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
#include <sys/types.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_IO_H
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#include "tiffio.h"
|
|
|
|
#ifndef EXIT_SUCCESS
|
|
#define EXIT_SUCCESS 0
|
|
#endif
|
|
#ifndef EXIT_FAILURE
|
|
#define EXIT_FAILURE 1
|
|
#endif
|
|
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0
|
|
#endif
|
|
|
|
static union
|
|
{
|
|
TIFFHeaderClassic classic;
|
|
TIFFHeaderBig big;
|
|
TIFFHeaderCommon common;
|
|
} hdr;
|
|
static char *appname;
|
|
static char *curfile;
|
|
static int swabflag;
|
|
static int bigendian;
|
|
static int bigtiff;
|
|
static uint32_t maxitems = 24; /* maximum indirect data items to print */
|
|
|
|
static const char bytefmt[] = "%s%#02" PRIx8; /* BYTE */
|
|
static const char sbytefmt[] = "%s%" PRId8; /* SBYTE */
|
|
static const char shortfmtd[] = "%s%" PRIu16; /* SHORT */
|
|
static const char shortfmth[] = "%s%#" PRIx16;
|
|
static const char sshortfmtd[] = "%s%" PRId16; /* SSHORT */
|
|
static const char sshortfmth[] = "%s%#" PRIx16;
|
|
static const char longfmtd[] = "%s%" PRIu32; /* LONG */
|
|
static const char longfmth[] = "%s%#" PRIx32;
|
|
static const char slongfmtd[] = "%s%" PRId32; /* SLONG */
|
|
static const char slongfmth[] = "%s%#" PRIx32;
|
|
static const char ifdfmt[] = "%s%#04" PRIx32; /* IFD offset */
|
|
static const char long8fmt[] = "%s%" PRIu64; /* LONG8 */
|
|
static const char slong8fmt[] = "%s%" PRId64; /* SLONG8 */
|
|
static const char ifd8fmt[] = "%s%#08" PRIx64; /* IFD offset8 */
|
|
static const char rationalfmt[] = "%s%g"; /* RATIONAL */
|
|
static const char srationalfmt[] = "%s%g"; /* SRATIONAL */
|
|
static const char floatfmt[] = "%s%g"; /* FLOAT */
|
|
static const char doublefmt[] = "%s%g"; /* DOUBLE */
|
|
|
|
unsigned int hex_mode;
|
|
|
|
static void dump(int, uint64_t);
|
|
|
|
#if !HAVE_DECL_OPTARG
|
|
extern int optind;
|
|
extern char *optarg;
|
|
#endif
|
|
|
|
void usage()
|
|
{
|
|
fprintf(stderr, "\nDisplay directory information from TIFF files\n\n");
|
|
fprintf(stderr, "usage: %s [-h] [-o offset] [-m maxitems] file.tif ...\n",
|
|
appname);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int one = 1, fd;
|
|
int multiplefiles = (argc > 1);
|
|
int c;
|
|
uint64_t diroff = 0;
|
|
hex_mode = 0;
|
|
bigendian = (*(char *)&one == 0);
|
|
|
|
appname = argv[0];
|
|
while ((c = getopt(argc, argv, "m:o:h")) != -1)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'h': /* print values in hex */
|
|
hex_mode = 1;
|
|
break;
|
|
case 'o':
|
|
diroff = (uint64_t)strtoul(optarg, NULL, 0);
|
|
break;
|
|
case 'm':
|
|
maxitems = strtoul(optarg, NULL, 0);
|
|
break;
|
|
default:
|
|
usage();
|
|
}
|
|
}
|
|
if (optind >= argc)
|
|
usage();
|
|
for (; optind < argc; optind++)
|
|
{
|
|
fd = open(argv[optind], O_RDONLY | O_BINARY, 0);
|
|
if (fd < 0)
|
|
{
|
|
perror(argv[0]);
|
|
return (EXIT_FAILURE);
|
|
}
|
|
if (multiplefiles)
|
|
printf("%s:\n", argv[optind]);
|
|
curfile = argv[optind];
|
|
swabflag = 0;
|
|
bigtiff = 0;
|
|
dump(fd, diroff);
|
|
close(fd);
|
|
}
|
|
return (EXIT_SUCCESS);
|
|
}
|
|
|
|
#define ord(e) ((int)e)
|
|
|
|
static uint64_t ReadDirectory(int, unsigned, uint64_t);
|
|
static void ReadError(char *);
|
|
static void Error(const char *, ...);
|
|
static void Fatal(const char *, ...);
|
|
|
|
static void dump(int fd, uint64_t diroff)
|
|
{
|
|
unsigned i, j;
|
|
uint64_t *visited_diroff = NULL;
|
|
unsigned int count_visited_dir = 0;
|
|
|
|
_TIFF_lseek_f(fd, (_TIFF_off_t)0, 0);
|
|
if (read(fd, (char *)&hdr, sizeof(TIFFHeaderCommon)) !=
|
|
sizeof(TIFFHeaderCommon))
|
|
ReadError("TIFF header");
|
|
if (hdr.common.tiff_magic != TIFF_BIGENDIAN &&
|
|
hdr.common.tiff_magic != TIFF_LITTLEENDIAN &&
|
|
#if HOST_BIGENDIAN
|
|
/* MDI is sensitive to the host byte order, unlike TIFF */
|
|
MDI_BIGENDIAN != hdr.common.tiff_magic
|
|
#else
|
|
MDI_LITTLEENDIAN != hdr.common.tiff_magic
|
|
#endif
|
|
)
|
|
{
|
|
Fatal("Not a TIFF or MDI file, bad magic number %u (%#x)",
|
|
hdr.common.tiff_magic, hdr.common.tiff_magic);
|
|
}
|
|
if (hdr.common.tiff_magic == TIFF_BIGENDIAN ||
|
|
hdr.common.tiff_magic == MDI_BIGENDIAN)
|
|
swabflag = !bigendian;
|
|
else
|
|
swabflag = bigendian;
|
|
if (swabflag)
|
|
TIFFSwabShort(&hdr.common.tiff_version);
|
|
if (hdr.common.tiff_version == 42)
|
|
{
|
|
if (read(fd,
|
|
((char *)&hdr.classic) +
|
|
offsetof(TIFFHeaderClassic, tiff_diroff),
|
|
4) != 4)
|
|
ReadError("TIFF header");
|
|
if (swabflag)
|
|
TIFFSwabLong(&hdr.classic.tiff_diroff);
|
|
printf("Magic: %#x <%s-endian> Version: %#x <%s>\n",
|
|
hdr.classic.tiff_magic,
|
|
hdr.classic.tiff_magic == TIFF_BIGENDIAN ? "big" : "little", 42,
|
|
"ClassicTIFF");
|
|
if (diroff == 0)
|
|
diroff = hdr.classic.tiff_diroff;
|
|
}
|
|
else if (hdr.common.tiff_version == 43)
|
|
{
|
|
if (read(fd,
|
|
((char *)&hdr.big) + offsetof(TIFFHeaderBig, tiff_offsetsize),
|
|
12) != 12)
|
|
ReadError("TIFF header");
|
|
if (swabflag)
|
|
{
|
|
TIFFSwabShort(&hdr.big.tiff_offsetsize);
|
|
TIFFSwabShort(&hdr.big.tiff_unused);
|
|
TIFFSwabLong8(&hdr.big.tiff_diroff);
|
|
}
|
|
printf("Magic: %#x <%s-endian> Version: %#x <%s>\n", hdr.big.tiff_magic,
|
|
hdr.big.tiff_magic == TIFF_BIGENDIAN ? "big" : "little", 43,
|
|
"BigTIFF");
|
|
printf("OffsetSize: %#x Unused: %#x\n", hdr.big.tiff_offsetsize,
|
|
hdr.big.tiff_unused);
|
|
if (diroff == 0)
|
|
diroff = hdr.big.tiff_diroff;
|
|
bigtiff = 1;
|
|
}
|
|
else
|
|
Fatal("Not a TIFF file, bad version number %u (%#x)",
|
|
hdr.common.tiff_version, hdr.common.tiff_version);
|
|
for (i = 0; diroff != 0; i++)
|
|
{
|
|
for (j = 0; j < count_visited_dir; j++)
|
|
{
|
|
if (visited_diroff[j] == diroff)
|
|
{
|
|
free(visited_diroff);
|
|
Fatal("Cycle detected in chaining of TIFF directories!");
|
|
}
|
|
}
|
|
{
|
|
size_t alloc_size;
|
|
alloc_size = TIFFSafeMultiply(tmsize_t, (count_visited_dir + 1),
|
|
sizeof(uint64_t));
|
|
if (alloc_size == 0)
|
|
{
|
|
if (visited_diroff)
|
|
free(visited_diroff);
|
|
visited_diroff = 0;
|
|
}
|
|
else
|
|
{
|
|
visited_diroff =
|
|
(uint64_t *)realloc(visited_diroff, alloc_size);
|
|
}
|
|
}
|
|
if (!visited_diroff)
|
|
Fatal("Out of memory");
|
|
visited_diroff[count_visited_dir] = diroff;
|
|
count_visited_dir++;
|
|
|
|
if (i > 0)
|
|
putchar('\n');
|
|
diroff = ReadDirectory(fd, i, diroff);
|
|
}
|
|
if (visited_diroff)
|
|
free(visited_diroff);
|
|
}
|
|
|
|
static const int datawidth[] = {
|
|
0, /* 00 = undefined */
|
|
1, /* 01 = TIFF_BYTE */
|
|
1, /* 02 = TIFF_ASCII */
|
|
2, /* 03 = TIFF_SHORT */
|
|
4, /* 04 = TIFF_LONG */
|
|
8, /* 05 = TIFF_RATIONAL */
|
|
1, /* 06 = TIFF_SBYTE */
|
|
1, /* 07 = TIFF_UNDEFINED */
|
|
2, /* 08 = TIFF_SSHORT */
|
|
4, /* 09 = TIFF_SLONG */
|
|
8, /* 10 = TIFF_SRATIONAL */
|
|
4, /* 11 = TIFF_FLOAT */
|
|
8, /* 12 = TIFF_DOUBLE */
|
|
4, /* 13 = TIFF_IFD */
|
|
0, /* 14 = undefined */
|
|
0, /* 15 = undefined */
|
|
8, /* 16 = TIFF_LONG8 */
|
|
8, /* 17 = TIFF_SLONG8 */
|
|
8, /* 18 = TIFF_IFD8 */
|
|
};
|
|
#define NWIDTHS (sizeof(datawidth) / sizeof(datawidth[0]))
|
|
static void PrintTag(FILE *, uint16_t);
|
|
static void PrintType(FILE *, uint16_t);
|
|
static void PrintData(FILE *, uint16_t, uint32_t, unsigned char *);
|
|
|
|
/*
|
|
* Read the next TIFF directory from a file
|
|
* and convert it to the internal format.
|
|
* We read directories sequentially.
|
|
*/
|
|
static uint64_t ReadDirectory(int fd, unsigned int ix, uint64_t off)
|
|
{
|
|
uint16_t dircount;
|
|
uint32_t direntrysize;
|
|
void *dirmem = NULL;
|
|
uint64_t nextdiroff = 0;
|
|
uint32_t n;
|
|
uint8_t *dp;
|
|
|
|
if (off == 0) /* no more directories */
|
|
goto done;
|
|
if (_TIFF_lseek_f(fd, (_TIFF_off_t)off, SEEK_SET) != (_TIFF_off_t)off)
|
|
{
|
|
Fatal("Seek error accessing TIFF directory");
|
|
goto done;
|
|
}
|
|
if (!bigtiff)
|
|
{
|
|
if (read(fd, (char *)&dircount, sizeof(uint16_t)) != sizeof(uint16_t))
|
|
{
|
|
ReadError("directory count");
|
|
goto done;
|
|
}
|
|
if (swabflag)
|
|
TIFFSwabShort(&dircount);
|
|
direntrysize = 12;
|
|
}
|
|
else
|
|
{
|
|
uint64_t dircount64 = 0;
|
|
if (read(fd, (char *)&dircount64, sizeof(uint64_t)) != sizeof(uint64_t))
|
|
{
|
|
ReadError("directory count");
|
|
goto done;
|
|
}
|
|
if (swabflag)
|
|
TIFFSwabLong8(&dircount64);
|
|
if (dircount64 > 0xFFFF)
|
|
{
|
|
Error("Sanity check on directory count failed");
|
|
goto done;
|
|
}
|
|
dircount = (uint16_t)dircount64;
|
|
direntrysize = 20;
|
|
}
|
|
dirmem = _TIFFmalloc(TIFFSafeMultiply(tmsize_t, dircount, direntrysize));
|
|
if (dirmem == NULL)
|
|
{
|
|
Fatal("No space for TIFF directory");
|
|
goto done;
|
|
}
|
|
n = read(fd, (char *)dirmem, dircount * direntrysize);
|
|
if (n != dircount * direntrysize)
|
|
{
|
|
n /= direntrysize;
|
|
Error("Could only read %" PRIu32 " of %" PRIu16
|
|
" entries in directory at offset %#" PRIu64,
|
|
n, dircount, off);
|
|
dircount = n;
|
|
nextdiroff = 0;
|
|
}
|
|
else
|
|
{
|
|
if (!bigtiff)
|
|
{
|
|
uint32_t nextdiroff32;
|
|
if (read(fd, (char *)&nextdiroff32, sizeof(uint32_t)) !=
|
|
sizeof(uint32_t))
|
|
nextdiroff32 = 0;
|
|
if (swabflag)
|
|
TIFFSwabLong(&nextdiroff32);
|
|
nextdiroff = nextdiroff32;
|
|
}
|
|
else
|
|
{
|
|
if (read(fd, (char *)&nextdiroff, sizeof(uint64_t)) !=
|
|
sizeof(uint64_t))
|
|
nextdiroff = 0;
|
|
if (swabflag)
|
|
TIFFSwabLong8(&nextdiroff);
|
|
}
|
|
}
|
|
printf("Directory %u: offset %" PRIu64 " (%#" PRIx64 ") next %" PRIu64
|
|
" (%#" PRIx64 ")\n",
|
|
ix, off, off, nextdiroff, nextdiroff);
|
|
for (dp = (uint8_t *)dirmem, n = dircount; n > 0; n--)
|
|
{
|
|
uint16_t tag;
|
|
uint16_t type;
|
|
uint16_t typewidth;
|
|
uint64_t count;
|
|
uint64_t datasize;
|
|
int datafits;
|
|
void *datamem;
|
|
uint64_t dataoffset;
|
|
int datatruncated;
|
|
int datasizeoverflow;
|
|
|
|
tag = *(uint16_t *)dp;
|
|
if (swabflag)
|
|
TIFFSwabShort(&tag);
|
|
dp += sizeof(uint16_t);
|
|
type = *(uint16_t *)dp;
|
|
dp += sizeof(uint16_t);
|
|
if (swabflag)
|
|
TIFFSwabShort(&type);
|
|
PrintTag(stdout, tag);
|
|
putchar(' ');
|
|
PrintType(stdout, type);
|
|
putchar(' ');
|
|
if (!bigtiff)
|
|
{
|
|
uint32_t count32;
|
|
count32 = *(uint32_t *)dp;
|
|
if (swabflag)
|
|
TIFFSwabLong(&count32);
|
|
dp += sizeof(uint32_t);
|
|
count = count32;
|
|
}
|
|
else
|
|
{
|
|
memcpy(&count, dp, sizeof(uint64_t));
|
|
if (swabflag)
|
|
TIFFSwabLong8(&count);
|
|
dp += sizeof(uint64_t);
|
|
}
|
|
printf("%" PRIu64 "<", count);
|
|
if (type >= NWIDTHS)
|
|
typewidth = 0;
|
|
else
|
|
typewidth = datawidth[type];
|
|
datasize = TIFFSafeMultiply(tmsize_t, count, typewidth);
|
|
datasizeoverflow = (typewidth > 0 && datasize / typewidth != count);
|
|
datafits = 1;
|
|
datamem = dp;
|
|
dataoffset = 0;
|
|
datatruncated = 0;
|
|
if (!bigtiff)
|
|
{
|
|
if (datasizeoverflow || datasize > 4)
|
|
{
|
|
uint32_t dataoffset32;
|
|
datafits = 0;
|
|
datamem = NULL;
|
|
dataoffset32 = *(uint32_t *)dp;
|
|
if (swabflag)
|
|
TIFFSwabLong(&dataoffset32);
|
|
dataoffset = dataoffset32;
|
|
}
|
|
dp += sizeof(uint32_t);
|
|
}
|
|
else
|
|
{
|
|
if (datasizeoverflow || datasize > 8)
|
|
{
|
|
datafits = 0;
|
|
datamem = NULL;
|
|
memcpy(&dataoffset, dp, sizeof(uint64_t));
|
|
if (swabflag)
|
|
TIFFSwabLong8(&dataoffset);
|
|
}
|
|
dp += sizeof(uint64_t);
|
|
}
|
|
if (datasizeoverflow || datasize > 0x10000)
|
|
{
|
|
datatruncated = 1;
|
|
count = 0x10000 / typewidth;
|
|
datasize = TIFFSafeMultiply(tmsize_t, count, typewidth);
|
|
}
|
|
if (count > maxitems)
|
|
{
|
|
datatruncated = 1;
|
|
count = maxitems;
|
|
datasize = TIFFSafeMultiply(tmsize_t, count, typewidth);
|
|
}
|
|
if (!datafits)
|
|
{
|
|
datamem = _TIFFmalloc(datasize);
|
|
if (datamem)
|
|
{
|
|
if (_TIFF_lseek_f(fd, (_TIFF_off_t)dataoffset, 0) !=
|
|
(_TIFF_off_t)dataoffset)
|
|
{
|
|
Error("Seek error accessing tag %u value", tag);
|
|
_TIFFfree(datamem);
|
|
datamem = NULL;
|
|
}
|
|
else if (read(fd, datamem, (size_t)datasize) !=
|
|
(tmsize_t)datasize)
|
|
{
|
|
Error("Read error accessing tag %u value", tag);
|
|
_TIFFfree(datamem);
|
|
datamem = NULL;
|
|
}
|
|
}
|
|
else
|
|
Error("No space for data for tag %u", tag);
|
|
}
|
|
if (datamem)
|
|
{
|
|
if (swabflag)
|
|
{
|
|
switch (type)
|
|
{
|
|
case TIFF_BYTE:
|
|
case TIFF_ASCII:
|
|
case TIFF_SBYTE:
|
|
case TIFF_UNDEFINED:
|
|
break;
|
|
case TIFF_SHORT:
|
|
case TIFF_SSHORT:
|
|
TIFFSwabArrayOfShort((uint16_t *)datamem,
|
|
(tmsize_t)count);
|
|
break;
|
|
case TIFF_LONG:
|
|
case TIFF_SLONG:
|
|
case TIFF_FLOAT:
|
|
case TIFF_IFD:
|
|
TIFFSwabArrayOfLong((uint32_t *)datamem,
|
|
(tmsize_t)count);
|
|
break;
|
|
case TIFF_RATIONAL:
|
|
case TIFF_SRATIONAL:
|
|
TIFFSwabArrayOfLong((uint32_t *)datamem,
|
|
(tmsize_t)count * 2);
|
|
break;
|
|
case TIFF_DOUBLE:
|
|
case TIFF_LONG8:
|
|
case TIFF_SLONG8:
|
|
case TIFF_IFD8:
|
|
TIFFSwabArrayOfLong8((uint64_t *)datamem,
|
|
(tmsize_t)count);
|
|
break;
|
|
}
|
|
}
|
|
PrintData(stdout, type, (uint32_t)count, datamem);
|
|
if (datatruncated)
|
|
printf(" ...");
|
|
if (!datafits)
|
|
{
|
|
_TIFFfree(datamem);
|
|
datamem = NULL;
|
|
}
|
|
}
|
|
printf(">\n");
|
|
}
|
|
done:
|
|
if (dirmem)
|
|
_TIFFfree((char *)dirmem);
|
|
return (nextdiroff);
|
|
}
|
|
|
|
static const struct tagname
|
|
{
|
|
uint16_t tag;
|
|
const char *name;
|
|
} tagnames[] = {
|
|
{TIFFTAG_SUBFILETYPE, "SubFileType"},
|
|
{TIFFTAG_OSUBFILETYPE, "OldSubFileType"},
|
|
{TIFFTAG_IMAGEWIDTH, "ImageWidth"},
|
|
{TIFFTAG_IMAGELENGTH, "ImageLength"},
|
|
{TIFFTAG_BITSPERSAMPLE, "BitsPerSample"},
|
|
{TIFFTAG_COMPRESSION, "Compression"},
|
|
{TIFFTAG_PHOTOMETRIC, "Photometric"},
|
|
{TIFFTAG_THRESHHOLDING, "Threshholding"},
|
|
{TIFFTAG_CELLWIDTH, "CellWidth"},
|
|
{TIFFTAG_CELLLENGTH, "CellLength"},
|
|
{TIFFTAG_FILLORDER, "FillOrder"},
|
|
{TIFFTAG_DOCUMENTNAME, "DocumentName"},
|
|
{TIFFTAG_IMAGEDESCRIPTION, "ImageDescription"},
|
|
{TIFFTAG_MAKE, "Make"},
|
|
{TIFFTAG_MODEL, "Model"},
|
|
{TIFFTAG_STRIPOFFSETS, "StripOffsets"},
|
|
{TIFFTAG_ORIENTATION, "Orientation"},
|
|
{TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel"},
|
|
{TIFFTAG_ROWSPERSTRIP, "RowsPerStrip"},
|
|
{TIFFTAG_STRIPBYTECOUNTS, "StripByteCounts"},
|
|
{TIFFTAG_MINSAMPLEVALUE, "MinSampleValue"},
|
|
{TIFFTAG_MAXSAMPLEVALUE, "MaxSampleValue"},
|
|
{TIFFTAG_XRESOLUTION, "XResolution"},
|
|
{TIFFTAG_YRESOLUTION, "YResolution"},
|
|
{TIFFTAG_PLANARCONFIG, "PlanarConfig"},
|
|
{TIFFTAG_PAGENAME, "PageName"},
|
|
{TIFFTAG_XPOSITION, "XPosition"},
|
|
{TIFFTAG_YPOSITION, "YPosition"},
|
|
{TIFFTAG_FREEOFFSETS, "FreeOffsets"},
|
|
{TIFFTAG_FREEBYTECOUNTS, "FreeByteCounts"},
|
|
{TIFFTAG_GRAYRESPONSEUNIT, "GrayResponseUnit"},
|
|
{TIFFTAG_GRAYRESPONSECURVE, "GrayResponseCurve"},
|
|
{TIFFTAG_GROUP3OPTIONS, "Group3Options"},
|
|
{TIFFTAG_GROUP4OPTIONS, "Group4Options"},
|
|
{TIFFTAG_RESOLUTIONUNIT, "ResolutionUnit"},
|
|
{TIFFTAG_PAGENUMBER, "PageNumber"},
|
|
{TIFFTAG_COLORRESPONSEUNIT, "ColorResponseUnit"},
|
|
{TIFFTAG_TRANSFERFUNCTION, "TransferFunction"},
|
|
{TIFFTAG_SOFTWARE, "Software"},
|
|
{TIFFTAG_DATETIME, "DateTime"},
|
|
{TIFFTAG_ARTIST, "Artist"},
|
|
{TIFFTAG_HOSTCOMPUTER, "HostComputer"},
|
|
{TIFFTAG_PREDICTOR, "Predictor"},
|
|
{TIFFTAG_WHITEPOINT, "Whitepoint"},
|
|
{TIFFTAG_PRIMARYCHROMATICITIES, "PrimaryChromaticities"},
|
|
{TIFFTAG_COLORMAP, "Colormap"},
|
|
{TIFFTAG_HALFTONEHINTS, "HalftoneHints"},
|
|
{TIFFTAG_TILEWIDTH, "TileWidth"},
|
|
{TIFFTAG_TILELENGTH, "TileLength"},
|
|
{TIFFTAG_TILEOFFSETS, "TileOffsets"},
|
|
{TIFFTAG_TILEBYTECOUNTS, "TileByteCounts"},
|
|
{TIFFTAG_BADFAXLINES, "BadFaxLines"},
|
|
{TIFFTAG_CLEANFAXDATA, "CleanFaxData"},
|
|
{TIFFTAG_CONSECUTIVEBADFAXLINES, "ConsecutiveBadFaxLines"},
|
|
{TIFFTAG_SUBIFD, "SubIFD"},
|
|
{TIFFTAG_INKSET, "InkSet"},
|
|
{TIFFTAG_INKNAMES, "InkNames"},
|
|
{TIFFTAG_NUMBEROFINKS, "NumberOfInks"},
|
|
{TIFFTAG_DOTRANGE, "DotRange"},
|
|
{TIFFTAG_TARGETPRINTER, "TargetPrinter"},
|
|
{TIFFTAG_EXTRASAMPLES, "ExtraSamples"},
|
|
{TIFFTAG_SAMPLEFORMAT, "SampleFormat"},
|
|
{TIFFTAG_SMINSAMPLEVALUE, "SMinSampleValue"},
|
|
{TIFFTAG_SMAXSAMPLEVALUE, "SMaxSampleValue"},
|
|
{TIFFTAG_JPEGPROC, "JPEGProcessingMode"},
|
|
{TIFFTAG_JPEGIFOFFSET, "JPEGInterchangeFormat"},
|
|
{TIFFTAG_JPEGIFBYTECOUNT, "JPEGInterchangeFormatLength"},
|
|
{TIFFTAG_JPEGRESTARTINTERVAL, "JPEGRestartInterval"},
|
|
{TIFFTAG_JPEGLOSSLESSPREDICTORS, "JPEGLosslessPredictors"},
|
|
{TIFFTAG_JPEGPOINTTRANSFORM, "JPEGPointTransform"},
|
|
{TIFFTAG_JPEGTABLES, "JPEGTables"},
|
|
{TIFFTAG_JPEGQTABLES, "JPEGQTables"},
|
|
{TIFFTAG_JPEGDCTABLES, "JPEGDCTables"},
|
|
{TIFFTAG_JPEGACTABLES, "JPEGACTables"},
|
|
{TIFFTAG_YCBCRCOEFFICIENTS, "YCbCrCoefficients"},
|
|
{TIFFTAG_YCBCRSUBSAMPLING, "YCbCrSubsampling"},
|
|
{TIFFTAG_YCBCRPOSITIONING, "YCbCrPositioning"},
|
|
{TIFFTAG_REFERENCEBLACKWHITE, "ReferenceBlackWhite"},
|
|
{TIFFTAG_REFPTS, "IgReferencePoints (Island Graphics)"},
|
|
{TIFFTAG_REGIONTACKPOINT, "IgRegionTackPoint (Island Graphics)"},
|
|
{TIFFTAG_REGIONWARPCORNERS, "IgRegionWarpCorners (Island Graphics)"},
|
|
{TIFFTAG_REGIONAFFINE, "IgRegionAffine (Island Graphics)"},
|
|
{TIFFTAG_MATTEING, "OBSOLETE Matteing (Silicon Graphics)"},
|
|
{TIFFTAG_DATATYPE, "OBSOLETE DataType (Silicon Graphics)"},
|
|
{TIFFTAG_IMAGEDEPTH, "ImageDepth (Silicon Graphics)"},
|
|
{TIFFTAG_TILEDEPTH, "TileDepth (Silicon Graphics)"},
|
|
{32768, "OLD BOGUS Matteing tag"},
|
|
{TIFFTAG_COPYRIGHT, "Copyright"},
|
|
{TIFFTAG_ICCPROFILE, "ICC Profile"},
|
|
{TIFFTAG_JBIGOPTIONS, "JBIG Options"},
|
|
{TIFFTAG_STONITS, "StoNits"},
|
|
{TIFFTAG_GDAL_METADATA, "GDALMetadata"},
|
|
{TIFFTAG_GDAL_NODATA, "GDALNoDataValue"},
|
|
};
|
|
#define NTAGS (sizeof(tagnames) / sizeof(tagnames[0]))
|
|
|
|
static void PrintTag(FILE *fd, uint16_t tag)
|
|
{
|
|
const struct tagname *tp;
|
|
|
|
for (tp = tagnames; tp < &tagnames[NTAGS]; tp++)
|
|
if (tp->tag == tag)
|
|
{
|
|
fprintf(fd, "%s (%u)", tp->name, tag);
|
|
return;
|
|
}
|
|
fprintf(fd, "%u (%#x)", tag, tag);
|
|
}
|
|
|
|
static void PrintType(FILE *fd, uint16_t type)
|
|
{
|
|
static const char *typenames[] = {
|
|
"0", "BYTE", "ASCII", "SHORT", "LONG",
|
|
"RATIONAL", "SBYTE", "UNDEFINED", "SSHORT", "SLONG",
|
|
"SRATIONAL", "FLOAT", "DOUBLE", "IFD", "14",
|
|
"15", "LONG8", "SLONG8", "IFD8"};
|
|
#define NTYPES (sizeof(typenames) / sizeof(typenames[0]))
|
|
|
|
if (type < NTYPES)
|
|
fprintf(fd, "%s (%u)", typenames[type], type);
|
|
else
|
|
fprintf(fd, "%u (%#x)", type, type);
|
|
}
|
|
#undef NTYPES
|
|
|
|
#include <ctype.h>
|
|
|
|
static void PrintASCII(FILE *fd, uint32_t cc, const unsigned char *cp)
|
|
{
|
|
for (; cc > 0; cc--, cp++)
|
|
{
|
|
const char *tp;
|
|
|
|
if (isprint(*cp))
|
|
{
|
|
fputc(*cp, fd);
|
|
continue;
|
|
}
|
|
for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++)
|
|
if (*tp++ == *cp)
|
|
break;
|
|
if (*tp)
|
|
fprintf(fd, "\\%c", *tp);
|
|
else if (*cp)
|
|
fprintf(fd, "\\%03o", *cp);
|
|
else
|
|
fprintf(fd, "\\0");
|
|
}
|
|
}
|
|
|
|
static void PrintData(FILE *fd, uint16_t type, uint32_t count,
|
|
unsigned char *data)
|
|
{
|
|
char *sep = "";
|
|
|
|
switch (type)
|
|
{
|
|
case TIFF_BYTE:
|
|
while (count-- > 0)
|
|
fprintf(fd, bytefmt, sep, *data++), sep = " ";
|
|
break;
|
|
case TIFF_SBYTE:
|
|
while (count-- > 0)
|
|
fprintf(fd, sbytefmt, sep, *(char *)data++), sep = " ";
|
|
break;
|
|
case TIFF_UNDEFINED:
|
|
while (count-- > 0)
|
|
fprintf(fd, bytefmt, sep, *data++), sep = " ";
|
|
break;
|
|
case TIFF_ASCII:
|
|
PrintASCII(fd, count, data);
|
|
break;
|
|
case TIFF_SHORT:
|
|
{
|
|
uint16_t *wp = (uint16_t *)data;
|
|
while (count-- > 0)
|
|
fprintf(fd, hex_mode ? shortfmth : shortfmtd, sep, *wp++),
|
|
sep = " ";
|
|
break;
|
|
}
|
|
case TIFF_SSHORT:
|
|
{
|
|
int16_t *wp = (int16_t *)data;
|
|
while (count-- > 0)
|
|
fprintf(fd, hex_mode ? sshortfmth : sshortfmtd, sep, *wp++),
|
|
sep = " ";
|
|
break;
|
|
}
|
|
case TIFF_LONG:
|
|
{
|
|
uint32_t *lp = (uint32_t *)data;
|
|
while (count-- > 0)
|
|
{
|
|
fprintf(fd, hex_mode ? longfmth : longfmtd, sep, *lp++);
|
|
sep = " ";
|
|
}
|
|
break;
|
|
}
|
|
case TIFF_SLONG:
|
|
{
|
|
int32_t *lp = (int32_t *)data;
|
|
while (count-- > 0)
|
|
fprintf(fd, hex_mode ? slongfmth : slongfmtd, sep, *lp++),
|
|
sep = " ";
|
|
break;
|
|
}
|
|
case TIFF_LONG8:
|
|
{
|
|
uint64_t *llp = (uint64_t *)data;
|
|
while (count-- > 0)
|
|
{
|
|
uint64_t val;
|
|
memcpy(&val, llp, sizeof(uint64_t));
|
|
llp++;
|
|
fprintf(fd, long8fmt, sep, val);
|
|
sep = " ";
|
|
}
|
|
break;
|
|
}
|
|
case TIFF_SLONG8:
|
|
{
|
|
int64_t *llp = (int64_t *)data;
|
|
while (count-- > 0)
|
|
{
|
|
int64_t val;
|
|
memcpy(&val, llp, sizeof(int64_t));
|
|
llp++;
|
|
fprintf(fd, slong8fmt, sep, val);
|
|
sep = " ";
|
|
}
|
|
break;
|
|
}
|
|
case TIFF_RATIONAL:
|
|
{
|
|
uint32_t *lp = (uint32_t *)data;
|
|
while (count-- > 0)
|
|
{
|
|
if (lp[1] == 0)
|
|
fprintf(fd, "%sNan (%" PRIu32 "/%" PRIu32 ")", sep, lp[0],
|
|
lp[1]);
|
|
else
|
|
fprintf(fd, rationalfmt, sep,
|
|
(double)lp[0] / (double)lp[1]);
|
|
sep = " ";
|
|
lp += 2;
|
|
}
|
|
break;
|
|
}
|
|
case TIFF_SRATIONAL:
|
|
{
|
|
int32_t *lp = (int32_t *)data;
|
|
while (count-- > 0)
|
|
{
|
|
if (lp[1] == 0)
|
|
fprintf(fd, "%sNan (%" PRId32 "/%" PRId32 ")", sep, lp[0],
|
|
lp[1]);
|
|
else
|
|
fprintf(fd, srationalfmt, sep,
|
|
(double)lp[0] / (double)lp[1]);
|
|
sep = " ";
|
|
lp += 2;
|
|
}
|
|
break;
|
|
}
|
|
case TIFF_FLOAT:
|
|
{
|
|
float *fp = (float *)data;
|
|
while (count-- > 0)
|
|
fprintf(fd, floatfmt, sep, *fp++), sep = " ";
|
|
break;
|
|
}
|
|
case TIFF_DOUBLE:
|
|
{
|
|
double *dp = (double *)data;
|
|
while (count-- > 0)
|
|
fprintf(fd, doublefmt, sep, *dp++), sep = " ";
|
|
break;
|
|
}
|
|
case TIFF_IFD:
|
|
{
|
|
uint32_t *lp = (uint32_t *)data;
|
|
while (count-- > 0)
|
|
{
|
|
fprintf(fd, ifdfmt, sep, *lp++);
|
|
sep = " ";
|
|
}
|
|
break;
|
|
}
|
|
case TIFF_IFD8:
|
|
{
|
|
uint64_t *llp = (uint64_t *)data;
|
|
while (count-- > 0)
|
|
{
|
|
fprintf(fd, ifd8fmt, sep, *llp++);
|
|
sep = " ";
|
|
sep = " ";
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ReadError(char *what) { Fatal("Error while reading %s", what); }
|
|
|
|
#include <stdarg.h>
|
|
|
|
static void vError(FILE *fd, const char *fmt, va_list ap)
|
|
{
|
|
fprintf(fd, "%s: ", curfile);
|
|
vfprintf(fd, fmt, ap);
|
|
fprintf(fd, ".\n");
|
|
}
|
|
|
|
static void Error(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vError(stderr, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
static void Fatal(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vError(stderr, fmt, ap);
|
|
va_end(ap);
|
|
exit(EXIT_FAILURE);
|
|
}
|