Exemple #1
0
static void WarnBadInstruction(gs_font_type42 *pfont, int glyph_index)
{
    char buf[gs_font_name_max + 1];
    int l;
    gs_font_type42 *base_font = pfont;

    while ((gs_font_type42 *)base_font->base != base_font)
        base_font = (gs_font_type42 *)base_font->base;
    if (!base_font->data.warning_bad_instruction) {
        l = min(sizeof(buf) - 1, base_font->font_name.size);
        memcpy(buf, base_font->font_name.chars, l);
        buf[l] = 0;
        if (glyph_index >= 0)
            emprintf2(pfont->memory,
                      "Failed to interpret TT instructions for glyph index %d of font %s. "
                      "Continue ignoring instructions of the font.\n",
                      glyph_index, buf);
        else
            emprintf1(pfont->memory,
                      "Failed to interpret TT instructions in font %s. "
                      "Continue ignoring instructions of the font.\n",
                      buf);
        base_font->data.warning_bad_instruction = true;
    }
}
Exemple #2
0
/* Fill the page with the current color. */
int
gs_fillpage(gs_state * pgs)
{
    gx_device *dev = gs_currentdevice(pgs);
    int code;

    /* If we get here without a valid get_color_mapping_procs, fail */
    if (dev_proc(dev, get_color_mapping_procs) == NULL || 
        dev_proc(dev, get_color_mapping_procs) == gx_error_get_color_mapping_procs) {
	emprintf1(dev->memory,
                  "\n   *** Error: No get_color_mapping_procs for device: %s\n",
                  dev->dname);
	return_error(gs_error_Fatal);
    }
    /* Processing a fill object operation */
    gs_set_object_tag((gs_imager_state*) pgs, GS_PATH_TAG);

    gx_set_dev_color(pgs);

    code = (*dev_proc(dev, fillpage))(dev, (gs_imager_state *)pgs,
				      gs_currentdevicecolor_inline(pgs));
    if (code < 0)
	return code;
    return (*dev_proc(dev, sync_output)) (dev);
}
FILE *
gp_open_scratch_file (const gs_memory_t *mem,
                      const char        *prefix,
                      char               fname[gp_file_name_sizeof],
                      const char        *mode)
{
    char thefname[256];
    Str255 thepfname;
    OSErr myErr;
    short foundVRefNum;
    long foundDirID;
    FSSpec fSpec;
    FILE *f;
    int prefix_length = strlen(prefix);

    if (prefix_length > gp_file_name_sizeof) return NULL;
    strcpy (fname, (char *) prefix);
      {
        char newName[50];

        tmpnam (newName);
        if ( prefix_length + strlen(newName) > gp_file_name_sizeof ) return NULL;
        strcat (fname, newName);
      }

   if ( strlen(fname) > 255 ) return NULL;
   if ( strrchr(fname,':') == NULL ) {
       memmove((char*)&thepfname[1],(char *)&fname[0],strlen(fname));
           thepfname[0]=strlen(fname);
                myErr = FindFolder(kOnSystemDisk,kTemporaryFolderType,kCreateFolder,
                        &foundVRefNum, &foundDirID);
                if ( myErr != noErr ) {
                        emprintf(mem, "Can't find temp folder.\n");
                        return (NULL);
                }
                FSMakeFSSpec(foundVRefNum, foundDirID,thepfname, &fSpec);
                convertSpecToPath(&fSpec, thefname, sizeof(thefname) - 1);
                sprintf(fname,"%s",thefname);
   } else {
       sprintf((char*)&thefname[0],"%s\0",fname);
       memmove((char*)&thepfname[1],(char *)&thefname[0],strlen(thefname));
           thepfname[0]=strlen(thefname);
   }

    f = gp_fopen (thefname, mode);
    if (f == NULL)
        emprintf1(mem, "**** Could not open temporary file %s\n", fname);
    return f;
}
Exemple #4
0
static int
clist_fopen(char fname[gp_file_name_sizeof], const char *fmode,
            clist_file_ptr * pcf, gs_memory_t * mem, gs_memory_t *data_mem,
            bool ok_to_compress)
{
    if (*fname == 0) {
        if (fmode[0] == 'r')
            return_error(gs_error_invalidfileaccess);
        *pcf = (clist_file_ptr)gp_open_scratch_file_64(mem,
                                                   gp_scratch_file_name_prefix,
                                                   fname, fmode);
    } else
        *pcf = gp_fopen(fname, fmode);
    if (*pcf == NULL) {
        emprintf1(mem, "Could not open the scratch file %s.\n", fname);
        return_error(gs_error_invalidfileaccess);
    }
    return 0;
}
Exemple #5
0
xps_item_t *
xps_parse_xml(xps_context_t *ctx, byte *buf, int len)
{
    xps_parser_t parser;
    XML_Parser xp;
    int code;

    parser.ctx = ctx;
    parser.root = NULL;
    parser.head = NULL;
    parser.error = NULL;

    xp = XML_ParserCreateNS(NULL, ' ');
    if (!xp)
    {
        gs_throw(-1, "xml error: could not create expat parser");
        return NULL;
    }

    XML_SetUserData(xp, &parser);
    XML_SetParamEntityParsing(xp, XML_PARAM_ENTITY_PARSING_NEVER);
    XML_SetStartElementHandler(xp, (XML_StartElementHandler)on_open_tag);
    XML_SetEndElementHandler(xp, (XML_EndElementHandler)on_close_tag);
    XML_SetCharacterDataHandler(xp, (XML_CharacterDataHandler)on_text);

    code = XML_Parse(xp, (char*)buf, len, 1);
    if (code == 0 || parser.error != NULL)
    {
        if (parser.root)
            xps_free_item(ctx, parser.root);
        if (XML_ErrorString(XML_GetErrorCode(xp)) != 0)
            emprintf1(parser.ctx->memory, "XML_Error: %s\n", XML_ErrorString(XML_GetErrorCode(xp)));
        XML_ParserFree(xp);
        gs_throw1(-1, "parser error: %s", parser.error);
        return NULL;
    }

    XML_ParserFree(xp);

    return parser.root;
}
Exemple #6
0
/* Fill the page with the current color. */
int
gs_fillpage(gs_state * pgs)
{
    gx_device *dev = gs_currentdevice(pgs);
    int code;
    gx_cm_color_map_procs *   pprocs;

    pprocs = get_color_mapping_procs_subclass(dev);
    /* If we get here without a valid get_color_mapping_procs, fail */
    if (pprocs == NULL ||
        /* Deliberately use the terminal device here */
        dev_proc(dev, get_color_mapping_procs) ==  gx_error_get_color_mapping_procs) {
        emprintf1(dev->memory,
                  "\n   *** Error: No get_color_mapping_procs for device: %s\n",
                  dev->dname);
        return_error(gs_error_Fatal);
    }
    /* Processing a fill object operation */
    dev_proc(pgs->device, set_graphics_type_tag)(pgs->device, GS_PATH_TAG);

    code = gx_set_dev_color(pgs);
    if (code != 0)
        return code;

    code = (*dev_proc(dev, fillpage))(dev, (gs_imager_state *)pgs,
                                      gs_currentdevicecolor_inline(pgs));
    if (code < 0)
        return code;

    /* If GrayDetection is set, make sure monitoring is enabled. */
    if (dev->icc_struct != NULL &&
            dev->icc_struct->graydetection && !dev->icc_struct->pageneutralcolor) {
        dev->icc_struct->pageneutralcolor = true;	/* start detecting again */
        code = gsicc_mcm_begin_monitor(pgs->icc_link_cache, dev);
    }
    if (code < 0)
        return code;
    return (*dev_proc(dev, sync_output)) (dev);
}
Exemple #7
0
static int
clist_fopen(char fname[gp_file_name_sizeof], const char *fmode,
            clist_file_ptr * pcf, gs_memory_t * mem, gs_memory_t *data_mem,
            bool ok_to_compress)
{
    if (*fname == 0) {
        if (fmode[0] == 'r')
            return_error(gs_error_invalidfileaccess);
        if (gp_can_share_fdesc()) {
            *pcf = (clist_file_ptr)wrap_file(mem, gp_open_scratch_file_rm(mem,
                                                       gp_scratch_file_name_prefix,
                                                       fname, fmode), fmode);
            /* If the platform supports FILE duplication then we overwrite the
             * file name with an encoded form of the FILE pointer */
            file_to_fake_path(*pcf, fname);
        } else {
            *pcf = (clist_file_ptr)wrap_file(mem, gp_open_scratch_file_64(mem,
                                                       gp_scratch_file_name_prefix,
                                                       fname, fmode), fmode);
        }
    } else {
        // Check if a special path is passed in. If so, clone the FILE handle
        clist_file_ptr ocf = fake_path_to_file(fname);
        if (ocf) {
            *pcf = wrap_file(mem, gp_fdup(((IFILE *)ocf)->f, fmode), fmode);
        } else {
            *pcf = wrap_file(mem, gp_fopen(fname, fmode), fmode);
        }
    }

    if (*pcf == NULL) {
        emprintf1(mem, "Could not open the scratch file %s.\n", fname);
        return_error(gs_error_invalidfileaccess);
    }

    return 0;
}
Exemple #8
0
static int
test10(gs_state * pgs, gs_memory_t * mem)
{
    gs_c_param_list list;
    gs_param_string nstr, OFstr;
    gs_param_float_array PSa;
    gs_param_float_array HWRa;
    gs_param_int_array HWSa;
    int HWSize[2];
    float HWResolution[2], PageSize[2];
    long MaxBitmap;
    int code;
    gx_device *dev = gs_currentdevice(pgs);
    float xlate_x, xlate_y;
    gs_rect cliprect;

    gs_c_param_list_write(&list, mem);
    code = gs_getdeviceparams(dev, (gs_param_list *) & list);
    if (code < 0) {
        lprintf1("getdeviceparams failed! code = %d\n", code);
        gs_abort(mem);
    }
    gs_c_param_list_read(&list);
    code = param_read_string((gs_param_list *) & list, "Name", &nstr);
    if (code < 0) {
        lprintf1("reading Name failed! code = %d\n", code);
        gs_abort(mem);
    }
    code = param_read_int_array((gs_param_list *) & list,
                                "HWSize", &HWSa);
    if (code < 0) {
        lprintf1("reading HWSize failed! code = %d\n", code);
        gs_abort(mem);
    }
    emprintf3(mem, "HWSize[%d] = [ %d, %d ]\n", HWSa.size,
              HWSa.data[0], HWSa.data[1]);
    code = param_read_float_array((gs_param_list *) & list,
                                  "HWResolution", &HWRa);
    if (code < 0) {
        lprintf1("reading Resolution failed! code = %d\n", code);
        gs_abort(mem);
    }
    emprintf3(mem, "HWResolution[%d] = [ %f, %f ]\n", HWRa.size,
              HWRa.data[0], HWRa.data[1]);
    code = param_read_float_array((gs_param_list *) & list,
                                  "PageSize", &PSa);
    if (code < 0) {
        lprintf1("reading PageSize failed! code = %d\n", code);
        gs_abort(mem);
    }
    emprintf3(mem, "PageSize[%d] = [ %f, %f ]\n", PSa.size,
              PSa.data[0], PSa.data[1]);
    code = param_read_long((gs_param_list *) & list,
                           "MaxBitmap", &MaxBitmap);
    if (code < 0) {
        lprintf1("reading MaxBitmap failed! code = %d\n", code);
        gs_abort(mem);
    }
    emprintf1(mem, "MaxBitmap = %ld\n", MaxBitmap);
    /* Switch to param list functions to "write" */
    gs_c_param_list_write(&list, mem);
    /* Always set the PageSize. */
    PageSize[0] = 72.0 * ypage_wid;
    PageSize[1] = 72.0 * xpage_len;
    PSa.data = PageSize;
    code = param_write_float_array((gs_param_list *) & list,
                                   "PageSize", &PSa);
    if (nstr.data[0] != 'v') {
        /* Set the OutputFile string file name */
        OFstr.persistent = false;
        OFstr.data = outfile;
        OFstr.size = strlen(outfile);
        code = param_write_string((gs_param_list *) & list,
                                  "OutputFile", &OFstr);
        if (code < 0) {
            lprintf1("setting OutputFile name failed, code=%d\n",
                     code);
            gs_abort(mem);
        }
        if (nstr.data[0] == 'x') {
            HWResolution[0] = HWResolution[1] = 72.0;
        } else {
            HWResolution[0] = HWResolution[1] = 360.0;
        }
        HWRa.data = HWResolution;
        HWSize[0] = (int)(HWResolution[0] * ypage_wid);
        HWSize[1] = (int)(HWResolution[1] * xpage_len);
        emprintf3(mem, "\tHWSize = [%d,%d], HWResolution = %f dpi\n",
                  HWSize[0], HWSize[1], HWResolution[0]);
        HWSa.data = HWSize;
        code = param_write_float_array((gs_param_list *) & list,
                                       "HWResolution", &HWRa);
        code = param_write_int_array((gs_param_list *) & list,
                                     "HWSize", &HWSa);
        MaxBitmap = 1000000L;
        code = param_write_long((gs_param_list *) & list,
                                "MaxBitmap", &MaxBitmap);
    }
    gs_c_param_list_read(&list);
    code = gs_putdeviceparams(dev, (gs_param_list *) & list);
    emprintf1(mem, "putdeviceparams: code=%d\n", code);
    gs_c_param_list_release(&list);

    /* note: initgraphics no longer resets the color or color space */
    gs_erasepage(pgs);
    gs_initgraphics(pgs);
    {
        gs_color_space *cs = gs_cspace_new_DeviceGray(mem);
        gs_setcolorspace(pgs, cs);
        gs_setcolorspace(pgs, cs);
        gs_decrement(cs, "test10 DeviceGray");
    }

    gs_clippath(pgs);
    gs_pathbbox(pgs, &cliprect);
    emprintf4(mem, "\tcliprect = [[%g,%g],[%g,%g]]\n",
              cliprect.p.x, cliprect.p.y, cliprect.q.x, cliprect.q.y);
    gs_newpath(pgs);

    switch (((rotate_value + 270) / 90) & 3) {
        default:
        case 0:		/* 0 = 360 degrees in PS == 90 degrees in printer */
            xlate_x = cliprect.p.x;
            xlate_y = cliprect.p.y;
            break;
        case 1:		/* 90 degrees in PS = 180 degrees printer */
            xlate_x = cliprect.q.x;
            xlate_y = cliprect.p.y;
            break;
        case 2:		/* 180 degrees in PS == 270 degrees in printer */
            xlate_x = cliprect.q.x;
            xlate_y = cliprect.q.y;
            break;
        case 3:		/* 270 degrees in PS == 0 degrees in printer */
            xlate_x = cliprect.p.x;
            xlate_y = cliprect.q.y;
            break;
    }
    emprintf2(mem, "translate origin to [ %f, %f ]\n", xlate_x, xlate_y);
    gs_translate(pgs, xlate_x, xlate_y);

    /* further move (before rotate) by user requested amount */
    gs_translate(pgs, 72.0 * (float)xmove_origin, 72.0 * (float)ymove_origin);

    gs_rotate(pgs, (float)rotate_value + 270.0);
    gs_scale(pgs, scale_x * 72.0 / 2032.0,
             scale_y * 72.0 / 2032.0);
    gs_setlinecap(pgs, gs_cap_butt);
    gs_setlinejoin(pgs, gs_join_bevel);
    gs_setfilladjust(pgs, 0.0, 0.0);

    capture_exec(pgs);
    return 0;
}
Exemple #9
0
/* Exported for use by background printing.                             */
gx_device *
setup_device_and_mem_for_thread(gs_memory_t *chunk_base_mem, gx_device *dev, bool bg_print, gsicc_link_cache_t **cachep)
{
    int i, code;
    char fmode[4];
    gs_memory_t *thread_mem;
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_printer *pdev = (gx_device_printer *)dev;
    gx_device_clist_common *cdev = (gx_device_clist_common *)cldev;
    gx_device *ndev;
    gx_device_clist *ncldev;
    gx_device_clist_common *ncdev;
    gx_device_printer *npdev;
    gx_device *protodev;
    gs_c_param_list paramlist;
    gs_devn_params *pclist_devn_params;

    /* Every thread will have a 'chunk allocator' to reduce the interaction
     * with the 'base' allocator which has 'mutex' (locking) protection.
     * This improves performance of the threads.
     */
    if ((code = gs_memory_chunk_wrap(&(thread_mem), chunk_base_mem )) < 0) {
        emprintf1(dev->memory, "chunk_wrap returned error code: %d\n", code);
        return NULL;
    }
    /* Find the prototype for this device (needed so we can copy from it) */
    for (i=0; (protodev = (gx_device *)gs_getdevice(i)) != NULL; i++)
        if (strcmp(protodev->dname, dev->dname) == 0)
            break;

    /* Clone the device from the prototype device */
    if (protodev == NULL ||
        (code = gs_copydevice((gx_device **) &ndev, protodev, thread_mem)) < 0) {
        gs_memory_chunk_release(thread_mem);
        return NULL;
    }
    ncldev = (gx_device_clist *)ndev;
    ncdev = (gx_device_clist_common *)ndev;
    npdev = (gx_device_printer *)ndev;
    gx_device_fill_in_procs(ndev);
    ((gx_device_printer *)ncdev)->buffer_memory =
        ncdev->memory =
            ncdev->bandlist_memory =
               thread_mem;
    ndev->PageCount = dev->PageCount;       /* copy to prevent mismatch error */
    npdev->file = pdev->file;               /* For background printing when doing N copies with %d */
    strcpy((npdev->fname), (pdev->fname));
    ndev->color_info = dev->color_info;     /* copy before putdeviceparams */
    ndev->pad = dev->pad;
    ndev->log2_align_mod = dev->log2_align_mod;
    ndev->is_planar = dev->is_planar;
#if CMM_THREAD_SAFE
        ndev->icc_struct = dev->icc_struct;  /* Set before put params */
        rc_increment(ndev->icc_struct);
#endif
    /* get the current device parameters to put into the cloned device */
    gs_c_param_list_write(&paramlist, dev->memory);
    if ((code = gs_getdeviceparams(dev, (gs_param_list *)&paramlist)) < 0) {
        emprintf1(dev->memory,
                  "Error getting device params, code=%d. Rendering threads not started.\n",
                  code);
        goto out_cleanup;
    }
    gs_c_param_list_read(&paramlist);
    if ((code = gs_putdeviceparams(ndev, (gs_param_list *)&paramlist)) < 0)
        goto out_cleanup;
    gs_c_param_list_release(&paramlist);

    /* In the case of a separation device, we need to make sure we get the
       devn params copied over */
    pclist_devn_params = dev_proc(dev, ret_devn_params)(dev);
    if (pclist_devn_params != NULL) {
        code = devn_copy_params(dev, ndev);
        if (code < 0) {
#ifdef DEBUG /* suppress a warning on a release build */
            gs_note_error(gs_error_VMerror);
#endif
            goto out_cleanup;
        }
    }
    /* Also make sure supports_devn is set correctly */
    ndev->icc_struct->supports_devn = cdev->icc_struct->supports_devn;
    ncdev->page_uses_transparency = cdev->page_uses_transparency;
    if_debug3m(gs_debug_flag_icc, cdev->memory,
               "[icc] MT clist device = 0x%p profile = 0x%p handle = 0x%p\n",
               ncdev,
               ncdev->icc_struct->device_profile[0],
               ncdev->icc_struct->device_profile[0]->profile_handle);
    /* If the device is_planar, then set the flag in the new_device and the procs */
    if ((ncdev->is_planar = cdev->is_planar))
        gdev_prn_set_procs_planar(ndev);

    /* gdev_prn_allocate_memory sets the clist for writing, creating new files.
     * We need  to unlink those files and open the main thread's files, then
     * reset the clist state for reading/rendering
     */
    if ((code = gdev_prn_allocate_memory(ndev, NULL, ndev->width, ndev->height)) < 0)
        goto out_cleanup;

    /* close and unlink the temp files just created */
    ncdev->page_info.io_procs->fclose(ncdev->page_info.cfile, ncdev->page_info.cfname, true);
    ncdev->page_info.io_procs->fclose(ncdev->page_info.bfile, ncdev->page_info.bfname, true);
    ncdev->page_info.cfile = ncdev->page_info.bfile = NULL;

    /* open the main thread's files for this thread */
    strcpy(fmode, "r");                 /* read access for threads */
    strncat(fmode, gp_fmode_binary_suffix, 1);
    if ((code=cdev->page_info.io_procs->fopen(cdev->page_info.cfname, fmode, &ncdev->page_info.cfile,
                        thread_mem, thread_mem, true)) < 0 ||
         (code=cdev->page_info.io_procs->fopen(cdev->page_info.bfname, fmode, &ncdev->page_info.bfile,
                        thread_mem, thread_mem, false)) < 0)
        goto out_cleanup;

    strcpy((ncdev->page_info.cfname), (cdev->page_info.cfname));
    strcpy((ncdev->page_info.bfname), (cdev->page_info.bfname));
    clist_render_init(ncldev);      /* Initialize clist device for reading */
    ncdev->page_info.bfile_end_pos = cdev->page_info.bfile_end_pos;

    /* The threads are maintained until clist_finish_page.  At which
       point, the threads are torn down, the master clist reader device
       is changed to writer, and the icc_table and the icc_cache_cl freed */
#if CMM_THREAD_SAFE
    /* safe to share the link cache */
    ncdev->icc_cache_cl = cdev->icc_cache_cl;
    rc_increment(cdev->icc_cache_cl, "setup_render_thread");
#else
    /* each thread needs its own link cache */
    if (cachep != NULL) {
        if (*cachep == NULL) {
            /* We don't have one cached that we can reuse, so make one. */
            if ((*cachep = gsicc_cache_new(thread_mem->thread_safe_memory)) == NULL)
                goto out_cleanup;
        }
        rc_increment(*cachep);
        ncdev->icc_cache_cl = *cachep;
    } else if ((ncdev->icc_cache_cl = gsicc_cache_new(thread_mem)) == NULL)
        goto out_cleanup;
#endif
    if (bg_print) {
        gx_device_clist_reader *ncrdev = (gx_device_clist_reader *)ncdev;

        if (cdev->icc_table != NULL) {
            /* This is a background printing thread, so it cannot share the icc_table  */
            /* since this probably was created with a GC'ed allocator and the bg_print */
            /* thread can't deal with the relocation. Free the cdev->icc_table and get */
            /* a new one from the clist.                                               */
            clist_free_icc_table(cdev->icc_table, cdev->memory);
            cdev->icc_table = NULL;
            if ((code = clist_read_icctable((gx_device_clist_reader *)ncdev)) < 0)
                goto out_cleanup;
        }
        /* Similarly for the color_usage_array, when the foreground device switches to */
        /* writer mode, the foreground's array will be freed.                          */
        if ((code = clist_read_color_usage_array(ncrdev)) < 0)
            goto out_cleanup;
    } else {
    /* Use the same profile table and color usage array in each thread */
        ncdev->icc_table = cdev->icc_table;		/* OK for multiple rendering threads */
        ((gx_device_clist_reader *)ncdev)->color_usage_array =
                ((gx_device_clist_reader *)cdev)->color_usage_array;
    }
    /* Needed for case when the target has cielab profile and pdf14 device
       has a RGB profile stored in the profile list of the clist */
    ncdev->trans_dev_icc_hash = cdev->trans_dev_icc_hash;

    /* success */
    return ndev;

out_cleanup:
    /* Close the file handles, but don't delete (unlink) the files */
    if (ncdev->page_info.bfile != NULL)
        ncdev->page_info.io_procs->fclose(ncdev->page_info.bfile, ncdev->page_info.bfname, false);
    if (ncdev->page_info.cfile != NULL)
        ncdev->page_info.io_procs->fclose(ncdev->page_info.cfile, ncdev->page_info.cfname, false);
    ncdev->do_not_open_or_close_bandfiles = true; /* we already closed the files */

    if (ndev != NULL) {
        gdev_prn_free_memory(ndev);
        gs_free_object(thread_mem, ndev, "setup_device_and_mem_for_thread");
    }
    gs_memory_chunk_release(thread_mem);
    return NULL;
}
Exemple #10
0
/* Set up and start the render threads */
static int
clist_setup_render_threads(gx_device *dev, int y, gx_process_page_options_t *options)
{
    gx_device_printer *pdev = (gx_device_printer *)dev;
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_clist_common *cdev = (gx_device_clist_common *)cldev;
    gx_device_clist_reader *crdev = &cldev->reader;
    gs_memory_t *mem = cdev->bandlist_memory;
    gs_memory_t *chunk_base_mem = mem->thread_safe_memory;
    gs_memory_status_t mem_status;
    int i, band;
    int code = 0;
    int band_count = cdev->nbands;
    int band_height = crdev->page_info.band_params.BandHeight;
    crdev->num_render_threads = pdev->num_render_threads_requested;

    if(gs_debug[':'] != 0)
        dmprintf1(mem, "%% %d rendering threads requested.\n", pdev->num_render_threads_requested);

    if (crdev->num_render_threads > band_count)
        crdev->num_render_threads = band_count; /* don't bother starting more threads than bands */

    /* Allocate and initialize an array of thread control structures */
    crdev->render_threads = (clist_render_thread_control_t *)
              gs_alloc_byte_array(mem, crdev->num_render_threads,
              sizeof(clist_render_thread_control_t), "clist_setup_render_threads" );
    /* fallback to non-threaded if allocation fails */
    if (crdev->render_threads == NULL) {
        emprintf(mem, " VMerror prevented threads from starting.\n");
        return_error(gs_error_VMerror);
    }

    memset(crdev->render_threads, 0, crdev->num_render_threads *
            sizeof(clist_render_thread_control_t));
    crdev->main_thread_data = cdev->data;               /* save data area */
    /* Based on the line number requested, decide the order of band rendering */
    /* Almost all devices go in increasing line order (except the bmp* devices ) */
    crdev->thread_lookahead_direction = (y < (cdev->height - 1)) ? 1 : -1;
    band = y / band_height;

    /* If the 'mem' is not thread safe, we need to wrap it in a locking memory */
    gs_memory_status(chunk_base_mem, &mem_status);
    if (mem_status.is_thread_safe == false) {
            return_error(gs_error_VMerror);
    }

    /* If we don't have one large enough already, create an icc cache list */
    if (crdev->num_render_threads > crdev->icc_cache_list_len) {
        void *old = crdev->icc_cache_list;
        crdev->icc_cache_list = gs_alloc_byte_array(mem->thread_safe_memory,
                                    crdev->num_render_threads,
                                    sizeof(void*), "clist_render_setup_threads");
        if (crdev->icc_cache_list == NULL) {
            crdev->icc_cache_list = NULL;
            return_error(gs_error_VMerror);
        }
        if (crdev->icc_cache_list_len > 0)
            memcpy(crdev->icc_cache_list, old, sizeof(void *)*crdev->icc_cache_list_len);
        memset(&crdev->icc_cache_list[crdev->icc_cache_list_len], 0,
            (crdev->num_render_threads - crdev->icc_cache_list_len) * sizeof(void *));
        crdev->icc_cache_list_len = crdev->num_render_threads;
        gs_free_object(mem, old, "clist_render_setup_threads");
    }

    /* Loop creating the devices and semaphores for each thread, then start them */
    for (i=0; (i < crdev->num_render_threads) && (band >= 0) && (band < band_count);
            i++, band += crdev->thread_lookahead_direction) {
        gx_device *ndev;
        clist_render_thread_control_t *thread = &(crdev->render_threads[i]);

        ndev = setup_device_and_mem_for_thread(chunk_base_mem, dev, false, &crdev->icc_cache_list[i]);
        if (ndev == NULL) {
            code = gs_error_VMerror;	/* set code to an error for cleanup after the loop */
            break;
        }

        thread->cdev = ndev;
        thread->memory = ndev->memory;
        thread->band = -1;              /* a value that won't match any valid band */
        thread->options = options;
        thread->buffer = NULL;
        if (options && options->init_buffer_fn) {
            code = options->init_buffer_fn(options->arg, dev, thread->memory, dev->width, band_height, &thread->buffer);
            if (code < 0)
                break;
        }

        /* create the buf device for this thread, and allocate the semaphores */
        if ((code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
                                &(thread->bdev), ndev,
                                band*crdev->page_band_height, NULL,
                                thread->memory, &(crdev->color_usage_array[0])) < 0))
            break;
        if ((thread->sema_this = gx_semaphore_alloc(thread->memory)) == NULL ||
            (thread->sema_group = gx_semaphore_alloc(thread->memory)) == NULL) {
            code = gs_error_VMerror;
            break;
        }
        /* Start thread 'i' to do band */
        if ((code = clist_start_render_thread(dev, i, band)) < 0)
            break;
    }
    /* If the code < 0, the last thread creation failed -- clean it up */
    if (code < 0) {
        band -= crdev->thread_lookahead_direction;	/* update for 'next_band' usage */
        /* the following relies on 'free' ignoring NULL pointers */
        gx_semaphore_free(crdev->render_threads[i].sema_group);
        gx_semaphore_free(crdev->render_threads[i].sema_this);
        if (crdev->render_threads[i].bdev != NULL)
            cdev->buf_procs.destroy_buf_device(crdev->render_threads[i].bdev);
        if (crdev->render_threads[i].cdev != NULL) {
            gx_device_clist_common *thread_cdev = (gx_device_clist_common *)crdev->render_threads[i].cdev;

            /* Close the file handles, but don't delete (unlink) the files */
            thread_cdev->page_info.io_procs->fclose(thread_cdev->page_info.bfile, thread_cdev->page_info.bfname, false);
            thread_cdev->page_info.io_procs->fclose(thread_cdev->page_info.cfile, thread_cdev->page_info.cfname, false);
            thread_cdev->do_not_open_or_close_bandfiles = true; /* we already closed the files */

            gdev_prn_free_memory((gx_device *)thread_cdev);
            gs_free_object(crdev->render_threads[i].memory, thread_cdev,
            "clist_setup_render_threads");
        }
        if (crdev->render_threads[i].buffer != NULL && options && options->free_buffer_fn != NULL) {
            options->free_buffer_fn(options->arg, dev, crdev->render_threads[i].memory, crdev->render_threads[i].buffer);
            crdev->render_threads[i].buffer = NULL;
        }
        if (crdev->render_threads[i].memory != NULL) {
            gs_memory_chunk_release(crdev->render_threads[i].memory);
            crdev->render_threads[i].memory = NULL;
        }
    }
    /* If we weren't able to create at least one thread, punt   */
    /* Although a single thread isn't any more efficient, the   */
    /* machinery still works, so that's OK.                     */
    if (i == 0) {
        if (crdev->render_threads[0].memory != NULL) {
            gs_memory_chunk_release(crdev->render_threads[0].memory);
            /* free up the locking wrapper if we allocated one */
            if (chunk_base_mem != mem) {
                gs_memory_locked_release((gs_memory_locked_t *)chunk_base_mem);
                gs_free_object(mem, chunk_base_mem, "clist_setup_render_threads(locked allocator)");
            }
        }
        gs_free_object(mem, crdev->render_threads, "clist_setup_render_threads");
        crdev->render_threads = NULL;
        /* restore the file pointers */
        if (cdev->page_info.cfile == NULL) {
            char fmode[4];

            strcpy(fmode, "a+");        /* file already exists and we want to re-use it */
            strncat(fmode, gp_fmode_binary_suffix, 1);
            cdev->page_info.io_procs->fopen(cdev->page_info.cfname, fmode, &cdev->page_info.cfile,
                                mem, cdev->bandlist_memory, true);
            cdev->page_info.io_procs->fseek(cdev->page_info.cfile, 0, SEEK_SET, cdev->page_info.cfname);
            cdev->page_info.io_procs->fopen(cdev->page_info.bfname, fmode, &cdev->page_info.bfile,
                                mem, cdev->bandlist_memory, false);
            cdev->page_info.io_procs->fseek(cdev->page_info.bfile, 0, SEEK_SET, cdev->page_info.bfname);
        }
        emprintf1(mem, "Rendering threads not started, code=%d.\n", code);
        return_error(code);
    }
    crdev->num_render_threads = i;
    crdev->curr_render_thread = 0;
        crdev->next_band = band;

    if(gs_debug[':'] != 0)
        dmprintf1(mem, "%% Using %d rendering threads\n", i);

    return 0;
}
Exemple #11
0
/* Set up and start the render threads */
static int
clist_setup_render_threads(gx_device *dev, int y)
{
    gx_device_printer *pdev = (gx_device_printer *)dev;
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_clist_common *cdev = (gx_device_clist_common *)cldev;
    gx_device_clist_reader *crdev = &cldev->reader;
    gs_memory_t *mem = cdev->bandlist_memory;
    gs_memory_t *chunk_base_mem = mem->thread_safe_memory;
    gs_memory_status_t mem_status;
    gx_device *protodev;
    gs_c_param_list paramlist;
    int i, code, band;
    int band_count = cdev->nbands;
    char fmode[4];
    gs_devn_params *pclist_devn_params;
    crdev->num_render_threads = pdev->num_render_threads_requested;

    if(gs_debug[':'] != 0)
        dprintf1("%% %d rendering threads requested.\n", pdev->num_render_threads_requested);

    if (crdev->num_render_threads > band_count)
        crdev->num_render_threads = band_count; /* don't bother starting more threads than bands */

    /* Allocate and initialize an array of thread control structures */
    crdev->render_threads = (clist_render_thread_control_t *)
              gs_alloc_byte_array(mem, crdev->num_render_threads,
              sizeof(clist_render_thread_control_t), "clist_setup_render_threads" );
    /* fallback to non-threaded if allocation fails */
    if (crdev->render_threads == NULL) {
        emprintf(mem, " VMerror prevented threads from starting.\n");
        return_error(gs_error_VMerror);
    }

    memset(crdev->render_threads, 0, crdev->num_render_threads *
            sizeof(clist_render_thread_control_t));
    crdev->main_thread_data = cdev->data;               /* save data area */
    /* Based on the line number requested, decide the order of band rendering */
    /* Almost all devices go in increasing line order (except the bmp* devices ) */
    crdev->thread_lookahead_direction = (y < (cdev->height - 1)) ? 1 : -1;
    band = y / crdev->page_info.band_params.BandHeight;

    /* Close the files so we can open them in multiple threads */
    if ((code = cdev->page_info.io_procs->fclose(cdev->page_cfile, cdev->page_cfname, false)) < 0 ||
        (code = cdev->page_info.io_procs->fclose(cdev->page_bfile, cdev->page_bfname, false)) < 0) {
        gs_free_object(mem, crdev->render_threads, "clist_setup_render_threads");
        crdev->render_threads = NULL;
        emprintf(mem, "Closing clist files prevented threads from starting.\n");
        return_error(gs_error_unknownerror); /* shouldn't happen */
    }
    cdev->page_cfile = cdev->page_bfile = NULL;
    strcpy(fmode, "r");                 /* read access for threads */
    strncat(fmode, gp_fmode_binary_suffix, 1);
    /* Find the prototype for this device (needed so we can copy from it) */
    for (i=0; (protodev = (gx_device *)gs_getdevice(i)) != NULL; i++)
        if (strcmp(protodev->dname, dev->dname) == 0)
            break;
    if (protodev == NULL) {
        emprintf(mem,
                 "Could not find prototype device. Rendering threads not started.\n");
        return gs_error_rangecheck;
    }

    gs_c_param_list_write(&paramlist, mem);
    if ((code = gs_getdeviceparams(dev, (gs_param_list *)&paramlist)) < 0) {
        emprintf1(mem,
                  "Error getting device params, code=%d. Rendering threads not started.\n",
                  code);
        return code;
    }

    /* If the 'mem' is not thread safe, we need to wrap it in a locking memory */
    gs_memory_status(chunk_base_mem, &mem_status);
    if (mem_status.is_thread_safe == false) {
            return_error(gs_error_VMerror);
    }

    /* Loop creating the devices and semaphores for each thread, then start them */
    for (i=0; (i < crdev->num_render_threads) && (band >= 0) && (band < band_count);
            i++, band += crdev->thread_lookahead_direction) {
        gx_device *ndev;
        gx_device_clist *ncldev;
        gx_device_clist_common *ncdev;
        clist_render_thread_control_t *thread = &(crdev->render_threads[i]);

        /* Every thread will have a 'chunk allocator' to reduce the interaction
         * with the 'base' allocator which has 'mutex' (locking) protection.
         * This improves performance of the threads.
         */
        if ((code = gs_memory_chunk_wrap(&(thread->memory), chunk_base_mem )) < 0) {
            emprintf1(mem, "chunk_wrap returned error code: %d\n", code);
            break;
        }

        thread->band = -1;              /* a value that won't match any valid band */
        if ((code = gs_copydevice((gx_device **) &ndev, protodev, thread->memory)) < 0) {
            code = 0;           /* even though we failed, no cleanup needed */
            break;
        }
        ncldev = (gx_device_clist *)ndev;
        ncdev = (gx_device_clist_common *)ndev;
        gx_device_fill_in_procs(ndev);
        ((gx_device_printer *)ncdev)->buffer_memory = ncdev->memory =
                ncdev->bandlist_memory = thread->memory;
        gs_c_param_list_read(&paramlist);
        ndev->PageCount = dev->PageCount;       /* copy to prevent mismatch error */
#if CMM_THREAD_SAFE
        ndev->icc_struct = dev->icc_struct;  /* Set before put params */
        rc_increment(ndev->icc_struct);
#endif
        if ((code = gs_putdeviceparams(ndev, (gs_param_list *)&paramlist)) < 0)
            break;
        /* In the case of a separation device, we need to make sure we get the
           devn params copied over */
        pclist_devn_params = dev_proc(dev, ret_devn_params)(dev);
        if (pclist_devn_params != NULL) {
            code = devn_copy_params(dev, (gx_device*) ncdev);
            if (code < 0) return_error(gs_error_VMerror);
        }
        ncdev->page_uses_transparency = cdev->page_uses_transparency;
        if_debug3('{',"[{]MT clist device = 0x%x profile = 0x%x handle = 0x%x\n", 
                  ncdev,
                  ncdev->icc_struct->device_profile[0],
                  ncdev->icc_struct->device_profile[0]->profile_handle);
        /* gdev_prn_allocate_memory sets the clist for writing, creating new files.
         * We need  to unlink those files and open the main thread's files, then
         * reset the clist state for reading/rendering
         */
        if ((code = gdev_prn_allocate_memory(ndev, NULL, ndev->width, ndev->height)) < 0)
            break;
        /* Needed for case when the target has cielab profile and pdf14 device
           has a RGB profile stored in the profile list of the clist */
        ncdev->trans_dev_icc_hash = cdev->trans_dev_icc_hash;
        thread->cdev = ndev;
        /* close and unlink the temp files just created */
        cdev->page_info.io_procs->fclose(ncdev->page_cfile, ncdev->page_cfname, true);
        cdev->page_info.io_procs->fclose(ncdev->page_bfile, ncdev->page_bfname, true);
        /* open the main thread's files for this thread */
        if ((code=cdev->page_info.io_procs->fopen(cdev->page_cfname, fmode, &ncdev->page_cfile,
                            thread->memory, thread->memory, true)) < 0 ||
             (code=cdev->page_info.io_procs->fopen(cdev->page_bfname, fmode, &ncdev->page_bfile,
                            thread->memory, thread->memory, false)) < 0)
            break;
        clist_render_init(ncldev);      /* Initialize clist device for reading */
        ncdev->page_bfile_end_pos = cdev->page_bfile_end_pos;
        /* Use the same link cache in each thread and the same profile table.
           The threads are maintained until clist_finish_page.  At which
           point, the threads are torn down and the master clist reader device
           is destroyed along with the icc_table and the icc_cache_cl */
#if CMM_THREAD_SAFE
        ncdev->icc_cache_cl = cdev->icc_cache_cl;
#else
        ncdev->icc_cache_cl = gsicc_cache_new(crdev->memory);
#endif
        ncdev->icc_table = cdev->icc_table;
        /* create the buf device for this thread, and allocate the semaphores */
        if ((code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
                                &(thread->bdev), cdev->target,
                                band*crdev->page_band_height, NULL,
                                thread->memory, clist_get_band_complexity(dev,y)) < 0))
            break;
        if ((thread->sema_this = gx_semaphore_alloc(thread->memory)) == NULL ||
            (thread->sema_group = gx_semaphore_alloc(thread->memory)) == NULL) {
            code = gs_error_VMerror;
            break;
        }
        /* Start thread 'i' to do band */
        if ((code = clist_start_render_thread(dev, i, band)) < 0)
            break;
    }
    gs_c_param_list_release(&paramlist);
    /* If the code < 0, the last thread creation failed -- clean it up */
    if (code < 0) {
        /* the following relies on 'free' ignoring NULL pointers */
        gx_semaphore_free(crdev->render_threads[i].sema_group);
        gx_semaphore_free(crdev->render_threads[i].sema_this);
        if (crdev->render_threads[i].bdev != NULL)
            cdev->buf_procs.destroy_buf_device(crdev->render_threads[i].bdev);
        if (crdev->render_threads[i].cdev != NULL) {
            gx_device_clist_common *thread_cdev = (gx_device_clist_common *)crdev->render_threads[i].cdev;

            /* Close the file handles, but don't delete (unlink) the files */
            thread_cdev->page_info.io_procs->fclose(thread_cdev->page_bfile, thread_cdev->page_bfname, false);
            thread_cdev->page_info.io_procs->fclose(thread_cdev->page_cfile, thread_cdev->page_cfname, false);
            thread_cdev->do_not_open_or_close_bandfiles = true; /* we already closed the files */

            gdev_prn_free_memory((gx_device *)thread_cdev);
            gs_free_object(crdev->render_threads[i].memory, thread_cdev,
            "clist_setup_render_threads");
        }
        if (crdev->render_threads[i].memory != NULL)
            gs_memory_chunk_release(crdev->render_threads[i].memory);
    }
    /* If we weren't able to create at least one thread, punt   */
    /* Although a single thread isn't any more efficient, the   */
    /* machinery still works, so that's OK.                     */
    if (i == 0) {
        if (crdev->render_threads[0].memory != NULL) {
            gs_memory_chunk_release(crdev->render_threads[0].memory);
            /* free up the locking wrapper if we allocated one */
            if (chunk_base_mem != mem) {
                gs_memory_locked_release((gs_memory_locked_t *)chunk_base_mem);
                gs_free_object(mem, chunk_base_mem, "clist_setup_render_threads(locked allocator)");
            }
        }
        gs_free_object(mem, crdev->render_threads, "clist_setup_render_threads");
        crdev->render_threads = NULL;
        /* restore the file pointers */
        if (cdev->page_cfile == NULL) {
            char fmode[4];

            strcpy(fmode, "a+");        /* file already exists and we want to re-use it */
            strncat(fmode, gp_fmode_binary_suffix, 1);
            cdev->page_info.io_procs->fopen(cdev->page_cfname, fmode, &cdev->page_cfile,
                                mem, cdev->bandlist_memory, true);
            cdev->page_info.io_procs->fseek(cdev->page_cfile, 0, SEEK_SET, cdev->page_cfname);
            cdev->page_info.io_procs->fopen(cdev->page_bfname, fmode, &cdev->page_bfile,
                                mem, cdev->bandlist_memory, false);
            cdev->page_info.io_procs->fseek(cdev->page_bfile, 0, SEEK_SET, cdev->page_bfname);
        }
        emprintf1(mem, "Rendering threads not started, code=%d.\n", code);
        return_error(code);
    }
    crdev->num_render_threads = i;
    crdev->curr_render_thread = 0;

    if(gs_debug[':'] != 0)
        dprintf1("%% Using %d rendering threads\n", i);

    return 0;
}
Exemple #12
0
/* Write the actual file name at fname. */
static FILE *
gp_open_scratch_file_generic(const gs_memory_t *mem,
                             const char        *prefix,
                                   char         fname[gp_file_name_sizeof],
                             const char        *mode,
                                   bool         b64)
{       /* The -8 is for XXXXXX plus a possible final / and -. */
    int prefix_length = strlen(prefix);
    int len = gp_file_name_sizeof - prefix_length - 8;
    FILE *fp;

    if (gp_file_name_is_absolute(prefix, prefix_length))
        *fname = 0;
    else if (gp_gettmpdir(fname, &len) != 0)
        strcpy(fname, "/tmp/");
    else {
        if (strlen(fname) != 0 && fname[strlen(fname) - 1] != '/')
            strcat(fname, "/");
    }
    if (strlen(fname) + prefix_length + 8 >= gp_file_name_sizeof)
        return 0;               /* file name too long */
    strcat(fname, prefix);
    /* Prevent trailing X's in path from being converted by mktemp. */
    if (*fname != 0 && fname[strlen(fname) - 1] == 'X')
        strcat(fname, "-");
    strcat(fname, "XXXXXX");

#ifdef HAVE_MKSTEMP
    {
        int file;
        char ofname[gp_file_name_sizeof];

        /* save the old filename template in case mkstemp fails */
        memcpy(ofname, fname, gp_file_name_sizeof);
#ifdef HAVE_MKSTEMP64
        if (b64)
            file = mkstemp64(fname);
        else
            file = mkstemp(fname);
#else
        file = mkstemp(fname);
#endif
        if (file < -1) {
            emprintf1(mem, "**** Could not open temporary file %s\n", ofname);
            return NULL;
        }
#if defined(O_LARGEFILE) && defined(__hpux)
        if (b64)
            fcntl(file, F_SETFD, fcntl(file, F_GETFD) | O_LARGEFILE);
#else
        /* Fixme : what to do with b64 and 32-bit mkstemp? Unimplemented. */
#endif

        fp = fdopen(file, mode);
        if (fp == NULL)
            close(file);
    }
#else
    mktemp(fname);
    fp = (b64 ? gp_fopentemp : gp_fopentemp_64)(fname, mode);
#endif
    if (fp == NULL)
        emprintf1(mem, "**** Could not open temporary file %s\n", fname);
    return fp;
}
Exemple #13
0
/*
 * Caller should make sure that this device supports saved_pages:
 * dev_proc(dev, dev_spec_op)(dev, gxdso_supports_saved_pages, NULL, 0) == 1
 *
 * Returns < 0 if error, 1 if erasepage needed, 0 if no action needed.
 */
