Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/pdf/pdf_obj.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2020-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
#include "ghostpdf.h"
17
#include "pdf_stack.h"
18
#include "pdf_array.h"
19
#include "pdf_dict.h"
20
#include "pdf_obj.h"
21
#include "pdf_cmap.h"
22
#include "pdf_font.h"
23
#include "pdf_deref.h" /* for replace_cache_entry() */
24
#include "pdf_mark.h"
25
#include "pdf_file.h" /* for pdfi_stream_to_buffer() */
26
#include "pdf_loop_detect.h"
27
#include "stream.h"
28
29
/***********************************************************************************/
30
/* Functions to create the various kinds of 'PDF objects', Created objects have a  */
31
/* reference count of 0. Composite objects (dictionaries, arrays, strings) use the */
32
/* 'size' argument to create an object with the correct numbr of entries or of the */
33
/* requested size. Simple objects (integers etc) ignore this parameter.            */
34
/* Objects do not get their data assigned, that's up to the caller, but we do      */
35
/* set the length or size fields for composite objects.                             */
36
37
int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pdf_obj **obj)
38
784M
{
39
784M
    int bytes = 0;
40
784M
    int code = 0;
41
42
784M
    switch(type) {
43
14.9M
        case PDF_ARRAY_MARK:
44
27.7M
        case PDF_DICT_MARK:
45
28.0M
        case PDF_PROC_MARK:
46
28.0M
            bytes = sizeof(pdf_obj);
47
28.0M
            break;
48
208M
        case PDF_INT:
49
335M
        case PDF_REAL:
50
335M
            bytes = sizeof(pdf_num);
51
335M
            break;
52
73.6M
        case PDF_STRING:
53
358M
        case PDF_NAME:
54
358M
            bytes = sizeof(pdf_string) + size - PDF_NAME_DECLARED_LENGTH;
55
358M
            break;
56
40.9k
        case PDF_BUFFER:
57
40.9k
            bytes = sizeof(pdf_buffer);
58
40.9k
            break;
59
14.8M
        case PDF_ARRAY:
60
14.8M
            bytes = sizeof(pdf_array);
61
14.8M
            break;
62
13.4M
        case PDF_DICT:
63
13.4M
            bytes = sizeof(pdf_dict);
64
13.4M
            break;
65
18.4M
        case PDF_INDIRECT:
66
18.4M
            bytes = sizeof(pdf_indirect_ref);
67
18.4M
            break;
68
15.5M
        case PDF_KEYWORD:
69
15.5M
            bytes = sizeof(pdf_keyword) + size - PDF_NAME_DECLARED_LENGTH;
70
15.5M
            break;
71
        /* The following aren't PDF object types, but are objects we either want to
72
         * reference count, or store on the stack.
73
         */
74
0
        case PDF_XREF_TABLE:
75
0
            bytes = sizeof(xref_table_t);
76
0
            break;
77
1.02M
        case PDF_STREAM:
78
1.02M
            bytes = sizeof(pdf_stream);
79
1.02M
            break;
80
0
        case PDF_NULL:
81
0
        case PDF_BOOL:
82
0
        default:
83
0
            code = gs_note_error(gs_error_typecheck);
84
0
            goto error_out;
85
784M
    }
86
784M
    *obj = (pdf_obj *)gs_alloc_bytes(ctx->memory, bytes, "pdfi_object_alloc");
87
784M
    if (*obj == NULL) {
88
0
        code = gs_note_error(gs_error_VMerror);
89
0
        goto error_out;
90
0
    }
91
92
784M
    memset(*obj, 0x00, bytes);
93
784M
    (*obj)->ctx = ctx;
94
784M
    (*obj)->type = type;
95
96
784M
    switch(type) {
97
/*      PDF_NULL and PDF_BOOL are now handled as special (not allocated) data types
98
        and we will return an error in the switch above if we get a call to allocate
99
        one of these. Having the cases isn't harmful but Coverity complains of dead
100
        code, so commenting these out to silence Coverity while preserving the old
101
        semantics to indicate what's happening.
102
        case PDF_NULL:
103
        case PDF_BOOL: */
104
105
208M
        case PDF_INT:
106
335M
        case PDF_REAL:
107
353M
        case PDF_INDIRECT:
108
368M
        case PDF_ARRAY_MARK:
109
381M
        case PDF_DICT_MARK:
110
381M
        case PDF_PROC_MARK:
111
381M
            break;
112
15.5M
        case PDF_KEYWORD:
113
89.1M
        case PDF_STRING:
114
373M
        case PDF_NAME:
115
373M
            ((pdf_string *)*obj)->length = size;
116
373M
            break;
117
40.9k
        case PDF_BUFFER:
118
40.9k
            {
119
40.9k
                pdf_buffer *b = (pdf_buffer *)*obj;
120
               /* NOTE: size can be 0 if the caller wants to allocate the data area itself
121
                */
122
40.9k
                if (size > 0) {
123
0
                    b->data = gs_alloc_bytes(ctx->memory, size, "pdfi_object_alloc");
124
0
                    if (b->data == NULL) {
125
0
                        code = gs_note_error(gs_error_VMerror);
126
0
                        goto error_out;
127
0
                    }
128
0
                }
129
40.9k
                else {
130
40.9k
                    b->data = NULL;
131
40.9k
                }
132
40.9k
                b->length = size;
133
40.9k
            }
134
0
            break;
135
14.8M
        case PDF_ARRAY:
136
14.8M
            {
137
14.8M
                pdf_obj **values = NULL;
138
139
14.8M
                ((pdf_array *)*obj)->size = size;
140
14.8M
                if (size > 0) {
141
13.8M
                    values = (pdf_obj **)gs_alloc_bytes(ctx->memory, size * sizeof(pdf_obj *), "pdfi_object_alloc");
142
13.8M
                    if (values == NULL) {
143
0
                        code = gs_note_error(gs_error_VMerror);
144
0
                        goto error_out;
145
0
                    }
146
13.8M
                    ((pdf_array *)*obj)->values = values;
147
13.8M
                    memset(((pdf_array *)*obj)->values, 0x00, size * sizeof(pdf_obj *));
148
13.8M
                }
149
14.8M
            }
150
14.8M
            break;
151
14.8M
        case PDF_DICT:
152
13.4M
            {
153
13.4M
                pdf_dict_entry *entries = NULL;
154
155
13.4M
                ((pdf_dict *)*obj)->size = size;
156
13.4M
                if (size > 0) {
157
12.7M
                    entries = (pdf_dict_entry *)gs_alloc_bytes(ctx->memory, size * sizeof(pdf_dict_entry), "pdfi_object_alloc");
158
12.7M
                    if (entries == NULL) {
159
0
                        code = gs_note_error(gs_error_VMerror);
160
0
                        goto error_out;
161
0
                    }
162
12.7M
                    ((pdf_dict *)*obj)->list = entries;
163
12.7M
                    memset(((pdf_dict *)*obj)->list, 0x00, size * sizeof(pdf_dict_entry));
164
12.7M
                }
165
13.4M
            }
166
13.4M
            break;
167
        /* The following aren't PDF object types, but are objects we either want to
168
         * reference count, or store on the stack.
169
         */
170
13.4M
        case PDF_XREF_TABLE:
171
0
            break;
172
1.02M
        default:
173
1.02M
            break;
174
784M
    }
175
#if REFCNT_DEBUG
176
    (*obj)->UID = ctx->ref_UID++;
177
    outprintf(ctx->memory, "Allocated object of type %c with UID %"PRIi64"\n", (*obj)->type, (*obj)->UID);
178
#endif
179
784M
    return 0;
180
0
error_out:
181
0
    gs_free_object(ctx->memory, *obj, "pdfi_object_alloc");
182
0
    *obj = NULL;
183
0
    return code;
184
784M
}
185
186
/* Create a PDF number object from a numeric value. Attempts to create
187
 * either a REAL or INT as appropriate. As usual for the alloc functions
188
 * this returns an object with a reference count of 0.
189
 */
