home *** CD-ROM | disk | FTP | other *** search
- /* tiffdump - dump a tiff file, to avoid painful hex dumps
- */
- #define WINDOWS 1 /* define MACINTOSH instead, if on MAC */
- #include "stdio.h"
-
- /* basic data types -- may be different per machine/compiler
- */
- typedef unsigned short WORD; /* 16-bit */
- typedef unsigned long DWORD; /* 32-bit */
- typedef int RC; /* return code */
- typedef char *LPSTR;
-
-
- #ifndef NULL
- #define NULL 0L
- #endif
- #define FAR
- #define SUCCESS 0
- #define LOCAL static
- #define INTELTIFF (0x4949)
- #define MOTOROLATIFF (0x4d4d)
-
- /* TIFF data types
- */
- #define TIFFBYTE 1
- #define TIFFASCII 2
- #define TIFFSHORT 3
- #define TIFFLONG 4
- #define TIFFRATIONAL 5
-
- /* TIFF tag constants
- */
- #define TGSUBFILETYPE 255
- #define TGIMAGEWIDTH 256
- #define TGIMAGELENGTH 257
- #define TGBITSPERSAMPLE 258
- #define TGCOMPRESSION 259
-
- #define TGPHOTOMETRICINTERPRETATION 262
- #define TGTHRESHHOLDING 263
- #define TGCELLWIDTH 264
- #define TGCELLLENGTH 265
- #define TGFILLORDER 266
- #define TGDOCUMENTNAME 269
- #define TGIMAGEDESCRIPTION 270
- #define TGMAKE 271
- #define TGMODEL 272
-
- #define TGSTRIPOFFSETS 273
- #define TGORIENTATION 274
-
- #define TGSAMPLESPERPIXEL 277
- #define TGROWSPERSTRIP 278
- #define TGSTRIPBYTECOUNTS 279
- #define TGMINSAMPLEVALUE 280
- #define TGMAXSAMPLEVALUE 281
- #define TGXRESOLUTION 282
- #define TGYRESOLUTION 283
- #define TGPLANARCONFIGURATION 284
- #define TGPAGENAME 285
- #define TGXPOSITION 286
- #define TGYPOSITION 287
- #define TGFREEOFFSETS 288
- #define TGFREEBYTECOUNTS 289
-
- /* TIFF "header" (8 bytes)
- * note: GtTiffHdr plays a little loose with this structure.
- */
- typedef struct {
- WORD thByteOrder;
- WORD thVersion;
- DWORD thIfdOffset;
- } TIFFHDR;
-
- /* IFD entry
- * note: GtTiffEntry plays a little loose with this structure.
- */
- typedef struct {
- WORD deTag;
- WORD deType;
- DWORD deLength;
- DWORD deVal;
- } DIRENTRY;
-
- /* image data location
- */
- typedef struct {
- WORD dlWhere;
- #define INFILE 1
- #define INTABLE 2
- FILE *dlFp;
- LPSTR dlTable; /* address of locked-down table bytes */
- WORD dlOrder; /* INTELTIFF or MOTOROLATIFF.
- * relevant only when reading data.
- */
- } DLOC;
-
- static struct {
- WORD tag;
- char *str;
- } tagstr[] = {
- TGSUBFILETYPE, "SubfileType",
- TGIMAGEWIDTH, "ImageWidth",
- TGIMAGELENGTH, "ImageLength",
- TGCOMPRESSION, "Compression",
- TGPHOTOMETRICINTERPRETATION,"PhotometricInterp",
- TGTHRESHHOLDING, "Threshholding",
- TGCELLWIDTH, "CellWidth",
- TGCELLLENGTH, "CellLength",
- TGFILLORDER, "FillOrder",
- TGSTRIPOFFSETS, "StripOffsets",
- TGORIENTATION, "Orientation",
- TGSAMPLESPERPIXEL, "SamplesPerPixel",
- TGBITSPERSAMPLE, "BitsPerSample",
- TGROWSPERSTRIP, "RowsPerStrip",
- TGSTRIPBYTECOUNTS, "StripByteCounts",
- TGMINSAMPLEVALUE, "MinSampleValue",
- TGMAXSAMPLEVALUE, "MaxSampleValue",
- TGXRESOLUTION, "XResolution",
- TGYRESOLUTION, "YResolution",
- TGPLANARCONFIGURATION, "PlanarConfiguration",
- TGDOCUMENTNAME, "DocumentName",
- TGPAGENAME, "PageName",
- TGXPOSITION, "XPosition",
- TGYPOSITION, "YPosition",
- TGIMAGEDESCRIPTION, "ImageDescription",
- TGMAKE, "Make",
- TGMODEL, "Model",
- TGFREEOFFSETS, "FreeOffsets",
- TGFREEBYTECOUNTS, "FreeByteCounts",
- };
-
- /***************************** subroutines ***************************/
-
- /* swap bytes -- overlapping arrays are handled properly
- */
- static void swab (lpSrc, lpDst, nbytes)
- register LPSTR lpSrc, lpDst; /* assumed to be word-aligned */
- WORD nbytes; /* assumed to be even */
- {
- register WORD words;
- union {
- char c[2];
- WORD w;
- } wrd;
-
- words = nbytes/2;
-
- if (lpDst <= lpSrc || lpDst >= lpSrc + nbytes) {
- for (; words--; lpSrc += 2) {
- wrd.w = *(WORD FAR *)lpSrc;
- *lpDst++ = *(LPSTR)(wrd.c + 1); /* W2 doesn't like wrd.c[1] */
- *lpDst++ = *(LPSTR)(wrd.c);
- }
- }
- else { /* we'll have to go backward */
- lpSrc += nbytes - sizeof(WORD);
- lpDst += nbytes - 1;
- for (; words--; lpSrc -= 2) {
- wrd.w = *(WORD FAR *)lpSrc;
- *lpDst-- = *(LPSTR)(wrd.c);
- *lpDst-- = *(LPSTR)(wrd.c + 1);
- }
- }
- }
-
- /* swap words -- overlapping ranges are handled properly
- */
- LOCAL void swaw (lpSrc, lpDst, nbytes)
- register LPSTR lpSrc, lpDst; /* assumed to be word-aligned */
- WORD nbytes; /* assumed to be multiple of 4 */
- {
- register WORD dwords;
- union {
- char c[4];
- DWORD dw;
- } dwrd;
-
- dwords = nbytes/4;
-
- if (lpDst <= lpSrc || lpDst >= lpSrc + nbytes) {
- for (; dwords--; lpSrc += 4) {
- dwrd.dw = *(DWORD FAR *)lpSrc;
- *lpDst++ = *(LPSTR)(dwrd.c + 3);
- *lpDst++ = *(LPSTR)(dwrd.c + 2);
- *lpDst++ = *(LPSTR)(dwrd.c + 1);
- *lpDst++ = *(LPSTR)(dwrd.c);
- }
- }
- else { /* we'll have to go backward */
- lpSrc += nbytes - sizeof(DWORD);
- lpDst += nbytes - 1;
- for (; dwords--; lpSrc -= 4) {
- dwrd.dw = *(DWORD FAR *)lpSrc;
- *lpDst-- = *(LPSTR)(dwrd.c);
- *lpDst-- = *(LPSTR)(dwrd.c + 1);
- *lpDst-- = *(LPSTR)(dwrd.c + 2);
- *lpDst-- = *(LPSTR)(dwrd.c + 3);
- }
- }
- }
-
- RC GtTiffSizeof (n, p)
- WORD n; /* TIFFBYTE or ... */
- WORD *p; /* output */
- {
- RC err = SUCCESS;
-
- switch (n) {
- case TIFFBYTE:
- case TIFFASCII:
- *p = 1;
- break;
- case TIFFSHORT:
- *p = 2;
- break;
- case TIFFLONG:
- *p = 4;
- break;
- case TIFFRATIONAL:
- *p = 8;
- break;
- default:
- *p = 1;
- err = -1;
- break;
- }
- return err;
- }
-
- /* get data -- handles file/table and byte-order problems
- * 64K max
- */
- LOCAL RC GtData (pDloc, pos, n, dtype, lpData)
- DLOC *pDloc; /* data location - open file or locked-down table */
- DWORD pos; /* file/table position, with respect to its beginning */
- WORD n; /* number of data elements to read */
- WORD dtype; /* data type: TIFFSHORT, etc */
- LPSTR lpData; /* where to put the data */
- {
- RC err;
- WORD tsize;
- WORD BytesToRead;
- int red; /* # of bytes read */
- int ii;
-
- /* read the data
- */
- if (err = GtTiffSizeof (dtype, &tsize)) {
- printf ( "GtData: bad dtype\n");
- return err;
- }
- BytesToRead = tsize * n;
- if (pDloc->dlWhere == INFILE) {
- if (err = fseek (pDloc->dlFp, (long) pos, 0)) {
- printf ( "GtData: fseek error\n");
- return err;
- }
- if ((red = fread (lpData, 1, BytesToRead, pDloc->dlFp)) == 0) {
- printf ( "GtData: fread error\n");
- return -1;
- }
- }
- else if (pDloc->dlWhere == INTABLE) {
- printf ( "GtData: INTABLE not implemented here.\n");
- return -1;
- }
- else {
- printf ( "GtData: bad dlWhere\n");
- return -1;
- }
-
- /* change the byte order, if necessary
- */
- #ifdef WINDOWS
- if (pDloc->dlOrder == MOTOROLATIFF) {
- #endif
- #ifdef MACINTOSH
- if (pDloc->dlOrder == INTELTIFF) {
- #endif
- if (dtype == TIFFSHORT)
- swab (lpData, lpData, BytesToRead);
- else if (dtype == TIFFLONG)
- swaw (lpData, lpData, BytesToRead);
- else if (dtype == TIFFRATIONAL)
- swaw (lpData, lpData, BytesToRead);
- }
-
- /* return
- */
- return SUCCESS;
- }
-
- /* get TIFF 8-byte header
- * currently only probably portable. depends somewhat on compiler's
- * structure organization.
- */
- LOCAL RC GtTiffHdr (pDloc, pHdr)
- DLOC *pDloc;
- TIFFHDR *pHdr;
- {
- RC err;
-
- /* get the first 2 words
- */
- if (err = GtData (pDloc, (DWORD) 0, 2, TIFFSHORT,
- (LPSTR)&pHdr->thByteOrder)) {
- printf ( "GtTiffHdr: A\n");
- return err;
- }
-
- /* get the double word (IFD offset)
- */
- if (err = GtData (pDloc, (DWORD)4, 1, TIFFLONG,
- (LPSTR)&pHdr->thIfdOffset)) {
- printf ( "GtTiffHdr: B\n");
- return err;
- }
-
- /* return
- */
- return SUCCESS;
- }
-
- /* get TIFF directory entry
- */
- LOCAL RC GtTiffEntry (pDloc, EntryOffset, pDe)
- DLOC *pDloc;
- DWORD EntryOffset;
- DIRENTRY *pDe;
- {
- RC err;
-
- /* get the 2 words beginning with deTag
- */
- if (err = GtData (pDloc, EntryOffset, 2, TIFFSHORT,
- (LPSTR)&pDe->deTag)) {
- printf ("GtTiffEntry: A\n");
- return err;
- }
-
- /* get the 2 dwords, beginning with deLength
- */
- if (err = GtData (pDloc, EntryOffset + 4L, 2, TIFFLONG,
- (LPSTR)&pDe->deLength)) {
- printf ("GtTiffEntry: B\n");
- return err;
- }
-
- /* return
- */
- return SUCCESS;
- }
-
- /* get tag string
- */
- static char defstr[] = "???";
- LOCAL void GtTagString (tag, ps)
- WORD tag;
- char **ps;
- {
- int tablen;
- int ii;
-
- tablen = sizeof (tagstr) / sizeof (tagstr[0]);
- for (ii = 0; ii < tablen; ii++) {
- if (tag == tagstr[ii].tag) {
- *ps = tagstr[ii].str;
- return;
- }
- }
- *ps = defstr;
- }
-
- /* dump an entry
- */
- #define MAXVAL 80
-
- LOCAL RC dumpentry (pDloc, pos, pde)
- DLOC *pDloc;
- DWORD pos;
- DIRENTRY *pde;
- {
- RC err;
- WORD tsize;
- WORD BytesToRead;
- char *bufptr;
- union {
- char bytes[MAXVAL];
- DWORD dword;
- } buf;
- WORD maxitems;
- WORD item;
- char *s;
- DWORD valpos;
-
- /* dump the basic entry first:
- */
- GtTagString (pde->deTag, &s);
- printf ("%6lu tag=%5u [%-20.20s] type=%u length=%lu val=%lu\n",
- pos, pde->deTag, s, pde->deType, pde->deLength, pde->deVal);
-
- /* print out the value intelligently
- */
- if (err = GtTiffSizeof (pde->deType, &tsize)) {
- printf( "dumpentry: GtTiffSizeof error\n");
- return err;
- }
- BytesToRead = tsize * pde->deLength;
- maxitems = MAXVAL / tsize;
- maxitems = (pde->deLength < (DWORD) maxitems) ?
- (WORD)(pde->deLength) : maxitems;
- /* careful here: we can't just use deVal to grab data out of, since
- * may already have been byte-reversed!
- */
- if (BytesToRead <= 4)
- valpos = pos + 8L; /* deVal starts on byte 8, wit de */
- else
- valpos = pde->deVal;
- if (err = GtData (pDloc, valpos, maxitems, pde->deType, buf.bytes)) {
- printf ( "dumpentry: GtData error\n");
- return err;
- }
- bufptr = buf.bytes;
-
- switch (pde->deType) {
- case TIFFBYTE:
- for (item = 0; item < maxitems; item++)
- printf ("%x", (unsigned)(*bufptr++));
- printf ("\n");
- break;
- case TIFFASCII:
- if (maxitems == 0)
- break;
- printf ("%.*s\n", maxitems, bufptr);
- break;
- case TIFFSHORT:
- for (item = 0; item < maxitems; item++, bufptr += 2)
- printf ("%u ", *((WORD *)bufptr));
- printf ("\n");
- break;
- case TIFFLONG:
- for (item = 0; item < maxitems; item++, bufptr += 4)
- printf ("%lu ", *((DWORD *)bufptr));
- printf ("\n");
- break;
- case TIFFRATIONAL:
- for (item = 0; item < maxitems; item++) {
- printf ("% lu ", *((DWORD *)bufptr));
- bufptr += 4;
- printf ("%lu ", *((DWORD *)bufptr));
- bufptr += 4;
- }
- printf ("\n");
- break;
- default:
- printf ( "dumpentry: can't get here\n");
- break;
- }
- return SUCCESS;
- }
-
-
-
- /***************************** main routine **************************/
-
- main (ac, av)
- int ac;
- char **av;
- {
- RC err;
- TIFFHDR th;
- DIRENTRY de;
- WORD entries;
- WORD entry;
- DWORD location;
- DLOC dloc;
- DWORD dwtemp;
- WORD wtemp;
-
-
- /* check # of args
- */
- if (ac != 2) {
- printf ("usage: tiffdump filename\n");
- exit (1);
- }
-
- /* open the file
- */
- if ((dloc.dlFp = fopen (av[1], "rb")) == (FILE *) NULL) {
- printf ("can't open %s\n", av[1]);
- exit (1);
- }
- printf ("FILE: %s\n", av[1]);
- dloc.dlWhere = INFILE;
-
- /* read the first word, and determine the byte order
- */
- dloc.dlOrder = INTELTIFF; /* arbitrary -- I'll change it below */
- if (err = GtData (&dloc, 0L, 1, TIFFSHORT, &wtemp)) {
- printf ("can't read first word\n");
- goto quit;
- }
- dloc.dlOrder = wtemp;
-
- /* read the 8-byte header, and dump it
- */
- if (err = GtTiffHdr (&dloc, &th)) {
- printf ("can't read header\n");
- goto quit;
- }
- if (th.thByteOrder == INTELTIFF)
- printf ("%6lu ByteOrder = INTELTIFF\n", 0L);
- else if (th.thByteOrder == MOTOROLATIFF)
- printf ("%6lu ByteOrder = MOTOROLATIFF\n", 0L);
- else {
- printf ("bad byte order.\n");
- goto quit;
- }
- printf ("%6lu Version = %d\n", 2L, th.thVersion);
- printf ("%6lu IfdOffset = %lu\n", 4L, th.thIfdOffset);
-
- location = th.thIfdOffset;
- dloc.dlOrder = th.thByteOrder;
-
- /* loop through the IFD's
- */
- do {
- /* if ifd location is 0, quit
- */
- if (location == 0L) {
- printf ("ifd at 0. quit.\n");
- break;
- }
-
- /* read the number of entries, and dump it
- */
- if (err = GtData (&dloc, location, 1, TIFFSHORT, &entries)) {
- printf ("can't read # of entries\n");
- break;
- }
- printf ("\n%6lu Entries = %d\n", th.thIfdOffset, entries);
- if (entries == 0) {
- printf ("number of entries is 0. quit.\n");
- break;
- }
- location += 2;
-
- /* loop through the entries
- */
- for (entry = 0; entry < entries; entry++) {
-
- /* read the entry, and dump it
- */
- if (err = GtTiffEntry (&dloc, location, &de)) {
- printf ("can't read entry\n");
- goto quit;
- }
- if (err = dumpentry (&dloc, location, &de)) {
- printf ("dumpentry error\n");
- goto quit;
- }
-
- /* adjust the current location
- */
- location += sizeof (DIRENTRY);
-
- } /* end of entry loop */
-
- /* read the location of the next ifd
- */
- if (err = GtData(&dloc, location, 1, TIFFLONG, &dwtemp)) {
- printf ("%6lu can't read location of the next ifd\n",
- location);
- goto quit;
- }
- printf ("%6lu next ifd at %lu\n", location, dwtemp);
- location = dwtemp;
-
- } while (1); /* end of ifd loop */
-
- quit: ;
- fclose (dloc.dlFp);
- exit (0);
- }