Coverage Report

Created: 2022-04-16 11:23

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