190
int pdfi_num_alloc(pdf_context *ctx, double d, pdf_num **num)
191
8.99k
{
192
8.99k
    uint64_t test = 0;
193
8.99k
    int code = 0;
194
195
8.99k
    test = (uint64_t)floor(d);
196
8.99k
    if (d == test) {
197
6.28k
        code = pdfi_object_alloc(ctx, PDF_INT, 0, (pdf_obj **)num);
198
6.28k
        if (code < 0)
199
0
            return code;
200
6.28k
        (*num)->value.i = test;
201
6.28k
    }
202
2.70k
    else {
203
2.70k
        code = pdfi_object_alloc(ctx, PDF_REAL, 0, (pdf_obj **)num);
204
2.70k
        if (code < 0)
205
0
            return code;
206
2.70k
        (*num)->value.d = d;
207
2.70k
    }
208
209
8.99k
    return 0;
210
8.99k
}
211
212
/***********************************************************************************/
213
/* Functions to free the various kinds of 'PDF objects'.                           */
214
/* All objects are reference counted, newly allocated objects, as noted above have */
215
/* a reference count of 0. Pushing an object onto the stack increments             */
216
/* its reference count, popping it from the stack decrements its reference count.  */
217
/* When an object's reference count is decremented to 0, pdfi_countdown calls      */
218
/* pdfi_free_object() to free it.                                                  */
219
220
static void pdfi_free_namestring(pdf_obj *o)
221
358M
{
222
    /* Currently names and strings are the same, so a single cast is OK */
223
358M
    pdf_name *n = (pdf_name *)o;
224
225
358M
    gs_free_object(OBJ_MEMORY(n), n, "pdf interpreter free name or string");
226
358M
}
227
228
static void pdfi_free_keyword(pdf_obj *o)
229
15.5M
{
230
15.5M
    pdf_keyword *k = (pdf_keyword *)o;
231
232
15.5M
    gs_free_object(OBJ_MEMORY(k), k, "pdf interpreter free keyword");
233
15.5M
}
234
235
static void pdfi_free_xref_table(pdf_obj *o)
236
86.7k
{
237
86.7k
    xref_table_t *xref = (xref_table_t *)o;
238
239
86.7k
    gs_free_object(OBJ_MEMORY(xref), xref->xref, "pdfi_free_xref_table");
240
86.7k
    gs_free_object(OBJ_MEMORY(xref), xref, "pdfi_free_xref_table");
241
86.7k
}
242
243
static void pdfi_free_stream(pdf_obj *o)
244
1.02M
{
245
1.02M
    pdf_stream *stream = (pdf_stream *)o;
246
247
1.02M
    pdfi_countdown(stream->stream_dict);
248
1.02M
    gs_free_object(OBJ_MEMORY(o), o, "pdfi_free_stream");
249
1.02M
}
250
251
static void pdfi_free_buffer(pdf_obj *o)
252
40.9k
{
253
40.9k
    pdf_buffer *b = (pdf_buffer *)o;
254
255
40.9k
    gs_free_object(OBJ_MEMORY(b), b->data, "pdfi_free_buffer(data)");
256
40.9k
    gs_free_object(OBJ_MEMORY(o), o, "pdfi_free_buffer");
257
40.9k
}
258
259
void pdfi_free_object(pdf_obj *o)
260
786M
{
261
786M
    if (o == NULL)
262
712k
        return;
263
785M
    if ((intptr_t)o < (intptr_t)TOKEN__LAST_KEY)
264
0
        return;
265
785M
    switch(o->type) {
266
14.9M
        case PDF_ARRAY_MARK:
267
27.7M
        case PDF_DICT_MARK:
268
28.0M
        case PDF_PROC_MARK:
269
236M
        case PDF_INT:
270
363M
        case PDF_REAL:
271
381M
        case PDF_INDIRECT:
272
381M
            gs_free_object(OBJ_MEMORY(o), o, "pdf interpreter object refcount to 0");
273
381M
            break;
274
73.6M
        case PDF_STRING:
275
358M
        case PDF_NAME:
276
358M
            pdfi_free_namestring(o);
277
358M
            break;
278
40.9k
        case PDF_BUFFER:
279
40.9k
            pdfi_free_buffer(o);
280
40.9k
            break;
281
14.8M
        case PDF_ARRAY:
282
14.8M
            pdfi_free_array(o);
283
14.8M
            break;
284
13.3M
        case PDF_DICT:
285
13.3M
            pdfi_free_dict(o);
286
13.3M
            break;
287
1.02M
        case PDF_STREAM:
288
1.02M
            pdfi_free_stream(o);
289
1.02M
            break;
290
15.5M
        case PDF_KEYWORD:
291
15.5M
            pdfi_free_keyword(o);
292
15.5M
            break;
293
86.7k
        case PDF_XREF_TABLE:
294
86.7k
            pdfi_free_xref_table(o);
295
86.7k
            break;
296
986k
        case PDF_FONT:
297
986k
            pdfi_free_font(o);
298
986k
            break;
299
79.4k
        case PDF_CMAP:
300
79.4k
            pdfi_free_cmap(o);
301
79.4k
            break;
302
0
        case PDF_BOOL:
303
0
        case PDF_NULL:
304
0
            dbgmprintf(OBJ_MEMORY(o), "!!! Attempting to free non-allocated object type !!!\n");
305
0
            break;
306
53
        default:
307
53
            dbgmprintf(OBJ_MEMORY(o), "!!! Attempting to free unknown object type !!!\n");
308
53
            break;
309
785M
    }
310
785M
}
311
312
313
/* Convert a pdf_dict to a pdf_stream.
314
 * do_convert -- convert the stream to use same object num as dict
315
 *               (This assumes the dict has not been cached.)
316
 * The stream will come with 1 refcnt, dict refcnt will be incremented by 1.
317
 */
