/* * Ensure that a dictionary uses the unpacked representation for keys. * We can't just use dict_resize, because the values slots mustn't move. */ int dict_unpack(ref * pdref, dict_stack_t *pds) { dict *pdict = pdref->value.pdict; if (!dict_is_packed(pdict)) return 0; /* nothing to do */ { gs_ref_memory_t *mem = dict_memory(pdict); uint count = nslots(pdict); const ref_packed *okp = pdict->keys.value.packed; ref old_keys; int code; ref *nkp; old_keys = pdict->keys; if (ref_must_save_in(mem, &old_keys)) ref_do_save_in(mem, pdref, &pdict->keys, "dict_unpack(keys)"); code = dict_create_unpacked_keys(count, pdref); if (code < 0) return code; for (nkp = pdict->keys.value.refs; count--; okp++, nkp++) if (r_packed_is_name(okp)) { packed_get((const gs_memory_t *)mem, okp, nkp); ref_mark_new_in(mem, nkp); } else if (*okp == packed_key_deleted) r_set_attrs(nkp, a_executable); if (!ref_must_save_in(mem, &old_keys)) gs_free_ref_array(mem, &old_keys, "dict_unpack(old keys)"); if (pds) dstack_set_top(pds); /* just in case */ } return 0; }
/* <obj> <typenames> .type <name> */ static int ztype(i_ctx_t *i_ctx_p) { os_ptr op = osp; ref tnref; int code = array_get(imemory, op, (long)r_btype(op - 1), &tnref); if (code < 0) return code; if (!r_has_type(&tnref, t_name)) { /* Must be either a stack underflow or a t_[a]struct. */ check_op(2); { /* Get the type name from the structure. */ const char *sname = gs_struct_type_name_string(gs_object_type(imemory, op[-1].value.pstruct)); int code = name_ref(imemory, (const byte *)sname, strlen(sname), (ref *) (op - 1), 0); if (code < 0) return code; } r_set_attrs(op - 1, a_executable); } else { ref_assign(op - 1, &tnref); } pop(1); return 0; }
/* or if they are identical. */ void packed_get(const gs_memory_t *mem, const ref_packed * packed, ref * pref) { const ref_packed elt = *packed; uint value = elt & packed_value_mask; switch (elt >> r_packed_type_shift) { default: /* (shouldn't happen) */ make_null(pref); break; case pt_executable_operator: op_index_ref(value, pref); break; case pt_integer: make_int(pref, (int)value + packed_min_intval); break; case pt_literal_name: name_index_ref(mem, value, pref); break; case pt_executable_name: name_index_ref(mem, value, pref); r_set_attrs(pref, a_executable); break; case pt_full_ref: case pt_full_ref + 1: ref_assign(pref, (const ref *)packed); } }
/* The keys are allocated using the same allocator as the dictionary. */ static int dict_create_unpacked_keys(uint asize, const ref * pdref) { dict *pdict = pdref->value.pdict; gs_ref_memory_t *mem = dict_memory(pdict); int code; code = gs_alloc_ref_array(mem, &pdict->keys, a_all, asize, "dict_create_unpacked_keys"); if (code >= 0) { uint new_mask = imemory_new_mask(mem); ref *kp = pdict->keys.value.refs; r_set_attrs(&pdict->keys, new_mask); refset_null_new(kp, asize, new_mask); r_set_attrs(kp, a_executable); /* wraparound entry */ } return code; }
/* or if the object did not have the access already when modify=1. */ static int access_check(i_ctx_t *i_ctx_p, int access, /* mask for attrs */ bool modify) /* if true, reduce access */ { os_ptr op = osp; ref *aop; switch (r_type(op)) { case t_dictionary: aop = dict_access_ref(op); if (modify) { if (!r_has_attrs(aop, access)) return_error(e_invalidaccess); ref_save(op, aop, "access_check(modify)"); r_clear_attrs(aop, a_all); r_set_attrs(aop, access); dict_set_top(); return 0; } break; case t_array: case t_file: case t_string: case t_mixedarray: case t_shortarray: case t_astruct: case t_device:; if (modify) { if (!r_has_attrs(op, access)) return_error(e_invalidaccess); r_clear_attrs(op, a_all); r_set_attrs(op, access); return 0; } aop = op; break; default: return_op_typecheck(op); } return (r_has_attrs(aop, access) ? 1 : 0); }
static int runandhide_restore_hidden(i_ctx_t *i_ctx_p, ref *obj, ref *attrs) { os_ptr op = osp; push(1); /* restore the hidden_object and its type_attrs */ ref_assign(op, obj); r_clear_attrs(op, a_all); r_set_attrs(op, attrs->value.intval); return 0; }
/* Call out to a PostScript procedure. */ static int push_callout(i_ctx_t *i_ctx_p, const char *callout_name) { int code; check_estack(1); code = name_enter_string(imemory, callout_name, esp + 1); if (code < 0) return code; ++esp; r_set_attrs(esp, a_executable); return o_push_estack; }
/* Convert strings to executable names for build_proc_refs. */ int build_proc_name_refs(const gs_memory_t *mem, build_proc_refs * pbuild, const char *bcstr, const char *bgstr) { int code; if (!bcstr) make_null(&pbuild->BuildChar); else { if ((code = name_ref(mem, (const byte *)bcstr, strlen(bcstr), &pbuild->BuildChar, 0)) < 0) return code; r_set_attrs(&pbuild->BuildChar, a_executable); } if (!bgstr) make_null(&pbuild->BuildGlyph); else { if ((code = name_ref(mem, (const byte *)bgstr, strlen(bgstr), &pbuild->BuildGlyph, 0)) < 0) return code; r_set_attrs(&pbuild->BuildGlyph, a_executable); } return 0; }
/* - .wrapfont - */ static int zwrapfont(i_ctx_t *i_ctx_p) { gs_font *font = gs_currentfont(igs); gs_font_type0 *font0; int wmode = 0; int code; switch (font->FontType) { case ft_TrueType: code = gs_font_type0_from_type42(&font0, (gs_font_type42 *)font, wmode, true, font->memory); if (code < 0) return code; /* * Patch up BuildChar and CIDMap. This isn't necessary for * TrueType fonts in general, only for Type 42 fonts whose * BuildChar is implemented in PostScript code. */ { font_data *pdata = pfont_data(font); const char *bgstr = "%Type11BuildGlyph"; ref temp; make_int(&temp, 0); ref_assign(&pdata->u.type42.CIDMap, &temp); code = name_ref((const byte *)bgstr, strlen(bgstr), &temp, 1); if (code < 0) return code; r_set_attrs(&temp, a_executable); ref_assign(&pdata->BuildGlyph, &temp); } break; case ft_CID_encrypted: case ft_CID_user_defined: case ft_CID_TrueType: code = gs_font_type0_from_cidfont(&font0, font, wmode, NULL, font->memory); break; default: return_error(e_rangecheck); } if (code < 0) return code; gs_setfont(igs, (gs_font *)font0); return 0; }
/* Note that this is now internal, since it only handles "new" arrays. */ static int array_new_indexed_param_write(iparam_list * iplist, const ref * pkey, const ref * pvalue) { const ref *const arr = &((dict_param_list *)iplist)->dict; ref *eltp; if (!r_has_type(pkey, t_integer)) return_error(e_typecheck); check_int_ltu(*pkey, r_size(arr)); store_check_dest(arr, pvalue); eltp = arr->value.refs + pkey->value.intval; /* ref_assign_new(eltp, pvalue); */ ref_assign(eltp, pvalue); r_set_attrs(eltp, imemory_new_mask(iplist->ref_memory)); return 0; }
/* the VM space where the dictionary is allocated. */ static int dict_create_contents(uint size, const ref * pdref, bool pack) { dict *pdict = pdref->value.pdict; gs_ref_memory_t *mem = dict_memory(pdict); uint new_mask = imemory_new_mask(mem); uint asize = dict_round_size((size == 0 ? 1 : size)); int code; register uint i; if (asize == 0 || asize > max_array_size - 1) /* too large */ return_error(gs_error_limitcheck); asize++; /* allow room for wraparound entry */ code = gs_alloc_ref_array(mem, &pdict->values, a_all, asize, "dict_create_contents(values)"); if (code < 0) return code; r_set_attrs(&pdict->values, new_mask); refset_null_new(pdict->values.value.refs, asize, new_mask); if (pack) { uint ksize = (asize + packed_per_ref - 1) / packed_per_ref; ref arr; ref_packed *pkp; ref_packed *pzp; code = gs_alloc_ref_array(mem, &arr, a_all, ksize, "dict_create_contents(packed keys)"); if (code < 0) return code; pkp = (ref_packed *) arr.value.refs; make_tasv(&pdict->keys, t_shortarray, r_space(&arr) | a_all | new_mask, asize, packed, pkp); for (pzp = pkp, i = 0; i < asize || i % packed_per_ref; pzp++, i++) *pzp = packed_key_empty; *pkp = packed_key_deleted; /* wraparound entry */ } else { /* not packed */ int code = dict_create_unpacked_keys(asize, pdref); if (code < 0) return code; } make_tav(&pdict->count, t_integer, new_mask, intval, 0); make_tav(&pdict->maxlength, t_integer, new_mask, intval, size); return 0; }
/* Mark a ref. Return true if new mark. */ bool ptr_ref_mark(enum_ptr_t *pep, gc_state_t * ignored) { ref_packed *rpp = (void *)pep->ptr; if (r_is_packed(rpp)) { if (r_has_pmark(rpp)) return false; r_set_pmark(rpp); } else { ref *const pref = (ref *)rpp; if (r_has_attr(pref, l_mark)) return false; r_set_attrs(pref, l_mark); } return true; }
/* <obj> cvx <obj> */ int zcvx(i_ctx_t *i_ctx_p) { os_ptr op = osp; ref *aop; uint opidx; check_op(1); /* * If the object is an internal operator, we can't allow it to * exist in executable form anywhere outside the e-stack. */ if (r_has_type(op, t_operator) && ((opidx = op_index(op)) == 0 || op_def_is_internal(op_index_def(opidx))) ) return_error(e_rangecheck); aop = ACCESS_REF(op); r_set_attrs(aop, a_executable); return 0; }
/* - .typenames <name1|null> ... <nameN|null> */ static int ztypenames(i_ctx_t *i_ctx_p) { os_ptr op = osp; static const char *const tnames[] = { REF_TYPE_NAME_STRINGS }; int i; check_ostack(t_next_index); for (i = 0; i < t_next_index; i++) { ref *const rtnp = op + 1 + i; if (i >= countof(tnames) || tnames[i] == 0) make_null(rtnp); else { int code = name_enter_string(imemory, tnames[i], rtnp); if (code < 0) return code; r_set_attrs(rtnp, a_executable); } } osp += t_next_index; 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; }
/* Remove an element from a dictionary. */ int dict_undef(ref * pdref, const ref * pkey, dict_stack_t *pds) { gs_ref_memory_t *mem; ref *pvslot; dict *pdict; uint index; int code = dict_find(pdref, pkey, &pvslot); switch (code) { case 0: case gs_error_dictfull: return_error(gs_error_undefined); case 1: break; default: /* other error */ return code; } /* Remove the entry from the dictionary. */ pdict = pdref->value.pdict; index = pvslot - pdict->values.value.refs; mem = dict_memory(pdict); if (dict_is_packed(pdict)) { ref_packed *pkp = pdict->keys.value.writable_packed + index; bool must_save = ref_must_save_in(mem, &pdict->keys); if_debug3m('d', (const gs_memory_t *)mem, "[d]0x%lx: removing key at 0%lx: 0x%x\n", (ulong)pdict, (ulong)pkp, (uint)*pkp); /* See the initial comment for why it is safe not to save */ /* the change if the keys array itself is new. */ if (must_save) ref_do_save_in(mem, &pdict->keys, pkp, "dict_undef(key)"); /* * Accumulating deleted entries slows down lookup. * Detect the easy case where we can use an empty entry * rather than a deleted one, namely, when the next entry * in the probe order is empty. */ if (pkp[-1] == packed_key_empty) { /* * In this case we can replace any preceding deleted keys with * empty ones as well. */ uint end = nslots(pdict); *pkp = packed_key_empty; if (must_save) { while (++index < end && *++pkp == packed_key_deleted) { ref_do_save_in(mem, &pdict->keys, pkp, "dict_undef(key)"); *pkp = packed_key_empty; } } else { while (++index < end && *++pkp == packed_key_deleted) *pkp = packed_key_empty; } } else *pkp = packed_key_deleted; } else { /* not packed */ ref *kp = pdict->keys.value.refs + index; if_debug4m('d', (const gs_memory_t *)mem, "[d]0x%lx: removing key at 0%lx: 0x%lx 0x%lx\n", (ulong)pdict, (ulong)kp, ((ulong *)kp)[0], ((ulong *)kp)[1]); make_null_old_in(mem, &pdict->keys, kp, "dict_undef(key)"); /* * Accumulating deleted entries slows down lookup. * Detect the easy case where we can use an empty entry * rather than a deleted one, namely, when the next entry * in the probe order is empty. */ if (!r_has_type(kp - 1, t_null) || /* full entry */ r_has_attr(kp - 1, a_executable) /* deleted or wraparound */ ) r_set_attrs(kp, a_executable); /* mark as deleted */ } ref_save_in(mem, pdref, &pdict->count, "dict_undef(count)"); pdict->count.value.intval--; /* If the key is a name, update its 1-element cache. */ if (r_has_type(pkey, t_name)) { name *pname = pkey->value.pname; if (pv_valid(pname->pvalue)) { #ifdef DEBUG /* Check the the cache is correct. */ if (!(pds && dstack_dict_is_permanent(pds, pdref))) lprintf1("dict_undef: cached name value pointer 0x%lx is incorrect!\n", (ulong) pname->pvalue); #endif /* Clear the cache */ pname->pvalue = pv_no_defn; } } make_null_old_in(mem, &pdict->values, pvslot, "dict_undef(value)"); return 0; }