Exemple #1
0
/* Copy one parameter list to another, recursively if necessary. */
int
param_list_copy(gs_param_list *plto, gs_param_list *plfrom)
{
    gs_param_enumerator_t key_enum;
    gs_param_key_t key;
    /*
     * If plfrom and plto use different allocators, we must copy
     * aggregate values even if they are "persistent".
     */
    bool copy_persists = plto->memory == plfrom->memory;
    int code;

    param_init_enumerator(&key_enum);
    while ((code = param_get_next_key(plfrom, &key_enum, &key)) == 0) {
	char string_key[256];	/* big enough for any reasonable key */
	gs_param_typed_value value;
	gs_param_collection_type_t coll_type;
	gs_param_typed_value copy;

	if (key.size > sizeof(string_key) - 1) {
	    code = gs_note_error(gs_error_rangecheck);
	    break;
	}
	memcpy(string_key, key.data, key.size);
	string_key[key.size] = 0;
	if ((code = param_read_typed(plfrom, string_key, &value)) != 0) {
	    code = (code > 0 ? gs_note_error(gs_error_unknownerror) : code);
	    break;
	}
	gs_param_list_set_persistent_keys(plto, key.persistent);
	switch (value.type) {
	case gs_param_type_dict:
	    coll_type = gs_param_collection_dict_any;
	    goto cc;
	case gs_param_type_dict_int_keys:
	    coll_type = gs_param_collection_dict_int_keys;
	    goto cc;
	case gs_param_type_array:
	    coll_type = gs_param_collection_array;
	cc:
	    copy.value.d.size = value.value.d.size;
	    if ((code = param_begin_write_collection(plto, string_key,
						     &copy.value.d,
						     coll_type)) < 0 ||
		(code = param_list_copy(copy.value.d.list,
					value.value.d.list)) < 0 ||
		(code = param_end_write_collection(plto, string_key,
						   &copy.value.d)) < 0)
		break;
	    code = param_end_read_collection(plfrom, string_key,
					     &value.value.d);
	    break;
	case gs_param_type_string:
	    value.value.s.persistent &= copy_persists; goto ca;
	case gs_param_type_name:
	    value.value.n.persistent &= copy_persists; goto ca;
	case gs_param_type_int_array:
	    value.value.ia.persistent &= copy_persists; goto ca;
	case gs_param_type_float_array:
	    value.value.fa.persistent &= copy_persists; goto ca;
	case gs_param_type_string_array:
	    value.value.sa.persistent &= copy_persists;
	ca:
	default:
	    code = param_write_typed(plto, string_key, &value);
	}
	if (code < 0)
	    break;
    }
    return code;
}
/* Serialize the contents of a gs_param_list (including sub-dicts) */
int				/* ret -ve err, else # bytes needed to represent param list, whether */

/* or not it actually fit into buffer. List was successully */

