Coverage Report

Created: 2025-06-10 07:17

/src/ghostpdl/base/gsparaml.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* gsparaml.c -  Handling of reading lists of params from strings */
18
19
#include <stdlib.h>
20
#include "gsparam.h"
21
#include "gserrors.h"
22
#include "string_.h"
23
24
static int
25
add_tokens(gs_param_list *plist, gs_param_name key, char **pp, uint *dict_count);
26
27
static int
28
walk_number(char **p, bool *is_integer)
29
0
{
30
0
    char *p1 = *p;
31
0
    bool integer = true;
32
33
0
    if (*p1 == '+')
34
0
        p1++;
35
0
    while (*p1 == ' ')
36
0
        p1++;
37
0
    while (*p1 == '-')
38
0
        p1++;
39
0
    while (*p1 == ' ')
40
0
        p1++;
41
0
    if (*p1 == 0 || ((*p1 < '0' || *p1 > '9') && (*p1 != '.')))
42
0
        return -1;
43
0
    while ((*p1 >= '0' && *p1 <= '9') || *p1 == '.') {
44
0
        if (*p1 == '.') {
45
0
            if (!integer) /* Can't cope with multiple .'s */
46
0
                return -1;
47
0
            integer = false;
48
0
        }
49
50
0
        p1++;
51
0
    }
52
    /* Allow for exponent form. */
53
0
    if (*p1 == 'e' || *p1 == 'E') {
54
0
        p1++;
55
0
        if (*p1 == '-')
56
0
            p1++;
57
0
        if (*p1 < '0' || *p1 > '9')
58
0
            return -1;
59
0
        while (*p1 >= '0' && *p1 <= '9')
60
0
            p1++;
61
0
    }
62
63
0
    *is_integer = integer;
64
0
    *p = p1;
65
66
0
    return 0;
67
0
}
68
69
/* Delimiter chars, as taken from pdf spec. Any of these characters
70
 * ends a token. */
71
static int
72
ends_token(const char *p)
73
0
{
74
0
    return (*p == 0 ||
75
0
            *p == 9 ||
76
0
            *p == 10 ||
77
0
            *p == 12 ||
78
0
            *p == 13 ||
79
0
            *p == 32 ||
80
0
            *p == '/' ||
81
0
            *p == '%' ||
82
0
            *p == '<' || *p == '>' ||
83
0
            *p == '[' || *p == ']' ||
84
0
            *p == '{' || *p == '}' ||
85
0
            *p == '(' || *p == ')');
86
0
}
87
88
/* Dictionaries are surprisingly easy, we just make a param_dict
89
 * and then call the existing routine to parse the string and
90
 * add tokens to the parameter list contained in the dictionary.
91
 */
92
static int
93
process_dict(gs_memory_t *mem, gs_c_param_list *plist, gs_param_name key, char **p)
94
0
{
95
0
    gs_param_dict dict;
96
0
    int code, code2;
97
98
    /* We are implicitly relying on that fact that we're working to
99
     * C param lists, not ref param lists here, as C param lists don't
100
     * need the size up front, but ref param lists do. This makes the
101
     * recursion MUCH simpler. */
102
0
    code = param_begin_write_dict((gs_param_list *)plist, key, &dict, false);
103
0
    if (code < 0)
104
0
        return code;
105
106
0
    gs_param_list_set_persistent_keys(dict.list, false);
107
108
0
    dict.size = 0;
109
0
    code = add_tokens(dict.list, NULL, p, &dict.size);
110
0
    if (code >= 0) {
111
0
        if ((*p)[0] != '>' || (*p)[1] != '>')
112
0
            code = gs_error_syntaxerror;
113
0
        else
114
0
           (*p) += 2;
115
0
    }
116
0
    code2 = param_end_write_dict((gs_param_list *)plist, key, &dict);
117
0
    return code < 0 ? code : code2;
118
0
}
119
120
static int
121
process_dict_or_hexstring(gs_memory_t *mem, gs_c_param_list *plist, gs_param_name key, char **p)
122
0
{
123
0
    char *p1 = *p, *src, *dest, data;
124
0
    int i;
125
0
    gs_param_string ps;
126
127
0
    if (p1[1] == '<') {
128
0
        *p += 2;
129
0
        return process_dict(mem, plist, key, p);
130
0
    }
131
132
0
    dest = p1;
133
0
    src = p1+1;
134
0
    while (*src && *src != '>') {
135
0
        data = 0;
136
0
        for (i=0;i<2;i++) {
137
0
            if (*src >= '0' && *src <= '9') {
138
0
                data = (data << 4);
139
0
                data += (*src - '0');
140
0
            } else if (*src >= 'A' && *src <= 'F') {
141
0
                data = (data << 4);
142
0
                data += (*src - 'A' + 10);
143
0
            } else if (*src >= 'a' && *src <= 'f') {
144
0
                data = (data << 4);
145
0
                data += (*src - 'a' + 10);
146
0
            } else {
147
0
                return -1;
148
0
            }
149
0
            src++;
150
0
        }
151
0
        *dest++ = data;
152
0
    }
153
154
0
    if (*src == 0)
155
0
        return -1;
156
157
0
    *p = src + 1;
158
159
0
    ps.data = (const byte *)p1;
160
0
    ps.size = dest - p1;
161
0
    ps.persistent = false;
162
0
    return param_write_string((gs_param_list *)plist, key, &ps);
163
0
}
164
165
/* On entry, p points to the '/'. Because we need to null terminate
166
 * to cope with reading the key of key/value pairs, we move all the
167
 * chars back by 1, overwriting the '/' to give us room. This avoids
168
 * us relying on trailing whitespace. */
