Tizen 2.1 base
[platform/upstream/hplip.git] / ip / ipmain.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  * ipmain.c - main control code and entry points for image processor
40  *
41  *****************************************************************************
42  *
43  * Mark Overton, Dec 1997
44  *
45 \*****************************************************************************/
46
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50 #include <string.h>    /* for memcpy, memset, etc. */
51 #include <unistd.h>
52 #include "hpip.h"
53 #include "ipdefs.h"
54
55 //#define HPIP_DEBUG
56
57 #ifdef HPIP_DEBUG
58     #include <stdio.h>
59     #include <assert.h>
60
61     #define _T(msg) msg
62
63     #define PRINT0(args...) fprintf(stderr, args) 
64
65     #if 0
66         #define PRINT1(args...) fprintf(stderr, args)
67     #else
68         #define PRINT1(args...)
69     #endif
70
71     #undef INSURE
72     #define INSURE(boolexp) \
73         do { if (0) goto fatal_error; assert(boolexp); } while(0)
74
75     int infd;
76     int outfd;
77
78 #else
79     #define PRINT0(args...)
80     #define PRINT1(args...)
81 #endif
82
83
84
85 /*****************************************************************************\
86  *
87  * Constants
88  *
89 \*****************************************************************************/
90
91
92 #define CHECK_VALUE    0xACEC0DE4U /* for checking validity of instance struc */
93 #define MIN_GENBUF_LEN 4000        /* arbitrary, but higher boosts speed some */
94 #define PERMANENT_RESULTS \
95            (IP_INPUT_ERROR | IP_FATAL_ERROR | IP_DONE)
96
97
98
99 /*****************************************************************************\
100  *
101  * Types
102  *
103 \*****************************************************************************/
104
105
106 /* XFORM_STATE enum - all possible states of an xform */
107
108 typedef enum {
109     XS_NONEXISTENT=0,  /* xform is not yet instantiated */
110     XS_PARSING_HEADER, /* parsing header (always goes thru this state) */
111     XS_CONVERTING,     /* inputting and outputting */
112     XS_CONV_NOT_RFD,   /* only outputting; not ready for input */
113     XS_FLUSHING,       /* outputting buffered stuff; no more input */
114     XS_DONE            /* done and de-instantiated */
115 } XFORM_STATE;
116
117
118 /* XFORM_INFO type - everything we know about an xform */
119
120 typedef struct {
121     XFORM_STATE      eState;         /* state of this xform */
122     PIP_XFORM_TBL    pXform;         /* ptr to jmp-table for xform */
123     LPIP_PEEK_FUNC   pfReadPeek;     /* callback when xform dvr reads data */
124     LPIP_PEEK_FUNC   pfWritePeek;    /* callback when xform dvr writes data */
125     PVOID            pUserData;      /* Data passed to user in peek functions. */
126     DWORD_OR_PVOID   aXformInfo[8];  /* xform-specific information */
127     IP_XFORM_HANDLE  hXform;         /* handle for the xform */
128     IP_IMAGE_TRAITS  inTraits;       /* traits of input data into xform */
129     IP_IMAGE_TRAITS  outTraits;      /* traits of output data from xform */
130     DWORD            dwMinInBufLen;  /* min # bytes in input buf */
131     DWORD            dwMinOutBufLen; /* min # bytes in output buf */
132 } XFORM_INFO, *PXFORM_INFO;
133
134
135 /* GENBUF type - a general-purpose buffer which allows one to write or read
136  * varying amounts of data.
137  */
138 typedef struct {
139     PBYTE pbBuf;        /* ptr to beginning of buffer */
140     DWORD dwBufLen;     /* size of entire buffer (# of bytes) */
141     DWORD dwValidStart; /* index of first valid data byte in buffer */
142     DWORD dwValidLen;   /* number of valid data bytes in buffer */
143     DWORD dwFilePos;    /* file-pos of start of valid data (starts at 0) */
144 } GENBUF, *PGENBUF;
145
146
147 /* INST type - all variables in an instance of the image processor */
148
149 typedef struct {
150
151     /* genbufs are used for input into the first xform, and to store output
152      * from the last xform. The client's input data is first put into gbIn,
153      * which is then fed into the first xform. The last xform's output is put
154      * into gbOut, which is then copied out to the client's output buffer.
155      */
156     GENBUF gbIn;
157     GENBUF gbOut;
158
159     /* mid-buffers are simple buffers that handle fixed-length raster-rows
160      * passed between xforms in the xform-list. For an xform, there's an input
161      * and an output buffer. For the next xform, they swap roles, so the old
162      * output buffer becomes the new input buffer, and vice versa. When the
163      * roles are swapped, the two pointers below are swapped.
164      */
165     PBYTE pbMidInBuf;         /* ptr to beginning of input mid-buf */
166     PBYTE pbMidOutBuf;        /* ptr to beginning of output mid-buf */
167     DWORD dwMidLen;           /* size of either buffer (# of bytes) */
168     DWORD dwMidValidLen;      /* # of bytes of good data in input mid-buf */
169     int   iOwner;             /* index into xfArray of xform owning (using)
170                                * the input mid-buf. negative means no owner
171                                * and that pbMidInBuf is empty */
172
173     /* variables pertaining to the array of xforms */
174
175     XFORM_INFO xfArray[IP_MAX_XFORMS]; /* the array of xforms */
176     WORD    xfCount;                /* number of xforms */
177
178     /* misc variables */
179
180     DWORD   dwValidChk;       /* struct validity check value */
181     DWORD   dwForcedHorizDPI; /* horiz DPI override as 16.16; 0=none */
182     DWORD   dwForcedVertDPI;  /* vert  DPI override as 16.16; 0=none */
183     WORD    wResultMask;      /* desired ipConvert result bits */
184     long    lInRows;          /* number of rows we've input */
185     long    lOutRows;         /* number of rows we've output */
186     int     iInPages;         /* number of pages we've received */
187     int     iOutPages;        /* number of pages we've output */
188     BOOL    pendingInsert;    /* ret IP_WRITE_INSERT_OK after outbuf empty? */
189         
190 } INST, *PINST;
191
192
193
194 /*****************************************************************************\
195  *
196  * xformJumpTables - Array of ptrs to all driver jump tables
197  *
198  * Warning: This array is indexed by the enum IP_XFORM.  If one changes,
199  *          the other must change too.
200  *
201 \*****************************************************************************/
202
203 extern IP_XFORM_TBL faxEncodeTbl, faxDecodeTbl;
204 extern IP_XFORM_TBL pcxEncodeTbl, pcxDecodeTbl;
205 /* extern IP_XFORM_TBL bmpEncodeTbl, bmpDecodeTbl; */
206 extern IP_XFORM_TBL jpgEncodeTbl, jpgDecodeTbl, jpgFixTbl;
207 extern IP_XFORM_TBL tifEncodeTbl, tifDecodeTbl;
208 extern IP_XFORM_TBL pnmEncodeTbl, pnmDecodeTbl;
209 extern IP_XFORM_TBL scaleTbl;
210 extern IP_XFORM_TBL gray2biTbl, bi2grayTbl;
211 extern IP_XFORM_TBL colorTbl;
212 extern IP_XFORM_TBL yXtractTbl;
213 /* extern IP_XFORM_TBL headerTbl; */
214 extern IP_XFORM_TBL thumbTbl;
215 extern IP_XFORM_TBL tableTbl;
216 extern IP_XFORM_TBL cropTbl;
217 extern IP_XFORM_TBL tonemapTbl;
218 extern IP_XFORM_TBL saturationTbl;
219 extern IP_XFORM_TBL rotateTbl;
220 extern IP_XFORM_TBL padTbl;
221 extern IP_XFORM_TBL fakeMonoTbl;
222 extern IP_XFORM_TBL grayOutTbl;
223 extern IP_XFORM_TBL changeBPPTbl;
224 extern IP_XFORM_TBL matrixTbl;
225 extern IP_XFORM_TBL convolveTbl;
226 extern IP_XFORM_TBL invertTbl;
227 extern IP_XFORM_TBL skelTbl;
228
229 static IP_XFORM_TBL * const xformJumpTables[] = {
230     &faxEncodeTbl, &faxDecodeTbl,  /* MH, MR and MMR formats */
231     &pcxEncodeTbl, &pcxDecodeTbl,
232     /* &bmpEncodeTbl, &bmpDecodeTbl, */
233     &jpgEncodeTbl, &jpgDecodeTbl, &jpgFixTbl,
234     &tifEncodeTbl, &tifDecodeTbl,
235     &pnmEncodeTbl, &pnmDecodeTbl,
236     &scaleTbl,
237     &gray2biTbl, &bi2grayTbl,
238     &colorTbl,
239     &yXtractTbl,
240     /* &headerTbl, */
241     &thumbTbl,
242     &tableTbl,
243     &cropTbl,
244     &tonemapTbl,
245     &saturationTbl,
246     &rotateTbl,
247     &padTbl,
248     &fakeMonoTbl,
249     &grayOutTbl,
250     &changeBPPTbl,
251     &matrixTbl,
252     &convolveTbl,
253     &invertTbl,
254     &skelTbl,
255 };
256
257
258
259 /*****************************************************************************\
260  *
261  * fatalBreakPoint - Called when INSURE fails, used for debugger breakpoint
262  *
263 \*****************************************************************************/
264
265 void fatalBreakPoint (void)
266 {
267    /* do nothing */
268 #if defined _DEBUG
269     __asm int 3;
270 #endif
271    PRINT0 (_T("\nhit fatalBreakPoint!\n"));
272 }
273
274
275
276 /*****************************************************************************\
277  *
278  * deleteMidBufs - Frees the two mid-buffers, if they've been allocated
279  *
280 \*****************************************************************************/
281
282 static void deleteMidBufs (PINST g)
283 {
284     PRINT0 (_T("deleteMidBufs\n"));
285
286     if (g->pbMidInBuf != NULL)
287         IP_MEM_FREE (g->pbMidInBuf);
288
289     if (g->pbMidOutBuf != NULL)
290         IP_MEM_FREE (g->pbMidOutBuf);
291
292     g->pbMidInBuf  = NULL;
293     g->pbMidOutBuf = NULL;
294 }
295
296
297
298 /*****************************************************************************\
299  *
300  * ipOpen - Opens a new conversion job
301  *
302 \*****************************************************************************/
303
304 EXPORT(WORD) ipOpen (
305     int             nXforms,      /* in:  number of xforms in lpXforms below */
306     LPIP_XFORM_SPEC lpXforms,     /* in:  the xforms we should perform */
307     int             nClientData,  /* in:  # bytes of additional client data */
308     PIP_HANDLE      phJob)        /* out: handle for conversion job */
309
310     PINST           g;
311     int             i;
312     PIP_XFORM_SPEC src;
313     PXFORM_INFO     dest;
314
315 #ifdef HPIP_DEBUG
316     char *ipIn = "/tmp/ipIn.dib";
317 #endif
318
319     PRINT0 (_T("ipOpen: nXforms=%d\n"), nXforms);
320     INSURE (nXforms>0 && lpXforms!=NULL && nClientData>=0 && phJob!=NULL);
321
322 #ifdef HPIP_DEBUG
323     for (i=0; i<nXforms; i++)
324     {
325        switch (lpXforms[i].eXform)
326        {
327           case X_FAX_DECODE:
328             PRINT0("Fax_format=%d\n", lpXforms[i].aXformInfo[IP_FAX_FORMAT].dword);
329             ipIn = "/tmp/ipIn.pbm";
330             break;
331           case X_JPG_DECODE:
332             PRINT0("JPG_decode=%d\n", lpXforms[i].aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword);
333             ipIn = "/tmp/ipIn.jpg";
334             break;
335           case X_CNV_COLOR_SPACE:
336             PRINT0("Color_space conversion=%d\n", lpXforms[i].aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword);
337             PRINT0("Color_space gamma=%d\n", lpXforms[i].aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword);
338             break;
339           case X_CROP:
340             PRINT0("Crop_left=%d\n", lpXforms[i].aXformInfo[IP_CROP_LEFT].dword);
341             PRINT0("Crop_right=%d\n", lpXforms[i].aXformInfo[IP_CROP_RIGHT].dword);
342             PRINT0("Crop_top=%d\n", lpXforms[i].aXformInfo[IP_CROP_TOP].dword);
343             PRINT0("Crop_maxoutrows=%d\n", lpXforms[i].aXformInfo[IP_CROP_MAXOUTROWS].dword);
344             break;
345           case X_PAD:
346             PRINT0("Pad_left=%d\n", lpXforms[i].aXformInfo[IP_PAD_LEFT].dword);
347             PRINT0("Pad_right=%d\n", lpXforms[i].aXformInfo[IP_PAD_RIGHT].dword);
348             PRINT0("Pad_top=%d\n", lpXforms[i].aXformInfo[IP_PAD_TOP].dword);
349             PRINT0("Pad_bottom=%d\n", lpXforms[i].aXformInfo[IP_PAD_BOTTOM].dword);
350             PRINT0("Pad_value=%d\n", lpXforms[i].aXformInfo[IP_PAD_VALUE].dword);
351             PRINT0("Pad_minheight=%d\n", lpXforms[i].aXformInfo[IP_PAD_MIN_HEIGHT].dword);
352             break;
353           default:
354             PRINT0("Unknown xform\n");
355             break;
356        }
357     }
358
359     infd = creat(ipIn, 0600);
360     outfd = creat("/tmp/ipOut.ppm", 0600);
361 #endif
362
363     /**** Create Instance and Init Misc Variables ****/
364
365     IP_MEM_ALLOC (sizeof(INST) + nClientData, g);
366     *phJob = g;
367
368     memset (g, 0, sizeof(INST));
369     g->dwValidChk = CHECK_VALUE;
370     g->iOwner = -1;
371     g->wResultMask = PERMANENT_RESULTS;
372
373     /**** Transfer the Xforms to xfArray ****/
374
375     g->xfCount = (WORD)nXforms;
376
377     for (i=0; i<nXforms; i++) {
378         src  = &(lpXforms[i]);
379         dest = &(g->xfArray[i]);
380
381         dest->eState = XS_NONEXISTENT;
382         dest->pXform = (src->pXform != NULL)
383                        ? src->pXform
384                        : xformJumpTables[src->eXform];
385         INSURE (dest->pXform != NULL);
386         dest->pfReadPeek  = src->pfReadPeek;
387         dest->pfWritePeek = src->pfWritePeek;
388         dest->pUserData   = src->pUserData;
389         memcpy (dest->aXformInfo, src->aXformInfo, sizeof(dest->aXformInfo));
390     }
391
392     return IP_DONE;
393
394     fatal_error:
395     return IP_FATAL_ERROR;
396 }
397
398
399
400 /*****************************************************************************\
401  *
402  * ipClose - Destroys the given conversion job, deallocating all its memory
403  *
404 \*****************************************************************************/
405
406 EXPORT(WORD) ipClose (IP_HANDLE hJob)
407 {
408     PINST       g;
409     PXFORM_INFO pXform;
410     WORD        n;
411
412     PRINT0 (_T("ipClose: hJob=%p\n"), (void*)hJob);
413     HANDLE_TO_PTR (hJob, g);
414
415     /**** Delete All Buffers ****/
416
417     deleteMidBufs (g);
418     g->dwMidLen      = 0;
419     g->dwMidValidLen = 0;
420
421     if (g->gbIn.pbBuf  != NULL) IP_MEM_FREE (g->gbIn.pbBuf);
422     if (g->gbOut.pbBuf != NULL) IP_MEM_FREE (g->gbOut.pbBuf);
423
424     /**** Delete All Xform Instances ****/
425
426     for (n=0; n<g->xfCount; n++) {
427         pXform = &(g->xfArray[n]);
428         if (pXform->hXform != NULL)
429             pXform->pXform->closeXform (pXform->hXform);
430     }
431
432     IP_MEM_FREE (g);   /* Delete our instance, and we're done */
433
434 #ifdef HPIP_DEBUG
435     close(infd); 
436     close(outfd); 
437 #endif
438
439     return IP_DONE;
440
441     fatal_error:
442     return IP_FATAL_ERROR;
443 }
444
445
446
447 /*****************************************************************************\
448  *
449  * ipGetClientDataPtr - Returns ptr to client's data in conversion instance
450  *
451 \*****************************************************************************/
452
453 EXPORT(WORD) ipGetClientDataPtr (
454     IP_HANDLE  hJob,            /* in:  handle to conversion job */
455     PVOID     *ppvClientData)   /* out: ptr to client's memory area */
456 {
457     PINST g;
458
459     PRINT0 (_T("ipGetClientDataPtr\n"));
460     HANDLE_TO_PTR (hJob, g);
461     *ppvClientData = (PVOID)((PBYTE)g + sizeof(INST));
462     return IP_DONE;
463
464     fatal_error:
465     return IP_FATAL_ERROR;
466 }
467
468
469
470 /****************************************************************************\
471  *
472  * ipResultMask - Selects bit-results to be returned by ipConvert
473  *
474 \****************************************************************************/
475
476 EXPORT(WORD) ipResultMask (
477     IP_HANDLE  hJob,     /* in:  handle to conversion job */
478     WORD       wMask)    /* in:  result bits you are interested in */
479 {
480     PINST g;
481
482     PRINT0 (_T("ipResultMask: hJob=%p, wMask=%04x\n"), (void*)hJob, wMask);
483     HANDLE_TO_PTR (hJob, g);
484     g->wResultMask = wMask | PERMANENT_RESULTS;
485     return IP_DONE;
486
487     fatal_error:
488     return IP_FATAL_ERROR;
489 }
490
491
492
493 /*****************************************************************************\
494  *
495  * ipSetDefaultInputTraits - Specifies default input image traits
496  *
497  *****************************************************************************
498  *
499  * The header of the file-type handled by the first transform might not
500  * include *all* the image traits we'd like to know.  Those not specified
501  * in the file-header are filled in from info provided by this routine.
502  *
503  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
504  *
505 \*****************************************************************************/
506
507 EXPORT(WORD) ipSetDefaultInputTraits (
508     IP_HANDLE         hJob,       /* in: handle to conversion job */
509     LPIP_IMAGE_TRAITS pTraits)    /* in: default image traits */
510 {
511     PINST g;
512     PIP_IMAGE_TRAITS p;
513
514     PRINT0 (_T("ipSetDefaultInputTraits: hJob=%p PixelsPerRow=%d BitsPerPixel=%d ComponentsPerPixel=%d HorzDPI=%ld VertDPI=%ld Rows=%ld Pages=%d PageNum=%d\n"), 
515                        (void*)hJob, pTraits->iPixelsPerRow, pTraits->iBitsPerPixel, pTraits->iComponentsPerPixel, pTraits->lHorizDPI, 
516                         pTraits->lVertDPI, pTraits->lNumRows, pTraits->iNumPages, pTraits->iPageNum);
517     HANDLE_TO_PTR (hJob, g);
518     INSURE (g->xfArray[0].eState == XS_NONEXISTENT);
519     g->xfArray[0].inTraits = *pTraits;   /* a structure copy */
520
521     /* Convert DPI from integer to 16.16 fixed-pt if necessary */
522     p = &(g->xfArray[0].inTraits);
523     if (p->lHorizDPI < 0x10000) p->lHorizDPI <<= 16;
524     if (p->lVertDPI  < 0x10000) p->lVertDPI  <<= 16;
525
526     return IP_DONE;
527
528     fatal_error:
529     return IP_FATAL_ERROR;
530 }
531
532
533
534 /*****************************************************************************\
535  *
536  * ipGetImageTraits - Returns traits of input and output images
537  *
538  *****************************************************************************
539  *
540  * After the conversion job is done, these traits will contain the actual
541  * number of rows input and output (ipConvert patches traits upon completion).
542  *
543 \*****************************************************************************/
544
545 EXPORT(WORD) ipGetImageTraits (
546     IP_HANDLE         hJob,          /* in:  handle to conversion job */
547     LPIP_IMAGE_TRAITS pInputTraits,  /* out: traits of input image */
548     LPIP_IMAGE_TRAITS pOutputTraits) /* out: traits of output image */
549 {
550     PINST       g;
551     PXFORM_INFO pTail;
552
553     PRINT0 (_T("ipGetImageTraits: hJob=%p\n"), (void*)hJob);
554     HANDLE_TO_PTR (hJob, g);
555     INSURE (g->xfCount > 0);
556     pTail = &(g->xfArray[g->xfCount-1]);
557
558     if (pInputTraits != NULL) {
559         INSURE (g->xfArray[0].eState > XS_PARSING_HEADER);
560         *pInputTraits = g->xfArray[0].inTraits;
561         PRINT0 (_T("InputTraits: hJob=%p PixelsPerRow=%d BitsPerPixel=%d ComponentsPerPixel=%d HorzDPI=%ld VertDPI=%ld Rows=%ld Pages=%d PageNum=%d\n"), 
562                        (void*)hJob, pInputTraits->iPixelsPerRow, pInputTraits->iBitsPerPixel, pInputTraits->iComponentsPerPixel, pInputTraits->lHorizDPI, 
563                         pInputTraits->lVertDPI, pInputTraits->lNumRows, pInputTraits->iNumPages, pInputTraits->iPageNum);
564     }
565
566     if (pOutputTraits != NULL) {
567         INSURE (pTail->eState > XS_PARSING_HEADER);
568         *pOutputTraits = pTail->outTraits;
569         PRINT0 (_T("OutputTraits: hJob=%p PixelsPerRow=%d BitsPerPixel=%d ComponentsPerPixel=%d HorzDPI=%ld VertDPI=%ld Rows=%ld Pages=%d PageNum=%d\n"), 
570                        (void*)hJob, pOutputTraits->iPixelsPerRow, pOutputTraits->iBitsPerPixel, pOutputTraits->iComponentsPerPixel, pOutputTraits->lHorizDPI, 
571                         pOutputTraits->lVertDPI, pOutputTraits->lNumRows, pOutputTraits->iNumPages, pOutputTraits->iPageNum);
572     }
573
574     return IP_DONE;
575
576     fatal_error:
577     return IP_FATAL_ERROR;
578 }
579
580
581
582 /*****************************************************************************\
583  *
584  * ipInsertedData - Client inserted some bytes into our output stream
585  *
586 \*****************************************************************************/
587
588 EXPORT(WORD) ipInsertedData (
589     IP_HANDLE  hJob,         /* in: handle to conversion job */
590     DWORD      dwNumBytes)   /* in: # of bytes of additional data written */
591 {
592     PINST       g;
593     PXFORM_INFO pTail;
594
595     PRINT0 (_T("ipInsertedData: hJob=%p, dwNumBytes=%d\n"), (void*)hJob, dwNumBytes);
596     HANDLE_TO_PTR (hJob, g);
597     INSURE (g->xfCount > 0);
598     pTail = &(g->xfArray[g->xfCount-1]);
599     INSURE (pTail->eState > XS_PARSING_HEADER);
600     INSURE (g->gbOut.dwValidLen == 0);   /* output genbuf must be empty */
601
602     pTail->pXform->insertedData (pTail->hXform, dwNumBytes);
603     return IP_DONE;
604
605     fatal_error:
606     return IP_FATAL_ERROR;
607 }
608
609
610
611 /*****************************************************************************\
612  *
613  * ipOverrideDPI - Force a different DPI to be reported in the output
614  *
615 \*****************************************************************************/
616
617 EXPORT(WORD) ipOverrideDPI (
618     IP_HANDLE hJob,        /* in: handle to conversion job */
619     DWORD     dwHorizDPI,  /* in: horiz DPI as 16.16; 0 means no override */
620     DWORD     dwVertDPI)   /* in: vert  DPI as 16.16; 0 means no override */
621 {
622     PINST g;
623
624     PRINT0 (_T("ipOverrideDPI: dwHorizDPI=%x, dwVertDPI=%x\n"),
625             dwHorizDPI, dwVertDPI);
626     HANDLE_TO_PTR (hJob, g);
627
628     /* Convert from integer to fixed-pt if necessary */
629     if (dwHorizDPI < 0x10000) dwHorizDPI <<= 16;
630     if (dwVertDPI  < 0x10000) dwVertDPI  <<= 16;
631
632     g->dwForcedHorizDPI = dwHorizDPI;
633     g->dwForcedVertDPI  = dwVertDPI;
634     return IP_DONE;
635
636     fatal_error:
637     return IP_FATAL_ERROR;
638 }
639
640
641
642 /*****************************************************************************\
643  *
644  * ipGetFuncPtrs - Loads jump-table with pointers to the ip entry points
645  *
646 \*****************************************************************************/
647
648 EXPORT(WORD) ipGetFuncPtrs (LPIP_JUMP_TBL lpJumpTbl)
649 {
650     PRINT0 (_T("ipGetFuncPtrs\n"));
651     INSURE (lpJumpTbl!=NULL && lpJumpTbl->wStructSize==sizeof(IP_JUMP_TBL));
652
653     lpJumpTbl->ipOpen                  = (LPVOID) ipOpen;
654     lpJumpTbl->ipConvert               = (LPVOID) ipConvert;
655     lpJumpTbl->ipClose                 = (LPVOID) ipClose;
656     lpJumpTbl->ipGetClientDataPtr      = (LPVOID) ipGetClientDataPtr;
657     lpJumpTbl->ipResultMask            = (LPVOID) ipResultMask;
658     lpJumpTbl->ipSetDefaultInputTraits = (LPVOID) ipSetDefaultInputTraits;     
659     lpJumpTbl->ipGetImageTraits        = (LPVOID) ipGetImageTraits;
660     lpJumpTbl->ipInsertedData          = (LPVOID) ipInsertedData;
661     lpJumpTbl->ipOverrideDPI           = (LPVOID) ipOverrideDPI;
662     lpJumpTbl->ipGetOutputTraits       = (LPVOID) ipGetOutputTraits;
663
664     return IP_DONE;    
665
666     fatal_error:
667     return IP_FATAL_ERROR;
668 }
669
670
671
672 /*****************************************************************************\
673  *
674  * ipGetOutputTraits - Returns the output traits before ipConvert is called
675  *
676  *****************************************************************************
677  *
678  * If the first xform does not have a header, then you can call this function
679  * *after* calling ipSetDefaultInputTraits to get the output image traits.
680  * Ordinarily, you'd have to call ipConvert a few times and wait until it tells
681  * you that the (non-existent) header has been parsed.  But if you need the
682  * output traits before calling ipConvert, this function will return them.
683  *
684  * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
685  *
686 \*****************************************************************************/
687
688 EXPORT(WORD) ipGetOutputTraits (
689     IP_HANDLE         hJob,      /* in:  handle to conversion job */
690     LPIP_IMAGE_TRAITS pTraits)   /* out: output image traits */
691 {
692     PINST           g;
693     IP_IMAGE_TRAITS inTraits, outTraits;
694     int        iXform;
695     PXFORM_INFO     pXform;
696     WORD        result;
697     DWORD        dwHeaderLen;
698     DWORD        dwInUsed, dwInNextPos;
699
700     HANDLE_TO_PTR (hJob, g);
701     INSURE (g->xfCount>=1);
702     inTraits = g->xfArray[0].inTraits;  /* set by SetDefaultInputTraits */
703
704     for (iXform=0; iXform<g->xfCount; iXform++) {
705         pXform = &(g->xfArray[iXform]);
706         INSURE (pXform->eState == XS_NONEXISTENT);
707
708         /* Open the xform, set it up, get the traits, and close it */
709
710         result = pXform->pXform->openXform (&pXform->hXform);
711         INSURE (result == IP_DONE);
712
713         result = pXform->pXform->setDefaultInputTraits (
714                     pXform->hXform, &inTraits);
715         INSURE (result == IP_DONE);
716
717         result = pXform->pXform->setXformSpec (
718                     pXform->hXform, pXform->aXformInfo);
719         INSURE (result == IP_DONE);
720
721         result = pXform->pXform->getHeaderBufSize (
722                     pXform->hXform, &dwHeaderLen);
723         INSURE (result == IP_DONE);
724         INSURE (dwHeaderLen == 0);
725
726         result = pXform->pXform->getActualTraits (
727                     pXform->hXform,
728                     0, NULL, &dwInUsed, &dwInNextPos,
729                     &inTraits, &outTraits);
730         INSURE (result & IP_DONE);
731
732         result = pXform->pXform->closeXform (pXform->hXform);
733         INSURE (result == IP_DONE);
734
735         inTraits = outTraits;
736         pXform->hXform = NULL;
737     }
738
739     *pTraits = outTraits;
740     return IP_DONE;
741
742     fatal_error:
743     return IP_FATAL_ERROR;
744 }
745
746
747
748 /*****************************************************************************\
749  *
750  * ipConvert - Converts some input data (work-horse function)
751  *
752 \*****************************************************************************/
753
754 EXPORT(WORD) ipConvert (
755     IP_HANDLE  hJob,              /* in:  handle to conversion job */
756     DWORD      dwInputAvail,      /* in:  # avail bytes in input buf */
757     PBYTE      pbInputBuf,        /* in:  ptr to input buffer */
758     PDWORD     pdwInputUsed,      /* out: # bytes used from input buf */
759     PDWORD     pdwInputNextPos,   /* out: file-pos to read from next */
760     DWORD      dwOutputAvail,     /* in:  # avail bytes in output buf */
761     PBYTE      pbOutputBuf,       /* in:  ptr to output buffer */
762     PDWORD     pdwOutputUsed,     /* out: # bytes written in out buf */
763     PDWORD     pdwOutputThisPos)  /* out: file-pos to write this data */
764 {
765     PINST       g;
766     WORD        ipResult;
767     int         iXform;
768     WORD        result;
769     PGENBUF     pgbIn, pgbOut;
770     BOOL        atTheHead, atTheTail;
771     PXFORM_INFO pXform, pPriorXform, pNextXform;
772     BOOL        needInput, selectCnvState;
773     DWORD       dwBytes;
774     int         i;
775     DWORD       n;
776     DWORD       dwInUsed, dwOutUsed;
777     DWORD       dwInNextPos, dwOutThisPos;
778     DWORD       dwTheInLen, dwTheOutLen;
779     PBYTE       pbTemp;
780     PBYTE       pbTheInBuf, pbTheOutBuf;
781     DWORD       dwJunk;
782
783     if (pbOutputBuf == NULL) {
784         /* client wants us to discard all data */
785         pdwOutputUsed    = &dwJunk;
786         pdwOutputThisPos = &dwJunk;
787         dwOutputAvail    = 0xfffffffu;
788     }
789
790     PRINT0 (_T("ipConvert: hJob=%p, pbInputBuf=%p InputBufSize=%d pbOutputBuf=%p OutputBufSize=%d\n"),
791                              (void*)hJob, pbInputBuf, dwInputAvail, pbOutputBuf, dwOutputAvail);
792     INSURE (pdwInputUsed !=NULL && pdwInputNextPos !=NULL &&
793             pdwOutputUsed!=NULL && pdwOutputThisPos!=NULL);
794     HANDLE_TO_PTR (hJob, g);
795     INSURE (g->xfCount>=1);
796
797     pgbIn  = &g->gbIn;
798     pgbOut = &g->gbOut;
799
800     *pdwInputUsed  = 0;
801     *pdwOutputUsed = 0;
802     ipResult = 0;
803
804       /**************************/
805      /* Beginning of Main Loop */
806     /**************************/
807
808     while (TRUE) {
809
810     /**** Output any data in the output genbuf ****/
811
812     if (*pdwOutputUsed == 0)
813         *pdwOutputThisPos = pgbOut->dwFilePos;
814
815     if (pgbOut->dwValidLen != 0) {   /* output genbuf is not empty */
816         /* Logic below:
817          *
818          * 1. If next output file-pos doesn't match output genbuf, exit loop.
819          *
820          * 2. Copy as much as possible from output genbuf to clients output buf.
821          *      2.1 decide number of bytes to copy
822          *      2.2 copy them
823          *      2.3 update misc variables
824          *
825          * 3. If output genbuf is not empty, exit loop (client's buf is full),
826          *    else set wValidStart to 0 because output genbuf is empty.
827          */
828
829         if ((*pdwOutputThisPos+*pdwOutputUsed) != pgbOut->dwFilePos) {
830             PRINT0 (_T("ipConvert: output seek to %d\n"), pgbOut->dwFilePos);
831             goto exitLoop;
832         }
833
834         dwBytes = pgbOut->dwValidLen;
835         if (dwOutputAvail < dwBytes)
836             dwBytes = dwOutputAvail;
837
838         if (pbOutputBuf != NULL) {
839             memcpy (pbOutputBuf + *pdwOutputUsed,
840                     pgbOut->pbBuf + pgbOut->dwValidStart,
841                     dwBytes);
842         }
843
844         *pdwOutputUsed       += dwBytes;
845         dwOutputAvail        -= dwBytes;
846         pgbOut->dwValidStart += dwBytes;
847         pgbOut->dwFilePos    += dwBytes;
848         pgbOut->dwValidLen   -= dwBytes;
849
850         if (pgbOut->dwValidLen != 0)
851             goto exitLoop;
852
853         pgbOut->dwValidStart = 0;   /* output genbuf is now empty */
854     }
855
856     if (g->pendingInsert) {
857         g->pendingInsert = FALSE;
858         ipResult |= IP_WRITE_INSERT_OK;
859     }
860
861     /**** If ipResult has any returnable bits set, exit loop now ****/
862
863     if (ipResult & g->wResultMask)
864         goto exitLoop;
865
866     /**** Select an xform to run ****/
867
868     /* select the owner of input midbuf, or negative means 'none selected' */
869     iXform = g->iOwner;
870
871     if (iXform < 0) {
872         for (i=g->xfCount-1; i>=0; i--) {
873             if (g->xfArray[i].eState == XS_CONV_NOT_RFD) {
874                 /* select last xform that's convnotrfd; this xform
875                  * is outputting (or thinking) but not inputting */
876                 iXform = i;
877                 break;
878             }
879         }
880     }
881
882     if (iXform < 0) {
883         for (i=0; i<g->xfCount; i++) {
884             if (g->xfArray[i].eState != XS_DONE) {
885                 /* select first xform that's not done */
886                 iXform = i;
887                 break;
888             }
889         }
890     }
891
892     if (iXform < 0) {
893         /* all xforms are done: discard all input, and report that we're done */
894         *pdwInputUsed = dwInputAvail;
895         ipResult |= IP_DONE;
896         /* patch the last outtraits with actual # of rows output, so that
897          * ipGetImageTraits will return actual row-count after we're done */
898         g->xfArray[g->xfCount-1].outTraits.lNumRows = g->lOutRows;
899         /* patch first intraits for the same reason */
900         g->xfArray[0].inTraits.lNumRows = g->lInRows;
901         goto exitLoop;
902     }
903
904     /**** Miscellaneous preparation ****/
905
906     pXform = &(g->xfArray[iXform]);
907     atTheHead = (iXform == 0);
908     atTheTail = (iXform == g->xfCount-1);
909     pPriorXform = atTheHead ? NULL : &(g->xfArray[iXform-1]);
910     pNextXform  = atTheTail ? NULL : &(g->xfArray[iXform+1]);
911
912     /**** Create the Xform if necessary ****/
913
914     if (pXform->eState == XS_NONEXISTENT) {
915         PRINT0 (_T("ipConvert: creating xform %d\n"), iXform);
916         INSURE (atTheHead || pPriorXform->eState>=XS_CONVERTING);
917         
918         if (atTheHead) {
919             /* this xform's input traits were set by ipSetDefaultInputTraits */
920         } else {
921             /* this xform's input traits are prior xform's output traits */
922             memcpy (&pXform->inTraits, &pPriorXform->outTraits,
923                     sizeof(IP_IMAGE_TRAITS));
924
925             if (atTheTail) {
926                 /* apply any DPI overrides */
927                 if (g->dwForcedHorizDPI != 0)
928                     pXform->inTraits.lHorizDPI = (long)g->dwForcedHorizDPI;
929                 if (g->dwForcedVertDPI != 0)
930                     pXform->inTraits.lVertDPI  = (long)g->dwForcedVertDPI;
931             }
932         }
933         
934         result = pXform->pXform->openXform (&pXform->hXform);
935         INSURE (result == IP_DONE);
936         result = pXform->pXform->setDefaultInputTraits (
937                     pXform->hXform, &pXform->inTraits);
938         INSURE (result == IP_DONE);
939         result = pXform->pXform->setXformSpec (
940                     pXform->hXform, pXform->aXformInfo);
941         INSURE (result == IP_DONE);
942         result = pXform->pXform->getHeaderBufSize (
943                     pXform->hXform, &pXform->dwMinInBufLen);
944         INSURE (result == IP_DONE);
945
946         if (! atTheHead) {
947             /* a header is only allowed on first xform */
948             INSURE (pXform->dwMinInBufLen == 0);
949         } else {
950             /* allocate the input genbuf */
951             if (pXform->dwMinInBufLen == 0)
952                 pXform->dwMinInBufLen = 1;
953             PRINT0 (_T("ipConvert: alloc input genbuf, len=%d\n"),
954                 pXform->dwMinInBufLen);
955             IP_MEM_ALLOC (pXform->dwMinInBufLen, pgbIn->pbBuf);
956             pgbIn->dwBufLen     = pXform->dwMinInBufLen;
957             pgbIn->dwValidStart = 0;
958             pgbIn->dwValidLen   = 0;
959             pgbIn->dwFilePos    = 0;
960         }
961
962         pXform->eState = XS_PARSING_HEADER;
963     }
964
965     /**** Enter flushing state if appropriate ****/
966
967     if (pXform->eState == XS_CONVERTING &&
968         (( atTheHead && pbInputBuf==NULL && pgbIn->dwValidLen==0) ||
969          (!atTheHead && pPriorXform->eState==XS_DONE && g->iOwner<0))) {
970         /* there will never be any more input to this xform: start flushing */
971         PRINT0 (_T("ipConvert: xform %d is now flushing\n"), iXform);
972         pXform->eState = XS_FLUSHING;
973     }
974
975     /**** Check that input data and output space are available ****/
976
977     needInput = (pXform->eState==XS_PARSING_HEADER ||
978                  pXform->eState==XS_CONVERTING);
979
980     if (needInput) {
981         if (! atTheHead) {
982             /* the input midbuf must contain data */
983             INSURE (g->iOwner>=0 && g->dwMidValidLen>0);
984             PRINT1 (_T("not at head, pixels = %08x\n"), *(DWORD*)(g->pbMidInBuf));
985         } else if (pbInputBuf != NULL) {
986             DWORD dwUnusedStart;
987
988             /* left-justify data in input genbuf if necessary */
989
990             if (pgbIn->dwBufLen-pgbIn->dwValidStart < pXform->dwMinInBufLen) {
991                 /* too much wasted space on left end, so left justify */
992                 memmove (pgbIn->pbBuf, pgbIn->pbBuf + pgbIn->dwValidStart,
993                          pgbIn->dwValidLen);
994                 pgbIn->dwValidStart = 0;
995                 PRINT1 (_T("left just, pixels = %08x\n"), *(DWORD*)(pgbIn->pbBuf));
996             }
997
998             /* put as much client input as possible into the input genbuf */
999
1000             dwUnusedStart = pgbIn->dwValidStart + pgbIn->dwValidLen;
1001             dwBytes = pgbIn->dwBufLen - dwUnusedStart;
1002             if (dwBytes > dwInputAvail)
1003                 dwBytes = dwInputAvail;
1004
1005             memcpy (pgbIn->pbBuf + dwUnusedStart,
1006                     pbInputBuf + *pdwInputUsed,
1007                     dwBytes);
1008
1009             pgbIn->dwValidLen += dwBytes;
1010             *pdwInputUsed     += dwBytes;
1011             dwInputAvail      -= dwBytes;
1012             *pdwInputNextPos  += dwBytes;
1013
1014             /* if input genbuf has insufficient data, exit loop */
1015             if (pgbIn->dwValidLen < pXform->dwMinInBufLen)
1016                 goto exitLoop;
1017             PRINT1 (_T("at head, pixels = %08x\n"), *(DWORD*)(pgbIn->pbBuf));
1018         }
1019     }
1020
1021     if (atTheTail && pXform->eState!=XS_PARSING_HEADER) {
1022         /* output might be produced; output genbuf must be empty */
1023         INSURE (pgbOut->dwValidLen == 0);
1024     }
1025
1026     /**** Call the Conversion Routine ****/
1027
1028     pbTheInBuf   = atTheHead ? pgbIn->pbBuf + pgbIn->dwValidStart : g->pbMidInBuf;
1029     dwTheInLen   = atTheHead ? pgbIn->dwValidLen : g->dwMidValidLen;
1030     pbTheOutBuf  = atTheTail ? pgbOut->pbBuf : g->pbMidOutBuf;
1031     dwTheOutLen  = atTheTail ? pgbOut->dwBufLen : g->dwMidLen;
1032
1033     if (pXform->eState == XS_PARSING_HEADER) {
1034         result = pXform->pXform->getActualTraits (
1035                     pXform->hXform,
1036                     dwTheInLen, pbTheInBuf, &dwInUsed, &dwInNextPos,
1037                     &pXform->inTraits,
1038                     &pXform->outTraits);
1039         dwOutUsed = 0;
1040         dwOutThisPos = 0;
1041     } else {
1042         if (pXform->eState == XS_FLUSHING)
1043             pbTheInBuf = NULL;
1044         result = pXform->pXform->convert (
1045                     pXform->hXform,
1046                     dwTheInLen,  pbTheInBuf,  &dwInUsed,  &dwInNextPos,
1047                     dwTheOutLen, pbTheOutBuf, &dwOutUsed, &dwOutThisPos);
1048     }
1049
1050     PRINT1 (_T("ipConvert: xform %d returned %04x\n"), iXform, result);
1051     PRINT1 (_T("ipConvert:         consumed %d and produced %d bytes\n"),
1052            dwInUsed, dwOutUsed);
1053
1054     if (pbTheOutBuf != NULL)
1055         PRINT1 (_T("ipConvert: out data = %08x\n"), *(DWORD*)pbTheOutBuf);
1056
1057     INSURE ((result & IP_FATAL_ERROR) == 0);
1058
1059     /**** Update Input and Output Buffers ****/
1060
1061     if (dwInUsed > 0) {
1062         if (pXform->pfReadPeek != NULL) {
1063             #if defined _WIN32
1064                 __try {
1065             #endif
1066             pXform->pfReadPeek (hJob, &(pXform->inTraits),
1067                                 dwInUsed, pbTheInBuf, pgbIn->dwFilePos, 
1068                                 pXform->pUserData);
1069             #if defined _WIN32
1070                 } __except (EXCEPTION_EXECUTE_HANDLER) {
1071                     goto fatal_error;
1072                 }
1073             #endif
1074         }
1075
1076         if (! atTheHead) {
1077             /* We _assume_ that the xform consumed all the data in the midbuf */
1078             g->iOwner = -1;   /* input midbuf is consumed and un-owned now */
1079             g->dwMidValidLen = 0;
1080         }
1081     }
1082
1083     if (needInput && atTheHead) {
1084         if (dwInUsed >= pgbIn->dwValidLen) {
1085             /* consumed all input; mark input genbuf as empty */
1086             pgbIn->dwValidLen   = 0;
1087             pgbIn->dwValidStart = 0;
1088             pgbIn->dwFilePos    = dwInNextPos;
1089         } else {
1090             /* advance counters in genbuf */
1091             pgbIn->dwValidLen   -= dwInUsed;
1092             pgbIn->dwValidStart += dwInUsed;
1093             pgbIn->dwFilePos    += dwInUsed;
1094         }
1095
1096         /* if new genbuf file-pos doesn't match what xform wants,
1097          * discard remainder of buffer */
1098         if (pgbIn->dwFilePos != dwInNextPos) {
1099             PRINT0 (_T("ipConvert: input seek to %d\n"), dwInNextPos);
1100             pgbIn->dwValidLen   = 0;
1101             pgbIn->dwValidStart = 0;
1102             pgbIn->dwFilePos    = dwInNextPos;
1103         }
1104     }
1105
1106     if (dwOutUsed > 0) {
1107         if (pXform->pfWritePeek != NULL) {
1108             #if defined _WIN32
1109                 __try {
1110             #endif
1111             pXform->pfWritePeek (hJob, &(pXform->outTraits),
1112                                  dwOutUsed, pbTheOutBuf, dwOutThisPos,
1113                                  pXform->pUserData);
1114             #if defined _WIN32
1115                 } __except (EXCEPTION_EXECUTE_HANDLER) {
1116                     goto fatal_error;
1117                 }
1118             #endif
1119         }
1120
1121         if (atTheTail) {
1122             pgbOut->dwFilePos    = dwOutThisPos;
1123             pgbOut->dwValidStart = 0;
1124             pgbOut->dwValidLen   = dwOutUsed;
1125         } else {
1126             INSURE (g->iOwner < 0);   /* mid inbuf must be unowned here */
1127             g->iOwner = iXform + 1;   /* next xform hereby owns mid inbuf */
1128             /* swap input and output midbuf pointers */
1129             pbTemp = g->pbMidInBuf;
1130             g->pbMidInBuf    = g->pbMidOutBuf;
1131             g->pbMidOutBuf   = pbTemp;
1132             g->dwMidValidLen = dwOutUsed;
1133         }
1134     }
1135
1136     /**** Handle Results of Conversion Call ****/
1137
1138     selectCnvState = FALSE;
1139
1140     if (pXform->eState == XS_PARSING_HEADER) {
1141
1142         if (result & IP_DONE) {
1143             PRINT0 (_T("ipConvert: xform %d is done parsing header\n"), iXform);
1144             pXform->pXform->getActualBufSizes (pXform->hXform,
1145                 &pXform->dwMinInBufLen, &pXform->dwMinOutBufLen);
1146
1147             if (atTheHead) {
1148                 /* allocate new input genbuf, and xfer data into it */
1149                 n = pXform->dwMinInBufLen;
1150                 if (n < MIN_GENBUF_LEN)
1151                     n = MIN_GENBUF_LEN;
1152                 if (n < pgbIn->dwValidLen)
1153                     n = pgbIn->dwValidLen;
1154                 PRINT0 (_T("ipConvert: alloc new input genbuf, ")
1155                        _T("old len=%d, new len=%d\n"), pgbIn->dwBufLen, n);
1156                 PRINT0 (_T("   dwMinInBufLen=%d, dwValidLen=%d\n"),
1157                     pXform->dwMinInBufLen, pgbIn->dwValidLen);
1158                 IP_MEM_ALLOC (n, pbTemp);
1159                 memcpy (pbTemp,
1160                         pgbIn->pbBuf + pgbIn->dwValidStart,
1161                         pgbIn->dwValidLen);
1162                 IP_MEM_FREE (pgbIn->pbBuf);
1163                 pgbIn->pbBuf        = pbTemp;
1164                 pgbIn->dwBufLen     = n;
1165                 pgbIn->dwValidStart = 0;
1166             }
1167
1168             /* boost size of midbufs if necessary (also 1st malloc of them) */
1169             n = atTheHead ? 0 : pXform->dwMinInBufLen;
1170             if (!atTheTail && pXform->dwMinOutBufLen > n)
1171                 n = pXform->dwMinOutBufLen;
1172             /* note: the code below (correctly) does not create mid-bufs if
1173              * n is 0, which occurs if there's only one xform in the list */
1174             if (n > g->dwMidLen) {
1175                 /* delete both mid-bufs, and (re) allocate them */
1176                 /* copy data from old to new, if necessary */
1177                 PBYTE pbOldMidInBuf = g->pbMidInBuf;
1178                 g->pbMidInBuf = NULL;
1179                 PRINT0 (_T("ipConvert: alloc mid-bufs, old len=%d, new len=%d\n"),
1180                         g->dwMidLen, n);
1181                 deleteMidBufs (g);
1182                 IP_MEM_ALLOC (n, g->pbMidInBuf );
1183                 IP_MEM_ALLOC (n, g->pbMidOutBuf);
1184                 if (pbOldMidInBuf != NULL) {
1185                     memcpy (g->pbMidInBuf, pbOldMidInBuf, g->dwMidLen);
1186                     IP_MEM_FREE (pbOldMidInBuf);
1187                 }
1188                 g->dwMidLen = n;
1189             }
1190
1191             if (atTheTail) {
1192                 /* allocate output genbuf */
1193                 n = pXform->dwMinOutBufLen;
1194                 if (n < MIN_GENBUF_LEN)
1195                     n = MIN_GENBUF_LEN;
1196                 PRINT0 (_T("ipConvert: alloc output genbuf, len=%d, minlen=%d\n"),
1197                      n, pXform->dwMinOutBufLen);
1198                 IP_MEM_ALLOC (n, pgbOut->pbBuf);
1199                 pgbOut->dwBufLen     = n;
1200                 pgbOut->dwValidStart = 0;
1201                 pgbOut->dwValidLen   = 0;
1202
1203                 /* At this point it is permissible to call ipGetImageTraits
1204                  * to obtain output traits because all xforms are past the
1205                  * parsing-header state, and thus the output traits are known.
1206                  * So tell caller that we're done parsing the header.  */
1207                 ipResult |= IP_PARSED_HEADER;
1208             }
1209
1210             selectCnvState = TRUE;
1211         }
1212
1213     } else {    /* state is XS_CONVERTING or XS_CONV_NOT_RFD or XS_FLUSHING */
1214
1215         if (atTheHead) {
1216             /* handle status bits pertaining to the input data */
1217             if (result & IP_CONSUMED_ROW) {
1218                g->lInRows += 1;
1219                ipResult |= IP_CONSUMED_ROW;
1220             }
1221             if (result & IP_NEW_OUTPUT_PAGE) {
1222                 /* a new *output* page for the input xform is a new *input* page
1223                  * for the IP as a whole */
1224                 g->iInPages += 1;
1225                 ipResult |= IP_NEW_INPUT_PAGE;
1226             }
1227         }
1228
1229         if (atTheTail) {
1230             /* handle status bits pertaining to the output data */
1231             ipResult |= (result & (IP_PRODUCED_ROW | IP_NEW_OUTPUT_PAGE));
1232             if (result & IP_PRODUCED_ROW)
1233                 g->lOutRows += 1;
1234             if (result & IP_NEW_OUTPUT_PAGE)
1235                 g->iOutPages += 1;
1236             if (result & IP_WRITE_INSERT_OK & g->wResultMask)
1237                 g->pendingInsert = TRUE;
1238         } else if (result & IP_NEW_OUTPUT_PAGE) {
1239             /* this xform hit end of page, so tell next xform about it */
1240             PRINT0 (_T("ipConvert: xform %d hit end of page\n"), iXform);
1241             pNextXform->pXform->newPage (pNextXform->hXform);
1242         }
1243
1244         if (result & IP_DONE) {
1245             PRINT0 (_T("ipConvert: xform %d is done\n"), iXform);
1246             pXform->eState = XS_DONE;
1247         } else if (pXform->eState != XS_FLUSHING)
1248             selectCnvState = TRUE;
1249     } /* if state is 'parsing header' */
1250
1251     if (selectCnvState) {
1252         /* go to one of the two 'converting' states */
1253         if ((result & IP_READY_FOR_DATA) == 0)
1254             PRINT1 (_T("ipConvert: xform %d is not ready for data\n"), iXform);
1255         pXform->eState = (result & IP_READY_FOR_DATA)
1256                          ? XS_CONVERTING : XS_CONV_NOT_RFD;
1257     }
1258
1259     }  /* end of while (TRUE) */
1260     exitLoop: ;
1261
1262       /********************/
1263      /* End of Main Loop */
1264     /********************/
1265
1266     *pdwInputNextPos = pgbIn->dwFilePos + pgbIn->dwValidLen;
1267
1268     /* After headers are parsed, parsed-header bit should always be set */
1269     if (g->xfArray[g->xfCount-1].eState >= XS_CONVERTING)
1270         ipResult |= IP_PARSED_HEADER;
1271
1272     PRINT0 (_T("ipConvert: ipResult=%04x, returning %04x, InputUsed=%d InputNextPos=%d OutputUsed=%d OutputThisPos=%d\n"),
1273             ipResult, ipResult & g->wResultMask, *pdwInputUsed, *pdwInputNextPos, *pdwOutputUsed, *pdwOutputThisPos);
1274
1275 #ifdef HPIP_DEBUG
1276     if (pbInputBuf && *pdwInputUsed)
1277        write(infd, pbInputBuf, *pdwInputUsed); 
1278
1279     if (*pdwOutputUsed)
1280        write(outfd, pbOutputBuf, *pdwOutputUsed); 
1281 #endif
1282
1283     return ipResult & g->wResultMask;
1284
1285     fatal_error:
1286     return IP_FATAL_ERROR;
1287 }
1288
1289
1290
1291 /*****************************************************************************\
1292  *
1293  * ipMirrorBytes - Swaps bits in each byte of buffer
1294  *                 (bits 0<->7, 1<->6, etc.)
1295  *
1296 \*****************************************************************************/
1297
1298 static const BYTE baMirrorImage[256] =
1299 {
1300     0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
1301     0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
1302     0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
1303     0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
1304     0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
1305     0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
1306     0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
1307     0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
1308     0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
1309     0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
1310     0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
1311     0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
1312     0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
1313     0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
1314     0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
1315     0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
1316     0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
1317     0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
1318     0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
1319     0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
1320     0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
1321     0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
1322     0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
1323     0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
1324     0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
1325     0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
1326     0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
1327     0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
1328     0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
1329     0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
1330     0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
1331     0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
1332 };
1333
1334 VOID ipMirrorBytes(PBYTE pbInputBuf,DWORD dwInputAvail) {
1335     while (dwInputAvail>0) {
1336         *pbInputBuf=baMirrorImage[*pbInputBuf];
1337         pbInputBuf++;
1338         dwInputAvail--;
1339     }
1340 }
1341
1342 /* End of File */