Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1995, 2000 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: gscparam.c,v 1.10 2004/08/04 19:36:12 stefan Exp $ */
18
/* Default implementation of parameter lists */
19
#include "memory_.h"
20
#include "string_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gsparam.h"
24
#include "gsstruct.h"
25
 
26
/* Forward references */
27
typedef union c_param_value_s {
28
    GS_PARAM_VALUE_UNION(gs_c_param_list);
29
} gs_c_param_value;
30
/*typedef struct gs_c_param_s gs_c_param; *//* in gsparam.h */
31
 
32
/* Define the GC type for a parameter list. */
33
private_st_c_param_list();
34
 
35
/* Lengths corresponding to various gs_param_type_xxx types */
36
const byte gs_param_type_sizes[] = {
37
    GS_PARAM_TYPE_SIZES(sizeof(gs_c_param_list))
38
};
39
 
40
/* Lengths of *actual* data-containing type pointed to or contained by gs_param_type_xxx's */
41
const byte gs_param_type_base_sizes[] = {
42
    GS_PARAM_TYPE_BASE_SIZES(0)
43
};
44
 
45
/*
46
 * Define a parameter list element.  We use gs_param_type_any to identify
47
 * elements that have been requested but not yet written.  The reading
48
 * procedures must recognize such elements as undefined, and ignore them.
49
 */
50
struct gs_c_param_s {
51
    gs_c_param *next;
52
    gs_param_key_t key;
53
    bool free_key;
54
    gs_c_param_value value;
55
    gs_param_type type;
56
    void *alternate_typed_data;
57
};
58
 
59
/* GC descriptor and procedures */
60
gs_private_st_composite(st_c_param, gs_c_param, "gs_c_param",
61
			c_param_enum_ptrs, c_param_reloc_ptrs);
62
ENUM_PTRS_WITH(c_param_enum_ptrs, gs_c_param *param) {
63
    index -= 3;
64
    switch (param->type) {
65
	/* Only the aggregate types are handled specially. */
66
    case gs_param_type_dict:
67
    case gs_param_type_dict_int_keys:
68
    case gs_param_type_array:
69
	return ENUM_USING(st_c_param_list, &param->value.d,
70
			  sizeof(param->value.d), index);
71
    default: {
72
	gs_param_typed_value value;
73
 
74
	value.value = *(const gs_param_value *)&param->value;
75
	value.type = param->type;
76
	return gs_param_typed_value_enum_ptrs(mem, &value, sizeof(value), index,
77
					      pep, NULL, gcst);
78
    }
79
    }
80
}
81
case 0: return ENUM_OBJ(param->next);
82
case 1: return ENUM_OBJ(param->alternate_typed_data);
83
case 2:
84
    if (!param->key.persistent) {
85
	gs_const_string key;
86
 
87
	key.data = param->key.data;
88
	key.size = param->key.size;
89
	return ENUM_STRING(&key);
90
    } else
91
	return ENUM_OBJ(0);	/* keep going */
92
ENUM_PTRS_END
93
RELOC_PTRS_WITH(c_param_reloc_ptrs, gs_c_param *param) {
94
    RELOC_VAR(param->next);
95
    RELOC_VAR(param->alternate_typed_data);
96
    if (!param->key.persistent) {
97
	gs_const_string key;
98
 
99
	key.data = param->key.data;
100
	key.size = param->key.size;
101
	RELOC_CONST_STRING_VAR(key);
102
	param->key.data = key.data;
103
    }
104
    switch (param->type) {
105
	/* Only the aggregate types are handled specially. */
106
    case gs_param_type_dict:
107
    case gs_param_type_dict_int_keys:
108
    case gs_param_type_array:
109
	RELOC_USING(st_c_param_list, &param->value.d, sizeof(param->value.d));
110
	break;
111
    default: {
112
	gs_param_typed_value value;
113
 
114
	value.value = *(gs_param_value *)&param->value;
115
	value.type = param->type;
116
	gs_param_typed_value_reloc_ptrs(&value, sizeof(value), NULL, gcst);
117
	*(gs_param_value *)&param->value = value.value;
118
    }
119
    }
120
}
121
RELOC_PTRS_END
122
 
123
/* ---------------- Utilities ---------------- */
124
 
125
gs_c_param_list *
126
gs_c_param_list_alloc(gs_memory_t *mem, client_name_t cname)
127
{
128
    return gs_alloc_struct(mem, gs_c_param_list, &st_c_param_list, cname);
129
}
130
 
