Пример #1
0
/*
 * Ensure that a dictionary uses the unpacked representation for keys.
 * We can't just use dict_resize, because the values slots mustn't move.
 */
int
dict_unpack(ref * pdref, dict_stack_t *pds)
{
    dict *pdict = pdref->value.pdict;

    if (!dict_is_packed(pdict))
        return 0;		/* nothing to do */
    {
        gs_ref_memory_t *mem = dict_memory(pdict);
        uint count = nslots(pdict);
        const ref_packed *okp = pdict->keys.value.packed;
        ref old_keys;
        int code;
        ref *nkp;

        old_keys = pdict->keys;
        if (ref_must_save_in(mem, &old_keys))
            ref_do_save_in(mem, pdref, &pdict->keys, "dict_unpack(keys)");
        code = dict_create_unpacked_keys(count, pdref);
        if (code < 0)
            return code;
        for (nkp = pdict->keys.value.refs; count--; okp++, nkp++)
            if (r_packed_is_name(okp)) {
                packed_get((const gs_memory_t *)mem, okp, nkp);
                ref_mark_new_in(mem, nkp);
            } else if (*okp == packed_key_deleted)
                r_set_attrs(nkp, a_executable);
        if (!ref_must_save_in(mem, &old_keys))
            gs_free_ref_array(mem, &old_keys, "dict_unpack(old keys)");
        if (pds)
            dstack_set_top(pds);	/* just in case */
    }
    return 0;
}
Пример #2
0
/* the VM space where the dictionary is allocated. */
static int
dict_create_contents(uint size, const ref * pdref, bool pack)
{
    dict *pdict = pdref->value.pdict;
    gs_ref_memory_t *mem = dict_memory(pdict);
    uint new_mask = imemory_new_mask(mem);
    uint asize = dict_round_size((size == 0 ? 1 : size));
    int code;
    register uint i;

    if (asize == 0 || asize > max_array_size - 1)	/* too large */
        return_error(gs_error_limitcheck);
    asize++;			/* allow room for wraparound entry */
    code = gs_alloc_ref_array(mem, &pdict->values, a_all, asize,
                              "dict_create_contents(values)");
    if (code < 0)
        return code;
    r_set_attrs(&pdict->values, new_mask);
    refset_null_new(pdict->values.value.refs, asize, new_mask);
    if (pack) {
        uint ksize = (asize + packed_per_ref - 1) / packed_per_ref;
        ref arr;
        ref_packed *pkp;
        ref_packed *pzp;

        code = gs_alloc_ref_array(mem, &arr, a_all, ksize,
                                  "dict_create_contents(packed keys)");
        if (code < 0)
            return code;
        pkp = (ref_packed *) arr.value.refs;
        make_tasv(&pdict->keys, t_shortarray,
                  r_space(&arr) | a_all | new_mask,
                  asize, packed, pkp);
        for (pzp = pkp, i = 0; i < asize || i % packed_per_ref; pzp++, i++)
            *pzp = packed_key_empty;
        *pkp = packed_key_deleted;	/* wraparound entry */
    } else {			/* not packed */
        int code = dict_create_unpacked_keys(asize, pdref);

        if (code < 0)
            return code;
    }
    make_tav(&pdict->count, t_integer, new_mask, intval, 0);
    make_tav(&pdict->maxlength, t_integer, new_mask, intval, size);
    return 0;
}
Пример #3
0
/* The keys are allocated using the same allocator as the dictionary. */
static int
dict_create_unpacked_keys(uint asize, const ref * pdref)
{
    dict *pdict = pdref->value.pdict;
    gs_ref_memory_t *mem = dict_memory(pdict);
    int code;

    code = gs_alloc_ref_array(mem, &pdict->keys, a_all, asize,
                              "dict_create_unpacked_keys");
    if (code >= 0) {
        uint new_mask = imemory_new_mask(mem);
        ref *kp = pdict->keys.value.refs;

        r_set_attrs(&pdict->keys, new_mask);
        refset_null_new(kp, asize, new_mask);
        r_set_attrs(kp, a_executable);	/* wraparound entry */
    }
    return code;
}
Пример #4
0
/* Grow a dictionary for dict_put. */
int
dict_grow(ref * pdref, dict_stack_t *pds)
{
    dict *pdict = pdref->value.pdict;
    /* We might have maxlength < npairs, if */
    /* dict_round_size increased the size. */
    ulong new_size = (ulong) d_maxlength(pdict);
    /* Adobe does this */
    if (new_size < 20)
        new_size += 10;
    else if (new_size < 200)
        new_size *= 2;
    else
        new_size += new_size / 2;
#if ARCH_SIZEOF_INT < ARCH_SIZEOF_LONG
    if (new_size > max_uint)
        new_size = max_uint;
#endif
    if (new_size > npairs(pdict)) {
        int code = dict_resize(pdref, (uint) new_size, pds);

        if (code >= 0)
            return code;
        /* new_size was too big. */
        if (npairs(pdict) < dict_max_size) {
            code = dict_resize(pdref, dict_max_size, pds);
            if (code >= 0)
                return code;
        }
        if (npairs(pdict) == d_maxlength(pdict)) {	/* Can't do it. */
            return code;
        }
        /* We can't grow to new_size, but we can grow to npairs. */
        new_size = npairs(pdict);
    }
    /* maxlength < npairs, we can grow in place */
    ref_save_in(dict_memory(pdict), pdref, &pdict->maxlength,
                "dict_put(maxlength)");
    d_set_maxlength(pdict, new_size);
    return 0;
}
Пример #5
0
/* <dict> .initialize_dsc_parser - */
static int
zinitialize_dsc_parser(i_ctx_t *i_ctx_p)
{
    ref local_ref;
    int code;
    os_ptr const op = osp;
    dict * const pdict = op->value.pdict;
    gs_memory_t * const mem = (gs_memory_t *)dict_memory(pdict);
    dsc_data_t * const data =
	gs_alloc_struct(mem, dsc_data_t, &st_dsc_data_t,
			"DSC parser init");

    data->dsc_data_ptr = dsc_init((void *) "Ghostscript DSC parsing");
    if (!data->dsc_data_ptr)
    	return_error(e_VMerror);
    dsc_set_error_function(data->dsc_data_ptr, dsc_error_handler);
    make_astruct(&local_ref, a_readonly | r_space(op), (byte *) data);
    code = idict_put_string(op, dsc_dict_name, &local_ref);
    if (code >= 0)
	pop(1);
    return code;
}
Пример #6
0
/* Resize a dictionary. */
int
dict_resize(ref * pdref, uint new_size, dict_stack_t *pds)
{
    dict *pdict = pdref->value.pdict;
    gs_ref_memory_t *mem = dict_memory(pdict);
    uint new_mask = imemory_new_mask(mem);
    ushort orig_attrs = r_type_attrs(&pdict->values) & (a_all | a_executable);
    dict dnew;
    ref drto;
    int code;

    if (new_size < d_length(pdict)) {
        if (!mem->gs_lib_ctx->dict_auto_expand)
            return_error(gs_error_dictfull);
        new_size = d_length(pdict);
    }
    make_tav(&drto, t_dictionary, r_space(pdref) | a_all | new_mask,
             pdict, &dnew);
    dnew.memory = pdict->memory;
    if ((code = dict_create_contents(new_size, &drto, dict_is_packed(pdict))) < 0)
        return code;
    /*
     * We must suppress the store check, in case we are expanding
     * systemdict or another global dictionary that is allowed
     * to reference local objects.
     */
    r_set_space(&drto, avm_local);
    /*
     * If we are expanding a permanent dictionary, we must make sure that
     * dict_put doesn't think this is a second definition for any
     * single-definition names.  This in turn requires that
     * dstack_dict_is_permanent must be true for the second ("to")
     * argument of dict_copy_elements, which requires temporarily
     * setting *pdref = drto.
     */
    if (CAN_SET_PVALUE_CACHE(pds, pdref, mem)) {
        ref drfrom;

        drfrom = *pdref;
        *pdref = drto;
        dict_copy_elements(&drfrom, pdref, COPY_FOR_RESIZE, pds);
        *pdref = drfrom;
    } else {
        dict_copy_elements(pdref, &drto, 0, pds);
    }
    /* Save or free the old dictionary. */
    if (ref_must_save_in(mem, &pdict->values))
        ref_do_save_in(mem, pdref, &pdict->values, "dict_resize(values)");
    else
        gs_free_ref_array(mem, &pdict->values, "dict_resize(old values)");
    if (ref_must_save_in(mem, &pdict->keys))
        ref_do_save_in(mem, pdref, &pdict->keys, "dict_resize(keys)");
    else
        gs_free_ref_array(mem, &pdict->keys, "dict_resize(old keys)");
    ref_assign(&pdict->keys, &dnew.keys);
    ref_assign(&pdict->values, &dnew.values);
    r_store_attrs(&pdict->values, a_all | a_executable, orig_attrs);
    ref_save_in(dict_memory(pdict), pdref, &pdict->maxlength,
                "dict_resize(maxlength)");
    d_set_maxlength(pdict, new_size);
    if (pds)
        dstack_set_top(pds);	/* just in case this is the top dict */
    return 0;
}
Пример #7
0
/* Remove an element from a dictionary. */
int
dict_undef(ref * pdref, const ref * pkey, dict_stack_t *pds)
{
    gs_ref_memory_t *mem;
    ref *pvslot;
    dict *pdict;
    uint index;
    int code = dict_find(pdref, pkey, &pvslot);

    switch (code) {
    case 0:
    case gs_error_dictfull:
        return_error(gs_error_undefined);
    case 1:
        break;
    default:			/* other error */
        return code;
    }
    /* Remove the entry from the dictionary. */
    pdict = pdref->value.pdict;
    index = pvslot - pdict->values.value.refs;
    mem = dict_memory(pdict);
    if (dict_is_packed(pdict)) {
        ref_packed *pkp = pdict->keys.value.writable_packed + index;
        bool must_save = ref_must_save_in(mem, &pdict->keys);

        if_debug3m('d', (const gs_memory_t *)mem,
                   "[d]0x%lx: removing key at 0%lx: 0x%x\n",
                   (ulong)pdict, (ulong)pkp, (uint)*pkp);
        /* See the initial comment for why it is safe not to save */
        /* the change if the keys array itself is new. */
        if (must_save)
            ref_do_save_in(mem, &pdict->keys, pkp, "dict_undef(key)");
        /*
         * Accumulating deleted entries slows down lookup.
         * Detect the easy case where we can use an empty entry
         * rather than a deleted one, namely, when the next entry
         * in the probe order is empty.
         */
        if (pkp[-1] == packed_key_empty) {
            /*
             * In this case we can replace any preceding deleted keys with
             * empty ones as well.
             */
            uint end = nslots(pdict);

            *pkp = packed_key_empty;
            if (must_save) {
                while (++index < end && *++pkp == packed_key_deleted) {
                    ref_do_save_in(mem, &pdict->keys, pkp, "dict_undef(key)");
                    *pkp = packed_key_empty;
                }
            } else {
                while (++index < end && *++pkp == packed_key_deleted)
                    *pkp = packed_key_empty;
            }
        } else
            *pkp = packed_key_deleted;
    } else {			/* not packed */
        ref *kp = pdict->keys.value.refs + index;

        if_debug4m('d', (const gs_memory_t *)mem,
                   "[d]0x%lx: removing key at 0%lx: 0x%lx 0x%lx\n",
                   (ulong)pdict, (ulong)kp, ((ulong *)kp)[0], ((ulong *)kp)[1]);
        make_null_old_in(mem, &pdict->keys, kp, "dict_undef(key)");
        /*
         * Accumulating deleted entries slows down lookup.
         * Detect the easy case where we can use an empty entry
         * rather than a deleted one, namely, when the next entry
         * in the probe order is empty.
         */
        if (!r_has_type(kp - 1, t_null) ||	/* full entry */
            r_has_attr(kp - 1, a_executable)	/* deleted or wraparound */
            )
            r_set_attrs(kp, a_executable);	/* mark as deleted */
    }
    ref_save_in(mem, pdref, &pdict->count, "dict_undef(count)");
    pdict->count.value.intval--;
    /* If the key is a name, update its 1-element cache. */
    if (r_has_type(pkey, t_name)) {
        name *pname = pkey->value.pname;

        if (pv_valid(pname->pvalue)) {
#ifdef DEBUG
            /* Check the the cache is correct. */
            if (!(pds && dstack_dict_is_permanent(pds, pdref)))
                lprintf1("dict_undef: cached name value pointer 0x%lx is incorrect!\n",
                         (ulong) pname->pvalue);
#endif
            /* Clear the cache */
            pname->pvalue = pv_no_defn;
        }
    }
    make_null_old_in(mem, &pdict->values, pvslot, "dict_undef(value)");
    return 0;
}
Пример #8
0
/*
 * Enter a key-value pair in a dictionary.
 * See idict.h for the possible return values.
 */
