/* * Restore state after finishing, or unwinding from an error within, a show * operation. Note that we assume op == osp, and may reset osp. */ static int op_show_restore(i_ctx_t *i_ctx_p, bool for_error) { register es_ptr ep = esp + snumpush; gs_text_enum_t *penum = esenum(ep); int saved_level = esgslevel(ep).value.intval; int code = 0; if (for_error) { #if 0 /* Disabled for CPSI compatibility for 13-12-4. CPSI doesn't remove cshow, kshow proc operands. */ uint saved_count = esodepth(ep).value.intval; uint count = ref_stack_count(&o_stack); if (count > saved_count) /* if <, we're in trouble */ ref_stack_pop(&o_stack, count - saved_count); #endif if (ep[1].value.opproc == op_show_continue && penum->enum_client_data != NULL) { /* Replace the continuation operaton on estack with the right operator : */ op_proc_t proc; *(void **)&proc = penum->enum_client_data; make_op_estack(ep + 1, proc); } } if (SHOW_IS_STRINGWIDTH(penum) && igs->text_rendering_mode != 3) { /* stringwidth does an extra gsave */ --saved_level; } if (penum->text.operation & TEXT_REPLACE_WIDTHS) { gs_free_const_object(penum->memory, penum->text.y_widths, "y_widths"); if (penum->text.x_widths != penum->text.y_widths) gs_free_const_object(penum->memory, penum->text.x_widths, "x_widths"); } /* * We might have been inside a cshow, in which case currentfont was * reset temporarily, as though we were inside a BuildChar/ BuildGlyph * procedure. To handle this case, set currentfont back to its original * state. NOTE: this code previously used fstack[0] in the enumerator * for the root font: we aren't sure that this change is correct. */ gs_set_currentfont(igs, penum->orig_font); while (igs->level > saved_level && code >= 0) { if (igs->saved == 0 || igs->saved->saved == 0) { /* * Bad news: we got an error inside a save inside a BuildChar or * BuildGlyph. Don't attempt to recover. */ code = gs_note_error(e_Fatal); } else code = gs_grestore(igs); } gs_text_release(penum, "op_show_restore"); return code; }
/* the TransformPQR procedure. -mark- ... v -> v */ static int cie_post_exec_tpqr(i_ctx_t *i_ctx_p) { os_ptr op = osp; uint count = ref_stack_counttomark(&o_stack); ref vref; if (count < 2) return_error(e_unmatchedmark); vref = *op; ref_stack_pop(&o_stack, count - 1); *osp = vref; return 0; }
/* This is the Level 2 >> operator. */ static int zdicttomark(i_ctx_t *i_ctx_p) { uint count2 = ref_stack_counttomark(&o_stack); ref rdict; int code; uint idx; if (count2 == 0) return_error(e_unmatchedmark); count2--; if ((count2 & 1) != 0) return_error(e_rangecheck); code = dict_create(count2 >> 1, &rdict); if (code < 0) return code; if ((i_ctx_p->scanner_options & SCAN_PDF_RULES) != 0) { for (idx = count2; idx > 0; idx -= 2) { code = idict_put(&rdict, ref_stack_index(&o_stack, idx - 1), ref_stack_index(&o_stack, idx - 2)); if (code < 0) { /* There's no way to free the dictionary -- too bad. */ return code; } } } else { /* << /a 1 /a 2 >> => << /a 1 >>, i.e., */ /* we must enter the keys in top-to-bottom order. */ for (idx = 0; idx < count2; idx += 2) { code = idict_put(&rdict, ref_stack_index(&o_stack, idx + 1), ref_stack_index(&o_stack, idx)); if (code < 0) { /* There's no way to free the dictionary -- too bad. */ return code; } } } ref_stack_pop(&o_stack, count2); ref_assign(osp, &rdict); return code; }
/* <iodevice> .getdevparams <mark> <name> <value> ... */ static int zgetdevparams(i_ctx_t *i_ctx_p) { os_ptr op = osp; gx_io_device *iodev; stack_param_list list; gs_param_list *const plist = (gs_param_list *) & list; int code; ref *pmark; check_read_type(*op, t_string); iodev = gs_findiodevice(imemory, op->value.bytes, r_size(op)); if (iodev == 0) return_error(e_undefined); stack_param_list_write(&list, &o_stack, NULL, iimemory); if ((code = gs_getdevparams(iodev, plist)) < 0) { ref_stack_pop(&o_stack, list.count * 2); return code; } pmark = ref_stack_index(&o_stack, list.count * 2); make_mark(pmark); return 0; }
/* <obj_0> ... <obj_n-1> <array> astore <array> */ static int zastore(i_ctx_t *i_ctx_p) { os_ptr op = osp; uint size; int code; if (!r_is_array(op)) return_op_typecheck(op); size = r_size(op); /* Amazingly, the following is valid: 0 array noaccess astore */ if (size == 0) return 0; if (!r_has_type_attrs(op, t_array, a_write)) return_error(gs_error_invalidaccess); if (size > op - osbot) { /* The store operation might involve other stack segments. */ ref arr; if (size >= ref_stack_count(&o_stack)) return_error(gs_error_stackunderflow); arr = *op; code = ref_stack_store(&o_stack, &arr, size, 1, 0, true, idmemory, "astore"); if (code < 0) return code; ref_stack_pop(&o_stack, size); *ref_stack_index(&o_stack, 0) = arr; } else { code = refcpy_to_old(op, 0, op - size, size, idmemory, "astore"); if (code < 0) return code; op[-(int)size] = *op; pop(size); } return 0; }
/* Note that .putdeviceparams clears the current pagedevice. */ static int zputdeviceparams(i_ctx_t *i_ctx_p) { uint count = ref_stack_counttomark(&o_stack); ref *prequire_all; ref *ppolicy; ref *pdev; gx_device *dev; stack_param_list list; int code; int old_width, old_height; int i, dest; if (count == 0) return_error(e_unmatchedmark); prequire_all = ref_stack_index(&o_stack, count); ppolicy = ref_stack_index(&o_stack, count + 1); pdev = ref_stack_index(&o_stack, count + 2); if (pdev == 0) return_error(e_stackunderflow); check_type_only(*prequire_all, t_boolean); check_write_type_only(*pdev, t_device); dev = pdev->value.pdevice; code = stack_param_list_read(&list, &o_stack, 0, ppolicy, prequire_all->value.boolval, iimemory); if (code < 0) return code; old_width = dev->width; old_height = dev->height; code = gs_putdeviceparams(dev, (gs_param_list *) & list); /* Check for names that were undefined or caused errors. */ for (dest = count - 2, i = 0; i < count >> 1; i++) if (list.results[i] < 0) { *ref_stack_index(&o_stack, dest) = *ref_stack_index(&o_stack, count - (i << 1) - 2); gs_errorname(i_ctx_p, list.results[i], ref_stack_index(&o_stack, dest - 1)); dest -= 2; } iparam_list_release(&list); if (code < 0) { /* There were errors reported. */ ref_stack_pop(&o_stack, dest + 1); return 0; } if (code > 0 || (code == 0 && (dev->width != old_width || dev->height != old_height))) { /* * The device was open and is now closed, or its dimensions have * changed. If it was the current device, call setdevice to * reinstall it and erase the page. */ /****** DOESN'T FIND ALL THE GSTATES THAT REFERENCE THE DEVICE. ******/ if (gs_currentdevice(igs) == dev) { bool was_open = dev->is_open; code = gs_setdevice_no_erase(igs, dev); /* If the device wasn't closed, setdevice won't erase the page. */ if (was_open && code >= 0) code = 1; } } if (code < 0) return code; ref_stack_pop(&o_stack, count + 1); make_bool(osp, code); clear_pagedevice(istate); return 0; }
/* ensuring that refs in mixed arrays are properly aligned. */ #undef idmemory /****** NOTA BENE ******/ int make_packed_array(ref * parr, ref_stack_t * pstack, uint size, gs_dual_memory_t *idmemory, client_name_t cname) { uint i; const ref *pref; uint idest = 0, ishort = 0; ref_packed *pbody; ref_packed *pdest; ref_packed *pshort; /* points to start of */ /* last run of short elements */ gs_ref_memory_t *imem = idmemory->current; uint space = imemory_space(imem); int skip = 0, pad; ref rtemp; int code; /* Do a first pass to calculate the size of the array, */ /* and to detect local-into-global stores. */ for (i = size; i != 0; i--) { pref = ref_stack_index(pstack, i - 1); switch (r_btype(pref)) { /* not r_type, opers are special */ case t_name: if (name_index(imem, pref) >= packed_name_max_index) break; /* can't pack */ idest++; continue; case t_integer: if (pref->value.intval < packed_min_intval || pref->value.intval > packed_max_intval ) break; idest++; continue; case t_oparray: /* Check for local-into-global store. */ store_check_space(space, pref); /* falls through */ case t_operator: { uint oidx; if (!r_has_attr(pref, a_executable)) break; oidx = op_index(pref); if (oidx == 0 || oidx > packed_int_mask) break; } idest++; continue; default: /* Check for local-into-global store. */ store_check_space(space, pref); } /* Can't pack this element, use a full ref. */ /* We may have to unpack up to align_packed_per_ref - 1 */ /* preceding short elements. */ /* If we are at the beginning of the array, however, */ /* we can just move the elements up. */ { int i = (idest - ishort) & (align_packed_per_ref - 1); if (ishort == 0) /* first time */ idest += skip = -i & (align_packed_per_ref - 1); else idest += (packed_per_ref - 1) * i; } ishort = idest += packed_per_ref; } pad = -(int)idest & (packed_per_ref - 1); /* padding at end */ /* Now we can allocate the array. */ code = gs_alloc_ref_array(imem, &rtemp, 0, (idest + pad) / packed_per_ref, cname); if (code < 0) return code; pbody = (ref_packed *) rtemp.value.refs; /* Make sure any initial skipped elements contain legal packed */ /* refs, so that the garbage collector can scan storage. */ pshort = pbody; for (; skip; skip--) *pbody++ = pt_tag(pt_integer); pdest = pbody; for (i = size; i != 0; i--) { pref = ref_stack_index(pstack, i - 1); switch (r_btype(pref)) { /* not r_type, opers are special */ case t_name: { uint nidx = name_index(imem, pref); if (nidx >= packed_name_max_index) break; /* can't pack */ *pdest++ = nidx + (r_has_attr(pref, a_executable) ? pt_tag(pt_executable_name) : pt_tag(pt_literal_name)); } continue; case t_integer: if (pref->value.intval < packed_min_intval || pref->value.intval > packed_max_intval ) break; *pdest++ = pt_tag(pt_integer) + ((short)pref->value.intval - packed_min_intval); continue; case t_oparray: case t_operator: { uint oidx; if (!r_has_attr(pref, a_executable)) break; oidx = op_index(pref); if (oidx == 0 || oidx > packed_int_mask) break; *pdest++ = pt_tag(pt_executable_operator) + oidx; } continue; } /* Can't pack this element, use a full ref. */ /* We may have to unpack up to align_packed_per_ref - 1 */ /* preceding short elements. */ /* Note that if we are at the beginning of the array, */ /* 'skip' already ensures that we don't need to do this. */ { int i = (pdest - pshort) & (align_packed_per_ref - 1); const ref_packed *psrc = pdest; ref *pmove = (ref *) (pdest += (packed_per_ref - 1) * i); ref_assign_new(pmove, pref); while (--i >= 0) { --psrc; --pmove; packed_get(imem->non_gc_memory, psrc, pmove); } } pshort = pdest += packed_per_ref; } { int atype = (pdest == pbody + size ? t_shortarray : t_mixedarray); /* Pad with legal packed refs so that the garbage collector */ /* can scan storage. */ for (; pad; pad--) *pdest++ = pt_tag(pt_integer); /* Finally, make the array. */ ref_stack_pop(pstack, size); make_tasv_new(parr, atype, a_readonly | space, size, packed, pbody + skip); } return 0; }
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; }
/* <mark> <x0> <y0> ... <xn> <yn> .pdfinkpath - */ static int zpdfinkpath(i_ctx_t *i_ctx_p) { os_ptr optr, op = osp; uint count = ref_stack_counttomark(&o_stack); uint i, ocount; int code; double x0, y0, x1, y1, x2, y2, x3, y3, xc1, yc1, xc2, yc2, xc3, yc3; double len1, len2, len3, k1, k2, xm1, ym1, xm2, ym2; double ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y; const double smooth_value = 1; /* from 0..1 range */ if (count == 0) return_error(e_unmatchedmark); if ((count & 1) == 0 || count < 3) return_error(e_rangecheck); ocount = count - 1; optr = op - ocount + 1; if ((code = real_param(optr, &x1)) < 0) return code; if ((code = real_param(optr + 1, &y1)) < 0) return code; if ((code = gs_moveto(igs, x1, y1)) < 0) return code; if (ocount == 2) goto pop; if ((code = real_param(optr + 2, &x2)) < 0) return code; if ((code = real_param(optr + 3, &y2)) < 0) return code; if (ocount == 4) { if((code = gs_lineto(igs, x2, y2)) < 0) return code; goto pop; } x0 = 2*x1 - x2; y0 = 2*y1 - y2; for (i = 4; i <= ocount; i += 2) { if (i < ocount) { if ((code = real_param(optr + i, &x3)) < 0) return code; if ((code = real_param(optr + i + 1, &y3)) < 0) return code; } else { x3 = 2*x2 - x1; y3 = 2*y2 - y1; } xc1 = (x0 + x1) / 2.0; yc1 = (y0 + y1) / 2.0; xc2 = (x1 + x2) / 2.0; yc2 = (y1 + y2) / 2.0; xc3 = (x2 + x3) / 2.0; yc3 = (y2 + y3) / 2.0; len1 = hypot(x1 - x0, y1 - y0); len2 = hypot(x2 - x1, y2 - y1); len3 = hypot(x3 - x2, y3 - y2); k1 = len1 / (len1 + len2); k2 = len2 / (len2 + len3); xm1 = xc1 + (xc2 - xc1) * k1; ym1 = yc1 + (yc2 - yc1) * k1; xm2 = xc2 + (xc3 - xc2) * k2; ym2 = yc2 + (yc3 - yc2) * k2; ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1; ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1; ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2; ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2; code = gs_curveto(igs, ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y, x2, y2); if (code < 0) return code; x0 = x1, x1 = x2, x2 = x3; y0 = y1, y1 = y2, y2 = y3; } pop: ref_stack_pop(&o_stack, count); return 0; }