/* search */ int zsearch(register os_ptr op) { os_ptr op1 = op - 1; uint size = r_size(op); uint count; byte *ptr; check_read_type(*op1, t_string); check_read_type(*op, t_string); if ( size > r_size(op1) ) /* can't match */ { make_bool(op, 0); return 0; } count = r_size(op1) - size; ptr = op1->value.bytes; do { if ( !memcmp(ptr, op->value.bytes, size) ) { op->tas.type_attrs = op1->tas.type_attrs; op->value.bytes = ptr; r_set_size(op, size); push(1); *op = *op1; r_set_size(op, ptr - op->value.bytes); op1->value.bytes = ptr + size; r_set_size(op1, count); push(1); make_bool(op, 1); return 0; } ptr++; } while ( count-- ); /* No match */ make_bool(op, 0); return 0; }
static int push_execstack(i_ctx_t *i_ctx_p, os_ptr op1, bool include_marks, op_proc_t cont) { uint size; /* * We can't do this directly, because the interpreter * might have cached some state. To force the interpreter * to update the stored state, we push a continuation on * the exec stack; the continuation is executed immediately, * and does the actual transfer. */ uint depth; if (!r_is_array(op1)) return_op_typecheck(op1); /* Check the length before the write access per CET 28-03 */ size = r_size(op1); depth = count_exec_stack(i_ctx_p, include_marks); if (depth > size) return_error(e_rangecheck); check_write(*op1); { int code = ref_stack_store_check(&e_stack, op1, size, 0); if (code < 0) return code; } check_estack(1); r_set_size(op1, depth); push_op_estack(cont); return o_push_estack; }
static int zreadstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint start) { stream *s; uint len, rlen; int status; check_write_type(*op, t_string); check_read_file(s, op - 1); len = r_size(op); status = sgets(s, op->value.bytes + start, len - start, &rlen); rlen += start; switch (status) { case EOFC: case 0: break; default: return handle_read_status(i_ctx_p, status, op - 1, &rlen, zreadstring_continue); } /* * The most recent Adobe specification says that readstring * must signal a rangecheck if the string length is zero. * I can't imagine the motivation for this, but we emulate it. * It's safe to check it here, rather than earlier, because if * len is zero, sgets will return 0 immediately with rlen = 0. */ if (len == 0) return_error(e_rangecheck); r_set_size(op, rlen); op[-1] = *op; make_bool(op, (rlen == len ? 1 : 0)); return 0; }
static int type1crypt(i_ctx_t *i_ctx_p, int (*proc)(byte *, const byte *, uint, ushort *)) { os_ptr op = osp; crypt_state state; uint ssize; check_type(op[-2], t_integer); state = op[-2].value.intval; if (op[-2].value.intval != state) return_error(e_rangecheck); /* state value was truncated */ check_read_type(op[-1], t_string); check_write_type(*op, t_string); ssize = r_size(op - 1); if (r_size(op) < ssize) return_error(e_rangecheck); discard((*proc)(op->value.bytes, op[-1].value.const_bytes, ssize, &state)); /* can't fail */ op[-2].value.intval = state; op[-1] = *op; r_set_size(op - 1, ssize); pop(1); return 0; }
/* Continuation operator for enumerating files */ static int file_continue(i_ctx_t *i_ctx_p) { os_ptr op = osp; es_ptr pscratch = esp - 2; file_enum *pfen = r_ptr(esp - 1, file_enum); long devlen = esp[-3].value.intval; gx_io_device *iodev = r_ptr(esp - 4, gx_io_device); uint len = r_size(pscratch); uint code; if (len < devlen) return_error(e_rangecheck); /* not even room for device len */ memcpy((char *)pscratch->value.bytes, iodev->dname, devlen); code = iodev->procs.enumerate_next(pfen, (char *)pscratch->value.bytes + devlen, len - devlen); if (code == ~(uint) 0) { /* all done */ esp -= 5; /* pop proc, pfen, devlen, iodev , mark */ return o_pop_estack; } else if (code > len) /* overran string */ return_error(e_rangecheck); else { push(1); ref_assign(op, pscratch); r_set_size(op, code + devlen); push_op_estack(file_continue); /* come again */ *++esp = pscratch[2]; /* proc */ return o_push_estack; } }
/* <string> <pattern> search <string> -false- */ static int zsearch(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr op1 = op - 1; uint size = r_size(op); uint count; byte *pat; byte *ptr; byte ch; check_read_type(*op1, t_string); check_read_type(*op, t_string); if (size > r_size(op1)) { /* can't match */ make_false(op); return 0; } count = r_size(op1) - size; ptr = op1->value.bytes; if (size == 0) goto found; pat = op->value.bytes; ch = pat[0]; do { if (*ptr == ch && (size == 1 || !memcmp(ptr, pat, size))) goto found; ptr++; } while (count--); /* No match */ make_false(op); return 0; found: op->tas.type_attrs = op1->tas.type_attrs; op->value.bytes = ptr; r_set_size(op, size); push(2); op[-1] = *op1; r_set_size(op - 1, ptr - op[-1].value.bytes); op1->value.bytes = ptr + size; r_set_size(op1, count); make_true(op); return 0; }
static int zwritecvp_at(i_ctx_t *i_ctx_p, os_ptr op, uint start, bool first) { stream *s; byte str[100]; /* arbitrary */ ref rstr; const byte *data = str; uint len; int code, status; check_write_file(s, op - 2); check_type(*op, t_integer); code = obj_cvp(op - 1, str, sizeof(str), &len, (int)op->value.intval, start, imemory, true); if (code == e_rangecheck) { code = obj_string_data(imemory, op - 1, &data, &len); if (len < start) return_error(e_rangecheck); data += start; len -= start; } if (code < 0) return code; r_set_size(&rstr, len); rstr.value.const_bytes = data; status = write_string(&rstr, s); switch (status) { default: return_error(e_ioerror); case 0: break; case INTC: case CALLC: len = start + len - r_size(&rstr); if (!first) --osp; /* pop(1) without affecting op */ return handle_write_status(i_ctx_p, status, op - 2, &len, zwritecvp_continue); } if (code == 1) { if (first) check_ostack(1); push_op_estack(zwritecvp_continue); if (first) push(1); make_int(osp, start + len); return o_push_estack; } if (first) /* zwritecvp */ pop(3); else /* zwritecvp_continue */ pop(4); return 0; }
static int zwritehexstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint odd) { register stream *s; register byte ch; register const byte *p; register const char *const hex_digits = "0123456789abcdef"; register uint len; int status; #define MAX_HEX 128 byte buf[MAX_HEX]; check_write_file(s, op - 1); check_read_type(*op, t_string); p = op->value.bytes; len = r_size(op); while (len) { uint len1 = min(len, MAX_HEX / 2); register byte *q = buf; uint count = len1; ref rbuf; do { ch = *p++; *q++ = hex_digits[ch >> 4]; *q++ = hex_digits[ch & 0xf]; } while (--count); r_set_size(&rbuf, (len1 << 1) - odd); rbuf.value.bytes = buf + odd; status = write_string(&rbuf, s); switch (status) { default: return_error(e_ioerror); case 0: len -= len1; odd = 0; continue; case INTC: case CALLC: count = rbuf.value.bytes - buf; op->value.bytes += count >> 1; r_set_size(op, len - (count >> 1)); count &= 1; return handle_write_status(i_ctx_p, status, op - 1, &count, zwritehexstring_continue); } } pop(2); return 0; #undef MAX_HEX }
/* <string1> <string2> copy <substring2> */ static int zcopy_interval(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr op1 = op - 1; int code = copy_interval(i_ctx_p, op, 0, op1, "copy"); if (code < 0) return code; r_set_size(op, r_size(op1)); *op1 = *op; pop(1); return 0; }
/* * We could handle readline the same way as readstring, * except for the anomalous situation where we get interrupted * between the CR and the LF of an end-of-line marker. * We hack around this in the following way: if we get interrupted * before we've read any characters, we just restart the readline; * if we get interrupted at any other time, we use readline_continue; * we use start=0 (which we have just ruled out as a possible start value * for readline_continue) to indicate interruption after the CR. */ static int zreadline_at(i_ctx_t *i_ctx_p, os_ptr op, uint count, bool in_eol) { stream *s; int status; gs_string str; check_write_type(*op, t_string); check_read_file(s, op - 1); str.data = op->value.bytes; str.size = r_size(op); status = zreadline_from(s, &str, NULL, &count, &in_eol); switch (status) { case 0: case EOFC: break; case 1: return_error(e_rangecheck); default: if (count == 0 && !in_eol) return handle_read_status(i_ctx_p, status, op - 1, NULL, zreadline); else { if (in_eol) { r_set_size(op, count); count = 0; } return handle_read_status(i_ctx_p, status, op - 1, &count, zreadline_continue); } } r_set_size(op, count); op[-1] = *op; make_bool(op, status == 0); return 0; }
/* Convert a file name to a C string by adding a null terminator. */ int terminate_file_name(parsed_file_name *pfn, client_name_t cname) { uint len = pfn->len; ref fnref; const char *fname; if ( pfn->iodev == NULL ) /* no device */ pfn->iodev = iodev_default; fnref.value.const_bytes = (const byte *)pfn->fname; r_set_size(&fnref, len); fname = ref_to_string(&fnref, imemory, cname); if ( fname == 0 ) return_error(e_VMerror); pfn->fname = fname; pfn->len = len + 1; /* null terminator */ return 0; }
/* <dnum> <string> .dcvs <substring> */ static int zdcvs(i_ctx_t *i_ctx_p) { os_ptr op = osp; double num; int code = double_params(op - 1, 1, &num); char dot, str[MAX_CHARS + 1]; int len; if (code < 0) return code; check_write_type(*op, t_string); sprintf(str, "%f", 1.5); dot = str[1]; /* locale-dependent */ /* * To get fully accurate output results for IEEE double- * precision floats (53 bits of mantissa), the ANSI * %g default of 6 digits is not enough; 16 are needed. * Unfortunately, using %.16g produces unfortunate artifacts such as * 1.2 printing as 1.200000000000005. Therefore, we print using %g, * and if the result isn't accurate enough, print again * using %.16g. */ { double scanned; sprintf(str, "%g", num); sscanf(str, "%lf", &scanned); if (scanned != num) sprintf(str, "%.16g", num); } len = strlen(str); if (len > r_size(op)) return_error(e_rangecheck); /* Juggling locales isn't thread-safe. Posix me harder. */ if (dot != '.') { char *pdot = strchr(str, dot); if (pdot) *pdot = '.'; } memcpy(op->value.bytes, str, len); op[-1] = *op; r_set_size(op - 1, len); pop(1); return 0; }
/* <seq:array|packedarray|string> <index> <count> getinterval <subseq> */ static int zgetinterval(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr op1 = op - 1; os_ptr op2 = op1 - 1; uint index; uint count; switch (r_type(op2)) { default: return_op_typecheck(op2); case t_array: case t_string: case t_mixedarray: case t_shortarray:; } check_read(*op2); check_int_leu(*op1, r_size(op2)); index = op1->value.intval; check_int_leu(*op, r_size(op2) - index); count = op->value.intval; switch (r_type(op2)) { case t_array: op2->value.refs += index; break; case t_string: op2->value.bytes += index; break; case t_mixedarray: { const ref_packed *packed = op2->value.packed; for (; index--;) packed = packed_next(packed); op2->value.packed = packed; break; } case t_shortarray: op2->value.packed += index; break; } r_set_size(op2, count); pop(2); return 0; }
/* anchorsearch */ int zanchorsearch(register os_ptr op) { os_ptr op1 = op - 1; uint size = r_size(op); check_read_type(*op1, t_string); check_read_type(*op, t_string); if ( size <= r_size(op1) && !memcmp(op1->value.bytes, op->value.bytes, size) ) { *op = *op1; r_set_size(op, size); op1->value.bytes += size; r_inc_size(op1, -size); push(1); make_bool(op, 1); } else make_bool(op, 0); return 0; }
/* If the status is INTC or CALLC, updates the string on the o-stack. */ static int write_string(ref * op, stream * s) { const byte *data = op->value.const_bytes; uint len = r_size(op); uint wlen; int status = sputs(s, data, len, &wlen); switch (status) { case INTC: case CALLC: op->value.const_bytes = data + wlen; r_set_size(op, len - wlen); /* falls through */ default: /* 0, EOFC, ERRC */ return status; } }
/* convenience of reusing procedures that take 1 state parameter */ static int zreadhexstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint start, int odd) { stream *s; uint len, nread; byte *str; int odd_byte = odd; stream_cursor_write cw; int status; check_read_file(s, op - 1); /*check_write_type(*op, t_string); *//* done by caller */ str = op->value.bytes; len = r_size(op); cw.ptr = str + start - 1; cw.limit = str + len - 1; for (;;) { status = s_hex_process(&s->cursor.r, &cw, &odd_byte, hex_ignore_garbage); if (status == 1) { /* filled the string */ ref_assign_inline(op - 1, op); make_true(op); return 0; } else if (status != 0) /* error or EOF */ break; /* Didn't fill, keep going. */ status = spgetc(s); if (status < 0) break; sputback(s); } nread = cw.ptr + 1 - str; if (status != EOFC) { /* Error */ nread |= odd_byte << 24; return handle_read_status(i_ctx_p, status, op - 1, &nread, zreadhexstring_continue); } /* Reached end-of-file before filling the string. */ /* Return an appropriate substring. */ ref_assign_inline(op - 1, op); r_set_size(op - 1, nread); make_false(op); return 0; }
static int zbosobject(i_ctx_t *i_ctx_p) { os_ptr op = osp; int code; check_type(op[-3], t_integer); check_type(op[-2], t_integer); check_write_type(*op, t_string); if (r_size(op) < 8) return_error(gs_error_rangecheck); code = encode_binary_token(i_ctx_p, op - 1, &op[-3].value.intval, &op[-2].value.intval, op->value.bytes); if (code < 0) return code; op[-1] = *op; r_set_size(op - 1, 8); pop(1); return 0; }
/* <file> <string> .peekstring <substring> <filled_bool> */ static int zpeekstring(i_ctx_t *i_ctx_p) { os_ptr op = osp; stream *s; uint len, rlen; check_read_file(s, op - 1); check_write_type(*op, t_string); len = r_size(op); while ((rlen = sbufavailable(s)) < len) { int status = s->end_status; switch (status) { case EOFC: break; case 0: /* * The following is a HACK. It should reallocate the buffer to hold * at least len bytes. However, this raises messy problems about * which allocator to use and how it should interact with restore. */ if (len >= s->bsize) return_error(e_rangecheck); s_process_read_buf(s); continue; default: return handle_read_status(i_ctx_p, status, op - 1, NULL, zpeekstring); } break; } if (rlen > len) rlen = len; /* Don't remove the data from the buffer. */ memcpy(op->value.bytes, sbufptr(s), rlen); r_set_size(op, rlen); op[-1] = *op; make_bool(op, (rlen == len ? 1 : 0)); return 0; }
/* Clear the relocation for a ref object. */ static void refs_clear_reloc(obj_header_t *hdr, uint size) { ref_packed *rp = (ref_packed *) (hdr + 1); ref_packed *end = (ref_packed *) ((byte *) rp + size); while (rp < end) { if (r_is_packed(rp)) rp++; else { /* Full-size ref. Store the relocation here if possible. */ ref *const pref = (ref *)rp; if (!ref_type_uses_size_or_null(r_type(pref))) { if_debug1('8', " [8]clearing reloc at 0x%lx\n", (ulong) rp); r_set_size(pref, 0); } rp += packed_per_ref; } } }
/* <string> <pattern> anchorsearch <string> -false- */ static int zanchorsearch(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr op1 = op - 1; uint size = r_size(op); check_read_type(*op, t_string); check_read_type(*op1, t_string); if (size <= r_size(op1) && !memcmp(op1->value.bytes, op->value.bytes, size)) { os_ptr op0 = op; push(1); *op0 = *op1; r_set_size(op0, size); op1->value.bytes += size; r_dec_size(op1, size); make_true(op); } else make_false(op); return 0; }
/* cvrs can use it when the radix is 10. */ static int convert_to_string(const gs_memory_t *mem, os_ptr op1, os_ptr op) { uint len; const byte *pstr = 0; int code = obj_cvs(mem, op1, op->value.bytes, r_size(op), &len, &pstr); if (code < 0) { /* * Some common downloaded error handlers assume that * operator names don't exceed a certain fixed size. * To work around this bit of bad design, we implement * a special hack here: if we got a rangecheck, and * the object is an operator whose name begins with * %, ., or @, we just truncate the name. */ if (code == e_rangecheck) switch (r_btype(op1)) { case t_oparray: case t_operator: if (pstr != 0) switch (*pstr) { case '%': case '.': case '@': len = r_size(op); memcpy(op->value.bytes, pstr, len); goto ok; } } return code; } ok: *op1 = *op; r_set_size(op1, len); return 0; }
/* .getbitsrect <height> <substring> */ static int zgetbitsrect(i_ctx_t *i_ctx_p) { /* * alpha? is 0 for no alpha, -1 for alpha first, 1 for alpha last. * std_depth is null for native pixels, depth/component for * standard color space. */ os_ptr op = osp; gx_device *dev; gs_int_rect rect; gs_get_bits_params_t params; int w, h; gs_get_bits_options_t options = GB_ALIGN_ANY | GB_RETURN_COPY | GB_OFFSET_0 | GB_RASTER_STANDARD | GB_PACKING_CHUNKY; int depth; uint raster; int num_rows; int code; check_read_type(op[-7], t_device); dev = op[-7].value.pdevice; check_int_leu(op[-6], dev->width); rect.p.x = op[-6].value.intval; check_int_leu(op[-5], dev->height); rect.p.y = op[-5].value.intval; check_int_leu(op[-4], dev->width); w = op[-4].value.intval; check_int_leu(op[-3], dev->height); h = op[-3].value.intval; check_type(op[-2], t_integer); /* * We use if/else rather than switch because the value is long, * which is not supported as a switch value in pre-ANSI C. */ if (op[-2].value.intval == -1) options |= GB_ALPHA_FIRST; else if (op[-2].value.intval == 0) options |= GB_ALPHA_NONE; else if (op[-2].value.intval == 1) options |= GB_ALPHA_LAST; else return_error(e_rangecheck); if (r_has_type(op - 1, t_null)) { options |= GB_COLORS_NATIVE; depth = dev->color_info.depth; } else { static const gs_get_bits_options_t depths[17] = { 0, GB_DEPTH_1, GB_DEPTH_2, 0, GB_DEPTH_4, 0, 0, 0, GB_DEPTH_8, 0, 0, 0, GB_DEPTH_12, 0, 0, 0, GB_DEPTH_16 }; gs_get_bits_options_t depth_option; int std_depth; check_int_leu(op[-1], 16); std_depth = (int)op[-1].value.intval; depth_option = depths[std_depth]; if (depth_option == 0) return_error(e_rangecheck); options |= depth_option | GB_COLORS_NATIVE; depth = (dev->color_info.num_components + (options & GB_ALPHA_NONE ? 0 : 1)) * std_depth; } if (w == 0) return_error(e_rangecheck); raster = (w * depth + 7) >> 3; check_write_type(*op, t_string); num_rows = r_size(op) / raster; h = min(h, num_rows); if (h == 0) return_error(e_rangecheck); rect.q.x = rect.p.x + w; rect.q.y = rect.p.y + h; params.options = options; params.data[0] = op->value.bytes; code = (*dev_proc(dev, get_bits_rectangle))(dev, &rect, ¶ms, NULL); if (code < 0) return code; make_int(op - 7, h); op[-6] = *op; r_set_size(op - 6, h * raster); pop(6); return 0; }
/* <bitmap> <cid> <type32font> <str22> .makeglyph32 <<same with substr>> */ static int zmakeglyph32(i_ctx_t *i_ctx_p) { os_ptr op = osp; bool long_form; uint msize; double metrics[10]; int wx, llx, lly, urx, ury; int width, height, raster; gs_font *pfont; int code; byte *str; check_array(op[-4]); msize = r_size(op - 4); switch (msize) { case 10: long_form = true; break; case 6: long_form = false; break; default: return_error(gs_error_rangecheck); } code = num_params(op[-4].value.refs + msize - 1, msize, metrics); if (code < 0) return code; if (~code & 0x3c) /* check llx .. ury for integers */ return_error(gs_error_typecheck); check_read_type(op[-3], t_string); llx = (int)metrics[2]; lly = (int)metrics[3]; urx = (int)metrics[4]; ury = (int)metrics[5]; width = urx - llx; height = ury - lly; raster = (width + 7) >> 3; if (width < 0 || height < 0 || r_size(op - 3) != raster * height) return_error(gs_error_rangecheck); check_int_leu(op[-2], 65535); code = font_param(op - 1, &pfont); if (code < 0) return code; if (pfont->FontType != ft_CID_bitmap) return_error(gs_error_invalidfont); check_write_type(*op, t_string); if (r_size(op) < 22) return_error(gs_error_rangecheck); str = op->value.bytes; if (long_form || metrics[0] != (wx = (int)metrics[0]) || metrics[1] != 0 || height == 0 || ((wx | width | height | (llx + 128) | (lly + 128)) & ~255) != 0 ) { /* Use the long form. */ int i, n = (long_form ? 10 : 6); str[0] = 0; str[1] = long_form; for (i = 0; i < n; ++i) { int v = (int)metrics[i]; /* no floating point widths yet */ str[2 + 2 * i] = (byte)(v >> 8); str[2 + 2 * i + 1] = (byte)v; } r_set_size(op, 2 + n * 2); } else {
/* Set the relocation for a ref object. */ static bool refs_set_reloc(obj_header_t * hdr, uint reloc, uint size) { ref_packed *rp = (ref_packed *) (hdr + 1); ref_packed *end = (ref_packed *) ((byte *) rp + size); uint freed = 0; /* * We have to be careful to keep refs aligned properly. * For the moment, we do this by either keeping or discarding * an entire (aligned) block of align_packed_per_ref packed elements * as a unit. We know that align_packed_per_ref <= packed_per_ref, * and we also know that packed refs are always allocated in blocks * of align_packed_per_ref, so this makes things relatively easy. */ while (rp < end) { if (r_is_packed(rp)) { #if align_packed_per_ref == 1 if (r_has_pmark(rp)) { if_debug1('8', " [8]packed ref 0x%lx is marked\n", (ulong) rp); rp++; } else { #else int i; /* * Note: align_packed_per_ref is typically * 2 or 4 for 32-bit processors. */ #define all_marked (align_packed_per_ref * lp_mark) # if align_packed_per_ref == 2 # if arch_sizeof_int == arch_sizeof_short * 2 # undef all_marked # define all_marked ( (lp_mark << (sizeof(short) * 8)) + lp_mark ) # define marked (*(int *)rp & all_marked) # else # define marked ((*rp & lp_mark) + (rp[1] & lp_mark)) # endif # else # if align_packed_per_ref == 4 # define marked ((*rp & lp_mark) + (rp[1] & lp_mark) +\ (rp[2] & lp_mark) + (rp[3] & lp_mark)) # else /* * The value of marked is logically a uint, not an int: * we declare it as int only to avoid a compiler warning * message about using a non-int value in a switch statement. */ int marked = *rp & lp_mark; for (i = 1; i < align_packed_per_ref; i++) marked += rp[i] & lp_mark; # endif # endif /* * Now marked is lp_mark * the number of marked * packed refs in the aligned block, except for * a couple of special cases above. */ switch (marked) { case all_marked: if_debug2('8', " [8]packed refs 0x%lx..0x%lx are marked\n", (ulong) rp, (ulong) (rp + (align_packed_per_ref - 1))); rp += align_packed_per_ref; break; default: /* At least one packed ref in the block */ /* is marked: Keep the whole block. */ for (i = align_packed_per_ref; i--; rp++) { r_set_pmark(rp); if_debug1('8', " [8]packed ref 0x%lx is marked\n", (ulong) rp); } break; case 0: #endif if_debug2('8', " [8]%d packed ref(s) at 0x%lx are unmarked\n", align_packed_per_ref, (ulong) rp); { uint rel = reloc + freed; /* Change this to an integer so we can */ /* store the relocation here. */ *rp = pt_tag(pt_integer) + min(rel, packed_max_value); } rp += align_packed_per_ref; freed += sizeof(ref_packed) * align_packed_per_ref; } } else { /* full-size ref */ uint rel = reloc + freed; /* The following assignment is logically */ /* unnecessary; we do it only for convenience */ /* in debugging. */ ref *pref = (ref *) rp; if (!r_has_attr(pref, l_mark)) { if_debug1('8', " [8]ref 0x%lx is unmarked\n", (ulong) pref); /* Change this to a mark so we can */ /* store the relocation. */ r_set_type(pref, t_mark); r_set_size(pref, rel); freed += sizeof(ref); } else { if_debug1('8', " [8]ref 0x%lx is marked\n", (ulong) pref); /* Store the relocation here if possible. */ if (!ref_type_uses_size_or_null(r_type(pref))) { if_debug2('8', " [8]storing reloc %u at 0x%lx\n", rel, (ulong) pref); r_set_size(pref, rel); } } rp += packed_per_ref; } } if_debug3('7', " [7]at end of refs 0x%lx, size = %u, freed = %u\n", (ulong) (hdr + 1), size, freed); if (freed == size) return false; #if arch_sizeof_int > arch_sizeof_short /* * If the final relocation can't fit in the r_size field * (which can't happen if the object shares a chunk with * any other objects, so we know reloc = 0 in this case), * we have to keep the entire object unless there are no * references to any ref in it. */ if (freed <= max_ushort) return true; /* * We have to mark all surviving refs, but we also must * overwrite any non-surviving refs with something that * doesn't contain any pointers. */ rp = (ref_packed *) (hdr + 1); while (rp < end) { if (r_is_packed(rp)) { if (!r_has_pmark(rp)) *rp = pt_tag(pt_integer) | lp_mark; ++rp; } else { /* The following assignment is logically */ /* unnecessary; we do it only for convenience */ /* in debugging. */ ref *pref = (ref *) rp; if (!r_has_attr(pref, l_mark)) { r_set_type_attrs(pref, t_mark, l_mark); r_set_size(pref, reloc); } else { if (!ref_type_uses_size_or_null(r_type(pref))) r_set_size(pref, reloc); } rp += packed_per_ref; } } /* The last ref has to remain unmarked. */ r_clear_attrs((ref *) rp - 1, l_mark); #endif return true; }
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; }
/* <num> <radix_int> <string> cvrs <substring> */ static int zcvrs(i_ctx_t *i_ctx_p) { os_ptr op = osp; int radix; check_type(op[-1], t_integer); if (op[-1].value.intval < 2 || op[-1].value.intval > 36) return_error(e_rangecheck); radix = op[-1].value.intval; check_write_type(*op, t_string); if (radix == 10) { switch (r_type(op - 2)) { case t_integer: case t_real: { int code = convert_to_string(imemory, op - 2, op); if (code < 0) return code; pop(2); return 0; } case t__invalid: return_error(e_stackunderflow); default: return_error(e_rangecheck); /* CET 24-05 wants rangecheck */ } } else { uint ival; byte digits[sizeof(ulong) * 8]; byte *endp = &digits[countof(digits)]; byte *dp = endp; switch (r_type(op - 2)) { case t_integer: ival = (uint) op[-2].value.intval; break; case t_real: { float fval = op[-2].value.realval; if (!REAL_CAN_BE_INT(fval)) return_error(e_rangecheck); ival = (ulong) (long)fval; } break; case t__invalid: return_error(e_stackunderflow); default: return_error(e_rangecheck); /* CET 24-05 wants rangecheck */ } do { int dit = ival % radix; *--dp = dit + (dit < 10 ? '0' : ('A' - 10)); ival /= radix; } while (ival); if (endp - dp > r_size(op)) return_error(e_rangecheck); memcpy(op->value.bytes, dp, (uint) (endp - dp)); r_set_size(op, endp - dp); } op[-2] = *op; pop(2); return 0; }