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