/* <array|dict|name|packedarray|string> length <int> */ static int zlength(i_ctx_t *i_ctx_p) { os_ptr op = osp; switch (r_type(op)) { case t_array: case t_string: case t_mixedarray: case t_shortarray: check_read(*op); make_int(op, r_size(op)); return 0; case t_dictionary: check_dict_read(*op); make_int(op, dict_length(op)); return 0; case t_name: { ref str; name_string_ref(imemory, op, &str); make_int(op, r_size(&str)); return 0; } case t_astruct: if (gs_object_type(imemory, op->value.pstruct) != &st_bytes) return_error(e_typecheck); check_read(*op); make_int(op, gs_object_size(imemory, op->value.pstruct)); return 0; default: return_op_typecheck(op); } }
/* * Force the enumerator to be a gs_show_enum *, which the current * implementation code requires. */ static int show_n_begin(gs_show_enum *penum, gs_state *pgs, int code, gs_text_enum_t *pte) { if (code < 0) return code; if (gs_object_type(pgs->memory, pte) != &st_gs_show_enum) { /* Use the default implementation. */ gx_device *dev = pgs->device; gs_text_params_t text; gs_memory_t *mem = pte->memory; dev_proc_text_begin((*text_begin)) = dev_proc(dev, text_begin); text = pte->text; gs_text_release(pte, "show_n_begin"); /* Temporarily reset the text_begin procedure to the default. */ set_dev_proc(dev, text_begin, gx_default_text_begin); code = gs_text_begin(pgs, &text, mem, &pte); set_dev_proc(dev, text_begin, text_begin); if (code < 0) return code; } /* Now we know pte points to a gs_show_enum. */ *penum = *(gs_show_enum *)pte; gs_free_object(pgs->memory, pte, "show_n_begin"); return code; }
/* <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; }
/* * Get graphics state pointer (from imager state pointer) */ const gs_state * gx_hld_get_gstate_ptr(const gs_imager_state * pis) { extern_st(st_gs_state); /* only for testing */ /* Check to verify the structure type is really st_gs_state */ if (pis == NULL || gs_object_type(pis->memory, pis) != &st_gs_state) return NULL; return (const gs_state *) pis; }
/* <string> <index> <int> put - */ static int zput(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr op1 = op - 1; os_ptr op2 = op1 - 1; byte *sdata; uint ssize; switch (r_type(op2)) { case t_dictionary: if (i_ctx_p->in_superexec == 0) check_dict_write(*op2); { int code = idict_put(op2, op1, op); if (code < 0) return code; /* error */ } break; case t_array: check_write(*op2); check_int_ltu(*op1, r_size(op2)); store_check_dest(op2, op); { ref *eltp = op2->value.refs + (uint) op1->value.intval; ref_assign_old(op2, eltp, op, "put"); } break; case t_mixedarray: /* packed arrays are read-only */ case t_shortarray: return_error(e_invalidaccess); case t_string: sdata = op2->value.bytes; ssize = r_size(op2); str: check_write(*op2); check_int_ltu(*op1, ssize); check_int_leu(*op, 0xff); sdata[(uint)op1->value.intval] = (byte)op->value.intval; break; case t_astruct: if (gs_object_type(imemory, op2->value.pstruct) != &st_bytes) return_error(e_typecheck); sdata = r_ptr(op2, byte); ssize = gs_object_size(imemory, op2->value.pstruct); goto str; default: return_op_typecheck(op2); } pop(3); return 0; }
/* r_size(op1) was set just above. */ static int do_execstack(i_ctx_t *i_ctx_p, bool include_marks, os_ptr op1) { os_ptr op = osp; ref *arefs = op1->value.refs; uint asize = r_size(op1); uint i; ref *rq; /* * Copy elements from the stack to the array, * optionally skipping executable nulls. * Clear the executable bit in any internal operators, and * convert t_structs and t_astructs (which can only appear * in connection with stack marks, which means that they will * probably be freed when unwinding) to something harmless. */ for (i = 0, rq = arefs + asize; rq != arefs; ++i) { const ref *rp = ref_stack_index(&e_stack, (long)i); if (r_has_type_attrs(rp, t_null, a_executable) && !include_marks) continue; --rq; ref_assign_old(op1, rq, rp, "execstack"); switch (r_type(rq)) { case t_operator: { uint opidx = op_index(rq); if (opidx == 0 || op_def_is_internal(op_index_def(opidx))) r_clear_attrs(rq, a_executable); break; } case t_struct: case t_astruct: { const char *tname = rq->value.pstruct ? gs_struct_type_name_string( gs_object_type(imemory, rq->value.pstruct)) : "NULL"; make_const_string(rq, a_readonly | avm_foreign, strlen(tname), (const byte *)tname); break; } default: ; } } pop(op - op1); return 0; }
/* BitsPerSample. */ static int dict_threshold2_params(const ref * pdict, gs_threshold2_halftone * ptp, ref * ptproc, gs_memory_t *mem) { ref *tstring; int code = dict_threshold_common_params(pdict, (gs_threshold_halftone_common *)ptp, &tstring, ptproc); int bps; uint size; int cw2, ch2; if (code < 0 || (code = cw2 = dict_int_param(pdict, "Width2", 0, 0x7fff, 0, &ptp->width2)) < 0 || (code = ch2 = dict_int_param(pdict, "Height2", 0, 0x7fff, 0, &ptp->height2)) < 0 || (code = dict_int_param(pdict, "BitsPerSample", 8, 16, -1, &bps)) < 0 ) return code; if ((bps != 8 && bps != 16) || cw2 != ch2 || (!cw2 && (ptp->width2 == 0 || ptp->height2 == 0)) ) return_error(e_rangecheck); ptp->bytes_per_sample = bps / 8; switch (r_type(tstring)) { case t_string: size = r_size(tstring); gs_bytestring_from_string(&ptp->thresholds, tstring->value.const_bytes, size); break; case t_astruct: if (gs_object_type(mem, tstring->value.pstruct) != &st_bytes) return_error(e_typecheck); size = gs_object_size(mem, tstring->value.pstruct); gs_bytestring_from_bytes(&ptp->thresholds, r_ptr(tstring, byte), 0, size); break; default: return_error(e_typecheck); } check_read(*tstring); if (size != (ptp->width * ptp->height + ptp->width2 * ptp->height2) * ptp->bytes_per_sample) return_error(e_rangecheck); return 0; }
/* <bytestring1> <index> <string2> putinterval - */ static int zputinterval(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr opindex = op - 1; os_ptr opto = opindex - 1; int code; switch (r_type(opto)) { default: return_error(e_typecheck); case t__invalid: if (r_type(op) != t_array && r_type(op) != t_string && r_type(op) != t__invalid) return_error(e_typecheck); /* to match Distiller */ else return_error(e_stackunderflow); case t_mixedarray: case t_shortarray: return_error(e_invalidaccess); case t_array: case t_string: check_write(*opto); check_int_leu(*opindex, r_size(opto)); code = copy_interval(i_ctx_p, opto, (uint)(opindex->value.intval), op, "putinterval"); break; case t_astruct: { uint dsize, ssize, index; check_write(*opto); if (gs_object_type(imemory, opto->value.pstruct) != &st_bytes) return_error(e_typecheck); dsize = gs_object_size(imemory, opto->value.pstruct); check_int_leu(*opindex, dsize); index = (uint)opindex->value.intval; check_read_type(*op, t_string); ssize = r_size(op); if (ssize > dsize - index) return_error(e_rangecheck); memcpy(r_ptr(opto, byte) + index, op->value.const_bytes, ssize); code = 0; break; } } if (code >= 0) pop(3); return code; }
/* Read a string value. */ static int ref_param_read_string_value(gs_memory_t *mem, const iparam_loc * ploc, gs_param_string * pvalue) { const ref *pref = ploc->pvalue; switch (r_type(pref)) { case t_name: { ref nref; name_string_ref(mem, pref, &nref); pvalue->data = nref.value.const_bytes; pvalue->size = r_size(&nref); pvalue->persistent = true; } break; case t_string: iparam_check_read(*ploc); pvalue->data = pref->value.const_bytes; pvalue->size = r_size(pref); pvalue->persistent = false; break; case t_astruct: /* Note: technically, instead of the "mem" argument, we should be using the plists's ref_memory. However, in a simple call to .putdeviceparams, they are identical. */ iparam_check_read(*ploc); if (gs_object_type(mem, pref->value.pstruct) != &st_bytes) return iparam_note_error(*ploc, e_typecheck); pvalue->data = r_ptr(pref, byte); pvalue->size = gs_object_size(mem, pref->value.pstruct); pvalue->persistent = false; break; default: return iparam_note_error(*ploc, e_typecheck); } return 0; }
static int zreusablestream(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr source_op = op - 1; long length = max_long; bool close_source; int code; check_type(*op, t_boolean); close_source = op->value.boolval; if (r_has_type(source_op, t_string)) { uint size = r_size(source_op); check_read(*source_op); code = make_rss(i_ctx_p, source_op, source_op->value.const_bytes, size, r_space(source_op), 0L, size, false); } else if (r_has_type(source_op, t_astruct)) { uint size = gs_object_size(imemory, source_op->value.pstruct); if (gs_object_type(imemory, source_op->value.pstruct) != &st_bytes) return_error(e_rangecheck); check_read(*source_op); code = make_rss(i_ctx_p, source_op, (const byte *)source_op->value.pstruct, size, r_space(source_op), 0L, size, true); } else if (r_has_type(source_op, t_array)) { /* no packedarrays */ int i, blk_cnt, blk_sz; ref *blk_ref; ulong filelen = 0; check_read(*source_op); blk_cnt = r_size(source_op); blk_ref = source_op->value.refs; if (blk_cnt > 0) { blk_sz = r_size(blk_ref); for (i = 0; i < blk_cnt; i++) { int len; check_read_type(blk_ref[i], t_string); len = r_size(&blk_ref[i]); if (len > blk_sz || (len < blk_sz && i < blk_cnt - 1)) return_error(e_rangecheck); /* last block can be smaller */ filelen += len; } } if (filelen == 0) { code = make_rss(i_ctx_p, source_op, (unsigned char *)"", 0, r_space(source_op), 0, 0, false); } else { code = make_aos(i_ctx_p, source_op, blk_sz, r_size(&blk_ref[blk_cnt - 1]), filelen); } } else { long offset = 0; stream *source; stream *s; check_read_file(i_ctx_p, source, source_op); s = source; rs: if (s->cbuf_string.data != 0) { /* string stream */ long pos = stell(s); long avail = sbufavailable(s) + pos; offset += pos; code = make_rss(i_ctx_p, source_op, s->cbuf_string.data, s->cbuf_string.size, imemory_space((const gs_ref_memory_t *)s->memory), offset, min(avail, length), false); } else if (s->file != 0) { /* file stream */ if (~s->modes & (s_mode_read | s_mode_seek)) return_error(e_ioerror); code = make_rfs(i_ctx_p, source_op, s, offset + stell(s), length); } else if (s->state->templat == &s_SFD_template) { /* SubFileDecode filter */ const stream_SFD_state *const sfd_state = (const stream_SFD_state *)s->state; if (sfd_state->eod.size != 0) return_error(e_rangecheck); offset += sfd_state->skip_count - sbufavailable(s); if (sfd_state->count != 0) { long left = max(sfd_state->count, 0) + sbufavailable(s); if (left < length) length = left; } s = s->strm; goto rs; } else /* some other kind of stream */ return_error(e_rangecheck); if (close_source) { stream *rs = fptr(source_op); rs->strm = source; /* only for close_source */ rs->close_strm = true; } } if (code >= 0) pop(1); return code; }
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); }