/* Only the type of *op has been checked. */ int zcopy_dict(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr op1 = op - 1; int code; check_type(*op1, t_dictionary); check_dict_read(*op1); check_dict_write(*op); if (!imemory->gs_lib_ctx->dict_auto_expand && (dict_length(op) != 0 || dict_maxlength(op) < dict_length(op1)) ) return_error(e_rangecheck); code = idict_copy(op1, op); if (code < 0) return code; /* * In Level 1 systems, we must copy the access attributes too. * The only possible effect this can have is to make the * copy read-only if the original dictionary is read-only. */ if (!level2_enabled) r_copy_attrs(dict_access_ref(op), a_write, dict_access_ref(op1)); ref_assign(op1, op); pop(1); return 0; }
/* 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); }
/* <obj:array|packedarray|dict|file|string> noaccess <obj> */ static int znoaccess(i_ctx_t *i_ctx_p) { os_ptr op = osp; check_op(1); if (r_has_type(op, t_dictionary)) { ref *aop = dict_access_ref(op); /* CPSI throws invalidaccess when seting noaccess to a readonly dictionary (CET 13-13-6) : */ if (!r_has_attrs(aop, a_write)) { if (!r_has_attrs(aop, a_read) && !r_has_attrs(aop, a_execute)) { /* Already noaccess - do nothing (CET 24-09-1). */ return 0; } return_error(e_invalidaccess); } /* Don't allow removing read access to permanent dictionaries. */ if (dict_is_permanent_on_dstack(op)) return_error(e_invalidaccess); } return access_check(i_ctx_p, 0, true); }
static int zmatchmedia(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr preq = op - 3; os_ptr pattr = op - 2; os_ptr ppol = op - 1; os_ptr pkeys = op; /* *const */ int policy_default; float best_mismatch = (float)max_long; /* adhoc */ float mepos_penalty; float mbest = best_mismatch; match_record_t match; ref no_priority; ref *ppriority; int mepos, orient; bool roll; int code; int ai; struct mkd_ { ref key, dict; } aelt; if (r_has_type(pattr, t_null)) { check_op(4); make_null(op - 3); make_true(op - 2); pop(2); return 0; } check_type(*preq, t_dictionary); check_dict_read(*preq); check_type(*pattr, t_dictionary); check_dict_read(*pattr); check_type(*ppol, t_dictionary); check_dict_read(*ppol); check_array(*pkeys); check_read(*pkeys); switch (code = dict_int_null_param(preq, "MediaPosition", 0, 0x7fff, 0, &mepos)) { default: return code; case 2: case 1: mepos = -1; case 0:; } switch (code = dict_int_null_param(preq, "Orientation", 0, 3, 0, &orient)) { default: return code; case 2: case 1: orient = -1; case 0:; } code = dict_bool_param(preq, "RollFedMedia", false, &roll); if (code < 0) return code; code = dict_int_param(ppol, "PolicyNotFound", 0, 7, 0, &policy_default); if (code < 0) return code; if (dict_find_string(pattr, "Priority", &ppriority) > 0) { check_array_only(*ppriority); check_read(*ppriority); } else { make_empty_array(&no_priority, a_readonly); ppriority = &no_priority; } match.no_match_priority = r_size(ppriority); reset_match(&match); for (ai = dict_first(pattr); (ai = dict_next(pattr, ai, (ref * /*[2]*/)&aelt)) >= 0; ) { if (r_has_type(&aelt.dict, t_dictionary) && r_has_attr(dict_access_ref(&aelt.dict), a_read) && r_has_type(&aelt.key, t_integer) ) { bool match_all; uint ki, pi; code = dict_bool_param(&aelt.dict, "MatchAll", false, &match_all); if (code < 0) return code; for (ki = 0; ki < r_size(pkeys); ki++) { ref key; ref kstr; ref *prvalue; ref *pmvalue; ref *ppvalue; int policy; array_get(imemory, pkeys, ki, &key); if (dict_find(&aelt.dict, &key, &pmvalue) <= 0) continue; if (dict_find(preq, &key, &prvalue) <= 0 || r_has_type(prvalue, t_null) ) { if (match_all) goto no; else continue; } /* Look for the Policies entry for this key. */ if (dict_find(ppol, &key, &ppvalue) > 0) { check_type_only(*ppvalue, t_integer); policy = ppvalue->value.intval; } else policy = policy_default; /* * Match a requested attribute value with the attribute value in the * description of a medium. For all attributes except PageSize, * matching means equality. PageSize is special; see match_page_size * below. */ if (r_has_type(&key, t_name) && (name_string_ref(imemory, &key, &kstr), r_size(&kstr) == 8 && !memcmp(kstr.value.bytes, "PageSize", 8)) ) { gs_matrix ignore_mat; gs_point ignore_msize; if (zmatch_page_size(imemory, prvalue, pmvalue, policy, orient, roll, &best_mismatch, &ignore_mat, &ignore_msize) <= 0) goto no; } else if (!obj_eq(imemory, prvalue, pmvalue)) goto no; } mepos_penalty = (mepos < 0 || aelt.key.value.intval == mepos) ? 0 : .001; /* We have a match. Save the match in case no better match is found */ if (r_has_type(&match.match_key, t_null)) match.match_key = aelt.key; /* * If it is a better match than the current best it supersedes it * regardless of priority. If the match is the same, then update * to the current only if the key value is lower. */ if (best_mismatch + mepos_penalty <= mbest) { if (best_mismatch + mepos_penalty < mbest || (r_has_type(&match.match_key, t_integer) && match.match_key.value.intval > aelt.key.value.intval)) { reset_match(&match); match.match_key = aelt.key; mbest = best_mismatch + mepos_penalty; } } /* In case of a tie, see if the new match has priority. */ for (pi = match.priority; pi > 0;) { ref pri; pi--; array_get(imemory, ppriority, pi, &pri); if (obj_eq(imemory, &aelt.key, &pri)) { /* Yes, higher priority. */ match.best_key = aelt.key; match.priority = pi; break; } } no:; } } if (r_has_type(&match.match_key, t_null)) { make_false(op - 3); pop(3); } else { if (r_has_type(&match.best_key, t_null)) op[-3] = match.match_key; else op[-3] = match.best_key; make_true(op - 2); pop(2); } return 0; }
int zdefault_make_font(gs_font_dir * pdir, const gs_font * oldfont, const gs_matrix * pmat, gs_font ** ppfont) { gs_font *newfont = *ppfont; gs_memory_t *mem = newfont->memory; /* HACK: we know this font was allocated by the interpreter. */ gs_ref_memory_t *imem = (gs_ref_memory_t *)mem; ref *fp = pfont_dict(oldfont); font_data *pdata; ref newdict, newmat, scalemat; uint dlen = dict_maxlength(fp); uint mlen = dict_length(fp) + 3; /* FontID, OrigFont, ScaleMatrix */ int code; if (dlen < mlen) dlen = mlen; if ((pdata = gs_alloc_struct(mem, font_data, &st_font_data, "make_font(font_data)")) == 0 ) return_error(e_VMerror); /* * This dictionary is newly created: it's safe to pass NULL as the * dstack pointer to dict_copy and dict_put_string. */ if ((code = dict_alloc(imem, dlen, &newdict)) < 0 || (code = dict_copy(fp, &newdict, NULL)) < 0 || (code = gs_alloc_ref_array(imem, &newmat, a_all, 12, "make_font(matrices)")) < 0 ) return code; refset_null_new(newmat.value.refs, 12, imemory_new_mask(imem)); ref_assign(&scalemat, &newmat); r_set_size(&scalemat, 6); scalemat.value.refs += 6; /* * Create the scaling matrix. We could do this several different * ways: by "dividing" the new FontMatrix by the base FontMatrix, by * multiplying the current scaling matrix by a ScaleMatrix kept in * the gs_font, or by multiplying the current scaling matrix by the * ScaleMatrix from the font dictionary. We opt for the last of * these. */ { gs_matrix scale, prev_scale; ref *ppsm; if (!(dict_find_string(fp, "ScaleMatrix", &ppsm) > 0 && read_matrix(mem, ppsm, &prev_scale) >= 0 && gs_matrix_multiply(pmat, &prev_scale, &scale) >= 0) ) scale = *pmat; write_matrix_new(&scalemat, &scale, imem); } r_clear_attrs(&scalemat, a_write); r_set_size(&newmat, 6); write_matrix_new(&newmat, &newfont->FontMatrix, imem); r_clear_attrs(&newmat, a_write); if ((code = dict_put_string(&newdict, "FontMatrix", &newmat, NULL)) < 0 || (code = dict_put_string(&newdict, "OrigFont", pfont_dict(oldfont->base), NULL)) < 0 || (code = dict_put_string(&newdict, "ScaleMatrix", &scalemat, NULL)) < 0 || (code = add_FID(NULL, &newdict, newfont, imem)) < 0 ) return code; newfont->client_data = pdata; *pdata = *pfont_data(oldfont); pdata->dict = newdict; r_clear_attrs(dict_access_ref(&newdict), a_write); 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; }