home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TIFF / DVTIF1.ZIP / TIFFDUMP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1986-09-23  |  13.4 KB  |  587 lines

  1. /* tiffdump - dump a tiff file, to avoid painful hex dumps
  2.  */
  3. #define     WINDOWS        1        /* define MACINTOSH instead, if on MAC */
  4. #include "stdio.h"
  5.  
  6. /* basic data types -- may be different per machine/compiler
  7.  */
  8. typedef unsigned short        WORD;        /* 16-bit */
  9. typedef unsigned long        DWORD;        /* 32-bit */
  10. typedef int                    RC;            /* return code */
  11. typedef char                *LPSTR;
  12.  
  13.  
  14. #ifndef NULL
  15. #define        NULL            0L
  16. #endif
  17. #define        FAR
  18. #define        SUCCESS            0
  19. #define        LOCAL            static
  20. #define        INTELTIFF        (0x4949)
  21. #define        MOTOROLATIFF    (0x4d4d)
  22.  
  23. /* TIFF data types
  24.  */
  25. #define TIFFBYTE        1
  26. #define TIFFASCII        2
  27. #define TIFFSHORT        3
  28. #define TIFFLONG        4
  29. #define TIFFRATIONAL    5
  30.  
  31. /* TIFF tag constants
  32.  */
  33. #define TGSUBFILETYPE                255
  34. #define TGIMAGEWIDTH                256
  35. #define TGIMAGELENGTH                257
  36. #define TGBITSPERSAMPLE                258
  37. #define TGCOMPRESSION                259
  38.  
  39. #define TGPHOTOMETRICINTERPRETATION    262
  40. #define TGTHRESHHOLDING                263
  41. #define TGCELLWIDTH                    264
  42. #define TGCELLLENGTH                265
  43. #define TGFILLORDER                    266
  44. #define TGDOCUMENTNAME                269
  45. #define TGIMAGEDESCRIPTION            270
  46. #define TGMAKE                        271
  47. #define TGMODEL                        272
  48.  
  49. #define TGSTRIPOFFSETS                273
  50. #define TGORIENTATION                274
  51.  
  52. #define TGSAMPLESPERPIXEL            277
  53. #define TGROWSPERSTRIP                278
  54. #define TGSTRIPBYTECOUNTS            279
  55. #define TGMINSAMPLEVALUE            280
  56. #define TGMAXSAMPLEVALUE            281
  57. #define TGXRESOLUTION                282
  58. #define TGYRESOLUTION                283
  59. #define TGPLANARCONFIGURATION        284
  60. #define TGPAGENAME                    285
  61. #define TGXPOSITION                    286
  62. #define TGYPOSITION                    287
  63. #define TGFREEOFFSETS                288
  64. #define TGFREEBYTECOUNTS            289
  65.  
  66. /* TIFF "header" (8 bytes)
  67.  * note: GtTiffHdr plays a little loose with this structure.
  68.  */
  69. typedef struct {
  70.         WORD    thByteOrder;
  71.         WORD    thVersion;
  72.         DWORD    thIfdOffset;
  73. } TIFFHDR;
  74.  
  75. /* IFD entry
  76.  * note: GtTiffEntry plays a little loose with this structure.
  77.  */
  78. typedef struct {
  79.         WORD  deTag;
  80.         WORD  deType;
  81.         DWORD deLength;
  82.         DWORD deVal;
  83. } DIRENTRY;
  84.  
  85. /* image data location
  86.  */
  87. typedef struct {
  88.     WORD        dlWhere;
  89. #define                INFILE    1
  90. #define                INTABLE    2
  91.     FILE        *dlFp;
  92.     LPSTR        dlTable;    /* address of locked-down table bytes */
  93.     WORD        dlOrder;    /* INTELTIFF or MOTOROLATIFF.  
  94.                              * relevant only when reading data.
  95.                              */
  96. } DLOC;
  97.  
  98. static struct {
  99.     WORD    tag;
  100.      char    *str;
  101. } tagstr[] = {
  102. TGSUBFILETYPE,                "SubfileType",
  103. TGIMAGEWIDTH,                "ImageWidth",
  104. TGIMAGELENGTH,                "ImageLength",
  105. TGCOMPRESSION,                "Compression",
  106. TGPHOTOMETRICINTERPRETATION,"PhotometricInterp",
  107. TGTHRESHHOLDING,            "Threshholding",
  108. TGCELLWIDTH,                "CellWidth",
  109. TGCELLLENGTH,                "CellLength",
  110. TGFILLORDER,                "FillOrder",
  111. TGSTRIPOFFSETS,                "StripOffsets",
  112. TGORIENTATION,                "Orientation",
  113. TGSAMPLESPERPIXEL,            "SamplesPerPixel",
  114. TGBITSPERSAMPLE,            "BitsPerSample",
  115. TGROWSPERSTRIP,                "RowsPerStrip",
  116. TGSTRIPBYTECOUNTS,            "StripByteCounts",
  117. TGMINSAMPLEVALUE,            "MinSampleValue",
  118. TGMAXSAMPLEVALUE,            "MaxSampleValue",
  119. TGXRESOLUTION,                "XResolution",
  120. TGYRESOLUTION,                "YResolution",
  121. TGPLANARCONFIGURATION,        "PlanarConfiguration",
  122. TGDOCUMENTNAME,                "DocumentName",
  123. TGPAGENAME,                    "PageName",
  124. TGXPOSITION,                "XPosition",
  125. TGYPOSITION,                "YPosition",
  126. TGIMAGEDESCRIPTION,            "ImageDescription",
  127. TGMAKE,                        "Make",
  128. TGMODEL,                    "Model",
  129. TGFREEOFFSETS,                "FreeOffsets",
  130. TGFREEBYTECOUNTS,            "FreeByteCounts",
  131. };
  132.  
  133. /***************************** subroutines ***************************/
  134.  
  135. /* swap bytes -- overlapping arrays are handled properly
  136.  */
  137. static void swab (lpSrc, lpDst, nbytes)
  138. register LPSTR    lpSrc, lpDst;    /* assumed to be word-aligned */
  139. WORD              nbytes;            /* assumed to be even */
  140. {
  141.         register WORD words;
  142.         union {
  143.             char c[2];
  144.             WORD w;
  145.         } wrd;
  146.  
  147.         words = nbytes/2;
  148.  
  149.         if (lpDst <= lpSrc || lpDst >= lpSrc + nbytes) {
  150.             for (; words--; lpSrc += 2) {
  151.                 wrd.w = *(WORD FAR *)lpSrc;
  152.                 *lpDst++ = *(LPSTR)(wrd.c + 1);    /* W2 doesn't like wrd.c[1] */
  153.                 *lpDst++ = *(LPSTR)(wrd.c);
  154.             }
  155.         }
  156.         else {        /* we'll have to go backward */
  157.             lpSrc += nbytes - sizeof(WORD);
  158.             lpDst += nbytes - 1;
  159.             for (; words--; lpSrc -= 2) {
  160.                 wrd.w = *(WORD FAR *)lpSrc;
  161.                 *lpDst-- = *(LPSTR)(wrd.c);
  162.                 *lpDst-- = *(LPSTR)(wrd.c + 1);
  163.             }
  164.         }
  165. }
  166.  
  167. /* swap words -- overlapping ranges are handled properly
  168.  */
  169. LOCAL void swaw (lpSrc, lpDst, nbytes)
  170. register LPSTR    lpSrc, lpDst;    /* assumed to be word-aligned */
  171. WORD              nbytes;            /* assumed to be multiple of 4 */
  172. {
  173.         register WORD dwords;
  174.         union {
  175.             char c[4];
  176.             DWORD dw;
  177.         } dwrd;
  178.  
  179.         dwords = nbytes/4;
  180.  
  181.         if (lpDst <= lpSrc || lpDst >= lpSrc + nbytes) {
  182.             for (; dwords--; lpSrc += 4) {
  183.                 dwrd.dw = *(DWORD FAR *)lpSrc;
  184.                 *lpDst++ = *(LPSTR)(dwrd.c + 3);
  185.                 *lpDst++ = *(LPSTR)(dwrd.c + 2);
  186.                 *lpDst++ = *(LPSTR)(dwrd.c + 1);
  187.                 *lpDst++ = *(LPSTR)(dwrd.c);
  188.             }
  189.         }
  190.         else {        /* we'll have to go backward */
  191.             lpSrc += nbytes - sizeof(DWORD);
  192.             lpDst += nbytes - 1;
  193.             for (; dwords--; lpSrc -= 4) {
  194.                 dwrd.dw = *(DWORD FAR *)lpSrc;
  195.                 *lpDst-- = *(LPSTR)(dwrd.c);
  196.                 *lpDst-- = *(LPSTR)(dwrd.c + 1);
  197.                 *lpDst-- = *(LPSTR)(dwrd.c + 2);
  198.                 *lpDst-- = *(LPSTR)(dwrd.c + 3);
  199.             }
  200.         }
  201. }
  202.  
  203. RC GtTiffSizeof (n, p)
  204. WORD n;        /* TIFFBYTE or ... */
  205. WORD *p;    /* output */
  206. {
  207.     RC err = SUCCESS;
  208.  
  209.     switch (n) {
  210.     case TIFFBYTE:
  211.     case TIFFASCII:
  212.         *p = 1;
  213.         break;
  214.     case TIFFSHORT:
  215.         *p = 2;
  216.         break;
  217.     case TIFFLONG:
  218.         *p = 4;
  219.         break;
  220.     case TIFFRATIONAL:
  221.         *p = 8;
  222.         break;
  223.     default:
  224.         *p = 1;
  225.         err = -1;
  226.         break;
  227.     }
  228.     return err;
  229. }
  230.  
  231. /* get data -- handles file/table and byte-order problems
  232.  * 64K max
  233.  */
  234. LOCAL RC GtData (pDloc, pos, n, dtype, lpData)
  235. DLOC    *pDloc;        /* data location - open file or locked-down table */
  236. DWORD    pos;        /* file/table position, with respect to its beginning */
  237. WORD    n;            /* number of data elements to read */
  238. WORD    dtype;        /* data type: TIFFSHORT, etc */
  239. LPSTR    lpData;        /* where to put the data */
  240. {
  241.         RC        err;
  242.         WORD    tsize;
  243.         WORD    BytesToRead;
  244.         int        red;        /* # of bytes read */
  245.         int        ii;
  246.  
  247.         /* read the data
  248.          */
  249.         if (err = GtTiffSizeof (dtype, &tsize)) {
  250.             printf ( "GtData: bad dtype\n");
  251.             return err;
  252.         }
  253.         BytesToRead = tsize * n;
  254.         if (pDloc->dlWhere == INFILE) {
  255.             if (err = fseek (pDloc->dlFp, (long) pos, 0)) {
  256.                 printf ( "GtData: fseek error\n");
  257.                 return err;
  258.             }
  259.             if ((red = fread (lpData, 1, BytesToRead, pDloc->dlFp)) == 0) {
  260.                 printf ( "GtData: fread error\n");
  261.                 return -1;
  262.             }
  263.         }
  264.         else if (pDloc->dlWhere == INTABLE) {
  265.             printf ( "GtData: INTABLE not implemented here.\n");
  266.             return -1;
  267.         }
  268.         else {
  269.             printf ( "GtData: bad dlWhere\n");
  270.             return -1;
  271.         }
  272.  
  273.         /* change the byte order, if necessary
  274.          */
  275. #ifdef WINDOWS
  276.         if (pDloc->dlOrder == MOTOROLATIFF) {
  277. #endif
  278. #ifdef MACINTOSH
  279.         if (pDloc->dlOrder == INTELTIFF) {
  280. #endif
  281.             if (dtype == TIFFSHORT)
  282.                 swab (lpData, lpData, BytesToRead);
  283.             else if (dtype == TIFFLONG)
  284.                 swaw (lpData, lpData, BytesToRead);
  285.             else if (dtype == TIFFRATIONAL)
  286.                 swaw (lpData, lpData, BytesToRead);
  287.         }
  288.  
  289.         /* return
  290.          */
  291.         return SUCCESS;
  292. }
  293.  
  294. /* get TIFF 8-byte header
  295.  * currently only probably portable.  depends somewhat on compiler's 
  296.  * structure organization.
  297.  */
  298. LOCAL RC GtTiffHdr (pDloc, pHdr)
  299. DLOC *pDloc;
  300. TIFFHDR *pHdr;
  301. {
  302.         RC err;
  303.  
  304.         /* get the first 2 words
  305.          */
  306.         if (err = GtData (pDloc, (DWORD) 0, 2, TIFFSHORT, 
  307.          (LPSTR)&pHdr->thByteOrder)) {
  308.             printf ( "GtTiffHdr: A\n");
  309.             return err;
  310.         }
  311.  
  312.         /* get the double word (IFD offset)
  313.          */
  314.         if (err = GtData (pDloc, (DWORD)4, 1, TIFFLONG, 
  315.          (LPSTR)&pHdr->thIfdOffset)) {
  316.             printf ( "GtTiffHdr: B\n");
  317.             return err;
  318.         }
  319.  
  320.         /* return
  321.          */
  322.         return SUCCESS;
  323. }
  324.  
  325. /* get TIFF directory entry
  326.  */
  327. LOCAL RC GtTiffEntry (pDloc, EntryOffset, pDe)
  328. DLOC    *pDloc;
  329. DWORD    EntryOffset;
  330. DIRENTRY    *pDe;
  331. {
  332.         RC err;
  333.  
  334.         /* get the 2 words beginning with deTag
  335.          */
  336.         if (err = GtData (pDloc, EntryOffset, 2, TIFFSHORT,
  337.          (LPSTR)&pDe->deTag)) {
  338.             printf ("GtTiffEntry: A\n");
  339.             return err;
  340.         }
  341.  
  342.         /* get the 2 dwords, beginning with deLength
  343.          */
  344.         if (err = GtData (pDloc, EntryOffset + 4L, 2, TIFFLONG,
  345.          (LPSTR)&pDe->deLength)) {
  346.             printf ("GtTiffEntry: B\n");
  347.             return err;
  348.         }
  349.  
  350.         /* return
  351.          */
  352.         return SUCCESS;
  353. }
  354.  
  355. /* get tag string
  356.  */
  357. static char defstr[] = "???";
  358. LOCAL void GtTagString (tag, ps)
  359. WORD    tag;
  360. char    **ps;
  361. {
  362.         int tablen;
  363.         int ii;
  364.  
  365.         tablen = sizeof (tagstr) / sizeof (tagstr[0]);
  366.         for (ii = 0; ii < tablen; ii++) {
  367.             if (tag == tagstr[ii].tag) {
  368.                 *ps = tagstr[ii].str;
  369.                 return;
  370.             }
  371.         }
  372.         *ps = defstr;
  373. }
  374.  
  375. /* dump an entry
  376.  */
  377. #define MAXVAL 80
  378.  
  379. LOCAL RC dumpentry (pDloc, pos, pde)
  380. DLOC        *pDloc;
  381. DWORD        pos;
  382. DIRENTRY    *pde;
  383. {
  384.         RC        err;
  385.         WORD    tsize;
  386.         WORD    BytesToRead;
  387.         char    *bufptr;
  388.         union {
  389.             char    bytes[MAXVAL];
  390.             DWORD    dword;
  391.         } buf;
  392.         WORD    maxitems;
  393.         WORD    item;
  394.         char    *s;
  395.         DWORD    valpos;
  396.  
  397.         /* dump the basic entry first:
  398.          */
  399.         GtTagString (pde->deTag, &s);
  400.         printf ("%6lu  tag=%5u [%-20.20s] type=%u length=%lu val=%lu\n",
  401.          pos, pde->deTag, s, pde->deType, pde->deLength, pde->deVal);
  402.  
  403.         /* print out the value intelligently
  404.          */
  405.         if (err = GtTiffSizeof (pde->deType, &tsize)) {
  406.             printf( "dumpentry: GtTiffSizeof error\n");
  407.             return err;
  408.         }
  409.         BytesToRead = tsize * pde->deLength;
  410.         maxitems = MAXVAL / tsize;
  411.         maxitems = (pde->deLength < (DWORD) maxitems) ?
  412.          (WORD)(pde->deLength) : maxitems;
  413.         /* careful here: we can't just use deVal to grab data out of, since
  414.          * may already have been byte-reversed!
  415.          */
  416.         if (BytesToRead <= 4)
  417.             valpos = pos + 8L;    /* deVal starts on byte 8, wit de */
  418.         else
  419.             valpos = pde->deVal;
  420.         if (err = GtData (pDloc, valpos, maxitems, pde->deType, buf.bytes)) {
  421.             printf ( "dumpentry: GtData error\n");
  422.             return err;
  423.         }
  424.         bufptr = buf.bytes;
  425.         
  426.         switch (pde->deType) {
  427.         case TIFFBYTE:
  428.             for (item = 0; item < maxitems; item++)
  429.                 printf ("%x", (unsigned)(*bufptr++));
  430.             printf ("\n");
  431.             break;
  432.         case TIFFASCII:
  433.             if (maxitems == 0)
  434.                 break;
  435.             printf ("%.*s\n", maxitems, bufptr);
  436.             break;
  437.         case TIFFSHORT:
  438.             for (item = 0; item < maxitems; item++, bufptr += 2)
  439.                 printf ("%u ", *((WORD *)bufptr));
  440.             printf ("\n");
  441.             break;
  442.         case TIFFLONG:
  443.             for (item = 0; item < maxitems; item++, bufptr += 4)
  444.                 printf ("%lu ", *((DWORD *)bufptr));
  445.             printf ("\n");
  446.             break;
  447.         case TIFFRATIONAL:
  448.             for (item = 0; item < maxitems; item++) {
  449.                 printf ("% lu ", *((DWORD *)bufptr));
  450.                 bufptr += 4;
  451.                 printf ("%lu ", *((DWORD *)bufptr));
  452.                 bufptr += 4;
  453.             }
  454.             printf ("\n");
  455.             break;
  456.         default:
  457.             printf ( "dumpentry: can't get here\n");
  458.             break;
  459.         }
  460.         return SUCCESS;
  461. }
  462.  
  463.  
  464.  
  465. /***************************** main routine **************************/
  466.  
  467. main (ac, av)
  468. int ac;
  469. char **av;
  470. {
  471.          RC            err;
  472.          TIFFHDR        th;
  473.          DIRENTRY    de;
  474.          WORD        entries;
  475.         WORD        entry;
  476.          DWORD        location;
  477.         DLOC        dloc;
  478.         DWORD        dwtemp;
  479.         WORD        wtemp;
  480.          
  481.          
  482.          /* check # of args
  483.           */
  484.          if (ac != 2) {
  485.              printf ("usage: tiffdump  filename\n");
  486.              exit (1);
  487.          }
  488.          
  489.          /* open the file
  490.           */
  491.          if ((dloc.dlFp = fopen (av[1], "rb")) == (FILE *) NULL) {
  492.              printf ("can't open %s\n", av[1]);
  493.              exit (1);
  494.          }
  495.          printf ("FILE: %s\n", av[1]);
  496.         dloc.dlWhere = INFILE;
  497.  
  498.         /* read the first word, and determine the byte order
  499.          */
  500.         dloc.dlOrder = INTELTIFF;    /* arbitrary -- I'll change it below */
  501.         if (err = GtData (&dloc, 0L, 1, TIFFSHORT, &wtemp)) {
  502.             printf ("can't read first word\n");
  503.             goto quit;
  504.         }
  505.         dloc.dlOrder = wtemp;
  506.  
  507.          /* read the 8-byte header, and dump it
  508.           */
  509.          if (err = GtTiffHdr (&dloc, &th)) {
  510.              printf ("can't read header\n");
  511.              goto quit;
  512.          }
  513.          if (th.thByteOrder == INTELTIFF)
  514.              printf ("%6lu  ByteOrder = INTELTIFF\n", 0L);
  515.          else if (th.thByteOrder == MOTOROLATIFF)
  516.              printf ("%6lu  ByteOrder = MOTOROLATIFF\n", 0L);
  517.         else {
  518.             printf ("bad byte order.\n");
  519.             goto quit;
  520.         }
  521.          printf ("%6lu  Version = %d\n", 2L, th.thVersion);
  522.          printf ("%6lu  IfdOffset = %lu\n", 4L, th.thIfdOffset);
  523.          
  524.          location = th.thIfdOffset;
  525.         dloc.dlOrder = th.thByteOrder;
  526.          
  527.          /* loop through the IFD's
  528.           */
  529.          do {
  530.              /* if ifd location is 0, quit
  531.               */
  532.              if (location == 0L) {
  533.                  printf ("ifd at 0. quit.\n");
  534.                  break;
  535.              }
  536.          
  537.              /* read the number of entries, and dump it
  538.               */
  539.              if (err = GtData (&dloc, location, 1, TIFFSHORT, &entries)) {
  540.                  printf ("can't read # of entries\n");
  541.                  break;
  542.              }
  543.              printf ("\n%6lu  Entries = %d\n", th.thIfdOffset, entries);
  544.              if (entries == 0) {
  545.                  printf ("number of entries is 0. quit.\n");
  546.                  break;
  547.              }
  548.              location += 2;
  549.          
  550.              /* loop through the entries
  551.               */
  552.              for (entry = 0; entry < entries; entry++) {
  553.              
  554.                  /* read the entry, and dump it
  555.                   */
  556.                  if (err = GtTiffEntry (&dloc, location, &de)) {
  557.                      printf ("can't read entry\n");
  558.                      goto quit;
  559.                  }
  560.                 if (err = dumpentry (&dloc, location, &de)) {
  561.                     printf ("dumpentry error\n");
  562.                     goto quit;
  563.                 }
  564.                  
  565.                  /* adjust the current location
  566.                   */
  567.                  location += sizeof (DIRENTRY);
  568.                  
  569.              } /* end of entry loop */
  570.              
  571.              /* read the location of the next ifd
  572.               */
  573.              if (err = GtData(&dloc, location, 1, TIFFLONG, &dwtemp)) {
  574.                  printf ("%6lu  can't read location of the next ifd\n",
  575.                   location);
  576.                  goto quit;
  577.              }    
  578.              printf ("%6lu  next ifd at %lu\n", location, dwtemp);
  579.              location = dwtemp;
  580.              
  581.          } while (1); /* end of ifd loop */
  582.          
  583. quit:    ;
  584.          fclose (dloc.dlFp);
  585.          exit (0);
  586. }
  587.