diff options
Diffstat (limited to 'gs/base/gsparam2.c')
-rw-r--r-- | gs/base/gsparam2.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/gs/base/gsparam2.c b/gs/base/gsparam2.c new file mode 100644 index 000000000..89817e410 --- /dev/null +++ b/gs/base/gsparam2.c @@ -0,0 +1,381 @@ +/* Copyright (C) 2001-2006 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ + or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, + San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + +/* $Id$ */ +/* Serialize and unserialize parameter lists */ + +/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */ +/* 8/8/98 L. Peter Deutsch (ghost@aladdin.com) Rewritten to use streams */ + +#include "gx.h" +#include "memory_.h" +#include "gserrors.h" +#include "gsparams.h" + +#define MAX_PARAM_KEY 255 + +/* ---------------- Serializer ---------------- */ + +/* Forward references */ +static int sput_word(stream *dest, uint value); +static int sput_bytes(stream *dest, const byte *data, uint size); + +/* + * Serialize the contents of a gs_param_list, including sub-dictionaries, + * onto a stream. The list must be in READ mode. + */ +int +gs_param_list_puts(stream *dest, gs_param_list *list) +{ + int code = 0; + gs_param_enumerator_t key_enum; + gs_param_key_t key; + + 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) + * word: # of elements + * byte[]: data associated with array contents + * (if string/name array) + * word: # of elements + * { word: length of string + * byte[]: string data + * } for each string in array + * (if dict/dict_int_keys/hetero_array) + * word: # of entries in collection + * entries follow immediately + */ + /* 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; + const void *data; + uint size; + + /* Get next datum & put its type & key to stream */ + gs_param_typed_value value; + char string_key[MAX_PARAM_KEY + 1]; + + 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) { + if (code > 0) + code = gs_note_error(gs_error_unknownerror); + break; + } + sput_word(dest, (unsigned)key.size + 1); + sput_word(dest, (unsigned)value.type); + sput_bytes(dest, (byte *)string_key, key.size + 1); + + /* Put value & its size to stream */ + 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_bool: + case gs_param_type_int: + case gs_param_type_long: + case gs_param_type_float: + sput_bytes(dest, (byte *)&value.value, value_top_sizeof); + case gs_param_type_null: + break; + + case gs_param_type_string: + data = value.value.s.data, size = value.value.s.size; + goto scalar_array; + case gs_param_type_name: + data = value.value.n.data, size = value.value.n.size; + goto scalar_array; + case gs_param_type_int_array: + data = value.value.ia.data, size = value.value.ia.size; + goto scalar_array; + case gs_param_type_float_array: + data = value.value.fa.data, size = value.value.fa.size; +scalar_array: sput_word(dest, size); + sput_bytes(dest, data, value_base_sizeof * size); + break; + + case gs_param_type_string_array: + data = value.value.sa.data, size = value.value.sa.size; + goto string_array; + case gs_param_type_name_array: + data = value.value.na.data, size = value.value.na.size; +string_array: sput_word(dest, size); + { + uint count; + const gs_param_string *sa; + + for (count = size, sa = data; count-- > 0; ++sa) { + sput_word(dest, sa->size); + sput_bytes(dest, sa->data, sa->size); + } + } + break; + + case gs_param_type_dict: + case gs_param_type_dict_int_keys: + case gs_param_type_array: + sput_word(dest, value.value.d.size); + code = gs_param_list_puts(dest, value.value.d.list); + { + int end_code = + param_end_read_dict(list, key.data, &value.value.d); + + if (code >= 0) + code = end_code; + } + break; + + default: + code = gs_note_error(gs_error_unknownerror); + break; + } + if (code < 0) + break; + } + + /* Write end marker, which is an (illegal) 0 key length */ + return (code < 0 ? code : sput_word(dest, 0)); +} + +/* Put a variable-length value on a stream. */ +static int +sput_word(stream *dest, uint value) +{ + int code = 0; + + do { + byte chunk = value & 0x7f; + + if ((value >>= 7) != 0) + chunk |= 0x80; + if ((code = sputc(dest, chunk)) < 0) + break; + } + while (value != 0); + return code; +} + +/* Put bytes on a stream. */ +static int +sput_bytes(stream *dest, const byte *data, uint size) +{ + uint ignore_count; + + return sputs(dest, data, size, &ignore_count); +} + +/* ---------------- Unserializer ---------------- */ + +/* Forward references */ +static int sget_word(stream *src, uint *pvalue); +static int sget_bytes(stream *src, byte *data, uint size); + +/* + * Unserialize a parameter list from a stream. The list must be in WRITE + * mode. + */ +int +gs_param_list_gets(stream *src, gs_param_list *list, gs_memory_t *mem) +{ + int code = 0; + + do { + gs_param_typed_value typed; + uint key_sizeof; + int value_top_sizeof; + int value_base_sizeof; + uint temp; + void *data; + uint size; + gs_param_type type; + char string_key[MAX_PARAM_KEY + 1]; + + /* key length 0 indicates end of data */ + if ((code = sget_word(src, &key_sizeof)) < 0 || + key_sizeof == 0 || + /* data type */ + (code = sget_word(src, &temp)) < 0) + break; + + if (key_sizeof > sizeof(string_key)) { + code = gs_note_error(gs_error_rangecheck); + break; + } + /* key */ + code = sget_bytes(src, (byte *)string_key, key_sizeof); + if (code < 0) + break; + + /* Data values */ + type = (gs_param_type)temp; + value_top_sizeof = gs_param_type_sizes[type]; + value_base_sizeof = gs_param_type_base_sizes[type]; + typed.type = type; + switch (type) { + case gs_param_type_bool: + case gs_param_type_int: + case gs_param_type_long: + case gs_param_type_float: + code = sget_bytes(src, (byte *)&typed.value, value_top_sizeof); + case gs_param_type_null: + goto put; + default: + ; + } + /* All other data values start with a size. */ + code = sget_word(src, &size); + if (code < 0) + break; + + switch (type) { + case gs_param_type_string: + case gs_param_type_name: + case gs_param_type_int_array: + case gs_param_type_float_array: + data = + (value_base_sizeof == 1 ? + gs_alloc_string(mem, size, "param string/name") : + gs_alloc_byte_array(mem, size, value_base_sizeof, + "param scalar array")); + if (data == 0) { + code = gs_note_error(gs_error_VMerror); + break; + } + typed.value.s.data = data; + typed.value.s.persistent = false; + typed.value.s.size = size; + code = sget_bytes(src, data, size * value_base_sizeof); + break; + + case gs_param_type_string_array: + case gs_param_type_name_array: + /****** SHOULD BE STRUCT ARRAY ******/ + data = gs_alloc_byte_array(mem, size, value_top_sizeof, + "param string/name array"); + if (data == 0) { + code = gs_note_error(gs_error_VMerror); + break; + } + typed.value.sa.data = data; + typed.value.sa.persistent = false; + typed.value.sa.size = size; + { + gs_param_string *sa = data; + byte *str_data; + uint index, str_size; + + /* Clean pointers in case we bail out. */ + for (index = 0; index < size; ++index) + sa[index].data = 0, sa[index].size = 0; + for (index = 0; index < size; ++index, ++sa) { + code = sget_word(src, &str_size); + if (code < 0) + break; + str_data = gs_alloc_string(mem, str_size, + "param string/name element"); + if (str_data == 0) { + code = gs_note_error(gs_error_VMerror); + break; + } + code = sget_bytes(src, str_data, str_size); + if (code < 0) + break; + } + } + break; + + case gs_param_type_dict: + case gs_param_type_dict_int_keys: + case gs_param_type_array: + typed.value.d.size = size; + code = param_begin_write_collection + (list, string_key, &typed.value.d, + type - gs_param_type_dict); + if (code < 0) + break; + code = gs_param_list_gets(src, typed.value.d.list, mem); + { + int end_code = + param_end_write_collection(list, string_key, + &typed.value.d); + + if (code >= 0) + code = end_code; + } + break; + + default: + code = gs_note_error(gs_error_unknownerror); + break; + } +put: if (code < 0) + break; + if (typed.type != gs_param_type_dict && + typed.type != gs_param_type_dict_int_keys && + typed.type != gs_param_type_array + ) + code = param_write_typed(list, string_key, &typed); + } + while (code >= 0); + + return code; +} + + +/* ---------- Utility functions -------- */ + +/* Get a value stored with sput_word */ +static int +sget_word(stream *src, uint *pvalue) +{ + uint value = 0; + int chunk; + uint shift = 0; + + do { + chunk = sgetc(src); + if (chunk < 0) + return chunk; + value |= (chunk & 0x7f) << shift; + shift += 7; + } + while (chunk & 0x80); + + *pvalue = value; + return 0; +} + +/* Get bytes from a stream */ +static int +sget_bytes(stream *src, byte *data, uint size) +{ + uint ignore_count; + + int status = sgets(src, data, size, &ignore_count); + + if (status < 0 && status != EOFC) + return_error(gs_error_ioerror); + }; + + return 0; +} |