318
int pdfi_obj_dict_to_stream(pdf_context *ctx, pdf_dict *dict, pdf_stream **stream, bool do_convert)
319
1.02M
{
320
1.02M
    int code = 0;
321
1.02M
    pdf_stream *new_stream = NULL;
322
323
1.02M
    if (pdfi_type_of(dict) != PDF_DICT)
324
0
        return_error(gs_error_typecheck);
325
326
1.02M
    code = pdfi_object_alloc(ctx, PDF_STREAM, 0, (pdf_obj **)&new_stream);
327
1.02M
    if (code < 0)
328
0
        goto error_exit;
329
330
1.02M
    new_stream->ctx = ctx;
331
1.02M
    pdfi_countup(new_stream);
332
333
1.02M
    new_stream->stream_dict = dict;
334
1.02M
    pdfi_countup(dict);
335
336
    /* this replaces the dict with the stream.
337
     * assumes it's not cached
338
     */
339
1.02M
    if (do_convert) {
340
958k
        new_stream->object_num = dict->object_num;
341
958k
        new_stream->generation_num = dict->generation_num;
342
958k
        dict->object_num = 0;
343
958k
        dict->generation_num = 0;
344
958k
    }
345
1.02M
    *stream = new_stream;
346
1.02M
    return 0;
347
348
0
 error_exit:
349
0
    pdfi_countdown(new_stream);
350
0
    return code;
351
1.02M
}
352
353
int pdfi_get_stream_dict(pdf_context *ctx, pdf_stream *stream, pdf_dict **dict)
354
201
{
355
201
    *dict = stream->stream_dict;
356
357
    /* Make sure the dictionary won't go away */
358
201
    pdfi_countup(*dict);
359
201
    if ((*dict)->object_num == 0) {
360
0
        (*dict)->object_num = stream->object_num;
361
0
        (*dict)->generation_num = stream->generation_num;
362
0
    }
363
364
201
    return 0;
365
201
}
366
367
/* Create a pdf_string from a c char * */
368
int pdfi_obj_charstr_to_string(pdf_context *ctx, const char *charstr, pdf_string **string)
369
415
{
370
415
    int code;
371
415
    int length = strlen(charstr);
372
415
    pdf_string *newstr = NULL;
373
374
415
    *string = NULL;
375
376
415
    code = pdfi_object_alloc(ctx, PDF_STRING, length, (pdf_obj **)&newstr);
377
415
    if (code < 0) goto exit;
378
379
415
    memcpy(newstr->data, (byte *)charstr, length);
380
381
415
    *string = newstr;
382
415
    pdfi_countup(newstr);
383
415
 exit:
384
415
    return code;
385
415
}
386
387
/* Create a pdf_name from a c char * */
388
int pdfi_obj_charstr_to_name(pdf_context *ctx, const char *charstr, pdf_name **name)
389
803k
{
390
803k
    int code;
391
803k
    int length = strlen(charstr);
392
803k
    pdf_name *newname = NULL;
393
394
803k
    *name = NULL;
395
396
803k
    code = pdfi_object_alloc(ctx, PDF_NAME, length, (pdf_obj **)&newname);
397
803k
    if (code < 0) goto exit;
398
399
803k
    memcpy(newname->data, (byte *)charstr, length);
400
401
803k
    *name = newname;
402
803k
    pdfi_countup(newname);
403
803k
 exit:
404
803k
    return code;
405
803k
}
406
407
/************ bufstream module BEGIN **************/
408
11.7k
#define INIT_BUF_SIZE 256
409
410
typedef struct {
411
    int len;  /* Length of buffer */
412
    int cur;  /* Current position */
413
    byte *data;
414
} pdfi_bufstream_t;
415
416
417
static int pdfi_bufstream_init(pdf_context *ctx, pdfi_bufstream_t *stream)
418
11.7k
{
419
11.7k
    stream->len = INIT_BUF_SIZE;
420
11.7k
    stream->cur = 0;
421
11.7k
    stream->data = gs_alloc_bytes(ctx->memory, stream->len, "pdfi_bufstream_init(data)");
422
423
11.7k
    if (!stream->data)
424
0
        return_error(gs_error_VMerror);
425
11.7k
    return 0;
426
11.7k
}
427
428
static int pdfi_bufstream_free(pdf_context *ctx, pdfi_bufstream_t *stream)
429
11.7k
{
430
11.7k
    if (stream->data)
431
110
        gs_free_object(ctx->memory, stream->data, "pdfi_bufstream_free(data)");
432
11.7k
    stream->len = 0;
433
11.7k
    stream->cur = 0;
434
11.7k
    stream->data = NULL;
435
11.7k
    return 0;
436
11.7k
}
437
438
/* Grab a copy of the stream's buffer */
439
static int pdfi_bufstream_copy(pdf_context *ctx, pdfi_bufstream_t *stream, byte **buf, int *len)
440
11.5k
{
441
11.5k
    *buf = stream->data;
442
11.5k
    *len = stream->cur;
443
11.5k
    stream->len = 0;
444
11.5k
    stream->cur = 0;
445
11.5k
    stream->data = NULL;
446
11.5k
    return 0;
447
11.5k
}
448
449
/* Increase the size of the buffer by doubling and added the known needed amount */
450
static int pdfi_bufstream_increase(pdf_context *ctx, pdfi_bufstream_t *stream, uint64_t needed)
451
156
{
452
156
    byte *data = NULL;
453
156
    uint64_t newsize;
454
455
156
    newsize = stream->len * 2 + needed;
456
156
    data = gs_alloc_bytes(ctx->memory, newsize, "pdfi_bufstream_increase(data)");
457
156
    if (!data)
458
0
        return_error(gs_error_VMerror);
459
460
156
    memcpy(data, stream->data, stream->len);
461
156
    gs_free_object(ctx->memory, stream->data, "pdfi_bufstream_increase(data)");
462
156
    stream->data = data;
463
156
    stream->len = newsize;
464
465
156
    return 0;
466
156
}
467
468
static int pdfi_bufstream_write(pdf_context *ctx, pdfi_bufstream_t *stream, byte *data, uint64_t len)
469
99.6k
{
470
99.6k
    int code = 0;
471
472
99.6k
    if (stream->cur + len > stream->len) {
473
156
        code = pdfi_bufstream_increase(ctx, stream, len);
474
156
        if (code < 0)
475
0
            goto exit;
476
156
    }
477
99.6k
    memcpy(stream->data + stream->cur, data, len);
478
99.6k
    stream->cur += len;
479
480
99.6k
 exit:
481
99.6k
    return code;
482
99.6k
}
483
484
/************ bufstream module END **************/
485
486
487
/* Create a c-string to use as object label
488
 * Uses the object_num to make it unique.
489
 * (don't call this for objects with object_num=0, though I am not going to check that here)
490
 *
491
 * Bug #708127; just the object number alone is insufficient. Two consecutive input files might use the
492
 * same object number for a pdfmark, but with different content, we need to differntiate between the two.
493
 * Add a simple hash of the input filename (uses the same dumb but fast hash as pattern ID generation), this gives
494
 * the last bytes in the filename more say in the final result so is 'probably' sufficiently unique with the
495
 * object number and generation.
496
 */
