Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gsparams.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
/* Generic parameter list serializer & expander */
18
19
/* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
20
/* 11/16/98 L. Peter Deutsch (ghost@aladdin.com) edited to remove names
21
   put_bytes, put_word which conflicted with other modules */
22
23
#include "gx.h"
24
#include "memory_.h"
25
#include "gserrors.h"
26
#include "gsparams.h"
27
28
/* ----------- Local Type Decl's ------------ */
29
typedef struct {
30
    byte *buf;      /* current buffer ptr */
31
    byte *buf_end;    /* end of buffer */
32
    unsigned total_sizeof;  /* current # bytes in buf */
33
} WriteBuffer;
34
35
/* ---------- Forward refs ----------- */
36
static void
37
ptr_align_to(
38
            const byte ** src,  /* pointer to align */
39
            unsigned alignment  /* alignment, must be power of 2 */
40
            );
41
static void
42
wb_put_word(
43
            unsigned source,  /* number to put to buffer */
44
            WriteBuffer * dest  /* destination descriptor */
45
            );
46
static void
47
wb_put_bytes(
48
             const byte * source, /* bytes to put to buffer */
49
             unsigned source_sizeof,  /* # bytes to put */
50
             WriteBuffer * dest   /* destination descriptor */
51
             );
52
static void
53
wb_put_alignment(
54
                 unsigned alignment,  /* alignment to match, must be power 2 */
55
                 WriteBuffer * dest /* destination descriptor */
56
                 );
57
58
/* Get word compressed with wb_put_word */
59
static unsigned   /* decompressed word */
60
buf_get_word(
61
            const byte ** src /* UPDATES: ptr to src buf ptr */
62
            );