/* serialized only if if this # is <= supplied buf size. */
gs_param_list_serialize(
                           gs_param_list * list,	/* root of list to serialize */
                                        /* list MUST BE IN READ MODE */
                           byte * buf,	/* destination buffer (can be 0) */
                           int buf_sizeof	/* # bytes available in buf (can be 0) */
)
{
    int code = 0;
    int temp_code;
    gs_param_enumerator_t key_enum;
    gs_param_key_t key;
    WriteBuffer write_buf;

    write_buf.buf = buf;
    write_buf.buf_end = buf + (buf ? buf_sizeof : 0);
    write_buf.total_sizeof = 0;
    param_init_enumerator(&key_enum);

    /* Each item is serialized as ("word" means compressed word):
     *  word: key sizeof + 1, or 0 if end of list/dict
     *  word: data type(gs_param_type_xxx)
     *  byte[]: key, including trailing \0
     *  (if simple type)
     *   byte[]: unpacked representation of data
     *  (if simple array or string)
     *   byte[]: unpacked mem image of gs_param_xxx_array structure
     *   pad: to array alignment
     *   byte[]: data associated with array contents
     *  (if string/name array)
     *   byte[]: unpacked mem image of gs_param_string_array structure
     *   pad: to void *
     *   { gs_param_string structure mem image;
     *     data associated with string;
     *   } for each string in array
     *  (if dict/dict_int_keys)
     *   word: # of entries in dict,
     *   pad: to void *
     *   dict entries follow immediately until end-of-dict
     *
     * NB that this format is designed to allow using an input buffer
     * as the direct source of data when expanding a gs_c_param_list
     */
    /* Enumerate all the keys; use keys to get their typed values */
    while ((code = param_get_next_key(list, &key_enum, &key)) == 0) {
        int value_top_sizeof;
        int value_base_sizeof;

        /* Get next datum & put its type & key to buffer */
        gs_param_typed_value value;
        char string_key[256];

        if (sizeof(string_key) < key.size + 1) {
            code = gs_note_error(gs_error_rangecheck);
            break;
        }
        memcpy(string_key, key.data, key.size);
        string_key[key.size] = 0;
        if ((code = param_read_typed(list, string_key, &value)) != 0) {
            code = code > 0 ? gs_note_error(gs_error_unknownerror) : code;
            break;
        }
        wb_put_word((unsigned)key.size + 1, &write_buf);
        wb_put_word((unsigned)value.type, &write_buf);
        wb_put_bytes((byte *) string_key, key.size + 1, &write_buf);

        /* Put value & its size to buffer */
        value_top_sizeof = gs_param_type_sizes[value.type];
        value_base_sizeof = gs_param_type_base_sizes[value.type];
        switch (value.type) {
            case gs_param_type_null:
            case gs_param_type_bool:
            case gs_param_type_int:
            case gs_param_type_long:
            case gs_param_type_float:
                wb_put_bytes((byte *) & value.value, value_top_sizeof, &write_buf);
                break;

            case gs_param_type_string:
            case gs_param_type_name:
            case gs_param_type_int_array:
            case gs_param_type_float_array:
                wb_put_bytes((byte *) & value.value, value_top_sizeof, &write_buf);
                wb_put_alignment(value_base_sizeof, &write_buf);
                value_base_sizeof *= value.value.s.size;
                wb_put_bytes(value.value.s.data, value_base_sizeof, &write_buf);
                break;

            case gs_param_type_string_array:
            case gs_param_type_name_array:
                value_base_sizeof *= value.value.sa.size;
                wb_put_bytes((const byte *)&value.value, value_top_sizeof, &write_buf);
                wb_put_alignment(sizeof(void *), &write_buf);

                wb_put_bytes((const byte *)value.value.sa.data, value_base_sizeof,
                          &write_buf);
                {
                    int str_count;
                    const gs_param_string *sa;

                    for (str_count = value.value.sa.size,
                         sa = value.value.sa.data; str_count-- > 0; ++sa)
                        wb_put_bytes(sa->data, sa->size, &write_buf);
                }
                break;

            case gs_param_type_dict:
            case gs_param_type_dict_int_keys:
                wb_put_word(value.value.d.size, &write_buf);
                wb_put_alignment(sizeof(void *), &write_buf);

                {
                    int bytes_written =
                    gs_param_list_serialize(value.value.d.list,
                                            write_buf.buf,
                     write_buf.buf ? write_buf.buf_end - write_buf.buf : 0);

                    temp_code = param_end_read_dict(list,
                                                    (const char *)key.data,
                                                    &value.value.d);
                    if (bytes_written < 0)
                        code = bytes_written;
                    else {
                        code = temp_code;
                        if (bytes_written)
                            wb_put_bytes(write_buf.buf, bytes_written, &write_buf);
                    }
                }
                break;

            default:
                code = gs_note_error(gs_error_unknownerror);
                break;
        }
        if (code < 0)
            break;
    }

    /* Write end marker, which is an (illegal) 0 key length */
    if (code >= 0) {
        wb_put_word(0, &write_buf);
        code = write_buf.total_sizeof;
    }
    return code;
}