/* Fill in a gs_param_key_t from a name or int ref. */ static int ref_to_key(const ref * pref, gs_param_key_t * key, iparam_list *plist) { if (r_has_type(pref, t_name)) { ref nref; name_string_ref(plist->memory, pref, &nref); key->data = nref.value.const_bytes; key->size = r_size(&nref); key->persistent = false; /* names may be freed */ } else if (r_has_type(pref, t_integer)) { char istr[sizeof(long) * 8 / 3 + 2]; int len; byte *buf; sprintf(istr, "%d", pref->value.intval); len = strlen(istr); /* GC will take care of freeing this: */ buf = gs_alloc_string(plist->memory, len, "ref_to_key"); if (!buf) return_error(e_VMerror); key->data = buf; key->size = len; key->persistent = true; } else return_error(e_typecheck); return 0; }
/* * make a new dictionary entry. */ static int pl_dict_build_new_entry(pl_dict_t * pdict, const byte * kdata, uint ksize, void *value, pl_dict_entry_t * link) { /* Make a new entry. */ byte *kstr; gs_memory_t *mem = pdict->memory; pl_dict_entry_t *pde; pde = gs_alloc_struct(mem, pl_dict_entry_t, &st_pl_dict_entry, "pl_dict_put(entry)"); kstr = (ksize <= pl_dict_max_short_key ? pde->short_key : gs_alloc_string(mem, ksize, "pl_dict_put(key)")); if (pde == 0 || kstr == 0) { if (kstr && kstr != pde->short_key) gs_free_string(mem, kstr, ksize, "pl_dict_put(key)"); gs_free_object(mem, pde, "pl_dict_put(entry)"); return -1; } memcpy(kstr, kdata, ksize); pde->key.data = (ksize <= pl_dict_max_short_key ? 0 : kstr); pde->key.size = ksize; pde->link = link; pde->value = value; pde->next = pdict->entries; pdict->entries = pde; pdict->entry_count++; return 0; }
static int charstring_make_notdef(gs_glyph_data_t *pgd, gs_font *font) { gs_font_type1 *const pfont = (gs_font_type1 *)font; static const byte char_data[4] = { 139, /* 0 */ 139, /* 0 */ c1_hsbw, cx_endchar }; uint len = max(pfont->data.lenIV, 0) + sizeof(char_data); byte *chars = gs_alloc_string(font->memory, len, "charstring_make_notdef"); if (chars == 0) return_error(e_VMerror); gs_glyph_data_from_string(pgd, chars, len, font); if (pfont->data.lenIV < 0) memcpy(chars, char_data, sizeof(char_data)); else { crypt_state state = crypt_charstring_seed; memcpy(chars + pfont->data.lenIV, char_data, sizeof(char_data)); gs_type1_encrypt(chars, chars, len, &state); } return 0; }
/* Return 0 iff the buffer can't be allocated. */ char * ref_to_string(const ref * pref, gs_memory_t * mem, client_name_t cname) { uint size = r_size(pref); char *str = (char *)gs_alloc_string(mem, size + 1, cname); if (str == 0) return 0; memcpy(str, (const char *)pref->value.bytes, size); str[size] = 0; return str; }
/* Get FontMatrix and FontName parameters. */ static int sub_font_params(gs_memory_t *mem, const ref *op, gs_matrix *pmat, gs_matrix *pomat, ref *pfname) { ref *pmatrix, *pfontname, *pfontstyle, *porigfont, *pfontinfo; if (dict_find_string(op, "FontMatrix", &pmatrix) <= 0 || read_matrix(mem, pmatrix, pmat) < 0 ) return_error(e_invalidfont); if (dict_find_string(op, "OrigFont", &porigfont) <= 0) porigfont = NULL; if (pomat!= NULL) { if (porigfont == NULL || dict_find_string(porigfont, "FontMatrix", &pmatrix) <= 0 || read_matrix(mem, pmatrix, pomat) < 0 ) memset(pomat, 0, sizeof(*pomat)); } /* Use the FontInfo/OrigFontName key preferrentially (created by MS PSCRIPT driver) */ if ((dict_find_string((porigfont != NULL ? porigfont : op), "FontInfo", &pfontinfo) > 0) && r_has_type(pfontinfo, t_dictionary) && (dict_find_string(pfontinfo, "OrigFontName", &pfontname) > 0)) { if ((dict_find_string(pfontinfo, "OrigFontStyle", &pfontstyle) > 0) && r_size(pfontstyle) > 0) { const byte *tmpStr1 = pfontname->value.const_bytes; const byte *tmpStr2 = pfontstyle->value.const_bytes; int fssize1 = r_size(pfontname), fssize2 = r_size(pfontstyle), fssize = fssize1 + fssize2 + 1; byte *sfname = gs_alloc_string(mem, fssize, "sub_font_params"); if (sfname == NULL) return_error(e_VMerror); memcpy(sfname, tmpStr1, fssize1); sfname[fssize1]=',' ; memcpy(sfname + fssize1 + 1, tmpStr2, fssize2); make_string(pfname, a_readonly, fssize, sfname); } else get_font_name(mem, pfname, pfontname); } else if (dict_find_string((porigfont != NULL ? porigfont : op), ".Alias", &pfontname) > 0) { /* If we emulate the font, we want the requested name rather than a substitute. */ get_font_name(mem, pfname, pfontname); } else if (dict_find_string((porigfont != NULL ? porigfont : op), "FontName", &pfontname) > 0) { get_font_name(mem, pfname, pfontname); } else make_empty_string(pfname, a_readonly); return 0; }
/* Prepare to write a string value. */ static int ref_param_write_string_value(ref * pref, const gs_param_string * pvalue, gs_ref_memory_t *imem) { const byte *pdata = pvalue->data; uint n = pvalue->size; if (pvalue->persistent) make_const_string(pref, a_readonly | avm_foreign, n, pdata); else { byte *pstr = gs_alloc_string((gs_memory_t *)imem, n, "ref_param_write_string"); if (pstr == 0) return_error(e_VMerror); memcpy(pstr, pdata, n); make_string(pref, a_readonly | imemory_space(imem), n, pstr); } return 0; }
/* Convert a file name to a C string by adding a null terminator. */ int gs_terminate_file_name(gs_parsed_file_name_t * pfn, gs_memory_t *mem, client_name_t cname) { uint len = pfn->len; char *fname; if (pfn->iodev == NULL) /* no device */ pfn->iodev = iodev_default; if (pfn->memory) return 0; /* already copied */ /* Copy the file name to a C string. */ fname = (char *)gs_alloc_string(mem, len + 1, cname); if (fname == 0) return_error(gs_error_VMerror); memcpy(fname, pfn->fname, len); fname[len] = 0; pfn->memory = mem; pfn->fname = fname; pfn->len = len + 1; /* null terminator */ return 0; }
static char * svg_make_color(gx_device_svg *svg, const gx_drawing_color *pdc) { char *paint = (char *)gs_alloc_string(svg->memory, 8, "svg_make_color"); if (!paint) { gs_throw(gs_error_VMerror, "string allocation failed"); return NULL; } if (gx_dc_is_pure(pdc)) { gx_color_index color = gx_dc_pure_color(pdc); sprintf(paint, "#%06x", (int)(color & 0xffffffL)); } else if (gx_dc_is_null(pdc)) { sprintf(paint, "None"); } else { gs_free_string(svg->memory, (byte *)paint, 8, "svg_make_color"); gs_throw(gs_error_rangecheck, "unknown color type"); return NULL; } return paint; }
/* Get bytes from GlyphData or DataSource. */ static int cid0_read_bytes(gs_font_cid0 *pfont, ulong base, uint count, byte *buf, gs_glyph_data_t *pgd) { const font_data *pfdata = pfont_data(pfont); byte *data = buf; gs_font *gdfont = 0; /* pfont if newly allocated, 0 if not */ int code = 0; /* Check for overflow. */ if (base != (long)base || base > base + count) return_error(e_rangecheck); if (r_has_type(&pfdata->u.cid0.DataSource, t_null)) { /* Get the bytes from GlyphData (a string or array of strings). */ const ref *pgdata = &pfdata->u.cid0.GlyphData; if (r_has_type(pgdata, t_string)) { /* single string */ uint size = r_size(pgdata); if (base >= size || count > size - base) return_error(e_rangecheck); data = pgdata->value.bytes + base; } else { /* array of strings */ /* * The algorithm is similar to the one in * string_array_access_proc in zfont42.c, but it also has to * deal with the case where the requested string crosses array * elements. */ ulong skip = base; uint copied = 0; uint index = 0; ref rstr; uint size; for (;; skip -= size, ++index) { int code = array_get(pfont->memory, pgdata, index, &rstr); if (code < 0) return code; if (!r_has_type(&rstr, t_string)) return_error(e_typecheck); size = r_size(&rstr); if (skip < size) break; } size -= skip; if (count <= size) { data = rstr.value.bytes + skip; } else { /* multiple strings needed */ if (data == 0) { /* no buffer provided */ data = gs_alloc_string(pfont->memory, count, "cid0_read_bytes"); if (data == 0) return_error(e_VMerror); gdfont = (gs_font *)pfont; /* newly allocated */ } memcpy(data, rstr.value.bytes + skip, size); copied = size; while (copied < count) { int code = array_get(pfont->memory, pgdata, ++index, &rstr); if (code < 0) goto err; if (!r_has_type(&rstr, t_string)) { code = gs_note_error(e_typecheck); goto err; } size = r_size(&rstr); if (size > count - copied) size = count - copied; memcpy(data + copied, rstr.value.bytes, size); copied += size; } } } } else { /* Get the bytes from DataSource (a stream). */ stream *s; uint nread; i_ctx_t *i_ctx_p = get_minst_from_memory(pfont->memory)->i_ctx_p; check_read_known_file(i_ctx_p, s, &pfdata->u.cid0.DataSource, return_error); if (sseek(s, base) < 0) return_error(e_ioerror); if (data == 0) { /* no buffer provided */ data = gs_alloc_string(pfont->memory, count, "cid0_read_bytes"); if (data == 0) return_error(e_VMerror); gdfont = (gs_font *)pfont; /* newly allocated */ } if (sgets(s, data, count, &nread) < 0 || nread != count) { code = gs_note_error(e_ioerror); goto err; } } gs_glyph_data_from_string(pgd, data, count, gdfont); return code; err: if (data != buf) gs_free_string(pfont->memory, data, count, "cid0_read_bytes"); return code; }
/* Set up the color space information for a bitmap image or pattern. */ int px_image_color_space(gs_image_t *pim, const px_bitmap_params_t *params, const gs_string *palette, const gs_state *pgs) { int depth = params->depth; gs_color_space *pbase_pcs = NULL; gs_color_space *pcs = NULL; bool cie_space = false; int code = 0; switch ( params->color_space ) { case eGray: pbase_pcs = gs_cspace_new_DeviceGray(pgs->memory); pbase_pcs->cmm_icc_profile_data = pgs->icc_manager->default_gray; pbase_pcs->type = &gs_color_space_type_ICC; rc_increment(pbase_pcs->cmm_icc_profile_data); break; case eRGB: pbase_pcs = gs_cspace_new_DeviceRGB(pgs->memory); pbase_pcs->cmm_icc_profile_data = pgs->icc_manager->default_rgb; pbase_pcs->type = &gs_color_space_type_ICC; rc_increment(pbase_pcs->cmm_icc_profile_data); break; case eSRGB: case eCRGB: if ( pl_cspace_init_SRGB(&pbase_pcs, pgs) < 0 ) /* should not happen */ return_error(errorInsufficientMemory); cie_space = true; pbase_pcs->cmm_icc_profile_data = pgs->icc_manager->default_rgb; pbase_pcs->type = &gs_color_space_type_ICC; rc_increment(pbase_pcs->cmm_icc_profile_data); break; default: return_error(errorIllegalAttributeValue); } if (pbase_pcs == NULL) return_error(errorInsufficientMemory); if ( params->indexed ) { pcs = gs_cspace_alloc(pgs->memory, &gs_color_space_type_Indexed); if ( pcs == NULL ) { /* free the base space also */ rc_decrement(pbase_pcs, "px_image_color_space"); return_error(errorInsufficientMemory); } pcs->base_space = pbase_pcs; pcs->params.indexed.hival = (1 << depth) - 1; pcs->params.indexed.lookup.table.size = palette->size; { uint n = palette->size; byte *p = gs_alloc_string(pgs->memory, n, "px_image_color_space(palette)"); if ( p == 0 ) { rc_decrement(pbase_pcs, "px_image_color_space"); return_error(errorInsufficientMemory); } memcpy(p, palette->data, n); pcs->params.indexed.lookup.table.data = p; } pcs->params.indexed.use_proc = 0; } else { pcs = pbase_pcs; } gs_image_t_init(pim, pcs); pim->ColorSpace = pcs; pim->BitsPerComponent = depth; if ( params->indexed ) pim->Decode[1] = (1 << depth) - 1; /* NB - this needs investigation */ if (cie_space && !px_is_currentcolor_pattern(pgs)) { code = pl_setSRGBcolor((gs_state *)pgs, 0.0, 0.0, 0.0); } return code; }
/* * Create an Indexed color space. This is a single-use procedure, * broken out only for readability. */ static int pdf_indexed_color_space(gx_device_pdf *pdev, cos_value_t *pvalue, const gs_color_space *pcs, cos_array_t *pca) { const gs_indexed_params *pip = &pcs->params.indexed; const gs_color_space *base_space = pcs->base_space; int num_entries = pip->hival + 1; int num_components = gs_color_space_num_components(base_space); uint table_size = num_entries * num_components; /* Guess at the extra space needed for PS string encoding. */ uint string_size = 2 + table_size * 4; uint string_used; byte buf[100]; /* arbitrary */ stream_AXE_state st; stream s, es; gs_memory_t *mem = pdev->pdf_memory; byte *table; byte *palette; cos_value_t v; int code; /* PDF doesn't support Indexed color spaces with more than 256 entries. */ if (num_entries > 256) return_error(gs_error_rangecheck); if (pdev->CompatibilityLevel < 1.3) { switch (gs_color_space_get_index(pcs)) { case gs_color_space_index_Pattern: case gs_color_space_index_Separation: case gs_color_space_index_Indexed: case gs_color_space_index_DeviceN: return_error(gs_error_rangecheck); default: DO_NOTHING; } } table = gs_alloc_string(mem, string_size, "pdf_color_space(table)"); palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)"); if (table == 0 || palette == 0) { gs_free_string(mem, palette, table_size, "pdf_color_space(palette)"); gs_free_string(mem, table, string_size, "pdf_color_space(table)"); return_error(gs_error_VMerror); } s_init(&s, mem); swrite_string(&s, table, string_size); s_init(&es, mem); s_init_state((stream_state *)&st, &s_PSSE_template, NULL); s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s); sputc(&s, '('); if (pcs->params.indexed.use_proc) { gs_client_color cmin, cmax; byte *pnext = palette; int i, j; /* Find the legal range for the color components. */ for (j = 0; j < num_components; ++j) cmin.paint.values[j] = (float)min_long, cmax.paint.values[j] = (float)max_long; gs_color_space_restrict_color(&cmin, base_space); gs_color_space_restrict_color(&cmax, base_space); /* * Compute the palette values, with the legal range for each * one mapped to [0 .. 255]. */ for (i = 0; i < num_entries; ++i) { gs_client_color cc; gs_cspace_indexed_lookup(pcs, i, &cc); for (j = 0; j < num_components; ++j) { float v = (cc.paint.values[j] - cmin.paint.values[j]) * 255 / (cmax.paint.values[j] - cmin.paint.values[j]); *pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v); } } } else memcpy(palette, pip->lookup.table.data, table_size); if (gs_color_space_get_index(base_space) == gs_color_space_index_DeviceRGB ) { /* Check for an all-gray palette3. */ int i; for (i = table_size; (i -= 3) >= 0; ) if (palette[i] != palette[i + 1] || palette[i] != palette[i + 2] ) break; if (i < 0) { /* Change the color space to DeviceGray. */ for (i = 0; i < num_entries; ++i) palette[i] = palette[i * 3]; table_size = num_entries; base_space = gs_cspace_new_DeviceGray(mem); } } stream_write(&es, palette, table_size); gs_free_string(mem, palette, table_size, "pdf_color_space(palette)"); sclose(&es); sflush(&s); string_used = (uint)stell(&s); table = gs_resize_string(mem, table, string_size, string_used, "pdf_color_space(table)"); /* * Since the array is always referenced by name as a resource * rather than being written as a value, even for in-line images, * always use the full name for the color space. * * We don't have to worry about the range of the base space: * in PDF, unlike PostScript, the values from the lookup table are * scaled automatically. */ if ((code = pdf_color_space(pdev, pvalue, NULL, base_space, &pdf_color_space_names, false)) < 0 || (code = cos_array_add(pca, cos_c_string_value(&v, pdf_color_space_names.Indexed /*pcsn->Indexed*/))) < 0 || (code = cos_array_add(pca, pvalue)) < 0 || (code = cos_array_add_int(pca, pip->hival)) < 0 || (code = cos_array_add_no_copy(pca, cos_string_value(&v, table, string_used))) < 0 ) return code; return 0; }
/* This opens %statementedit% or %lineedit% and is also the * continuation proc for callouts. * Input: * string is the statement/line buffer, * int is the write index into string * bool is true if %statementedit% * file is stdin * Output: * file is a string based stream * We store the line being read in a PostScript string. * This limits the size to max_string_size (64k). * This could be increased by storing the input line in something * other than a PostScript string. */ int zfilelineedit(i_ctx_t *i_ctx_p) { uint count = 0; bool in_eol = false; int code; os_ptr op = osp; bool statement; stream *s; stream *ins; gs_string str; uint initial_buf_size; const char *filename; /* * buf exists only for stylistic parallelism: all occurrences of * buf-> could just as well be str. . */ gs_string *const buf = &str; check_type(*op, t_string); /* line assembled so far */ buf->data = op->value.bytes; buf->size = op->tas.rsize; check_type(*(op-1), t_integer); /* index */ count = (op-1)->value.intval; check_type(*(op-2), t_boolean); /* statementedit/lineedit */ statement = (op-2)->value.boolval; check_read_file(ins, op - 3); /* %stdin */ /* extend string */ initial_buf_size = statement ? STATEMENTEDIT_BUF_SIZE : LINEEDIT_BUF_SIZE; if (initial_buf_size > max_string_size) return_error(e_limitcheck); if (!buf->data || (buf->size < initial_buf_size)) { count = 0; buf->data = gs_alloc_string(imemory_system, initial_buf_size, "zfilelineedit(buffer)"); if (buf->data == 0) return_error(e_VMerror); op->value.bytes = buf->data; op->tas.rsize = buf->size = initial_buf_size; } rd: code = zreadline_from(ins, buf, imemory_system, &count, &in_eol); if (buf->size > max_string_size) { /* zreadline_from reallocated the buffer larger than * is valid for a PostScript string. * Return an error, but first realloc the buffer * back to a legal size. */ byte *nbuf = gs_resize_string(imemory_system, buf->data, buf->size, max_string_size, "zfilelineedit(shrink buffer)"); if (nbuf == 0) return_error(e_VMerror); op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = max_string_size; return_error(e_limitcheck); } op->value.bytes = buf->data; /* zreadline_from sometimes resizes the buffer. */ op->tas.rsize = buf->size; switch (code) { case EOFC: code = gs_note_error(e_undefinedfilename); /* falls through */ case 0: break; default: code = gs_note_error(e_ioerror); break; case CALLC: { ref rfile; (op-1)->value.intval = count; /* callout is for stdin */ make_file(&rfile, a_readonly | avm_system, ins->read_id, ins); code = s_handle_read_exception(i_ctx_p, code, &rfile, NULL, 0, zfilelineedit); } break; case 1: /* filled buffer */ { uint nsize = buf->size; byte *nbuf; if (nsize >= max_string_size) { code = gs_note_error(e_limitcheck); break; } else if (nsize >= max_string_size / 2) nsize= max_string_size; else nsize = buf->size * 2; nbuf = gs_resize_string(imemory_system, buf->data, buf->size, nsize, "zfilelineedit(grow buffer)"); if (nbuf == 0) { code = gs_note_error(e_VMerror); break; } op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = nsize; goto rd; } } if (code != 0) return code; if (statement) { /* If we don't have a complete token, keep going. */ stream st; stream *ts = &st; scanner_state state; ref ignore_value; uint depth = ref_stack_count(&o_stack); int code; /* Add a terminating EOL. */ if (count + 1 > buf->size) { uint nsize; byte *nbuf; nsize = buf->size + 1; if (nsize > max_string_size) { return_error(gs_note_error(e_limitcheck)); } else { nbuf = gs_resize_string(imemory_system, buf->data, buf->size, nsize, "zfilelineedit(grow buffer)"); if (nbuf == 0) { code = gs_note_error(e_VMerror); return_error(code); } op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = nsize; } } buf->data[count++] = char_EOL; s_init(ts, NULL); sread_string(ts, buf->data, count); sc: scanner_init_stream_options(&state, ts, SCAN_CHECK_ONLY); code = scan_token(i_ctx_p, &ignore_value, &state); ref_stack_pop_to(&o_stack, depth); if (code < 0) code = scan_EOF; /* stop on scanner error */ switch (code) { case 0: /* read a token */ case scan_BOS: goto sc; /* keep going until we run out of data */ case scan_Refill: goto rd; case scan_EOF: break; default: /* error */ return code; } } buf->data = gs_resize_string(imemory_system, buf->data, buf->size, count, "zfilelineedit(resize buffer)"); if (buf->data == 0) return_error(e_VMerror); op->value.bytes = buf->data; op->tas.rsize = buf->size; s = file_alloc_stream(imemory_system, "zfilelineedit(stream)"); if (s == 0) return_error(e_VMerror); sread_string(s, buf->data, count); s->save_close = s->procs.close; s->procs.close = file_close_disable; filename = statement ? gs_iodev_statementedit.dname : gs_iodev_lineedit.dname; code = ssetfilename(s, (const byte *)filename, strlen(filename)+1); if (code < 0) { sclose(s); return_error(e_VMerror); } pop(3); make_stream_file(osp, s, "r"); return code; }
/* * 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; }
/* * Implement get_params for a sample device CRD. A useful convention, * for devices that can provide more than one CRD, is to have a settable * parameter CRDName, which gives the name of the CRD in use. This sample * code provides a constant CRDName: making it settable is left as an * exercise to the reader. */ int sample_device_crd_get_params(gx_device *pdev, gs_param_list *plist, const char *crd_param_name) { int ecode = 0; if (param_requested(plist, "CRDName") > 0) { gs_param_string cns; int code; cns.data = (const byte *)crd_param_name; cns.size = strlen(crd_param_name); cns.persistent = true; code = param_write_string(plist, "CRDName", &cns); if (code < 0) ecode = code; } if (param_requested(plist, crd_param_name) > 0) { gs_cie_render *pcrd; int code = gs_cie_render1_build(&pcrd, pdev->memory, "sample_device_crd_get_params"); if (code >= 0) { gs_cie_transform_proc3 tpqr; tpqr = bit_TransformPQR; tpqr.driver_name = pdev->dname; code = gs_cie_render1_initialize(pdev->memory, pcrd, NULL, &bit_WhitePoint, NULL /*BlackPoint*/, NULL /*MatrixPQR*/, &bit_RangePQR, &tpqr, NULL /*MatrixLMN*/, &bit_EncodeLMN, &bit_RangeLMN, &bit_MatrixABC, &bit_EncodeABC, NULL /*RangeABC*/, &bit_RenderTable); if (code >= 0) { code = param_write_cie_render1(plist, crd_param_name, pcrd, pdev->memory); } rc_decrement(pcrd, "sample_device_crd_get_params"); /* release */ } if (code < 0) ecode = code; } if (param_requested(plist, bit_TransformPQR.proc_name) > 0) { /* * We definitely do not recommend the following use of a static * to hold the address: this is a shortcut. */ gs_cie_transform_proc my_proc = bit_TransformPQR_proc; byte *my_addr = gs_alloc_string(pdev->memory, sizeof(my_proc), "sd_crd_get_params(proc)"); int code; if (my_addr == 0) code = gs_note_error(gs_error_VMerror); else { gs_param_string as; memcpy(my_addr, &my_proc, sizeof(my_proc)); as.data = my_addr; as.size = sizeof(my_proc); as.persistent = true; code = param_write_string(plist, bit_TransformPQR.proc_name, &as); } if (code < 0) ecode = code; } return ecode; }
/* We separate device allocation and initialization at customer request. */ int gs_initialize_wordimagedevice(gx_device_memory * new_dev, const gs_matrix * pmat, uint width, uint height, const byte * colors, int colors_size, bool word_oriented, bool page_device, gs_memory_t * mem) { const gx_device_memory *proto_dev; int palette_count = colors_size; int num_components = 1; int pcount; int bits_per_pixel; float x_pixels_per_unit, y_pixels_per_unit; byte palette[256 * 3]; bool has_color; switch (colors_size) { case 3 * 2: palette_count = 2; num_components = 3; case 2: bits_per_pixel = 1; break; case 3 * 4: palette_count = 4; num_components = 3; case 4: bits_per_pixel = 2; break; case 3 * 16: palette_count = 16; num_components = 3; case 16: bits_per_pixel = 4; break; case 3 * 256: palette_count = 256; num_components = 3; case 256: bits_per_pixel = 8; break; case -16: bits_per_pixel = 16; palette_count = 0; break; case -24: bits_per_pixel = 24; palette_count = 0; break; case -32: bits_per_pixel = 32; palette_count = 0; break; default: return_error(gs_error_rangecheck); } proto_dev = (word_oriented ? gdev_mem_word_device_for_bits(bits_per_pixel) : gdev_mem_device_for_bits(bits_per_pixel)); if (proto_dev == 0) /* no suitable device */ return_error(gs_error_rangecheck); pcount = palette_count * 3; /* Check to make sure the palette contains white and black, */ /* and, if it has any colors, the six primaries. */ if (bits_per_pixel <= 8) { const byte *p; byte *q; int primary_mask = 0; int i; has_color = false; for (i = 0, p = colors, q = palette; i < palette_count; i++, q += 3 ) { int mask = 1; switch (num_components) { case 1: /* gray */ q[0] = q[1] = q[2] = *p++; break; default /* case 3 */ : /* RGB */ q[0] = p[0], q[1] = p[1], q[2] = p[2]; p += 3; } #define shift_mask(b,n)\ switch ( b ) { case 0xff: mask <<= n; case 0: break; default: mask = 0; } shift_mask(q[0], 4); shift_mask(q[1], 2); shift_mask(q[2], 1); #undef shift_mask primary_mask |= mask; if (q[0] != q[1] || q[0] != q[2]) has_color = true; } switch (primary_mask) { case 129: /* just black and white */ if (has_color) /* color but no primaries */ return_error(gs_error_rangecheck); case 255: /* full color */ break; default: return_error(gs_error_rangecheck); } } else has_color = true; /* * The initial transformation matrix must map 1 user unit to * 1/72". Let W and H be the width and height in pixels, and * assume the initial matrix is of the form [A 0 0 B X Y]. * Then the size of the image in user units is (W/|A|,H/|B|), * hence the size in inches is ((W/|A|)/72,(H/|B|)/72), so * the number of pixels per inch is * (W/((W/|A|)/72),H/((H/|B|)/72)), or (|A|*72,|B|*72). * Similarly, if the initial matrix is [0 A B 0 X Y] for a 90 * or 270 degree rotation, the size of the image in user * units is (W/|B|,H/|A|), so the pixels per inch are * (|B|*72,|A|*72). We forbid non-orthogonal transformation * matrices. */ if (is_fzero2(pmat->xy, pmat->yx)) x_pixels_per_unit = pmat->xx, y_pixels_per_unit = pmat->yy; else if (is_fzero2(pmat->xx, pmat->yy)) x_pixels_per_unit = pmat->yx, y_pixels_per_unit = pmat->xy; else return_error(gs_error_undefinedresult); /* All checks done, initialize the device. */ if (bits_per_pixel == 1) { /* Determine the polarity from the palette. */ gs_make_mem_device(new_dev, proto_dev, mem, (page_device ? 1 : -1), 0); /* This is somewhat bogus, but does the right thing */ /* in the only cases we care about. */ gdev_mem_mono_set_inverted(new_dev, (palette[0] | palette[1] | palette[2]) != 0); } else { byte *dev_palette = gs_alloc_string(mem, pcount, "gs_makeimagedevice(palette)"); if (dev_palette == 0) return_error(gs_error_VMerror); gs_make_mem_device(new_dev, proto_dev, mem, (page_device ? 1 : -1), 0); new_dev->palette.size = pcount; new_dev->palette.data = dev_palette; memcpy(dev_palette, palette, pcount); if (!has_color) { new_dev->color_info.num_components = 1; new_dev->color_info.max_color = 0; new_dev->color_info.dither_colors = 0; new_dev->color_info.gray_index = 0; } } /* Memory defice is always initialised as an internal device but */ /* this is an external device */ new_dev->retained = true; rc_init(new_dev, new_dev->memory, 1); new_dev->initial_matrix = *pmat; new_dev->MarginsHWResolution[0] = new_dev->HWResolution[0] = fabs(x_pixels_per_unit) * 72; new_dev->MarginsHWResolution[1] = new_dev->HWResolution[1] = fabs(y_pixels_per_unit) * 72; gx_device_set_width_height((gx_device *) new_dev, width, height); /* Set the ImagingBBox so we get a correct clipping region. */ { gs_rect bbox; bbox.p.x = 0; bbox.p.y = 0; bbox.q.x = width; bbox.q.y = height; gs_bbox_transform_inverse(&bbox, pmat, &bbox); new_dev->ImagingBBox[0] = bbox.p.x; new_dev->ImagingBBox[1] = bbox.p.y; new_dev->ImagingBBox[2] = bbox.q.x; new_dev->ImagingBBox[3] = bbox.q.y; new_dev->ImagingBBox_set = true; } /* The bitmap will be allocated when the device is opened. */ new_dev->is_open = false; new_dev->bitmap_memory = mem; return 0; }
int gs_image_next_planes(gs_image_enum * penum, gs_const_string *plane_data /*[num_planes]*/, uint *used /*[num_planes]*/) { const int num_planes = penum->num_planes; int i; int code = 0; #ifdef DEBUG vd_get_dc('i'); vd_set_shift(0, 0); vd_set_scale(0.01); vd_set_origin(0, 0); if (gs_debug_c('b')) { int pi; for (pi = 0; pi < num_planes; ++pi) dprintf6("[b]plane %d source=0x%lx,%u pos=%u data=0x%lx,%u\n", pi, (ulong)penum->planes[pi].source.data, penum->planes[pi].source.size, penum->planes[pi].pos, (ulong)plane_data[pi].data, plane_data[pi].size); } #endif for (i = 0; i < num_planes; ++i) { used[i] = 0; if (penum->wanted[i] && plane_data[i].size != 0) { penum->planes[i].source.size = plane_data[i].size; penum->planes[i].source.data = plane_data[i].data; } } for (;;) { /* If wanted can vary, only transfer 1 row at a time. */ int h = (penum->wanted_varies ? 1 : max_int); /* Move partial rows from source[] to row[]. */ for (i = 0; i < num_planes; ++i) { int pos, size; uint raster; if (!penum->wanted[i]) continue; /* skip unwanted planes */ pos = penum->planes[i].pos; size = penum->planes[i].source.size; raster = penum->image_planes[i].raster; if (size > 0) { if (pos < raster && (pos != 0 || size < raster)) { /* Buffer a partial row. */ int copy = min(size, raster - pos); uint old_size = penum->planes[i].row.size; /* Make sure the row buffer is fully allocated. */ if (raster > old_size) { gs_memory_t *mem = gs_image_row_memory(penum); byte *old_data = penum->planes[i].row.data; byte *row = (old_data == 0 ? gs_alloc_string(mem, raster, "gs_image_next(row)") : gs_resize_string(mem, old_data, old_size, raster, "gs_image_next(row)")); if_debug5('b', "[b]plane %d row (0x%lx,%u) => (0x%lx,%u)\n", i, (ulong)old_data, old_size, (ulong)row, raster); if (row == 0) { code = gs_note_error(gs_error_VMerror); free_row_buffers(penum, i, "gs_image_next(row)"); break; } penum->planes[i].row.data = row; penum->planes[i].row.size = raster; } memcpy(penum->planes[i].row.data + pos, penum->planes[i].source.data, copy); penum->planes[i].source.data += copy; penum->planes[i].source.size = size -= copy; penum->planes[i].pos = pos += copy; used[i] += copy; } } if (h == 0) continue; /* can't transfer any data this cycle */ if (pos == raster) { /* * This plane will be transferred from the row buffer, * so we can only transfer one row. */ h = min(h, 1); penum->image_planes[i].data = penum->planes[i].row.data; } else if (pos == 0 && size >= raster) { /* We can transfer 1 or more planes from the source. */ h = min(h, size / raster); penum->image_planes[i].data = penum->planes[i].source.data; } else h = 0; /* not enough data in this plane */ } if (h == 0 || code != 0) break; /* Pass rows to the device. */ if (penum->dev == 0) { /* * ****** NOTE: THE FOLLOWING IS NOT CORRECT FOR ImageType 3 * ****** InterleaveType 2, SINCE MASK HEIGHT AND IMAGE HEIGHT * ****** MAY DIFFER (BY AN INTEGER FACTOR). ALSO, plane_depths[0] * ****** AND plane_widths[0] ARE NOT UPDATED. */ if (penum->y + h < penum->height) code = 0; else h = penum->height - penum->y, code = 1; } else { code = gx_image_plane_data_rows(penum->info, penum->image_planes, h, &h); if_debug2('b', "[b]used %d, code=%d\n", h, code); penum->error = code < 0; } penum->y += h; /* Update positions and sizes. */ if (h == 0) break; for (i = 0; i < num_planes; ++i) { int count; if (!penum->wanted[i]) continue; count = penum->image_planes[i].raster * h; if (penum->planes[i].pos) { /* We transferred the row from the row buffer. */ penum->planes[i].pos = 0; } else { /* We transferred the row(s) from the source. */ penum->planes[i].source.data += count; penum->planes[i].source.size -= count; used[i] += count; } } cache_planes(penum); if (code > 0) break; } /* Return the retained data pointers. */ for (i = 0; i < num_planes; ++i) plane_data[i] = penum->planes[i].source; vd_release_dc; return code; }
static int px_gstate_client_copy_for(void *to, void *from, gs_state_copy_reason_t reason) { #define pxfrom ((px_gstate_t *)from) #define pxto ((px_gstate_t *)to) px_gstate_rc_adjust(pxfrom, 1, pxfrom->memory); px_gstate_rc_adjust(pxto, -1, pxto->memory); /* * In the context of the PCL XL code, this routine may be called for * gsave, grestore, or gstate (copying the gstate for makepattern * or Pattern rendering). See gxstate.h for details of the 'from' * and 'to' arguments for each of these cases. * * We have some structures that belong to the individual gstates for * storage management purposes. Currently these are: * dither_matrix, temp_pattern_dict * px_gstate_client_alloc initializes them to an empty state. * For gsave and gstate, the new current gstate or copied gstate * respectively should have the empty structure. For grestore, * we want to swap the structures, because we will then free the * saved gstate (and release the structure that was in the current * gstate before the grestore). * * halftone.thresholds is a different special case. We need to * copy it for gsave and gstate, and free it on grestore. */ { gs_string tmat; gs_string thtt; pl_dict_t tdict; gs_string *phtt; tmat = pxto->dither_matrix; thtt = pxto->halftone.thresholds; tdict = pxto->temp_pattern_dict; *pxto = *pxfrom; switch ( reason ) { case copy_for_gstate: /* Just put back the (empty) 'to' structures. */ pxto->dither_matrix = tmat; pxto->temp_pattern_dict = tdict; phtt = &pxto->halftone.thresholds; goto copy; case copy_for_gsave: /* Swap the structures, but set the parent of the new */ /* (empty) dictionary to the old one. */ pxfrom->dither_matrix = tmat; pxfrom->temp_pattern_dict = tdict; pl_dict_set_parent(&pxfrom->temp_pattern_dict, &pxto->temp_pattern_dict); phtt = &pxfrom->halftone.thresholds; copy: if ( phtt->data ) { byte *str = gs_alloc_string(pxfrom->memory, phtt->size, "px_gstate_client_copy(thresholds)"); if ( str == 0 ) return_error(errorInsufficientMemory); memcpy(str, phtt->data, phtt->size); phtt->data = str; } break; default: /* copy_for_grestore */ /* Swap the structures. */ pxfrom->dither_matrix = tmat; pxfrom->halftone.thresholds = thtt; pxfrom->temp_pattern_dict = tdict; } } return 0; #undef pxfrom #undef pxto }