497
int pdfi_obj_get_label(pdf_context *ctx, pdf_obj *obj, char **label)
498
7.81k
{
499
7.81k
    int code = 0, i;
500
7.81k
    int length;
501
7.81k
    const char *template = "{Obj%dG%dF%d}"; /* The '{' and '}' are special to pdfmark/pdfwrite driver */
502
7.81k
    char *string = NULL;
503
7.81k
    pdf_indirect_ref *ref = (pdf_indirect_ref *)obj;
504
7.81k
    uint32_t hash = 5381;
505
506
7.81k
    if (ctx->main_stream->s->file_name.data != NULL) {
507
0
        string = (char *)ctx->main_stream->s->file_name.data;
508
0
        length = ctx->main_stream->s->file_name.size;
509
510
0
        for (i=0;i < length;i++) {
511
#if ARCH_IS_BIG_ENDIAN
512
            hash = ((hash << 5) + hash) + string[length - 1 - i]; /* hash * 33 + c */
513
#else
514
0
            hash = ((hash << 5) + hash) + string[i]; /* hash * 33 + c */
515
0
#endif
516
0
        }
517
0
    }
518
519
7.81k
    *label = NULL;
520
7.81k
    length = strlen(template)+30;
521
522
7.81k
    string = (char *)gs_alloc_bytes(ctx->memory, length, "pdf_obj_get_label(label)");
523
7.81k
    if (string == NULL) {
524
0
        code = gs_note_error(gs_error_VMerror);
525
0
        goto exit;
526
0
    }
527
528
7.81k
    if (pdfi_type_of(obj) == PDF_INDIRECT)
529
7.80k
        gs_snprintf(string, length, template, ref->ref_object_num, ref->ref_generation_num, hash);
530
1
    else
531
1
        gs_snprintf(string, length, template, obj->object_num, obj->generation_num, hash);
532
533
7.81k
    *label = string;
534
7.81k
 exit:
535
7.81k
    return code;
536
7.81k
}
537
538
/*********** BEGIN obj_to_string module ************/
539
540
typedef int (*str_func)(pdf_context *ctx, pdf_obj *obj, byte **data, int *len);
541
542
/* Dispatch to get string representation of an object */
543
typedef struct {
544
    pdf_obj_type type;
545
    str_func func;
546
} obj_str_dispatch_t;
547
548
static int pdfi_obj_default_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
549
3
{
550
3
    int code = 0;
551
3
    int size = 12;
552
3
    byte *buf;
553
554
3
    buf = gs_alloc_bytes(ctx->memory, size, "pdfi_obj_default_str(data)");
555
3
    if (buf == NULL)
556
0
        return_error(gs_error_VMerror);
557
3
    memcpy(buf, "/placeholder", size);
558
3
    *data = buf;
559
3
    *len = size;
560
3
    return code;
561
3
}
562
563
static int pdfi_obj_name_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
564
38.3k
{
565
38.3k
    int code = 0;
566
38.3k
    pdf_name *name = (pdf_name *)obj;
567
38.3k
    int size = name->length + 1;
568
38.3k
    byte *buf;
569
570
38.3k
    buf = gs_alloc_bytes(ctx->memory, size, "pdfi_obj_name_str(data)");
571
38.3k
    if (buf == NULL)
572
0
        return_error(gs_error_VMerror);
573
38.3k
    buf[0] = '/';
574
38.3k
    memcpy(buf+1, name->data, name->length);
575
38.3k
    *data = buf;
576
38.3k
    *len = size;
577
38.3k
    return code;
578
38.3k
}
579
580
static int pdfi_obj_real_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
581
11.1k
{
582
11.1k
    int code = 0;
583
11.1k
    int size = 15;
584
11.1k
    pdf_num *number = (pdf_num *)obj;
585
11.1k
    char *buf;
586
587
11.1k
    buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_obj_real_str(data)");
588
11.1k
    if (buf == NULL)
589
0
        return_error(gs_error_VMerror);
590
11.1k
    snprintf(buf, size, "%.4f", number->value.d);
591
11.1k
    *data = (byte *)buf;
592
11.1k
    *len = strlen(buf);
593
11.1k
    return code;
594
11.1k
}
595
596
static int pdfi_obj_int_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
597
17.2k
{
598
17.2k
    int code = 0;
599
17.2k
    int size = 15;
600
17.2k
    pdf_num *number = (pdf_num *)obj;
601
17.2k
    char *buf;
602
603
17.2k
    buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_obj_int_str(data)");
604
17.2k
    if (buf == NULL)
605
0
        return_error(gs_error_VMerror);
606
17.2k
    snprintf(buf, size, "%"PRId64"", number->value.i);
607
17.2k
    *data = (byte *)buf;
608
17.2k
    *len = strlen(buf);
609
17.2k
    return code;
610
17.2k
}
611
612
static int pdfi_obj_getrefstr(pdf_context *ctx, uint64_t object_num, uint32_t generation, byte **data, int *len)
613
513
{
614
513
    int size = 100;
615
513
    char *buf;
616
617
513
    buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_obj_getrefstr(data)");
618
513
    if (buf == NULL)
619
0
        return_error(gs_error_VMerror);
620
513
    snprintf(buf, size, "%"PRId64" %d R", object_num, generation);
621
513
    *data = (byte *)buf;
622
513
    *len = strlen(buf);
623
513
    return 0;
624
513
}
625
626
static int pdfi_obj_indirect_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
627
8.48k
{
628
8.48k
    int code = 0;
629
8.48k
    pdf_indirect_ref *ref = (pdf_indirect_ref *)obj;
630
8.48k
    char *buf;
631
8.48k
    pdf_obj *object = NULL;
632
8.48k
    bool use_label = true;
633
634
8.48k
    code = pdfi_loop_detector_mark(ctx);
635
8.48k
    if (code < 0)
636
0
        return code;
637
638
8.48k
    if (ref->is_highlevelform) {
639
140
        code = pdfi_obj_getrefstr(ctx, ref->highlevel_object_num, 0, data, len);
640
140
        ref->is_highlevelform = false;
641
8.34k
    } else {
642
8.34k
        if (!ref->is_marking) {
643
4.12k
            code = pdfi_dereference(ctx, ref->ref_object_num, ref->ref_generation_num, &object);
644
4.12k
            if (code == gs_error_undefined) {
645
                /* Do something sensible for undefined reference (this would be a broken file) */
646
                /* TODO: Flag an error? */
647
373
                code = pdfi_obj_getrefstr(ctx, ref->ref_object_num, ref->ref_generation_num, data, len);
648
373
                goto exit;
649
373
            }
650
3.75k
            if (code < 0 && code != gs_error_circular_reference)
651
60
                goto exit;
652
3.69k
            if (code == 0) {
653
3.63k
                if (pdfi_type_of(object) == PDF_STREAM) {
654
210
                    code = pdfi_pdfmark_stream(ctx, (pdf_stream *)object);
655
210
                    if (code < 0) goto exit;
656
3.42k
                } else if (pdfi_type_of(object) == PDF_DICT) {
657
3.36k
                    code = pdfi_pdfmark_dict(ctx, (pdf_dict *)object);
658
3.36k
                    if (code < 0) goto exit;
659
3.36k
                } else {
660
60
                    code = pdfi_obj_to_string(ctx, object, data, len);
661
60
                    if (code < 0) goto exit;
662
49
                    use_label = false;
663
49
                }
664
3.63k
            }
665
3.69k
        }
666
7.85k
        if (use_label) {
667
7.80k
            code = pdfi_obj_get_label(ctx, (pdf_obj *)ref, &buf);
668
7.80k
            if (code < 0) goto exit;
669
7.80k
            *data = (byte *)buf;
670
7.80k
            *len = strlen(buf);
671
7.80k
        }
672
7.85k
    }
673
674
8.48k
 exit:
675
8.48k
    (void)pdfi_loop_detector_cleartomark(ctx);
676
8.48k
    pdfi_countdown(object);
677
8.48k
    return code;
678
8.48k
}
679
680
static int pdfi_obj_bool_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
681
259
{
682
259
    int code = 0;
683
259
    int size = 5;
684
259
    char *buf;
685
686
259
    buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_obj_bool_str(data)");
687
259
    if (buf == NULL)
688
0
        return_error(gs_error_VMerror);
689
259
    if (obj == PDF_TRUE_OBJ) {
690
148
        memcpy(buf, (byte *)"true", 4);
691
148
        *len = 4;
692
148
    } else {
693
111
        memcpy(buf, (byte *)"false", 5);
694
111
        *len = 5;
695
111
    }
696
259
    *data = (byte *)buf;
697
259
    return code;
698
259
}
699
700
static int pdfi_obj_null_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
701
256
{
702
256
    int code = 0;
703
256
    int size = 4;
704
256
    char *buf;
705
706
256
    buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_obj_null_str(data)");
707
256
    if (buf == NULL)
708
0
        return_error(gs_error_VMerror);
709
256
    memcpy(buf, (byte *)"null", 4);
710
256
    *len = 4;
711
256
    *data = (byte *)buf;
712
256
    return code;
713
256
}
714
715
static int pdfi_obj_string_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
716
4.60k
{
717
4.60k
    pdf_string *string = (pdf_string *)obj;
718
4.60k
    char *buf;
719
4.60k
    int i, length = 0, j;
720
721
172k
    for (j=0;j<string->length;j++) {
722
167k
        if (string->data[j] == 0x0a || string->data[j] == 0x0d || string->data[j] == '(' || string->data[j] == ')' || string->data[j] == '\\')
723
540
                length += 2;
724
167k
        else {
725
167k
            if (string->data[j] < 0x20 || string->data[j] > 0x7F || string->data[j] == '\\')
726
7.06k
                length += 4;
727
160k
            else
728
160k
                length++;
729
167k
        }
730
167k
    }
731
4.60k
    length += 2;
732
4.60k
    buf = (char *)gs_alloc_bytes(ctx->memory, length, "pdfi_obj_string_str(data)");
733
4.60k
    if (buf == NULL)
734
0
        return_error(gs_error_VMerror);
735
4.60k
    buf[0] = '(';
736
4.60k
    i = 1;
737
172k
    for (j=0;j<string->length;j++) {
738
167k
        switch(string->data[j]) {
739
162
            case 0x0a:
740
162
                buf[i++] = '\\';
741
162
                buf[i++] = 'n';
742
162
                break;
743
12
            case 0x0d:
744
12
                buf[i++] = '\\';
745
12
                buf[i++] = 'r';
746
12
                break;
747
181
            case '(':
748
363
            case ')':
749
366
            case '\\':
750
366
                buf[i++] = '\\';
751
366
                buf[i++] = string->data[j];
752
366
                break;
753
167k
            default:
754
167k
                if (string->data[j] < 0x20 || string->data[j] > 0x7F) {
755
7.06k
                    buf[i++] = '\\';
756
7.06k
                    buf[i++] = (string->data[j] >> 6) + 0x30;
757
7.06k
                    buf[i++] = ((string->data[j] & 0x3F) >> 3) + 0x30;
758
7.06k
                    buf[i++] = (string->data[j] & 0x07) + 0x30;
759
7.06k
                } else
760
160k
                buf[i++] = string->data[j];
761
167k
                break;
762
167k
        }
763
167k
    }
764
4.60k
    buf[i++] = ')';
765
766
4.60k
    *len = i;
767
4.60k
    *data = (byte *)buf;
768
4.60k
    return 0;
769
4.60k
}
770
771
static int pdfi_obj_array_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
772
4.77k
{
773
4.77k
    int code = 0;
774
4.77k
    pdf_array *array = (pdf_array *)obj;
775
4.77k
    pdf_obj *object = NULL;
776
4.77k
    byte *itembuf = NULL;
777
4.77k
    int itemsize;
778
4.77k
    pdfi_bufstream_t bufstream;
779
4.77k
    uint64_t index, arraysize;
780
781
4.77k
    code = pdfi_bufstream_init(ctx, &bufstream);
782
4.77k
    if (code < 0) goto exit;
783
784
4.77k
    code = pdfi_bufstream_write(ctx, &bufstream, (byte *)"[", 1);
785
4.77k
    if (code < 0) goto exit;
786
787
4.77k
    arraysize = pdfi_array_size(array);
788
30.8k
    for (index = 0; index < arraysize; index++) {
789
26.0k
        code = pdfi_array_get_no_deref(ctx, array, index, &object);
790
26.0k
        if (code < 0) goto exit;
791
792
26.0k
        code = pdfi_obj_to_string(ctx, object, &itembuf, &itemsize);
793
26.0k
        if (code < 0) goto exit;
794
795
26.0k
        code = pdfi_bufstream_write(ctx, &bufstream, itembuf, itemsize);
796
26.0k
        if (code < 0) goto exit;
797
798
26.0k
        gs_free_object(ctx->memory, itembuf, "pdfi_obj_array_str(itembuf)");
799
26.0k
        itembuf = NULL;
800
26.0k
        itemsize = 0;
801
26.0k
        pdfi_countdown(object);
802
26.0k
        object = NULL;
803
804
        /* Put a space between elements unless last item */
805
26.0k
        if (index+1 != arraysize) {
806
21.3k
            code = pdfi_bufstream_write(ctx, &bufstream, (byte *)" ", 1);
807
21.3k
            if (code < 0) goto exit;
808
21.3k
        }
809
26.0k
    }
810
811
4.73k
    code = pdfi_bufstream_write(ctx, &bufstream, (byte *)"]", 1);
812
4.73k
    if (code < 0) goto exit;
813
814
    /* Now copy the results out into the string we can keep */
815
4.73k
    code = pdfi_bufstream_copy(ctx, &bufstream, data, len);
816
817
4.77k
 exit:
818
4.77k
    if (itembuf)
819
0
        gs_free_object(ctx->memory, itembuf, "pdfi_obj_array_str(itembuf)");
820
4.77k
    pdfi_bufstream_free(ctx, &bufstream);
821
4.77k
    pdfi_countdown(object);
822
4.77k
    return code;
823
4.73k
}
824
825
static int pdfi_obj_stream_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
826
221
{
827
221
    int code = 0;
828
221
    byte *buf;
829
221
    pdf_stream *stream = (pdf_stream *)obj;
830
221
    int64_t bufsize = 0;
831
221
    pdf_indirect_ref *streamref = NULL;
832
833
    /* TODO: How to deal with stream dictionaries?
834
     * /AP is one example that has special handling (up in pdf_annot.c), but there are others.
835
     * See 'pushpin' annotation in annotations-galore_II.ps
836
     *
837
     * This will just literally grab the stream data.
838
     */
839
221
    if (stream->is_marking) {
840
195
        code = pdfi_stream_to_buffer(ctx, stream, &buf, &bufsize);
841
195
        if (code < 0) goto exit;
842
195
        *data = buf;
843
195
        *len = (int)bufsize;
844
195
    } else {
845
        /* Create an indirect ref for the stream */
846
26
        code = pdfi_object_alloc(ctx, PDF_INDIRECT, 0, (pdf_obj **)&streamref);
847
26
        if (code < 0) goto exit;
848
26
        pdfi_countup(streamref);
849
26
        streamref->ref_object_num = stream->object_num;
850
26
        streamref->ref_generation_num = stream->generation_num;
851
26
        code = pdfi_obj_indirect_str(ctx, (pdf_obj *)streamref, data, len);
852
26
    }
853
854
221
 exit:
855
221
    pdfi_countdown(streamref);
856
221
    return code;
857
221
}
858
859
/* This fetches without dereferencing.  If you want to see the references inline,
860
 * then you need to pre-resolve them.  See pdfi_resolve_indirect().
861
 */