169
static int
170
process_name(gs_memory_t *mem, gs_c_param_list *plist, gs_param_name *key, char **p)
171
0
{
172
0
    char *out = *p;
173
0
    char *in = *p + 1;
174
0
    char *start = out;
175
0
    gs_param_string ps;
176
177
0
    while (!ends_token(in)) {
178
0
        if (*in == '#') {
179
0
            int v;
180
0
            if (in[1] >= '0' && in[1] <= '9')
181
0
                v = (in[1] - '0')<<4;
182
0
            else if (in[1] >= 'a' && in[1] <= 'f')
183
0
                v = (in[1] - 'a' + 10)<<4;
184
0
            else if (in[1] >= 'A' && in[1] <= 'F')
185
0
                v = (in[1] - 'a' + 10)<<4;
186
0
            else
187
0
                return -1;
188
0
            if (in[2] >= '0' && in[2] <= '9')
189
0
                v += (in[2] - '0');
190
0
            else if (in[2] >= 'a' && in[2] <= 'f')
191
0
                v += (in[2] - 'a' + 10);
192
0
            else if (in[2] >= 'A' && in[2] <= 'F')
193
0
                v += (in[2] - 'a' + 10);
194
0
            else
195
0
                return -1;
196
0
            if (v == 0)
197
0
                return -1;
198
0
            *out++ = v;
199
0
            in += 3;
200
0
            continue;
201
0
        }
202
0
        *out++ = *in++;
203
0
    }
204
205
    /* Null terminate (in case it's the '*key = NULL' case below) */
206
0
    *out = 0;
207
0
    *p = in;
208
209
0
    if (*key == NULL)
210
0
        *key = (gs_param_name)start;
211
0
    else {
212
0
        ps.data = (const byte *)start;
213
0
        ps.size = out - start;
214
0
        ps.persistent = false;
215
0
        param_write_name((gs_param_list *)plist, *key, &ps);
216
0
        *key = NULL;
217
0
    }
218
0
    return 0;
219
0
}
220
221
static int
222
process_string(gs_memory_t *mem, gs_c_param_list *plist, gs_param_name key, char **p)
223
0
{
224
0
    char *p1 = *p;
225
0
    char *start = p1 + 1;
226
0
    gs_param_string ps;
227
228
0
    while (*p1 && *p1 != ')')
229
0
        p1++;
230
231
0
    if (*p1 == 0)
232
0
        return -1;
233
234
0
    *p = p1 + 1; /* Resume after the ')' */
235
236
0
    ps.data = (const byte *)start;
237
0
    ps.size = p1-start;
238
0
    ps.persistent = false;
239
0
    return param_write_string((gs_param_list *)plist, key, &ps);
240
0
}
241
242
/* Arrays are *way* more complicated than dicts :-(
243
 * We have 4 different kinds of arrays; name, string, int and float.
244
 * It seems that parameter arrays can only contain homogenous data, it
245
 * all has to be of the same type. This complicates matters because we
246
 * can't know in advance what the type is!
247
 *
248
 * So we only handle 3 types of array; int, float and string. Anything
249
 * which isn't one of those either gets converted to a string or (arrays
250
 * and dictionaries) throws an error.
251
 *
252
 * For numbers, we look at the first element, if it's an integer we make
253
 * an int array, otherwise we make a float array. If we start an int array
254
 * and later encounter a float, we make a new float array, copy the existing
255
 * integers into it (converting to floats) and throw away the old int array.
256
 *
257
 * Otherwise if we encounter an object whose type doesn't match the array we
258
 * created we throw an error.
259
 */