131
private gs_c_param *
132
c_param_find(const gs_c_param_list *plist, gs_param_name pkey, bool any)
133
{
134
    gs_c_param *pparam = plist->head;
135
    uint len = strlen(pkey);
136
 
137
    for (; pparam != 0; pparam = pparam->next)
138
	if (pparam->key.size == len && !memcmp(pparam->key.data, pkey, len))
139
	    return (pparam->type != gs_param_type_any || any ? pparam : 0);
140
    return 0;
141
}
142
 
143
/* ---------------- Writing parameters to a list ---------------- */
144
 
145
private param_proc_begin_xmit_collection(c_param_begin_write_collection);
146
private param_proc_end_xmit_collection(c_param_end_write_collection);
147
private param_proc_xmit_typed(c_param_write_typed);
148
private param_proc_request(c_param_request);
149
private param_proc_requested(c_param_requested);
150
private const gs_param_list_procs c_write_procs =
151
{
152
    c_param_write_typed,
153
    c_param_begin_write_collection,
154
    c_param_end_write_collection,
155
    NULL,			/* get_next_key */
156
    c_param_request,
157
    c_param_requested
158
};
159
 
160
/* Initialize a list for writing. */
161
void
162
gs_c_param_list_write(gs_c_param_list * plist, gs_memory_t * mem)
163
{
164
    plist->memory = mem;
165
    plist->head = 0;
166
    plist->target = 0;		/* not used for writing */
167
    plist->count = 0;
168
    plist->any_requested = false;
169
    plist->persistent_keys = true;
170
    gs_c_param_list_write_more(plist);
171
}
172
 
173
/* Set the target of a list.  Only relevant for reading. */
174
void
175
gs_c_param_list_set_target(gs_c_param_list *plist, gs_param_list *target)
176
{
177
    plist->target = target;
178
}
179
 
180
/* Re-enable a list for writing, without clearing it. */
181
/* gs_c_param_list_write must have been called previously. */
182
void
183
gs_c_param_list_write_more(gs_c_param_list * plist)
184
{
185
    plist->procs = &c_write_procs;
186
    plist->coll_type = gs_param_collection_dict_any;
187
}
188
 
189
/* Release a list. */
190
void
191
gs_c_param_list_release(gs_c_param_list * plist)
192
{
193
    gs_memory_t *mem = plist->memory;
194
    gs_c_param *pparam;
195
 
196
    while ((pparam = plist->head) != 0) {
197
	gs_c_param *next = pparam->next;
198
 
199
	switch (pparam->type) {
200
	    case gs_param_type_dict:
201
	    case gs_param_type_dict_int_keys:
202
	    case gs_param_type_array:
203
		gs_c_param_list_release(&pparam->value.d);
204
		break;
205
	    case gs_param_type_string:
206
	    case gs_param_type_name:
207
	    case gs_param_type_int_array:
208
	    case gs_param_type_float_array:
209
	    case gs_param_type_string_array:
210
	    case gs_param_type_name_array:
211
		if (!pparam->value.s.persistent)
212
		    gs_free_const_object(mem, pparam->value.s.data,
213
					 "gs_c_param_list_release data");
214
		break;
215
	    default:
216
		break;
217
	}
218
	if (pparam->free_key) {
219
	    /* We allocated this, so we must free it. */
220
	    gs_free_const_string(mem, pparam->key.data, pparam->key.size,
221
				 "gs_c_param_list_release key");
222
	}
223
	gs_free_object(mem, pparam->alternate_typed_data,
224
		       "gs_c_param_list_release alternate data");
225
	gs_free_object(mem, pparam,
226
		       "gs_c_param_list_release entry");
227
	plist->head = next;
228
	plist->count--;
229
    }
230
}
231
 
