/* * We have collected all of the sample data. Create a type 0 function stucture. */ static int sampled_data_finish(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_sampled_data_enum *penum = senum; /* Build a type 0 function using the given parameters */ gs_function_Sd_params_t * params = (gs_function_Sd_params_t *)&penum->pfn->params; gs_function_t * pfn; ref cref; /* closure */ int code = gs_function_Sd_init(&pfn, params, imemory); if (code < 0) return code; code = ialloc_ref_array(&cref, a_executable | a_execute, 2, "sampled_data_finish(cref)"); if (code < 0) return code; make_istruct_new(cref.value.refs, a_executable | a_execute, pfn); make_oper_new(cref.value.refs + 1, 0, zexecfunction); ref_assign(op, &cref); esp -= estack_storage; ifree_object(penum->pfn, "sampled_data_finish(pfn)"); ifree_object(penum, "sampled_data_finish(enum)"); return o_pop_estack; }
int cie_cache_joint(i_ctx_t *i_ctx_p, const ref_cie_render_procs * pcrprocs, const gs_cie_common *pcie, gs_state * pgs) { const gs_cie_render *pcrd = gs_currentcolorrendering(pgs); gx_cie_joint_caches *pjc = gx_unshare_cie_caches(pgs); gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_state_memory(pgs); ref pqr_procs; uint space; int code; int i; if (pcrd == 0) /* cache is not set up yet */ return 0; if (pjc == 0) /* must already be allocated */ return_error(e_VMerror); if (r_has_type(&pcrprocs->TransformPQR, t_null)) { /* * This CRD came from a driver, not from a PostScript dictionary. * Resample TransformPQR in C code. */ return gs_cie_cs_complete(pgs, true); } gs_cie_compute_points_sd(pjc, pcie, pcrd); code = ialloc_ref_array(&pqr_procs, a_readonly, 3 * (1 + 4 + 4 * 6), "cie_cache_common"); if (code < 0) return code; /* When we're done, deallocate the procs and complete the caches. */ check_estack(3); cie_cache_push_finish(i_ctx_p, cie_tpqr_finish, imem, pgs); *++esp = pqr_procs; space = r_space(&pqr_procs); for (i = 0; i < 3; i++) { ref *p = pqr_procs.value.refs + 3 + (4 + 4 * 6) * i; const float *ppt = (float *)&pjc->points_sd; int j; make_array(pqr_procs.value.refs + i, a_readonly | a_executable | space, 4, p); make_array(p, a_readonly | space, 4 * 6, p + 4); p[1] = pcrprocs->TransformPQR.value.refs[i]; make_oper(p + 2, 0, cie_exec_tpqr); make_oper(p + 3, 0, cie_post_exec_tpqr); for (j = 0, p += 4; j < 4 * 6; j++, p++, ppt++) make_real(p, *ppt); } return cie_prepare_cache3(i_ctx_p, &pcrd->RangePQR, pqr_procs.value.const_refs, pjc->TransformPQR.caches, pjc, imem, "Transform.PQR"); }
/* <int> array <array> */ int zarray(i_ctx_t *i_ctx_p) { os_ptr op = osp; uint size; int code; check_int_leu(*op, max_array_size); size = op->value.intval; code = ialloc_ref_array((ref *)op, a_all, size, "array"); if (code < 0) return code; refset_null(op->value.refs, size); return 0; }
/* Create a function procedure from a function structure. */ static int make_function_proc(i_ctx_t *i_ctx_p, ref *op, gs_function_t *pfn) { ref cref; /* closure */ int code; code = ialloc_ref_array(&cref, a_executable | a_execute, 2, ".buildfunction"); if (code < 0) return code; make_istruct_new(cref.value.refs, a_executable | a_execute, pfn); make_oper_new(cref.value.refs + 1, 0, zexecfunction); ref_assign(op, &cref); return 0; }
/* <int> array <array> */ int zarray(i_ctx_t *i_ctx_p) { os_ptr op = osp; uint size; int code; check_type(*op, t_integer); if (op->value.intval < 0) return_error(gs_error_rangecheck); if (op->value.intval > max_array_size) return_error(gs_error_limitcheck); size = op->value.intval; code = ialloc_ref_array((ref *)op, a_all, size, "array"); if (code < 0) return code; refset_null(op->value.refs, size); return 0; }
/* Create an op_array table. */ static int alloc_op_array_table(i_ctx_t *i_ctx_p, uint size, uint space, op_array_table *opt) { uint save_space = ialloc_space(idmemory); int code; ialloc_set_space(idmemory, space); code = ialloc_ref_array(&opt->table, a_readonly, size, "op_array table"); ialloc_set_space(idmemory, save_space); if (code < 0) return code; refset_null(opt->table.value.refs, size); opt->nx_table = (ushort *) ialloc_byte_array(size, sizeof(ushort), "op_array nx_table"); if (opt->nx_table == 0) return_error(e_VMerror); opt->count = 0; opt->attrs = space | a_executable; return 0; }
/* initialize the dictionaries that hold operator definitions. */ int obj_init(i_ctx_t **pi_ctx_p, gs_dual_memory_t *idmem) { int level = gs_op_language_level(); ref system_dict; i_ctx_t *i_ctx_p; int code; /* * Create systemdict. The context machinery requires that * we do this before initializing the interpreter. */ code = dict_alloc(idmem->space_global, (level >= 3 ? SYSTEMDICT_LL3_SIZE : level >= 2 ? SYSTEMDICT_LEVEL2_SIZE : SYSTEMDICT_SIZE), &system_dict); if (code < 0) return code; /* Initialize the interpreter. */ code = gs_interp_init(pi_ctx_p, &system_dict, idmem); if (code < 0) return code; i_ctx_p = *pi_ctx_p; { #define icount countof(initial_dictionaries) ref idicts[icount]; int i; const op_def *const *tptr; min_dstack_size = MIN_DSTACK_SIZE; refset_null(idicts, icount); /* Put systemdict on the dictionary stack. */ if (level >= 2) { dsp += 2; /* * For the moment, let globaldict be an alias for systemdict. */ dsp[-1] = system_dict; min_dstack_size++; } else { ++dsp; } *dsp = system_dict; /* Create dictionaries which are to be homes for operators. */ for (tptr = op_defs_all; *tptr != 0; tptr++) { const op_def *def; for (def = *tptr; def->oname != 0; def++) if (op_def_is_begin_dict(def)) { if (make_initial_dict(i_ctx_p, def->oname, idicts) == 0) return_error(e_VMerror); } } /* Set up the initial dstack. */ for (i = 0; i < countof(initial_dstack); i++) { const char *dname = initial_dstack[i]; ++dsp; if (!strcmp(dname, "userdict")) dstack_userdict_index = dsp - dsbot; ref_assign(dsp, make_initial_dict(i_ctx_p, dname, idicts)); } /* Enter names of referenced initial dictionaries into systemdict. */ initial_enter_name("systemdict", systemdict); for (i = 0; i < icount; i++) { ref *idict = &idicts[i]; if (!r_has_type(idict, t_null)) { /* * Note that we enter the dictionary in systemdict * even if it is in local VM. There is a special * provision in the garbage collector for this: * see ivmspace.h for more information. * In order to do this, we must temporarily * identify systemdict as local, so that the * store check in dict_put won't fail. */ uint save_space = r_space(systemdict); r_set_space(systemdict, avm_local); code = initial_enter_name(initial_dictionaries[i].name, idict); r_set_space(systemdict, save_space); if (code < 0) return code; } } #undef icount } gs_interp_reset(i_ctx_p); { ref vnull, vtrue, vfalse; make_null(&vnull); make_true(&vtrue); make_false(&vfalse); if ((code = initial_enter_name("null", &vnull)) < 0 || (code = initial_enter_name("true", &vtrue)) < 0 || (code = initial_enter_name("false", &vfalse)) < 0 ) return code; } /* Create the error name table */ { int n = countof(gs_error_names) - 1; int i; ref era; code = ialloc_ref_array(&era, a_readonly, n, "ErrorNames"); if (code < 0) return code; for (i = 0; i < n; i++) if ((code = name_enter_string(imemory, (const char *)gs_error_names[i], era.value.refs + i)) < 0) return code; return initial_enter_name("ErrorNames", &era); } }
/* .getnativefonts [ [<name> <path>] ... ] */ static int z_fontenum(i_ctx_t *i_ctx_p) { os_ptr op = osp; void *enum_state; int code = 0; int e,elements; char *fontname, *path; fontenum_t *r, *results; ref array; uint length; byte *string; enum_state = gp_enumerate_fonts_init(imemory); if (enum_state == NULL) { /* put false on the stack and return */ push(1); make_bool(op, false); return code; } r = results = gs_malloc(imemory->non_gc_memory, 1, sizeof(fontenum_t), "fontenum list"); elements = 0; while((code = gp_enumerate_fonts_next(enum_state, &fontname, &path )) > 0) { if (fontname == NULL || path == NULL) { gp_enumerate_fonts_free(enum_state); return_error(e_ioerror); } length = strlen(fontname) + 1; r->fontname = gs_malloc(imemory->non_gc_memory, length, 1, "native font name"); memcpy(r->fontname, fontname, length); length = strlen(path) + 1; r->path = gs_malloc(imemory->non_gc_memory, length, 1, "native font path"); memcpy(r->path, path, length); r->next = gs_malloc(imemory->non_gc_memory, 1, sizeof(fontenum_t), "fontenum list"); r = r->next; elements += 1; } gp_enumerate_fonts_free(enum_state); code = ialloc_ref_array(&array, a_all | icurrent_space, elements, "native fontmap"); r = results; for (e = 0; e < elements; e++) { ref mapping; code = ialloc_ref_array(&mapping, a_all | icurrent_space, 2, "native font mapping"); length = strlen(r->fontname); string = ialloc_string(length, "native font name"); if (string == NULL) return_error(e_VMerror); memcpy(string, r->fontname, length); make_string(&(mapping.value.refs[0]), a_all | icurrent_space, length, string); length = strlen(r->path); string = ialloc_string(length, "native font path"); if (string == NULL) return_error(e_VMerror); memcpy(string, r->path, length); make_string(&(mapping.value.refs[1]), a_all | icurrent_space, length, string); ref_assign(&(array.value.refs[e]), &mapping); results = r; r = r->next; gs_free(imemory->non_gc_memory, results->fontname, strlen(results->fontname) + 1, 1, "native font name"); gs_free(imemory->non_gc_memory, results->path, strlen(results->path) + 1, 1, "native font path"); gs_free(imemory->non_gc_memory, results, 1, sizeof(fontenum_t), "fontenum list"); } push(2); ref_assign(op-1, &array); make_bool(op, true); return code; }
static int zgetpath(i_ctx_t *i_ctx_p) { os_ptr op = osp; int i, code, path_size, leaf_count; ref *main_ref, *operators[5]; push(1); path_size = code = path_length_for_upath(igs->path); if (code < 0) return code; leaf_count = (path_size + max_array_size - 1) / max_array_size; code = ialloc_ref_array(op, a_all, leaf_count, "zgetpath_master"); if (code < 0) return code; if (path_size == 0) return 0; if (dict_find_string(systemdict, "moveto", &operators[1]) <= 0 || dict_find_string(systemdict, "lineto", &operators[2]) <= 0 || dict_find_string(systemdict, "curveto", &operators[3]) <= 0 || dict_find_string(systemdict, "closepath", &operators[4]) <= 0) return_error(e_undefined); main_ref = op->value.refs; for (i = 0; i < leaf_count; i++) { int leaf_size = ( i == leaf_count - 1) ? path_size - i * max_array_size : max_array_size; code = ialloc_ref_array(&main_ref[i], a_all | a_executable, leaf_size, "zgetpath_leaf"); if (code < 0) return code; } { int pe, j, k; gs_path_enum penum; static const int oper_count[5] = { 0, 2, 2, 6, 0 }; gs_point pts[3]; const double *fts[6]; fts[0] = &pts[0].x; fts[1] = &pts[0].y; fts[2] = &pts[1].x; fts[3] = &pts[1].y; fts[4] = &pts[2].x; fts[5] = &pts[2].y; main_ref = op->value.refs; gs_path_enum_copy_init(&penum, igs, false); pe = gs_path_enum_next(&penum, pts); if (pe < 0) return pe; k = 0; for (i = 0; i < leaf_count; i++) { int leaf_size = ( i == leaf_count - 1) ? path_size - i * max_array_size : max_array_size; ref *leaf_ref = main_ref[i].value.refs; for (j = 0; j < leaf_size; j++) { if (k < oper_count[pe]) make_real_new(&leaf_ref[j], (float)*fts[k++]); else { k = 0; ref_assign(&leaf_ref[j], operators[pe]); pe = gs_path_enum_next(&penum, pts); if (pe <= 0) return pe; if (pe >= 5) return_error(e_unregistered); } } } } return 0; }
int make_upath(i_ctx_t *i_ctx_p, ref *rupath, gs_state *pgs, gx_path *ppath, bool with_ucache) { int size = (with_ucache ? 6 : 5); gs_path_enum penum; gs_rect bbox; int op; ref *next; int code; /* Compute the bounding box. */ if ((code = gs_upathbbox(pgs, &bbox, true)) < 0) { /* * Note: Adobe throws 'nocurrentpoint' error, but the PLRM does * not list this as a possible error from 'upath', so if we are * not in CPSI compatibility mode, we set a reasonable default * bbox instead. */ if (code != e_nocurrentpoint || gs_currentcpsimode(imemory)) return code; bbox.p.x = bbox.p.y = bbox.q.x = bbox.q.y = 0; } code = path_length_for_upath(ppath); if (code < 0) return code; size += code; if (size >= 65536) return_error(e_limitcheck); code = ialloc_ref_array(rupath, a_all | a_executable, size, "make_upath"); if (code < 0) return code; /* Construct the path. */ next = rupath->value.refs; if (with_ucache) { if ((code = name_enter_string(pgs->memory, "ucache", next)) < 0) return code; r_set_attrs(next, a_executable | l_new); ++next; } make_real_new(next, bbox.p.x); make_real_new(next + 1, bbox.p.y); make_real_new(next + 2, bbox.q.x); make_real_new(next + 3, bbox.q.y); next += 4; if ((code = name_enter_string(pgs->memory, "setbbox", next)) < 0) return code; r_set_attrs(next, a_executable | l_new); ++next; { gs_point pts[3]; /* Patch the path in the gstate to set up the enumerator. */ gx_path *save_path = pgs->path; pgs->path = ppath; gs_path_enum_copy_init(&penum, pgs, false); pgs->path = save_path; while ((op = gs_path_enum_next(&penum, pts)) != 0) { const char *opstr; switch (op) { case gs_pe_moveto: opstr = "moveto"; goto ml; case gs_pe_lineto: opstr = "lineto"; ml:make_real_new(next, pts[0].x); make_real_new(next + 1, pts[0].y); next += 2; break; case gs_pe_curveto: opstr = "curveto"; make_real_new(next, pts[0].x); make_real_new(next + 1, pts[0].y); make_real_new(next + 2, pts[1].x); make_real_new(next + 3, pts[1].y); make_real_new(next + 4, pts[2].x); make_real_new(next + 5, pts[2].y); next += 6; break; case gs_pe_closepath: opstr = "closepath"; break; default: return_error(e_unregistered); } if ((code = name_enter_string(pgs->memory, opstr, next)) < 0) return code; r_set_attrs(next, a_executable); ++next; } } return 0; }
/* or a negative error code. */ int build_gs_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font ** ppfont, font_type ftype, gs_memory_type_ptr_t pstype, const build_proc_refs * pbuild, build_font_options_t options) { ref kname; /* t_string */ ref *pftype; ref *pencoding = 0; bool bitmapwidths; int exactsize, inbetweensize, transformedchar; int wmode; int code; gs_font *pfont; ref *pfid; ref *aop = dict_access_ref(op); bool cpsi_mode = gs_currentcpsimode(imemory); get_font_name(imemory, &kname, op - 1); if (dict_find_string(op, "FontType", &pftype) <= 0 || !r_has_type(pftype, t_integer) || pftype->value.intval != (int)ftype ) return_error(e_invalidfont); if (dict_find_string(op, "Encoding", &pencoding) <= 0) { if (!(options & bf_Encoding_optional)) return_error(e_invalidfont); pencoding = 0; } else { if (!r_is_array(pencoding)) return_error(e_invalidfont); } if (pencoding) { /* observed Adobe behavior */ int count = r_size(pencoding); int type = ftype ? t_name : t_integer; bool fixit = false; while (count--) { ref r; if ((code = array_get(imemory, pencoding, count, &r)) < 0 || !(r_has_type(&r, type) || r_has_type(&r, t_null))) { if (!cpsi_mode && ftype == ft_user_defined) { if (code < 0 || r_has_type(&r, t_null)) { return_error(e_typecheck); } fixit = true; break; } else { return_error(e_typecheck); } } } /* For at least Type 3 fonts, Adobe Distiller will "fix" an Encoding array, as in, for example * Bug 692681 where the arrays contain integers rather than names. Once the font is instantiated * the integers have been converted to names. * It is preferable to to this manipulation here, rather than in Postscript, because we are less * restricted by read-only attributes and VM save levels. */ if (fixit) { ref penc; uint size = 0; char buf[32], *bptr; avm_space curglob = ialloc_space(idmemory); avm_space useglob = r_is_local(pencoding) ? avm_local : avm_global; ialloc_set_space(idmemory, useglob); count = r_size(pencoding); if ((code = ialloc_ref_array(&penc, (r_type_attrs(pencoding) & a_readonly), count, "build_gs_font")) < 0) return code; while (count--) { ref r; if (array_get(imemory, pencoding, count, &r) < 0){ return_error(e_typecheck); } /* For type 3, we know the Encoding entries must be names */ if (r_has_type(&r, t_name)){ ref_assign(&(penc.value.refs[count]), &r); } else { if ((code = obj_cvs(imemory, &r, (byte *)buf, 32, &size, (const byte **)(&bptr))) < 0) { return(code); } if ((code = name_ref(imemory, (const byte *)bptr, size, &r, true)) < 0) return code; ref_assign(&(penc.value.refs[count]), &r); } } if ((code = dict_put_string(osp, "Encoding", &penc, NULL)) < 0) return code; ialloc_set_space(idmemory, curglob); } } if ((code = dict_int_param(op, "WMode", 0, 1, 0, &wmode)) < 0 || (code = dict_bool_param(op, "BitmapWidths", false, &bitmapwidths)) < 0 || (code = dict_int_param(op, "ExactSize", 0, 2, fbit_use_bitmaps, &exactsize)) < 0 || (code = dict_int_param(op, "InBetweenSize", 0, 2, fbit_use_outlines, &inbetweensize)) < 0 || (code = dict_int_param(op, "TransformedChar", 0, 2, fbit_use_outlines, &transformedchar)) < 0 ) return code; code = dict_find_string(op, "FID", &pfid); if (code > 0 && r_has_type(pfid, t_fontID)) { /* silently ignore invalid FID per CET 13-05.ps */ /* * If this font has a FID entry already, it might be a scaled font * made by makefont or scalefont; in a Level 2 environment, it might * be an existing font being registered under a second name, or a * re-encoded font (which was invalid in Level 1, but dvips did it * anyway). */ pfont = r_ptr(pfid, gs_font); /* * If the following condition is false this is a re-encoded font, * or some other questionable situation in which the FID * was preserved. Pretend the FID wasn't there. */ if (obj_eq(pfont->memory, pfont_dict(pfont), op)) { if (pfont->base == pfont) { /* original font */ if (!level2_enabled) return_error(e_invalidfont); *ppfont = pfont; return 1; } else { /* This was made by makefont or scalefont. */ /* Just insert the new name. */ gs_matrix mat; ref fname; /* t_string */ code = sub_font_params(imemory, op, &mat, NULL, &fname); if (code < 0) return code; code = 1; copy_font_name(&pfont->font_name, &fname); goto set_name; } } } /* This is a new font. */ if (!r_has_attr(aop, a_write)) return_error(e_invalidaccess); { ref encoding; /* * Since add_FID may resize the dictionary and cause * pencoding to become invalid, save the Encoding. */ if (pencoding) { encoding = *pencoding; pencoding = &encoding; } code = build_gs_sub_font(i_ctx_p, op, &pfont, ftype, pstype, pbuild, pencoding, op); if (code < 0) return code; } pfont->BitmapWidths = bitmapwidths; pfont->ExactSize = (fbit_type)exactsize; pfont->InBetweenSize = (fbit_type)inbetweensize; pfont->TransformedChar = (fbit_type)transformedchar; pfont->WMode = wmode; pfont->procs.font_info = zfont_info; code = 0; set_name: copy_font_name(&pfont->key_name, &kname); *ppfont = pfont; return code; }