260
static int
261
process_array(gs_memory_t *mem, gs_c_param_list *plist, gs_param_name key, char **p)
262
0
{
263
0
    int code = 0;
264
0
    gs_param_type array_type = gs_param_type_null;
265
0
    int index = 0, array_max = 0;
266
0
    char *start = *p + 1, *p1 = start;
267
0
    gs_param_string *parray = 0L;
268
0
    char *array_data = 0x00;
269
0
    gs_param_string_array string_array;
270
0
    gs_param_int_array int_array;
271
0
    gs_param_float_array float_array;
272
273
0
    p1 = start;
274
275
0
    while (*p1 != ']' && code == 0) {
276
0
        switch (*p1) {
277
0
            case ' ':
278
0
                p1++;
279
0
                break;
280
281
            /* We used to parse 'false' and 'true' here, but they ended
282
             * up as string params, rather that bools, thus making
283
             * [ false ] and [ (false) ] parse to the be the same thing.
284
             * That feels wrong, so we've removed the code until param
285
             * lists actually support arrays of bools. */
286
287
0
            case '<':
288
0
                if (array_type != gs_param_type_null && array_type != gs_param_type_string_array) {
289
0
                    code = gs_error_typecheck;
290
0
                    break;
291
0
                }
292
0
                if (index == array_max) {
293
0
                    int new_max = array_max * 2;
294
0
                    if (new_max == 0)
295
0
                        new_max = 32;
296
0
                    if (array_data == NULL) {
297
0
                        array_data = (char *)gs_alloc_bytes(mem, sizeof(gs_param_string) * new_max, "param string array in param parsing");
298
0
                        if (array_data == NULL) {
299
0
                            code = gs_error_VMerror;
300
0
                            break;
301
0
                        }
302
0
                    } else {
303
0
                        char *new_array = (char *)gs_resize_object(mem, array_data, sizeof(gs_param_string) * new_max, "param string array in param parsing");
304
0
                        if (new_array == NULL) {
305
0
                            code = gs_error_VMerror;
306
0
                            break;
307
0
                        }
308
0
                        array_data = new_array;
309
0
                    }
310
0
                    array_max = new_max;
311
0
                    array_type = gs_param_type_string_array;
312
0
                }
313
0
                if (*(p1+1) == '<') {
314
0
                    code = gs_error_typecheck;
315
0
                    break;
316
                    /* dictionary inside an array, not supported */
317
0
                } else {
318
0
                    char *src, *dest;
319
0
                    char data = 0;
320
0
                    int i;
321
322
0
                    parray = (gs_param_string *)array_data;
323
0
                    src = dest = ++p1;
324
0
                    parray[index].data = (const byte *)p1;
325
0
                    while (*src && *src != '>') {
326
0
                        data = 0;
327
0
                        for (i=0;i<2;i++) {
328
0
                            if (*src >= '0' && *src <= '9') {
329
0
                                data = (data << 4);
330
0
                                data += (*src - '0');
331
0
                            } else if (*src >= 'A' && *src <= 'F') {
332
0
                                data = (data << 4);
333
0
                                data += (*src - 'A' + 10);
334
0
                            } else if (*src >= 'a' && *src <= 'f') {
335
0
                                data = (data << 4);
336
0
                                data += (*src - 'a' + 10);
337
0
                            } else {
338
0
                                goto return_minus_one;
339
0
                            }
340
0
                            src++;
341
0
                        }
342
0
                        *dest++ = data;
343
0
                    }
344
0
                    parray[index].size = dest - p1;
345
0
                    parray[index++].persistent = false;
346
0
                    p1 = src;
347
0
                }
348
0
                break;
349
350
0
            case '/':
351
0
                if (array_type != gs_param_type_null && array_type != gs_param_type_name_array) {
352
0
                    code = gs_error_typecheck;
353
0
                    break;
354
0
                }
355
0
                if (index == array_max) {
356
0
                    int new_max = array_max * 2;
357
0
                    if (new_max == 0)
358
0
                        new_max = 32;
359
0
                    if (array_data == NULL) {
360
0
                        array_data = (char *)gs_alloc_bytes(mem, sizeof(gs_param_string) * new_max, "param string array in param parsing");
361
0
                        if (array_data == NULL) {
362
0
                            code = gs_error_VMerror;
363
0
                            break;
364
0
                        }
365
0
                    } else {
366
0
                        char *new_array = (char *)gs_resize_object(mem, array_data, sizeof(gs_param_string) * new_max, "param string array in param parsing");
367
0
                        if (new_array == NULL) {
368
0
                            code = gs_error_VMerror;
369
0
                            break;
370
0
                        }
371
0
                        array_data = new_array;
372
0
                    }
373
0
                    array_max = new_max;
374
0
                    array_type = gs_param_type_name_array;
375
0
                }
376
0
                parray = (gs_param_string *)array_data;
377
0
                parray[index].data = (const byte *)++p1;
378
0
                while (!ends_token(p1))
379
0
                    p1++;
380
0
                parray[index].size = p1 - (char *)(parray[index].data);
381
0
                if (parray[index].size == 0)
382
0
                    goto return_minus_one;
383
0
                parray[index++].persistent = false;
384
0
                break;
385
386
0
            case '(':
387
0
                if (array_type != gs_param_type_null && array_type != gs_param_type_string_array) {
388
0
                    code = gs_error_typecheck;
389
0
                    break;
390
0
                }
391
0
                if (index == array_max) {
392
0
                    int new_max = array_max * 2;
393
0
                    if (new_max == 0)
394
0
                        new_max = 32;
395
0
                    if (array_data == NULL) {
396
0
                        array_data = (char *)gs_alloc_bytes(mem, sizeof(gs_param_string) * new_max, "param string array in param parsing");
397
0
                        if (array_data == NULL) {
398
0
                            code = gs_error_VMerror;
399
0
                            break;
400
0
                        }
401
0
                    } else {
402
0
                        char *new_array = (char *)gs_resize_object(mem, array_data, sizeof(gs_param_string) * new_max, "param string array in param parsing");
403
0
                        if (new_array == NULL) {
404
0
                            code = gs_error_VMerror;
405
0
                            break;
406
0
                        }
407
0
                        array_data = new_array;
408
0
                    }
409
0
                    array_max = new_max;
410
0
                    array_type = gs_param_type_string_array;
411
0
                }
412
0
                parray = (gs_param_string *)array_data;
413
0
                parray[index].data = (const byte *)p1;
414
0
                while (*p1 && *p1 != ')')
415
0
                    p1++;
416
0
                if (*p1 == 0)
417
0
                    goto return_minus_one;
418
0
                parray[index].size = p1 - (char *)(parray[index].data);
419
0
                parray[index++].persistent = false;
420
0
                break;
421
0
            case '[':
422
                /* Nested arrays, not supported */
423
0
                code = gs_error_typecheck;
424
0
                break;
425
0
            case '0':
426
0
            case '1':
427
0
            case '2':
428
0
            case '3':
429
0
            case '4':
430
0
            case '5':
431
0
            case '6':
432
0
            case '7':
433
0
            case '8':
434
0
            case '9':
435
0
            case '.':
436
0
            case '+':
437
0
            case '-':
438
0
                if (array_type == gs_param_type_string_array || array_type == gs_param_type_name_array ) {
439
0
                    code = gs_error_typecheck;
440
0
                    break;
441
0
                } else {
442
0
                    bool integer;
443
0
                    const char *start = p1;
444
0
                    char c;
445
0
                    float *floats;
446
0
                    int *ints, i;
447
448
0
                    code = walk_number(&p1, &integer);
449
0
                    if (code < 0)
450
0
                        break;
451
452
0
                    if (array_type == gs_param_type_int_array && !integer) {
453
0
                        ints = (int *)array_data;
454
0
                        floats = (float *)gs_alloc_bytes(mem, sizeof(float) * array_max, "param string array in param parsing");
455
0
                        if (floats == NULL){
456
0
                            code = gs_error_VMerror;
457
0
                            break;
458
0
                        }
459
0
                        array_type = gs_param_type_float_array;
460
0
                        for (i=0;i<index;i++){
461
0
                            floats[i] = (float)(ints[i]);
462
0
                        }
463
0
                        gs_free_object(mem, ints, "param string array in param parsing");
464
0
                        array_data = (char *)floats;
465
0
                    }
466
0
                    if (index == array_max) {
467
0
                        union { float f; int i; } size_me;
468
0
                        int new_max = array_max * 2;
469
0
                        if (new_max == 0) {
470
0
                            new_max = 32;
471
0
                            array_type = integer ? gs_param_type_int_array : gs_param_type_float_array;
472
0
                        }
473
0
                        if (array_data == NULL) {
474
0
                            array_data = (char *)gs_alloc_bytes(mem, sizeof(size_me) * new_max, "param string array in param parsing");
475
0
                            if (array_data == NULL) {
476
0
                                code = gs_error_VMerror;
477
0
                                break;
478
0
                            }
479
0
                        } else {
480
0
                            char *new_array = (char *)gs_resize_object(mem, array_data, sizeof(size_me) * new_max, "param string array in param parsing");
481
0
                            if (new_array == NULL) {
482
0
                                code = gs_error_VMerror;
483
0
                                break;
484
0
                            }
485
0
                            array_data = new_array;
486
0
                        }
487
0
                        array_max = new_max;
488
0
                    }
489
0
                    c = *p1;
490
0
                    *p1 = 0;
491
0
                    if (array_type == gs_param_type_int_array) {
492
0
                        ints = (int *)array_data;
493
0
                        ints[index++] = (int)atol(start);
494
0
                    } else {
495
0
                        floats = (float *)array_data;
496
0
                        floats[index++] = (float)atof(start);
497
0
                    }
498
0
                    *p1 = c;
499
0
                }
500
0
                break;
501
0
            default:
502
0
                code = gs_error_typecheck;
503
0
                break;
504
0
        }
505
0
    }
506
0
    if (0) {
507
0
return_minus_one:
508
0
        code = -1;
509
0
    }
510
511
    /* Now we have to deal with adding the array to the parm list, there are
512
     * (of course!) different calls for each array type....
513
     */
514
0
    if (code >= 0)
515
0
    {
516
0
        *p = p1 + 1;
517
0
        switch(array_type) {
518
0
            case gs_param_type_string_array:
519
0
                string_array.data = (const gs_param_string *)array_data;
520
0
                string_array.persistent = 0;
521
0
                string_array.size = index;
522
0
                code = param_write_string_array((gs_param_list *)plist, key, &string_array);
523
0
                break;
524
0
            case gs_param_type_name_array:
525
0
                string_array.data = (const gs_param_string *)array_data;
526
0
                string_array.persistent = 0;
527
0
                string_array.size = index;
528
0
                code = param_write_name_array((gs_param_list *)plist, key, &string_array);
529
0
                break;
530
0
            case gs_param_type_int_array:
531
0
                int_array.data = (const int *)array_data;
532
0
                int_array.persistent = 0;
533
0
                int_array.size = index;
534
0
                code = param_write_int_array((gs_param_list *)plist, key, &int_array);
535
0
                break;
536
0
            case gs_param_type_float_array:
537
0
                float_array.data = (const float *)array_data;
538
0
                float_array.persistent = 0;
539
0
                float_array.size = index;
540
0
                code = param_write_float_array((gs_param_list *)plist, key, &float_array);
541
0
                break;
542
543
0
            default:
544
0
                break;
545
0
        }
546
0
    }
547
548
    /* And now we can throw away the array data, we copied it to the param list. */
549
0
    gs_free_object(mem, array_data, "param string array in param parsing");
550
551
0
    return code;
552
0
}
553
554
/* We rely on the fact that we can overwrite, then restore *end here. */
555
static int
556
process_number(gs_memory_t *mem, gs_c_param_list *plist, gs_param_name key, char **p)
557
0
{
558
0
    bool integer;
559
0
    const char *start = *p;
560
0
    char c;
561
0
    int code = walk_number(p, &integer);
562
563
0
    if (code < 0)
564
0
        return code;
565
566
    /* Hacky. Null terminate so that atof/atol don't overrun. This is
567
     * safe because at worst p points to the null terminator byte, and
568
     * we can safely overwrite end for a moment. Ick. */
569
0
    c = **p;
570
0
    **p = 0;
571
0
    if (!integer) {
572
0
        float f = (float)atof(start);
573
0
        code = param_write_float((gs_param_list *)plist, key, (float *)&f);
574
0
    } else {
575
        /* FIXME: Should probably really be int64_t here rather than int? */
576
0
        long i = atol(start);
577
0
        code = param_write_long((gs_param_list *)plist, key, &i);
578
0
    }
579
0
    **p = c;
580
581
0
    return code;
582
0
}
583
584
static int
585
add_tokens(gs_param_list *plist, gs_param_name key, char **pp, uint *dict_count)
586
0
{
587
0
    char *p = *pp;
588
0
    int code = 0;
589
    /* If single == true, then we are looking for a single value,
590
     * otherwise it's a list of key/value pairs */
591
0
    int single = (key != NULL);
592
    /* If single_done, then we've read our single value. Any non
593
     * whitespace we read is an error. */
594
0
    int single_done = 0;
595
0
    bool f = false, t = true;
596
597
0
    while (*p) {
598
0
        switch (*p) {
599
0
            case ' ':
600
0
                p++;
601
0
                break;
602
0
            case 'f':
603
0
                if (single_done || key == NULL)
604
0
                    return -1;
605
0
                if (strncmp(p, "false", 5) != 0)
606
0
                    return -1;
607
0
                if (!ends_token(p+5))
608
0
                    return -1;
609
0
                code = param_write_bool((gs_param_list *)plist, key, &f);
610
0
                if (code >= 0 && dict_count != NULL)
611
0
                    (*dict_count)++;
612
0
                p += 5;
613
0
                single_done = single;
614
0
                key = NULL;
615
0
                break;
616
0
            case 't':
617
0
                if (single_done || key == NULL)
618
0
                    return -1;
619
0
                if (strncmp(p, "true", 4) != 0)
620
0
                    return -1;
621
0
                if (!ends_token(p+4))
622
0
                    return -1;
623
0
                code = param_write_bool((gs_param_list *)plist, key, &t);
624
0
                if (code >= 0 && dict_count != NULL)
625
0
                    (*dict_count)++;
626
0
                p += 4;
627
0
                single_done = single;
628
0
                key = NULL;
629
0
                break;
630
0
            case '<':
631
0
                if (single_done || key == NULL)
632
0
                    return -1;
633
0
                code = process_dict_or_hexstring(plist->memory, (gs_c_param_list *)plist, key, &p);
634
0
                if (code >= 0 && dict_count != NULL)
635
0
                    (*dict_count)++;
636
0
                single_done = single;
637
0
                key = NULL;
638
0
                break;
639
0
            case '/':
640
0
            {
641
0
                int have_key = (key != NULL);
642
0
                if (single_done)
643
0
                    return -1;
644
0
                code = process_name(plist->memory, (gs_c_param_list *)plist, &key, &p);
645
0
                if (code >= 0 && have_key && dict_count != NULL)
646
0
                    (*dict_count)++;
647
0
                if (have_key) {
648
0
                    single_done = single;
649
0
                    key = NULL;
650
0
                }
651
0
                break;
652
0
            }
653
0
            case '(':
654
0
                if (single_done || key == NULL)
655
0
                    return -1;
656
0
                code = process_string(plist->memory, (gs_c_param_list *)plist, key, &p);
657
0
                if (code >= 0 && dict_count != NULL)
658
0
                    (*dict_count)++;
659
0
                single_done = single;
660
0
                key = NULL;
661
0
                break;
662
0
            case '[':
663
0
                if (single_done || key == NULL)
664
0
                    return -1;
665
0
                code = process_array(plist->memory, (gs_c_param_list *)plist, key, &p);
666
0
                if (code >= 0 && dict_count != NULL)
667
0
                    (*dict_count)++;
668
0
                single_done = single;
669
0
                key = NULL;
670
0
                break;
671
0
            case '0':
672
0
            case '1':
673
0
            case '2':
674
0
            case '3':
675
0
            case '4':
676
0
            case '5':
677
0
            case '6':
678
0
            case '7':
679
0
            case '8':
680
0
            case '9':
681
0
            case '.':
682
0
                if (single_done || key == NULL)
683
0
                    return -1;
684
0
                code = process_number(plist->memory, (gs_c_param_list *)plist, key, &p);
685
0
                if (code >= 0 && dict_count != NULL)
686
0
                    (*dict_count)++;
687
0
                single_done = single;
688
0
                key = NULL;
689
0
                break;
690
0
            case '>':
691
0
                if (dict_count != NULL && p[1] == '>') {
692
0
                    if (key != NULL)
693
0
                        return -1;
694
0
                    *pp = p;
695
0
                    return 0;
696
0
                }
697
0
                return -1;
698
0
            default:
699
0
                return -1;
700
0
                break;
701
0
        }
702
0
        if (code < 0)
703
0
            return code;
704
0
    }
705
706
0
    *pp = p;
707
0
    return 0;
708
0
}
709
710
/* Given a string to parse (a list of key/value pairs), parse it and add
711
 * what we find to the supplied param list.
712
 */
