/* 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, ©.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, ©.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; }