/* 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); } }
void debug_print_packed_ref(const ref_packed *pref) { ushort elt = *pref; ref nref; switch ( elt >> packed_type_shift ) { case pt_executable_operator: dprintf("<op_name>"); elt &= packed_int_mask; op_index_ref(elt, &nref); debug_print_ref(&nref); break; case pt_integer: dprintf1("<int> %d", (int)(elt & packed_int_mask) + packed_min_intval); break; case pt_literal_name: case pt_literal_name+1: dprintf("<lit_name>"); elt &= packed_max_name_index; goto ptn; case pt_executable_name: case pt_executable_name+1: dprintf("<exec_name>"); elt &= packed_max_name_index; ptn: name_index_ref(elt, &nref); dprintf2("(0x%lx#%x)", (ulong)nref.value.pname, elt); debug_print_name(&nref); break; } }
/* Convert a glyph to a ref. */ void glyph_ref(const gs_memory_t *mem, gs_glyph glyph, ref * gref) { if (glyph < gs_min_cid_glyph) name_index_ref(mem, glyph, gref); else make_int(gref, glyph - gs_min_cid_glyph); }
/* Print a ref */ void debug_print_full_ref(const ref *pref) { unsigned size = r_size(pref); ref nref; dprintf1("(%x)", r_type_attrs(pref)); switch ( r_type(pref) ) { case t_array: dprintf2("array(%u)0x%lx", size, (ulong)pref->value.refs); break; case t_boolean: dprintf1("boolean %x", pref->value.index); break; case t_condition: dprintf1("condition 0x%lx", (ulong)pref->value.pcond); break; case t_device: dprintf1("device 0x%lx", (ulong)pref->value.pdevice); break; case t_dictionary: dprintf3("dict(%u/%u)0x%lx", dict_length(pref), dict_maxlength(pref), (ulong)pref->value.pdict); break; case t_file: dprintf1("file 0x%lx", (ulong)pref->value.pfile); break; case t_gstate: dprintf1("gstate 0x%lx", (ulong)pref->value.pgstate); break; case t_integer: dprintf1("int %ld", pref->value.intval); break; case t_lock: dprintf1("lock 0x%lx", (ulong)pref->value.plock); break; case t_mark: dprintf("mark"); break; case t_mixedarray: dprintf2("mixed packedarray(%u)0x%lx", size, (ulong)pref->value.packed); break; case t_name: dprintf2("name(0x%lx#%x)", (ulong)pref->value.pname, name_index(pref)); debug_print_name(pref); break; case t_null: dprintf("null"); break; case t_oparray: dprintf1("op_array(0x%x)", size); name_index_ref(op_array_nx_table[size - op_def_count], &nref); debug_print_name(&nref); break; case t_operator: dprintf1("op(0x%x", size); if ( size ) dprintf1(":%s", (const char *)(op_def_table[size]->oname + 1)); dprintf1(")0x%lx", (ulong)pref->value.opproc); break; case t_real: dprintf1("real %f", pref->value.realval); break; case t_shortarray: dprintf2("short packedarray(%u)0x%lx", size, (ulong)pref->value.packed); break; case t_string: dprintf2("string(%u)0x%lx", size, (ulong)pref->value.bytes); break; default: dprintf1("type 0x%x", r_type(pref)); } }
/* * This routine translates a gs_separation_name value into a character string * pointer and a string length. */ int gs_get_colorname_string(const gs_memory_t *mem, gs_separation_name colorname_index, unsigned char **ppstr, unsigned int *pname_size) { ref nref; name_index_ref(mem, colorname_index, &nref); name_string_ref(mem, &nref, &nref); return obj_string_data(mem, &nref, (const unsigned char**) ppstr, pname_size); }
/* Get the name of a glyph. */ static int zfont_glyph_name(gs_font *font, gs_glyph index, gs_const_string *pstr) { ref nref, sref; if (index >= gs_min_cid_glyph) { /* Fabricate a numeric name. */ char cid_name[sizeof(gs_glyph) * 3 + 1]; int code; sprintf(cid_name, "%lu", (ulong) index); code = name_ref(font->memory, (const byte *)cid_name, strlen(cid_name), &nref, 1); if (code < 0) return code; } else name_index_ref(font->memory, index, &nref); name_string_ref(font->memory, &nref, &sref); pstr->data = sref.value.const_bytes; pstr->size = r_size(&sref); return 0; }
static gs_char gs_font_map_glyph_by_dict(const gs_memory_t *mem, const ref *map, gs_glyph glyph) { ref *v, n; if (glyph >= gs_min_cid_glyph) { uint cid = glyph - gs_min_cid_glyph; if (dict_find_string(map, "CIDCount", &v) > 0) { /* This is a CIDDEcoding resource. */ make_int(&n, cid / 256); if (dict_find(map, &n, &v) > 0) { ref vv; if (array_get(mem, v, cid % 256, &vv) == 0 && r_type(&vv) == t_integer) return vv.value.intval; } return GS_NO_CHAR; /* Absent in the map. */ } /* This is GlyphNames2Unicode dictionary. */ make_int(&n, cid); } else name_index_ref(mem, glyph, &n); if (dict_find(map, &n, &v) > 0) { if (r_has_type(v, t_string)) { int i, l = r_size(v); gs_char c = 0; for (i = 0; i < l; i++) c = (c << 8) | v->value.const_bytes[i]; return c; } if (r_type(v) == t_integer) return v->value.intval; } return GS_NO_CHAR; /* Absent in the map. */ }
static int zbind(i_ctx_t *i_ctx_p) { os_ptr op = osp; uint depth = 1; ref defn; register os_ptr bsp; switch (r_type(op)) { case t_array: if (!r_has_attr(op, a_write)) { return 0; /* per PLRM3 */ } case t_mixedarray: case t_shortarray: defn = *op; break; case t_oparray: defn = *op->value.const_refs; break; default: return_op_typecheck(op); } push(1); *op = defn; bsp = op; /* * We must not make the top-level procedure read-only, * but we must bind it even if it is read-only already. * * Here are the invariants for the following loop: * `depth' elements have been pushed on the ostack; * For i < depth, p = ref_stack_index(&o_stack, i): * *p is an array (or packedarray) ref. */ while (depth) { while (r_size(bsp)) { ref_packed *const tpp = (ref_packed *)bsp->value.packed; /* break const */ r_dec_size(bsp, 1); if (r_is_packed(tpp)) { /* Check for a packed executable name */ ushort elt = *tpp; if (r_packed_is_exec_name(&elt)) { ref nref; ref *pvalue; name_index_ref(imemory, packed_name_index(&elt), &nref); if ((pvalue = dict_find_name(&nref)) != 0 && r_is_ex_oper(pvalue) ) { store_check_dest(bsp, pvalue); /* * Always save the change, since this can only * happen once. */ ref_do_save(bsp, tpp, "bind"); *tpp = pt_tag(pt_executable_operator) + op_index(pvalue); } } bsp->value.packed = tpp + 1; } else { ref *const tp = bsp->value.refs++; switch (r_type(tp)) { case t_name: /* bind the name if an operator */ if (r_has_attr(tp, a_executable)) { ref *pvalue; if ((pvalue = dict_find_name(tp)) != 0 && r_is_ex_oper(pvalue) ) { store_check_dest(bsp, pvalue); ref_assign_old(bsp, tp, pvalue, "bind"); } } break; case t_array: /* push into array if writable */ if (!r_has_attr(tp, a_write)) break; case t_mixedarray: case t_shortarray: if (r_has_attr(tp, a_executable)) { /* Make reference read-only */ r_clear_attrs(tp, a_write); if (bsp >= ostop) { /* Push a new stack block. */ ref temp; int code; temp = *tp; osp = bsp; code = ref_stack_push(&o_stack, 1); if (code < 0) { ref_stack_pop(&o_stack, depth); return_error(code); } bsp = osp; *bsp = temp; } else *++bsp = *tp; depth++; } } } } bsp--; depth--; if (bsp < osbot) { /* Pop back to the previous stack block. */ osp = bsp; ref_stack_pop_block(&o_stack); bsp = osp; } } osp = bsp; return 0; }
int obj_cvp(const ref * op, byte * str, uint len, uint * prlen, int full_print, uint start_pos, const gs_memory_t *mem, bool restart) { char buf[50]; /* big enough for any float, double, or struct name */ const byte *data = (const byte *)buf; uint size; int code; ref nref; if (full_print) { static const char * const type_strings[] = { REF_TYPE_PRINT_STRINGS }; switch (r_btype(op)) { case t_boolean: case t_integer: break; case t_real: { /* * To get fully accurate output results for IEEE * single-precision floats (24 bits of mantissa), the ANSI %g * default of 6 digits is not enough; 9 are needed. * Unfortunately, using %.9g for floats (as opposed to doubles) * produces unfortunate artifacts such as 0.01 5 mul printing as * 0.049999997. Therefore, we print using %g, and if the result * isn't accurate enough, print again using %.9g. * Unfortunately, a few PostScript programs 'know' that the * printed representation of floats fits into 6 digits (e.g., * with cvs). We resolve this by letting cvs, cvrs, and = do * what the Adobe interpreters appear to do (use %g), and only * produce accurate output for ==, for which there is no * analogue of cvs. What a hack! */ float value = op->value.realval; float scanned; sprintf(buf, "%g", value); sscanf(buf, "%f", &scanned); if (scanned != value) sprintf(buf, "%.9g", value); ensure_dot(buf); goto rs; } case t_operator: case t_oparray: code = obj_cvp(op, (byte *)buf + 2, sizeof(buf) - 4, &size, 0, 0, mem, restart); if (code < 0) return code; buf[0] = buf[1] = buf[size + 2] = buf[size + 3] = '-'; size += 4; goto nl; case t_name: if (r_has_attr(op, a_executable)) { code = obj_string_data(mem, op, &data, &size); if (code < 0) return code; goto nl; } if (start_pos > 0) return obj_cvp(op, str, len, prlen, 0, start_pos - 1, mem, restart); if (len < 1) return_error(e_rangecheck); code = obj_cvp(op, str + 1, len - 1, prlen, 0, 0, mem, restart); if (code < 0) return code; str[0] = '/'; ++*prlen; return code; case t_null: data = (const byte *)"null"; goto rs; case t_string: if (!r_has_attr(op, a_read)) goto other; size = r_size(op); { bool truncate = (full_print == 1 && size > CVP_MAX_STRING); stream_cursor_read r; stream_cursor_write w; uint skip; byte *wstr; uint len1; int status = 1; if (start_pos == 0) { if (len < 1) return_error(e_rangecheck); str[0] = '('; skip = 0; wstr = str + 1; } else { skip = start_pos - 1; wstr = str; } len1 = len + (str - wstr); r.ptr = op->value.const_bytes - 1; r.limit = r.ptr + (truncate ? CVP_MAX_STRING : size); while (skip && status == 1) { uint written; w.ptr = (byte *)buf - 1; w.limit = w.ptr + min(skip + len1, sizeof(buf)); status = s_PSSE_template.process(NULL, &r, &w, false); written = w.ptr - ((byte *)buf - 1); if (written > skip) { written -= skip; memcpy(wstr, buf + skip, written); wstr += written; skip = 0; break; } skip -= written; } /* * We can reach here with status == 0 (and skip != 0) if * start_pos lies within the trailing ")" or "...)". */ if (status == 0) { #ifdef DEBUG if (skip > (truncate ? 4 : 1)) { return_error(e_Fatal); } #endif } w.ptr = wstr - 1; w.limit = str - 1 + len; if (status == 1) status = s_PSSE_template.process(NULL, &r, &w, false); *prlen = w.ptr - (str - 1); if (status != 0) return 1; if (truncate) { if (len - *prlen < 4 - skip) return 1; memcpy(w.ptr + 1, "...)" + skip, 4 - skip); *prlen += 4 - skip; } else { if (len - *prlen < 1 - skip) return 1; memcpy(w.ptr + 1, ")" + skip, 1 - skip); *prlen += 1 - skip; } } return 0; case t_astruct: case t_struct: if (r_is_foreign(op)) { /* gs_object_type may not work. */ data = (const byte *)"-foreign-struct-"; goto rs; } if (!mem) { data = (const byte *)"-(struct)-"; goto rs; } data = (const byte *) gs_struct_type_name_string( gs_object_type(mem, (const obj_header_t *)op->value.pstruct)); size = strlen((const char *)data); if (size > 4 && !memcmp(data + size - 4, "type", 4)) size -= 4; if (size > sizeof(buf) - 2) return_error(e_rangecheck); buf[0] = '-'; memcpy(buf + 1, data, size); buf[size + 1] = '-'; size += 2; data = (const byte *)buf; goto nl; default: other: { int rtype = r_btype(op); if (rtype > countof(type_strings)) return_error(e_rangecheck); data = (const byte *)type_strings[rtype]; if (data == 0) return_error(e_rangecheck); } goto rs; } } /* full_print = 0 */ switch (r_btype(op)) { case t_boolean: data = (const byte *)(op->value.boolval ? "true" : "false"); break; case t_integer: sprintf(buf, "%ld", op->value.intval); break; case t_string: check_read(*op); /* falls through */ case t_name: code = obj_string_data(mem, op, &data, &size); if (code < 0) return code; goto nl; case t_oparray: { uint index = op_index(op); const op_array_table *opt = op_index_op_array_table(index); name_index_ref(mem, opt->nx_table[index - opt->base_index], &nref); name_string_ref(mem, &nref, &nref); code = obj_string_data(mem, &nref, &data, &size); if (code < 0) return code; goto nl; } case t_operator: { /* Recover the name from the initialization table. */ uint index = op_index(op); /* * Check the validity of the index. (An out-of-bounds index * is only possible when examining an invalid object using * the debugger.) */ if (index > 0 && index < op_def_count) { data = (const byte *)(op_index_def(index)->oname + 1); break; } /* Internal operator, no name. */ sprintf(buf, "@0x%lx", (ulong) op->value.opproc); break; } case t_real: /* * The value 0.0001 is a boundary case that the Adobe interpreters * print in f-format but at least some gs versions print in * e-format, presumably because of differences in the underlying C * library implementation. Work around this here. */ if (op->value.realval == (float)0.0001) { strcpy(buf, "0.0001"); } else { sprintf(buf, "%g", op->value.realval); } ensure_dot(buf); break; default: data = (const byte *)"--nostringval--"; } rs: size = strlen((const char *)data); nl: if (size < start_pos) return_error(e_rangecheck); if (!restart && size > len) return_error(e_rangecheck); size -= start_pos; *prlen = min(size, len); memmove(str, data + start_pos, *prlen); return (size > len); }
/* * Look up a name on the dictionary stack. * Return the pointer to the value if found, 0 if not. */ ref * dstack_find_name_by_index(dict_stack_t * pds, uint nidx) { ds_ptr pdref = pds->stack.p; /* Since we know the hash function is the identity function, */ /* there's no point in allocating a separate variable for it. */ #define hash dict_name_index_hash(nidx) ref_packed kpack = packed_name_key(nidx); do { dict *pdict = pdref->value.pdict; uint size = npairs(pdict); const gs_memory_t *mem = dict_mem(pdict); #ifdef DEBUG if (gs_debug_c('D')) { ref dnref; name_index_ref(mem, nidx, &dnref); dlputs("[D]lookup "); debug_print_name(mem, &dnref); dprintf3(" in 0x%lx(%u/%u)\n", (ulong) pdict, dict_length(pdref), dict_maxlength(pdref)); } #endif #define INCR_DEPTH(pdref)\ INCR(depth[min(MAX_STATS_DEPTH, pds->stack.p - pdref)]) if (dict_is_packed(pdict)) { packed_search_1(INCR_DEPTH(pdref), return packed_search_value_pointer, DO_NOTHING, goto miss); packed_search_2(INCR_DEPTH(pdref), return packed_search_value_pointer, DO_NOTHING, break); miss:; } else { ref *kbot = pdict->keys.value.refs; register ref *kp; int wrap = 0; /* Search the dictionary */ for (kp = kbot + dict_hash_mod(hash, size) + 2;;) { --kp; if (r_has_type(kp, t_name)) { if (name_index(mem, kp) == nidx) { INCR_DEPTH(pdref); return pdict->values.value.refs + (kp - kbot); } } else if (r_has_type(kp, t_null)) { /* Empty, deleted, or wraparound. */ /* Figure out which. */ if (!r_has_attr(kp, a_executable)) break; if (kp == kbot) { /* wrap */ if (wrap++) break; /* 2 wraps */ kp += size + 1; } } } } #undef INCR_DEPTH }