Exemple #1
0
int main(int argc, char **argv)
{
    int i, idx, op = -1;

    if (argc < 2)
        print_usage_and_exit();

    for (i = 0; i < sizeof(OPS) / sizeof(OPS[0]); i++)
        if (!strcmp(argv[1], OPS[i])){
            op = i;
            break;
        }

    if (op == -1)
        print_usage_and_exit();

    idx = initialize(argc, argv, op);

    switch (op){
        case OP_MAKE:
            return op_make(&options);
        case OP_DUMP:
            return op_dump(&options);
        case OP_INDEX:
            return op_index(&options);
        case OP_MERGE:
            return op_merge(&options,
                            (const char**)&argv[idx],
                            argc - idx);
        default:
            print_usage_and_exit();
    }

    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;
}
Exemple #3
0
/* <obj> cvx <obj> */
int
zcvx(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    ref *aop;
    uint opidx;

    check_op(1);
    /*
     * If the object is an internal operator, we can't allow it to
     * exist in executable form anywhere outside the e-stack.
     */
    if (r_has_type(op, t_operator) &&
	((opidx = op_index(op)) == 0 ||
	 op_def_is_internal(op_index_def(opidx)))
	)
	return_error(e_rangecheck);
    aop = ACCESS_REF(op);
    r_set_attrs(aop, a_executable);
    return 0;
}
Exemple #4
0
/* Dump an array. */
void
debug_dump_array(const ref *array)
{	const ref_packed *pp;
	unsigned int type = r_type(array);
	uint len;

	switch (type)
	   {
	default:
		dprintf2 ("%s at 0x%lx isn't an array.\n",
			  (type < countof(type_strings) ?
			   type_strings[type] : "????"),
			  (ulong)array);
		return;
	case t_oparray:
		/* This isn't really an array, but we'd like to see */
		/* its contents anyway. */
		debug_dump_array(op_array_table.value.refs + op_index(array) -
				 op_def_count);
		return;
	case t_array:
	case t_mixedarray:
	case t_shortarray: 
		;
	   }

	/* This "packed" loop works for all array-types. */
	for ( len = r_size (array), pp = array->value.packed;
	      len > 0;
	      len--, pp = packed_next(pp))
	   {	ref temp;
		packed_get(pp, &temp);
		dprintf3("..%04x%c 0x%02x ", 
			 (uint)pp & 0xffff,
			 ((r_is_packed(pp)) ? '*' : ':'),
			 r_type(&temp));
		debug_dump_one_ref(&temp);
		dputc ('\n');
	   }
}
Exemple #5
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;
}
Exemple #6
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;
}
Exemple #7
0
bool
obj_eq(const gs_memory_t *mem, const ref * pref1, const ref * pref2)
{
    ref nref;

    if (r_type(pref1) != r_type(pref2)) {
	/*
	 * Only a few cases need be considered here:
	 * integer/real (and vice versa), name/string (and vice versa),
	 * arrays, and extended operators.
	 */
	switch (r_type(pref1)) {
	    case t_integer:
		return (r_has_type(pref2, t_real) &&
			pref2->value.realval == pref1->value.intval);
	    case t_real:
		return (r_has_type(pref2, t_integer) &&
			pref2->value.intval == pref1->value.realval);
	    case t_name:
		if (!r_has_type(pref2, t_string))
		    return false;
		name_string_ref(mem, pref1, &nref);
		pref1 = &nref;
		break;
	    case t_string:
		if (!r_has_type(pref2, t_name))
		    return false;
		name_string_ref(mem, pref2, &nref);
		pref2 = &nref;
		break;
		/*
		 * Differing implementations of packedarray can be eq,
		 * if the length is zero, but an array is never eq to a
		 * packedarray.
		 */
	    case t_mixedarray:
	    case t_shortarray:
		/*
		 * Since r_type(pref1) is one of the above, this is a
		 * clever fast check for r_type(pref2) being the other.
		 */
		return ((int)r_type(pref1) + (int)r_type(pref2) ==
			t_mixedarray + t_shortarray) &&
		    r_size(pref1) == 0 && r_size(pref2) == 0;
	    default:
		if (r_btype(pref1) != r_btype(pref2))
		    return false;
	}
    }
    /*
     * Now do a type-dependent comparison.  This would be very simple if we
     * always filled in all the bytes of a ref, but we currently don't.
     */
    switch (r_btype(pref1)) {
	case t_array:
	    return ((pref1->value.refs == pref2->value.refs ||
	             r_size(pref1) == 0) &&
		    r_size(pref1) == r_size(pref2));
	case t_mixedarray:
	case t_shortarray:
	    return ((pref1->value.packed == pref2->value.packed ||
	             r_size(pref1) == 0) &&
		    r_size(pref1) == r_size(pref2));
	case t_boolean:
	    return (pref1->value.boolval == pref2->value.boolval);
	case t_dictionary:
	    return (pref1->value.pdict == pref2->value.pdict);
	case t_file:
	    return (pref1->value.pfile == pref2->value.pfile &&
		    r_size(pref1) == r_size(pref2));
	case t_integer:
	    return (pref1->value.intval == pref2->value.intval);
	case t_mark:
	case t_null:
	    return true;
	case t_name:
	    return (pref1->value.pname == pref2->value.pname);
	case t_oparray:
	case t_operator:
	    return (op_index(pref1) == op_index(pref2));
	case t_real:
	    return (pref1->value.realval == pref2->value.realval);
	case t_save:
	    return (pref2->value.saveid == pref1->value.saveid);
	case t_string:
	    return (!bytes_compare(pref1->value.bytes, r_size(pref1),
				   pref2->value.bytes, r_size(pref2)));
	case t_device:
	    return (pref1->value.pdevice == pref2->value.pdevice);
	case t_struct:
	case t_astruct:
	    return (pref1->value.pstruct == pref2->value.pstruct);
	case t_fontID:
	    /* This is complicated enough to deserve a separate procedure. */
	    return fid_eq(mem, r_ptr(pref1, gs_font), r_ptr(pref2, gs_font));
    }
    return false;		/* shouldn't happen! */
}
Exemple #8
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);
}