232
/* Add an entry to a list.  Doesn't set: value, type, plist->head. */
233
private gs_c_param *
234
c_param_add(gs_c_param_list * plist, gs_param_name pkey)
235
{
236
    gs_c_param *pparam =
237
	gs_alloc_struct(plist->memory, gs_c_param, &st_c_param,
238
			"c_param_add entry");
239
    uint len = strlen(pkey);
240
 
241
    if (pparam == 0)
242
	return 0;
243
    pparam->next = plist->head;
244
    if (!plist->persistent_keys) {
245
	/* We must copy the key. */
246
	byte *str = gs_alloc_string(plist->memory, len, "c_param_add key");
247
 
248
	if (str == 0) {
249
	    gs_free_object(plist->memory, pparam, "c_param_add entry");
250
	    return 0;
251
	}
252
	memcpy(str, pkey, len);
253
	pparam->key.data = str;
254
	pparam->key.persistent = false; /* we will free it */
255
	pparam->free_key = true;
256
    } else {
257
	pparam->key.data = (const byte *)pkey;
258
	pparam->key.persistent = true;
259
	pparam->free_key = false;
260
    }
261
    pparam->key.size = len;
262
    pparam->alternate_typed_data = 0;
263
    return pparam;
264
}
265
 
266
/*  Write a dynamically typed parameter to a list. */
267
private int
268
c_param_write(gs_c_param_list * plist, gs_param_name pkey, void *pvalue,
269
	      gs_param_type type)
270
{
271
    unsigned top_level_sizeof = 0;
272
    unsigned second_level_sizeof = 0;
273
    gs_c_param *pparam = c_param_add(plist, pkey);
274
 
275
    if (pparam == 0)
276
	return_error(gs_error_VMerror);
277
    memcpy(&pparam->value, pvalue, gs_param_type_sizes[(int)type]);
278
    pparam->type = type;
279
 
280
    /* Need deeper copies of data if it's not persistent */
281
    switch (type) {
282
	    gs_param_string const *curr_string;
283
	    gs_param_string const *end_string;
284
 
285
	case gs_param_type_string_array:
286
	case gs_param_type_name_array:
287
	    /* Determine how much mem needed to hold actual string data */
288
	    curr_string = pparam->value.sa.data;
289
	    end_string = curr_string + pparam->value.sa.size;
290
	    for (; curr_string < end_string; ++curr_string)
291
		if (!curr_string->persistent)
292
		    second_level_sizeof += curr_string->size;
293
	    /* fall thru */
294
 
295
	case gs_param_type_string:
296
	case gs_param_type_name:
297
	case gs_param_type_int_array:
298
	case gs_param_type_float_array:
299
	    if (!pparam->value.s.persistent) {	/* Allocate & copy object pointed to by array or string */
300
		byte *top_level_memory = NULL;
301
 
302
		top_level_sizeof =
303
		    pparam->value.s.size * gs_param_type_base_sizes[type];
304
		if (top_level_sizeof + second_level_sizeof > 0) {
305
		    top_level_memory =
306
			gs_alloc_bytes_immovable(plist->memory,
307
				     top_level_sizeof + second_level_sizeof,
308
					     "c_param_write data");
309
		    if (top_level_memory == 0) {
310
			gs_free_object(plist->memory, pparam, "c_param_write entry");
311
			return_error(gs_error_VMerror);
312
		    }
313
		    memcpy(top_level_memory, pparam->value.s.data, top_level_sizeof);
314
		}
315
		pparam->value.s.data = top_level_memory;
316
 
317
		/* String/name arrays need to copy actual str data */
318
 
319
		if (second_level_sizeof > 0) {
320
		    byte *second_level_memory =
321
		    top_level_memory + top_level_sizeof;
322
 
323
		    curr_string = pparam->value.sa.data;
324
		    end_string = curr_string + pparam->value.sa.size;
325
		    for (; curr_string < end_string; ++curr_string)
326
			if (!curr_string->persistent) {
327
			    memcpy(second_level_memory,
328
				   curr_string->data, curr_string->size);
329
			    ((gs_param_string *) curr_string)->data
330
				= second_level_memory;
331
			    second_level_memory += curr_string->size;
332
			}
333
		}
334
	    }
335
	    break;
336
	default:
337
	    break;
338
    }
339
 
340
    plist->head = pparam;
341
    plist->count++;
342
    return 0;
343
}
344
 
345
/* Individual writing routines. */
346
private int
347
c_param_begin_write_collection(gs_param_list * plist, gs_param_name pkey,
348
	       gs_param_dict * pvalue, gs_param_collection_type_t coll_type)
349
{
350
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
351
    gs_c_param_list *dlist =
352
	gs_c_param_list_alloc(cplist->memory,
353
			      "c_param_begin_write_collection");
354
 
355
    if (dlist == 0)
356
	return_error(gs_error_VMerror);
357
    gs_c_param_list_write(dlist, cplist->memory);
358
    dlist->coll_type = coll_type;
359
    pvalue->list = (gs_param_list *) dlist;
360
    return 0;
361
}
362
private int
363
c_param_end_write_collection(gs_param_list * plist, gs_param_name pkey,
364
			     gs_param_dict * pvalue)
