Category : C Source Code
Archive   : TIFTOOL.ZIP
Filename : TIFFSWAP.C

 
Output of file : TIFFSWAP.C contained in archive : TIFTOOL.ZIP

/* 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;
}