2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: ilpipe.c /main/6 1996/06/19 12:21:13 ageorge $ */
24 /**---------------------------------------------------------------------
26 *** (c)Copyright 1991 Hewlett-Packard Co.
28 *** RESTRICTED RIGHTS LEGEND
29 *** Use, duplication, or disclosure by the U.S. Government is subject to
30 *** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
31 *** Technical Data and Computer Software clause in DFARS 252.227-7013.
32 *** Hewlett-Packard Company
33 *** 3000 Hanover Street
34 *** Palo Alto, CA 94304 U.S.A.
35 *** Rights for non-DOD U.S. Government Departments and Agencies are as set
36 *** forth in FAR 52.227-19(c)(1,2).
38 ***-------------------------------------------------------------------*/
40 /* /ilc/ilpipe.c : General pipe handling code.
41 Also contains ilCrop() as this function is very much tied to the
42 implementation of pipes.
47 #include "ilpipelem.h"
48 #include "ilpipeint.h"
51 /* One element in the pipe, added by ilAddElement(). Notes:
53 pNext, pPrev forward/back ptrs to next/prev element in list. First element
54 in list is *ilPipePtr->elementHead.pNext; last is *pPrev.
56 elementType One of: IL_PRODUCER, IL_FILTER, IL_CONSUMER. Not needed or
57 used, but very handy for debugging.
59 flags flag values, e.g. IL_ADD_PIPE_NO_DST
61 exec par block to Execute() for this element: ptrs to src/dst image
62 src/dst lines to read.
67 Execute() functions passed to ilAddPipeElement(); see spec for details
69 clientPrivate start of client's private area; MUST BE LAST
71 typedef struct _ilElementRec {
72 struct _ilElementRec *pNext, *pPrev;
73 unsigned int elementType;
79 ilError (*ExecuteThree)();
80 ilError (*ExecuteFour)(register ilExecuteData *,
84 unsigned long clientPrivate; /* client private: MUST BE LAST */
85 } ilElementRec, *ilElementPtr;
88 /* Actual contents of a ilPipe. Notes:
90 o std object header: MUST BE FIRST
92 state current state of the pipe as returned by ilGetPipeInfo(); one
95 IL_PIPE_INVALID an error occurred in forming the pipe, and the pipe
96 cannot be used until ilEmptyPipe() is done. No more
97 elements should be added. The pipe is in fact empty,
98 only the state is different, to prevent other elements
99 from being added. This state is set by calling
100 ilDeclarePipeInvalid().
102 IL_PIPE_EMPTY pipe is empty; ready to add a producer (read)
104 IL_PIPE_FORMING pipe has a producer and zero or more filters; ready to
105 add filters or a consumer (write)
107 IL_PIPE_COMPLETE pipe has a consumer (write); ilExecutePipe() can now
108 be called on it (executable, from caller's view).
109 Error if an attempt to add an element.
111 IL_PIPE_EXECUTING one or more, but not all, strips have been processed.
113 producerCode code that defines producer; one of:
115 IL_PIPE_NOT_IMAGE the producer was not an image
116 IL_PIPE_IMAGE producer was an ilReadImage() call
117 IL_PIPE_FEED_IMAGE producer was an ilFeedFromImage() call
123 feedDone used only if producerCode == IL_PIPE_FEED_IMAGE: values
124 passed to / used by ilSetFeedPipeData()
126 elementHead head/tail of list of ilElementRec, the elements in the pipe
128 hookHead head/tail of list of IL_HOOK ilElementRec, the pseudo-elements
129 in the pipe of type "hook" - not in elementHead list.
131 stackIndex index of top of "execStack"; see below.
133 execStack stack of ptrs to elements that returned IL_ERROR_ELEMENT_AGAIN
134 "stackIndex" points to the top of stack. [0] contains the
135 first element in the list.
137 nDestroyObjects # of elements in "destroyObjects" array; see below.
139 destroyObjects an array of "nDestroyObjects" objects which must be destroyed
140 (by calling ilDestroyObject()) when the pipe is emptied. This
141 array is added to by calling ilAddPipeDestroyObject().
143 lastStrip inited to false when pipe started, set true when "last strip"
144 error returned from an element. Pipe execution is complete
145 when lastStrip && stackIndex <= 0 (> 0 => last strip has still
146 not made it all the way through the pipe).
148 needProducerThrottle true iff ilAddProducerImage() just called: pipe began
149 with an ilReadImage() and no filters added yet.
151 copyToConsumerImage true iff a copy filter must be inserted if the next
152 element is a consumer, specifying a consumerImage, e.g.
153 is ilWriteImage(). This would be true right after
154 ilAddProducerImage() is called, or right after any
155 IL_ADD_PIPE_NO_DST filter.
157 imageHead head/tail of list of ilImageRec, the temporary images
158 associated with this pipe. The images object prev/next ptrs
159 are used to maintain this list. Note that the images in this
160 list are not official objects; they must be deleted when then
161 the pipe is emptied. The images have buffers only when state
162 is IL_PIPE_EXECUTING; the list is null when state is IL_PIPE
165 pSrcPipeImage if non-null, points the source (input) pipe image to the next
166 element to be added. If null, must allocate a src image for
167 the next element unless it is a ilWriteImage().
169 image describes the current pipe image. The values in this struct
170 meaningful only if pipe forming (state == IL_PIPE_FORMING).
171 The fields are as returned by ilGetPipeInfo().
174 #define IL_MAX_EXEC_STACK 100
175 #define IL_MAX_DESTROY_OBJECTS 10
178 ilObjectRec o; /* std header: MUST BE FIRST */
180 unsigned int producerCode;
181 long feedStartLine, feedNLines, feedCompOffset, feedCompNBytes;
183 ilElementRec elementHead;
184 ilElementRec hookHead;
186 ilElementPtr execStack [IL_MAX_EXEC_STACK];
188 ilObject destroyObjects [IL_MAX_DESTROY_OBJECTS];
190 ilBool needProducerThrottle;
191 ilBool copyToConsumerImage;
192 ilObjectRec imageHead;
193 ilImageInfo *pSrcPipeImage;
197 ilImageFormat format;
199 } ilPipeRec, *ilPipePtr;
202 /* Default optimal strip size, in bytes. Used by ilRecommendedStripHeight().
203 NOTE: currently the same as TIFF strip size, "IL_WRITE_TIFF_STRIP_SIZE" in
204 /ilc/iltiffwrite.c . The two are not directly coupled, but making them different
205 may adversely affect performance, e.g. cause de/recompression!
207 static long ilDefaultStripSize = (16 * 1024);
209 /* ------------------------ _ilSetDefaultStripSize ------------------------ */
210 /* "Back door" call to set ilDefaultStripSize. The IL test suite uses this
211 call to ensure that small images are stripped, and so that strip
212 size is consistent between test baselevels.
214 void _ilSetDefaultStripSize (
218 ilDefaultStripSize = stripSize;
222 /* ------------------------ ilFreeTempImageBuffers ------------------------ */
223 /* Free the buffers associated with the temp images of this pipe. The image
224 structures are not freed; just the pixels.
226 static void ilFreeTempImageBuffers (
227 register ilPipePtr pPipe
230 register ilImagePtr pImage;
232 pImage = (ilImagePtr)pPipe->imageHead.pNext;
233 while (pImage != (ilImagePtr)&pPipe->imageHead) {
234 _ilFreeImagePixels (pImage);
235 pImage = (ilImagePtr)pImage->o.pNext;
239 /* -------------------------- ilAllocTempImage ----------------------- */
240 /* Allocates a temporary (buffer) image, inits it and returns a ptr to it or
241 null if failure. The buffer for the pixels is not allocated. The
242 height of the image is not set; the caller must do that.
244 static ilImagePtr ilAllocTempImage (
245 register ilPipePtr pPipe,
248 ilImageFormat *pFormat
251 register ilImagePtr pImage;
253 pImage = (ilImagePtr)IL_MALLOC (sizeof (ilImageRec));
255 return (ilImagePtr)NULL; /* EXIT */
258 pImage->format = *pFormat;
259 pImage->pStripOffsets = (long *)NULL; /* freed if non-null */
261 pImage->i.pDes = &pImage->des;
262 pImage->i.pFormat = &pImage->format;
263 pImage->i.width = pInfo->width;
264 pImage->i.height = 0;
266 /* Set clientPixels/Palette/CompData true so they are *not* deallocated */
267 pImage->i.clientPixels = TRUE;
268 pImage->i.clientPalette = TRUE;
269 pImage->i.clientCompData = TRUE;
270 pImage->i.pPalette = pInfo->pPalette;
271 pImage->i.pCompData = pInfo->pCompData;
273 /* Link image into list of temp images, using object pPrev/pNext ptrs.
275 pImage->o.pNext = pPipe->imageHead.pNext;
276 pImage->o.pPrev = (ilPtr)&pPipe->imageHead;
277 ((ilImagePtr)pPipe->imageHead.pNext)->o.pPrev = (ilPtr)pImage;
278 pPipe->imageHead.pNext = (ilPtr)pImage;
284 /* ------------------------ ilCleanupRunningPipe ----------------------------- */
285 /* Cleanup a pipe which had been running, i.e. its state was IL_PIPE_EXECUTING.
286 "aborting" should be TRUE if the pipe is being aborted (was not finished).
287 The pipe state is set to IL_PIPE_COMPLETE.
289 static ilError ilCleanupRunningPipe (
290 register ilPipePtr pPipe,
294 register ilElementPtr pElement, pElementHead;
295 ilError error, prevError;
297 /* Run thru the list of elements and call Cleanup function if non-null, then
298 do same for "hook" list. Pass given aborting flag to Cleanup().
299 If an error return, switch to "aborting" mode and return first error returned.
302 pElementHead = &pPipe->elementHead;
304 pElement = pElementHead->pNext;
305 while (pElement != pElementHead) {
306 if (pElement->Cleanup) {
307 error = (*pElement->Cleanup) ((ilPtr)pElement->exec.pPrivate, aborting);
309 if (prevError == IL_OK)
311 aborting = TRUE; /* error; now considered aborted */
314 pElement = pElement->pNext;
316 if (pElementHead == &pPipe->hookHead)
317 break; /* both lists scanned; done */
318 pElementHead = &pPipe->hookHead; /* run thru hook list */
321 ilFreeTempImageBuffers (pPipe);
322 pPipe->stackIndex = 0;
323 pPipe->state = IL_PIPE_COMPLETE;
328 /* ------------------------ ilEmptyPipe -------------------------------- */
329 /* Public function: see spec.
330 Also called locally, for example when aborting a pipe.
336 register ilPipePtr pPipe;
337 register ilElementPtr pElement, pNextElement, pElementHead;
338 register ilImagePtr pImage, pNextImage;
342 pPipe = (ilPipePtr)pipe;
343 if (pPipe->o.p.objectType != IL_PIPE) {
344 pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
348 /* Action to empty a pipe depends on current state. Transition from running
349 (abort) to complete (empty element list) to invalid (mark as empty).
350 FALL THRU (no break) from each state.
352 error = IL_OK; /* assume no error; log error from Cleanup() */
353 switch (pPipe->state) {
354 case IL_PIPE_EXECUTING: /* executing: must abort, fall thru to complete */
355 error = ilCleanupRunningPipe (pPipe, TRUE);
357 case IL_PIPE_COMPLETE: /* elements but no buffers allocated */
358 case IL_PIPE_FORMING: /* forming is same as complete */
360 /* Run thru list of elements and free them. Call optional Destroy
361 function if non-null. Make list head empty.
363 pElementHead = &pPipe->elementHead;
365 pElement = pElementHead->pNext;
366 while (pElement != pElementHead) {
367 if (pElement->Destroy)
368 (*pElement->Destroy) ((ilPtr)pElement->exec.pPrivate);
369 pNextElement = pElement->pNext;
371 pElement = pNextElement;
373 if (pElementHead == &pPipe->hookHead)
374 break; /* both lists scanned; done */
375 pElementHead = &pPipe->hookHead; /* run thru hook list */
377 pPipe->elementHead.pNext = pPipe->elementHead.pPrev = &pPipe->elementHead;
378 pPipe->hookHead.pNext = pPipe->hookHead.pPrev = &pPipe->hookHead;
380 /* Destroy all temp images associated with this pipe. The buffers are
381 already gone, because they only exist when state is IL_PIPE_EXECUTING,
382 and ilCleanupRunningPipe() would be called in that case.
384 pImage = (ilImagePtr)pPipe->imageHead.pNext;
385 while (pImage != (ilImagePtr)&pPipe->imageHead) {
386 pNextImage = (ilImagePtr)pImage->o.pNext;
390 pPipe->imageHead.pNext = pPipe->imageHead.pPrev = (ilPtr)&pPipe->imageHead;
392 /* Destroy all objects in destroyObjects array. */
393 for (i = 0; i < pPipe->nDestroyObjects; i++)
394 ilDestroyObject (pPipe->destroyObjects[i]);
395 pPipe->nDestroyObjects = 0;
397 case IL_PIPE_INVALID: /* pipe already empty; change state */
398 pPipe->state = IL_PIPE_EMPTY;
400 case IL_PIPE_EMPTY: /* pipe in desired state */
404 pPipe->o.p.context->error = error;
405 return (error == IL_OK);
410 /* ------------------------ ilCreatePipe -------------------------------- */
411 /* Public function: see spec.
414 ilPipe ilCreatePipe (
416 unsigned long mustBeZero
419 register ilPipePtr pPipe;
421 if (mustBeZero != 0) {
422 context->error = IL_ERROR_PAR_NOT_ZERO;
426 pPipe = (ilPipePtr)_ilCreateObject (context, IL_PIPE, ((void (*)())ilEmptyPipe),
431 /* Declare pipe empty, set element and temp image lists to empty state.
432 The rest of the pipe state must be set by ilAddPipeElement() on each element.
433 Init some of elementHead, which itself is an element, and will be
434 referenced as the current element in a pipe with no elements.
436 pPipe->state = IL_PIPE_EMPTY;
437 pPipe->elementHead.pNext = pPipe->elementHead.pPrev = &pPipe->elementHead;
438 pPipe->hookHead.pNext = pPipe->hookHead.pPrev = &pPipe->hookHead;
439 pPipe->imageHead.pNext = pPipe->imageHead.pPrev = (ilPtr)&pPipe->imageHead;
440 pPipe->elementHead.flags = 0;
441 pPipe->stackIndex = 0;
442 pPipe->nDestroyObjects = 0;
443 pPipe->image.info.stripHeight = 0;
445 context->error = IL_OK;
446 return (ilPipe)pPipe;
450 /* ------------------------ ilDeclarePipeInvalid ----------------------------- */
451 /* Public function; see spec.
452 Empties the pipe, sets state to invalid and posts given error.
453 FALSE is always returned, to allow the following:
454 if (<something wrong while forming pipe>)
455 return ilDeclarePipeInvalid (pipe, errorCode);
457 ilBool ilDeclarePipeInvalid (
462 register ilPipePtr pPipe;
464 pPipe = (ilPipePtr)pipe;
465 ilEmptyPipe ((ilPipe)pPipe);
466 if (pPipe->o.p.objectType == IL_PIPE)
467 pPipe->state = IL_PIPE_INVALID;
468 pPipe->o.p.context->error = error;
473 /* ------------------------ ilQueryPipe ----------------------------- */
474 /* Public function; see spec.
475 Return description of current image, from pipe header, if pipe forming.
477 unsigned int ilQueryPipe (
479 long *pWidth, /* RETURNED */
480 long *pHeight, /* RETURNED */
481 ilImageDes *pDes /* RETURNED */
484 register ilPipePtr pPipe;
486 pPipe = (ilPipePtr)pipe;
487 if (pPipe->o.p.objectType != IL_PIPE) {
488 pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
489 return IL_PIPE_INVALID; /* return phony state because of error */
492 if (pPipe->state == IL_PIPE_FORMING) {
494 *pWidth = pPipe->image.info.width;
496 *pHeight = pPipe->image.info.height;
498 *pDes = pPipe->image.des;
501 pPipe->o.p.context->error = IL_OK;
506 /* ------------------------ ilGetPipeInfo ----------------------------- */
507 /* Public function; see spec.
508 If pipe state is "forming": if "forceDecompress" and image is compressed, make
509 it uncompressed, then return description of current pipe state.
511 unsigned int ilGetPipeInfo (
513 ilBool forceDecompress,
516 ilImageFormat *pFormat
519 register ilPipePtr pPipe;
521 pPipe = (ilPipePtr)pipe;
522 if (pPipe->o.p.objectType != IL_PIPE) {
523 pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
524 return IL_PIPE_INVALID; /* EXIT w/ pseudo-error */
526 if (pPipe->state == IL_PIPE_FORMING) {
528 /* Decompress image if it is compressed and caller asked for decompressed.
530 if (forceDecompress && (pPipe->image.des.compression != IL_UNCOMPRESSED)) {
531 _ilDecompress ((ilPipe)pPipe);
532 if (pPipe->o.p.context->error)
533 return IL_PIPE_INVALID; /* EXIT w/ pseudo-error */
537 *pInfo = pPipe->image.info;
539 *pDes = pPipe->image.des;
541 *pFormat = pPipe->image.format;
544 pPipe->o.p.context->error = IL_OK;
549 /* ----------------------- ilRecommendedStripHeight ------------------------ */
550 /* Public function; see spec.
552 long ilRecommendedStripHeight (
553 const ilImageDes *pDes,
554 const ilImageFormat *pFormat,
559 long bytesPerRow [IL_MAX_SAMPLES];
560 register long stripHeight, nBytes;
563 /* Get the bytes/row, per plane. If pixel format, all bytes are in plane 0,
564 else in pDes->nSamplesPerPixel planes.
569 ilGetBytesPerRow (pDes, pFormat, width, bytesPerRow);
570 if (pFormat->sampleOrder == IL_SAMPLE_PIXELS)
571 nBytes = bytesPerRow[0]; /* all bytes in one plane */
574 for (i = 0; i < pDes->nSamplesPerPixel; i++)
575 nBytes += bytesPerRow[i];
580 stripHeight = ilDefaultStripSize / nBytes;
581 if (stripHeight > height)
582 stripHeight = height;
583 if (stripHeight <= 0)
591 /* ----------------------- ilChangeStripHeight ------------------------ */
592 /* Calcs the recommended strip height, in ilPipeInfo for the pipe.
593 Should be called whenever the pipe stripHeight is changed, after the
594 pipe height is changed (limits stripHeight to image height).
596 static void ilChangeStripHeight (
597 register ilPipePtr pPipe
600 register long stripHeight;
602 /* Limit stripHeight to pipe height. */
603 stripHeight = pPipe->image.info.stripHeight;
604 if (stripHeight > pPipe->image.info.height)
605 pPipe->image.info.stripHeight = stripHeight = pPipe->image.info.height;
606 else if (stripHeight <= 0)
607 pPipe->image.info.stripHeight = stripHeight = 1;
609 /* If uncompressed image, calc recommendedStripHeight else current stripHeight */
610 if (pPipe->image.des.compression == IL_UNCOMPRESSED) {
612 i = ilRecommendedStripHeight (&pPipe->image.des, &pPipe->image.format,
613 pPipe->image.info.width, pPipe->image.info.height);
614 pPipe->image.info.recommendedStripHeight = (i > stripHeight) ? stripHeight : i;
616 else pPipe->image.info.recommendedStripHeight = stripHeight;
620 /* ------------------------ ilAddPipeDestroyObject ------------------------ */
621 /* IL internal function, declared in /ilc/ilpipeint.h .
622 Add the given object to a list of objects to be destroyed when this pipe
623 is emptied. The object's refCount should be inc'd before this call, so that
624 the object cannot be freed until this pipe is destroyed.
625 The pipe must be in the forming or complete state.
626 NOTE: a hard limit exists on the # of objects which can be added; not intended
627 for unlimited use, e.g. by filters!
628 Sets context->error to error code, returns true if success.
630 IL_PRIVATE ilBool _ilAddPipeDestroyObject (
635 register ilPipePtr pPipe;
637 pPipe = (ilPipePtr)pipe;
638 if (pPipe->nDestroyObjects >= IL_MAX_DESTROY_OBJECTS) {
639 pipe->context->error = IL_ERROR_MALLOC; /* should not happen, return phony */
642 pPipe->destroyObjects[pPipe->nDestroyObjects] = object;
643 pPipe->nDestroyObjects++;
644 pipe->context->error = IL_OK;
649 /* ---------------------------- ilAddProducerImage ------------------------ */
650 /* IL internal function, declared in /ilc/ilpipeint.h .
651 Called by ilReadImage() to set *pImage as the producer to this pipe.
652 The pipe MUST be in the empty state. "needProducerThrottle" is true iff a
653 throttle must be inserted before next element added by ilAddPipeElement().
655 IL_PRIVATE ilBool _ilAddProducerImage (
657 register ilImagePtr pImage,
658 unsigned int producerCode,
661 ilBool constantStrip,
662 ilBool needProducerThrottle
665 register ilPipePtr pPipe;
667 /* Copy image data into pipe info, point to given image as producer. */
668 pPipe = (ilPipePtr)pipe;
669 pPipe->producerCode = producerCode;
670 pPipe->image.des = pImage->des;
671 pPipe->image.format = pImage->format;
672 pPipe->image.info.producerObject = (ilObject)pImage;
673 pPipe->image.info.tempImage = FALSE;
674 pPipe->image.info.width = pImage->i.width;
675 pPipe->image.info.height = height;
676 pPipe->image.info.constantStrip = constantStrip;
677 pPipe->image.info.stripHeight = stripHeight;
678 ilChangeStripHeight (pPipe);
680 pPipe->image.info.producerObject = (ilObject)pImage;
681 pPipe->image.info.pPalette = pImage->i.pPalette; /* point to image palette */
682 pPipe->image.info.pCompData = pImage->i.pCompData; /* point to comp data */
683 pPipe->pSrcPipeImage = &pImage->i;
684 pPipe->state = IL_PIPE_FORMING;
685 pPipe->feedDone = FALSE; /* ilSetFeedPipeData not done yet. */
687 /* Signal ilAddPipeElement() to add a throttle before next filter is added,
688 and that a copy filter must be added if ilWriteImage() is called next.
690 pPipe->needProducerThrottle = needProducerThrottle;
691 pPipe->copyToConsumerImage = TRUE;
693 /* Inc pImage->refCount, and add as destroyObject for when pipe destroyed. */
694 pImage->o.refCount++;
695 return _ilAddPipeDestroyObject ((ilPipe)pPipe, (ilObject)pImage);
699 /* ------------------------ ilSetFeedPipeData ------------------------------- */
700 /* Called by ilFeedPipe() to set info for the first element in the given pipe,
701 which will be ilFeedProducerThrottleExecute(). If feeding compressed data:
702 "start" is the byte offset into the compressed data, and "nCompBytes" is
703 the number of bytes at that offset. If uncompressed data: "start" is the
704 starting line, and "nCompBytes" is ignored. Returns FALSE if the pipe was
705 not started with a ilFeedFromImage() producer.
707 IL_PRIVATE ilBool _ilSetFeedPipeData (
714 register ilPipePtr pPipe;
715 register ilImagePtr pImage;
717 pPipe = (ilPipePtr)pipe;
718 if (pPipe->producerCode != IL_PIPE_FEED_IMAGE)
721 /* If uncompressed image, starting line plus # lines must be <= height, and
722 "start" is starting line; if compressed "start" is starting byte offset.
724 pImage = (ilImagePtr)pPipe->image.info.producerObject;
725 if (pImage->des.compression == IL_UNCOMPRESSED) {
726 if ((start + nLines) > pImage->i.height)
728 pPipe->feedStartLine = start;
729 pPipe->feedCompNBytes = 0;
730 pPipe->feedCompOffset = 0;
733 pPipe->feedStartLine = 0;
734 pPipe->feedCompOffset = start;
735 pPipe->feedCompNBytes = nCompBytes;
737 pPipe->feedNLines = nLines;
738 pPipe->feedDone = TRUE; /* pipe now fed */
743 /* ------------------------ ilSetPipeDesFormat ------------------------------- */
744 /* IL internal function, declared in /ilc/ilpipeint.h .
745 Called by ilConvert() to "typecast" the pipe image to the given des and/or
746 format (ignored if pDes/pFormat null). No validation is done on the result!
748 IL_PRIVATE void _ilSetPipeDesFormat (
751 ilImageFormat *pFormat
754 register ilPipePtr pPipe;
756 pPipe = (ilPipePtr)pipe;
758 pPipe->image.des = *pDes;
760 pPipe->image.format = *pFormat;
764 /* ------------------------ ilAddPipeElement ------------------------------- */
765 /* Public function: see spec.
766 Add a pipe element if correct state.
768 ilPtr ilAddPipeElement (
771 /* Use portable type for sizeof() operator, bug report OSF_QAR# 32082 */
772 size_t nBytesPrivate,
774 ilSrcElementData *pSrcData,
775 ilDstElementData *pDstData,
777 ilError (*Cleanup)(),
778 ilError (*Destroy)(),
780 ** Added another execute function for passing in a fourth
781 ** parameter which is a floating pointing.
783 ilError (*ExecuteThree)(),
784 ilError (*ExecuteFour)(register ilExecuteData *,
788 unsigned long mustBeZero
791 register ilPipePtr pPipe;
792 unsigned int newState; /* pipe state after this element added */
793 register ilElementPtr pElement; /* ptr to new element to add to list */
794 ilElementPtr pPrevElement;
796 long stripHeight, srcBufferHeight;
797 ilBool constantStrip, haveConsumerImage, insertCopyFilter;
799 stripHeight = 0; /* initializing the stripHeight variable */
800 pPipe = (ilPipePtr)pipe;
801 if (pPipe->o.p.objectType != IL_PIPE) {
802 pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
803 return (ilPtr)NULL; /* EXIT */
805 if (mustBeZero != 0) {
806 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PAR_NOT_ZERO);
810 /* Validate elementType and pipe state: "empty" for producer, else "forming".
811 Set newState to state pipe becomes after this element is added.
812 If a "hook" element, add hook element and EXIT.
813 For filters and consumers: set stripHeight to source (input) strip height
814 required by this element; set constantStrip true if every strip (except last)
815 must be stripHeight lines high. Default if !pSrcData or stripHeight == 0:
816 !constantStrip; filters: recommended strip height; consumers: whole strip.
817 Set some flags, explained when used below.
819 haveConsumerImage = FALSE;
820 insertCopyFilter = FALSE;
822 switch (elementType) {
825 if (pPipe->state != IL_PIPE_EMPTY) {
826 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PIPE_STATE);
829 newState = IL_PIPE_FORMING;
833 if (pPipe->state != IL_PIPE_FORMING) {
834 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PIPE_STATE);
837 newState = IL_PIPE_FORMING;
838 if (pSrcData && (pSrcData->minBufferHeight > 0))
839 insertCopyFilter = pPipe->copyToConsumerImage;
840 if (!pSrcData || !pSrcData->stripHeight) {
841 stripHeight = pPipe->image.info.recommendedStripHeight;
842 constantStrip = FALSE;
845 stripHeight = pSrcData->stripHeight;
846 constantStrip = pSrcData->constantStrip;
851 if (pPipe->state != IL_PIPE_FORMING) {
852 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PIPE_STATE);
855 newState = IL_PIPE_COMPLETE;
857 if (pSrcData->consumerImage) {
858 haveConsumerImage = TRUE;
859 insertCopyFilter = pPipe->copyToConsumerImage;
861 else if (pSrcData->minBufferHeight > 0)
862 insertCopyFilter = pPipe->copyToConsumerImage;
864 if (!pSrcData || !pSrcData->stripHeight) {
865 stripHeight = pPipe->image.info.stripHeight; /* accept strip height */
866 constantStrip = FALSE;
869 stripHeight = pSrcData->stripHeight;
870 constantStrip = pSrcData->constantStrip;
874 /* A "hook" element: invalid if pipe executing or invalid, else add element
875 to hook list with Init/Cleanup/Destroy functions copied.
878 if ((pPipe->state == IL_PIPE_INVALID) || (pPipe->state == IL_PIPE_EXECUTING)) {
879 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PIPE_STATE);
882 if (ExecuteThree || ExecuteFour) {
883 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PAR_NOT_ZERO);
886 pElement = (ilElementPtr)IL_MALLOC_ZERO (sizeof(ilElementRec) + nBytesPrivate);
888 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_MALLOC);
889 return (ilPtr)NULL; /* EXIT */
891 pElement->pPrev = pPipe->hookHead.pPrev;
892 pElement->pNext = &pPipe->hookHead;
893 pPipe->hookHead.pPrev->pNext = pElement;
894 pPipe->hookHead.pPrev = pElement;
895 pElement->elementType = IL_HOOK;
896 pElement->exec.pPrivate = (ilPtr)&pElement->clientPrivate;
897 pElement->exec.pSrcImage = pElement->exec.pDstImage = (ilImageInfo *)NULL;
898 pElement->Init = Init;
899 pElement->Cleanup = Cleanup;
900 pElement->Destroy = Destroy;
902 pPipe->o.p.context->error = IL_OK;
903 return (ilPtr)pElement->exec.pPrivate; /* done; EXIT */
907 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_ELEMENT_TYPE);
910 } /* END switch elementType */
913 /* Force stripHeight to be in range 1..image height */
914 if (stripHeight <= 0)
916 else if (stripHeight > pPipe->image.info.height)
917 stripHeight = pPipe->image.info.height;
919 /* If pipe begins with an ilReadImage() and this is first filter, add
920 a throttle to entire strip height - this throttle knows to read whole strip
921 and return IL_ERROR_LAST_STRIP - otherwise ilExecutePipe() would not stop.
922 Note: ilAddThrottlePipeElement() calls this function: recursion!
923 Also, note that no pipe state has been changed up to this point. BUT,
924 set needProducerThrottle to false or below check causes infinite recursion.
926 if ((elementType != IL_PRODUCER) && pPipe->needProducerThrottle) {
927 pPipe->needProducerThrottle = FALSE; /* prevent recursion */
928 if (!_ilAddThrottlePipeElement ((ilPipe)pPipe, stripHeight,
929 constantStrip, pPipe->producerCode,
930 &pPipe->image.info.stripHeight, &pPipe->image.info.constantStrip)) {
931 ilDeclarePipeInvalid ((ilPipe)pPipe, pPipe->o.p.context->error);
936 /* If writing consumerImage (e.g. ilWriteImage()) or inserting a throttle
937 requiring minBufferHeight, insert copy filter if flagged: e.g. previous
938 element was "no dst" filter or ilReadImage(); else possibly add throttle:
939 If not a producer and pipe image is not compressed, check "stripHeight",
940 the desired strip height, set above.
941 If != current strip height, or caller requires a constant strip
942 and current is not constant, add a filter which makes it so.
943 If throttle added successfully, set image info to what was asked for, but
944 first save stripHeight - it is the size of the src buffer to create, if any.
946 srcBufferHeight = pPipe->image.info.stripHeight;
947 if (insertCopyFilter) {
948 if (pPipe->image.des.compression == IL_UNCOMPRESSED) {
949 if (!_ilInsertCopyFilter ((ilPipe)pPipe, pPipe->image.info.stripHeight))
952 else if (!_ilInsertCompressedCopyFilter ((ilPipe)pPipe))
955 else if ((elementType != IL_PRODUCER)
956 && (pPipe->image.des.compression == IL_UNCOMPRESSED)
957 && ((stripHeight != pPipe->image.info.stripHeight)
958 || (constantStrip && !pPipe->image.info.constantStrip)) ) {
959 if (!_ilAddThrottlePipeElement ((ilPipe)pPipe, stripHeight,
960 constantStrip, IL_PIPE_NOT_IMAGE,
961 &pPipe->image.info.stripHeight, &pPipe->image.info.constantStrip)) {
962 ilDeclarePipeInvalid ((ilPipe)pPipe, pPipe->o.p.context->error);
967 /* Allocate and zero element struct and add to end of list; exit if error. */
968 pElement = (ilElementPtr)IL_MALLOC_ZERO (sizeof(ilElementRec) + nBytesPrivate);
970 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_MALLOC);
971 return (ilPtr)NULL; /* EXIT */
973 pElement->pPrev = pPipe->elementHead.pPrev;
974 pElement->pNext = &pPipe->elementHead;
975 pPipe->elementHead.pPrev->pNext = pElement;
976 pPipe->elementHead.pPrev = pElement;
978 /* Copy passed data into the element struct and init element.
979 Each element's pNextSrcLine points to the next one's srcLine, and compressed.
980 pOffset/pNBytesWritten point to next one's srcOffset/nBytesToRead.
981 Set "Destroy" to null for now, so it will not be called if we fail here.
982 Set it to passed function only when sure of success.
984 pElement->elementType = elementType;
985 pElement->flags = flags;
986 pElement->exec.pPrivate = (ilPtr)&pElement->clientPrivate;
987 pPrevElement = pElement->pPrev;
988 pPrevElement->exec.pNextSrcLine = &pElement->exec.srcLine;
989 pPrevElement->exec.compressed.pDstOffset = &pElement->exec.compressed.srcOffset;
990 pPrevElement->exec.compressed.pNBytesWritten = &pElement->exec.compressed.nBytesToRead;
991 pElement->pNext->exec.srcLine = 0;
992 pElement->Init = Init;
993 pElement->Cleanup = Cleanup;
994 pElement->Destroy = IL_NPF; /* set when successful */
995 pElement->ExecuteThree = ExecuteThree;
996 pElement->ExecuteFour = ExecuteFour;
998 /* If a producer, must have valid dst data and pDes/Format, or error.
999 Skip allocation of src image for producers - they get src on their own;
1000 set pSrcPipeImage to NULL. Init # src lines to read to strip height.
1001 Set ilPipeInfo.pPalette to callers if palette image, else to null
1003 if (elementType == IL_PRODUCER) {
1004 if (!pDstData || !pDstData->pDes || !pDstData->pFormat) {
1005 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_PRODUCER_DATA);
1006 return (ilPtr)NULL; /* EXIT */
1008 if ((pDstData->width <= 0) || (pDstData->height <= 0)) {
1009 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_ZERO_SIZE_IMAGE);
1010 return (ilPtr)NULL; /* EXIT */
1012 error = _ilValidateDesFormat (TRUE, pDstData->pDes, pDstData->pFormat);
1014 ilDeclarePipeInvalid ((ilPipe)pPipe, error);
1015 return (ilPtr)NULL; /* EXIT */
1018 pPipe->producerCode = IL_PIPE_NOT_IMAGE; /* not a read from a (feed) image */
1019 pPipe->pSrcPipeImage = (ilImageInfo *)NULL;
1021 pPipe->image.des = *pDstData->pDes;
1022 pPipe->image.format = *pDstData->pFormat;
1023 pPipe->image.info.producerObject = pDstData->producerObject;
1024 pPipe->image.info.tempImage = TRUE;
1026 pPipe->image.info.width = pDstData->width;
1027 pPipe->image.info.height = pDstData->height;
1028 pPipe->image.info.constantStrip = pDstData->constantStrip;
1029 pPipe->image.info.stripHeight = pDstData->stripHeight;
1030 ilChangeStripHeight (pPipe);
1032 pPipe->image.info.pPalette = (pPipe->image.des.type == IL_PALETTE) ?
1033 pDstData->pPalette : (unsigned short *)NULL;
1034 pPipe->image.info.pCompData = pDstData->pCompData;
1035 pPipe->needProducerThrottle = FALSE; /* producer not an image */
1036 pPipe->copyToConsumerImage = FALSE;
1038 pElement->exec.pSrcImage = (ilImageInfo *)NULL;
1041 /* Not a producer. Create src image to this element, unless a consumer which
1042 specifies its source image (e.g. ilWriteImage()), or src image specified
1043 as output from last element = a producer (e.g. ilReadImage()): pSrcImage.
1045 if (pPipe->pSrcPipeImage) {
1046 pElement->exec.pSrcImage = pPipe->pSrcPipeImage;
1047 pPipe->pSrcPipeImage = (ilImageInfo *)NULL;
1049 else if (haveConsumerImage) {
1050 pElement->exec.pSrcImage = &((ilImagePtr)pSrcData->consumerImage)->i;
1053 /* Src image not provided; must create a temp and add to list of temps.
1054 Set image height = max (minHeight if present, srcBufferHeight).
1057 pImage = ilAllocTempImage (pPipe, &pPipe->image.info, &pPipe->image.des,
1058 &pPipe->image.format);
1060 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_MALLOC);
1061 return (ilPtr)NULL; /* EXIT */
1063 pElement->exec.pSrcImage = &pImage->i;
1064 if (pSrcData && (pSrcData->minBufferHeight > srcBufferHeight))
1065 srcBufferHeight = pSrcData->minBufferHeight;
1066 pImage->i.height = srcBufferHeight;
1069 /* Src image to this element is dst image of previous element.
1070 If no dst from this element, then src to this element is src to next,
1071 and must copy if next element is ilWriteImage(); otherwise, src to next
1072 is necessarily a temp image, and don't need to copy.
1074 pElement->pPrev->exec.pDstImage = pElement->exec.pSrcImage;
1075 if (flags & IL_ADD_PIPE_NO_DST) {
1076 pPipe->pSrcPipeImage = pElement->exec.pSrcImage;
1077 pPipe->copyToConsumerImage = TRUE;
1080 pPipe->image.info.tempImage = TRUE;
1081 pPipe->copyToConsumerImage = FALSE;
1084 /* If not a consumer and have pDstData: if non-null des/format ptr, copy
1085 data from it into the pipe image area - element changes des or format.
1086 Set rest of data from pDstData: stripHeight if not zero.
1087 Set ilPipeInfo.pPalette to null if not a palette image, or to callers
1088 value if it is not null.
1089 Validate pDes and pFormat together if either non-null (else no change).
1091 if (pDstData && (elementType != IL_CONSUMER)) {
1092 const ilImageDes *pDes;
1093 if ((pDstData->width <= 0) || (pDstData->height <= 0)) {
1094 ilDeclarePipeInvalid ((ilPipe)pPipe, IL_ERROR_ZERO_SIZE_IMAGE);
1095 return (ilPtr)NULL; /* EXIT */
1097 pPipe->image.info.width = pDstData->width;
1098 pPipe->image.info.height = pDstData->height;
1099 if (pDstData->stripHeight != 0) {
1100 pPipe->image.info.constantStrip = pDstData->constantStrip;
1101 pPipe->image.info.stripHeight = pDstData->stripHeight;
1103 if (pDes = pDstData->pDes) {
1104 if (pDes->type == IL_PALETTE) {
1105 if (pDstData->pPalette)
1106 pPipe->image.info.pPalette = pDstData->pPalette;
1108 else pPipe->image.info.pPalette = (unsigned short *)NULL;
1109 pPipe->image.des = *pDes;
1111 pPipe->image.info.pCompData = pDstData->pCompData;
1112 if (pDstData->pFormat)
1113 pPipe->image.format = *pDstData->pFormat;
1114 if (pDes || pDstData->pFormat) {
1115 error = _ilValidateDesFormat (TRUE /* allow private types */,
1116 &pPipe->image.des, &pPipe->image.format);
1118 ilDeclarePipeInvalid ((ilPipe)pPipe, error);
1119 return (ilPtr)NULL; /* EXIT */
1122 ilChangeStripHeight (pPipe); /* reset (recommended) strip height */
1123 } /* END have pDstData, not consumer */
1124 } /* END not a producer */
1126 /* Success: set pipe to new state; set pElement->Destroy, return pPriv. */
1127 pPipe->state = newState;
1128 pElement->Destroy = Destroy;
1130 pPipe->o.p.context->error = IL_OK;
1131 return (ilPtr)pElement->exec.pPrivate;
1135 /* ------------------------ ilAbortPipe -------------------------------- */
1136 /* Public function: see spec.
1137 Aborts the given pipe; if not running, a noop.
1139 ilBool ilAbortPipe (
1143 register ilPipePtr pPipe;
1145 pPipe = (ilPipePtr)pipe;
1146 if (pPipe->o.p.objectType != IL_PIPE) {
1147 pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
1151 if (pPipe->state == IL_PIPE_EXECUTING)
1152 return ((pPipe->o.p.context->error = ilCleanupRunningPipe (pPipe, TRUE)) == IL_OK);
1154 pPipe->o.p.context->error = IL_OK;
1159 /* ------------------------ ilExecutePipe -------------------------------- */
1160 /* Public function: see spec.
1168 register ilPipePtr pPipe;
1169 register ilElementPtr pElement, pExecHead, pElementHead;
1171 long nLines, initNLines;
1174 /* Validate zero par and that pipe is one.
1176 pPipe = (ilPipePtr)pipe;
1177 if (pPipe->o.p.objectType != IL_PIPE) {
1178 pPipe->o.p.context->error = IL_ERROR_OBJECT_TYPE;
1179 return IL_EXECUTE_ERROR; /* EXIT */
1182 /* Execute based on pipe state. Error if pipe invalid, empty or forming.
1183 Otherwise: abort if requested, cleanup if in progress. Compile pipe
1184 if complete, or executable and producer changed. If in progress and
1185 producer changed, cleanup and return error.
1187 pExecHead = &pPipe->elementHead; /* head of "executable" (non-hook) list */
1188 switch (pPipe->state) {
1189 case IL_PIPE_INVALID:
1191 case IL_PIPE_FORMING:
1192 pPipe->o.p.context->error = IL_ERROR_PIPE_STATE;
1193 return IL_EXECUTE_ERROR; /* EXIT */
1195 /* Pipe complete: do setup to become executable.
1196 Allocate pixel buffers for all temp images of this pipe.
1197 If error, don't cleanup, as init not done yet.
1199 case IL_PIPE_COMPLETE:
1200 pImage = (ilImagePtr)pPipe->imageHead.pNext;
1201 while (pImage != (ilImagePtr)&pPipe->imageHead) {
1202 ilError error = _ilMallocImagePixels (pImage);
1204 ilFreeTempImageBuffers (pPipe);
1205 pPipe->o.p.context->error = error;
1206 return IL_EXECUTE_ERROR; /* EXIT */
1208 pImage = (ilImagePtr)pImage->o.pNext;
1211 /* Call elements' Init() functions if non-null. If Init() returns error:
1212 call Cleanup() of previous elements, whose Init()s were already called,
1213 and free image buffers allocated above, and return error in errorInfo.
1214 Init all srcLines and srcOffsets to 0; always start at line/byte 0.
1215 Do above first for "hook" list, then for regular element list.
1217 pElementHead = &pPipe->hookHead;
1219 pElement = pElementHead->pNext;
1220 while (pElement != pElementHead) {
1221 pElement->exec.srcLine = 0;
1222 pElement->exec.compressed.srcOffset = 0;
1223 if (pElement->Init) {
1224 ilError error = (*pElement->Init) ((ilPtr)pElement->exec.pPrivate,
1225 pElement->exec.pSrcImage, pElement->exec.pDstImage);
1228 while (pElement->pPrev != pElementHead) {
1229 pElement = pElement->pPrev;
1230 if (pElement->Cleanup)
1231 (*pElement->Cleanup) (pElement->exec.pPrivate, TRUE);
1233 if (pElementHead == &pPipe->hookHead)
1234 break; /* both lists done */
1235 pElementHead = &pPipe->hookHead;
1236 pElement = pElementHead;
1238 ilFreeTempImageBuffers (pPipe);
1239 pPipe->o.p.context->errorInfo = error;
1240 pPipe->o.p.context->error = (error < 0) ?
1241 IL_ERROR_USER_PIPE_ELEMENT : IL_ERROR_PIPE_ELEMENT;
1242 return IL_EXECUTE_ERROR; /* EXIT */
1245 pElement = pElement->pNext;
1246 } /* END while, one element list */
1247 if (pElementHead == pExecHead)
1248 break; /* both lists scanned; done */
1249 pElementHead = pExecHead; /* run thru executable list */
1250 } /* END while TRUE, all element lists */
1252 /* Now executing; FALL THRU to execute one pass. Point top of execStack to
1253 first element; it changes to top of execStack on a push.
1255 pPipe->stackIndex = 0;
1256 pPipe->execStack[0] = pExecHead->pNext;
1257 pPipe->state = IL_PIPE_EXECUTING;
1258 pPipe->lastStrip = FALSE;
1260 /* Pipe being executed, possibly first time. Execute nStrips strips (or all
1261 if !nStrips). dstLine for each element is "srcLine" of next element.
1262 Start with top element of "execStack".
1263 "nLines" on entry to Execute() = # of src lines to read;
1264 on exit = # of dst lines written (== 0, skip rest of pipe).
1265 If error: check for pseudo-error, else abort. Pseudo-errors:
1266 IL_ERROR_LAST_STRIP: finish processing this strip, then done
1267 IL_ERROR_ELEMENT_AGAIN: element states that it needs to be recalled
1268 (e.g. a throttle with more left in its input buffer). Push
1269 pElement onto execStack; exit if overflow.
1270 IL_ERROR_ELEMENT_COMPLETE: element states that it previously issued
1271 "AGAIN" and is now done. Pop stack; exit if underflow.
1273 case IL_PIPE_EXECUTING:
1274 if (pPipe->producerCode == IL_PIPE_FEED_IMAGE) {
1275 ilElementPtr pFirstElement;
1277 if (!pPipe->feedDone) { /* pipe executed directly instead of fed */
1278 ilCleanupRunningPipe (pPipe, TRUE);
1279 pPipe->o.p.context->error = IL_ERROR_PIPE_NOT_FED;
1280 return IL_EXECUTE_ERROR;
1282 pPipe->feedDone = FALSE;
1283 initNLines = pPipe->feedNLines;
1284 pFirstElement = pExecHead->pNext;
1285 pFirstElement->exec.srcLine = pPipe->feedStartLine;
1286 pFirstElement->exec.compressed.srcOffset = pPipe->feedCompOffset;
1287 pFirstElement->exec.compressed.nBytesToRead = pPipe->feedCompNBytes;
1289 else initNLines = pPipe->image.info.height; /* first element reads whole image */
1291 while (TRUE) { /* until all or nStrips done */
1292 nLines = initNLines;
1293 pElement = pPipe->execStack [pPipe->stackIndex];
1294 while (pElement != pExecHead) {
1296 ** Added another execute function for passing in a fourth
1297 ** parameter which is a floating pointing. So check to see
1298 ** which execute function is not null and call that one.
1300 if(pElement->ExecuteThree)
1302 error = (*pElement->ExecuteThree) (&pElement->exec, pElement->pNext->exec.srcLine,
1307 error = (*pElement->ExecuteFour) (&pElement->exec,
1308 pElement->pNext->exec.srcLine,
1312 if (error == IL_ERROR_ELEMENT_AGAIN) {
1313 if (++pPipe->stackIndex >= IL_MAX_EXEC_STACK) {
1314 ilCleanupRunningPipe (pPipe, TRUE);
1315 pPipe->o.p.context->error = IL_ERROR_EXECUTE_STACK_OVERFLOW;
1316 return IL_EXECUTE_ERROR; /* EXIT */
1318 pPipe->execStack [pPipe->stackIndex] = pElement;
1320 else if (error == IL_ERROR_ELEMENT_COMPLETE) {
1321 if (--pPipe->stackIndex < 0) {
1322 ilCleanupRunningPipe (pPipe, TRUE);
1323 pPipe->o.p.context->error = IL_ERROR_EXECUTE_STACK_UNDERFLOW;
1324 return IL_EXECUTE_ERROR; /* EXIT */
1327 else if (error == IL_ERROR_LAST_STRIP)
1328 pPipe->lastStrip = TRUE;
1330 ilCleanupRunningPipe (pPipe, TRUE);
1331 pPipe->o.p.context->errorInfo = error;
1332 pPipe->o.p.context->error = (error < 0) ?
1333 IL_ERROR_USER_PIPE_ELEMENT : IL_ERROR_PIPE_ELEMENT;
1334 return IL_EXECUTE_ERROR; /* EXIT */
1337 if (nLines <= 0) /* no lines written; skip rest of pipe */
1339 pElement = pElement->pNext;
1342 /* If stack is empty (if not empty, still pushing the current strip
1343 thru the pipe): if last strip, do cleanup and exit, else downcount
1344 nStrips (if != 0 => all strips) and return if 0.
1346 if (pPipe->stackIndex <= 0) {
1347 if (pPipe->lastStrip) {
1348 ilError error = ilCleanupRunningPipe (pPipe, FALSE);
1350 return IL_EXECUTE_COMPLETE;
1352 pPipe->o.p.context->errorInfo = error;
1353 pPipe->o.p.context->error = (error < 0) ?
1354 IL_ERROR_USER_PIPE_ELEMENT : IL_ERROR_PIPE_ELEMENT;
1355 return IL_EXECUTE_ERROR;
1358 if ((nStrips != 0) && (--nStrips <= 0))
1359 return IL_EXECUTE_AGAIN;
1362 } /* END while true: execute strips */
1363 } /* END switch pipe state */