862
static int pdfi_obj_dict_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
863
6.93k
{
864
6.93k
    int code = 0;
865
6.93k
    pdf_dict *dict = (pdf_dict *)obj;
866
6.93k
    pdf_name *Key = NULL;
867
6.93k
    pdf_obj *Value = NULL;
868
6.93k
    byte *itembuf = NULL;
869
6.93k
    int itemsize;
870
6.93k
    pdfi_bufstream_t bufstream;
871
6.93k
    uint64_t index, dictsize;
872
6.93k
    uint64_t itemnum = 0;
873
874
6.93k
    code = pdfi_loop_detector_mark(ctx);
875
6.93k
    if (code < 0)
876
0
        return code;
877
878
6.93k
    code = pdfi_bufstream_init(ctx, &bufstream);
879
6.93k
    if (code < 0) goto exit;
880
881
6.93k
    dictsize = pdfi_dict_entries(dict);
882
    /* Handle empty dict specially */
883
6.93k
    if (dictsize == 0) {
884
1
        code = pdfi_bufstream_write(ctx, &bufstream, (byte *)"<< >>", 5);
885
1
        if (code < 0)
886
0
            goto exit;
887
1
        goto exit_copy;
888
1
    }
889
890
6.92k
    code = pdfi_bufstream_write(ctx, &bufstream, (byte *)"<<\n", 3);
891
6.92k
    if (code < 0) goto exit;
892
893
    /* Note: We specifically fetch without dereferencing, so there will be no circular
894
     * references to handle here.
895
     */
896
    /* Wrong.... */
897
898
6.92k
    if (dict->object_num !=0 ) {
899
350
        if (pdfi_loop_detector_check_object(ctx, dict->object_num)) {
900
1
            code = gs_note_error(gs_error_circular_reference);
901
1
            goto exit;
902
1
        }
903
349
        code = pdfi_loop_detector_add_object(ctx, dict->object_num);
904
349
        if (code < 0)
905
0
            goto exit;
906
349
    }
907
908
    /* Get each (key,val) pair from dict and setup param for it */
909
6.92k
    code = pdfi_dict_key_first(ctx, dict, (pdf_obj **)&Key, &index);
910
8.99k
    while (code >= 0) {
911
8.99k
        code = pdfi_obj_to_string(ctx, (pdf_obj *)Key, &itembuf, &itemsize);
912
8.99k
        if (code < 0) goto exit;
913
914
8.99k
        code = pdfi_bufstream_write(ctx, &bufstream, itembuf, itemsize);
915
8.99k
        if (code < 0) goto exit;
916
917
8.99k
        gs_free_object(ctx->memory, itembuf, "pdfi_obj_dict_str(itembuf)");
918
8.99k
        itembuf = NULL;
919
8.99k
        itemsize = 0;
920
921
        /* Put a space between elements */
922
8.99k
        code = pdfi_bufstream_write(ctx, &bufstream, (byte *)" ", 1);
923
8.99k
        if (code < 0) goto exit;
924
925
        /* No dereference */
926
8.99k
        code = pdfi_dict_get_no_deref(ctx, dict, (const pdf_name *)Key, &Value);
927
8.99k
        if (code < 0) goto exit;
928
8.99k
        code = pdfi_obj_to_string(ctx, Value, &itembuf, &itemsize);
929
8.99k
        if (code < 0) goto exit;
930
931
8.92k
        code = pdfi_bufstream_write(ctx, &bufstream, itembuf, itemsize);
932
8.92k
        if (code < 0) goto exit;
933
934
8.92k
        gs_free_object(ctx->memory, itembuf, "pdfi_obj_dict_str(itembuf)");
935
8.92k
        itembuf = NULL;
936
8.92k
        itemsize = 0;
937
938
8.92k
        pdfi_countdown(Value);
939
8.92k
        Value = NULL;
940
8.92k
        pdfi_countdown(Key);
941
8.92k
        Key = NULL;
942
943
8.92k
        code = pdfi_dict_key_next(ctx, dict, (pdf_obj **)&Key, &index);
944
8.92k
        if (code == gs_error_undefined) {
945
6.86k
            code = 0;
946
6.86k
            break;
947
6.86k
        }
948
2.06k
        if (code < 0) goto exit;
949
950
        /* Put a space between elements */
951
2.06k
        if (++itemnum != dictsize) {
952
2.06k
            code = pdfi_bufstream_write(ctx, &bufstream, (byte *)" ", 1);
953
2.06k
            if (code < 0) goto exit;
954
2.06k
        }
955
2.06k
    }
956
6.86k
    if (code < 0) goto exit;
957
958
6.86k
    code = pdfi_bufstream_write(ctx, &bufstream, (byte *)"\n>>", 3);
959
6.86k
    if (code < 0) goto exit;
960
961
6.86k
 exit_copy:
962
    /* Now copy the results out into the string we can keep */
963
6.86k
    code = pdfi_bufstream_copy(ctx, &bufstream, data, len);
964
965
6.93k
 exit:
966
6.93k
    if (itembuf)
967
0
        gs_free_object(ctx->memory, itembuf, "pdfi_obj_dict_str(itembuf)");
968
6.93k
    pdfi_countdown(Key);
969
6.93k
    pdfi_countdown(Value);
970
6.93k
    pdfi_bufstream_free(ctx, &bufstream);
971
6.93k
    if (code < 0)
972
66
        (void)pdfi_loop_detector_cleartomark(ctx);
973
6.86k
    else
974
6.86k
        code = pdfi_loop_detector_cleartomark(ctx);
975
6.93k
    return code;
976
6.86k
}
977
978
#define PARAM1(A) # A,
979
#define PARAM2(A,B) A,
980
static const char pdf_token_strings[][10] = {
981
#include "pdf_tokens.h"
982
};
983
984
static int pdfi_obj_fast_keyword_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
985
0
{
986
0
    int code = 0;
987
0
    const char *s = pdf_token_strings[(uintptr_t)obj];
988
0
    int size = (int)strlen(s) + 1;
989
0
    byte *buf;
990
991
0
    buf = gs_alloc_bytes(ctx->memory, size, "pdfi_obj_name_str(data)");
992
0
    if (buf == NULL)
993
0
        return_error(gs_error_VMerror);
994
0
    memcpy(buf, s, size);
995
0
    *data = buf;
996
0
    *len = size;
997
0
    return code;
998
0
}
999
1000
obj_str_dispatch_t obj_str_dispatch[] = {
1001
    {PDF_NAME, pdfi_obj_name_str},
1002
    {PDF_ARRAY, pdfi_obj_array_str},
1003
    {PDF_REAL, pdfi_obj_real_str},
1004
    {PDF_INT, pdfi_obj_int_str},
1005
    {PDF_BOOL, pdfi_obj_bool_str},
1006
    {PDF_STRING, pdfi_obj_string_str},
1007
    {PDF_DICT, pdfi_obj_dict_str},
1008
    {PDF_STREAM, pdfi_obj_stream_str},
1009
    {PDF_INDIRECT, pdfi_obj_indirect_str},
1010
    {PDF_NULL, pdfi_obj_null_str},
1011
    {PDF_FAST_KEYWORD, pdfi_obj_fast_keyword_str},
1012
    {0, NULL}
1013
};
1014
1015
/* Recursive function to build a string from an object
1016
 */
1017
int pdfi_obj_to_string(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
1018
92.3k
{
1019
92.3k
    obj_str_dispatch_t *dispatch_ptr;
1020
92.3k
    int code = 0;
1021
92.3k
    pdf_obj_type type;
1022
1023
92.3k
    *data = NULL;
1024
92.3k
    *len = 0;
1025
92.3k
    type = pdfi_type_of(obj);
1026
308k
    for (dispatch_ptr = obj_str_dispatch; dispatch_ptr->func; dispatch_ptr ++) {
1027
308k
        if (type == dispatch_ptr->type) {
1028
92.2k
            code = dispatch_ptr->func(ctx, obj, data, len);
1029
92.2k
            goto exit;
1030
92.2k
        }
1031
308k
    }
1032
    /* Not implemented, use default */
1033
3
    code = pdfi_obj_default_str(ctx, obj, data, len);
1034
92.3k
 exit:
1035
92.3k
    return code;
1036
3
}
1037
1038
/*********** END obj_to_string module ************/