Tizen 2.1 base
[platform/upstream/hplip.git] / ip / xtiff.c
1 /* libhpojip -- HP OfficeJet image-processing library. */
2
3 /* Copyright (C) 1995-2002 Hewlett-Packard Company
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
12  * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
13  * NON-INFRINGEMENT.  See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18  * MA 02111-1307, USA.
19  *
20  * In addition, as a special exception, Hewlett-Packard Company
21  * gives permission to link the code of this program with any
22  * version of the OpenSSL library which is distributed under a
23  * license identical to that listed in the included LICENSE.OpenSSL
24  * file, and distribute linked combinations including the two.
25  * You must obey the GNU General Public License in all respects
26  * for all of the code used other than OpenSSL.  If you modify
27  * this file, you may extend this exception to your version of the
28  * file, but you are not obligated to do so.  If you do not wish to
29  * do so, delete this exception statement from your version.
30  */
31
32 /* Original author: Mark Overton and others.
33  *
34  * Ported to Linux by David Paschal.
35  */
36
37 /*****************************************************************************\
38  *
39  * xtiff.c - encoder and decoder for TIFF files for image processor
40  *
41  *****************************************************************************
42  *
43  * Name of Global Jump-Table:
44  *
45  *    tifEncodeTbl = the encoder,
46  *    tifDecodeTbl = the decoder.
47  *
48  * Encoder:  Items in aXformInfo array passed into setXformSpec:
49  *
50  *    aXformInfo[IP_TIFF_FILE_PATH] = pointer to a file-path, or NULL
51  *
52  *        If NULL, a one-page TIFF is output in the normal manner.
53  *        If not NULL, this must be a pointer to a string containing a file-path.
54  *        If the given file does not exist, it will be created and one image will
55  *        be put in it.  If it does exist, the image will be APPENDED to this file,
56  *        and no data will be output by this xform.  So if one or more pages are
57  *        already in the file, we will add another page to it.  This xform does
58  *        the opening and closing of the file.
59  *
60  * Decoder:  Items in aXformInfo array passed into setXformSpec:
61  *
62  *       None.
63  *
64  * Capabilities and Limitations:
65  *
66  *    Handles 1, 8, 16, 24 and 48 bits per pixel.
67  *
68  * Default Input Traits, and Output Traits:
69  *
70  *          trait             default input             output
71  *    -------------------  ---------------------  ------------------------
72  *    iPixelsPerRow         * passed into output   same as default input
73  *    iBitsPerPixel         * passed into output   same as default input
74  *    iComponentsPerPixel     passed into output   same as default input
75  *    lHorizDPI               passed into output   same as default input
76  *    lVertDPI                passed into output   same as default input
77  *    lNumRows                passed into output   same as default input
78  *    iNumPages               passed into output   same as default input
79  *    iPageNum                passed into output   same as default input
80  *
81  *    Above, a "*" by an item indicates it must be valid (not negative).
82  *
83  * Apr 2000, Mark Overton, ported header-setup from TWAIN source, and added
84  *                         multi-page capability
85  * Feb 1998, Mark Overton, ported to new Image Processor code
86  * May 1996, Mark Overton, wrote original code
87  * Jun 2000, Mark Overton, wrote a simple decoder that does no file-seeks
88  *
89  *****************************************************************************/
90
91
92 #include "stdio.h"    /* for FILE operations */
93 #include "assert.h"
94 #include "hpip.h"
95 #include "ipdefs.h"
96 #include "string.h"
97
98
99 #if 0
100     #include "stdio.h"
101     #include <tchar.h>
102
103     #define PRINT(msg,arg1,arg2) \
104         _ftprintf(stderr, msg, (int)arg1, (int)arg2)
105 #else
106     #define PRINT(msg,arg1,arg2)
107 #endif
108
109 #define CHECK_VALUE 0x1ce5ca7e
110
111
112
113 /*____________________________________________________________________________
114  |                                                                            |
115  | Constants pertaining to tags                                               |
116  |____________________________________________________________________________|
117 */
118
119
120 /* TIF_INST - our instance variables */
121
122 typedef struct {
123     IP_IMAGE_TRAITS traits;   /* traits of the image */
124     int      iBitsPerSample;  /* bits per channel (1, 8 or 16) */
125     BOOL     bByteSwap;       /* bytes are in wrong endian order, so must swap? */
126     char     sFilePath[200];  /* path to the file (empty string means none) */
127     FILE    *fileOut;         /* handle of opened file */
128     DWORD    dwRawRowBytes;   /* bytes per raw row */
129     DWORD    dwRowsDone;      /* number of rows converted so far */
130     DWORD    dwValidChk;      /* struct validity check value */
131     DWORD    dwInNextPos;     /* file pos for subsequent input */
132     DWORD    dwOutNextPos;    /* file pos for subsequent output */
133     BOOL     fDidHeader;      /* already sent the header? */
134 } TIF_INST, *PTIF_INST;
135
136
137 /* Types having known sizes */
138 typedef unsigned char  TIFF_UBYTE;    /* 8 bits  */
139 typedef unsigned short TIFF_USHORT;   /* 16 bits */
140 typedef unsigned int   TIFF_ULONG;    /* 32 bits */
141 typedef   signed char  TIFF_SBYTE;    /* 8 bits  */
142 typedef   signed short TIFF_SSHORT;   /* 16 bits */
143 typedef   signed int   TIFF_SLONG;    /* 32 bits */
144
145 /* TIFF file header defines */
146 #define INTEL                 0x4949
147 #define TIFF_VERSION          42
148
149 /* TIFF field lengths */
150 #define TIFFBYTE              1
151 #define TIFFASCII             2
152 #define TIFFSHORT             3
153 #define TIFFLONG              4
154 #define TIFFRATIONAL          5
155 #define TIFFSBYTE             6
156 #define TIFFUNDEFINED         7
157 #define TIFFSSHORT            8
158 #define TIFFSLONG             9
159 #define TIFFSRATIONAL         10
160
161 /* TIFF compression type */
162 #define NOCOMPRESSION         1
163
164 /* TIFF planar configuration */
165 #define CONTIGUOUS            1
166 #define PLANAR                2
167
168 /* TIFF photometric interpretations */
169 #define ZERO_IS_WHITE         0
170 #define ZERO_IS_BLACK         1
171 #define RGB_COLOR             2
172
173 /* TIFF resolution units */
174 #define DOTS_PER_INCH         2
175
176
177 /* TIFF tags */
178 #define NUMTAGS 13
179 #define BITS_PER_SAMPLE       258    // 0x0102
180 #define COMPRESSION           259    // 0x0103
181 #define IMAGE_LENGTH          257    // 0x0101
182 #define IMAGE_WIDTH           256    // 0x0100
183 #define NEW_SUBFILE           254    // 0x00fe
184 #define PHOTO_INTERPRET       262    // 0x0106
185 #define RESOLUTION_UNIT       296    // 0x0128
186 #define ROWS_PER_STRIP        278    // 0x0116
187 #define SAMPLES_PER_PIXEL     277    // 0x0115
188 #define STRIP_COUNTS          279    // 0x0117
189 #define STRIP_OFFSETS         273    // 0x0111
190 #define XRESOLUTION           282    // 0x011A
191 #define YRESOLUTION           283    // 0x011B
192
193 typedef struct {
194      TIFF_ULONG n;
195      TIFF_ULONG d;
196 } __attribute__((packed)) RATIONAL;
197
198 typedef union {
199      TIFF_UBYTE  b[4];
200      TIFF_USHORT s[2];
201      TIFF_ULONG  l;
202      TIFF_ULONG  o;
203 } __attribute__((packed)) TIFFVALUE;
204
205 typedef struct {
206      TIFF_USHORT TagID;
207      TIFF_USHORT Kind;
208      TIFF_ULONG  Length;  /* number of items, NOT number of bytes */
209      TIFFVALUE   Value;
210 } __attribute__((packed)) TIFFTAG;
211
212 typedef struct {
213     TIFF_USHORT NumTags;
214     TIFFTAG     Tag[NUMTAGS];
215     TIFF_ULONG  OffsetNextIFD;
216 } __attribute__((packed)) TIFFIFD;
217
218 typedef struct {
219     TIFF_UBYTE    ByteOrder[2];
220     TIFF_USHORT    Version;
221     TIFF_ULONG    OffsetFirstIFD;
222 } __attribute__((packed)) TIFFHEADER;
223
224 #define NUMEXTBYTES (2*sizeof(RATIONAL) + 3*sizeof(TIFF_USHORT))
225 #define MAX_HEADER_SIZE (sizeof(TIFFHEADER) + sizeof(TIFFIFD) + NUMEXTBYTES)
226
227
228
229 /*****************************************************************************\
230  *
231  * tifEncode_openXform - Creates a new instance of the transformer
232  *
233  *****************************************************************************
234  *
235  * This returns a handle for the new instance to be passed into
236  * all subsequent calls.
237  *
238  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
239  *
240 \*****************************************************************************/
241
242 static WORD tifEncode_openXform (
243     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
244 {
245     PTIF_INST g;
246
247     INSURE (pXform != NULL);
248     IP_MEM_ALLOC (sizeof(TIF_INST), g);
249     *pXform = g;
250     memset (g, 0, sizeof(TIF_INST));
251     g->dwValidChk = CHECK_VALUE;
252     return IP_DONE;
253
254     fatal_error:
255     return IP_FATAL_ERROR;
256 }
257
258
259
260 /*****************************************************************************\
261  *
262  * tifEncode_setDefaultInputTraits - Specifies default input image traits
263  *
264  *****************************************************************************
265  *
266  * The header of the file-type handled by the transform probably does
267  * not include *all* the image traits we'd like to know.  Those not
268  * specified in the file-header are filled in from info provided by
269  * this routine.
270  *
271  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
272  *
273 \*****************************************************************************/
274
275 static WORD tifEncode_setDefaultInputTraits (
276     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
277     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
278 {
279     PTIF_INST g;
280     int       ppr, bpp;
281
282     HANDLE_TO_PTR (hXform, g);
283     ppr = pTraits->iPixelsPerRow;
284     bpp = pTraits->iBitsPerPixel;
285
286     /* Insure that values we actually use are known */
287     INSURE (ppr > 0);
288     INSURE (bpp > 0);
289
290     g->dwRawRowBytes = (ppr*bpp + 7) / 8;
291     g->traits = *pTraits;   /* a structure copy */
292
293     return IP_DONE;
294
295     fatal_error:
296     return IP_FATAL_ERROR;
297 }
298
299
300
301 /*****************************************************************************\
302  *
303  * tifEncode_setXformSpec - Provides xform-specific information
304  *
305 \*****************************************************************************/
306
307 static WORD tifEncode_setXformSpec (
308     IP_XFORM_HANDLE  hXform,         /* in: handle for xform */
309     DWORD_OR_PVOID   aXformInfo[])   /* in: xform information */
310 {
311     PTIF_INST g;
312     char      *s;
313
314     HANDLE_TO_PTR (hXform, g);
315     s = (char*)aXformInfo[IP_TIFF_FILE_PATH].pvoid;
316     if (s != NULL)
317         strcpy (g->sFilePath, s);
318     return IP_DONE;
319
320     fatal_error:
321     return IP_FATAL_ERROR;
322 }
323
324
325
326 /*****************************************************************************\
327  *
328  * tifEncode_getHeaderBufSize- Returns size of input buf needed to hold header
329  *
330 \*****************************************************************************/
331
332 static WORD tifEncode_getHeaderBufSize (
333     IP_XFORM_HANDLE   hXform,         /* in:  handle for xform */
334     DWORD            *pdwInBufLen)    /* out: buf size for parsing header */
335 {
336     /* since input is raw pixels, there is no header, so set it to zero */
337     *pdwInBufLen = 0;
338     return IP_DONE;
339 }
340
341
342
343 /*****************************************************************************\
344  *
345  * tifEncode_getActualTraits - Parses header, and returns input & output traits
346  *
347 \*****************************************************************************/
348
349 static WORD tifEncode_getActualTraits (
350     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
351     DWORD            dwInputAvail,   /* in:  # avail bytes in input buf */
352     PBYTE            pbInputBuf,     /* in:  ptr to input buffer */
353     PDWORD           pdwInputUsed,   /* out: # bytes used from input buf */
354     PDWORD           pdwInputNextPos,/* out: file-pos to read from next */
355     PIP_IMAGE_TRAITS pInTraits,      /* out: input image traits */
356     PIP_IMAGE_TRAITS pOutTraits)     /* out: output image traits */
357 {
358     PTIF_INST g;
359
360     HANDLE_TO_PTR (hXform, g);
361
362     /* Since there is no header, we'll report no usage of input */
363     *pdwInputUsed    = 0;
364     *pdwInputNextPos = 0;
365
366     /* Since we don't change traits, just copy out the default traits */
367     *pInTraits  = g->traits;
368     *pOutTraits = g->traits;
369     return IP_DONE | IP_READY_FOR_DATA;
370
371     fatal_error:
372     return IP_FATAL_ERROR;
373 }
374
375
376
377 /****************************************************************************\
378  *
379  * tifEncode_getActualBufSizes - Returns buf sizes needed for remainder of job
380  *
381 \****************************************************************************/
382
383 static WORD tifEncode_getActualBufSizes (
384     IP_XFORM_HANDLE  hXform,          /* in:  handle for xform */
385     PDWORD           pdwMinInBufLen,  /* out: min input buf size */
386     PDWORD           pdwMinOutBufLen) /* out: min output buf size */
387 {
388     PTIF_INST g;
389     UINT      len;
390
391     HANDLE_TO_PTR (hXform, g);
392     len = g->dwRawRowBytes;
393     *pdwMinInBufLen = len;
394
395     if (len < MAX_HEADER_SIZE)
396         len = MAX_HEADER_SIZE;
397     *pdwMinOutBufLen = len;
398
399     return IP_DONE;
400
401     fatal_error:
402     return IP_FATAL_ERROR;
403 }
404
405
406
407 /****************************************************************************\
408  *
409  * outputHeader - Only called by tifEncode_convert
410  *
411 \****************************************************************************/
412
413
414
415 static void SetTag (TIFFTAG *pTag, 
416              unsigned short TagID, short Kind, long Length, int Value)
417 {
418     pTag->TagID   = (TIFF_USHORT)TagID;
419     pTag->Kind    = (TIFF_USHORT)Kind;
420     pTag->Length  = (TIFF_ULONG)Length;
421     pTag->Value.l = (TIFF_ULONG)Value;   /* assumes little-endian computer */
422 }
423
424
425
426 static int WriteFileHeader (PBYTE pTIFF)
427 {
428     TIFFHEADER *pHead;
429
430     pHead = (TIFFHEADER*) pTIFF;
431     pHead->ByteOrder[0] = 'I';
432     pHead->ByteOrder[1] = 'I';    /* assumes little-endian computer */
433     pHead->Version = 42;
434     pHead->OffsetFirstIFD = 8;
435
436     return 8;   /* we output 8 bytes */
437 }
438
439
440
441 static int WriteIFD (
442     PBYTE pTIFF,         /* out: the IFD is written to this buffer */
443     int   iStartOffset,  /* in:  file-offset at which this IFD starts */
444     int   WidthBytes,    /* in:  row-width in bytes */
445     int   WidthPixels,   /* in:  row-width in pixels */
446     int   Height,        /* in:  number of rows */
447     int   BPP,           /* in:  bits per pixel */
448     int   XRes,          /* in:  dpi in X */
449     int   YRes)          /* in:  dpi in Y */
450 {
451     TIFFIFD     *pIFD;
452     TIFFTAG     *pTag;
453     BYTE        *pMore;
454     TIFF_USHORT *pBPS;
455     int          iBPSOffset, iImageOffset;
456     int          SPP, BPS, PI;
457
458     pIFD = (TIFFIFD*)pTIFF;
459     pMore = pTIFF + sizeof(TIFFIFD);   /* 1st byte after the IFD */
460
461     /* allocate space for the 3 shorts for the 3 bps values (if needed) */
462     iBPSOffset = iStartOffset + (pMore-pTIFF);
463     pBPS = (TIFF_USHORT*)pMore;
464     pMore += 3*sizeof(TIFF_USHORT);
465
466     /* the pixels are put after the above items */
467     iImageOffset = iStartOffset + (pMore-pTIFF);
468
469     switch (BPP) {
470         case 1:
471             PI = ZERO_IS_WHITE; SPP = 1; BPS = 1;  break;  /* 1-bit bilevel */
472         case 8:
473             PI = ZERO_IS_BLACK; SPP = 1; BPS = 8;  break;  /* 8-bit grayscale */
474         case 16:
475             PI = ZERO_IS_BLACK; SPP = 1; BPS = 16; break;  /* 16-bit grayscale */
476         case 24:
477             PI = RGB_COLOR;     SPP = 3; BPS = 8;  break;  /* 24-bit color */
478         case 48:
479             PI = RGB_COLOR;     SPP = 3; BPS = 16; break;  /* 48-bit color */
480         default:
481             PI = RGB_COLOR;     SPP = 3; BPS = 8;   /* guess 24-bit color */
482             assert (0);  /* crash if in debug mode */
483     }
484
485     pIFD->NumTags = NUMTAGS;
486     pTag = pIFD->Tag;
487     SetTag (pTag++, NEW_SUBFILE,       TIFFSHORT, 1,   0);
488     SetTag (pTag++, IMAGE_WIDTH,       TIFFLONG,  1,   WidthPixels);
489     SetTag (pTag++, IMAGE_LENGTH,      TIFFLONG,  1,   Height);
490     SetTag (pTag++, BITS_PER_SAMPLE,   TIFFSHORT, SPP, SPP>1 ? iBPSOffset : BPS);
491     SetTag (pTag++, COMPRESSION,       TIFFSHORT, 1,   1);
492     SetTag (pTag++, PHOTO_INTERPRET,   TIFFSHORT, 1,   PI);
493     SetTag (pTag++, STRIP_OFFSETS,     TIFFLONG,  1,   iImageOffset);
494     SetTag (pTag++, SAMPLES_PER_PIXEL, TIFFSHORT, 1,   SPP);
495     SetTag (pTag++, ROWS_PER_STRIP,    TIFFLONG,  1,   Height);
496     SetTag (pTag++, STRIP_COUNTS,      TIFFLONG,  1,   WidthBytes*Height);
497     SetTag (pTag++, XRESOLUTION,       TIFFSHORT, 1,   XRes);
498     SetTag (pTag++, YRESOLUTION,       TIFFSHORT, 1,   YRes);
499     SetTag (pTag++, RESOLUTION_UNIT,   TIFFSHORT, 1,   2);
500     assert ((pTag - pIFD->Tag) == NUMTAGS);
501     pIFD->OffsetNextIFD = 0L;    /* assume there is no next IFD */
502
503     /* Stick Samples Per Pixel here for color; Only used if pointed to by tag */
504     *pBPS++ = BPS;
505     *pBPS++ = BPS;
506     *pBPS++ = BPS;
507
508     return pMore - pTIFF;
509 }
510
511
512
513 static WORD AppendIFDToFile (
514     PTIF_INST g,              /* in:  ptr to instance structure */
515     PBYTE     pbTempBuf)      /* in:  temp buffer large enough to hold an IFD */
516 {
517     int         result;
518     TIFF_ULONG  fileEndPos, IFDPos, pointerPos;
519     TIFF_USHORT numTags;
520     int         iHeaderLen, iIFDLen, iTotalLen;
521
522     /***** If the file is empty, do usual set-up *****/
523
524     g->fileOut = fopen (g->sFilePath, "a+b");
525     INSURE (g->fileOut != NULL);
526     result = fseek (g->fileOut, 0, SEEK_END);
527     INSURE (result == 0);
528     fileEndPos = ftell (g->fileOut);
529     INSURE (result >= 0);
530
531     if (fileEndPos == 0) {
532         iHeaderLen = WriteFileHeader(pbTempBuf);
533         iIFDLen = WriteIFD (pbTempBuf+iHeaderLen, iHeaderLen,
534             g->dwRawRowBytes, g->traits.iPixelsPerRow,
535             g->traits.lNumRows, g->traits.iBitsPerPixel,
536             g->traits.lHorizDPI>>16, g->traits.lVertDPI>>16);
537
538         iTotalLen = iHeaderLen + iIFDLen;
539         INSURE (iTotalLen <= MAX_HEADER_SIZE);
540
541         result = fwrite (pbTempBuf, 1, iTotalLen, g->fileOut);
542         INSURE (result == iTotalLen);
543
544         return IP_READY_FOR_DATA;
545     }
546
547     /***** Find the last IFD *****/
548
549     result = fseek (g->fileOut, 4, SEEK_SET);
550     INSURE (result == 0);
551     result = fread (&IFDPos, 4, 1, g->fileOut);  /* assumes little-endian file */
552     INSURE (result == 1);
553
554     do {    /* hop thru the IFDs until we hit the last one */
555         result = fseek (g->fileOut, IFDPos, SEEK_SET);
556         INSURE (result == 0);
557         result = fread (&numTags, 2, 1, g->fileOut);  /* assumes little-endian file */
558         INSURE (result==1 && numTags>0);
559         pointerPos = IFDPos + 2 + numTags*sizeof(TIFFTAG);
560         result = fseek (g->fileOut, pointerPos, SEEK_SET);
561         INSURE (result == 0);
562         result = fread (&IFDPos, 4, 1, g->fileOut);  /* assumes little-endian file */
563         INSURE (result == 1);
564     } while (IFDPos != 0);
565
566     /***** PointerPos is the final IFD offset in the file; change it *****/
567
568     /* switch to writing from now on */
569     fclose (g->fileOut);
570     g->fileOut = fopen(g->sFilePath, "r+b");
571     INSURE (g->fileOut != NULL);
572
573     result = fseek (g->fileOut, pointerPos, SEEK_SET);
574     INSURE (result == 0);
575     result = fwrite (&fileEndPos, 4, 1, g->fileOut);  /* assumes little-endian file */
576     INSURE (result == 1);
577
578     /***** Output a new IFD for the new page *****/
579
580     iIFDLen = WriteIFD (pbTempBuf, fileEndPos,
581         g->dwRawRowBytes, g->traits.iPixelsPerRow,
582         g->traits.lNumRows, g->traits.iBitsPerPixel,
583         g->traits.lHorizDPI>>16, g->traits.lVertDPI>>16);
584
585     result = fseek (g->fileOut, 0, SEEK_END);
586     INSURE (result == 0);
587     result = fwrite (pbTempBuf, 1, iIFDLen, g->fileOut);
588     INSURE (result == iIFDLen);
589     /* leave the file-position at the end, where image-data will go */
590
591     return IP_READY_FOR_DATA;
592
593     fatal_error:
594     return IP_FATAL_ERROR;
595 }
596
597
598
599 static WORD outputHeader (
600     PTIF_INST g,                /* in:  ptr to instance structure */
601     DWORD     dwOutputAvail,    /* in:  # avail bytes in out-buf */
602     PBYTE     pbOutputBuf,      /* in:  ptr to out-buffer */
603     PDWORD    pdwOutputUsed,    /* out: # bytes written in out-buf */
604     PDWORD    pdwOutputThisPos) /* out: file-pos to write the data */
605 {
606     int iHeaderLen, iIFDLen, iTotalLen;
607
608     INSURE (dwOutputAvail >= MAX_HEADER_SIZE);
609     *pdwOutputThisPos = 0;
610
611     if (g->sFilePath[0] != 0) {
612         *pdwOutputUsed = 0;
613         return AppendIFDToFile (g, pbOutputBuf);
614     }
615
616     iHeaderLen = WriteFileHeader(pbOutputBuf);
617     iIFDLen = WriteIFD (pbOutputBuf+iHeaderLen, iHeaderLen,
618         g->dwRawRowBytes, g->traits.iPixelsPerRow,
619         g->traits.lNumRows, g->traits.iBitsPerPixel,
620         g->traits.lHorizDPI>>16, g->traits.lVertDPI>>16);
621
622     iTotalLen = iHeaderLen + iIFDLen;
623     INSURE (iTotalLen <= MAX_HEADER_SIZE);
624     *pdwOutputUsed    = iTotalLen;
625     *pdwOutputThisPos = 0;
626     g->dwOutNextPos   = iTotalLen;
627
628     return IP_READY_FOR_DATA;
629
630     fatal_error:
631     return IP_FATAL_ERROR;
632 }
633
634
635
636 /*****************************************************************************\
637  *
638  * tifEncode_convert - the work-horse routine
639  *
640 \*****************************************************************************/
641
642 static WORD tifEncode_convert (
643     IP_XFORM_HANDLE hXform,
644     DWORD           dwInputAvail,     /* in:  # avail bytes in in-buf */
645     PBYTE           pbInputBuf,       /* in:  ptr to in-buffer */
646     PDWORD          pdwInputUsed,     /* out: # bytes used from in-buf */
647     PDWORD          pdwInputNextPos,  /* out: file-pos to read from next */
648     DWORD           dwOutputAvail,    /* in:  # avail bytes in out-buf */
649     PBYTE           pbOutputBuf,      /* in:  ptr to out-buffer */
650     PDWORD          pdwOutputUsed,    /* out: # bytes written in out-buf */
651     PDWORD          pdwOutputThisPos) /* out: file-pos to write the data */
652 {
653     PTIF_INST g;
654     UINT      n;
655
656     HANDLE_TO_PTR (hXform, g);
657
658     /**** Output the Header if we haven't already ****/
659
660     if (! g->fDidHeader) {
661         g->fDidHeader = TRUE;
662         *pdwInputUsed    = 0;
663         *pdwInputNextPos = 0;
664         return outputHeader (g, dwOutputAvail, pbOutputBuf,
665                              pdwOutputUsed, pdwOutputThisPos);
666     }
667
668     /**** Check if we were told to flush ****/
669
670     if (pbInputBuf == NULL) {
671         PRINT (_T("tif_encode_convert_row: Told to flush.\n"), 0, 0);
672         if (g->traits.lNumRows < 0) {
673             /* # rows wasn't known at first, so output header again
674              * now that we know the number of rows */
675             INSURE (g->sFilePath[0] == 0);
676             g->traits.lNumRows = g->dwRowsDone;
677             *pdwInputUsed = 0;
678             *pdwInputNextPos = g->dwInNextPos;
679             return outputHeader (g, dwOutputAvail, pbOutputBuf,
680                                  pdwOutputUsed, pdwOutputThisPos);
681         }
682
683         *pdwInputUsed = *pdwOutputUsed = 0;
684         *pdwInputNextPos  = g->dwInNextPos;
685         *pdwOutputThisPos = g->dwOutNextPos;
686         return IP_DONE;
687     }
688
689     /**** Output a Row ****/
690
691     n = g->dwRawRowBytes;
692     INSURE (dwInputAvail  >= n);
693     INSURE (dwOutputAvail >= n);
694
695     if (g->sFilePath[0] == 0) {
696         memcpy (pbOutputBuf, pbInputBuf, n);
697
698         *pdwOutputUsed    = n;
699         *pdwOutputThisPos = g->dwOutNextPos;
700         g->dwOutNextPos  += n;
701     } else {
702         UINT result;
703         INSURE (g->fileOut != NULL);
704         result = fwrite (pbInputBuf, 1, n, g->fileOut);
705         INSURE (result == n);
706         
707         *pdwOutputUsed    = 0;
708         *pdwOutputThisPos = 0;
709         g->dwOutNextPos   = 0;
710     }
711
712     g->dwInNextPos   += n;
713     *pdwInputNextPos  = g->dwInNextPos;
714     *pdwInputUsed     = n;
715     g->dwRowsDone += 1;
716
717     return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
718
719     fatal_error:
720     return IP_FATAL_ERROR;
721 }
722
723
724
725 /*****************************************************************************\
726  *
727  * tifEncode_insertedData - client inserted into our output stream
728  *
729 \*****************************************************************************/
730
731 static WORD tifEncode_insertedData (
732     IP_XFORM_HANDLE hXform,
733     DWORD           dwNumBytes)
734 {
735     fatalBreakPoint ();
736     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
737 }
738
739
740
741 /*****************************************************************************\
742  *
743  * tifEncode_newPage - Tells us to flush this page, and start a new page
744  *
745 \*****************************************************************************/
746
747 static WORD tifEncode_newPage (
748     IP_XFORM_HANDLE hXform)
749 {
750     PTIF_INST g;
751
752     HANDLE_TO_PTR (hXform, g);
753     /* todo: return fatal error if convert is called again? */
754     return IP_DONE;   /* can't insert page-breaks, so ignore this call */
755
756     fatal_error:
757     return IP_FATAL_ERROR;
758
759 }
760
761
762
763 /*****************************************************************************\
764  *
765  * tifEncode_closeXform - Destroys this instance
766  *
767 \*****************************************************************************/
768
769 static WORD tifEncode_closeXform (IP_XFORM_HANDLE hXform)
770 {
771     PTIF_INST g;
772
773     HANDLE_TO_PTR (hXform, g);
774     if (g->fileOut != NULL)
775         fclose (g->fileOut);
776     g->dwValidChk = 0;
777     IP_MEM_FREE (g);       /* free memory for the instance */
778     return IP_DONE;
779
780     fatal_error:
781     return IP_FATAL_ERROR;
782 }
783
784
785
786 /*****************************************************************************\
787  *
788  * tifEncodeTbl - Jump-table for encoder
789  *
790 \*****************************************************************************/
791
792 IP_XFORM_TBL tifEncodeTbl = {
793     tifEncode_openXform,
794     tifEncode_setDefaultInputTraits,
795     tifEncode_setXformSpec,
796     tifEncode_getHeaderBufSize,
797     tifEncode_getActualTraits,
798     tifEncode_getActualBufSizes,
799     tifEncode_convert,
800     tifEncode_newPage,
801     tifEncode_insertedData,
802     tifEncode_closeXform
803 };
804
805
806
807
808 /*****************************************************************************\
809  *****************************************************************************
810  *
811  *                             D  E  C  O  D  E  R
812  *
813  *****************************************************************************
814 \*****************************************************************************/
815
816
817
818
819 /*****************************************************************************\
820  *
821  * tifDecode_openXform - Creates a new instance of the transformer
822  *
823  *****************************************************************************
824  *
825  * This returns a handle for the new instance to be passed into
826  * all subsequent calls.
827  *
828  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
829  *
830 \*****************************************************************************/
831
832 static WORD tifDecode_openXform (
833     IP_XFORM_HANDLE *pXform)   /* out: returned handle */
834 {
835     PTIF_INST g;
836
837     INSURE (pXform != NULL);
838     IP_MEM_ALLOC (sizeof(TIF_INST), g);
839     *pXform = g;
840     memset (g, 0, sizeof(TIF_INST));
841     g->dwValidChk = CHECK_VALUE;
842     return IP_DONE;
843
844     fatal_error:
845     return IP_FATAL_ERROR;
846 }
847
848
849
850 /*****************************************************************************\
851  *
852  * tifDecode_setDefaultInputTraits - Specifies default input image traits
853  *
854  *****************************************************************************
855  *
856  * The header of the file-type handled by the transform probably does
857  * not include *all* the image traits we'd like to know.  Those not
858  * specified in the file-header are filled in from info provided by
859  * this routine.
860  *
861  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
862  *
863 \*****************************************************************************/
864
865 static WORD tifDecode_setDefaultInputTraits (
866     IP_XFORM_HANDLE  hXform,     /* in: handle for xform */
867     PIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
868 {
869     PTIF_INST g;
870
871     HANDLE_TO_PTR (hXform, g);
872     g->traits = *pTraits;   /* a structure copy */
873     return IP_DONE;
874
875     fatal_error:
876     return IP_FATAL_ERROR;
877 }
878
879
880
881 /*****************************************************************************\
882  *
883  * tifDecode_setXformSpec - Provides xform-specific information
884  *
885 \*****************************************************************************/
886
887 static WORD tifDecode_setXformSpec (
888     IP_XFORM_HANDLE  hXform,         /* in: handle for xform */
889     DWORD_OR_PVOID   aXformInfo[])   /* in: xform information */
890 {
891     PTIF_INST g;
892     char      *s;
893
894     HANDLE_TO_PTR (hXform, g);
895     /* file-path is not used, but might be later, so save it */
896     s = (char*)aXformInfo[IP_TIFF_FILE_PATH].pvoid;
897     if (s != NULL)
898         strcpy (g->sFilePath, s);
899     return IP_DONE;
900
901     fatal_error:
902     return IP_FATAL_ERROR;
903 }
904
905
906
907 /*****************************************************************************\
908  *
909  * tifDecode_getHeaderBufSize - Returns size of input buf needed to hold header
910  *
911 \*****************************************************************************/
912
913 static WORD tifDecode_getHeaderBufSize (
914     IP_XFORM_HANDLE   hXform,         /* in:  handle for xform */
915     DWORD            *pdwInBufLen)    /* out: buf size for parsing header */
916 {
917     *pdwInBufLen = MAX_HEADER_SIZE + 10000;   /* 10000 gives us huge margin */
918     return IP_DONE;
919 }
920
921
922
923 /*****************************************************************************\
924  *
925  * ByteSwap - Reverses endian-type of the given variable (1, 2, 4 or 8 bytes)
926  *
927 \*****************************************************************************/
928
929 static void ByteSwap (
930     void *pvVar,
931     int   nBytes)
932 {
933     BYTE b;
934     BYTE *pb = (BYTE*)pvVar;
935
936     switch (nBytes) {
937         case 1:
938             /* do nothing */
939             break;
940         case 2:
941             b = pb[0];  pb[0] = pb[1];  pb[1] = b;
942             break;
943         case 4:
944             b = pb[1];  pb[1] = pb[2];  pb[2] = b;
945             b = pb[0];  pb[0] = pb[3];  pb[3] = b;
946             break;
947         case 8:
948             /* this is actually two longs, so fix each one */
949             ByteSwap (pvVar, 4);
950             ByteSwap ((BYTE*)pvVar+4, 4);
951             break;
952     }
953 }
954
955
956
957 /*****************************************************************************\
958  *
959  * ParseTag - Parses a tag, putting value in traits or dwImageOffset
960  *
961 \*****************************************************************************/
962
963 static BOOL ParseTag (
964     PTIF_INST  g,              /* in:  our instance variables */
965     TIFFTAG   *pTag,           /* in:  the tag to parse */
966     BYTE      *pbInputBuf,     /* in:  input buffer containing TIFF header */
967     BYTE      *pbBufAfter,     /* in:  1st byte after the input buffer */
968     DWORD     *pdwImageOffset) /* out: image start offset set by STRIP_OFFSETS */
969 {
970     unsigned  id;
971     unsigned  kind;
972     unsigned  count;
973     void     *pValue;
974     int       value;
975     int       nTypeBytes, nValueBytes;
976     int       i;
977
978     if (g->bByteSwap) {
979         ByteSwap (&(pTag->TagID ), 2);
980         ByteSwap (&(pTag->Kind  ), 2);
981         ByteSwap (&(pTag->Length), 4);
982     }
983
984     id    = pTag->TagID;
985     kind  = pTag->Kind;
986     count = pTag->Length;
987
988     switch (kind) {
989         case TIFFUNDEFINED: nTypeBytes = 1; break;
990         case TIFFBYTE:      nTypeBytes = 1; break;
991         case TIFFSBYTE:     nTypeBytes = 1; break;
992         case TIFFSHORT:     nTypeBytes = 2; break;
993         case TIFFSSHORT:    nTypeBytes = 2; break;
994         case TIFFLONG:      nTypeBytes = 4; break;
995         case TIFFSLONG:     nTypeBytes = 4; break;
996         case TIFFRATIONAL:  nTypeBytes = 8; break;
997         case TIFFSRATIONAL: nTypeBytes = 8; break;
998         default: INSURE(0);
999     }
1000
1001     nValueBytes = count * nTypeBytes;
1002
1003     if (nValueBytes <= 4)
1004         pValue = &(pTag->Value.l);
1005     else {
1006         if (g->bByteSwap)
1007             ByteSwap (&(pTag->Value.l), 4);
1008         pValue = pbInputBuf + pTag->Value.l;
1009     }
1010     INSURE ((BYTE*)pValue>pbInputBuf && (BYTE*)pValue<pbBufAfter);
1011
1012     if (g->bByteSwap) {
1013         for (i=0; i<(int)count; i++)
1014             ByteSwap ((BYTE*)pValue + i*nTypeBytes, nTypeBytes);
1015     }
1016
1017     switch (kind) {
1018         case TIFFUNDEFINED: value = *(TIFF_UBYTE *)pValue;  break;
1019         case TIFFBYTE:      value = *(TIFF_UBYTE *)pValue;  break;
1020         case TIFFSBYTE:     value = *(TIFF_SBYTE *)pValue;  break;
1021         case TIFFSHORT:     value = *(TIFF_USHORT*)pValue;  break;
1022         case TIFFSSHORT:    value = *(TIFF_SSHORT*)pValue;  break;
1023         case TIFFLONG:      value = *(TIFF_ULONG *)pValue;  break;
1024         case TIFFSLONG:     value = *(TIFF_SLONG *)pValue;  break;
1025         case TIFFRATIONAL:  value = ((RATIONAL*)pValue)->n / ((RATIONAL*)pValue)->d;  break;
1026         case TIFFSRATIONAL: value = ((RATIONAL*)pValue)->n / ((RATIONAL*)pValue)->d;  break;
1027         default: INSURE(0);
1028     }
1029
1030     switch (id) {
1031         case NEW_SUBFILE:
1032             /* do nothing */
1033             break;
1034         case IMAGE_WIDTH:
1035             g->traits.iPixelsPerRow = value;
1036             break;
1037         case IMAGE_LENGTH:
1038             g->traits.lNumRows = value;
1039             break;
1040         case BITS_PER_SAMPLE:
1041             g->iBitsPerSample = value;
1042             break;
1043         case COMPRESSION:
1044             INSURE (value == 1);  /* we only support uncompressed */
1045             break;
1046         case PHOTO_INTERPRET:
1047             /* do nothing */
1048             break;
1049         case STRIP_OFFSETS:
1050             INSURE (count == 1);  /* we only support one strip */
1051             *pdwImageOffset = value;
1052             break;
1053         case SAMPLES_PER_PIXEL:
1054             g->traits.iComponentsPerPixel = value;
1055             break;
1056         case ROWS_PER_STRIP:
1057             /* do nothing -- we assume entire image is in one strip */
1058             break;
1059         case STRIP_COUNTS:
1060             /* do nothing -- this should be the # bytes in the raw data */
1061             break;
1062         case XRESOLUTION:
1063             g->traits.lHorizDPI = value << 16;
1064             break;
1065         case YRESOLUTION:
1066             g->traits.lVertDPI = value << 16;
1067             break;
1068         case RESOLUTION_UNIT:
1069             /* do nothing -- if it's not DPI, then reported DPI will be wrong */
1070             break;
1071         default:
1072             /* ignore the unknown tag */
1073             break;
1074     }
1075
1076     return TRUE;
1077
1078     fatal_error:
1079     return FALSE;
1080 }
1081
1082
1083
1084 /*****************************************************************************\
1085  *
1086  * tifDecode_getActualTraits - Parses header, and returns input & output traits
1087  *
1088 \*****************************************************************************/
1089
1090 static WORD tifDecode_getActualTraits (
1091     IP_XFORM_HANDLE  hXform,         /* in:  handle for xform */
1092     DWORD            dwInputAvail,   /* in:  # avail bytes in input buf */
1093     PBYTE            pbInputBuf,     /* in:  ptr to input buffer */
1094     PDWORD           pdwInputUsed,   /* out: # bytes used from input buf */
1095     PDWORD           pdwInputNextPos,/* out: file-pos to read from next */
1096     PIP_IMAGE_TRAITS pInTraits,      /* out: input image traits */
1097     PIP_IMAGE_TRAITS pOutTraits)     /* out: output image traits */
1098 {
1099     PTIF_INST   g;
1100     DWORD       dwImageOffset;
1101     PBYTE       pb;
1102     TIFFHEADER *pHead;
1103     TIFFIFD    *pIFD;
1104     int         iTag, nTags;
1105
1106     HANDLE_TO_PTR (hXform, g);
1107     pb = pbInputBuf;
1108
1109     /**** Parse the file-header ****/
1110
1111     pHead = (TIFFHEADER*)pb;
1112     INSURE (pHead->ByteOrder[0]=='I' || pHead->ByteOrder[0]=='M');
1113     INSURE (pHead->ByteOrder[1]=='I' || pHead->ByteOrder[1]=='M');
1114     g->bByteSwap = pHead->ByteOrder[0] == 'M';
1115     if (g->bByteSwap)
1116         ByteSwap (&(pHead->OffsetFirstIFD), 4);
1117     INSURE (pHead->OffsetFirstIFD < dwInputAvail);
1118     /* ignore the file-version */
1119     pb = pbInputBuf + pHead->OffsetFirstIFD;
1120
1121     /**** Parse the IFD (i.e., the tags), setting traits ****/
1122
1123     pIFD = (TIFFIFD*)pb;
1124     if (g->bByteSwap)
1125         ByteSwap (&(pIFD->NumTags), 2);
1126     nTags = pIFD->NumTags;
1127     INSURE (nTags>0 && nTags<100);   /* sanity check */
1128     INSURE (nTags*sizeof(TIFFTAG) < dwInputAvail);
1129     dwImageOffset = 0;
1130
1131     for (iTag=0; iTag<nTags; iTag++) {
1132         if (! ParseTag (g, pIFD->Tag+iTag, pbInputBuf, pbInputBuf+dwInputAvail, &dwImageOffset))
1133             goto fatal_error;
1134     }
1135
1136     INSURE (g->iBitsPerSample==1 || g->iBitsPerSample==8 || g->iBitsPerSample==16);
1137     g->traits.iBitsPerPixel = g->iBitsPerSample * g->traits.iComponentsPerPixel;
1138     INSURE (dwImageOffset <= dwInputAvail);
1139     g->dwRawRowBytes = (g->traits.iBitsPerPixel*g->traits.iPixelsPerRow + 7) / 8;
1140
1141     /**** Finish up ****/
1142
1143     g->dwInNextPos   = dwImageOffset;
1144     *pdwInputUsed    = dwImageOffset;
1145     *pdwInputNextPos = dwImageOffset;
1146
1147     *pInTraits  = g->traits;
1148     *pOutTraits = g->traits;
1149     return IP_DONE | IP_READY_FOR_DATA;
1150
1151     fatal_error:
1152     return IP_FATAL_ERROR;
1153 }
1154
1155
1156
1157 /****************************************************************************\
1158  *
1159  * tifDecode_getActualBufSizes - Returns buf sizes needed for remainder of job
1160  *
1161 \****************************************************************************/
1162
1163 static WORD tifDecode_getActualBufSizes (
1164     IP_XFORM_HANDLE  hXform,          /* in:  handle for xform */
1165     PDWORD           pdwMinInBufLen,  /* out: min input buf size */
1166     PDWORD           pdwMinOutBufLen) /* out: min output buf size */
1167 {
1168     PTIF_INST g;
1169
1170     HANDLE_TO_PTR (hXform, g);
1171     *pdwMinInBufLen  = g->dwRawRowBytes;
1172     *pdwMinOutBufLen = g->dwRawRowBytes;
1173     return IP_DONE;
1174
1175     fatal_error:
1176     return IP_FATAL_ERROR;
1177 }
1178
1179
1180
1181 /*****************************************************************************\
1182  *
1183  * tifDecode_convert - the work-horse routine
1184  *
1185 \*****************************************************************************/
1186
1187 static WORD tifDecode_convert (
1188     IP_XFORM_HANDLE hXform,
1189     DWORD           dwInputAvail,     /* in:  # avail bytes in in-buf */
1190     PBYTE           pbInputBuf,       /* in:  ptr to in-buffer */
1191     PDWORD          pdwInputUsed,     /* out: # bytes used from in-buf */
1192     PDWORD          pdwInputNextPos,  /* out: file-pos to read from next */
1193     DWORD           dwOutputAvail,    /* in:  # avail bytes in out-buf */
1194     PBYTE           pbOutputBuf,      /* in:  ptr to out-buffer */
1195     PDWORD          pdwOutputUsed,    /* out: # bytes written in out-buf */
1196     PDWORD          pdwOutputThisPos) /* out: file-pos to write the data */
1197 {
1198     PTIF_INST g;
1199     UINT      n;
1200
1201     HANDLE_TO_PTR (hXform, g);
1202
1203     /**** Check if we were told to flush ****/
1204
1205     if (pbInputBuf == NULL) {
1206         PRINT (_T("tif_decode_convert_row: Told to flush.\n"), 0, 0);
1207         *pdwInputUsed = *pdwOutputUsed = 0;
1208         *pdwInputNextPos  = g->dwInNextPos;
1209         *pdwOutputThisPos = g->dwOutNextPos;
1210         return IP_DONE;
1211     }
1212
1213     /**** Output a Row ****/
1214
1215     n = g->dwRawRowBytes;
1216
1217     if (dwInputAvail < n) {
1218         /* we got a partial row at the end -- just toss it */
1219         g->dwInNextPos   += dwInputAvail;
1220         *pdwInputNextPos  = g->dwInNextPos;
1221         *pdwInputUsed     = dwInputAvail;
1222         *pdwOutputUsed    = 0;
1223         *pdwOutputThisPos = g->dwOutNextPos;
1224         return IP_READY_FOR_DATA;
1225     }
1226
1227     INSURE (dwOutputAvail >= n);
1228     memcpy (pbOutputBuf, pbInputBuf, n);
1229
1230     if (g->bByteSwap && g->iBitsPerSample==16) {
1231         /* we need to swap bytes in the 16-bit words in the pixels */
1232         BYTE *pb, *pbAfter, b;
1233         pbAfter = pbInputBuf + n;
1234         for (pb=pbInputBuf; pb<pbAfter; pb+=4) {
1235             /* process two words at a time for speed */
1236             b = pb[0];  pb[0] = pb[1];  pb[1] = b;
1237             b = pb[2];  pb[2] = pb[3];  pb[3] = b;
1238         }
1239     }
1240
1241     *pdwOutputUsed    = n;
1242     *pdwOutputThisPos = g->dwOutNextPos;
1243     g->dwOutNextPos  += n;
1244
1245     g->dwInNextPos   += n;
1246     *pdwInputNextPos  = g->dwInNextPos;
1247     *pdwInputUsed     = n;
1248     g->dwRowsDone += 1;
1249
1250     return IP_CONSUMED_ROW | IP_PRODUCED_ROW | IP_READY_FOR_DATA;
1251
1252     fatal_error:
1253     return IP_FATAL_ERROR;
1254 }
1255
1256
1257
1258 /*****************************************************************************\
1259  *
1260  * tifDecode_insertedData - client inserted into our output stream
1261  *
1262 \*****************************************************************************/
1263
1264 static WORD tifDecode_insertedData (
1265     IP_XFORM_HANDLE hXform,
1266     DWORD           dwNumBytes)
1267 {
1268     fatalBreakPoint ();
1269     return IP_FATAL_ERROR;   /* must never be called (can't insert data) */
1270 }
1271
1272
1273
1274 /*****************************************************************************\
1275  *
1276  * tifDecode_newPage - Tells us to flush this page, and start a new page
1277  *
1278 \*****************************************************************************/
1279
1280 static WORD tifDecode_newPage (
1281     IP_XFORM_HANDLE hXform)
1282 {
1283     PTIF_INST g;
1284
1285     HANDLE_TO_PTR (hXform, g);
1286     /* todo: return fatal error if convert is called again? */
1287     return IP_DONE;   /* can't insert page-breaks, so ignore this call */
1288
1289     fatal_error:
1290     return IP_FATAL_ERROR;
1291
1292 }
1293
1294
1295
1296 /*****************************************************************************\
1297  *
1298  * tifDecode_closeXform - Destroys this instance
1299  *
1300 \*****************************************************************************/
1301
1302 static WORD tifDecode_closeXform (IP_XFORM_HANDLE hXform)
1303 {
1304     PTIF_INST g;
1305
1306     HANDLE_TO_PTR (hXform, g);
1307     if (g->fileOut != NULL)
1308         fclose (g->fileOut);
1309     g->dwValidChk = 0;
1310     IP_MEM_FREE (g);       /* free memory for the instance */
1311     return IP_DONE;
1312
1313     fatal_error:
1314     return IP_FATAL_ERROR;
1315 }
1316
1317
1318
1319 /*****************************************************************************\
1320  *
1321  * tifDecodeTbl - Jump-table for decoder
1322  *
1323 \*****************************************************************************/
1324
1325 IP_XFORM_TBL tifDecodeTbl = {
1326     tifDecode_openXform,
1327     tifDecode_setDefaultInputTraits,
1328     tifDecode_setXformSpec,
1329     tifDecode_getHeaderBufSize,
1330     tifDecode_getActualTraits,
1331     tifDecode_getActualBufSizes,
1332     tifDecode_convert,
1333     tifDecode_newPage,
1334     tifDecode_insertedData,
1335     tifDecode_closeXform
1336 };
1337
1338 /* End of File */