365
{
366
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
367
    gs_c_param_list *dlist = (gs_c_param_list *) pvalue->list;
368
 
369
    return c_param_write(cplist, pkey, pvalue->list,
370
		    (dlist->coll_type == gs_param_collection_dict_int_keys ?
371
		     gs_param_type_dict_int_keys :
372
		     dlist->coll_type == gs_param_collection_array ?
373
		     gs_param_type_array : gs_param_type_dict));
374
}
375
private int
376
c_param_write_typed(gs_param_list * plist, gs_param_name pkey,
377
		    gs_param_typed_value * pvalue)
378
{
379
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
380
    gs_param_collection_type_t coll_type;
381
 
382
    switch (pvalue->type) {
383
	case gs_param_type_dict:
384
	    coll_type = gs_param_collection_dict_any;
385
	    break;
386
	case gs_param_type_dict_int_keys:
387
	    coll_type = gs_param_collection_dict_int_keys;
388
	    break;
389
	case gs_param_type_array:
390
	    coll_type = gs_param_collection_array;
391
	    break;
392
	default:
393
	    return c_param_write(cplist, pkey, &pvalue->value, pvalue->type);
394
    }
395
    return c_param_begin_write_collection
396
	(plist, pkey, &pvalue->value.d, coll_type);
397
}
398
 
399
/* Other procedures */
400
 
401
private int
402
c_param_request(gs_param_list * plist, gs_param_name pkey)
403
{
404
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
405
    gs_c_param *pparam;
406
 
407
    cplist->any_requested = true;
408
    if (c_param_find(cplist, pkey, true))
409
	return 0;
410
    pparam = c_param_add(cplist, pkey);
411
    if (pparam == 0)
412
	return_error(gs_error_VMerror);
413
    pparam->type = gs_param_type_any; /* mark as undefined */
414
    cplist->head = pparam;
415
    return 0;
416
}
417
 
418
private int
419
c_param_requested(const gs_param_list * plist, gs_param_name pkey)
420
{
421
    const gs_c_param_list *const cplist = (const gs_c_param_list *)plist;
422
    gs_param_list *target = cplist->target;
423
    int code;
424
 
425
    if (!cplist->any_requested)
426
	return (target ? param_requested(target, pkey) : -1);
427
    if (c_param_find(cplist, pkey, true) != 0)
428
	return 1;
429
    if (!target)
430
	return 0;
431
    code = param_requested(target, pkey);
432
    return (code < 0 ? 0 : 1);
433
}
434
 
435
/* ---------------- Reading from a list to parameters ---------------- */
436
 
437
private param_proc_begin_xmit_collection(c_param_begin_read_collection);
438
private param_proc_end_xmit_collection(c_param_end_read_collection);
439
private param_proc_xmit_typed(c_param_read_typed);
440
private param_proc_next_key(c_param_get_next_key);
441
private param_proc_get_policy(c_param_read_get_policy);
442
private param_proc_signal_error(c_param_read_signal_error);
443
private param_proc_commit(c_param_read_commit);
444
private const gs_param_list_procs c_read_procs =
445
{
446
    c_param_read_typed,
447
    c_param_begin_read_collection,
448
    c_param_end_read_collection,
449
    c_param_get_next_key,
450
    NULL,			/* request, N/A */
451
    NULL,			/* requested, N/A */
452
    c_param_read_get_policy,
453
    c_param_read_signal_error,
454
    c_param_read_commit
455
};
456
 
457
/* Switch a list from writing to reading. */
458
void
459
gs_c_param_list_read(gs_c_param_list * plist)
460
{
461
    plist->procs = &c_read_procs;
462
}
463
 
464
/* Generic routine for reading a parameter from a list. */
465
 
466
private int
467
c_param_read_typed(gs_param_list * plist, gs_param_name pkey,
468
		   gs_param_typed_value * pvalue)