63
64
/* ------------ Serializer ------------ */
65
/* Serialize the contents of a gs_param_list (including sub-dicts) */
66
int       /* ret -ve err, else # bytes needed to represent param list, whether */
67
68
/* or not it actually fit into buffer. List was successully */
69
70
/* serialized only if if this # is <= supplied buf size. */
71
gs_param_list_serialize(
72
                           gs_param_list * list,  /* root of list to serialize */
73
                                        /* list MUST BE IN READ MODE */
74
                           byte * buf,  /* destination buffer (can be 0) */
75
                           int buf_sizeof /* # bytes available in buf (can be 0) */
76
)
77
0
{
78
0
    int code = 0;
79
0
    int temp_code;
80
0
    gs_param_enumerator_t key_enum;
81
0
    gs_param_key_t key;
82
0
    WriteBuffer write_buf;
83
84
0
    write_buf.buf = buf;
85
0
    write_buf.buf_end = buf + (buf ? buf_sizeof : 0);
86
0
    write_buf.total_sizeof = 0;
87
0
    param_init_enumerator(&key_enum);
88
89
    /* Each item is serialized as ("word" means compressed word):
90
     *  word: key sizeof + 1, or 0 if end of list/dict
91
     *  word: data type(gs_param_type_xxx)
92
     *  byte[]: key, including trailing \0
93
     *  (if simple type)
94
     *   byte[]: unpacked representation of data
95
     *  (if simple array or string)
96
     *   byte[]: unpacked mem image of gs_param_xxx_array structure
97
     *   pad: to array alignment
98
     *   byte[]: data associated with array contents
99
     *  (if string/name array)
100
     *   byte[]: unpacked mem image of gs_param_string_array structure
101
     *   pad: to void *
102
     *   { gs_param_string structure mem image;
103
     *     data associated with string;
104
     *   } for each string in array
105
     *  (if dict/dict_int_keys)
106
     *   word: # of entries in dict,
107
     *   pad: to void *
108
     *   dict entries follow immediately until end-of-dict
109
     *
110
     * NB that this format is designed to allow using an input buffer
111
     * as the direct source of data when expanding a gs_c_param_list
112
     */
113
    /* Enumerate all the keys; use keys to get their typed values */
114
0
    while ((code = param_get_next_key(list, &key_enum, &key)) == 0) {
115
0
        int value_top_sizeof;
116
0
        int value_base_sizeof;
117
118
        /* Get next datum & put its type & key to buffer */
119
0
        gs_param_typed_value value;
120
0
        char string_key[256];
121
122
0
        if (sizeof(string_key) < key.size + 1) {
123
0
            code = gs_note_error(gs_error_rangecheck);
124
0
            break;
125
0
        }
126
0
        memcpy(string_key, key.data, key.size);
127
0
        string_key[key.size] = 0;
128
0
        if ((code = param_read_typed(list, string_key, &value)) != 0) {
129
0
            code = code > 0 ? gs_note_error(gs_error_unknownerror) : code;
130
0
            break;
131
0
        }
132
0
        wb_put_word((unsigned)key.size + 1, &write_buf);
133
0
        wb_put_word((unsigned)value.type, &write_buf);
134
0
        wb_put_bytes((byte *) string_key, key.size + 1, &write_buf);
135
136
        /* Put value & its size to buffer */
137
0
        value_top_sizeof = gs_param_type_sizes[value.type];
138
0
        value_base_sizeof = gs_param_type_base_sizes[value.type];
139
0
        switch (value.type) {
140
0
            case gs_param_type_null:
141
0
            case gs_param_type_bool:
142
0
            case gs_param_type_int:
143
0
            case gs_param_type_long:
144
0
            case gs_param_type_size_t:
145
0
            case gs_param_type_i64:
146
0
            case gs_param_type_float:
147
0
                wb_put_bytes((byte *) & value.value, value_top_sizeof, &write_buf);
148
0
                break;
149
150
0
            case gs_param_type_string:
151
0
            case gs_param_type_name:
152
0
            case gs_param_type_int_array:
153
0
            case gs_param_type_float_array:
154
0
                wb_put_bytes((byte *) & value.value, value_top_sizeof, &write_buf);
155
0
                wb_put_alignment(value_base_sizeof, &write_buf);
156
0
                value_base_sizeof *= value.value.s.size;
157
0
                wb_put_bytes(value.value.s.data, value_base_sizeof, &write_buf);
158
0
                break;
159
160
0
            case gs_param_type_string_array:
161
0
            case gs_param_type_name_array:
162
0
                value_base_sizeof *= value.value.sa.size;
163
0
                wb_put_bytes((const byte *)&value.value, value_top_sizeof, &write_buf);
164
0
                wb_put_alignment(sizeof(void *), &write_buf);
165
166
0
                wb_put_bytes((const byte *)value.value.sa.data, value_base_sizeof,
167
0
                          &write_buf);
168
0
                {
169
0
                    int str_count;
170
0
                    const gs_param_string *sa;
171
172
0
                    for (str_count = value.value.sa.size,
173
0
                         sa = value.value.sa.data; str_count-- > 0; ++sa)
174
0
                        wb_put_bytes(sa->data, sa->size, &write_buf);
175
0
                }
176
0
                break;
177
178
0
            case gs_param_type_dict:
179
0
            case gs_param_type_dict_int_keys:
180
0
                wb_put_word(value.value.d.size, &write_buf);
181
0
                wb_put_alignment(sizeof(void *), &write_buf);
182
183
0
                {
184
0
                    int bytes_written =
185
0
                    gs_param_list_serialize(value.value.d.list,
186
0
                                            write_buf.buf,
187
0
                     write_buf.buf ? write_buf.buf_end - write_buf.buf : 0);
188
189
0
                    temp_code = param_end_read_dict(list,
190
0
                                                    (const char *)key.data,
191
0
                                                    &value.value.d);
192
0
                    if (bytes_written < 0)
193
0
                        code = bytes_written;
194
0
                    else {
195
0
                        code = temp_code;
196
0
                        if (bytes_written)
197
0
                            wb_put_bytes(write_buf.buf, bytes_written, &write_buf);
198
0
                    }
199
0
                }
200
0
                break;
201
202
0
            default:
203
0
                code = gs_note_error(gs_error_unknownerror);
204
0
                break;
205
0
        }
206
0
        if (code < 0)
207
0
            break;
208
0
    }
209
210
    /* Write end marker, which is an (illegal) 0 key length */
211
0
    if (code >= 0) {
212
0
        wb_put_word(0, &write_buf);
213
0
        code = write_buf.total_sizeof;
214
0
    }
215
0
    return code;
216
0
}
217
218
/* ------------ Expander --------------- */
219
/* Expand a buffer into a gs_param_list (including sub-dicts) */
220
int       /* ret -ve err, +ve # of chars read from buffer */
221
gs_param_list_unserialize(
222
                             gs_param_list * list,  /* root of list to expand to */
223
                                        /* list MUST BE IN WRITE MODE */
224
                             const byte * buf /* source buffer */
225
)
226
0
{
227
0
    int code = 0;
228
0
    const byte *orig_buf = buf;
229
230
0
    do {
231
0
        gs_param_typed_value typed;
232
0
        gs_param_name key;
233
0
        unsigned key_sizeof;
234
0
        int value_top_sizeof;
235
0
        int value_base_sizeof;
236
0
        int temp_code;
237
0
        gs_param_type type;
238
239
        /* key length, 0 indicates end of data */
240
0
        key_sizeof = buf_get_word(&buf);
241
0
        if (key_sizeof == 0) /* end of data */
242
0
            break;
243
244
        /* data type */
245
0
        type = (gs_param_type) buf_get_word(&buf);
246
247
        /* key */
248
0
        key = (gs_param_name) buf;
249
0
        buf += key_sizeof;
250
251
        /* Data values */
252
0
        value_top_sizeof = gs_param_type_sizes[type];
253
0
        value_base_sizeof = gs_param_type_base_sizes[type];
254
0
        typed.type = type;
255
0
        if (type != gs_param_type_dict && type != gs_param_type_dict_int_keys) {
256
0
            memcpy(&typed.value, buf, value_top_sizeof);
257
0
            buf += value_top_sizeof;
258
0
        }
259
0
        switch (type) {
260
0
            case gs_param_type_null:
261
0
            case gs_param_type_bool:
262
0
            case gs_param_type_int:
263
0
            case gs_param_type_long:
264
0
            case gs_param_type_size_t:
265
0
            case gs_param_type_i64:
266
0
            case gs_param_type_float:
267
0
                break;
268
269
0
            case gs_param_type_string:
270
0
            case gs_param_type_name:
271
0
            case gs_param_type_int_array:
272
0
            case gs_param_type_float_array:
273
0
                ptr_align_to(&buf, value_base_sizeof);
274
0
                typed.value.s.data = buf;
275
0
                typed.value.s.persistent = false;
276
0
                buf += typed.value.s.size * value_base_sizeof;
277
0
                break;
278
279
0
            case gs_param_type_string_array:
280
0
            case gs_param_type_name_array:
281
0
                ptr_align_to(&buf, sizeof(void *));
282
283
0
                typed.value.sa.data = (const gs_param_string *)buf;
284
0
                typed.value.sa.persistent = false;
285
0
                buf += typed.value.s.size * value_base_sizeof;
286
0
                {
287
0
                    int str_count;
288
0
                    gs_param_string *sa;
289
290
0
                    for (str_count = typed.value.sa.size,
291
0
                         sa = (gs_param_string *) typed.value.sa.data;
292
0
                         str_count-- > 0; ++sa) {
293
0
                        sa->data = buf;
294
0
                        sa->persistent = false;
295
0
                        buf += sa->size;
296
0
                    }
297
0
                }
298
0
                break;
299
300
0
            case gs_param_type_dict:
301
0
            case gs_param_type_dict_int_keys:
302
0
                typed.value.d.size = buf_get_word(&buf);
303
0
                code = param_begin_write_dict
304
0
                    (list, key, &typed.value.d, type == gs_param_type_dict_int_keys);
305
0
                if (code < 0)
306
0
                    break;
307
0
                ptr_align_to(&buf, sizeof(void *));
308
309
0
                code = gs_param_list_unserialize(typed.value.d.list, buf);
310
0
                temp_code = param_end_write_dict(list, key, &typed.value.d);
311
0
                if (code >= 0) {
312
0
                    buf += code;
313
0
                    code = temp_code;
314
0
                }
315
0
                break;
316
317
0
            default:
318
0
                code = gs_note_error(gs_error_unknownerror);
319
0
                break;
320
0
        }
321
0
        if (code < 0)
322
0
            break;
323
0
        if (typed.type != gs_param_type_dict && typed.type != gs_param_type_dict_int_keys)
324
0
            code = param_write_typed(list, key, &typed);
325
0
    }
326
0
    while (code >= 0);
327
328
0
    return code >= 0 ? buf - orig_buf : code;
329
0
}
330
331
/* ---------- Utility functions -------- */
332
333
/* Align a byte pointer on the next Nth byte */
334
static void
335
ptr_align_to(
336
            const byte ** src,  /* pointer to align */
337
            unsigned alignment  /* alignment, must be power of 2 */
338
)
339
0
{
340
0
    *src += -(int)ALIGNMENT_MOD(*src, alignment) & (alignment - 1);
341
0
}
342
343
/* Put compressed word repr to a buffer */
344
static void
345
wb_put_word(
346
            unsigned source,  /* number to put to buffer */
347
            WriteBuffer * dest  /* destination descriptor */
348
)
349
0
{
350
0
    do {
351
0
        byte chunk = source & 0x7f;
352
353
0
        if (source >= 0x80)
354
0
            chunk |= 0x80;
355
0
        source >>= 7;
356
0
        ++dest->total_sizeof;
357
0
        if (dest->buf && dest->buf < dest->buf_end)
358
0
            *dest->buf++ = chunk;
359
0
    }
360
0
    while (source != 0);
361
0
}
362
363
/* Put array of bytes to buffer */
364
static void
365
wb_put_bytes(
366
             const byte * source, /* bytes to put to buffer */
367
             unsigned source_sizeof,  /* # bytes to put */
368
             WriteBuffer * dest /* destination descriptor */
369
)
370
0
{
371
0
    dest->total_sizeof += source_sizeof;
372
0
    if (dest->buf && dest->buf + source_sizeof <= dest->buf_end) {
373
0
        if (dest->buf != source)
374
0
            memcpy(dest->buf, source, source_sizeof);
375
0
        dest->buf += source_sizeof;
376
0
    }
377
0
}
378
379
/* Pad destination out to req'd alignment w/zeros */
380
static void
381
wb_put_alignment(
382
                 unsigned alignment,  /* alignment to match, must be power 2 */
383
                 WriteBuffer * dest /* destination descriptor */
384
)
385
0
{
386
0
    static const byte zero =
387
0
    {0};
388
389
0
    while ((dest->total_sizeof & (alignment - 1)) != 0)
390
0
        wb_put_bytes(&zero, 1, dest);
391
0
}
392
393
/* Get word compressed with wb_put_word */
394
static unsigned   /* decompressed word */
395
buf_get_word(
396
            const byte ** src /* UPDATES: ptr to src buf ptr */
397
)
398
0
{
399
0
    unsigned dest = 0;
400
0
    byte chunk;
401
0
    unsigned shift = 0;
402
403
0
    do {
404
0
        chunk = *(*src)++;
405
0
        dest |= (chunk & 0x7f) << shift;
406
0
        shift += 7;
407
0
    }
408
0
    while (chunk & 0x80);
409
410
0
    return dest;
411
0
}