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