Bool core_swstart_run(core_init_t initialisers[], size_t n_init, SWSTART *params) { size_t i ; HQASSERT(core_init_state == CORE_DOING_SWSTART, "Running SwStart initialisers when not in SwStart()") ; HQTRACE(trace_initialisers, ("Doing starters ...")); for (i = 0 ; i < n_init ; ++i, ++core_init_error ) { if ( initialisers[i].fns.swstart ) { HQTRACE(trace_initialisers, ("Starting: %s", initialisers[i].name)); if ( force_module_fail(initialisers[i].name, FAIL_PHASE_START) || !(*initialisers[i].fns.swstart)(params) ) { HQTRACE(trace_initialisers, ("... failed")); /* A previous phase may have successfully initialised modules after this one in the list, so run all of the finalisers. */ core_finish_run(initialisers, n_init) ; return core_init_failed(initialisers[i].name) ; } initialisers[i].needs_finish = TRUE ; } } HQTRACE(trace_initialisers, ("... starters finished.")); return TRUE ; }
Bool core_swinit_run(core_init_t initialisers[], size_t n_init, SWSTART *params) { size_t i ; HQASSERT(core_init_state == CORE_DOING_SWINIT, "Running SwInit initialisers when not in SwInit()") ; HQTRACE(trace_initialisers, ("Doing initialisers ...")); for (i = 0 ; i < n_init ; ++i, ++core_init_error ) { if ( initialisers[i].fns.swinit ) { HQTRACE(trace_initialisers, ("Initializing: %s", initialisers[i].name)); if ( force_module_fail(initialisers[i].name, FAIL_PHASE_INIT) || !(*initialisers[i].fns.swinit)(params) ) { HQTRACE(trace_initialisers, ("... failed")); /* In this case we know that no previous phases have run, so we can use the current number as the number of finalisers to check. */ core_finish_run(initialisers, i) ; return core_init_failed(initialisers[i].name) ; } initialisers[i].needs_finish = TRUE ; } } HQTRACE(trace_initialisers, ("... initialisers finished.")); return TRUE ; }
static int dll_u_feof(const void *context, void *filestream) { DEVICELIST *os ; DEVICETYPE *dev ; int32 *last_error = (int32 *)context ; DEVICE_FILEDESCRIPTOR handle = Dll_PtrToHandle(filestream) ; Hq32x2 size ; HQTRACE(!swstart_called, ("ICU feof() called before SwStart()")) ; if ( !os_device(&os, &dev) || handle < 0 ) { *last_error = TRUE ; return TRUE ; } if ( (*dev->bytes_file)(os, handle, &size, SW_BYTES_AVAIL_REL) < 0 ) { *last_error = ((*dev->last_error)(os) != DeviceNoError) ; return TRUE ; } *last_error = FALSE ; return FALSE ; }
static int32 dll_u_fwrite(const void *context, const void *addr, int32 bytes, void *filestream) { DEVICELIST *os ; DEVICETYPE *dev ; int32 *last_error = (int32 *)context ; DEVICE_FILEDESCRIPTOR handle = Dll_PtrToHandle(filestream) ; int32 size ; HQTRACE(!swstart_called, ("ICU fwrite() called before SwStart()")) ; if ( !os_device(&os, &dev) || addr == NULL || bytes < 0 || handle < 0 ) { *last_error = TRUE ; return 0 ; } if ( (size = (*dev->write_file)(os, handle, (uint8 *)addr, bytes)) < 0 ) { *last_error = ((*dev->last_error)(os) != DeviceNoError) ; return 0 ; } *last_error = FALSE ; return size ; }
void core_finish_run(core_init_t initialisers[], size_t n_init) { HQTRACE(trace_initialisers, ("Doing finishers ...")); /* Call finish functions in reverse order. */ while ( n_init-- > 0 ) { if (initialisers[n_init].needs_finish) { if ( initialisers[n_init].fns.finish != NULL ) { /* Report module being finished to track crashes. */ HQTRACE(trace_initialisers, ("Finishing: %s", initialisers[n_init].name)); (*initialisers[n_init].fns.finish)(); } initialisers[n_init].needs_finish = FALSE ; } } HQTRACE(trace_initialisers, ("... finishers finished.")); }
/** Set the region height, limited by MaxBackdropHeight. */ void set_region_size(DL_STATE *page) { int32 band_height = page->band_lines ; int32 max_height = page->max_region_height ; HQASSERT(max_height >= 0, "Max region height should not be negative") ; /** \todo ajcd 2009-12-09: Set the region width. This is taken from the transparency surface, if it is found. We default to the original backdrop region width if no transparency surface is found, just so nothing explodes. If the pagedevice parameter MaxBackdropWidth is set, it only applies if the backdrop has a variable width. */ page->region_width = REGION_WIDTH ; if ( page->surfaces != NULL ) { const transparency_surface_t *transurf ; if ( (transurf = surface_find_transparency(page->surfaces)) != NULL ) { HQASSERT(transurf->region_width >= 0, "Transparency surface region width should not be negative") ; if ( transurf->region_width == 0 ) { page->region_width = page->page_w ; if ( page->max_region_width > 0 && page->region_width > page->max_region_width ) page->region_width = page->max_region_width ; } else page->region_width = transurf->region_width ; } } if ( band_height > max_height && max_height > 0 ) { /* If the band height is very large, we try to limit the region size. We try to find an exact factor of the band height as close as possible to the max region height. This algorithm just uses trial division for the factorisation, because we don't expect MaxBackdropHeight to be set very large. If there is only one band, then we can select the exact max backdrop height we wanted. */ if ( page->sizedisplaylist > 1 ) { while ( max_height > 1 ) { if ( band_height % max_height == 0 ) { page->region_height = max_height ; return ; } --max_height ; } /* We've run out of possibilities. Since we can't exceed max_height, we'll have to use a region height of 1. This will probably cause trouble. */ HQTRACE(TRUE, ("Setting region height to 1 is likely to be very inefficient")); } page->region_height = max_height ; return ; } page->region_height = band_height ; }
Bool core_postboot_run(core_init_t initialisers[], size_t n_init) { size_t i ; HQTRACE(trace_initialisers, ("Doing postboot ...")); for (i = 0 ; i < n_init ; ++i, ++core_init_error ) { if ( initialisers[i].fns.postboot ) { HQTRACE(trace_initialisers, ("PostBoot: %s", initialisers[i].name)); if ( force_module_fail(initialisers[i].name, FAIL_PHASE_POSTBOOT) || !(*initialisers[i].fns.postboot)() ) { HQTRACE(trace_initialisers, ("... failed")); /* A previous phase may have successfully initialised modules after this one in the list, so run all of the finalisers. */ core_finish_run(initialisers, n_init) ; return core_init_failed(initialisers[i].name) ; } initialisers[i].needs_finish = TRUE ; } } HQTRACE(trace_initialisers, ("... postbooters finished.")); return TRUE ; }
static int dll_u_ferror(const void *context, void *filestream) { DEVICELIST *os ; DEVICETYPE *dev ; int32 *last_error = (int32 *)context ; DEVICE_FILEDESCRIPTOR handle = Dll_PtrToHandle(filestream) ; HQTRACE(!swstart_called, ("ICU ferror() called before SwStart()")) ; if ( !os_device(&os, &dev) || handle < 0 || *last_error ) return TRUE ; return FALSE ; }
static void dll_u_fclose(const void *context, void *filestream) { DEVICELIST *os ; DEVICETYPE *dev ; int32 *last_error = (int32 *)context ; DEVICE_FILEDESCRIPTOR handle = Dll_PtrToHandle(filestream) ; HQTRACE(!swstart_called, ("ICU fclose() called before SwStart()")) ; if ( !os_device(&os, &dev) || handle < 0 ) { *last_error = TRUE ; return ; } if ( (*dev->close_file)(os, handle) < 0 ) { *last_error = ((*dev->last_error)(os) != DeviceNoError) ; return ; } *last_error = FALSE ; }
static Bool genericFilterLastError( FILELIST *filter ) { Bool result = FALSE; DEVICELIST *dev; HQTRACE( debug_filters , ( "In genericFilterLastError" )) ; /* I (JJ) am not totally convinced by this test. It's throwing an error from * the device if one hasn't already been thrown by the filter code. * Right or wrong, it corresponds to what was there before. */ if ( newerror <= 0 ) { dev = theIDeviceList( filter ) ; HQASSERT( dev, "Null device in genericFilterLastError" ); result = device_error_handler( dev ) ; } if ( isIOpenFile( filter )) (void)genericFilterCloseAbort( filter , TRUE ) ; return result ; }
static int dll_u_fremove(const void *context, const char *filename) { DEVICELIST *os ; DEVICETYPE *dev ; int32 *last_error = (int32 *)context ; HQTRACE(!swstart_called, ("ICU fremove() called before SwStart()")) ; if ( !os_device(&os, &dev) || filename == NULL ) { *last_error = TRUE ; return -1 ; } if ( (*dev->delete_file)(os, (uint8 *)filename) < 0 ) { *last_error = ((*dev->last_error)(os) != DeviceNoError) ; return -1 ; } *last_error = FALSE ; return 0 ; }
static Bool genericDecodeBuffer( FILELIST *filter, int32 *ret_bytes ) /* called from fillbuff() */ { DEVICELIST *dev; uint8 *buff; int32 nbytes, len; HQTRACE( debug_filters , ( "In genericDecodeBuffer" )) ; dev = theIDeviceList( filter ); HQASSERT(dev, "encountered bad filter"); buff = theIBuffer( filter ); len = theIBufferSize( filter ); nbytes = (*theIReadFile( dev ))( dev, theIDescriptor(filter), buff, len ); if ( nbytes >= 0 ) { *ret_bytes = nbytes ; return TRUE; } return device_error_handler( dev ); }
/* Initialise XPS PrintTicket state for the start of a new Job. */ void pt_init( /*@out@*/ /*@notnull@*/ XPS_PT* pt) { device_iterator_t dev_iter; HQASSERT((pt != NULL), "pt_init: state pointer NULL"); /* Always start with job scope */ pt->scope = PT_SCOPE_JOB; /* No start file associated with scope yet */ pt->scope_file = onothing; /* Struct copy to set slot properties */ /* Find first mounted and enable XPS PT device */ for ( pt->device = device_first(&dev_iter, DEVICEENABLED|DEVICEWRITABLE|DEVICERELATIVE); pt->device != NULL; pt->device = device_next(&dev_iter) ) { /** \todo TODO Add PT device number as constant when can add swdevice.h */ if ( theIDevTypeNumber(theIDevType(pt->device)) == XPSPT_DEVICE_TYPE ) { #ifdef DEBUG_BUILD { /* Check no other PT devices are enabled! */ DEVICELIST* dev = device_next(&dev_iter); while ( dev != NULL ) { HQTRACE(theIDevTypeNumber(theIDevType(dev)) == XPSPT_DEVICE_TYPE, ("Warning: Found another enabled PT device: %s\n", theIDevName(dev))); dev = device_next(&dev_iter); } } #endif /* DEBUG_BUILD */ break; } } } /* pt_init */
static void *dll_u_fopen(const void *context, const char *filename, const char *mode) { DEVICELIST *os ; DEVICETYPE *dev ; int32 *last_error = (int32 *)context ; int32 openflags = 0 ; DEVICE_FILEDESCRIPTOR handle ; HQTRACE(!swstart_called, ("ICU fopen('%s','%s') called before SwStart()", filename, mode)) ; if ( !os_device(&os, &dev) || filename == NULL || mode == NULL ) { *last_error = TRUE ; return NULL ; } switch ( mode[0] ) { case 'r': openflags |= SW_RDONLY ; break ; case 'w': openflags |= SW_WRONLY|SW_CREAT|SW_TRUNC ; break ; default: *last_error = TRUE ; return NULL ; } if ( (handle = (*dev->open_file)(os, (uint8 *)filename, openflags)) < 0 ) { *last_error = ((*dev->last_error)(os) != DeviceNoError) ; return NULL ; } *last_error = FALSE ; return Dll_HandleToPtr(handle) ; }
static void rbt_rightrotate( /*@in@*/ RBT_ROOT *root , /*@in@*/ RBT_NODE *x ) { RBT_NODE *y = x->left ; HQASSERT( y != &( root->nil ) , "Left descendent shouldn't be a leaf." ) ; HQTRACE( rbt_debug , ( "rbt_rightrotate: [%x] %x , %x" , root , x->key , y->key )) ; /* Turn y's right subtree into x's left subtree. */ x->left = y->right ; if ( y->right != &( root->nil ) ) { y->right->p = x ; } /* Link x's parent to y. */ y->p = x->p ; if ( x->p == &( root->nil ) ) { root->node = y ; } else { if ( x == x->p->right ) { x->p->right = y ; } else { x->p->left = y ; } } /* Put x on y's right. */ y->right = x ; x->p = y ; }
static void dll_u_frewind(const void *context, void *filestream) { DEVICELIST *os ; DEVICETYPE *dev ; int32 *last_error = (int32 *)context ; DEVICE_FILEDESCRIPTOR handle = Dll_PtrToHandle(filestream) ; Hq32x2 where ; HQTRACE(!swstart_called, ("ICU frewind() called before SwStart()")) ; if ( !os_device(&os, &dev) || handle < 0 ) { *last_error = TRUE ; return ; } Hq32x2FromUint32(&where, 0) ; if ( (*dev->seek_file)(os, handle, &where, SW_SET) < 0 ) { *last_error = ((*dev->last_error)(os) != DeviceNoError) ; return ; } *last_error = FALSE ; }
static Bool genericFilterInit( FILELIST *filter , OBJECT *args , STACK *stack ) { DEVICELIST *dlist; uint8 *buff; DEVICE_FILEDESCRIPTOR desc; int32 flag; int32 pop_args = 0 ; HQTRACE( debug_filters , ( "In genericFilterInit" )) ; dlist = theIDeviceList( filter ); HQASSERT(dlist, "encountered bad filter"); theINextDev( dlist ) = ( DEVICELIST *)filter; /* connect up strs */ HQASSERT(args != NULL || stack != NULL, "Arguments and stack should not both be empty") ; if ( ! args && !isEmpty(*stack) ) { args = theITop(stack) ; if ( oType(*args) == ODICTIONARY ) pop_args = 1 ; } if ( args && oType(*args) == ODICTIONARY ) { if ( ! oCanRead(*oDict(*args)) && ! object_access_override(oDict(*args))) return error_handler(INVALIDACCESS ) ; if ( ! FilterCheckArgs( filter , args )) return FALSE ; OCopy( theIParamDict( filter ), *args ) ; } else args = NULL ; /* Get underlying source/target if we have a stack supplied. */ if ( stack ) { if ( theIStackSize(stack) < pop_args ) return error_handler(STACKUNDERFLOW) ; if ( ! filter_target_or_source(filter, stackindex(pop_args, stack)) ) return FALSE ; ++pop_args ; } if ( args ) { if ( ! walk_dictionary( args, device_set_params, (void *)dlist) ) return FALSE ; } /* allocate space for buffer */ theIBufferSize( filter ) = (*theIGetBuffSize( dlist ))( dlist ); buff = ( uint8 * )mm_alloc( mm_pool_temp , theIBufferSize( filter ) + 4 , MM_ALLOC_CLASS_FILTER_BUFFER ) ; if ( buff == NULL ) return error_handler( VMERROR ) ; theIBuffer( filter ) = buff + 4 ; theIPtr( filter ) = buff + 4 ; theICount( filter ) = 0 ; theIFilterState( filter ) = FILTER_INIT_STATE ; if ( isIInputFile( filter )) flag = SW_RDONLY ; else /* assume isIOutputFile is TRUE */ flag = SW_WRONLY ; /* open a file on the transform device */ desc = ( * theIOpenFile( dlist ))( dlist , NULL , flag ) ; if ( desc < 0 ) return device_error_handler(dlist); theIDescriptor( filter ) = desc ; HQASSERT(pop_args == 0 || stack != NULL, "Popping args but no stack") ; if ( pop_args > 0 ) npop(pop_args, stack) ; return TRUE ; }
Bool externalfilter_(ps_context_t *pscontext) { OBJECT *o1, *o2 ; int32 dev_number, name_length ; uint8 *filter_name ; UNUSED_PARAM(ps_context_t *, pscontext) ; HQTRACE( debug_filters , ( "Welcome to externalfilter" )) ; /* externalfilter is always called with two args on the stack, even if the second one isn't used */ if ( theStackSize( operandstack ) < 1 ) return error_handler( STACKUNDERFLOW ) ; o1 = theTop( operandstack ) ; /* integer code or dictionary */ switch ( oType(*o1) ) { case OINTEGER: dev_number = oInteger(*o1); break ; case ODICTIONARY: o2 = stackindex( 1, &operandstack ) ; /* filter name */ return filter_external_define( o1 , o2 ); /* device to be added */ default: return error_handler(TYPECHECK) ; } if ( dev_number == -3 ) { /* resourceforall */ pop( &operandstack ) ; return filter_external_forall(&operandstack); } o2 = stackindex(1, &operandstack ) ; /* filter name */ switch ( oType(*o2) ) { case ONAME: filter_name = theICList(oName(*o2)) ; name_length = theINLen(oName(*o2)) ; break ; case OSTRING: /* undocumented - but they allow strings as an argument */ filter_name = oString(*o2) ; name_length = theLen(*o2) ; break ; default: return error_handler( TYPECHECK ) ; } switch ( dev_number ) { case -2: /* findresource */ if ( filter_external_exists(filter_name, name_length) ) { Copy(o1, &tnewobj) ; } else { Copy(o1, &fnewobj) ; } return TRUE ; case -1: /* undefineresource */ npop(2, &operandstack) ; return filter_external_undefine(filter_name, name_length); } return error_handler(RANGECHECK) ; }
static int32 genericFilterCloseAbort( FILELIST * filter, int32 fAbort ) { /* close transform file and dismount transform device if no other filter of this type is active */ int32 result = 0 ; DEVICELIST *dlist ; FILELIST *uflptr ; HQASSERT( filter , "filter NULL in genericFilterCloseAbort." ) ; HQTRACE( debug_filters , ( "In genericFilterCloseAbort" )) ; dlist = theIDeviceList( filter ) ; SetIClosingFlag( filter ) ; if ( isIOutputFile( filter )) result = ( *theIMyFlushFile( filter ))( filter ) ; uflptr = theIUnderFile( filter ) ; if ( uflptr && isICST( filter ) && isIOpenFileFilterById( theIUnderFilterId( filter ) , uflptr )) { /* While this filter may be being closed implicitly, the closing of the * source is explicit */ if (( *theIMyCloseFile( uflptr ))( uflptr, CLOSE_EXPLICIT ) == EOF ) result = EOF ; } if ( dlist ) { DEVICE_FILEDESCRIPTOR desc = theIDescriptor( filter ) ; HQASSERT( theIBuffer( filter ) != NULL , "encountered bad filter" ) ; if ( fAbort ) (void)( *theIAbortFile( dlist ))( dlist , desc ) ; else (void)( *theICloseFile( dlist ))( dlist , desc ) ; (void)closeReadFileProgress( filter ) ; /* call to dismount device unconditional */ (void)( *theIDevDismount( dlist ))( dlist ) ; device_free(dlist) ; theIDeviceList( filter ) = NULL ; } if (theIBuffer(filter)) { mm_free( mm_pool_temp , ( mm_addr_t )( theIBuffer( filter ) - 4 ) , ( mm_size_t )( theIBufferSize( filter ) + 4 )) ; theIBuffer( filter ) = NULL ; } ClearIClosingFlag( filter ) ; SetIEofFlag( filter ) ; if ( ! isIRewindable( filter )) ClearIOpenFlag( filter ) ; return result ; }
RBT_NODE *rbt_remove( RBT_ROOT *root , RBT_NODE *z ) { RBT_NODE *x ; RBT_NODE *y ; if ( z == &( root->nil ) ) { return NULL ; } HQTRACE( rbt_debug , ( "rbt_remove: [%x] %x" , root , z->key )) ; if ( z->left == &( root->nil ) || z->right == &( root->nil ) ) { y = z ; } else { y = rbt_successor( root , z ) ; } HQASSERT( y != NULL , "Should rbt_successor return NULL?" ) ; if ( y->left != &( root->nil ) ) { x = y->left ; } else { x = y->right ; } x->p = y->p ; if ( y->p == &( root->nil ) ) { root->node = x ; } else { if ( y == y->p->left ) { y->p->left = x ; } else { y->p->right = x ; } } if ( y != z ) { uintptr_t tk ; void *td ; /* The example pseudo-code just copies data and "other fields" from y to z. That's not good enough when any one of them is a pointer: we end up with one data struct being doubly referenced and the other one orphaned. Solution: swap the pointers instead. */ tk = z->key ; z->key = y->key ; y->key = tk ; td = z->data ; z->data = y->data ; y->data = td ; } if ( y->red == FALSE ) { rbt_remove_fixup( root , x ) ; } root->count-- ; rbt_validate( root , root->node , NULL ) ; return y ; }
static void rbt_remove_fixup( RBT_ROOT *root , RBT_NODE *x ) { RBT_NODE *w ; while ( x != root->node && ! x->red ) { HQTRACE( rbt_debug , ( "rbt_remove_fixup: [%x] %x" , root , x->key )) ; if ( x == x->p->left ) { w = x->p->right ; if ( w->red ) { w->red = FALSE ; x->p->red = TRUE ; rbt_leftrotate( root , x->p ) ; w = x->p->right ; } if ( ! w->left->red && ! w->right->red ) { w->red = TRUE ; x = x->p ; } else { if ( ! w->right->red ) { w->left->red = FALSE ; w->red = TRUE ; rbt_rightrotate( root , w ) ; w = x->p->right ; } w->red = x->p->red ; x->p->red = FALSE ; w->right->red = FALSE ; rbt_leftrotate( root , x->p ) ; x = root->node ; } } else { w = x->p->left ; if ( w->red ) { w->red = FALSE ; x->p->red = TRUE ; rbt_rightrotate( root , x->p ) ; w = x->p->left ; } if ( ! w->right->red && ! w->left->red ) { w->red = TRUE ; x = x->p ; } else { if ( ! w->left->red ) { w->right->red = FALSE ; w->red = TRUE ; rbt_leftrotate( root , w ) ; w = x->p->left ; } w->red = x->p->red ; x->p->red = FALSE ; w->left->red = FALSE ; rbt_rightrotate( root , x->p ) ; x = root->node ; } } } x->red = FALSE ; HQTRACE( rbt_debug , ( "rbt_remove_fixup complete: [%x] %x" , root , x->key )) ; rbt_validate( root , root->node , NULL ) ; }
void rbt_insert( /*@in@*/ RBT_ROOT *root , RBT_NODE *x ) { RBT_NODE *y ; rbt_validate( root , root->node , NULL ) ; HQTRACE( rbt_debug , ( "rbt_insert: [%x] %x" , root , x->key )) ; bt_insert( root , x ) ; x->red = TRUE ; while ( x != root->node && x->p->red ) { if ( x->p == x->p->p->left ) { y = x->p->p->right ; if ( y->red ) { x->p->red = FALSE ; y->red = FALSE ; x->p->p->red = TRUE ; x = x->p->p ; } else { if ( x == x->p->right ) { x = x->p ; rbt_leftrotate( root , x ) ; } x->p->red = FALSE ; x->p->p->red = TRUE ; rbt_rightrotate( root , x->p->p ) ; } } else { y = x->p->p->left ; if ( y->red ) { x->p->red = FALSE ; y->red = FALSE ; x->p->p->red = TRUE ; x = x->p->p ; } else { if ( x == x->p->left ) { x = x->p ; rbt_rightrotate( root , x ) ; } x->p->red = FALSE ; x->p->p->red = TRUE ; rbt_leftrotate( root , x->p->p ) ; } } } root->node->red = FALSE ; root->count++ ; rbt_validate( root , root->node , NULL ) ; }
void HqStr__Test(void) { #define BUF_SIZE 50 char abBuf[BUF_SIZE]; /* The following strings end at the embedded null character. The four * plus-signs that follow the null character should never be read or * copied by HqStrCopy or HqStrCopyTrunc. */ #define LARGE_SIZE 40 #define LARGE_MAXLEN LARGE_SIZE-1 char *pbzLarge = "nine-long character sequences 123456789\0++++"; #define MEDIUM_SIZE 24 #define MEDIUM_MAXLEN MEDIUM_SIZE-1 #define SMALL_SIZE 5 #define SMALL_MAXLEN SMALL_SIZE-1 char *pbzSmall = "tiny\0++++"; #define EMPTY_SIZE 1 #define EMPTY_MAXLEN EMPTY_SIZE-1 char *pbzEmpty = "\0++++"; static int HqStr__TestDoDangerous = FALSE; char *src, *dest; int i; #if 1 /* Copy and Trunc */ /* ============== */ /* Copy a Large string to a destination just big enough */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzLarge; dest = HqStrCopy(dest, src, LARGE_SIZE); HQTRACE( TRUE, ("Copy a Large string to a destination just big enough\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); /* Copy a Small string to a Large destination, pad with zeroes */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzSmall; dest = HqStrCopy(dest, src, LARGE_SIZE); /* this will not have read beyond strlen(src) -- no easy way to check for this though! */ HQTRACE( TRUE, ("Copy a Small string to a Large destination, pad with zeroes\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); /* Copy an Empty string to a One-byte destination just big enough */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzEmpty; dest = HqStrCopy(dest, src, EMPTY_SIZE); HQTRACE( TRUE, ("Copy an Empty string to a One-byte destination just big enough\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); /* Copy string to a zero-sized destination (should do nothing) */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzEmpty; dest = HqStrCopy(dest, src, 0); HQTRACE( TRUE, ("Copy string to a zero-sized destination (should do nothing)\n" "no-got! followby(%s) from(%s).", dest+0, src) ); if (HqStr__TestDoDangerous) { /* BEWARE: If you 'ignore' the assert on * this test, memory will be nuked. */ /* Copy string to a NEGATIVE-SIZED destination */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzSmall; dest = HqStrCopy(dest, src, -1); HQTRACE( TRUE, ("Copy string to a NEGATIVE-SIZED destination\n" "no-got! followby(%s) from(%s).", dest+0, src) ); } /* Copy a Large string to a destination that's TOO SMALL */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzLarge; dest = HqStrCopy(dest, src, MEDIUM_SIZE); /* Asserts! (but still terminates safely, and doesn't write more than destsize bytes) */ HQTRACE( TRUE, ("Copy a Large string to a destination that's TOO SMALL\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); /* CopyTrunc a Large string to a smaller destination */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzLarge; dest = HqStrCopyTrunc(dest, src, MEDIUM_SIZE); HQTRACE( TRUE, ("CopyTrunc a Large string to a smaller destination\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); /* Copy Overlapping? */ /* ================= */ /* Copy to an immediately following, but not overlapping, destination */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; memset(abBuf, 'S', SMALL_SIZE-1); abBuf[SMALL_SIZE-1] = 0; dest = abBuf+SMALL_SIZE; src = abBuf; dest = HqStrCopy(dest, src, SMALL_SIZE); HQTRACE( TRUE, ("Copy to an immediately following, but not overlapping, destination\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); /* Copy to an immediately preceding, but not overlapping, destination */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; memset(abBuf+SMALL_SIZE, 'S', SMALL_SIZE-1); abBuf[SMALL_SIZE+SMALL_SIZE-1] = 0; dest = abBuf; src = abBuf+SMALL_SIZE; dest = HqStrCopy(dest, src, SMALL_SIZE); HQTRACE( TRUE, ("Copy to an immediately preceding, but not overlapping, destination\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); /* Copy from short string to an immediately following, but not overlapping, longer destination */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; memset(abBuf, 'S', SMALL_SIZE-1); abBuf[SMALL_SIZE-1] = 0; dest = abBuf+SMALL_SIZE; src = abBuf; dest = HqStrCopy(dest, src, MEDIUM_SIZE); HQTRACE( TRUE, ("Copy from short string to an immediately following, but not overlapping, longer destination\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); /* Copy to an OVERLAPPING following destination */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; memset(abBuf, 'S', SMALL_SIZE-1); abBuf[SMALL_SIZE-1] = 0; dest = abBuf+SMALL_SIZE-1; src = abBuf; dest = HqStrCopy(dest, src, SMALL_SIZE); /* Assert! overlapping! */ HQTRACE( TRUE, ("Copy to an OVERLAPPING following destination\n" "got(%s) followby(%s) from-now-corrupt(%s).", dest, dest+strlen(dest)+1, src) ); /* Copy to an OVERLAPPING preceding destination */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; memset(abBuf+SMALL_SIZE, 'S', SMALL_SIZE-1); abBuf[SMALL_SIZE+SMALL_SIZE-1] = 0; dest = abBuf+1; src = abBuf+SMALL_SIZE; dest = HqStrCopy(dest, src, SMALL_SIZE); /* Assert! overlapping! */ HQTRACE( TRUE, ("Copy to an OVERLAPPING preceding destination\n" "got(%s) followby(%s) from-now-corrupt(%s).", dest, dest+strlen(dest)+1, src) ); /* TruncCopy small initial portion to a destination that overlaps src string but not the portion being copied */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; memset(abBuf, 'M', MEDIUM_SIZE-1); abBuf[MEDIUM_SIZE-1] = 0; dest = abBuf+SMALL_SIZE; src = abBuf; dest = HqStrCopyTrunc(dest, src, SMALL_SIZE); /* Truncate as requested. Src gets corrupted, but not our problem. */ HQTRACE( TRUE, ("TruncCopy small initial portion to a destination that overlaps src string but not the portion being copied\n" "got(%s) followby(%s) from-now-corrupt(%s).", dest, dest+strlen(dest)+1, src) ); #endif #if 1 /* the check macro */ /* =============== */ /* ASSERTCHECK_HqStrBlat confirms that the storage sizes for two * strings match, confirming that HqStrBlat between these strings will * be safe. If the sizes don't match, it should assert, but only once. */ for (i=1; i<=2; i++) { ASSERTCHECK_HqStrBlat( BUF_SIZE , MEDIUM_SIZE ); /* fails! */ ASSERTCHECK_HqStrBlat( MEDIUM_SIZE , MEDIUM_SIZE+1 ); /* fails! */ ASSERTCHECK_HqStrBlat( MEDIUM_SIZE , MEDIUM_SIZE ); /* okay */ /* Only assert once -- second pass should be silent */ } #endif #if 1 /* Blat and Blind */ /* ============== */ /* Blat from a small string to small storage */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzSmall; dest = HqStrBlat(dest, src, SMALL_SIZE); HQTRACE( TRUE, ("Blat from a small string to small storage\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); /* Blat, ILLEGALLY, from a small string to medium storage */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzSmall; dest = HqStrBlat(dest, src, MEDIUM_SIZE); /* unsafe! reads beyond strlen(src) */ HQTRACE( TRUE, ("Blat, ILLEGALLY, from a small string to medium storage\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); /* Blat, ILLEGALLY, from a large string to medium storage */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzLarge; dest = HqStrBlat(dest, src, MEDIUM_SIZE); /* unsafe! doesn't terminate copy */ HQTRACE( TRUE, ("Blat, ILLEGALLY, from a large string to medium storage\n" "got(%s) from(%s).", dest, src) ); /* CopyBlind from what happens to be a large string into what happens to be sufficient storage */ memset(abBuf, '^', BUF_SIZE-1); abBuf[BUF_SIZE-1] = 0; dest = abBuf; src = pbzLarge; dest = HqStrCopyBlind(dest, src); /* Works, because we 'know' that strlen(pbzLarge)+1 will fit in abBuf's storage */ HQTRACE( TRUE, ("CopyBlind from what happens to be a large string into what happens to be sufficient storage\n" "got(%s) followby(%s) from(%s).", dest, dest+strlen(dest)+1, src) ); #endif #if 0 /* HqStr__Test should produce the following asserts and traces. * (Explicit file-and-line has been changed to "<in hqstr.c>") */ /* <in hqstr.c>: Copy a Large string to a destination just big enough got(nine-long character sequences 123456789) followby(^^^^^^^^^) from(nine-long character sequences 123456789). <in hqstr.c>: Copy a Small string to a Large destination, pad with zeroes got(tiny) followby() from(tiny). <in hqstr.c>: Copy an Empty string to a One-byte destination just big enough got() followby(^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^) from(). <in hqstr.c>: Copy string to a zero-sized destination (should do nothing) no-got! followby(^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^) from(). Assert failed <in hqstr.c>: HqStrCopy: string was truncated <in hqstr.c>: Copy a Large string to a destination that's TOO SMALL got(nine-long character seq) followby(^^^^^^^^^^^^^^^^^^^^^^^^^) from(nine-long character sequences 123456789). <in hqstr.c>: CopyTrunc a Large string to a smaller destination got(nine-long character seq) followby(^^^^^^^^^^^^^^^^^^^^^^^^^) from(nine-long character sequences 123456789). <in hqstr.c>: Copy to an immediately following, but not overlapping, destination got(SSSS) followby(^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^) from(SSSS). <in hqstr.c>: Copy to an immediately preceding, but not overlapping, destination got(SSSS) followby(SSSS) from(SSSS). <in hqstr.c>: Copy from short string to an immediately following, but not overlapping, longer destination got(SSSS) followby() from(SSSS). Assert failed <in hqstr.c>: HqStrCopy: dest and src must not overlap Assert failed <in hqstr.c>: HqStrCopy: string was truncated <in hqstr.c>: Copy to an OVERLAPPING following destination got(SSSS) followby(^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^) from-now-corrupt(SSSSSSSS). Assert failed <in hqstr.c>: HqStrCopy: dest and src must not overlap <in hqstr.c>: Copy to an OVERLAPPING preceding destination got(SSSS) followby(SSS) from-now-corrupt(). <in hqstr.c>: TruncCopy small initial portion to a destination that overlaps src string but not the portion being copied got(MMMM) followby(MMMMMMMMMMMMM) from-now-corrupt(MMMMMMMMM). Assert failed <in hqstr.c>: BUF_SIZE and MEDIUM_SIZE are no longer of equal magnitude; there are calls to HqStrBlat between strings with storage of these sizes, and these calls are now broken; you must use HqStrCopy instead. Assert failed <in hqstr.c>: MEDIUM_SIZE and MEDIUM_SIZE+1 are no longer of equal magnitude; there are calls to HqStrBlat between strings with storage of these sizes, and these calls are now broken; you must use HqStrCopy instead. <in hqstr.c>: Blat from a small string to small storage got(tiny) followby(^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^) from(tiny). <in hqstr.c>: Blat, ILLEGALLY, from a small string to medium storage got(tiny) followby(++++) from(tiny). <in hqstr.c>: Blat, ILLEGALLY, from a large string to medium storage got(nine-long character sequ^^^^^^^^^^^^^^^^^^^^^^^^^) from(nine-long character sequences 123456789). <in hqstr.c>: CopyBlind from what happens to be a large string into what happens to be sufficient storage got(nine-long character sequences 123456789) followby(^^^^^^^^^) from(nine-long character sequences 123456789). */ #endif }
/** Implementation for pdf_lookupxref(), with additional support for a stack of nested objnum's. If the objnum matches an objnum in the stack, it means that the original object is cyclic and there's no need to continue, and if we did it'll go infinite. 'idMatch' will be set to TRUE if the objnum matches one in the stack, otherwise FALSE. This allows repeated lookups of the same object within a particular context (such as pdf_resolvexrefs()) to be detected. */ static Bool pdf_lookupxref_with_id( PDFCONTEXT *pdfc , OBJECT **rpdfobj , int32 objnum , uint16 objgen , Bool streamDictOnly , Bool* idMatch ) { XREFCACHE *xrefcache ; XREFCACHE **p_xrefcache ; OBJECT *pdfobj ; int i; GET_PDFXC_AND_IXC; HQASSERT( rpdfobj != NULL && idMatch != NULL, "pdf_lookupxref_with_id - parameters cannot be null."); HQASSERT( objnum >= 0 , "pdf_lookupxref_with_id - object number must not be -ve" ) ; HQTRACE( pdftrace_xreflookups , ( "%d %d obj" , objnum , objgen )) ; pdfobj = NULL ; *rpdfobj = NULL ; *idMatch = FALSE ; /* Look up pdfobj in cache. */ for ( p_xrefcache = &pdfxc->xrefcache[ objnum & (XREF_CACHE_SIZE-1) ] ; (xrefcache = *p_xrefcache) != NULL ; p_xrefcache = &xrefcache->xrefnxt ) { if ( xrefcache->objnum == objnum ) { if ( xrefcache->streamDict != XREF_StreamDict || streamDictOnly ) { /* Move entry to start of list */ *p_xrefcache = xrefcache->xrefnxt; xrefcache->xrefnxt = pdfxc->xrefcache[objnum & (XREF_CACHE_SIZE - 1)]; pdfxc->xrefcache[objnum & (XREF_CACHE_SIZE - 1)] = xrefcache; #if defined( DEBUG_BUILD ) pdfxc->debugtotal_cachehits++ ; #endif HQASSERT( xrefcache->objgen == objgen , "objgen should be correct in cache" ) ; /* Update the last accessing page member to ensure that objects used on this page don't get deallocated during a sweep. */ if ( xrefcache->lastAccessId != pdfxc->pageId && xrefcache->lastAccessId >= 0 ) { if ( ! pdf_set_xref_last_access( pdfxc , xrefcache , pdfxc->pageId )) { return FALSE ; } #if defined( DEBUG_BUILD ) pdfxc->debugtotal_cachereclaims++ ; #endif } else if ( xrefcache->lastAccessId < 0 ) { /* Make sure all child objects have the same negative lastAccessId as the parent, otherwise we'll end up with dangling pointers. */ if ( ! pdf_set_xref_last_access( pdfxc , xrefcache , xrefcache->lastAccessId )) { return FALSE ; } } /* Set 'idMatch' if objnum matches one in the stack, i.e. the object references are cyclic. */ HQASSERT( pdfxc->lookup_depth > 0 && pdfxc->lookup_depth <= PDF_MAX_RECURSION_DEPTH && pdfxc->nestedObjnum[pdfxc->lookup_depth - 1] == objnum, "Inconsistent nestedObjnum stack") ; for ( i = 0; i < pdfxc->lookup_depth - 1; i++ ) { if ( pdfxc->nestedObjnum[ i ] == objnum ) { HQFAIL("Self-referential PDF object - please tell us"); *idMatch = TRUE ; } } pdfobj = & xrefcache->pdfobj ; /* If object is a stream, then try to rewind it. */ if ( oType(*pdfobj) == OFILE ) { FILELIST *flptr ; /* If pdfxc is an input context, flptr will be rewindable; PDF output filters are not rewindable. Output and Rewindability are mutually exclusive, but we cannot guarantee that either are set; the rewindable flag is cleared when a PDF stream is terminated. */ flptr = oFile( *pdfobj ) ; HQASSERT(!isIOutputFile(flptr) || !isIRewindable(flptr), "Output streams should not be rewindable") ; if ( !isIOutputFile(flptr) ) { Bool rewound = FALSE ; if ( !pdf_rewindstream(pdfc, pdfobj, &rewound)) return FALSE ; } } *rpdfobj = pdfobj ; return TRUE ; } else { /* We have the stream dict cached, but now the caller wants the whole stream complete with filter chain (or vice versa, I suppose, but this was written to speed up HqnPDFChecker so the normal pattern is a flurry of calls with streamDictOnly set to TRUE during the checking phase followed by a bunch with streamDictOnly FALSE during the running of the job). Free this cache entry and drop through to build a new one. */ XREFCACHE **ref ; for ( ref = & pdfxc->xrefcache[ objnum & (XREF_CACHE_SIZE-1) ] ; *ref != xrefcache ; ref = & ( *ref )->xrefnxt ) EMPTY_STATEMENT() ; *ref = xrefcache->xrefnxt ; pdf_freexrefcache( pdfc , xrefcache ) ; /* Since we just freed the cache we found, drop out of the loop in order go and re-cache the object. */ break ; } } } /* pdfobj not found in cache; so need to read from disk. */ { FILELIST *flptr, * objfile ; OBJECT object = OBJECT_NOTVM_NOTHING ; int32 objuse ; int8 streamDict = XREF_NotStream ; flptr = pdfxc->flptr ; HQASSERT( flptr , "flptr is null in pdf_xreflookup" ) ; if ( ! pdf_seek_to_xrefobj( pdfc , flptr , objnum , objgen , & objuse, &objfile )) return FALSE ; if ( objuse == XREF_Free ) return TRUE ; theGen( object ) = objgen ; oXRefID( object ) = objnum ; if (objuse == XREF_Uninitialised) { OBJECT nullobj = OBJECT_NOTVM_NULL; Copy(&object, &nullobj); } else { PDF_CHECK_METHOD(get_xref_object) ; if (objfile == flptr) { if ( !(*pdfxc->methods.get_xref_object)(pdfc, flptr, &object, NULL /* stream info */, streamDictOnly, &streamDict) ) return FALSE ; } else { if ( !(*pdfxc->methods.get_xref_streamobj)(pdfc, objfile, &object) ) return FALSE ; if (( *theIMyCloseFile( objfile ))( objfile, CLOSE_EXPLICIT ) == EOF ) return FALSE ; } if ( oType( object ) == ONOTHING ) return error_handler( UNDEFINEDRESULT ) ; } xrefcache = pdf_allocxrefcache( pdfc , objnum , objgen , & object , streamDict ) ; if ( ! xrefcache ) { pdf_freeobject( pdfc , & object ) ; return error_handler( VMERROR ) ; } *rpdfobj = & xrefcache->pdfobj ; } return TRUE ; }
Bool setg(DL_STATE *page, int32 colorType, int32 options) { corecontext_t *context = get_core_context_interp(); int32 patternid = INVALID_PATTERN_ID, parent_patternid = INVALID_PATTERN_ID ; int32 patterntype = -1 ; size_t retryFree = 512 * 1024, retryLastFree = 0 ; STATEOBJECT newstate, *dlstate ; int saved_dl_safe_recursion = dl_safe_recursion; if (colorType != GSC_UNDEFINED) COLORTYPE_ASSERT(colorType, "setg"); HQASSERT(colorType != GSC_UNDEFINED || (options & DEVICE_SETG_GROUP) != 0, "GSC_UNDEFINED only allowed for groups") ; /* Setup a default newstate; spotno may be overriden later. */ newstate = stateobject_new(page->default_spot_no) ; if ( (options & DEVICE_SETG_GROUP) == 0 ) { /* Now call any procedures we should call on the first graphics object; note that this may potentially change the graphics state, or indeed call setg recursively. */ static Bool fRecursive = FALSE; Bool fResult; if (! fRecursive) { fRecursive = TRUE; fResult = runHooks(&thegsDevicePageDict(*gstateptr), GENHOOK_StartPainting); fRecursive = FALSE; setHookStatus(GENHOOK_StartPainting, FALSE); if (! fResult) return FALSE; } if ( theICMYKDetected( workingsave )) if ( theICMYKDetect( workingsave )) if ( gsc_getcolorspace( gstateptr->colorInfo , colorType ) == SPACE_DeviceGray ) if ( ! detect_setcmykcolor_separation(gstateptr->colorInfo)) return FALSE ; if ( colorType != GSC_UNDEFINED ) { /* Set object's rendering intent. This is overridden for vignettes, and ignored for shfills, which give the Background and body of the shfill different intents. */ if ( colorType != GSC_SHFILL && colorType != GSC_SHFILL_INDEXED_BASE && colorType != GSC_VIGNETTE ) { uint8 currentReproType; /* This is a BIG hack to get the text context right. It can be done * properly when the target work arrives. */ if (textContextLevel > 0) { currentReproType = REPRO_TYPE_TEXT; if (!gsc_setRequiredReproType( gstateptr->colorInfo , colorType , currentReproType )) return FALSE; } else currentReproType = gsc_getRequiredReproType(gstateptr->colorInfo, colorType); DISPOSITION_STORE(dl_currentdisposition, currentReproType, colorType, gstateptr->user_label ? DISPOSITION_FLAG_USER : 0); } } else /* HDLs have mixed dispositions, no use for USER flag. */ DISPOSITION_STORE(dl_currentdisposition, REPRO_DISPOSITION_MIXED, colorType, 0); } else { /* Groups have mixed dispositions, no use for USER flag. */ DISPOSITION_STORE(dl_currentdisposition, REPRO_DISPOSITION_MIXED, colorType, 0); } degenerateClipping = FALSE ; #ifdef DEBUG_BUILD if ( debug_dl_skipsetg() ) degenerateClipping = TRUE ; #endif /* Here starts the creation of the DL state for this object. Partial paints are suppressed during the construction, so that the state is not destroyed, but if memory runs out, low-memory handling is performed which may partial paint, after which the state is recreated. After the state is created, partial paints are prevented until the operator that called DEVICE_SETG() is complete. */ for (;;) { STACK_POSITIONS stackPositions; Bool errorFound = FALSE; ++dl_safe_recursion; saveStackPositions(&stackPositions); /* Find the appropriate HDL to add object for this device type and ID to */ page->targetHdl = hdlTarget(page->currentHdl, gstateptr) ; if ( ! setup_dl_clipping(page, &newstate.clipstate)) return FALSE ; if ( newstate.clipstate ) { cclip_bbox = newstate.clipstate->bounds ; } else { degenerateClipping = TRUE ; cclip_bbox = gstateptr->thePAGEinfo.theclip.bounds ; } if ( oType(gstateptr->theGSTAGinfo.dict) == ODICTIONARY ) { HQASSERT( gstateptr->theGSTAGinfo.data , "Tags dictionary present but there's nowhere to put the data" ) ; if ( gstateptr->theGSTAGinfo.structure == NULL ) { if ( !make_gstagstructureobject(page, &gstateptr->theGSTAGinfo.dict, &gstateptr->theGSTAGinfo.structure) ) { /* We *could* be out of DL memory, it could be nasty tricks, * but one likely explanation is a bug in my code - paulc */ HQFAIL( "Nasty tricks can cause this but a bug is more likely" ) ; return FALSE ; } if ( gstateptr->theGSTAGinfo.data[0] != gstateptr->theGSTAGinfo.structure->alloc_words ) { HQFAIL( "Nasty tricks can cause this but a bug is more likely" ) ; /* Get gstate into a consistent state before failing */ theTags( gstateptr->theGSTAGinfo.dict ) = ONULL | LITERAL ; /* see null_ */ gstateptr->theGSTAGinfo.structure = NULL ; mm_free( mm_pool_temp, gstateptr->theGSTAGinfo.data, gstateptr->theGSTAGinfo.data[0] * sizeof(gstateptr->theGSTAGinfo.data[0])) ; gstateptr->theGSTAGinfo.data = NULL ; return error_handler( CONFIGURATIONERROR ) ; } } #if defined( ASSERT_BUILD ) } else { HQASSERT( gstateptr->theGSTAGinfo.structure == NULL, "tstructure should have been set to NULL if dict is null." ) ; #endif } /* Use a do - while loop as an error catcher */ errorFound = TRUE; do { if ( !getTransparencyState(&gstateptr->tranState, page, colorType == GSC_STROKE, &newstate.tranAttrib) ) break; if ( colorType != GSC_UNDEFINED ) { HQASSERT(!error_signalled_context(context->error), "Should not be invoking colour chains in error condition") ; /* When invoking the color chains, some operators may cause the gstate to change. Therefore, we must not directly reference the gstate variables after this point. Instead, refer to the variables that have been nicely cached above here. We won't invoke the colour chain if colour is not required for this call (eg via gs_pseudo_erasepage, where dlc_currentcolor is already set). */ if ( !is_pseudo_erasepage() && !gsc_invokeChainSingle(gstateptr->colorInfo, colorType) ) break; /* Get the late color management state - depends on gsc_invokeChainSingle. */ if ( !getLateColorState(gstateptr, page, colorType, &newstate.lateColorAttrib) ) break; /* Pattern state should not be set up for groups, or the render loop will composite the pattern data twice. Must be called after gsc_invokeChainSingle. NB. This will likely call setg recursively. */ if ( (options & DEVICE_SETG_GROUP) == 0 && !patterncheck(page, gstateptr, colorType, &patternid, &parent_patternid, &patterntype, newstate.tranAttrib) ) break; } if ( !getPclAttrib(page, colorType == GSC_IMAGE, (options & DEVICE_SETG_RETRY) == 0 && dl_safe_recursion <= 1 && retryLastFree == 0 /* first time for this object */, &newstate.pclAttrib) ) break; errorFound = FALSE; } while (FALSE); /* End of error catcher */ /* Retry after VMERROR. Don't use newerror since it gets * cleared if the error was inside a recursive interpreter call * (patterncheck calls createPatternDL which calls interpreter) */ if ( errorFound ) { if ( error_latest_context(context->error) == VMERROR ) { int32 actionNumber = 0 ; Bool free_test = FALSE; error_clear_context(context->error); /* Loop calling handleLowMemory until freed as much as we want or none */ for (;;) { dl_safe_recursion = saved_dl_safe_recursion ; HQTRACE( debug_lowmemory, ( "CALL(handleLowMemory): setg with action %d", actionNumber )) ; actionNumber = handleLowMemory( actionNumber, TRY_NORMAL_METHODS, NULL ) ; if ( actionNumber < 0 ) return FALSE; if ( actionNumber == 0 ) /* Couldn't free up anything more */ break ; free_test = setg_test_free_mem(retryFree, page); if ( free_test ) break; } /* Retry if we have at least as much free as we tried to free last time */ if ( retryLastFree != 0 ) free_test = setg_test_free_mem(retryLastFree, page); if ( retryLastFree == 0 || free_test ) { retryLastFree = retryFree ; retryFree += retryFree ; /* Try to free twice as much next time */ if ( !restoreStackPositions(&stackPositions, FALSE) ) return FAILURE(FALSE); /* stack underflow */ continue ; /* restart outer loop */ } return error_handler(VMERROR); /* Give up */ } return FALSE; /* Some error has already been raised */ } break ; /* Successful - end outer loop */ } /* Continue preventing partial paints until the end of this operator, unless the operator is a group start. This is reset to the previous value by the interpreter loop. */ if ( (options & DEVICE_SETG_GROUP) != 0 ) dl_safe_recursion = saved_dl_safe_recursion; /* Now that we've got the colour, after possible extra loops for error * handling, we'll reset the reproType for fill & stroke chains. The other * chain types are always initialised prior to use. * NB. There is no central point where this can be done at the start of * each object. */ if ( colorType != GSC_UNDEFINED ) { if (!gsc_resetRequiredReproType(gstateptr->colorInfo, colorType)) return FALSE; } if ( patternid != INVALID_PATTERN_ID && (dl_currentspflags(page->dlc_context) & RENDER_PATTERN) != 0 ) { Bool overprinting[2] = {FALSE, FALSE}; HQASSERT(patterntype != -1, "Should have a valid patterntype by now"); if (context->userparams->PatternOverprintOverride && patterntype == 2) { overprinting[GSC_FILL] = gsc_getoverprint(gstateptr->colorInfo, GSC_FILL); overprinting[GSC_STROKE] = gsc_getoverprint(gstateptr->colorInfo, GSC_STROKE); } /* We might have a pattern screen which is actually drawn in black or white, in which case it isn't to be treated as a pattern screen at all. This should have already been checked in updateHTCacheForPatternContone. */ /** \todo @@@ TODO FIXME ajcd 2002-12-30: We shouldn't really be using currentGroup here, because a setgstate may have altered the target HDL. However, the group stack doesn't currently recognise this, and a pattern group will be opened with currentGroup is its parent, so we need to match that. We need to think about using groupTop(inputpage->targetHdl) for all currentGroup references, and allowing a tree rather than stack structure to the groups. */ newstate.patternstate = patternObjectLookup(page->stores.pattern, patternid, parent_patternid, pageBaseMatrixId, page->currentGroup, dlc_currentcolor(page->dlc_context), overprinting, newstate.tranAttrib ) ; HQASSERT(newstate.patternstate, "Pattern found but no corresponding state created") ; } /* Pattern shapes vary independently of pattern objects; a single pattern object may have multiple pattern shapes. Look at the state from the last setg to see if that pattern shape can be continued). */ if ( !patternshape_lookup(page, page->currentdlstate, &newstate) ) return FALSE ; /* Transparent objects should use the page's default screen, set up in newstate above; Override opaque objects to current gstate screen. */ if ( tsOpaque(gsTranState(gstateptr), (colorType == GSC_STROKE ? TsStroke : TsNonStroke), gstateptr->colorInfo) && (page->currentGroup == NULL || !groupMustComposite(page->currentGroup)) ) newstate.spotno = gsc_getSpotno(gstateptr->colorInfo); newstate.gstagstructure = gstateptr->theGSTAGinfo.structure ; #ifdef METRICS_BUILD /* Only update the setg count when we get here; we're only interested in how many times we query the state cache. */ dl_metrics()->store.setgCount++; #endif /* In English: * If ( there is no current dlstate set up -OR- * the clip in the gstate ISNT the same as the one in the dlstate -OR- * what we want for the pattern ISNT the same as the dlstate -OR- * the spotno in the gstate ISNT the same as the dlstate -OR- * gs tags in the gstate ISNT the same as the dlstate -OR- * soft mask in the gstate ISNT the same as the dlstate ) * then make a new dlstate record. */ dlstate = page->currentdlstate ; if ( ! dlstate || newstate.clipstate != dlstate->clipstate || newstate.patternstate != dlstate->patternstate || newstate.patternshape != dlstate->patternshape || newstate.spotno != dlstate->spotno || newstate.gstagstructure != dlstate->gstagstructure || newstate.tranAttrib != dlstate->tranAttrib || newstate.lateColorAttrib != dlstate->lateColorAttrib || newstate.pclAttrib != dlstate->pclAttrib ) { /* Set new DL state */ page->currentdlstate = (STATEOBJECT*)dlSSInsert( page->stores.state, &newstate.storeEntry, TRUE ) ; if ( page->currentdlstate == NULL ) return FALSE ; } return TRUE ; }