469
{
470
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
471
    gs_param_type req_type = pvalue->type;
472
    gs_c_param *pparam = c_param_find(cplist, pkey, false);
473
    int code;
474
 
475
    if (pparam == 0)
476
	return (cplist->target ?
477
		param_read_typed(cplist->target, pkey, pvalue) : 1);
478
    pvalue->type = pparam->type;
479
    switch (pvalue->type) {
480
	case gs_param_type_dict:
481
	case gs_param_type_dict_int_keys:
482
	case gs_param_type_array:
483
	    gs_c_param_list_read(&pparam->value.d);
484
	    pvalue->value.d.list = (gs_param_list *) & pparam->value.d;
485
	    pvalue->value.d.size = pparam->value.d.count;
486
	    return 0;
487
	default:
488
	    break;
489
    }
490
    memcpy(&pvalue->value, &pparam->value,
491
	   gs_param_type_sizes[(int)pparam->type]);
492
    code = param_coerce_typed(pvalue, req_type, NULL);
493
/****** SHOULD LET param_coerce_typed DO THIS ******/
494
    if (code == gs_error_typecheck &&
495
	req_type == gs_param_type_float_array &&
496
	pvalue->type == gs_param_type_int_array
497
	) {
498
	/* Convert int array to float dest */
499
	gs_param_float_array fa;
500
	int element;
501
 
502
	fa.size = pparam->value.ia.size;
503
	fa.persistent = false;
504
 
505
	if (pparam->alternate_typed_data == 0) {
506
	    if ((pparam->alternate_typed_data
507
		 = (void *)gs_alloc_bytes_immovable(cplist->memory,
508
						    fa.size * sizeof(float),
509
			     "gs_c_param_read alternate float array")) == 0)
510
		      return_error(gs_error_VMerror);
511
 
512
	    for (element = 0; element < fa.size; ++element)
513
		((float *)(pparam->alternate_typed_data))[element]
514
		    = (float)pparam->value.ia.data[element];
515
	}
516
	fa.data = (float *)pparam->alternate_typed_data;
517
 
518
	pvalue->value.fa = fa;
519
	return 0;
520
    }
521
    return code;
522
}
523
 
524
/* Individual reading routines. */
525
private int
526
c_param_begin_read_collection(gs_param_list * plist, gs_param_name pkey,
527
	       gs_param_dict * pvalue, gs_param_collection_type_t coll_type)
528
{
529
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
530
    gs_c_param *pparam = c_param_find(cplist, pkey, false);
531
 
532
    if (pparam == 0)
533
	return
534
	    (cplist->target ?
535
	     param_begin_read_collection(cplist->target,
536
					 pkey, pvalue, coll_type) :
537
	     1);
538
    switch (pparam->type) {
539
	case gs_param_type_dict:
540
	    if (coll_type != gs_param_collection_dict_any)
541
		return_error(gs_error_typecheck);
542
	    break;
543
	case gs_param_type_dict_int_keys:
544
	    if (coll_type == gs_param_collection_array)
545
		return_error(gs_error_typecheck);
546
	    break;
547
	case gs_param_type_array:
548
	    break;
549
	default:
550
	    return_error(gs_error_typecheck);
551
    }
552
    gs_c_param_list_read(&pparam->value.d);
553
    pvalue->list = (gs_param_list *) & pparam->value.d;
554
    pvalue->size = pparam->value.d.count;
555
    return 0;
556
}
557
private int
558
c_param_end_read_collection(gs_param_list * plist, gs_param_name pkey,
559
			    gs_param_dict * pvalue)
560
{
561
    return 0;
562
}
563
 
564
/* Other procedures */
565
private int			/* ret 0 ok, 1 if EOF, or -ve err */
566
c_param_get_next_key(gs_param_list * plist, gs_param_enumerator_t * penum,
567
		     gs_param_key_t * key)
568
{
569
    gs_c_param_list *const cplist = (gs_c_param_list *)plist;
570
    gs_c_param *pparam =
571
    (penum->pvoid ? ((gs_c_param *) (penum->pvoid))->next :
572
     cplist->head);
573
 
574
    if (pparam == 0)
575
	return 1;
576
    penum->pvoid = pparam;
577
    *key = pparam->key;
578
    return 0;
579
}
580
private int
581
c_param_read_get_policy(gs_param_list * plist, gs_param_name pkey)
582
{
583
    return gs_param_policy_ignore;
584
}
585
private int
586
c_param_read_signal_error(gs_param_list * plist, gs_param_name pkey, int code)
587
{
588
    return code;
589
}
590
private int
591
c_param_read_commit(gs_param_list * plist)
592
{
593
    return 0;
594
}