int
gx_saved_pages_param_process(gx_device_printer *pdev, byte *param, int param_size)
{
    byte *param_scan = param;
    int param_left = param_size;
    byte *token;
    int token_size, code, printed_count, collated_copies = 1;
    int tmp_num;			/* during token scanning loop */
    int erasepage_needed = 0;

    while (pdev->child)
        pdev = (gx_device_printer *)pdev->child;

    while ((token = param_parse_token(param_scan, param_left, &token_size)) != NULL) {

        switch (param_find_key(token, token_size)) {
          case PARAM_BEGIN:
            if (pdev->saved_pages_list == NULL) {
                if ((pdev->saved_pages_list = gx_saved_pages_list_new(pdev)) == NULL)
                    return_error(gs_error_VMerror);

                /* We need to change to clist mode. Always uses clist when saving pages */
                pdev->saved_pages_list->save_banding_type = pdev->space_params.banding_type;
                pdev->space_params.banding_type = BandingAlways;
                if ((code = gdev_prn_reallocate_memory((gx_device *)pdev, &pdev->space_params, pdev->width, pdev->height)) < 0)
                    return code;
                erasepage_needed |= 1;
            }
            break;

          case PARAM_END:
            if (pdev->saved_pages_list != NULL) {
                /* restore to what was set before the "begin" */
                pdev->space_params.banding_type = pdev->saved_pages_list->save_banding_type;
                gx_saved_pages_list_free(pdev->saved_pages_list);
                pdev->saved_pages_list = NULL;
                /* We may need to change from clist mode since we forced clist when saving pages */
                code = gdev_prn_reallocate_memory((gx_device *)pdev, &pdev->space_params, pdev->width, pdev->height);
                if (code < 0)
                    return code;
                erasepage_needed |= 1;       /* make sure next page is erased */
            }
            break;

          case PARAM_FLUSH:
            if (pdev->saved_pages_list != NULL) {
                /* Save the collated copy count so the list we return will have it */
                collated_copies = pdev->saved_pages_list->collated_copies;
                gx_saved_pages_list_free(pdev->saved_pages_list);
            }
            /* Always return with an empty list, even if we weren't saving previously */
            if ((pdev->saved_pages_list = gx_saved_pages_list_new(pdev)) == NULL)
                return_error(gs_error_VMerror);
            /* restore the original count */
            pdev->saved_pages_list->collated_copies = collated_copies;
            break;

          case PARAM_COPIES:			/* copies requires a number next */
            /* make sure that we have a list */
            if (pdev->saved_pages_list == NULL) {
                return_error(gs_error_rangecheck);	/* copies not allowed before a 'begin' */
            }
            /* Move to past 'copies' token */
            param_left -= token - param_scan + token_size;
            param_scan = token + token_size;

            if ((token = param_parse_token(param_scan, param_left, &token_size)) == NULL ||
                 param_find_key(token, token_size) != PARAM_NUMBER) {
                emprintf(pdev->memory, "gx_saved_pages_param_process: copies not followed by number.\n");
                return_error(gs_error_typecheck);
            }
            if (sscanf((const char *)token, "%d", &tmp_num) != 1) {
                emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token);
                code = gs_error_typecheck;
                return code;
            }
            pdev->saved_pages_list->collated_copies = tmp_num;	/* save it for our loop */
            break;

          case PARAM_PRINT:
            /* Move to past 'print' token */
            param_left -= token - param_scan + token_size;
            param_scan = token + token_size;

            code = param_left;			/* in case list is NULL, skip rest of string */
            if (pdev->saved_pages_list != NULL) {
                if ((code = gx_saved_pages_list_print(pdev, pdev->saved_pages_list,
                                                 param_scan, param_left, &printed_count)) < 0)
                    return code;
                erasepage_needed |= 1;       /* make sure next page is erased */
            }
            /* adjust for all of the print parameters */
            token_size += code;
            break;

          /* We are expecting an action keyword, so other keywords and tokens */
          /* are not valid here (mostly the 'print' parameters).              */
          default:
            {
                byte *bad_token = gs_alloc_string(pdev->memory, token_size+1, "saved_pages_param_process");
                byte *param_string = gs_alloc_string(pdev->memory, param_size+1, "saved_pages_param_process");
                if (bad_token != NULL && param_string != NULL) {
                    memcpy(bad_token, token, token_size);
                    bad_token[token_size] = 0;          /* terminate string */
                    memcpy(param_string, param, param_size);
                    param_string[param_size] = 0;          /* terminate string */
                    emprintf2(pdev->memory, "*** Invalid saved-pages token '%s'\n *** in param string '%s'\n",
                              bad_token, param_string);
                    gs_free_string(pdev->memory, bad_token, token_size+1,  "saved_pages_param_process");
                    gs_free_string(pdev->memory, param_string, param_size+1,  "saved_pages_param_process");
                }
            }
        }
        /* Move to next token */
        param_left -= token - param_scan + token_size;
        param_scan = token + token_size;

    }
    return erasepage_needed;
}
Exemple #14
0
/*
 * Print selected pages from the list to on the selected device. The
 * saved_pages_list is NOT modified, allowing for reprint / recovery
 * print. Each saved_page is printed on a separate page (unlike the
 * gdev_prn_render_pages above which prints several saved_pages on
 * a single "master" page, performing imposition).
 *
 * This is primarily intended to allow printing in non-standard order
 * (reverse, odd, even) or producing collated copies for a job.
 *
 * On success return the number of bytes consumed or error code < 0.
 * The printed_count will contain the number of pages printed.
 *
 * -------------------------------------------------------------------
 *
 * The param string may begin with whitespace. The string is parsed
 * and the selected pages are printed. There may be any number of ranges
 * and or keywords separated by whitespace and/or comma ','.
 *
 * NB: The pdev printer device's PageCount is updated to reflect the
 *     total number of pages produced (per the spec for this parameter)
 *     since we may be producing multiple collated copies.
 *     Also the list PageCount is updated after printing since
 *     there may be a subsequent 'print' action.
 * keywords:
 *	copies #	Set the number of copies for subsequent printing actions
 *                      "copies 1" resets to a single copy
 *	normal		All pages are printed in normal order
 *	reverse		All pages are printed in reverse order
 *         The following two options may be useful for duplexing.
 *	odd		All odd pages are printed, e.g. 1, 3, 5, ...
 *	even		All even pages are printed, e.g. 2, 4, 6, ...
 *                      NB: an extra blank page will be printed if the list
 *                      has an odd number of pages.
 *      even0pad        All even pages, but no extra blank page if there are
 *                      an odd number of pages on the list.
 * range syntax:
 *	range range	multiple ranges are separated by commas ','
 *			and/or whitespace.
 *	#		a specific page number is a valid range
 *
 *	inclusive ranges below can have whitespace before
 *	or after the dash '-'.
 *	#-#		a range consisting of all pages from the first
 *			page # up to (and including) the second page #.
 *	#-*		all pages from # up through the last page
 *			"1-*" is equivalent to "normal"
 *	*-#		all pages from the last up through # page.
 *			"reverse" is equivalent to "*-1"
 */