713
int gs_param_list_add_tokens(gs_param_list *plist, char *p)
714
0
{
715
0
    char *r = p;
716
0
    return add_tokens(plist, NULL, &r, NULL);
717
0
}
718
719
/* Given a key, and a string representing a single (maybe complex) value
720
 * to parse, parse it and add what we find to the supplied param list.
721
 */
722
int gs_param_list_add_parsed_value(gs_param_list *plist, gs_param_name key, const char *p)
723
0
{
724
0
    size_t len;
725
0
    char *q, *r;
726
0
    int code;
727
728
    /* Treat NULL as the empty string. */
729
0
    if (p == NULL)
730
0
        return 0;
731
732
0
    len = strlen(p) + 1;
733
0
    q = (char *)gs_alloc_bytes(plist->memory, len, "gs_param_list_add_parsed_value");
734
0
    if (q == NULL)
735
0
        return_error(gs_error_VMerror);
736
0
    memcpy(q, p, len);
737
738
0
    r = q;
739
0
    code = add_tokens(plist, key, &r, NULL);
740
741
0
    gs_free_object(plist->memory, q, "gs_param_list_add_parsed_value");
742
743
0
    return code;
744
0
}
745
746
typedef struct {
747
    char *value;
748
    int *len;
749
    char last;
750
} outstate;
751
752
static void
753
out_string(outstate *out, const char *str)
754
0
{
755
0
    int slen = str ? (int)strlen(str) : 0;
756
757
0
    if (slen == 0)
758
0
        return;
759
760
0
    if (out->last != 0 && out->last != ')' && out->last != '>' &&
761
0
        out->last != '[' && out->last != ']' && out->last != '}' &&
762
0
        *str != '(' && *str != ')' && *str != '<' && *str != '>' &&
763
0
        *str != '[' && *str != ']' && *str != '{' && *str != '}' &&
764
0
        *str != '/') {
765
        /* We need to insert some whitespace */
766
0
        *out->len += 1;
767
0
        if (out->value != NULL) {
768
0
            *out->value++ = ' ';
769
0
            *out->value = 0;
770
0
        }
771
0
    }
772
773
0
    *out->len += slen;
774
0
    out->last = str[slen-1];
775
0
    if (out->value != NULL) {
776
0
        memcpy(out->value, str, slen);
777
0
        out->value += slen;
778
0
        *out->value = 0;
779
0
    }
780
0
}
781
782
static void
783
string_to_string(const char *data, int len, outstate *out)
784
0
{
785
0
    int i;
786
0
    char text[4];
787
0
    const char *d = data;
788
789
    /* Check to see if we have any awkward chars */
790
0
    for (i = len; i != 0; i--) {
791
0
        if (*d < 32 || *d >= 127 || *d == ')')
792
0
            break;
793
0
        d++;
794
0
    }
795
796
    /* No awkward chars, do it the easy way. */
797
0
    if (i == 0) {
798
0
        d = data;
799
0
        out_string(out, "(");
800
0
        out->last = 0;
801
0
        text[1] = 0;
802
0
        for (i = len; i != 0; i--) {
803
0
            text[0] = *d++;
804
0
            out->last = 0;
805
0
            out_string(out, text);
806
0
        }
807
0
        out->last = 0;
808
0
        out_string(out, ")");
809
0
        return;
810
0
    }
811
812
    /* Output as hexstring */
813
0
    out_string(out, "<");
814
0
    text[2] = 0;
815
0
    for (i = 0; i < len; i++) {
816
0
        text[0] = "0123456789ABCDEF"[(*data >> 4) & 15];
817
0
        text[1] = "0123456789ABCDEF"[(*data++) & 15];
818
0
        out->last = 0;
819
0
        out_string(out, text);
820
0
    }
821
0
    out_string(out, ">");
822
0
}
823
824
static void
825
name_to_string(const char *data, int len, outstate *out)
826
0
{
827
0
    int i;
828
0
    char text[4];
829
830
0
    out_string(out, "/");
831
0
    text[3] = 0;
832
0
    for (i = 0; i < len; i++) {
833
0
        char c = *data++;
834
0
        if (c > 32 && c < 127 && c != '/' && c != '#' &&
835
0
            c != '<' && c != '>' &&
836
0
            c != '[' && c != ']' &&
837
0
            c != '(' && c != ')' &&
838
0
            c != '{' && c != '}') {
839
0
            text[0] = c;
840
0
            text[1] = 0;
841
0
        } else {
842
0
            text[0] = '#';
843
0
            text[1] = "0123456789ABCDEF"[(c >> 4) & 15];
844
0
            text[2] = "0123456789ABCDEF"[c & 15];
845
0
        }
846
0
        out->last = 0;
847
0
        out_string(out, text);
848
0
    }
849
0
}
850
851
static void
852
int_array_to_string(gs_param_int_array ia, outstate *out)
853
0
{
854
0
    int i;
855
0
    char text[32];
856
857
0
    out_string(out, "[");
858
0
    for (i = 0; i < ia.size; i++) {
859
0
        gs_snprintf(text, sizeof(text), "%d", ia.data[i]);
860
0
        out_string(out, text);
861
0
    }
862
0
    out_string(out, "]");
863
0
}
864
865
static void
866
print_float(char text[32], float f)
867
0
{
868
    /* We attempt to tidy up %f's somewhat unpredictable output
869
     * here, so rather than printing 0.10000000 we print 0.1 */
870
0
    char *p = text;
871
0
    int frac = 0;
872
0
    gs_snprintf(text, 32, "%f", f);
873
    /* Find the terminator, or 'e' to spot exponent mode. */
874
0
    while (*p && *p != 'e' && *p != 'E') {
875
0
        if (*p == '.')
876
0
            frac = 1;
877
0
        p++;
878
0
    }
879
    /* If we've hit the terminator, and passed a '.' at some point
880
     * we know we potentially have a tail to tidy up. */
881
0
    if (*p == 0 && frac) {
882
0
        p--;
883
        /* Clear a trail of 0's. */
884
0
        while (*p == '0')
885
0
            *p-- = 0;
886
        /* If we cleared the entire fractional part, remove the . */
887
0
        if (*p == '.') {
888
            /* Allow for -.0000 => -0 rather than - */
889
0
            if (p == text || p[-1] < '0' || p[-1] > '9')
890
0
                *p = '0', p[1] = 0;
891
0
            else
892
0
                p[0] = 0;
893
0
        }
894
0
    }
895
0
}
896
897
static void
898
float_array_to_string(gs_param_float_array fa, outstate *out)
899
0
{
900
0
    int i;
901
0
    char text[32];
902
903
0
    out_string(out, "[");
904
0
    for (i = 0; i < fa.size; i++) {
905
0
        print_float(text, fa.data[i]);
906
0
        out_string(out, text);
907
0
    }
908
0
    out_string(out, "]");
909
0
}
910
911
static void
912
string_array_to_string(gs_param_string_array sa, outstate *out)
913
0
{
914
0
    int i;
915
916
0
    out_string(out, "[");
917
0
    for (i = 0; i < sa.size; i++) {
918
0
        string_to_string((const char *)sa.data[i].data, sa.data[i].size, out);
919
0
    }
920
0
    out_string(out, "]");
921
0
}
922
923
static void
924
name_array_to_string(gs_param_string_array na, outstate *out)
925
0
{
926
0
    int i;
927
928
0
    out_string(out, "[");
929
0
    for (i = 0; i < na.size; i++) {
930
0
        name_to_string((const char *)na.data[i].data, na.data[i].size, out);
931
0
    }
932
0
    out_string(out, "]");
933
0
}
934
935
static int to_string(gs_param_list *plist, gs_param_name key, outstate *out);
936
937
static int
938
out_dict(gs_param_collection *dict, outstate *out)
939
0
{
940
0
    gs_param_list *plist = dict->list;
941
0
    gs_param_enumerator_t enumerator;
942
0
    gs_param_key_t key;
943
0
    int code;
944
945
0
    out_string(out, "<<");
946
947
0
    param_init_enumerator(&enumerator);
948
0
    while ((code = param_get_next_key(plist, &enumerator, &key)) == 0) {
949
0
        char string_key[256]; /* big enough for any reasonable key */
950
951
0
        if (key.size > sizeof(string_key) - 1) {
952
0
            code = gs_note_error(gs_error_rangecheck);
953
0
            break;
954
0
        }
955
0
        memcpy(string_key, key.data, key.size);
956
0
        string_key[key.size] = 0;
957
0
        name_to_string((char *)key.data, key.size, out);
958
0
        code = to_string(plist, string_key, out);
959
0
        if (code < 0)
960
0
            break;
961
0
    }
962
963
0
    out_string(out, ">>");
964
0
    if (code == 1)
965
0
        code = 0;
966
967
0
    return code;
968
0
}
969
970
static int
971
to_string(gs_param_list *plist, gs_param_name key, outstate *out)
972
0
{
973
0
    int code = 0;
974
0
    gs_param_typed_value pvalue;
975
976
0
    pvalue.type = gs_param_type_any;
977
0
    code = param_read_typed(plist, key, &pvalue);
978
0
    if (code < 0)
979
0
        return code;
980
0
    if (code > 0)
981
0
        return_error(gs_error_undefined);
982
0
    switch (pvalue.type) {
983
0
    case gs_param_type_null:
984
0
        out_string(out, "null");
985
0
        break;
986
0
    case gs_param_type_bool:
987
0
        if (pvalue.value.b)
988
0
            out_string(out, "true");
989
0
        else
990
0
            out_string(out, "false");
991
0
        break;
992
0
    case gs_param_type_int:
993
0
    {
994
0
        char text[32];
995
0
        gs_snprintf(text, sizeof(text), "%d", pvalue.value.i);
996
0
        out_string(out, text);
997
0
        break;
998
0
    }
999
0
    case gs_param_type_i64:
1000
0
    {
1001
0
        char text[32];
1002
0
        gs_snprintf(text, sizeof(text), "%"PRId64, pvalue.value.i64);
1003
0
        out_string(out, text);
1004
0
        break;
1005
0
    }
1006
0
    case gs_param_type_long:
1007
0
    {
1008
0
        char text[32];
1009
0
        gs_snprintf(text, sizeof(text), "%ld", pvalue.value.l);
1010
0
        out_string(out, text);
1011
0
        break;
1012
0
    }
1013
0
    case gs_param_type_size_t:
1014
0
    {
1015
0
        char text[32];
1016
0
        gs_snprintf(text, sizeof(text), "%"PRIdSIZE, pvalue.value.z);
1017
0
        out_string(out, text);
1018
0
        break;
1019
0
    }
1020
0
    case gs_param_type_float:
1021
0
    {
1022
0
        char text[32];
1023
0
        print_float(text, pvalue.value.f);
1024
0
        out_string(out, text);
1025
0
        break;
1026
0
    }
1027
0
    case gs_param_type_dict:
1028
0
        code = out_dict(&pvalue.value.d, out);
1029
0
        break;
1030
0
    case gs_param_type_dict_int_keys:
1031
0
        return -1;
1032
0
    case gs_param_type_array:
1033
0
        return -1;
1034
0
    case gs_param_type_string:
1035
0
        string_to_string((char *)pvalue.value.s.data, pvalue.value.s.size, out);
1036
0
        break;
1037
0
    case gs_param_type_name:
1038
0
        name_to_string((char *)pvalue.value.n.data, pvalue.value.n.size, out);
1039
0
        break;
1040
0
    case gs_param_type_int_array:
1041
0
        int_array_to_string(pvalue.value.ia, out);
1042
0
        break;
1043
0
    case gs_param_type_float_array:
1044
0
        float_array_to_string(pvalue.value.fa, out);
1045
0
        break;
1046
0
    case gs_param_type_string_array:
1047
0
        string_array_to_string(pvalue.value.sa, out);
1048
0
        break;
1049
0
    case gs_param_type_name_array:
1050
0
        name_array_to_string(pvalue.value.na, out);
1051
0
        break;
1052
0
    default:
1053
0
        return -1;
1054
0
    }
1055
1056
0
    return code;
1057
0
}
1058
1059
int gs_param_list_to_string(gs_param_list *plist, gs_param_name key, char *value, int *len)
1060
0
{
1061
0
    outstate out;
1062
1063
0
    out.value = value;
1064
0
    out.len = len;
1065
0
    out.last = 0;
1066
0
    *len = 1; /* Always space for the terminator. */
1067
0
    if (value)
1068
0
        *value = 0;
1069
0
    return to_string(plist, key, &out);
1070
0
}
1071
1072
int gs_param_list_dump(gs_param_list *plist)
1073
0
{
1074
0
    gs_param_enumerator_t enumerator;
1075
0
    gs_param_key_t key;
1076
0
    int code;
1077
0
    char buffer[4096];
1078
0
    int len;
1079
1080
0
    param_init_enumerator(&enumerator);
1081
0
    while ((code = param_get_next_key(plist, &enumerator, &key)) == 0) {
1082
0
        char string_key[256]; /* big enough for any reasonable key */
1083
1084
0
        if (key.size > sizeof(string_key) - 1) {
1085
0
            code = gs_note_error(gs_error_rangecheck);
1086
0
            break;
1087
0
        }
1088
0
        memcpy(string_key, key.data, key.size);
1089
0
        string_key[key.size] = 0;
1090
0
        dlprintf1("%s ", string_key);
1091
0
        code = gs_param_list_to_string(plist, string_key, buffer, &len);
1092
0
        if (code < 0)
1093
0
            break;
1094
0
        dlprintf1("%s ", buffer);
1095
0
    }
1096
0
    dlprintf("\n");
1097
0
    return code;
1098
0
}