singe/thirdparty/SDL2_image/external/libtiff/tools/tiffinfo.c
2023-10-23 19:38:18 -05:00

752 lines
23 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_STRINGS_H
#include <strings.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#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);
}
}