int
gx_saved_pages_list_print(gx_device_printer *pdev, gx_saved_pages_list *list,
                          byte *param, int param_size, int *printed_count)
{
    byte *param_scan = NULL;
    int param_left;
    int start_page = 0;				/* 0 means start_page unknown */
    int end_page = 0;				/* < 0 means waiting for the end of a # - # range */
                                                /* i.e, a '-' was scanned. 0 means unknown */
    int tmp_num;				/* during token scanning loop */
    int code = 0, endcode = 0;
    byte *token;
    int copy, token_size;
    gx_device_clist_reader *crdev = (gx_device_clist_reader *)pdev;
    /* the following are used so we can go back to the original state */
    bool save_bg_print = false;                 /* arbitrary, silence warning */
    bool save_bandfile_open_close = false;      /* arbitrary, silence warning */
    gx_saved_page saved_page;
    clist_file_ptr saved_files[2];

    /* save the current (empty) page while we print  */
    if ((code = do_page_save(pdev, &saved_page, saved_files)) < 0) {
        emprintf(pdev->memory, "gx_saved_pages_list_print: Error getting device params\n");
        goto out;
    }

    /* save_page leaves the clist in writer mode, so prepare for reading clist */
    /* files. When we are done with printing, we'll go back to write mode.     */
    if ((code = clist_close_writer_and_init_reader((gx_device_clist *)pdev)) < 0)
        goto out;

    /* While printing, disable the saved_pages mode and bg_print */
    pdev->saved_pages_list = NULL;
    save_bg_print = pdev->bg_print_requested;

    /* Inhibits modifying the clist at end of output_page */
    save_bandfile_open_close = crdev->do_not_open_or_close_bandfiles;
    crdev->do_not_open_or_close_bandfiles = true;

    pdev->PageCount = list->PageCount;		/* adjust to value last printed */

    /* loop producing the number of copies */
    /* Note: list->collated_copies may change if 'copies' param follows the 'print' */
    for (copy = 1; copy <= list->collated_copies; copy++) {
        int page_skip = 0;
        bool do_blank_page_pad;
        int page;

        /* Set to start of 'print' params to do collated copies */
        param_scan = param;
        param_left = param_size;
        while ((token = param_parse_token(param_scan, param_left, &token_size)) != NULL) {
            saved_pages_key_enum key;

            page = 0;
            do_blank_page_pad = false;			/* only set for EVEN */
            key = param_find_key(token, token_size);
            switch (key) {
              case PARAM_DASH:
                if (start_page == 0) {
                    emprintf(pdev->memory, "gx_saved_pages_list_print: '-' unexpected\n");
                    code = gs_error_typecheck;
                    goto out;
                }
                end_page = -1;		/* the next number will end a range */
                break;

              case PARAM_STAR:
                page = list->count;		/* last page */
              case PARAM_NUMBER:
                if (page == 0) {
                     if (sscanf((const char *)token, "%d", &page) != 1) {
                         emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token);
                         code = gs_error_typecheck;
                         goto out;
                     }
                }
                if (start_page == 0) {
                    start_page = page;		/* first number seen */
                } else {
                    /* a second number was seen after the start_page was set */
                    if (end_page < 0) {
                        end_page = page;		/* end of a '# - #' range */
                        page_skip = (end_page >= start_page) ? 1 : -1;
                    } else {
                        /* 'page' was NOT part of a range after printing 'page' will start a new range */
                        end_page = start_page;	/* single page */
                        page_skip = 1;
                    }
                }
                break;

              case PARAM_COPIES:			/* copies requires a number next */
                /* Move to past 'copies' token */
                param_left -= token - param_scan + token_size;
                param_scan = token + token_size;

                if ((token = param_parse_token(param_scan, param_left, &token_size)) == NULL ||
                     param_find_key(token, token_size) != PARAM_NUMBER) {
                    emprintf(pdev->memory, "gx_saved_pages_list_print: copies not followed by number.\n");
                    code = gs_error_typecheck;
                    goto out;
                }
                if (sscanf((const char *)token, "%d", &tmp_num) != 1) {
                    emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token);
                    code = gs_error_typecheck;
                    goto out;
                }
                list->collated_copies = tmp_num;	/* save it for our loop */
                break;

              case PARAM_NORMAL:			/* sets both start and end */
                start_page = 1;
                end_page = list->count;
                page_skip = 1;
                break ;

              case PARAM_REVERSE:			/* sets both start and end */
                start_page = list->count;
                end_page = 1;
                page_skip = -1;
                break;

              case PARAM_EVEN:			/* sets both start and end */
                do_blank_page_pad = (list->count & 1) != 0;	/* pad if odd */
              case PARAM_EVEN0PAD:		/* sets both start and end */
                start_page = 2;
                end_page = list->count;
                page_skip = 2;
                break ;

              case PARAM_ODD:			/* sets both start and end */
                start_page = 1;
                end_page = list->count;
                page_skip = 2;
                break ;

              case PARAM_UNKNOWN:
              case PARAM_BEGIN:
              case PARAM_END:
              case PARAM_FLUSH:
              case PARAM_PRINT:
                token_size = 0;			/* non-print range token seen */
            }
            if (end_page > 0) {
                /* Here we have a range to print since start and end are known */
                int curr_page = start_page;
                gx_saved_pages_list_element *curr_elem = NULL;

                /* get the start_page saved_page */
                if (start_page <= list->count) {
                    for (curr_elem = list->head; curr_elem->sequence_number != start_page;
                                curr_elem = curr_elem->next) {
                        if (curr_elem->next == NULL) {
                             emprintf1(pdev->memory, "gx_saved_pages_list_print: page %d not found.\n", start_page);
                             code = gs_error_rangecheck;;
                             goto out;
                        }
                    }
                }

                for ( ; curr_elem != NULL; ) {

                    /* print the saved page from the current curr_elem */

                    if ((code = gx_output_saved_page(pdev, curr_elem->page)) < 0)
                        goto out;

                    curr_page += page_skip;
                    if (page_skip >= 0) {
                        if (curr_page > end_page)
                            break;
                        curr_elem = curr_elem->next;
                        if (page_skip > 1)
                            curr_elem = curr_elem->next;
                    } else {
                        /* reverse print order */
                        if (curr_page < end_page)
                            break;
                        curr_elem = curr_elem->prev;
                        /* Below is not needed since we never print reverse even/odd */
                        if (page_skip < -1)
                            curr_elem = curr_elem->prev;
                    }
                    if (curr_elem == NULL) {
                         emprintf1(pdev->memory, "gx_saved_pages_list_print: page %d not found.\n", curr_page);
                         code = gs_error_rangecheck;;
                         goto out;
                    }
                }

                /* If we were printing EVEN, we may need to spit out a blank 'pad' page */
                if (do_blank_page_pad) {
                    /* print the empty page we had upon entry */
                    /* FIXME: Note that the page size may not match the last odd page */
                    if ((code = gx_output_saved_page(pdev, &saved_page)) < 0)
                        goto out;
                }

                /* After printing, reset to handle next page range */
                start_page = (start_page == end_page) ? page : 0;   /* if single page, set start_page */
                                                                    /* from the number scanned above  */
                end_page = 0;
            }
            if (token_size == 0)
                break;				/* finished with print ranges */

            /* Move to next token */
            param_left -= token - param_scan + token_size;
            param_scan = token + token_size;
        }
    }
out:
    /* restore the device parameters saved upon entry */
    *printed_count = pdev->PageCount - list->PageCount;
    list->PageCount = pdev->PageCount;		/* retain for subsequent print action */
    pdev->saved_pages_list = list;
    pdev->bg_print_requested = save_bg_print;
    crdev->do_not_open_or_close_bandfiles = save_bandfile_open_close;

    /* load must be after we've set saved_pages_list which forces clist mode. */
    do_page_load(pdev, &saved_page, saved_files);

    /* Finally, do the finish page which will reset the clist to empty and write mode */
    endcode = clist_finish_page((gx_device *)pdev, true);
    return code < 0 ? code : endcode < 0 ? endcode : param_scan - param;
}