home *** CD-ROM | disk | FTP | other *** search
- /* TiffSwap.c - convert a Motorola-style (MM) TIFF file to an Intel-style (II) TIFF file,
- * in place.
- *
- * If the TIFF file is already of type "II", it is converted to type "MM."
- *
- * Assumes that the image data itself does not need to be byte-swapped. This is true
- * with all currently defined compression schemes (as of TIFF 5.0), and with
- * uncompressed data where BitsPerSample is less than or equal to 8.
- *
- * That is, if BitsPerSample is greater than 8, and the data is uncompressed, this
- * program will not do its job properly. The resulting file will appear to work, since
- * the "header" information will be correct, but the image will display and print incorrectly.
- *
- * If any field in the file is more than 64k bytes, it will not be byte swapped properly
- * on the PC.
- */
- #define WINDOWS 1 /* define MACINTOSH if on MAC, WINDOWS if on PC AT */
- #include "stdio.h"
-
- /* prototypes:
- */
- #ifdef MACINTOSH
- int printf (char *, ...);
- FILE * fopen (char *, char *);
- int fseek (FILE *, long, int);
- int fread (char *, int, int, FILE *);
- int fwrite (char *, int, int, FILE *);
- int fclose (FILE *);
- char *mlalloc (unsigned long);
- int free (char *);
- #endif
-
- #ifdef WINDOWS
- char * malloc(unsigned);
- #endif
- /* 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)
- #define MAXSHORT (0x7FFF) /* maximum 16-bit signed int */
-
- /* TIFF data types
- */
- #define TIFFBYTE 1
- #define TIFFASCII 2
- #define TIFFSHORT 3
- #define TIFFLONG 4
- #define TIFFRATIONAL 5
-
-
- /* 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;
-
-
- /* a particularly greasy static:
- */
- DWORD TiffStart = 0L;
-
- /***************************** subroutines ***************************/
-
- /* swap bytes -- overlapping arrays are handled properly
- */
- void swab (LPSTR,LPSTR,WORD);
- 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
- *
- * actually, does a 4-byte reversal, not a swap of words within double words
- */
- void swaw (LPSTR,LPSTR,WORD);
- 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 (WORD, WORD *);
- 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
- */
- RC GtData (DLOC *, DWORD, WORD, WORD, LPSTR);
- 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;
-
- if (n == 0)
- goto done;
-
- /* 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+TiffStart), 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
- */
- done: return SUCCESS;
- }
-
- /* get TIFF 8-byte header
- * currently only probably portable. depends somewhat on compiler's
- * structure organization.
- */
- RC GtTiffHdr (DLOC *, TIFFHDR *);
- 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)) {
- return err;
- }
-
- /* get the double word (IFD offset)
- */
- if (err = GtData (pDloc, (DWORD)4, 1, TIFFLONG,
- (LPSTR)&pHdr->thIfdOffset)) {
- return err;
- }
-
- /* return
- */
- return SUCCESS;
- }
-
- /* get TIFF directory entry
- */
- RC GtTiffEntry (DLOC *, DWORD, DIRENTRY *);
- 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)) {
- return err;
- }
-
- /* get the 2 dwords, beginning with deLength
- */
- if (err = GtData (pDloc, EntryOffset + 4L, 2, TIFFLONG,
- (LPSTR)&pDe->deLength)) {
- return err;
- }
-
- /* return
- */
- return SUCCESS;
- }
-
-
- #define WORDS 1
- #define DWORDS 2
-
- /* byte-reverse words or double-words in a file
- */
- RC RevInFile (WORD, DWORD, WORD, FILE *);
- LOCAL RC RevInFile (which, dwPos, nItems, fp)
- WORD which; /* 1 = words, 2 = double words */
- DWORD dwPos;
- WORD nItems; /* words or double words */
- FILE *fp;
- {
- RC err = SUCCESS;
- WORD ItemSize;
- DWORD dwBytes;
- char *buf;
- int red;
-
- /* WORDS or DWORDS?
- */
- if (which == WORDS) {
- ItemSize = 2;
- } else {
- ItemSize = 4;
- }
-
- /* allocate
- *
- * On the PC, this code will break if dwBytes is greater than 64k.
- */
- {
- dwBytes = (DWORD)nItems * (DWORD)ItemSize;
-
- #ifdef MACINTOSH
- if ((buf = mlalloc (dwBytes)) == (char *)NULL)
- #endif
-
- #ifdef WINDOWS
- if ((buf = malloc ((unsigned)dwBytes)) == (char *)NULL)
- #endif
-
- {
- printf ("RevInFile: mlalloc\n");
- err = -1;
- goto cu0;
- }
- }
-
- /* read
- *
- * note that we are restricted to 32K-byte reads!
- */
- {
- if (err = fseek (fp, (long) (dwPos+TiffStart), 0)) {
- printf ("RevInFile: fseek error\n");
- goto cu1;
- }
-
- if (dwBytes > MAXSHORT) {
- printf ("RevInFile: too large\n");
- err = -1;
- goto cu1;
- }
-
- if ((red = fread (buf, ItemSize, (int)nItems, fp)) == 0) {
- printf ( "RevInFile: fread error\n");
- err = -1;
- goto cu1;
- }
- }
-
- /* reverse bytes within words or double words
- */
- if (which == WORDS) {
- swab (buf, buf, (WORD)dwBytes);
- } else {
- swaw (buf, buf, (WORD)dwBytes);
- }
-
- /* write
- */
- {
- if (err = fseek (fp, (long) (dwPos+TiffStart), 0)) {
- printf ("RevInFile: fseek error\n");
- goto cu1;
- }
-
- if ((red = fwrite (buf, ItemSize, (int)nItems, fp)) == 0) {
- printf ( "RevInFile: fread error\n");
- err = -1;
- goto cu1;
- }
- }
-
- /* return
- */
- cu1: free (buf);
- cu0: return err;
- }
-
-
- /* byte-reverse a directory entry in a TIFF file
- */
- RC RevEntry (DWORD, DIRENTRY *, FILE *);
- LOCAL RC RevEntry (dwPos, pde, fp)
- DWORD dwPos;
- DIRENTRY *pde;
- FILE *fp;
- {
- RC err = SUCCESS;
- WORD tsize;
- DWORD dwBytesToRead;
- DWORD dwValPos;
-
- /* reverse tag, type
- */
- if (err = RevInFile (WORDS, dwPos, 2, fp)) {
- printf ("RevEntry: tag,type\n");
- goto cu0;
- }
-
- /* reverse the length
- */
- if (err = RevInFile (DWORDS, dwPos + 4L, 1, fp)) {
- printf ("RevEntry: length\n");
- goto cu0;
- }
-
- /* reverse the value
- */
- {
- /* how many bytes to we have here?
- */
- if (err = GtTiffSizeof (pde->deType, &tsize)) {
- printf("RevEntry: GtTiffSizeof error\n");
- goto cu0;
- }
- dwBytesToRead = (DWORD)tsize * pde->deLength;
-
- /* if less than 4, the value is right here
- */
- if (dwBytesToRead <= 4L) {
- dwValPos = dwPos + 8L; /* deVal starts on byte 8, wit de */
- }
-
- /* otherwise we need to work harder, and reverse the pointer as
- * well as the data (if the data is not byte-oriented)
- */
- else {
-
- /* reverse the pointer
- */
- if (err = RevInFile (DWORDS, dwPos + 8L, 1, fp)) {
- printf ("RevEntry: pointer\n");
- goto cu0;
- }
-
- /* calculate file position of the value
- */
- dwValPos = pde->deVal;
- }
-
- /* read, reverse, and write, depending on the data type
- */
- switch (pde->deType) {
- case TIFFBYTE:
- case TIFFASCII:
- break;
- case TIFFSHORT:
- if (err = RevInFile (WORDS, dwValPos, pde->deLength, fp)) {
- printf ("error reversing SHORT values\n");
- goto cu0;
- }
- break;
- case TIFFLONG:
- if (err = RevInFile (DWORDS, dwValPos, pde->deLength, fp)) {
- printf ("error reversing LONG values\n");
- goto cu0;
- }
- break;
- case TIFFRATIONAL:
- if (err = RevInFile (DWORDS, dwValPos, pde->deLength * 2, fp)) {
- printf ("error reversing RATIONAL values\n");
- goto cu0;
- }
- break;
- default:
- printf ("RevEntry: can't get here\n");
- err = -1;
- goto cu0;
- break;
- }
-
- } /* end of value-reversing */
-
- cu0: return err;
- }
-
-
- /***************************** main routine **************************/
- #ifdef MACINTOSH
- int _main (int, char **);
- int _main (ac, av)
- #endif
-
- #ifdef WINDOWS
- int main (int, char **);
- int main (ac, av)
- #endif
-
- int ac;
- char **av;
- {
- RC err;
- TIFFHDR th;
- DIRENTRY de;
- WORD entries;
- WORD entry;
- DWORD location;
- DLOC dloc;
- DWORD dwtemp;
- WORD wtemp;
- WORD ByteOrder;
- WORD red;
- register FILE *fp;
-
-
- /* check # of args
- */
- if (ac != 2) {
- printf ("usage: filename\n");
- goto cu0;
- }
-
- /* open the input/output file
- */
- if ((fp = fopen (av[1], "r+b")) == (FILE *) NULL) {
- printf ("can't open %s\n", av[1]);
- goto cu0;
- }
- dloc.dlFp = fp;
- printf ("FILE: %s\n", av[1]);
- dloc.dlWhere = INFILE;
-
- /* since I use this program to process TIFF "files" that are embedded in
- * other files (a nonstandard thing to do), I will look for a
- * plausible start of the TIFF section. TODO: make this more
- * general (cycle through TIFF "files") and more robust (check for
- * version #, at least).
- */
- while ((red = fread ((char *)&ByteOrder, sizeof(WORD), 1, fp)) == 1) {
- if (ByteOrder == INTELTIFF || ByteOrder == MOTOROLATIFF)
- break;
- else
- TiffStart += 2L;
- }
- printf("TiffStart=%lu\n",TiffStart);
- printf("ByteOrder=%x\n",ByteOrder);
- if (red == 0) {
- printf ("can't find ByteOrder\n");
- goto quit;
- }
- dloc.dlOrder = ByteOrder;
-
- /* 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", 0L);
- printf (" (converting to MOTOROLATIFF)\n");
- }
- else if (th.thByteOrder == MOTOROLATIFF) {
- printf ("%6lu ByteOrder = MOTOROLATIFF", 0L);
- printf (" (converting to INTELTIFF)\n");
- }
- 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;
-
- /* change the byte order in the 8-byte header
- */
- {
- /* byte order
- */
- {
- WORD NewByteOrder;
- int retval;
-
- if (th.thByteOrder == INTELTIFF) {
- NewByteOrder = MOTOROLATIFF;
- } else {
- NewByteOrder = INTELTIFF;
- }
-
- if ((retval = fseek (fp, 0L, 0)) != 0) {
- printf ("can't seek to byte 0\n");
- goto quit;
- }
- if ((retval = fwrite ((char *)&NewByteOrder, sizeof(NewByteOrder), 1, fp))
- == 0) {
- printf ("can't write new byte order\n");
- goto quit;
- }
- }
-
- /* version:
- */
- if (err = RevInFile (WORDS, 2L, 1, fp)) {
- printf ("can't reverse header words\n");
- goto quit;
- }
- /* offset to 1st IFD:
- */
- if (err = RevInFile (DWORDS, 4L, 1, fp)) {
- printf ("can't reverse header words\n");
- goto quit;
- }
- }
-
- /* 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, (DWORD)location, 1, TIFFSHORT,
- (LPSTR)&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;
- }
-
- /* reverse the number of entries
- */
- if (err = RevInFile (WORDS, location, 1, fp)) {
- printf ("can't reverse number of entries\n");
- goto quit;
- }
-
- /* update location
- */
- 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 0
- if (err = dumpentry (&dloc, location, &de)) {
- printf ("dumpentry error\n");
- goto quit;
- }
- #endif /* 0 */
- /* reverse the entry
- */
- if (err = RevEntry (location, &de, fp)) {
- printf ("can't reverse entry\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, (DWORD)location, 1, TIFFLONG,
- (LPSTR)&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 (fp);
- cu0: return;
- }