/* Make a reusable file stream. */ static int make_rfs(i_ctx_t *i_ctx_p, os_ptr op, stream *fs, long offset, long length) { uint save_space = icurrent_space; uint stream_space = imemory_space((const gs_ref_memory_t *)fs->memory); gs_const_string fname; gs_parsed_file_name_t pname; stream *s; int code; if (sfilename(fs, &fname) < 0) return_error(e_ioerror); code = gs_parse_file_name(&pname, (const char *)fname.data, fname.size, imemory); if (code < 0) return code; if (pname.len == 0) /* %stdin% etc. won't have a filename */ return_error(e_invalidfileaccess); /* can't reopen */ if (pname.iodev == NULL) pname.iodev = iodev_default(imemory); /* Open the file again, to be independent of the source. */ ialloc_set_space(idmemory, stream_space); code = zopen_file(i_ctx_p, &pname, "r", &s, imemory); ialloc_set_space(idmemory, save_space); if (code < 0) return code; if (sread_subfile(s, offset, length) < 0) { sclose(s); return_error(e_ioerror); } s->close_at_eod = false; make_stream_file(op, s, "r"); return 0; }
/* The caller guarantees that *op is a dictionary. */ int build_gs_sub_font(i_ctx_t *i_ctx_p, const ref *op, gs_font **ppfont, font_type ftype, gs_memory_type_ptr_t pstype, const build_proc_refs * pbuild, const ref *pencoding, ref *fid_op) { gs_matrix mat, omat; ref fname; /* t_string */ gs_font *pfont; font_data *pdata; /* * Make sure that we allocate the font data * in the same VM as the font dictionary. */ uint space = ialloc_space(idmemory); int code = sub_font_params(imemory, op, &mat, &omat, &fname); if (code < 0) return code; ialloc_set_space(idmemory, r_space(op)); pfont = gs_font_alloc(imemory, pstype, &gs_font_procs_default, NULL, "buildfont(font)"); pdata = ialloc_struct(font_data, &st_font_data, "buildfont(data)"); if (pfont == 0 || pdata == 0) code = gs_note_error(e_VMerror); else if (fid_op) code = add_FID(i_ctx_p, fid_op, pfont, iimemory); if (code < 0) { ifree_object(pdata, "buildfont(data)"); ifree_object(pfont, "buildfont(font)"); ialloc_set_space(idmemory, space); return code; } refset_null((ref *) pdata, sizeof(font_data) / sizeof(ref)); ref_assign_new(&pdata->dict, op); ref_assign_new(&pdata->BuildChar, &pbuild->BuildChar); ref_assign_new(&pdata->BuildGlyph, &pbuild->BuildGlyph); if (pencoding) ref_assign_new(&pdata->Encoding, pencoding); pfont->client_data = pdata; pfont->FontType = ftype; pfont->FontMatrix = mat; pfont->orig_FontMatrix = omat; pfont->BitmapWidths = false; pfont->ExactSize = fbit_use_bitmaps; pfont->InBetweenSize = fbit_use_outlines; pfont->TransformedChar = fbit_use_outlines; pfont->WMode = 0; pfont->procs.encode_char = zfont_encode_char; pfont->procs.glyph_name = zfont_glyph_name; ialloc_set_space(idmemory, space); copy_font_name(&pfont->font_name, &fname); *ppfont = pfont; return 0; }
/* Make a transformed font (common code for makefont/scalefont). */ static int make_font(i_ctx_t *i_ctx_p, const gs_matrix * pmat) { os_ptr op = osp; os_ptr fp = op - 1; gs_font *oldfont, *newfont; int code; ref *pencoding = 0; code = font_param(fp, &oldfont); if (code < 0) return code; { uint space = ialloc_space(idmemory); ialloc_set_space(idmemory, r_space(fp)); if (dict_find_string(fp, "Encoding", &pencoding) > 0 && !r_is_array(pencoding) ) code = gs_note_error(e_invalidfont); else { /* * Temporarily substitute the new dictionary * for the old one, in case the Encoding changed. */ ref olddict; olddict = *pfont_dict(oldfont); *pfont_dict(oldfont) = *fp; code = gs_makefont(ifont_dir, oldfont, pmat, &newfont); *pfont_dict(oldfont) = olddict; } ialloc_set_space(idmemory, space); } if (code < 0) return code; /* * We have to allow for the possibility that the font's Encoding * is different from that of the base font. Note that the * font_data of the new font was simply copied from the old one. */ if (pencoding != 0 && !obj_eq(imemory, pencoding, &pfont_data(newfont)->Encoding) ) { if (newfont->FontType == ft_composite) return_error(e_rangecheck); /* We should really do validity checking here.... */ ref_assign(&pfont_data(newfont)->Encoding, pencoding); lookup_gs_simple_font_encoding((gs_font_base *) newfont); } *fp = *pfont_dict(newfont); pop(1); return 0; }
/* Execute an operator with a specific VM selected as current VM. */ static int specific_vm_op(i_ctx_t *i_ctx_p, op_proc_t opproc, uint space) { uint save_space = icurrent_space; int code; ialloc_set_space(idmemory, space); code = opproc(i_ctx_p); ialloc_set_space(idmemory, save_space); return code; }
/* <bool> .setglobal - */ private int zsetglobal(register os_ptr op) { check_type(*op, t_boolean); ialloc_set_space(idmemory, (op->value.boolval ? avm_global : avm_local)); pop(1); return 0; }
/* <save> .forgetsave - */ static int zforgetsave(i_ctx_t *i_ctx_p) { os_ptr op = osp; alloc_save_t *asave; vm_save_t *vmsave; int code = restore_check_operand(op, &asave, idmemory); if (code < 0) return 0; vmsave = alloc_save_client_data(asave); /* Reset l_new in all stack entries if the new save level is zero. */ restore_fix_stack(&o_stack, asave, false); restore_fix_stack(&e_stack, asave, false); restore_fix_stack(&d_stack, asave, false); /* * Forget the gsaves, by deleting the bottom gstate on * the current stack and the top one on the saved stack and then * concatenating the stacks together. */ { gs_state *pgs = igs; gs_state *last; while (gs_state_saved(last = gs_state_saved(pgs)) != 0) pgs = last; gs_state_swap_saved(last, vmsave->gsave); gs_grestore(last); gs_grestore(last); } /* Forget the save in the memory manager. */ code = alloc_forget_save_in(idmemory, asave); if (code < 0) return code; { uint space = icurrent_space; ialloc_set_space(idmemory, avm_local); /* See above for why we clear the gsave pointer here. */ vmsave->gsave = 0; ifree_object(vmsave, "zrestore"); ialloc_set_space(idmemory, space); } pop(1); return 0; }
/* The caller guarantees that *op is a dictionary. */ int build_gs_simple_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont, font_type ftype, gs_memory_type_ptr_t pstype, const build_proc_refs * pbuild, build_font_options_t options) { double bbox[4]; gs_uid uid; int code; gs_font_base *pfont; uint space = ialloc_space(idmemory); code = font_bbox_param(imemory, op, bbox); if (code < 0) return code; /* * Make sure that we allocate uid * in the same VM as the font dictionary * (see build_gs_sub_font). */ ialloc_set_space(idmemory, r_space(op)); code = dict_uid_param(op, &uid, 0, imemory, i_ctx_p); ialloc_set_space(idmemory, space); if (code < 0) return code; if ((options & bf_UniqueID_ignored) && uid_is_UniqueID(&uid)) uid_set_invalid(&uid); code = build_gs_font(i_ctx_p, op, (gs_font **) ppfont, ftype, pstype, pbuild, options); if (code != 0) /* invalid or scaled font */ return code; pfont = *ppfont; pfont->procs.init_fstack = gs_default_init_fstack; pfont->procs.define_font = gs_no_define_font; pfont->procs.decode_glyph = gs_font_map_glyph_to_unicode; pfont->procs.make_font = zbase_make_font; pfont->procs.next_char_glyph = gs_default_next_char_glyph; pfont->FAPI = 0; pfont->FAPI_font_data = 0; init_gs_simple_font(pfont, bbox, &uid); lookup_gs_simple_font_encoding(pfont); get_GlyphNames2Unicode(i_ctx_p, (gs_font *)pfont, op); return 0; }
/* Make a reusable string stream. */ int make_rss(i_ctx_t *i_ctx_p, os_ptr op, const byte * data, uint size, uint string_space, long offset, long length, bool is_bytestring) { uint save_space = icurrent_space; stream *s; long left = min(length, size - offset); ialloc_set_space(idmemory, string_space); s = file_alloc_stream(imemory, "make_rss"); ialloc_set_space(idmemory, save_space); if (s == 0) return_error(e_VMerror); sread_string_reusable(s, data + offset, max(left, 0)); if (is_bytestring) s->cbuf_string.data = 0; /* byte array, not string */ make_stream_file(op, s, "r"); return 0; }
/* <bool> .setglobal - */ private int zsetglobal(i_ctx_t *i_ctx_p) { os_ptr op = osp; check_type(*op, t_boolean); ialloc_set_space(idmemory, (op->value.boolval ? avm_global : avm_local)); pop(1); return 0; }
/* Initialize the allocator */ int ialloc_init(gs_dual_memory_t *dmem, gs_memory_t * rmem, uint chunk_size, bool level2) { gs_ref_memory_t *ilmem = ialloc_alloc_state(rmem, chunk_size); gs_ref_memory_t *ilmem_stable = ialloc_alloc_state(rmem, chunk_size); gs_ref_memory_t *igmem = 0; gs_ref_memory_t *igmem_stable = 0; gs_ref_memory_t *ismem = ialloc_alloc_state(rmem, chunk_size); int i; if (ilmem == 0 || ilmem_stable == 0 || ismem == 0) goto fail; ilmem->stable_memory = (gs_memory_t *)ilmem_stable; if (level2) { igmem = ialloc_alloc_state(rmem, chunk_size); igmem_stable = ialloc_alloc_state(rmem, chunk_size); if (igmem == 0 || igmem_stable == 0) goto fail; igmem->stable_memory = (gs_memory_t *)igmem_stable; } else igmem = ilmem, igmem_stable = ilmem_stable; for (i = 0; i < countof(dmem->spaces_indexed); i++) dmem->spaces_indexed[i] = 0; dmem->space_local = ilmem; dmem->space_global = igmem; dmem->space_system = ismem; dmem->spaces.vm_reclaim = gs_gc_reclaim; /* real GC */ dmem->reclaim = 0; /* no interpreter GC yet */ /* Level 1 systems have only local VM. */ igmem->space = avm_global; igmem_stable->space = avm_global; ilmem->space = avm_local; /* overrides if ilmem == igmem */ ilmem_stable->space = avm_local; /* ditto */ ismem->space = avm_system; # if IGC_PTR_STABILITY_CHECK igmem->space_id = (i_vm_global << 1) + 1; igmem_stable->space_id = i_vm_global << 1; ilmem->space_id = (i_vm_local << 1) + 1; /* overrides if ilmem == igmem */ ilmem_stable->space_id = i_vm_local << 1; /* ditto */ ismem->space_id = (i_vm_system << 1); # endif ialloc_set_space(dmem, avm_global); return 0; fail: gs_free_object(rmem, igmem_stable, "ialloc_init failure"); gs_free_object(rmem, igmem, "ialloc_init failure"); gs_free_object(rmem, ismem, "ialloc_init failure"); gs_free_object(rmem, ilmem_stable, "ialloc_init failure"); gs_free_object(rmem, ilmem, "ialloc_init failure"); return_error(e_VMerror); }
/* - save <save> */ int zsave(i_ctx_t *i_ctx_p) { os_ptr op = osp; uint space = icurrent_space; vm_save_t *vmsave; ulong sid; int code; gs_state *prev; if (I_VALIDATE_BEFORE_SAVE) ivalidate_clean_spaces(i_ctx_p); ialloc_set_space(idmemory, avm_local); vmsave = ialloc_struct(vm_save_t, &st_vm_save, "zsave"); ialloc_set_space(idmemory, space); if (vmsave == 0) return_error(e_VMerror); code = alloc_save_state(idmemory, vmsave, &sid); if (code < 0) return code; if (sid == 0) { ifree_object(vmsave, "zsave"); return_error(e_VMerror); } if_debug2('u', "[u]vmsave 0x%lx, id = %lu\n", (ulong) vmsave, (ulong) sid); code = gs_gsave_for_save(igs, &prev); if (code < 0) return code; code = gs_gsave(igs); if (code < 0) return code; vmsave->gsave = prev; push(1); make_tav(op, t_save, 0, saveid, sid); if (I_VALIDATE_AFTER_SAVE) ivalidate_clean_spaces(i_ctx_p); 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 allocator */ void ialloc_init(gs_memory_t *mem, uint chunk_size, bool level2) { gs_ref_memory_t *ilmem = ialloc_alloc_state(mem, chunk_size); gs_ref_memory_t *igmem = (level2 ? ialloc_alloc_state(mem, chunk_size) : ilmem); gs_ref_memory_t *ismem = ialloc_alloc_state(mem, chunk_size); int i; for ( i = 0; i < countof(gs_imemory.spaces.indexed); i++ ) gs_imemory.spaces.indexed[i] = 0; gs_imemory.space_local = ilmem; gs_imemory.space_global = igmem; gs_imemory.space_system = ismem; gs_imemory.reclaim = 0; /* Level 1 systems have only local VM. */ igmem->space = avm_global; ilmem->space = avm_local; /* overrides if ilmem == igmem */ igmem->global = ilmem->global = igmem; ismem->space = avm_system; ialloc_set_space(&gs_imemory, avm_global); }
int zrestore(i_ctx_t *i_ctx_p) { os_ptr op = osp; alloc_save_t *asave; bool last; vm_save_t *vmsave; int code = restore_check_operand(op, &asave, idmemory); if (code < 0) return code; if_debug2('u', "[u]vmrestore 0x%lx, id = %lu\n", (ulong) alloc_save_client_data(asave), (ulong) op->value.saveid); if (I_VALIDATE_BEFORE_RESTORE) ivalidate_clean_spaces(i_ctx_p); /* Check the contents of the stacks. */ osp--; { int code; if ((code = restore_check_stack(i_ctx_p, &o_stack, asave, false)) < 0 || (code = restore_check_stack(i_ctx_p, &e_stack, asave, true)) < 0 || (code = restore_check_stack(i_ctx_p, &d_stack, asave, false)) < 0 ) { osp++; return code; } } /* Reset l_new in all stack entries if the new save level is zero. */ /* Also do some special fixing on the e-stack. */ restore_fix_stack(&o_stack, asave, false); restore_fix_stack(&e_stack, asave, true); restore_fix_stack(&d_stack, asave, false); /* Iteratively restore the state of memory, */ /* also doing a grestoreall at each step. */ do { vmsave = alloc_save_client_data(alloc_save_current(idmemory)); /* Restore the graphics state. */ gs_grestoreall_for_restore(igs, vmsave->gsave); /* * If alloc_save_space decided to do a second save, the vmsave * object was allocated one save level less deep than the * current level, so ifree_object won't actually free it; * however, it points to a gsave object that definitely * *has* been freed. In order not to trip up the garbage * collector, we clear the gsave pointer now. */ vmsave->gsave = 0; /* Now it's safe to restore the state of memory. */ code = alloc_restore_step_in(idmemory, asave); if (code < 0) return code; last = code; } while (!last); { uint space = icurrent_space; ialloc_set_space(idmemory, avm_local); ifree_object(vmsave, "zrestore"); ialloc_set_space(idmemory, space); } dict_set_top(); /* reload dict stack cache */ if (I_VALIDATE_AFTER_RESTORE) ivalidate_clean_spaces(i_ctx_p); /* If the i_ctx_p LockFilePermissions is true, but the userparams */ /* we just restored is false, we need to make sure that we do not */ /* cause an 'invalidaccess' in setuserparams. Temporarily set */ /* LockFilePermissions false until the gs_lev2.ps can do a */ /* setuserparams from the restored userparam dictionary. */ i_ctx_p->LockFilePermissions = false; 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; }