/* * 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 #include #include #ifdef HAVE_STRINGS_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include "tiffiop.h" #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif static TIFFErrorHandler old_error_handler = 0; static int status = EXIT_SUCCESS; /* exit status */ static int showdata = 0; /* show data */ static int rawdata = 0; /* show raw/decoded data */ static int showwords = 0; /* show data as bytes/words */ static int readdata = 0; /* read data in file */ static int stoponerr = 1; /* stop on first read error */ static void usage(int); static void tiffinfo(TIFF *, uint16_t, long, int); #define DEFAULT_MAX_MALLOC (256 * 1024 * 1024) /* malloc size limit (in bytes) * disabled when set to 0 */ static tmsize_t maxMalloc = DEFAULT_MAX_MALLOC; static void PrivateErrorHandler(const char *module, const char *fmt, va_list ap) { if (old_error_handler) (*old_error_handler)(module, fmt, ap); status = EXIT_FAILURE; } int main(int argc, char *argv[]) { int dirnum = -1, multiplefiles, c; uint16_t order = 0; TIFF *tif; #if !HAVE_DECL_OPTARG extern int optind; extern char *optarg; #endif long flags = 0; uint64_t diroff = 0; int chopstrips = 0; /* disable strip chopping */ while ((c = getopt(argc, argv, "f:o:M:cdDSjilmrsvwz0123456789h")) != -1) switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': dirnum = atoi(&argv[optind - 1][1]); break; case 'd': showdata++; /* fall through... */ case 'D': readdata++; break; case 'c': flags |= TIFFPRINT_COLORMAP | TIFFPRINT_CURVES; break; case 'f': /* fill order */ if (streq(optarg, "lsb2msb")) order = FILLORDER_LSB2MSB; else if (streq(optarg, "msb2lsb")) order = FILLORDER_MSB2LSB; else usage(EXIT_FAILURE); break; case 'i': stoponerr = 0; break; case 'M': maxMalloc = (tmsize_t)strtoul(optarg, NULL, 0) << 20; break; case 'o': diroff = strtoul(optarg, NULL, 0); break; case 'j': flags |= TIFFPRINT_JPEGQTABLES | TIFFPRINT_JPEGACTABLES | TIFFPRINT_JPEGDCTABLES; break; case 'r': rawdata = 1; break; case 's': flags |= TIFFPRINT_STRIPS; break; case 'w': showwords = 1; break; case 'z': chopstrips = 1; break; case 'h': usage(EXIT_SUCCESS); /*NOTREACHED*/ break; case '?': usage(EXIT_FAILURE); /*NOTREACHED*/ break; } if (optind >= argc) usage(EXIT_FAILURE); old_error_handler = TIFFSetErrorHandler(PrivateErrorHandler); multiplefiles = (argc - optind > 1); for (; optind < argc; optind++) { if (multiplefiles) printf("File %s:\n", argv[optind]); TIFFOpenOptions *opts = TIFFOpenOptionsAlloc(); if (opts == NULL) { status = EXIT_FAILURE; break; } TIFFOpenOptionsSetMaxSingleMemAlloc(opts, maxMalloc); tif = TIFFOpenExt(argv[optind], chopstrips ? "rC" : "rc", opts); TIFFOpenOptionsFree(opts); if (tif != NULL) { if (dirnum != -1) { if (TIFFSetDirectory(tif, (tdir_t)dirnum)) tiffinfo(tif, order, flags, 1); } else if (diroff != 0) { if (TIFFSetSubDirectory(tif, diroff)) tiffinfo(tif, order, flags, 1); } else { do { toff_t offset = 0; tdir_t curdir = TIFFCurrentDirectory(tif); printf("=== TIFF directory %u ===\n", curdir); tiffinfo(tif, order, flags, 1); if (TIFFGetField(tif, TIFFTAG_EXIFIFD, &offset)) { printf("--- EXIF directory within directory %u \n", curdir); if (TIFFReadEXIFDirectory(tif, offset)) { tiffinfo(tif, order, flags, 0); /*-- Go back to previous directory, (directory is * reloaded from file!) */ TIFFSetDirectory(tif, curdir); } } if (TIFFGetField(tif, TIFFTAG_GPSIFD, &offset)) { printf("--- GPS directory within directory %u \n", curdir); if (TIFFReadGPSDirectory(tif, offset)) { tiffinfo(tif, order, flags, 0); TIFFSetDirectory(tif, curdir); } } /*-- Check for SubIFDs --*/ uint16_t nCount; void *vPtr; uint64_t *subIFDoffsets = NULL; if (TIFFGetField(tif, TIFFTAG_SUBIFD, &nCount, &vPtr)) { if (nCount > 0) { subIFDoffsets = malloc(nCount * sizeof(uint64_t)); if (subIFDoffsets != NULL) { memcpy(subIFDoffsets, vPtr, nCount * sizeof(subIFDoffsets[0])); printf("--- SubIFD image descriptor tag within " "TIFF directory %u with array of %d " "SubIFD chains ---\n", curdir, nCount); for (int i = 0; i < nCount; i++) { offset = subIFDoffsets[i]; int s = 0; if (TIFFSetSubDirectory(tif, offset)) { /* print info and check for SubIFD chain */ do { printf("--- SubIFD %d of chain %d " "at offset 0x%" PRIx64 " (%" PRIu64 "):\n", s, i, offset, offset); tiffinfo(tif, order, flags, 0); s++; } while (TIFFReadDirectory(tif)); } } TIFFSetDirectory(tif, curdir); free(subIFDoffsets); subIFDoffsets = NULL; } else { fprintf(stderr, "Error: Could not allocate memory for " "SubIFDs list. SubIFDs not parsed.\n"); } } } printf("\n"); } while (TIFFReadDirectory(tif)); } TIFFClose(tif); } } return (status); } static const char usage_info[] = "Display information about TIFF files\n\n" "usage: tiffinfo [options] input...\n" "where options are:\n" " -D read data\n" " -i ignore read errors\n" " -c display data for grey/color response curve or " "colormap\n" " -d display raw/decoded image data\n" " -f lsb2msb force lsb-to-msb FillOrder for input\n" " -f msb2lsb force msb-to-lsb FillOrder for input\n" " -j show JPEG tables\n" " -o offset set initial directory offset\n" " -r read/display raw image data instead of decoded data\n" " -s display strip offsets and byte counts\n" " -w display raw data in words rather than bytes\n" " -z enable strip chopping\n" " -M size set the memory allocation limit in MiB. 0 to disable limit\n" " -# set initial directory (first directory is # 0)\n"; static void usage(int code) { FILE *out = (code == EXIT_SUCCESS) ? stdout : stderr; fprintf(out, "%s\n\n", TIFFGetVersion()); fprintf(out, "%s", usage_info); exit(code); } static void ShowStrip(tstrip_t strip, unsigned char *pp, uint32_t nrow, tsize_t scanline) { register tsize_t cc; printf("Strip %" PRIu32 ":\n", strip); while (nrow-- > 0) { for (cc = 0; cc < scanline; cc++) { printf(" %02x", *pp++); if (((cc + 1) % 24) == 0) putchar('\n'); } putchar('\n'); } } void TIFFReadContigStripData(TIFF *tif) { unsigned char *buf; tsize_t scanline = TIFFScanlineSize(tif); tmsize_t stripsize = TIFFStripSize(tif); if (maxMalloc != 0 && stripsize > maxMalloc) { fprintf(stderr, "Memory allocation attempt %" TIFF_SSIZE_FORMAT " over memory limit (%" TIFF_SSIZE_FORMAT ")\n", stripsize, maxMalloc); return; } buf = (unsigned char *)_TIFFmalloc(stripsize); if (buf) { uint32_t row, h = 0; uint32_t rowsperstrip = (uint32_t)-1; TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); for (row = 0; row < h; row += rowsperstrip) { uint32_t nrow = (row + rowsperstrip > h ? h - row : rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, 0); if (TIFFReadEncodedStrip(tif, strip, buf, nrow * scanline) < 0) { if (stoponerr) break; } else if (showdata) ShowStrip(strip, buf, nrow, scanline); } _TIFFfree(buf); } else { fprintf(stderr, "Cannot allocate %" TIFF_SSIZE_FORMAT " bytes.\n", stripsize); } } void TIFFReadSeparateStripData(TIFF *tif) { unsigned char *buf; tsize_t scanline = TIFFScanlineSize(tif); tmsize_t stripsize = TIFFStripSize(tif); if (maxMalloc != 0 && stripsize > maxMalloc) { fprintf(stderr, "Memory allocation attempt %" TIFF_SSIZE_FORMAT " over memory limit (%" TIFF_SSIZE_FORMAT ")\n", stripsize, maxMalloc); return; } buf = (unsigned char *)_TIFFmalloc(stripsize); if (buf) { uint32_t row, h = 0; uint32_t rowsperstrip = (uint32_t)-1; tsample_t s, samplesperpixel = 0; TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); for (row = 0; row < h; row += rowsperstrip) { for (s = 0; s < samplesperpixel; s++) { uint32_t nrow = (row + rowsperstrip > h ? h - row : rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, s); if (TIFFReadEncodedStrip(tif, strip, buf, nrow * scanline) < 0) { if (stoponerr) break; } else if (showdata) ShowStrip(strip, buf, nrow, scanline); } } _TIFFfree(buf); } else { fprintf(stderr, "Cannot allocate %" TIFF_SSIZE_FORMAT " bytes.\n", stripsize); } } static void ShowTile(uint32_t row, uint32_t col, tsample_t sample, unsigned char *pp, uint32_t nrow, tsize_t rowsize) { uint32_t cc; printf("Tile (%" PRIu32 ",%" PRIu32 "", row, col); if (sample != (tsample_t)-1) printf(",%" PRIu16, sample); printf("):\n"); while (nrow-- > 0) { for (cc = 0; cc < (uint32_t)rowsize; cc++) { printf(" %02x", *pp++); if (((cc + 1) % 24) == 0) putchar('\n'); } putchar('\n'); } } void TIFFReadContigTileData(TIFF *tif) { unsigned char *buf; tmsize_t rowsize = TIFFTileRowSize(tif); tmsize_t tilesize = TIFFTileSize(tif); if (maxMalloc != 0 && tilesize > maxMalloc) { fprintf(stderr, "Memory allocation attempt %" TIFF_SSIZE_FORMAT " over memory limit (%" TIFF_SSIZE_FORMAT ")\n", tilesize, maxMalloc); return; } buf = (unsigned char *)_TIFFmalloc(tilesize); if (buf) { uint32_t tw = 0, th = 0, w = 0, h = 0; uint32_t row, col; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); if (rowsize == 0 || th > (size_t)(tilesize / rowsize)) { fprintf(stderr, "Cannot display data: th * rowsize > tilesize\n"); _TIFFfree(buf); return; } for (row = 0; row < h; row += th) { for (col = 0; col < w; col += tw) { if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0) { if (stoponerr) break; } else if (showdata) ShowTile(row, col, (tsample_t)-1, buf, th, rowsize); } } _TIFFfree(buf); } else { fprintf(stderr, "Cannot allocate %" TIFF_SSIZE_FORMAT " bytes.\n", tilesize); } } void TIFFReadSeparateTileData(TIFF *tif) { unsigned char *buf; tmsize_t rowsize = TIFFTileRowSize(tif); tmsize_t tilesize = TIFFTileSize(tif); if (maxMalloc != 0 && tilesize > maxMalloc) { fprintf(stderr, "Memory allocation attempt %" TIFF_SSIZE_FORMAT " over memory limit (%" TIFF_SSIZE_FORMAT ")\n", tilesize, maxMalloc); return; } buf = (unsigned char *)_TIFFmalloc(tilesize); if (buf) { uint32_t tw = 0, th = 0, w = 0, h = 0; uint32_t row, col; tsample_t s, samplesperpixel = 0; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); if (rowsize == 0 || th > (size_t)(tilesize / rowsize)) { fprintf(stderr, "Cannot display data: th * rowsize > tilesize\n"); _TIFFfree(buf); return; } for (row = 0; row < h; row += th) { for (col = 0; col < w; col += tw) { for (s = 0; s < samplesperpixel; s++) { if (TIFFReadTile(tif, buf, col, row, 0, s) < 0) { if (stoponerr) break; } else if (showdata) ShowTile(row, col, s, buf, th, rowsize); } } } _TIFFfree(buf); } else { fprintf(stderr, "Cannot allocate %" TIFF_SSIZE_FORMAT " bytes.\n", tilesize); } } void TIFFReadData(TIFF *tif) { uint16_t config = PLANARCONFIG_CONTIG; TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config); if (TIFFIsTiled(tif)) { if (config == PLANARCONFIG_CONTIG) TIFFReadContigTileData(tif); else TIFFReadSeparateTileData(tif); } else { if (config == PLANARCONFIG_CONTIG) TIFFReadContigStripData(tif); else TIFFReadSeparateStripData(tif); } } static void ShowRawBytes(unsigned char *pp, uint32_t n) { uint32_t i; for (i = 0; i < n; i++) { printf(" %02x", *pp++); if (((i + 1) % 24) == 0) printf("\n "); } putchar('\n'); } static void ShowRawWords(uint16_t *pp, uint32_t n) { uint32_t i; for (i = 0; i < n; i++) { printf(" %04" PRIx16, *pp++); if (((i + 1) % 15) == 0) printf("\n "); } putchar('\n'); } static void TIFFReadRawDataStriped(TIFF *tif, int bitrev) { tstrip_t nstrips = TIFFNumberOfStrips(tif); const char *what = "Strip"; uint64_t *stripbc = NULL; TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbc); if (stripbc != NULL && nstrips > 0) { uint32_t bufsize = 0; tdata_t buf = NULL; tstrip_t s; for (s = 0; s < nstrips; s++) { if (stripbc[s] > bufsize || buf == NULL) { tdata_t newbuf; if (maxMalloc != 0 && stripbc[s] > (uint64_t)maxMalloc) { fprintf(stderr, "Memory allocation attempt %" TIFF_SSIZE_FORMAT " over memory limit (%" TIFF_SSIZE_FORMAT ")\n", (tmsize_t)stripbc[s], maxMalloc); break; } newbuf = _TIFFrealloc(buf, (tmsize_t)stripbc[s]); if (newbuf == NULL) { fprintf(stderr, "Cannot allocate buffer to read strip %" PRIu32 "\n", s); break; } bufsize = (uint32_t)stripbc[s]; buf = newbuf; } if (TIFFReadRawStrip(tif, s, buf, (tmsize_t)stripbc[s]) < 0) { fprintf(stderr, "Error reading strip %" PRIu32 "\n", s); if (stoponerr) break; } else if (showdata) { if (bitrev) { TIFFReverseBits(buf, (tmsize_t)stripbc[s]); printf("%s %" PRIu32 ": (bit reversed)\n ", what, s); } else printf("%s %" PRIu32 ":\n ", what, s); if (showwords) ShowRawWords((uint16_t *)buf, (uint32_t)stripbc[s] >> 1); else ShowRawBytes((unsigned char *)buf, (uint32_t)stripbc[s]); } } if (buf != NULL) _TIFFfree(buf); } } static void TIFFReadRawDataTiled(TIFF *tif, int bitrev) { const char *what = "Tile"; uint32_t ntiles = TIFFNumberOfTiles(tif); uint64_t *tilebc = NULL; TIFFGetField(tif, TIFFTAG_TILEBYTECOUNTS, &tilebc); if (tilebc != NULL && ntiles > 0) { uint64_t bufsize = 0; tdata_t buf = NULL; uint32_t t; for (t = 0; t < ntiles; t++) { if (tilebc[t] > bufsize || buf == NULL) { tdata_t newbuf; if (maxMalloc != 0 && tilebc[t] > (uint64_t)maxMalloc) { fprintf(stderr, "Memory allocation attempt %" TIFF_SSIZE_FORMAT " over memory limit (%" TIFF_SSIZE_FORMAT ")\n", (tmsize_t)tilebc[t], maxMalloc); break; } newbuf = _TIFFrealloc(buf, (tmsize_t)tilebc[t]); if (newbuf == NULL) { fprintf(stderr, "Cannot allocate buffer to read tile %" PRIu32 "\n", t); break; } bufsize = (uint32_t)tilebc[t]; buf = newbuf; } if (TIFFReadRawTile(tif, t, buf, (tmsize_t)tilebc[t]) < 0) { fprintf(stderr, "Error reading tile %" PRIu32 "\n", t); if (stoponerr) break; } else if (showdata) { if (bitrev) { TIFFReverseBits(buf, (tmsize_t)tilebc[t]); printf("%s %" PRIu32 ": (bit reversed)\n ", what, t); } else { printf("%s %" PRIu32 ":\n ", what, t); } if (showwords) { ShowRawWords((uint16_t *)buf, (uint32_t)(tilebc[t] >> 1)); } else { ShowRawBytes((unsigned char *)buf, (uint32_t)tilebc[t]); } } } if (buf != NULL) _TIFFfree(buf); } } void TIFFReadRawData(TIFF *tif, int bitrev) { if (TIFFIsTiled(tif)) { TIFFReadRawDataTiled(tif, bitrev); } else { TIFFReadRawDataStriped(tif, bitrev); } } static void tiffinfo(TIFF *tif, uint16_t order, long flags, int is_image) { TIFFPrintDirectory(tif, stdout, flags); if (!readdata || !is_image) return; if (rawdata) { if (order) { uint16_t o; TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &o); TIFFReadRawData(tif, o != order); } else TIFFReadRawData(tif, 0); } else { if (order) TIFFSetField(tif, TIFFTAG_FILLORDER, order); TIFFReadData(tif); } }