int
dict_put(ref * pdref /* t_dictionary */ , const ref * pkey, const ref * pvalue,
         dict_stack_t *pds)
{
    dict *pdict = pdref->value.pdict;
    gs_ref_memory_t *mem = dict_memory(pdict);
    gs_memory_t *pmem = dict_mem(pdict);
    int rcode = 0;
    int code;
    ref *pvslot, kname;

    /* Check the value. */
    store_check_dest(pdref, pvalue);
  top:if ((code = dict_find(pdref, pkey, &pvslot)) <= 0) {	/* not found *//* Check for overflow */
        uint index;

        switch (code) {
            case 0:
                break;
            case gs_error_dictfull:
                if (!pmem->gs_lib_ctx->dict_auto_expand)
                    return_error(gs_error_dictfull);
                code = dict_grow(pdref, pds);
                if (code < 0)
                    return code;
                goto top;	/* keep things simple */
            default:		/* gs_error_typecheck */
                return code;
        }
        index = pvslot - pdict->values.value.refs;
        /* If the key is a string, convert it to a name. */
        if (r_has_type(pkey, t_string)) {
            int code;

            if (!r_has_attr(pkey, a_read))
                return_error(gs_error_invalidaccess);
            code = name_from_string(pmem, pkey, &kname);
            if (code < 0)
                return code;
            pkey = &kname;
        }
        if (dict_is_packed(pdict)) {
            ref_packed *kp;

            if (!r_has_type(pkey, t_name) ||
                name_index(pmem, pkey) > packed_name_max_index
                ) {		/* Change to unpacked representation. */
                int code = dict_unpack(pdref, pds);

                if (code < 0)
                    return code;
                goto top;
            }
            kp = pdict->keys.value.writable_packed + index;
            if (ref_must_save_in(mem, &pdict->keys)) {	/* See initial comment for why it is safe */
                /* not to save the change if the keys */
                /* array itself is new. */
                ref_do_save_in(mem, &pdict->keys, kp, "dict_put(key)");
            }
            *kp = pt_tag(pt_literal_name) + name_index(pmem, pkey);
        } else {
            ref *kp = pdict->keys.value.refs + index;

            if_debug2m('d', (const gs_memory_t *)mem, "[d]0x%lx: fill key at 0x%lx\n",
                       (ulong) pdict, (ulong) kp);
            store_check_dest(pdref, pkey);
            ref_assign_old_in(mem, &pdict->keys, kp, pkey,
                              "dict_put(key)");	/* set key of pair */
        }
        ref_save_in(mem, pdref, &pdict->count, "dict_put(count)");
        pdict->count.value.intval++;
        /* If the key is a name, update its 1-element cache. */
        if (r_has_type(pkey, t_name)) {
            name *pname = pkey->value.pname;

            if (pname->pvalue == pv_no_defn &&
                CAN_SET_PVALUE_CACHE(pds, pdref, mem)
                ) {		/* Set the cache. */
                if_debug0m('d', (const gs_memory_t *)mem, "[d]set cache\n");
                pname->pvalue = pvslot;
            } else {		/* The cache can't be used. */
                if_debug0m('d', (const gs_memory_t *)mem, "[d]no cache\n");
                pname->pvalue = pv_other;
            }
        }
        rcode = 1;
    }
    if_debug8m('d', (const gs_memory_t *)mem,
               "[d]0x%lx: put key 0x%lx 0x%lx\n  value at 0x%lx: old 0x%lx 0x%lx, new 0x%lx 0x%lx\n",
               (ulong) pdref->value.pdict,
               ((const ulong *)pkey)[0], ((const ulong *)pkey)[1],
               (ulong) pvslot,
               ((const ulong *)pvslot)[0], ((const ulong *)pvslot)[1],
               ((const ulong *)pvalue)[0], ((const ulong *)pvalue)[1]);
    ref_assign_old_in(mem, &pdref->value.pdict->values, pvslot, pvalue,
                      "dict_put(value)");
    return rcode;
}