Coverage Report

Created: 2025-06-10 07:24

/src/ghostpdl/pdf/ghostpdf.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2018-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
/* Top level PDF access routines */
17
#include "ghostpdf.h"
18
#include "pdf_types.h"
19
#include "pdf_dict.h"
20
#include "pdf_array.h"
21
#include "pdf_int.h"
22
#include "pdf_misc.h"
23
#include "pdf_stack.h"
24
#include "pdf_file.h"
25
#include "pdf_loop_detect.h"
26
#include "pdf_trans.h"
27
#include "pdf_font_types.h"
28
#include "pdf_gstate.h"
29
#include "stream.h"
30
#include "strmio.h"
31
#include "pdf_colour.h"
32
#include "pdf_font.h"
33
#include "pdf_text.h"
34
#include "pdf_page.h"
35
#include "pdf_check.h"
36
#include "pdf_optcontent.h"
37
#include "pdf_sec.h"
38
#include "pdf_doc.h"
39
#include "pdf_repair.h"
40
#include "pdf_xref.h"
41
#include "pdf_device.h"
42
#include "pdf_mark.h"
43
44
#include "gsstate.h"        /* For gs_gstate */
45
#include "gsicc_manage.h"  /* For gsicc_init_iccmanager() */
46
47
#if PDFI_LEAK_CHECK
48
#include "gsmchunk.h"
49
#endif
50
51
#ifndef USE_PDF_PERMISSIONS
52
#define USE_PDF_PERMISSIONS 0
53
#endif
54
55
extern const char gp_file_name_list_separator;
56
/*
57
 * Convenience routine to check if a given string exists in a dictionary
58
 * verify its contents and print it in a particular fashion to stdout. This
59
 * is used to display information about the PDF in response to -dPDFINFO
60
 */
61
static int dump_info_string(pdf_context *ctx, pdf_dict *source_dict, const char *Key)
62
0
{
63
0
    int code;
64
0
    pdf_string *s = NULL;
65
0
    char *Cstr;
66
67
0
    code = pdfi_dict_knownget_type(ctx, source_dict, Key, PDF_STRING, (pdf_obj **)&s);
68
0
    if (code > 0) {
69
0
        Cstr = (char *)gs_alloc_bytes(ctx->memory, s->length + 1, "Working memory for string dumping");
70
0
        if (Cstr) {
71
0
            memcpy(Cstr, s->data, s->length);
72
0
            Cstr[s->length] = 0x00;
73
0
            outprintf(ctx->memory, "%s: %s\n", Key, Cstr);
74
0
            gs_free_object(ctx->memory, Cstr, "Working memory for string dumping");
75
0
        }
76
0
        code = 0;
77
0
    }
78
0
    pdfi_countdown(s);
79
80
0
    return code;
81
0
}
82
83
static int pdfi_output_metadata(pdf_context *ctx)
84
0
{
85
0
    int code = 0;
86
87
0
    if (ctx->filename != NULL)
88
0
        outprintf(ctx->memory, "\n        %s has %"PRIi64" ", ctx->filename, ctx->num_pages);
89
0
    else
90
0
        outprintf(ctx->memory, "\n        File has %"PRIi64" ", ctx->num_pages);
91
92
0
    if (ctx->num_pages > 1)
93
0
        outprintf(ctx->memory, "pages\n\n");
94
0
    else
95
0
        outprintf(ctx->memory, "page.\n\n");
96
97
0
    if (ctx->Info != NULL) {
98
0
        pdf_name *n = NULL;
99
0
        char *Cstr;
100
101
0
        code = dump_info_string(ctx, ctx->Info, "Title");
102
0
        if (code < 0) {
103
0
            if (ctx->args.pdfstoponerror)
104
0
                return code;
105
0
        }
106
107
0
        code = dump_info_string(ctx, ctx->Info, "Author");
108
0
        if (code < 0) {
109
0
            if (ctx->args.pdfstoponerror)
110
0
                return code;
111
0
        }
112
113
0
        code = dump_info_string(ctx, ctx->Info, "Subject");
114
0
        if (code < 0) {
115
0
            if (ctx->args.pdfstoponerror)
116
0
                return code;
117
0
        }
118
119
0
        code = dump_info_string(ctx, ctx->Info, "Keywords");
120
0
        if (code < 0) {
121
0
            if (ctx->args.pdfstoponerror)
122
0
                return code;
123
0
        }
124
125
0
        code = dump_info_string(ctx, ctx->Info, "Creator");
126
0
        if (code < 0) {
127
0
            if (ctx->args.pdfstoponerror)
128
0
                return code;
129
0
        }
130
131
0
        code = dump_info_string(ctx, ctx->Info, "Producer");
132
0
        if (code < 0) {
133
0
            if (ctx->args.pdfstoponerror)
134
0
                return code;
135
0
        }
136
137
0
        code = dump_info_string(ctx, ctx->Info, "CreationDate");
138
0
        if (code < 0) {
139
0
            if (ctx->args.pdfstoponerror)
140
0
                return code;
141
0
        }
142
143
0
        code = dump_info_string(ctx, ctx->Info, "ModDate");
144
0
        if (code < 0) {
145
0
            if (ctx->args.pdfstoponerror)
146
0
                return code;
147
0
        }
148
149
150
0
        code = pdfi_dict_knownget_type(ctx, ctx->Info, "Trapped", PDF_NAME, (pdf_obj **)&n);
151
0
        if (code > 0) {
152
0
            Cstr = (char *)gs_alloc_bytes(ctx->memory, n->length + 1, "Working memory for string dumping");
153
0
            if (Cstr) {
154
0
                memcpy(Cstr, n->data, n->length);
155
0
                Cstr[n->length] = 0x00;
156
0
                outprintf(ctx->memory, "Trapped: %s\n\n", Cstr);
157
0
                gs_free_object(ctx->memory, Cstr, "Working memory for string dumping");
158
0
            }
159
0
            code = 0;
160
0
        }
161
0
        pdfi_countdown(n);
162
0
        n = NULL;
163
0
    }
164
0
    outprintf(ctx->memory, "\n");
165
0
    return code;
166
0
}
167
168
/*
169
 * Convenience routine to check if a given *Box exists in a page dictionary
170
 * verify its contents and print it in a particular fashion to stdout. This
171
 * is used to display information about the PDF in response to -dPDFINFO
172
 */
173
static int pdfi_dump_box(pdf_context *ctx, pdf_dict *page_dict, const char *Key)
174
0
{
175
0
    int code, i;
176
0
    pdf_array *a = NULL;
177
0
    double f;
178
179
0
    code = pdfi_dict_knownget_type(ctx, page_dict, Key, PDF_ARRAY, (pdf_obj **)&a);
180
0
    if (code > 0) {
181
0
        if (pdfi_array_size(a) != 4) {
182
0
            outprintf(ctx->memory, "Error - %s does not contain 4 values.\n", Key);
183
0
            code = gs_note_error(gs_error_rangecheck);
184
0
        } else {
185
0
            outprintf(ctx->memory, " %s: [", Key);
186
0
            for (i = 0; i < pdfi_array_size(a); i++) {
187
0
                code = pdfi_array_get_number(ctx, a, (uint64_t)i, &f);
188
0
                if (i != 0)
189
0
                    outprintf(ctx->memory, " ");
190
0
                if (code == 0) {
191
0
                    if (pdfi_type_of(a->values[i]) == PDF_INT)
192
0
                        outprintf(ctx->memory, "%"PRIi64"", ((pdf_num *)a->values[i])->value.i);
193
0
                    else
194
0
                        outprintf(ctx->memory, "%f", ((pdf_num *)a->values[i])->value.d);
195
0
                } else {
196
0
                    outprintf(ctx->memory, "NAN");
197
0
                }
198
0
            }
199
0
            outprintf(ctx->memory, "]");
200
0
        }
201
0
    }
202
0
    pdfi_countdown(a);
203
0
    return code;
204
0
}
205
206
static int dump_font(pdf_context *ctx, pdf_dict *font_dict, bool space_name)
207
0
{
208
0
    pdf_obj *obj = NULL;
209
0
    char *str = NULL;
210
0
    int len = 0, code = 0, i;
211
0
    bool known = false, type0 = false;
212
213
0
    code = pdfi_dict_get_type(ctx, font_dict, "BaseFont", PDF_NAME, &obj);
214
0
    if (code >= 0) {
215
0
        code = pdfi_string_from_name(ctx, (pdf_name *)obj, &str, &len);
216
0
        if (code >= 0) {
217
0
            outprintf(ctx->memory, "%s", str);
218
0
            if (len < 32 && space_name) {
219
0
                for (i = 0; i < 32 - len;i++)
220
0
                    outprintf(ctx->memory, " ");
221
0
            } else
222
0
                outprintf(ctx->memory, "    ");
223
0
            (void)pdfi_free_string_from_name(ctx, str);
224
0
        }
225
0
        pdfi_countdown(obj);
226
0
        obj = NULL;
227
0
    }
228
229
0
    code = pdfi_dict_get_type(ctx, font_dict, "Subtype", PDF_NAME, &obj);
230
0
    if (code >= 0) {
231
0
        code = pdfi_string_from_name(ctx, (pdf_name *)obj, &str, &len);
232
0
        if (code >= 0) {
233
0
            outprintf(ctx->memory, "%s", str);
234
0
            for (i = 0; i < 16 - len;i++)
235
0
                outprintf(ctx->memory, " ");
236
0
            (void)pdfi_free_string_from_name(ctx, str);
237
0
        }
238
0
        if (pdfi_name_is((pdf_name *)obj, "Type0"))
239
0
            type0 = true;
240
0
        pdfi_countdown(obj);
241
0
        obj = NULL;
242
0
    }
243
244
0
    if (!type0) {
245
0
        code = pdfi_dict_get_type(ctx, font_dict, "Embedded", PDF_BOOL, &obj);
246
0
        if (code >= 0) {
247
0
            if (obj == PDF_FALSE_OBJ)
248
0
                outprintf(ctx->memory, "Not embedded    ");
249
0
            else
250
0
                outprintf(ctx->memory, "Embedded        ");
251
0
            pdfi_countdown(obj);
252
0
            obj = NULL;
253
0
        }
254
0
        else
255
0
            outprintf(ctx->memory, "Not embedded    ");
256
0
    } else
257
0
        outprintf(ctx->memory, "                ");
258
259
0
    code = pdfi_dict_get_type(ctx, font_dict, "ToUnicode", PDF_BOOL, &obj);
260
0
    if (code >= 0) {
261
0
        if (obj == PDF_TRUE_OBJ)
262
0
            outprintf(ctx->memory, "Has ToUnicode    ");
263
0
        else
264
0
            outprintf(ctx->memory, "No ToUnicode     ");
265
0
        pdfi_countdown(obj);
266
0
        obj = NULL;
267
0
    }
268
0
    else
269
0
        outprintf(ctx->memory, "No ToUnicode    ");
270
271
0
    code = pdfi_dict_known(ctx, font_dict, "Descendants", &known);
272
0
    if (code >= 0 && known) {
273
0
        code = pdfi_dict_get_type(ctx, font_dict, "Descendants", PDF_ARRAY, &obj);
274
0
        if (code >= 0) {
275
0
            pdf_obj *desc = NULL;
276
277
0
            code = pdfi_array_get_type(ctx, (pdf_array *)obj, 0, PDF_DICT, &desc);
278
0
            if (code >= 0) {
279
0
                outprintf(ctx->memory, "\n            Descendants: [");
280
0
                (void)dump_font(ctx, (pdf_dict *)desc, false);
281
0
                outprintf(ctx->memory, "]");
282
0
            }
283
0
            pdfi_countdown(obj);
284
0
            obj = NULL;
285
0
        }
286
0
    }
287
0
    return 0;
288
0
}
289
290
/*
291
 * This routine along with pdfi_output_metadtaa above, dumps certain kinds
292
 * of metadata from the PDF file, and from each page in the PDF file. It is
293
 * intended to duplicate the pdf_info.ps functionality of the PostScript-based
294
 * PDF interpreter in Ghostscript.
295
 *
296
 * It is not yet complete, we don't allow an option for dumping media sizes
297
 * we always emit them, and the switches -dDumpFontsNeeded, -dDumpXML,
298
 * -dDumpFontsUsed and -dShowEmbeddedFonts are not implemented at all yet.
299
 */
300
int pdfi_output_page_info(pdf_context *ctx, uint64_t page_num)
301
0
{
302
0
    int code;
303
0
    bool known = false;
304
0
    double f;
305
0
    pdf_dict *page_dict = NULL;
306
0
    pdf_array *fonts_array = NULL, *spots_array = NULL;
307
308
0
    code = pdfi_page_get_dict(ctx, page_num, &page_dict);
309
0
    if (code < 0)
310
0
        return code;
311
312
0
    outprintf(ctx->memory, "Page %"PRIi64"", page_num + 1);
313
314
0
    code = pdfi_dict_knownget_number(ctx, page_dict, "UserUnit", &f);
315
0
    if (code > 0)
316
0
        outprintf(ctx->memory, " UserUnit: %f ", f);
317
0
    if (code < 0) {
318
0
        pdfi_countdown(page_dict);
319
0
        return code;
320
0
    }
321
322
0
    code = pdfi_dump_box(ctx, page_dict, "MediaBox");
323
0
    if (code < 0) {
324
0
        if (code != gs_error_undefined && ctx->args.pdfstoponerror) {
325
0
            pdfi_countdown(page_dict);
326
0
            return code;
327
0
        }
328
0
    }
329
330
0
    code = pdfi_dump_box(ctx, page_dict, "CropBox");
331
0
    if (code < 0) {
332
0
        if (code != gs_error_undefined && ctx->args.pdfstoponerror) {
333
0
            pdfi_countdown(page_dict);
334
0
            return code;
335
0
        }
336
0
    }
337
338
0
    code = pdfi_dump_box(ctx, page_dict, "BleedBox");
339
0
    if (code < 0) {
340
0
        if (code != gs_error_undefined && ctx->args.pdfstoponerror) {
341
0
            pdfi_countdown(page_dict);
342
0
            return code;
343
0
        }
344
0
    }
345
346
0
    code = pdfi_dump_box(ctx, page_dict, "TrimBox");
347
0
    if (code < 0) {
348
0
        if (code != gs_error_undefined && ctx->args.pdfstoponerror) {
349
0
            pdfi_countdown(page_dict);
350
0
            return code;
351
0
        }
352
0
    }
353
354
0
    code = pdfi_dump_box(ctx, page_dict, "ArtBox");
355
0
    if (code < 0) {
356
0
        if (code != gs_error_undefined && ctx->args.pdfstoponerror) {
357
0
            pdfi_countdown(page_dict);
358
0
            return code;
359
0
        }
360
0
    }
361
362
0
    code = pdfi_dict_knownget_number(ctx, page_dict, "Rotate", &f);
363
0
    if (code > 0)
364
0
        outprintf(ctx->memory, "    Rotate = %d ", (int)f);
365
0
    if (code < 0) {
366
0
        pdfi_countdown(page_dict);
367
0
        return code;
368
0
    }
369
370
0
    code = pdfi_check_page(ctx, page_dict, &fonts_array, &spots_array, false);
371
0
    if (code < 0) {
372
0
        if (ctx->args.pdfstoponerror)
373
0
            return code;
374
0
    } else {
375
0
        if (ctx->page.has_transparency)
376
0
            outprintf(ctx->memory, "     Page uses transparency features");
377
0
    }
378
379
0
    code = pdfi_dict_known(ctx, page_dict, "Annots", &known);
380
0
    if (code < 0) {
381
0
        if (code != gs_error_undefined && ctx->args.pdfstoponerror)
382
0
            goto error;
383
0
    } else {
384
0
        if (known == true)
385
0
            outprintf(ctx->memory, "     Page contains Annotations");
386
0
        code = 0;
387
0
    }
388
389
0
    if (spots_array != NULL) {
390
0
        uint64_t index = 0;
391
0
        pdf_name *spot = NULL;
392
0
        char *str = NULL;
393
0
        int len;
394
395
0
        outprintf(ctx->memory, "\n    Page Spot colors: \n");
396
0
        for (index = 0;index < pdfi_array_size(spots_array);index++) {
397
0
            code = pdfi_array_get(ctx, spots_array, index, (pdf_obj **)&spot);
398
0
            if (code >= 0) {
399
0
                if (pdfi_type_of(spot) == PDF_NAME) {
400
0
                    code = pdfi_string_from_name(ctx, spot, &str, &len);
401
0
                    if (code >= 0) {
402
0
                        outprintf(ctx->memory, "        '%s'\n", str);
403
0
                        (void)pdfi_free_string_from_name(ctx, str);
404
0
                    }
405
0
                }
406
0
                pdfi_countdown(spot);
407
0
                spot = NULL;
408
0
            }
409
0
        }
410
0
        code = 0;
411
0
    }
412
413
0
    if (fonts_array != NULL && pdfi_array_size(fonts_array) != 0) {
414
0
        uint64_t index = 0;
415
0
        pdf_dict *font_dict = NULL;
416
417
0
        outprintf(ctx->memory, "\n    Fonts used: \n");
418
0
        for (index = 0;index < pdfi_array_size(fonts_array);index++) {
419
0
            code = pdfi_array_get_type(ctx, fonts_array, index, PDF_DICT, (pdf_obj **)&font_dict);
420
0
            if (code >= 0) {
421
0
                outprintf(ctx->memory, "        ");
422
0
                (void)dump_font(ctx, font_dict, true);
423
0
                outprintf(ctx->memory, "\n");
424
0
                pdfi_countdown(font_dict);
425
0
                font_dict = NULL;
426
0
            }
427
0
        }
428
0
        code = 0;
429
0
    }
430
431
0
error:
432
0
    pdfi_countdown(fonts_array);
433
0
    pdfi_countdown(spots_array);
434
0
    outprintf(ctx->memory, "\n\n");
435
0
    pdfi_countdown(page_dict);
436
437
0
    return code;
438
0
}
439
440
/* Error and warning string tables. There should be a string for each error and warning
441
 * defined in the error (pdf_error_e) and warning (pdf_warning_e) enumerators. Having
442
 * more strings is harmless, having too few may cause crashes. These need to be kept in sync.
443
 *
444
 * The Ghostscript graphics library errors should be kept up to date, but this is less critical
445
 * if the error code is greater than the last error we know about we just print a generic
446
 * 'unknown' message.
447
 */
448
const char *pdf_error_strings[] = {
449
#define PARAM(A,B) B
450
#include "pdf_errors.h"
451
    ""                               /* last error, should not be used */
452
};
453
454
const char *pdf_warning_strings[] = {
455
#define PARAM(A,B) B
456
#include "pdf_warnings.h"
457
    ""                               /* Last warning should not be used */
458
};
459
460
const char *gs_error_strings[] = {
461
    "no error",
462
    "unknownerror",
463
    "dictfull",
464
    "dictstackoverflow",
465
    "dictstackunderflow",
466
    "execstackoverflow",
467
    "interrupt",
468
    "invalidaccess",
469
    "invalidexit",
470
    "invalidfileaccess",
471
    "invalidfont",
472
    "invalidrestore",
473
    "ioerror",
474
    "limitcheck",
475
    "nocurrentpoint",
476
    "rangecheck",
477
    "stackoverflow",
478
    "stackunderflow",
479
    "syntaxerror",
480
    "timeout",
481
    "typecheck",
482
    "undefined",
483
    "undefinedfilename",
484
    "undefinedresult",
485
    "unmatchedmark",
486
    "VMerror",
487
    "configurationerror",
488
    "undefinedresource",
489
    "unregistered",
490
    "invalidcontext",
491
    "invalidid",
492
    "pdf_stackoverflow",
493
    "circular reference"
494
};
495
496
const char *gs_internal_error_strings[] = {
497
    "error hit",
498
    "fatal error",
499
    "quit",
500
    "interpreter exit",
501
    "remap color",
502
    "exec stack underflow",
503
    "VMreclaim",
504
    "Need input",
505
    "need file",
506
    "No defined error",
507
    "No defined error (2)",
508
    "error info",
509
    "handled",
510
};
511
0
#define LASTNORMALGSERROR gs_error_circular_reference * -1
512
0
#define FIRSTINTERNALERROR gs_error_hit_detected * -1
513
0
#define LASTGSERROR gs_error_handled * -1
514
515
void pdfi_verbose_error(pdf_context *ctx, int gs_error, const char *gs_lib_function, int pdfi_error, const char *pdfi_function_name, const char *extra_info, const char *file_line)
516
0
{
517
0
    char fallback[] = "unknown graphics library error";
518
519
0
    if (ctx->args.verbose_errors && !ctx->args.QUIET) {
520
0
        if (gs_error != 0) {
521
0
            char *error_string;
522
0
            unsigned int code = gs_error * -1;
523
524
0
            if (code > LASTGSERROR)
525
0
                error_string = fallback;
526
0
            else {
527
0
                if (code > LASTNORMALGSERROR) {
528
0
                    if (code < FIRSTINTERNALERROR)
529
0
                        error_string = fallback;
530
0
                    else
531
0
                        error_string = (char *)gs_internal_error_strings[code - FIRSTINTERNALERROR];
532
0
                } else
533
0
                    error_string = (char *)gs_error_strings[code];
534
0
            }
535
0
            errprintf(ctx->memory, "Graphics library error %d (%s) in function '%s'", gs_error, error_string, pdfi_function_name);
536
0
            if (gs_lib_function != NULL)
537
0
                errprintf(ctx->memory, " from lib routine '%s'", gs_lib_function);
538
539
#if DEBUG_FILE_LINE==1
540
            if (file_line != NULL)
541
                errprintf(ctx->memory, "%s'.\n", file_line);
542
            else
543
                errprintf(ctx->memory, ".\n");
544
#else
545
0
            errprintf(ctx->memory, ".\n");
546
0
#endif
547
548
0
            if (pdfi_error != 0)
549
0
                errprintf(ctx->memory, "\tSetting pdfi error %d - %s.\n", pdfi_error, pdf_error_strings[pdfi_error]);
550
0
            if (extra_info != NULL)
551
0
                errprintf(ctx->memory, "\t%s\n", extra_info);
552
0
        } else {
553
0
            if (pdfi_error != 0) {
554
#if DEBUG_FILE_LINE==1
555
                if (file_line != NULL)
556
                    errprintf(ctx->memory, "Function '%s' %s set pdfi error %d - %s.\n", pdfi_function_name, file_line, pdfi_error, pdf_error_strings[pdfi_error]);
557
                else
558
                    errprintf(ctx->memory, "Function '%s' set pdfi error %d - %s.\n", pdfi_function_name, pdfi_error, pdf_error_strings[pdfi_error]);
559
#else
560
0
                errprintf(ctx->memory, "Function '%s' set pdfi error %d - %s.\n", pdfi_function_name, pdfi_error, pdf_error_strings[pdfi_error]);
561
0
#endif
562
0
                if (extra_info != NULL)
563
0
                    errprintf(ctx->memory, "\t%s\n", extra_info);
564
0
            } else {
565
0
                if (extra_info != NULL)
566
0
                    errprintf(ctx->memory, "%s\n", extra_info);
567
0
            }
568
0
        }
569
0
    }
570
0
}
571
572
void pdfi_verbose_warning(pdf_context *ctx, int gs_error, const char *gs_lib_function, int pdfi_warning, const char *pdfi_function_name, const char *extra_info, const char *file_line)
573
0
{
574
0
    char fallback[] = "unknown graphics library error";
575
576
0
    if (ctx->args.verbose_warnings && !ctx->args.QUIET) {
577
0
        if (gs_error != 0) {
578
0
            char *error_string;
579
0
            unsigned int code = gs_error * -1;
580
581
0
            if (code > LASTGSERROR)
582
0
                error_string = fallback;
583
0
            else {
584
0
                if (code > LASTNORMALGSERROR) {
585
0
                    if (code < FIRSTINTERNALERROR)
586
0
                        error_string = fallback;
587
0
                    else
588
0
                        error_string = (char *)gs_internal_error_strings[code - FIRSTINTERNALERROR];
589
0
                } else
590
0
                    error_string = (char *)gs_error_strings[code];
591
0
            }
592
0
            outprintf(ctx->memory, "Graphics library error %d (%s) in function '%s'", gs_error, error_string, pdfi_function_name);
593
0
            if (gs_lib_function != NULL)
594
0
                outprintf(ctx->memory, " from lib routine '%s'.\n", gs_lib_function);
595
596
#if DEBUG_FILE_LINE==1
597
            if (file_line != NULL)
598
                errprintf(ctx->memory, "%s'.\n", file_line);
599
            else
600
                errprintf(ctx->memory, ".\n");
601
#else
602
0
            errprintf(ctx->memory, ".\n");
603
0
#endif
604
0
            if (pdfi_warning != 0)
605
0
                outprintf(ctx->memory, "\tsetting pdfi warning %d - %s.\n", pdfi_warning, pdf_warning_strings[pdfi_warning]);
606
0
            if (extra_info != NULL)
607
0
                outprintf(ctx->memory, "\t%s\n", extra_info);
608
0
        } else {
609
0
            if (pdfi_warning != 0) {
610
#if DEBUG_FILE_LINE==1
611
                if (file_line != NULL)
612
                    outprintf(ctx->memory, "Function '%s' %s set pdfi warning %d - %s.\n", pdfi_function_name, file_line, pdfi_warning, pdf_warning_strings[pdfi_warning]);
613
                else
614
                    outprintf(ctx->memory, "Function '%s' set pdfi warning %d - %s.\n", pdfi_function_name, pdfi_warning, pdf_warning_strings[pdfi_warning]);
615
#else
616
0
                outprintf(ctx->memory, "Function '%s' set pdfi warning %d - %s.\n", pdfi_function_name, pdfi_warning, pdf_warning_strings[pdfi_warning]);
617
0
#endif
618
0
                if (extra_info != NULL)
619
0
                    errprintf(ctx->memory, "\t%s\n", extra_info);
620
0
            } else {
621
0
                if (extra_info != NULL)
622
0
                    errprintf(ctx->memory, "\t%s\n", extra_info);
623
0
            }
624
0
        }
625
0
    }
626
0
}
627
628
int pdfi_set_error_var(pdf_context *ctx, int gs_error, const char *gs_lib_function, pdf_error pdfi_error, const char *pdfi_function_name, const char *fmt, ...)
629
3.70k
{
630
3.70k
    if (pdfi_error != 0)
631
3.70k
        ctx->pdf_errors[pdfi_error / (sizeof(char) * 8)] |= 1 << pdfi_error % (sizeof(char) * 8);
632
3.70k
    if (ctx->args.verbose_errors) {
633
0
        char extra_info[gp_file_name_sizeof];
634
0
        va_list args;
635
636
0
        va_start(args, fmt);
637
0
        (void)vsnprintf(extra_info, sizeof(extra_info), fmt, args);
638
0
        va_end(args);
639
640
0
        pdfi_verbose_error(ctx, gs_error, gs_lib_function, pdfi_error, pdfi_function_name, extra_info, NULL);
641
0
    }
642
3.70k
    if (ctx->args.pdfstoponerror) {
643
0
        if (gs_error < 0)
644
0
            return gs_error;
645
0
        else
646
0
            return gs_error_unknownerror;
647
0
    }
648
3.70k
    return 0;
649
3.70k
}
650
651
int pdfi_set_warning_var(pdf_context *ctx, int gs_error, const char *gs_lib_function, pdf_warning pdfi_warning, const char *pdfi_function_name, const char *fmt, ...)
652
128k
{
653
128k
    ctx->pdf_warnings[pdfi_warning / (sizeof(char) * 8)] |= 1 << pdfi_warning % (sizeof(char) * 8);
654
128k
    if (ctx->args.verbose_warnings) {
655
0
        char extra_info[gp_file_name_sizeof];
656
0
        va_list args;
657
658
0
        va_start(args, fmt);
659
0
        (void)vsnprintf(extra_info, sizeof(extra_info), fmt, args);
660
0
        va_end(args);
661
662
0
        pdfi_verbose_warning(ctx, gs_error, gs_lib_function, pdfi_warning, pdfi_function_name, extra_info, NULL);
663
0
    }
664
128k
    if (ctx->args.pdfstoponwarning) {
665
0
        if (gs_error < 0)
666
0
            return gs_error;
667
0
        else
668
0
            return gs_error_unknownerror;
669
0
    }
670
128k
    return 0;
671
128k
}
672
673
void
674
pdfi_report_errors(pdf_context *ctx)
675
5.09k
{
676
5.09k
    int code, i, j;
677
5.09k
    bool warnings_exist = false, errors_exist = false;
678
679
5.09k
    if (ctx->args.QUIET)
680
5.09k
        return;
681
682
0
    for (i = 0; i < PDF_ERROR_BYTE_SIZE; i++) {
683
0
        if (ctx->pdf_errors[i] != 0)
684
0
            errors_exist = true;
685
0
    }
686
687
0
    for (i = 0; i < PDF_WARNING_BYTE_SIZE; i++) {
688
0
        if (ctx->pdf_warnings[i] != 0)
689
0
            warnings_exist = true;
690
0
    }
691
692
0
    if (!errors_exist && !warnings_exist)
693
0
        return;
694
695
0
    if (errors_exist)
696
0
    {
697
0
        errprintf(ctx->memory, "\nThe following errors were encountered at least once while processing this file:\n");
698
0
        for (i = 0; i < PDF_ERROR_BYTE_SIZE; i++) {
699
0
            if (ctx->pdf_errors[i] != 0) {
700
0
                for (j=0;j < sizeof(char) * 8; j++) {
701
0
                    if (ctx->pdf_errors[i] & 1 << j) {
702
0
                        int error_num = (i * sizeof(char) * 8) + j;
703
704
0
                        errprintf(ctx->memory, "\t%s\n", pdf_error_strings[error_num]);
705
0
                    }
706
0
                }
707
0
            }
708
0
        }
709
0
    }
710
711
0
    if (warnings_exist)
712
0
    {
713
0
        outprintf(ctx->memory, "\nThe following warnings were encountered at least once while processing this file:\n");
714
0
        for (i = 0; i < PDF_WARNING_BYTE_SIZE; i++) {
715
0
            if (ctx->pdf_warnings[i] != 0) {
716
0
                for (j=0;j < sizeof(char) * 8; j++) {
717
0
                    if (ctx->pdf_warnings[i] & 1 << j) {
718
0
                        int warning_num = (i * sizeof(char) * 8) + j;
719
720
0
                        outprintf(ctx->memory, "\t%s\n", pdf_warning_strings[warning_num]);
721
0
                    }
722
0
                }
723
0
            }
724
0
        }
725
0
    }
726
727
0
    if (errors_exist)
728
0
        errprintf(ctx->memory, "\n   **** This file had errors that were repaired or ignored.\n");
729
0
    else {
730
0
        if (warnings_exist)
731
0
            outprintf(ctx->memory, "\n   **** This file had errors that were repaired or ignored.\n");
732
0
    }
733
0
    if (ctx->Info) {
734
0
        pdf_string *s = NULL;
735
736
0
        code = pdfi_dict_knownget_type(ctx, ctx->Info, "Producer", PDF_STRING, (pdf_obj **)&s);
737
0
        if (code > 0) {
738
0
            char *cs;
739
740
0
            cs = (char *)gs_alloc_bytes(ctx->memory, s->length + 1, "temporary string for error report");
741
0
            if (cs == NULL) {
742
0
                errprintf(ctx->memory, "   **** Out of memory while trying to display Producer ****\n");
743
0
            } else {
744
0
                memcpy(cs, s->data, s->length);
745
0
                cs[s->length] = 0x00;
746
0
                if (errors_exist)
747
0
                    errprintf(ctx->memory, "   **** The file was produced by: \n   **** >>>> %s <<<<\n", cs);
748
0
                else {
749
0
                    if (warnings_exist)
750
0
                    outprintf(ctx->memory, "   **** The file was produced by: \n   **** >>>> %s <<<<\n", cs);
751
0
                }
752
0
                gs_free_object(ctx->memory, cs, "temporary string for error report");
753
0
            }
754
0
        }
755
0
        pdfi_countdown(s);
756
0
    }
757
0
    if (errors_exist) {
758
0
        errprintf(ctx->memory, "   **** Please notify the author of the software that produced this\n");
759
0
        errprintf(ctx->memory, "   **** file that it does not conform to Adobe's published PDF\n");
760
0
        errprintf(ctx->memory, "   **** specification.\n\n");
761
0
    } else {
762
0
        outprintf(ctx->memory, "   **** Please notify the author of the software that produced this\n");
763
0
        outprintf(ctx->memory, "   **** file that it does not conform to Adobe's published PDF\n");
764
0
        outprintf(ctx->memory, "   **** specification.\n\n");
765
0
    }
766
0
}
767
768
/* Name table
769
 * I've been trying to avoid this for as long as possible, but it seems it cannot
770
 * be evaded. We need functions to get an index for a given string (which will
771
 * add the string to the table if its not present) and to cleear up the table
772
 * on finishing a PDF file.
773
 */
774
775
int pdfi_get_name_index(pdf_context *ctx, char *name, int len, unsigned int *returned)
776
2.06k
{
777
2.06k
    pdfi_name_entry_t *e = NULL, *last_entry = NULL, *new_entry = NULL;
778
2.06k
    int index = 0;
779
780
2.06k
    if (ctx->name_table == NULL) {
781
143
        e = NULL;
782
1.92k
    } else {
783
1.92k
        e = ctx->name_table;
784
1.92k
    }
785
786
2.06k
    while(e != NULL) {
787
1.92k
        if (e->len == len) {
788
1.92k
            if (memcmp(e->name, name, e->len) == 0) {
789
1.92k
                *returned = e->index;
790
1.92k
                return 0;
791
1.92k
            }
792
1.92k
        }
793
0
        last_entry = e;
794
0
        index = e->index;
795
0
        e = e->next;
796
0
    }
797
798
143
    new_entry = (pdfi_name_entry_t *)gs_alloc_bytes(ctx->memory, sizeof(pdfi_name_entry_t), "Alloc name table entry");
799
143
    if (new_entry == NULL)
800
0
        return_error(gs_error_VMerror);
801
143
    memset(new_entry, 0x00, sizeof(pdfi_name_entry_t));
802
143
    new_entry->name = (char *)gs_alloc_bytes(ctx->memory, len+1, "Alloc name table name");
803
143
    if (new_entry->name == NULL) {
804
0
        gs_free_object(ctx->memory, new_entry, "Failed to allocate name entry");
805
0
            return_error(gs_error_VMerror);
806
0
    }
807
143
    memset(new_entry->name, 0x00, len+1);
808
143
    memcpy(new_entry->name, name, len);
809
143
    new_entry->len = len;
810
143
    new_entry->index = ++index;
811
812
143
    if (last_entry)
813
0
        last_entry->next = new_entry;
814
143
    else
815
143
        ctx->name_table = new_entry;
816
817
143
    *returned = new_entry->index;
818
143
    return 0;
819
143
}
820
821
static int pdfi_free_name_table(pdf_context *ctx)
822
6.24k
{
823
6.24k
    if (ctx->name_table) {
824
143
        pdfi_name_entry_t *next = NULL, *e = (pdfi_name_entry_t *)ctx->name_table;
825
826
286
        while (e != NULL) {
827
143
            next = (pdfi_name_entry_t *)e->next;
828
143
            gs_free_object(ctx->memory, e->name, "free name table entries");
829
143
            gs_free_object(ctx->memory, e, "free name table entries");
830
143
            e = next;
831
143
        }
832
143
    }
833
6.24k
    ctx->name_table = NULL;
834
6.24k
    return 0;
835
6.24k
}
836
837
int pdfi_name_from_index(pdf_context *ctx, int index, unsigned char **name, unsigned int *len)
838
0
{
839
0
    pdfi_name_entry_t *e = (pdfi_name_entry_t *)ctx->name_table;
840
841
0
    while (e != NULL) {
842
0
        if (e->index == index) {
843
0
            *name = (unsigned char *)e->name;
844
0
            *len = e->len;
845
0
            return 0;
846
0
        }
847
0
        e = e->next;
848
0
    }
849
850
0
    return_error(gs_error_undefined);
851
0
}
852
853
int pdfi_separation_name_from_index(gs_gstate *pgs, gs_separation_name index, unsigned char **name, unsigned int *len)
854
2.03k
{
855
2.03k
    pdfi_int_gstate *igs = (pdfi_int_gstate *)pgs->client_data;
856
2.03k
    pdf_context *ctx = NULL;
857
2.03k
    pdfi_name_entry_t *e = NULL;
858
859
2.03k
    if (igs == NULL)
860
0
        return_error(gs_error_undefined);
861
862
2.03k
    ctx = igs->ctx;
863
2.03k
    if (ctx == NULL)
864
0
        return_error(gs_error_undefined);
865
866
2.03k
    e = (pdfi_name_entry_t *)ctx->name_table;
867
868
2.03k
    while (e != NULL) {
869
2.03k
        if (e->index == index) {
870
2.03k
            *name = (unsigned char *)e->name;
871
2.03k
            *len = e->len;
872
2.03k
            return 0;
873
2.03k
        }
874
0
        e = e->next;
875
0
    }
876
877
2.03k
    return_error(gs_error_undefined);
878
2.03k
}
879
880
int pdfi_finish_pdf_file(pdf_context *ctx)
881
5.09k
{
882
5.09k
    if (ctx->Root) {
883
5.09k
        if (ctx->device_state.writepdfmarks && ctx->device_state.WantsOptionalContent) {
884
0
            pdf_obj *o = NULL;
885
0
            int code = 0;
886
887
0
            code = pdfi_dict_knownget_type(ctx, ctx->Root, "OCProperties", PDF_DICT, &o);
888
0
            if (code > 0) {
889
                /* Build and send the OCProperties structure */
890
0
                code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "OCProperties");
891
0
                pdfi_countdown(o);
892
0
                if (code < 0)
893
                    /* Error message ? */
894
0
                ;
895
0
            }
896
0
        }
897
5.09k
    }
898
5.09k
    return 0;
899
5.09k
}
900
901
int pdfi_close_pdf_file(pdf_context *ctx)
902
0
{
903
0
    if (ctx->Root) {
904
0
        if (ctx->device_state.writepdfmarks && ctx->device_state.WantsOptionalContent) {
905
0
            pdf_obj *o = NULL;
906
0
            int code = 0;
907
908
0
            code = pdfi_dict_knownget(ctx, ctx->Root, "OCProperties", &o);
909
0
            if (code > 0) {
910
                /* Build and send the OCProperties structure */
911
0
                code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "OCProperties");
912
0
                pdfi_countdown(o);
913
0
                if (code < 0)
914
                    /* Error message ? */
915
0
                    ;
916
0
            }
917
0
        }
918
0
    }
919
920
0
    if (ctx->main_stream) {
921
0
        if (ctx->main_stream->s) {
922
0
            sfclose(ctx->main_stream->s);
923
0
        }
924
0
        gs_free_object(ctx->memory, ctx->main_stream, "Closing main PDF file");
925
0
        ctx->main_stream = NULL;
926
0
    }
927
0
    ctx->main_stream_length = 0;
928
929
0
    if (ctx->filename) {
930
0
        gs_free_object(ctx->memory, ctx->filename, "pdfi_close_pdf_file, free copy of filename");
931
0
        ctx->filename = NULL;
932
0
    }
933
934
0
    pdfi_clear_context(ctx);
935
0
    return 0;
936
0
}
937
938
static int pdfi_process(pdf_context *ctx)
939
0
{
940
0
    int code = 0, i;
941
942
    /* Loop over each page and either render it or output the
943
     * required information.
944
     */
945
0
    for (i=0;i < ctx->num_pages;i++) {
946
0
        if (ctx->args.first_page != 0) {
947
0
            if (i < ctx->args.first_page - 1)
948
0
                continue;
949
0
        }
950
0
        if (ctx->args.last_page != 0) {
951
0
            if (i > ctx->args.last_page - 1)
952
0
                break;
953
0
        }
954
0
        if (ctx->args.pdfinfo)
955
0
            code = pdfi_output_page_info(ctx, i);
956
0
        else
957
0
            code = pdfi_page_render(ctx, i, true);
958
959
0
        if (code < 0)
960
0
            code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_process", NULL);
961
0
    }
962
0
    pdfi_report_errors(ctx);
963
964
0
    return code;
965
0
}
966
967
/* This works by reading each embedded file referenced by the collection. If it
968
 * has a MIME type indicating it's a PDF file, or somewhere in the first 2KB it
969
 * has the PDF header (%PDF-) then we treat it as a PDF file. We read the contents
970
 * of the refrenced stream and write them to disk in a scratch file.
971
 *
972
 * We then process each scratch file in turn. Note that we actually return an
973
 * array of strings; the first string is the temporary filename, the second is
974
 * the entry from the names tree. Since this can be in UTF16-BE format, it can
975
 * contain embedded single byte NULL characters, so we can't use a regular C
976
 * string. Instead we use a triple byte NULL termination.
977
 *
978
 * It ought to be possible to do all the processing without creating scratch files, by saving the
979
 * current file state, and opening a new 'file' on the stream in the original PDF
980
 * file. But I couldn't immediately get that to work.
981
 * So this is a FIXME future enhancement.
982
 */
983
int pdfi_prep_collection(pdf_context *ctx, uint64_t *TotalFiles, char ***names_array)
984
0
{
985
0
    int code = 0, i, NumEmbeddedFiles = 0;
986
0
    pdf_obj *Names = NULL, *EmbeddedFiles = NULL;
987
0
    pdf_array *FileNames = NULL;
988
0
    pdf_obj *EF = NULL, *F = NULL;
989
0
    char **working_array = NULL;
990
991
0
    if (pdfi_dict_knownget_type(ctx, ctx->Root, "Names", PDF_DICT, &Names) > 0) {
992
0
        if(pdfi_dict_knownget_type(ctx, (pdf_dict *)Names, "EmbeddedFiles", PDF_DICT, &EmbeddedFiles) > 0) {
993
0
            if (pdfi_dict_knownget_type(ctx, (pdf_dict *)EmbeddedFiles, "Names", PDF_ARRAY, (pdf_obj **)&FileNames) > 0) {
994
0
                int ix = 0, index = 0;
995
0
                gp_file *scratch_file = NULL;
996
0
                char scratch_name[gp_file_name_sizeof];
997
998
0
                NumEmbeddedFiles = pdfi_array_size(FileNames) / 2;
999
1000
0
                working_array = (char **)gs_alloc_bytes(ctx->memory, NumEmbeddedFiles * 2 * sizeof(char *), "Collection file working names array");
1001
0
                if (working_array == NULL) {
1002
0
                    code = gs_note_error(gs_error_VMerror);
1003
0
                    goto exit;
1004
0
                }
1005
0
                memset(working_array, 0x00, NumEmbeddedFiles * 2 * sizeof(char *));
1006
1007
0
                for (ix = 0;ix < NumEmbeddedFiles;ix++) {
1008
0
                    pdf_obj *File = NULL;
1009
0
                    pdf_obj *Subtype = NULL;
1010
1011
0
                    code = pdfi_array_get(ctx, FileNames, (ix * 2) + 1, &File);
1012
0
                    if (code < 0)
1013
0
                        goto exit;
1014
1015
0
                    if (pdfi_type_of(File) == PDF_DICT) {
1016
0
                        if (pdfi_dict_knownget_type(ctx, (pdf_dict *)File, "EF", PDF_DICT, &EF) > 0) {
1017
0
                            if (pdfi_dict_knownget_type(ctx, (pdf_dict *)EF, "F", PDF_STREAM, &F) > 0) {
1018
0
                                pdf_dict *stream_dict = NULL;
1019
0
                                pdf_c_stream *s = NULL;
1020
1021
                                /* pdfi_dict_from_object does not increment the reference count of the stream dictionary
1022
                                 * so we do not need to count it down later.
1023
                                 */
1024
0
                                code = pdfi_dict_from_obj(ctx, F, &stream_dict);
1025
0
                                if (code >= 0) {
1026
0
                                    if (pdfi_dict_knownget_type(ctx, stream_dict, "Subtype", PDF_NAME, &Subtype) <= 0) {
1027
                                        /* No Subtype, (or not a name) we can't check the Mime type, so try to read the first 2Kb
1028
                                         * and look for a %PDF- in that. If not present, assume its not a PDF
1029
                                         */
1030
0
                                        code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, (pdf_stream *)F), SEEK_SET);
1031
0
                                        if (code >= 0) {
1032
0
                                            code = pdfi_filter(ctx, (pdf_stream *)F, ctx->main_stream, &s, false);
1033
0
                                            if (code >= 0) {
1034
0
                                                char Buffer[2048];
1035
0
                                                int bytes;
1036
1037
0
                                                bytes = pdfi_read_bytes(ctx, (byte *)Buffer, 1, 2048, s);
1038
0
                                                pdfi_close_file(ctx, s);
1039
0
                                                s = NULL;
1040
                                                /* Assertion; the smallest real PDF file is at least 400 bytes */
1041
0
                                                if (bytes >= 400) {
1042
0
                                                    if (strstr(Buffer, "%PDF-") == NULL)
1043
0
                                                        code = -1;
1044
0
                                                } else
1045
0
                                                    code = -1;
1046
0
                                            }
1047
0
                                        }
1048
0
                                    } else {
1049
0
                                        if (!pdfi_name_is((const pdf_name *)Subtype, "application/pdf"))
1050
0
                                            code = -1;
1051
0
                                    }
1052
1053
0
                                    if (code >= 0) {
1054
                                        /* Appears to be a PDF file. Create a scratch file to hold it, and then
1055
                                         * read the file from the PDF, and write it to the scratch file. Record
1056
                                         * the scratch filename in the working_array for later processing.
1057
                                         */
1058
0
                                        scratch_file = gp_open_scratch_file(ctx->memory, "gpdf-collection-", scratch_name, "wb");
1059
0
                                        if (scratch_file != NULL) {
1060
0
                                            code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, (pdf_stream *)F), SEEK_SET);
1061
0
                                            if (code >= 0) {
1062
0
                                                double L;
1063
0
                                                pdf_c_stream *SubFile_stream = NULL;
1064
1065
                                                /* Start by setting up the file to be read. Apply a SubFileDecode so that, if the input stream
1066
                                                 * is not compressed we will stop reading when we get to the end of the stream.
1067
                                                 */
1068
0
                                                if (pdfi_dict_knownget_number(ctx, stream_dict, "Length", &L) > 0) {
1069
1070
0
                                                    code = pdfi_apply_SubFileDecode_filter(ctx, (int)L, NULL, ctx->main_stream, &SubFile_stream, false);
1071
0
                                                    if (code >= 0)
1072
0
                                                        code = pdfi_filter(ctx, (pdf_stream *)F, SubFile_stream, &s, false);
1073
0
                                                } else
1074
0
                                                    code = pdfi_filter(ctx, (pdf_stream *)F, ctx->main_stream, &s, false);
1075
1076
0
                                                if (code >= 0) {
1077
0
                                                    char Buffer[2048];
1078
0
                                                    int bytes;
1079
0
                                                    pdf_string *Name = NULL;
1080
1081
                                                    /* Read the stream contents and write them to the scratch file */
1082
0
                                                    do {
1083
0
                                                        bytes = pdfi_read_bytes(ctx, (byte *)Buffer, 1, 2048, s);
1084
0
                                                        (void)gp_fwrite(Buffer, 1, bytes, scratch_file);
1085
0
                                                    } while (bytes > 0);
1086
1087
                                                    /* Create an entry for the Description in the names array */
1088
0
                                                    code = pdfi_array_get(ctx, FileNames, ix * 2, (pdf_obj **)&Name);
1089
0
                                                    if (code >= 0) {
1090
0
                                                        if (pdfi_type_of((pdf_obj *)Name) == PDF_STRING) {
1091
0
                                                            working_array[(index * 2) + 1] = (char *)gs_alloc_bytes(ctx->memory, Name->length + 3, "Collection file names array entry");
1092
0
                                                            if (working_array[(index * 2) + 1] != NULL) {
1093
0
                                                                memset(working_array[(index * 2) + 1], 0x00, Name->length + 3);
1094
0
                                                                memcpy(working_array[(index * 2) + 1], Name->data, Name->length);
1095
0
                                                            }
1096
0
                                                        }
1097
0
                                                        pdfi_countdown(Name);
1098
0
                                                        Name = NULL;
1099
0
                                                    }
1100
1101
                                                    /* And now the scratch file name */
1102
0
                                                    working_array[index * 2] = (char *)gs_alloc_bytes(ctx->memory, strlen(scratch_name) + 3, "Collection file names array entry");
1103
0
                                                    if (working_array[index * 2] != NULL) {
1104
0
                                                        memset(working_array[index * 2], 0x00, strlen(scratch_name) + 3);
1105
0
                                                        strcpy(working_array[index * 2], scratch_name);
1106
0
                                                    }
1107
1108
0
                                                    index++;
1109
0
                                                    (*TotalFiles)++;
1110
0
                                                    pdfi_close_file(ctx, s);
1111
0
                                                    s = NULL;
1112
0
                                                }
1113
0
                                                if (SubFile_stream != NULL)
1114
0
                                                    pdfi_close_file(ctx, SubFile_stream);
1115
0
                                                SubFile_stream = NULL;
1116
0
                                            }
1117
0
                                            gp_fclose(scratch_file);
1118
0
                                        } else
1119
0
                                            errprintf(ctx->memory, "\n   **** Warning: Failed to open a scratch file.\n");
1120
0
                                    }
1121
0
                                }
1122
0
                            }
1123
0
                        }
1124
0
                    }
1125
0
                    pdfi_countdown(Subtype);
1126
0
                    Subtype = NULL;
1127
0
                    pdfi_countdown(F);
1128
0
                    F = NULL;
1129
0
                    pdfi_countdown(EF);
1130
0
                    EF = NULL;
1131
0
                    pdfi_countdown(File);
1132
0
                    File = NULL;
1133
0
                }
1134
0
            } else {
1135
0
                errprintf(ctx->memory, "\n   **** Warning: Failed to read EmbeededFiles Names tree.\n");
1136
0
            }
1137
0
        } else {
1138
0
            errprintf(ctx->memory, "\n   **** Warning: Failed to read EmbeddedFiles.\n");
1139
0
        }
1140
0
    } else {
1141
0
        errprintf(ctx->memory, "\n   **** Warning: Failed to find Names tree.\n");
1142
0
    }
1143
0
    code = 0;
1144
1145
0
exit:
1146
0
    if (code >= 0) {
1147
0
        uint64_t ix = 0;
1148
1149
0
        (*names_array) = (char **)gs_alloc_bytes(ctx->memory, *TotalFiles * 2 * sizeof(char *), "Collection file namesarray");
1150
0
        if (*names_array == NULL)
1151
0
            code = gs_note_error(gs_error_VMerror);
1152
0
        else {
1153
0
            for (i = 0; i < NumEmbeddedFiles;i++) {
1154
0
                if (working_array[i * 2] != NULL && working_array[(i * 2) + 1] != NULL) {
1155
0
                    (*names_array)[ix * 2] = working_array[i * 2];
1156
0
                    working_array[i * 2] = NULL;
1157
0
                    (*names_array)[(ix * 2) + 1] = working_array[(i * 2) + 1];
1158
0
                    working_array[(i * 2) + 1] = NULL;
1159
0
                    ix++;
1160
0
                }
1161
0
            }
1162
0
        }
1163
0
    }
1164
1165
0
    if (working_array != NULL) {
1166
0
        for (i = 0; i < NumEmbeddedFiles;i++)
1167
0
            gs_free_object(ctx->memory, working_array[i], "free collection temporary filenames");
1168
0
        gs_free_object(ctx->memory, working_array, "free collection working array");
1169
0
    }
1170
0
    pdfi_countdown(F);
1171
0
    pdfi_countdown(EF);
1172
0
    pdfi_countdown(FileNames);
1173
0
    pdfi_countdown(EmbeddedFiles);
1174
0
    pdfi_countdown(Names);
1175
0
    return code;
1176
0
}
1177
1178
static int pdfi_process_collection(pdf_context *ctx)
1179
0
{
1180
0
    int code, i;
1181
0
    uint64_t TotalFiles = 0, ix = 0;
1182
0
    char **names_array = NULL;
1183
1184
0
    code = pdfi_prep_collection(ctx, &TotalFiles, &names_array);
1185
0
    if (code >= 0 && TotalFiles > 0)
1186
0
    {
1187
        /* names_array is full of pointers to the scratch file names containing PDF files.
1188
         * Now we need to run each PDF file. First we close down the current file.
1189
         */
1190
0
        (void)pdfi_close_pdf_file(ctx);
1191
1192
0
        for (ix = 0;ix < TotalFiles * 2;ix+=2) {
1193
0
            if (names_array[ix] != NULL) {
1194
0
                (void)pdfi_process_pdf_file(ctx, names_array[ix]);
1195
0
                (void)pdfi_close_pdf_file(ctx);
1196
0
            }
1197
0
        }
1198
0
    } else
1199
        /* We didn't find any PDF files in the Embedded Files. So just run the
1200
         * pages in the container file (the original PDF file)
1201
         */
1202
0
        pdfi_process(ctx);
1203
1204
0
    for (i = 0; i < TotalFiles * 2;i++)
1205
0
        gs_free_object(ctx->memory, names_array[i], "free collection temporary filenames");
1206
0
    gs_free_object(ctx->memory, names_array, "free collection names array");
1207
1208
0
    return 0;
1209
0
}
1210
1211
int pdfi_process_pdf_file(pdf_context *ctx, char *filename)
1212
0
{
1213
0
    int code = 0;
1214
1215
0
    code = pdfi_open_pdf_file(ctx, filename);
1216
0
    if (code < 0) {
1217
0
        pdfi_report_errors(ctx);
1218
0
        return code;
1219
0
    }
1220
1221
    /* Do any custom device configuration */
1222
0
    pdfi_device_misc_config(ctx);
1223
1224
0
    if (ctx->Collection != NULL)
1225
0
        code = pdfi_process_collection(ctx);
1226
0
    else
1227
0
        code = pdfi_process(ctx);
1228
1229
    /* Pdfmark_InitialPage is the offset for Page Dests in
1230
     * /Outlines and Link annotations. It is the count of pages
1231
     * processed so far. Update it by the number of pages in
1232
     * this file.
1233
     */
1234
0
    ctx->Pdfmark_InitialPage += ctx->num_pages;
1235
1236
0
    pdfi_close_pdf_file(ctx);
1237
0
    return code;
1238
0
}
1239
1240
static int pdfi_init_file(pdf_context *ctx)
1241
6.24k
{
1242
6.24k
    int code = 0;
1243
6.24k
    pdf_obj *o = NULL;
1244
1245
6.24k
    code = pdfi_read_xref(ctx);
1246
6.24k
    if (code < 0) {
1247
385
        if (ctx->is_hybrid) {
1248
0
            if ((code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_BADXREFSTREAM, "pdfi_init_file", NULL)) < 0) {
1249
0
                goto exit;
1250
0
            }
1251
            /* If its a hybrid file, and we failed to read the XrefStm, try
1252
             * again, but this time read the xref table instead.
1253
             */
1254
0
            pdfi_countdown(ctx->xref_table);
1255
0
            ctx->xref_table = NULL;
1256
0
            ctx->prefer_xrefstm = false;
1257
0
            code = pdfi_read_xref(ctx);
1258
0
            if (code < 0)
1259
0
                goto exit;
1260
385
        } else {
1261
385
            pdfi_set_error(ctx, code, NULL, E_PDF_BADXREFSTREAM, "pdfi_init_file", NULL);
1262
385
            goto exit;
1263
385
        }
1264
385
    }
1265
1266
5.85k
    pdfi_device_set_flags(ctx);
1267
1268
5.85k
    if (ctx->Trailer) {
1269
        /* See comment in pdfi_read_Root() (pdf_doc.c) for details */
1270
2.96k
        pdf_dict *d = ctx->Trailer;
1271
1272
2.96k
        pdfi_countup(d);
1273
2.96k
        code = pdfi_dict_get(ctx, d, "Encrypt", &o);
1274
2.96k
        pdfi_countdown(d);
1275
2.96k
        if (code < 0 && code != gs_error_undefined)
1276
1
            goto exit;
1277
2.96k
        if (code == 0) {
1278
84
            if (pdfi_type_of(o) == PDF_DICT) {
1279
#if USE_PDF_PERMISSIONS
1280
              double Permissions = 0;
1281
              uint32_t P = 0;
1282
#endif
1283
1284
83
                code = pdfi_initialise_Decryption(ctx);
1285
83
                if (code < 0)
1286
17
                    goto exit;
1287
1288
                /* This section is commetned out but deliberately retained. This code
1289
                 * prevents us from processing any PDF file where the 'print' permission
1290
                 * is not set. Additionally, if the 'print' permission is set, but bit 12
1291
                 * 'faitful digital copy' is not set, *and* we are writing to a high level
1292
                 * device, then we will throw an error..
1293
                 */
1294
#if USE_PDF_PERMISSIONS
1295
                code = pdfi_dict_knownget_number(ctx, (pdf_dict *)o, "P", &Permissions);
1296
                if (code < 0)
1297
                    goto exit;
1298
                if (Permissions > ((unsigned long)1 << 31)) {
1299
                    code = gs_note_error(gs_error_rangecheck);
1300
                    goto exit;
1301
                }
1302
                P = (uint32_t)Permissions;
1303
                if ((P & 0x04) == 0) {
1304
                    errprintf(ctx->memory, "   ****The owner of this file has requested you do not print it.\n");
1305
                    code = gs_note_error(gs_error_invalidfileaccess);
1306
                    goto exit;
1307
                }
1308
                if (ctx->device_state.HighLevelDevice) {
1309
                    if ((P & 0x800) == 0) {
1310
                        errprintf(ctx->memory, "   ****The owner of this file has requested you do not make a digital copy of it.\n");
1311
                        code = gs_note_error(gs_error_invalidfileaccess);
1312
                        goto exit;
1313
                    }
1314
                }
1315
#endif
1316
83
            } else {
1317
1
                if (pdfi_type_of(o) != PDF_NULL)
1318
1
                    if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_typecheck), NULL, E_PDF_BADENCRYPT, "pdfi_init_file", NULL)) < 0)
1319
0
                        goto exit;
1320
1
            }
1321
84
        }
1322
2.96k
    }
1323
1324
5.85k
read_root:
1325
5.85k
    if (ctx->Trailer) {
1326
2.96k
        code = pdfi_read_Root(ctx);
1327
2.96k
        if (code < 0) {
1328
            /* If we couldn#'t find the Root object, and we were using the XrefStm
1329
             * from a hybrid file, then try again, but this time use the xref table
1330
             */
1331
89
            if (code == gs_error_undefined && ctx->is_hybrid && ctx->prefer_xrefstm) {
1332
0
                pdfi_countdown(ctx->xref_table);
1333
0
                ctx->xref_table = NULL;
1334
0
                if ((code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_BADXREFSTREAM, "pdfi_init_file", NULL)) < 0)
1335
0
                    goto exit;
1336
1337
0
                ctx->prefer_xrefstm = false;
1338
0
                code = pdfi_read_xref(ctx);
1339
0
                if (code < 0) {
1340
0
                    pdfi_set_error(ctx, 0, NULL, E_PDF_BADXREF, "pdfi_init_file", NULL);
1341
0
                    goto exit;
1342
0
                }
1343
0
                code = pdfi_read_Root(ctx);
1344
0
                if (code < 0)
1345
0
                    goto exit;
1346
89
            } else {
1347
89
                int code1 = pdfi_repair_file(ctx);
1348
89
                if (code1 < 0)
1349
76
                    goto exit;
1350
13
                goto read_root;
1351
89
            }
1352
89
        }
1353
2.96k
    }
1354
1355
5.76k
    if (ctx->Trailer) {
1356
2.87k
        code = pdfi_read_Info(ctx);
1357
2.87k
        if (code < 0 && code != gs_error_undefined) {
1358
75
            if ((code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_init_file", NULL)) < 0)
1359
0
                goto exit;
1360
75
            pdfi_clearstack(ctx);
1361
75
        }
1362
2.87k
    }
1363
1364
5.76k
    if (!ctx->Root) {
1365
480
        errprintf(ctx->memory, "Catalog dictionary not located in file, unable to proceed\n");
1366
480
        return_error(gs_error_syntaxerror);
1367
480
    }
1368
1369
5.28k
    code = pdfi_read_Pages(ctx);
1370
5.28k
    if (code < 0)
1371
165
        goto exit;
1372
1373
5.11k
    code = pdfi_doc_page_array_init(ctx);
1374
5.11k
    if (code < 0)
1375
0
        goto exit;
1376
1377
5.11k
    if (ctx->num_pages == 0)
1378
11
        errprintf(ctx->memory, "\n   **** Warning: PDF document has no pages.\n");
1379
1380
5.11k
    code = pdfi_doc_trailer(ctx);
1381
5.11k
    if (code < 0)
1382
0
        goto exit;
1383
1384
5.11k
    pdfi_read_OptionalRoot(ctx);
1385
1386
5.11k
    if (ctx->args.pdfinfo) {
1387
0
        code = pdfi_output_metadata(ctx);
1388
0
        if (code < 0 && (code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_init_file", NULL)) < 0)
1389
0
            goto exit;
1390
0
    }
1391
1392
5.76k
exit:
1393
5.76k
    if (code < 0)
1394
644
        pdfi_set_error(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_init_file", NULL);
1395
5.76k
    pdfi_countdown(o);
1396
5.76k
    return code;
1397
5.11k
}
1398
1399
int pdfi_set_input_stream(pdf_context *ctx, stream *stm)
1400
6.24k
{
1401
6.24k
    byte *Buffer = NULL;
1402
6.24k
    char *s = NULL, *test = NULL;
1403
6.24k
    float version = 0.0;
1404
6.24k
    gs_offset_t Offset = 0;
1405
6.24k
    int64_t bytes = 0, leftover = 0, bytes_left = 0;
1406
6.24k
    bool found = false;
1407
6.24k
    int code;
1408
1409
    /* In case of broken PDF files, the repair could run off the end of the
1410
     * file, so make sure that doing so does *not* automagically close the file
1411
     */
1412
6.24k
    stm->close_at_eod = false;
1413
1414
6.24k
    ctx->main_stream = (pdf_c_stream *)gs_alloc_bytes(ctx->memory, sizeof(pdf_c_stream), "PDF interpreter allocate main PDF stream");
1415
6.24k
    if (ctx->main_stream == NULL)
1416
0
        return_error(gs_error_VMerror);
1417
6.24k
    memset(ctx->main_stream, 0x00, sizeof(pdf_c_stream));
1418
6.24k
    ctx->main_stream->s = stm;
1419
1420
6.24k
    Buffer = gs_alloc_bytes(ctx->memory, BUF_SIZE, "PDF interpreter - allocate working buffer for file validation");
1421
6.24k
    if (Buffer == NULL) {
1422
0
        code = gs_error_VMerror;
1423
0
        goto error;
1424
0
    }
1425
1426
    /* Determine file size */
1427
6.24k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
1428
6.24k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_END);
1429
6.24k
    ctx->main_stream_length = pdfi_tell(ctx->main_stream);
1430
6.24k
    Offset = BUF_SIZE;
1431
6.24k
    bytes = BUF_SIZE;
1432
6.24k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
1433
1434
6.24k
    bytes = Offset = min(BUF_SIZE - 1, ctx->main_stream_length);
1435
1436
6.24k
    if (ctx->args.pdfdebug)
1437
0
        outprintf(ctx->memory, "%% Reading header\n");
1438
1439
6.24k
    bytes = pdfi_read_bytes(ctx, Buffer, 1, Offset, ctx->main_stream);
1440
6.24k
    if (bytes <= 0) {
1441
0
        errprintf(ctx->memory, "Failed to read any bytes from input stream\n");
1442
0
        code = gs_error_ioerror;
1443
0
        goto error;
1444
0
    }
1445
6.24k
    if (bytes < 8) {
1446
1
        errprintf(ctx->memory, "Failed to read enough bytes for a valid PDF header from input stream\n");
1447
1
        code = gs_error_ioerror;
1448
1
        goto error;
1449
1
    }
1450
6.24k
    Buffer[Offset] = 0x00;
1451
1452
    /* First check for existence of header */
1453
6.24k
    test = (char *)Buffer;
1454
6.24k
    bytes_left = bytes;
1455
6.24k
    s = strstr((char *)test, "%PDF-");
1456
6.24k
    if (s == NULL) {
1457
0
        if ((code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_GARBAGE_B4HDR, "pdfi_set_input_stream", "")) < 0) {
1458
0
            goto error;
1459
0
        }
1460
0
    }
1461
    /* Garbage before the header can be anything, including binary and NULL (0x00) characters
1462
     * which can defeat using strstr, so if we fail to find a header, try moving on by the length
1463
     * of the C string + 1 and try again.
1464
     */
1465
6.24k
    while (s == NULL) {
1466
0
        bytes_left -= (strlen(test) + 1);
1467
0
        if (bytes_left < 5)
1468
0
            break;
1469
0
        test += strlen(test) + 1;
1470
0
        s = strstr((char *)test, "%PDF-");
1471
0
    };
1472
6.24k
    if (s == NULL) {
1473
0
        char extra_info[gp_file_name_sizeof];
1474
1475
0
        if (ctx->filename)
1476
0
            gs_snprintf(extra_info, sizeof(extra_info), "%% File %s does not appear to be a PDF file (no %%PDF in first 2Kb of file)\n", ctx->filename);
1477
0
        else
1478
0
            gs_snprintf(extra_info, sizeof(extra_info), "%% File does not appear to be a PDF stream (no %%PDF in first 2Kb of stream)\n");
1479
1480
0
        if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, E_PDF_NOHEADER, "pdfi_set_input_stream", extra_info) ) < 0)
1481
0
            goto error;
1482
6.24k
    } else {
1483
        /* Now extract header version (may be overridden later) */
1484
6.24k
        if (sscanf(s + 5, "%f", &version) != 1) {
1485
121
            ctx->HeaderVersion = 0;
1486
121
            if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, E_PDF_NOHEADERVERSION, "pdfi_set_input_stream", (char *)"%% Unable to read PDF version from header\n")) < 0)
1487
0
                goto error;
1488
121
        }
1489
6.12k
        else {
1490
6.12k
            ctx->HeaderVersion = version;
1491
6.12k
            s += 5;
1492
24.6k
            while (((*s >= '0' && *s <= '9') || *s == '.') && *s != 0x00)
1493
18.5k
                s++;
1494
6.28k
            while (*s != 0x00) {
1495
6.27k
                if (*s == 0x09 || *s== 0x0c || *s == 0x20) {
1496
169
                    s++;
1497
169
                    continue;
1498
169
                }
1499
6.10k
                if (*s != 0x0A && *s != 0x0D) {
1500
231
                    if ((code = pdfi_set_warning_stop(ctx, 0, NULL, W_PDF_VERSION_NO_EOL, "pdfi_set_input_stream", (char *)"%% PDF version not immediately followed with EOL\n")) < 0)
1501
0
                        goto error;
1502
231
                }
1503
6.10k
                break;
1504
6.10k
            }
1505
6.12k
        }
1506
6.24k
        if (ctx->args.pdfdebug)
1507
0
            outprintf(ctx->memory, "%% Found header, PDF version is %f\n", ctx->HeaderVersion);
1508
6.24k
    }
1509
1510
    /* Jump to EOF and scan backwards looking for startxref */
1511
6.24k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_END);
1512
1513
6.24k
    if (ctx->args.pdfdebug)
1514
0
        outprintf(ctx->memory, "%% Searching for 'startxref' keyword\n");
1515
1516
    /* Initially read min(BUF_SIZE, file_length) bytes of data to the buffer */
1517
6.24k
    bytes = Offset;
1518
1519
65.5k
    do {
1520
65.5k
        byte *last_lineend = NULL;
1521
65.5k
        uint32_t read;
1522
1523
65.5k
        if (pdfi_seek(ctx, ctx->main_stream, ctx->main_stream_length - Offset, SEEK_SET) != 0) {
1524
0
            char msg[128];
1525
0
            gs_snprintf(msg, 128, "%% File is smaller than %"PRIi64" bytes\n", (int64_t)Offset);
1526
0
            code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_ioerror), NULL, E_PDF_GS_LIB_ERROR, "pdfi_set_input_stream", msg);
1527
0
            goto error;
1528
0
        }
1529
65.5k
        read = pdfi_read_bytes(ctx, Buffer, 1, bytes, ctx->main_stream);
1530
1531
65.5k
        if (read <= 0) {
1532
0
            char msg[128];
1533
0
            gs_snprintf(msg, 128, "Failed to read %"PRIi64" bytes from file\n", (int64_t)bytes);
1534
0
            code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_ioerror), NULL, E_PDF_GS_LIB_ERROR, "pdfi_set_input_stream", msg);
1535
0
            goto error;
1536
0
        }
1537
1538
        /* When reading backwards, if we ran out of data in the last buffer while looking
1539
         * for a 'startxref, but we had found a linefeed, then we preserved everything
1540
         * from the beginning of the buffer up to that linefeed, by copying it to the end
1541
         * of the buffer and reducing the number of bytes to read so that it should have filled
1542
         * in the gap. If we didn't read enough bytes, then we have a gap between the end of
1543
         * the data we just read and the leftover data from teh last buffer. Move the preserved
1544
         * data down to meet the end of the data we just read.
1545
         */
1546
65.5k
        if (bytes != read && leftover != 0)
1547
0
            memcpy(Buffer + read, Buffer + bytes, leftover);
1548
1549
        /* As above, if we had any leftover data from the last buffer then increase the
1550
         * number of bytes available by that amount. We increase 'bytes' (the number of bytes
1551
         * to read) to the same value, which should mean we read an entire buffer's worth. Of
1552
         * course if we have any data left out of this buffer we'll reduce bytes again...
1553
         */
1554
65.5k
        read = bytes = read + leftover;
1555
1556
        /* Now search backwards in the buffer for the startxref token */
1557
126M
        while(read) {
1558
126M
            if (memcmp(Buffer + read - 9, "startxref", 9) == 0) {
1559
3.32k
                found = true;
1560
3.32k
                break;
1561
126M
            } else {
1562
126M
                if (Buffer[read - 1] == 0x0a || Buffer[read - 1] == 0x0d)
1563
1.93M
                    last_lineend = Buffer + read;
1564
126M
            }
1565
126M
            read--;
1566
126M
        }
1567
65.5k
        if (found) {
1568
3.32k
            byte *b = Buffer + read;
1569
1570
            /* Success! stop now */
1571
3.32k
            if(sscanf((char *)b, " %"PRIdOFFSET"", &ctx->startxref) != 1) {
1572
41
                if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, E_PDF_BADSTARTXREF, "pdfi_set_input_stream", "Unable to read offset of xref from PDF file\n")) < 0)
1573
0
                    goto error;
1574
41
            }
1575
3.32k
            break;
1576
62.2k
        } else {
1577
            /* Our file read could conceivably have read back to the point where we read
1578
             * part of the 'startxref' token, but not all of it. So we want to preserve
1579
             * the data in the buffer, but not all of it obviously! The 'startxref' should be followed
1580
             * by a line ending, so above we keep a note of the last line ending. If we found one, then
1581
             * we preserve from the start of the buffer to that point. This could slow us up if the file
1582
             * Is broken, or has a load of junk after the EOF, because we could potentially be saving a
1583
             * lot of data on each pass, but that's only going to happen with bad files.
1584
             * Note we reduce the number of bytes to read so that it just fits into the buffer up to the
1585
             * beginning of the data we preserved.
1586
             */
1587
62.2k
            if (last_lineend) {
1588
57.2k
                leftover = last_lineend - Buffer;
1589
                /* Ensure we don't try to copy more than half a buffer, because that will
1590
                 * end up overrunning the buffer end. Since we are only doing this to
1591
                 * ensure we don't drop a partial 'startxref' that's far more than enough.
1592
                 */
1593
57.2k
                if (leftover < BUF_SIZE / 2) {
1594
56.2k
                    memmove(Buffer + bytes - leftover, last_lineend, leftover);
1595
56.2k
                    bytes -= leftover;
1596
56.2k
                } else
1597
1.04k
                    leftover = 0;
1598
57.2k
            } else
1599
5.01k
                leftover = 0;
1600
62.2k
        }
1601
1602
62.2k
        Offset += bytes;
1603
62.2k
    } while(Offset < ctx->main_stream_length);
1604
1605
6.24k
    if (!found) {
1606
2.91k
        if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_undefined), NULL, E_PDF_NOSTARTXREF, "pdfi_set_input_stream", NULL)) < 0)
1607
0
            goto error;
1608
2.91k
    }
1609
1610
6.24k
    code = pdfi_init_file(ctx);
1611
1612
6.24k
error:
1613
6.24k
    gs_free_object(ctx->memory, Buffer, "PDF interpreter - allocate working buffer for file validation");
1614
6.24k
    return code;
1615
6.24k
}
1616
1617
int pdfi_open_pdf_file(pdf_context *ctx, char *filename)
1618
0
{
1619
0
    stream *s = NULL;
1620
0
    int code;
1621
1622
0
    if (ctx->args.pdfdebug)
1623
0
        outprintf(ctx->memory, "%% Attempting to open %s as a PDF file\n", filename);
1624
1625
0
    ctx->filename = (char *)gs_alloc_bytes(ctx->memory, strlen(filename) + 1, "copy of filename");
1626
0
    if (ctx->filename == NULL)
1627
0
        return_error(gs_error_VMerror);
1628
0
    strcpy(ctx->filename, filename);
1629
1630
0
    s = sfopen(filename, "r", ctx->memory);
1631
0
    if (s == NULL) {
1632
0
        emprintf1(ctx->memory, "Failed to open file %s\n", filename);
1633
0
        return_error(gs_error_ioerror);
1634
0
    }
1635
0
    code = pdfi_set_input_stream(ctx, s);
1636
0
    return code;
1637
0
}
1638
1639
static size_t pdfi_grdir_path_string_match(const byte *str, size_t sl0, byte *pat, size_t pl)
1640
0
{
1641
0
    bool found = false;
1642
0
    size_t sl = sl0;
1643
1644
0
    while (found == false) {
1645
0
        if (pl > sl)
1646
0
            break;
1647
0
        if (*str == *pat && memcmp(str, pat, pl) == 0)
1648
0
            found = true;
1649
0
        else {
1650
0
            str++;
1651
0
            sl--;
1652
0
        }
1653
0
    }
1654
0
    if (found)
1655
0
        return (sl0 - sl) + pl;
1656
0
    else
1657
0
        return 0;
1658
0
}
1659
1660
int pdfi_add_paths_to_search_paths(pdf_context *ctx, const char *ppath, int l, bool fontpath)
1661
0
{
1662
0
    int i, slen, npaths = (l > 0) ? 1 : 0;
1663
0
    const char *p = ppath;
1664
0
    char *ps;
1665
0
    const char *pe = p + l + 1;
1666
0
    int code = 0;
1667
0
    static const char *resstr = "Resource";
1668
0
    const int restrlen = strlen(resstr);
1669
0
    const char *dirsepstr = gp_file_name_directory_separator();
1670
0
    const int dirsepstrlen = strlen(dirsepstr);
1671
0
    char genresstr[64];
1672
1673
0
    for (ps = (char *)p; ps < pe; ps++) {
1674
0
        if (*ps == gp_file_name_list_separator)
1675
0
           npaths++;
1676
0
    }
1677
1678
0
    if (npaths > 0) {
1679
0
        gs_param_string *pathstrings;
1680
0
        int new_npaths = ctx->search_paths.num_resource_paths + npaths;
1681
1682
0
        if (fontpath != true) {
1683
0
            pathstrings = (gs_param_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_param_string) * new_npaths, "array of paths");
1684
0
            if (pathstrings == NULL)
1685
0
                return_error(gs_error_VMerror);
1686
1687
0
            memset(pathstrings, 0x00, sizeof(gs_param_string) * new_npaths);
1688
1689
0
            for (i = 1; i <= ctx->search_paths.num_init_resource_paths; i++) {
1690
0
                pathstrings[new_npaths - i] = ctx->search_paths.resource_paths[ctx->search_paths.num_resource_paths - i];
1691
0
            }
1692
1693
0
            for (i = 0; i < ctx->search_paths.num_resource_paths - ctx->search_paths.num_init_resource_paths; i++) {
1694
0
                pathstrings[i] = ctx->search_paths.resource_paths[i];
1695
0
            }
1696
            /* DO NOT CHANGE "i" BETWEEN HERE....... */
1697
0
            gs_free_object(ctx->memory, ctx->search_paths.resource_paths, "old array of paths");
1698
0
            ctx->search_paths.resource_paths = pathstrings;
1699
0
            ctx->search_paths.num_resource_paths += npaths;
1700
1701
            /* .....AND HERE */
1702
0
            for (ps = (char *)p; ps < pe; ps++) {
1703
0
                if (*ps == gp_file_name_list_separator || ps == pe - 1) {
1704
0
                    if (*p == gp_file_name_list_separator) p++; /* move past the separator */
1705
0
                    slen = ps - p;
1706
0
                    pathstrings[i].data = (byte *)gs_alloc_bytes(ctx->memory, slen, "path string body");
1707
1708
0
                    if (pathstrings[i].data == NULL) {
1709
0
                        code = gs_note_error(gs_error_VMerror);
1710
0
                        break;
1711
0
                    }
1712
1713
0
                    memcpy((char *)pathstrings[i].data, p, slen);
1714
0
                    pathstrings[i].size = slen;
1715
0
                    pathstrings[i].persistent = false;
1716
0
                    i++;
1717
0
                    p = ps++;
1718
0
                }
1719
0
            }
1720
0
            if ((restrlen + 2 * dirsepstrlen) < 64) {
1721
0
                size_t grdlen;
1722
1723
0
                memcpy(genresstr, resstr, restrlen  +1); /* +1 So we get the null terminator */
1724
0
                strncat(genresstr, dirsepstr, dirsepstrlen);
1725
1726
0
                for (i = 0; i < ctx->search_paths.num_resource_paths; i++) {
1727
0
                    if ((grdlen = pdfi_grdir_path_string_match(ctx->search_paths.resource_paths[i].data, ctx->search_paths.resource_paths[i].size, (byte *)genresstr, restrlen + dirsepstrlen)) > 0) {
1728
0
                        ctx->search_paths.genericresourcedir.data = ctx->search_paths.resource_paths[i].data;
1729
0
                        ctx->search_paths.genericresourcedir.size = grdlen;
1730
0
                        ctx->search_paths.genericresourcedir.persistent = true;
1731
0
                        break;
1732
0
                    }
1733
0
                }
1734
0
            }
1735
0
        }
1736
0
        else {
1737
0
            p = ppath;
1738
0
            pathstrings = (gs_param_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_param_string) * (npaths + ctx->search_paths.num_font_paths), "array of font paths");
1739
0
            if (pathstrings == NULL)
1740
0
                return_error(gs_error_VMerror);
1741
1742
0
            memset(pathstrings, 0x00, sizeof(gs_param_string) * (npaths + ctx->search_paths.num_font_paths));
1743
1744
0
            for (i = 0; i < ctx->search_paths.num_font_paths; i++) {
1745
0
                pathstrings[ctx->search_paths.num_font_paths + i] = ctx->search_paths.font_paths[i];
1746
0
            }
1747
0
            gs_free_object(ctx->memory, ctx->search_paths.font_paths, "old array of paths");
1748
0
            ctx->search_paths.font_paths = pathstrings;
1749
0
            ctx->search_paths.num_font_paths += npaths;
1750
1751
0
            i = 0;
1752
0
            for (ps = (char *)p; ps < pe; ps++) {
1753
0
                if (*ps == gp_file_name_list_separator || ps == pe - 1) {
1754
0
                    slen = ps - p;
1755
0
                    pathstrings[i].data = (byte *)gs_alloc_bytes(ctx->memory, slen, "path string body");
1756
1757
0
                    if (pathstrings[i].data == NULL) {
1758
0
                        code = gs_note_error(gs_error_VMerror);
1759
0
                        break;
1760
0
                    }
1761
1762
0
                    memcpy((char *)pathstrings[i].data, p, slen);
1763
0
                    pathstrings[i].size = slen;
1764
0
                    pathstrings[i].persistent = false;
1765
0
                    i++;
1766
0
                    p = ps++;
1767
0
                }
1768
0
            }
1769
0
        }
1770
0
    }
1771
1772
0
    return code;
1773
0
}
1774
1775
int pdfi_add_initial_paths_to_search_paths(pdf_context *ctx, const char *ppath, int l)
1776
0
{
1777
0
    int code;
1778
0
    if (ctx->search_paths.num_resource_paths != 0)
1779
0
        return_error(gs_error_invalidaccess);
1780
1781
0
    code = pdfi_add_paths_to_search_paths(ctx, ppath, l, false);
1782
0
    ctx->search_paths.num_init_resource_paths = ctx->search_paths.num_resource_paths;
1783
1784
0
    return code;
1785
0
}
1786
1787
static void pdfi_free_search_paths(pdf_context *ctx)
1788
6.24k
{
1789
6.24k
    int i;
1790
87.3k
    for (i = 0; i < ctx->search_paths.num_resource_paths; i++) {
1791
81.1k
        if (ctx->search_paths.resource_paths[i].persistent == false)
1792
81.1k
            gs_free_object(ctx->memory, (byte *)ctx->search_paths.resource_paths[i].data, "path string body");
1793
81.1k
    }
1794
6.24k
    for (i = 0; i < ctx->search_paths.num_font_paths; i++) {
1795
0
        if (ctx->search_paths.font_paths[i].persistent == false)
1796
0
            gs_free_object(ctx->memory, (byte *)ctx->search_paths.font_paths[i].data, "path string body");
1797
0
    }
1798
6.24k
    gs_free_object(ctx->memory, (byte *)ctx->search_paths.resource_paths, "array of paths");
1799
6.24k
    gs_free_object(ctx->memory, (byte *)ctx->search_paths.font_paths, "array of font paths");
1800
1801
6.24k
    if (ctx->search_paths.genericresourcedir.persistent == false)
1802
6.24k
        gs_free_object(ctx->memory, (byte *)ctx->search_paths.genericresourcedir.data, "generic resource directory");
1803
6.24k
}
1804
1805
static void pdfi_free_fontmapfiles(pdf_context *ctx)
1806
6.24k
{
1807
6.24k
    int i;
1808
6.24k
    for (i = 0; i < ctx->num_fontmapfiles; i++) {
1809
0
        gs_free_object(ctx->memory, ctx->fontmapfiles[i].data, "fontmapfiles string body");
1810
0
    }
1811
6.24k
    gs_free_object(ctx->memory, ctx->fontmapfiles, "fontmapfiles array");
1812
6.24k
}
1813
1814
/* The fontmap file list doesn't extend, later settings in the command line override earlier ones
1815
   (Unlike the "-I" search paths above).
1816
 */
1817
int pdfi_add_fontmapfiles(pdf_context *ctx, const char *ppath, int l)
1818
0
{
1819
0
    int i, nfilenames = (l > 0) ? 1 : 0;
1820
0
    const char *p = ppath;
1821
0
    char *ps;
1822
0
    const char *pe = p + l + 1;
1823
0
    int code = 0;
1824
1825
0
    pdfi_free_fontmapfiles(ctx);
1826
1827
0
    for (ps = (char *)p; ps < pe; ps++) {
1828
0
        if (*ps == gp_file_name_list_separator)
1829
0
           nfilenames++;
1830
0
    }
1831
0
    if (nfilenames > 0) {
1832
0
        ctx->fontmapfiles = (gs_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_string) * nfilenames, "array of fontmap files");
1833
0
        if (ctx->fontmapfiles == NULL) {
1834
0
            return_error(gs_error_VMerror);
1835
0
        }
1836
0
        else {
1837
0
           memset(ctx->fontmapfiles, 0x00, sizeof(gs_string) * nfilenames);
1838
0
           ctx->num_fontmapfiles = nfilenames;
1839
1840
0
           for (i = 0; i < nfilenames; i++) {
1841
0
               for (ps = (char *)p; ps < pe; ps++) {
1842
0
                   if (*ps == gp_file_name_list_separator)
1843
0
                       break;
1844
0
               }
1845
0
               ctx->fontmapfiles[i].data = gs_alloc_bytes(ctx->memory, ps - p, "fontmap file name body");
1846
0
               if (ctx->fontmapfiles[i].data == NULL) {
1847
0
                    code = gs_note_error(gs_error_VMerror);
1848
0
                    goto done;
1849
0
               }
1850
0
               memcpy(ctx->fontmapfiles[i].data, p, ps - p);
1851
0
               ctx->fontmapfiles[i].size = ps - p;
1852
0
               p = ps + 1;
1853
0
           }
1854
0
        }
1855
0
    }
1856
0
done:
1857
0
    return code;
1858
0
}
1859
1860
/***********************************************************************************/
1861
/* Highest level functions. The context we create here is returned to the 'PL'     */
1862
/* implementation, in future we plan to return it to PostScript by wrapping a      */
1863
/* gargabe collected object 'ref' around it and returning that to the PostScript   */
1864
/* world. custom PostScript operators will then be able to render pages, annots,   */
1865
/* AcroForms etc by passing the opaque object back to functions here, allowing     */
1866
/* the interpreter access to its context.                                          */
1867
1868
/* We start with routines for creating and destroying the interpreter context */
1869
pdf_context *pdfi_create_context(gs_memory_t *mem)
1870
6.24k
{
1871
6.24k
    pdf_context *ctx = NULL;
1872
6.24k
    gs_gstate *pgs = NULL;
1873
6.24k
    int code = 0;
1874
6.24k
    gs_memory_t *pmem = mem->non_gc_memory;
1875
#if PDFI_LEAK_CHECK
1876
    gs_memory_status_t mstat;
1877
    code = gs_memory_chunk_wrap(&pmem, mem->non_gc_memory);
1878
    if (code < 0)
1879
        return NULL;
1880
    gs_memory_status(pmem, &mstat);
1881
#endif
1882
1883
6.24k
    ctx = (pdf_context *) gs_alloc_bytes(pmem, sizeof(pdf_context), "pdf_create_context");
1884
1885
6.24k
    pgs = gs_gstate_alloc(pmem);
1886
1887
6.24k
    if (!ctx || !pgs)
1888
0
    {
1889
0
        if (ctx)
1890
0
            gs_free_object(pmem, ctx, "pdf_create_context");
1891
0
        if (pgs)
1892
0
            gs_gstate_free(pgs);
1893
0
        return NULL;
1894
0
    }
1895
1896
6.24k
    memset(ctx, 0, sizeof(pdf_context));
1897
6.24k
    ctx->memory = pmem;
1898
6.24k
    ctx->type = PDF_CTX;
1899
6.24k
    ctx->flags = 0;
1900
6.24k
    ctx->refcnt = 1;
1901
6.24k
    ctx->ctx = ctx;
1902
1903
#if PDFI_LEAK_CHECK
1904
    ctx->memstat = mstat;
1905
#endif
1906
1907
6.24k
    ctx->stack_bot = (pdf_obj **)gs_alloc_bytes(ctx->memory, INITIAL_STACK_SIZE * sizeof (pdf_obj *), "pdf_imp_allocate_interp_stack");
1908
6.24k
    if (ctx->stack_bot == NULL) {
1909
0
        gs_free_object(pmem, ctx, "pdf_create_context");
1910
0
        gs_gstate_free(pgs);
1911
0
        return NULL;
1912
0
    }
1913
6.24k
    ctx->stack_size = INITIAL_STACK_SIZE;
1914
6.24k
    ctx->stack_top = ctx->stack_bot - 1;
1915
6.24k
    code = sizeof(pdf_obj *);
1916
6.24k
    code *= ctx->stack_size;
1917
6.24k
    ctx->stack_limit = ctx->stack_bot + ctx->stack_size;
1918
1919
6.24k
    code = pdfi_init_font_directory(ctx);
1920
6.24k
    if (code < 0) {
1921
0
        gs_free_object(pmem, ctx->stack_bot, "pdf_create_context");
1922
0
        gs_free_object(pmem, ctx, "pdf_create_context");
1923
0
        gs_gstate_free(pgs);
1924
0
        return NULL;
1925
0
    }
1926
1927
6.24k
    code = gsicc_init_iccmanager(pgs);
1928
6.24k
    if (code < 0) {
1929
0
        gs_free_object(ctx->memory, ctx->font_dir, "pdf_create_context");
1930
0
        gs_free_object(pmem, ctx->stack_bot, "pdf_create_context");
1931
0
        gs_free_object(pmem, ctx, "pdf_create_context");
1932
0
        gs_gstate_free(pgs);
1933
0
        return NULL;
1934
0
    }
1935
1936
6.24k
    ctx->pgs = pgs;
1937
6.24k
    code = pdfi_gstate_set_client(ctx, pgs);
1938
6.24k
    if (code < 0) {
1939
0
        gs_free_object(ctx->memory, ctx->font_dir, "pdf_create_context");
1940
0
        gs_free_object(pmem, ctx->stack_bot, "pdf_create_context");
1941
0
        gs_free_object(pmem, ctx, "pdf_create_context");
1942
0
        gs_gstate_free(pgs);
1943
0
        return NULL;
1944
0
    }
1945
1946
    /* Some (but not all) path construction operations can either return
1947
     * an error or clamp values when out of range. In order to match Ghostscript's
1948
     * PDF interpreter written in PostScript, we need to clamp them.
1949
     */
1950
6.24k
    gs_setlimitclamp(pgs, true);
1951
1952
    /* Declare PDL client support for high level patterns, for the benefit
1953
     * of pdfwrite and other high-level devices
1954
     */
1955
6.24k
    ctx->pgs->have_pattern_streams = true;
1956
6.24k
    ctx->device_state.preserve_tr_mode = 0;
1957
6.24k
    ctx->args.notransparency = false;
1958
1959
6.24k
    ctx->main_stream = NULL;
1960
1961
    /* Setup some flags that don't default to 'false' */
1962
6.24k
    ctx->args.showannots = true;
1963
6.24k
    ctx->args.preserveannots = true;
1964
6.24k
    ctx->args.preservemarkedcontent = true;
1965
6.24k
    ctx->args.preserveembeddedfiles = true;
1966
6.24k
    ctx->args.preservedocview = true;
1967
    /* NOTE: For testing certain annotations on cluster, might want to set this to false */
1968
6.24k
    ctx->args.printed = false; /* True if OutputFile is set, false otherwise see pdftop.c, pdf_impl_set_param() */
1969
1970
    /* Initially, prefer the XrefStm in a hybrid file */
1971
6.24k
    ctx->prefer_xrefstm = true;
1972
1973
    /* We decrypt strings from encrypted files until we start a page */
1974
6.24k
    ctx->encryption.decrypt_strings = true;
1975
6.24k
    ctx->get_glyph_name = pdfi_glyph_name;
1976
6.24k
    ctx->get_glyph_index = pdfi_glyph_index;
1977
1978
6.24k
    ctx->job_gstate_level = ctx->pgs->level;
1979
    /* Weirdly the graphics library wants us to always have two gstates, the
1980
     * initial state and at least one saved state. if we don't then when we
1981
     * grestore back to the initial state, it immediately saves another one.
1982
     */
1983
6.24k
    code = gs_gsave(ctx->pgs);
1984
6.24k
    if (code < 0) {
1985
0
        gs_free_object(ctx->memory, ctx->font_dir, "pdf_create_context");
1986
0
        gs_free_object(pmem, ctx->stack_bot, "pdf_create_context");
1987
0
        gs_gstate_free(ctx->pgs);
1988
0
        gs_free_object(pmem, ctx, "pdf_create_context");
1989
0
        return NULL;
1990
0
    }
1991
#if REFCNT_DEBUG
1992
    ctx->UID = 1;
1993
#endif
1994
#if CACHE_STATISTICS
1995
    ctx->hits = 0;
1996
    ctx->misses = 0;
1997
    ctx->compressed_hits = 0;
1998
    ctx->compressed_misses = 0;
1999
#endif
2000
#ifdef DEBUG
2001
    ctx->args.verbose_errors = ctx->args.verbose_warnings = 1;
2002
#endif
2003
6.24k
    return ctx;
2004
6.24k
}
2005
2006
/* Purge all */
2007
static bool
2008
pdfi_fontdir_purge_all(const gs_memory_t * mem, cached_char * cc, void *dummy)
2009
103k
{
2010
103k
    return true;
2011
103k
}
2012
2013
#if DEBUG_CACHE
2014
#if DEBUG_CACHE_FREE
2015
static void
2016
pdfi_print_cache(pdf_context *ctx)
2017
{
2018
    pdf_obj_cache_entry *entry = ctx->cache_LRU, *next;
2019
2020
    outprintf(ctx->memory, "CACHE: #entries=%d\n", ctx->cache_entries);
2021
    while(entry) {
2022
        next = entry->next;
2023
#if REFCNT_DEBUG
2024
        outprintf(ctx->memory, "UID:%ld, Object:%d, refcnt:%d, next=%p, prev=%p\n",
2025
                  entry->o->UID, entry->o->object_num, entry->o->refcnt,
2026
                  entry->next, entry->previous);
2027
#else
2028
        outprintf(ctx->memory, "Object:%d, refcnt:%d, next=%p, prev=%p\n",
2029
                  entry->o->object_num, entry->o->refcnt,
2030
                  entry->next, entry->previous);
2031
#endif
2032
        entry = next;
2033
    }
2034
}
2035
#else
2036
static void
2037
pdfi_print_cache(pdf_context *ctx)
2038
{}
2039
#endif
2040
#endif /* DEBUG */
2041
2042
#if PURGE_CACHE_PER_PAGE
2043
void
2044
pdfi_purge_obj_cache(pdf_context *ctx)
2045
{
2046
    if (ctx->cache_entries != 0) {
2047
        pdf_obj_cache_entry *entry = ctx->cache_LRU, *next;
2048
2049
        while(entry) {
2050
            next = entry->next;
2051
            if (entry->o->object_num != 0) {
2052
                ctx->xref_table->xref[entry->o->object_num].cache = NULL;
2053
            }
2054
            pdfi_countdown(entry->o);
2055
            ctx->cache_entries--;
2056
            gs_free_object(ctx->memory, entry, "pdfi_clear_context, free LRU");
2057
            entry = next;
2058
#if REFCNT_DEBUG
2059
            ctx->cache_LRU = entry;
2060
#endif
2061
        }
2062
        ctx->cache_LRU = ctx->cache_MRU = NULL;
2063
        ctx->cache_entries = 0;
2064
    }
2065
}
2066
#endif
2067
2068
/* pdfi_clear_context frees all the PDF objects associated with interpreting a given
2069
 * PDF file. Once we've called this we can happily run another file. This function is
2070
 * called by pdf_free_context (in case of errors during the file leaving state around)
2071
 * and by pdfi_close_pdf_file.
2072
 */
2073
int pdfi_clear_context(pdf_context *ctx)
2074
6.24k
{
2075
#if CACHE_STATISTICS
2076
    float compressed_hit_rate = 0.0, hit_rate = 0.0;
2077
2078
    if (ctx->compressed_hits > 0 || ctx->compressed_misses > 0)
2079
        compressed_hit_rate = (float)ctx->compressed_hits / (float)(ctx->compressed_hits + ctx->compressed_misses);
2080
    if (ctx->hits > 0 || ctx->misses > 0)
2081
        hit_rate = (float)ctx->hits / (float)(ctx->hits + ctx->misses);
2082
2083
    outprintf(ctx->memory, "Number of normal object cache hits: %"PRIi64"\n", ctx->hits);
2084
    outprintf(ctx->memory, "Number of normal object cache misses: %"PRIi64"\n", ctx->misses);
2085
    outprintf(ctx->memory, "Number of compressed object cache hits: %"PRIi64"\n", ctx->compressed_hits);
2086
    outprintf(ctx->memory, "Number of compressed object cache misses: %"PRIi64"\n", ctx->compressed_misses);
2087
    outprintf(ctx->memory, "Normal object cache hit rate: %f\n", hit_rate);
2088
    outprintf(ctx->memory, "Compressed object cache hit rate: %f\n", compressed_hit_rate);
2089
#endif
2090
6.24k
    if (ctx->PathSegments != NULL) {
2091
259
        gs_free_object(ctx->memory, ctx->PathSegments, "pdfi_clear_context");
2092
259
        ctx->PathSegments = NULL;
2093
259
    }
2094
6.24k
    if (ctx->PathPts != NULL) {
2095
259
        gs_free_object(ctx->memory, ctx->PathPts, "pdfi_clear_context");
2096
259
        ctx->PathPts = NULL;
2097
259
    }
2098
2099
6.24k
    if (ctx->args.PageList) {
2100
0
        gs_free_object(ctx->memory, ctx->args.PageList, "pdfi_clear_context");
2101
0
        ctx->args.PageList = NULL;
2102
0
    }
2103
6.24k
    if (ctx->Trailer) {
2104
2.97k
        pdfi_countdown(ctx->Trailer);
2105
2.97k
        ctx->Trailer = NULL;
2106
2.97k
    }
2107
2108
6.24k
    if (ctx->AcroForm) {
2109
510
        pdfi_countdown(ctx->AcroForm);
2110
510
        ctx->AcroForm = NULL;
2111
510
    }
2112
2113
6.24k
    if(ctx->Root) {
2114
5.29k
        pdfi_countdown(ctx->Root);
2115
5.29k
        ctx->Root = NULL;
2116
5.29k
    }
2117
2118
6.24k
    if (ctx->Info) {
2119
1.73k
        pdfi_countdown(ctx->Info);
2120
1.73k
        ctx->Info = NULL;
2121
1.73k
    }
2122
2123
6.24k
    if (ctx->PagesTree) {
2124
5.09k
        pdfi_countdown(ctx->PagesTree);
2125
5.09k
        ctx->PagesTree = NULL;
2126
5.09k
    }
2127
2128
6.24k
    if (ctx->args.cidfsubstpath.data != NULL) {
2129
0
        gs_free_object(ctx->memory, ctx->args.cidfsubstpath.data, "cidfsubstpath.data");
2130
0
        ctx->args.cidfsubstpath.data = NULL;
2131
0
    }
2132
2133
6.24k
    if (ctx->args.cidfsubstfont.data != NULL) {
2134
0
        gs_free_object(ctx->memory, ctx->args.cidfsubstfont.data, "cidfsubstfont.data");
2135
0
        ctx->args.cidfsubstfont.data = NULL;
2136
0
    }
2137
2138
6.24k
    if (ctx->args.defaultfont.data != NULL) {
2139
0
        gs_free_object(ctx->memory, ctx->args.defaultfont.data, "cidfsubstfont.data");
2140
0
        ctx->args.defaultfont.data = NULL;
2141
0
    }
2142
2143
6.24k
    pdfi_free_cstring_array(ctx, &ctx->args.showannottypes);
2144
6.24k
    pdfi_free_cstring_array(ctx, &ctx->args.preserveannottypes);
2145
2146
6.24k
    pdfi_doc_page_array_free(ctx);
2147
2148
6.24k
    if (ctx->xref_table) {
2149
5.86k
        pdfi_countdown(ctx->xref_table);
2150
5.86k
        ctx->xref_table = NULL;
2151
5.86k
    }
2152
2153
6.24k
    pdfi_free_OptionalRoot(ctx);
2154
2155
6.24k
    if (ctx->stack_bot)
2156
6.24k
        pdfi_clearstack(ctx);
2157
2158
6.24k
    if (ctx->filename) {
2159
        /* This should already be closed! */
2160
0
        pdfi_close_pdf_file(ctx);
2161
0
        gs_free_object(ctx->memory, ctx->filename, "pdfi_clear_context, free copy of filename");
2162
0
        ctx->filename = NULL;
2163
0
    }
2164
2165
6.24k
    if (ctx->main_stream) {
2166
6.24k
        gs_free_object(ctx->memory, ctx->main_stream, "pdfi_clear_context, free main PDF stream");
2167
6.24k
        ctx->main_stream = NULL;
2168
6.24k
    }
2169
6.24k
    ctx->main_stream_length = 0;
2170
2171
6.24k
    if(ctx->pgs != NULL) {
2172
6.24k
        gx_pattern_cache_free(ctx->pgs->pattern_cache);
2173
6.24k
        ctx->pgs->pattern_cache = NULL;
2174
6.24k
        if (ctx->pgs->font)
2175
0
            pdfi_countdown_current_font(ctx);
2176
2177
        /* We use gs_grestore_only() instead of gs_grestore, because gs_grestore
2178
         * will not restore below two gstates and we want to clear the entire
2179
         * stack of saved states, back to the initial state.
2180
         */
2181
12.4k
        while (ctx->pgs->level != ctx->job_gstate_level && ctx->pgs->saved)
2182
6.24k
            gs_grestore_only(ctx->pgs);
2183
6.24k
    }
2184
2185
6.24k
    pdfi_free_DefaultQState(ctx);
2186
6.24k
    pdfi_oc_free(ctx);
2187
2188
6.24k
    if(ctx->encryption.EKey) {
2189
66
        pdfi_countdown(ctx->encryption.EKey);
2190
66
        ctx->encryption.EKey = NULL;
2191
66
    }
2192
6.24k
    if (ctx->encryption.Password) {
2193
0
        gs_free_object(ctx->memory, ctx->encryption.Password, "PDF Password from params");
2194
0
        ctx->encryption.Password = NULL;
2195
0
    }
2196
2197
6.24k
    if (ctx->cache_entries != 0) {
2198
5.19k
        pdf_obj_cache_entry *entry = ctx->cache_LRU, *next;
2199
2200
#if DEBUG_CACHE
2201
        int count;
2202
        bool stop = true;
2203
        pdf_obj_cache_entry *prev;
2204
2205
        do {
2206
            pdfi_print_cache(ctx);
2207
            entry = ctx->cache_LRU;
2208
            stop = true;
2209
            while(entry) {
2210
                pdfi_print_cache(ctx);
2211
                next = entry->next;
2212
                prev = entry->previous;
2213
2214
                /* pass through the cache, count down any objects which are only referenced by the cache (refcnt == 1)
2215
                 * this may cause other objects (referred to by the newly freed object) to decrement their refcnt
2216
                 * until they are also only pointed at by the cache.
2217
                 */
2218
                if (entry->o->refcnt == 1) {
2219
                    stop = false;
2220
                    pdfi_countdown(entry->o);
2221
                    if (prev != NULL)
2222
                        prev->next = next;
2223
                    else
2224
                        ctx->cache_LRU = next;
2225
                    if (next)
2226
                        next->previous = prev;
2227
                    ctx->cache_entries--;
2228
                    gs_free_object(ctx->memory, entry, "pdfi_clear_context, free LRU");
2229
                }
2230
                entry = next;
2231
            }
2232
        } while (stop == false);
2233
2234
        entry = ctx->cache_LRU;
2235
        while(entry) {
2236
            next = entry->next;
2237
            prev = entry->previous;
2238
            count = entry->o->refcnt;
2239
            dbgmprintf1(ctx->memory, "CLEANUP cache entry obj %d", entry->o->object_num);
2240
            dbgmprintf1(ctx->memory, " has refcnt %d\n", count);
2241
            entry = next;
2242
        }
2243
#else
2244
149k
        while(entry) {
2245
144k
            next = entry->next;
2246
144k
            pdfi_countdown(entry->o);
2247
144k
            ctx->cache_entries--;
2248
144k
            gs_free_object(ctx->memory, entry, "pdfi_clear_context, free LRU");
2249
144k
            entry = next;
2250
#if REFCNT_DEBUG
2251
            ctx->cache_LRU = entry;
2252
#endif
2253
144k
        }
2254
5.19k
#endif
2255
5.19k
        ctx->cache_LRU = ctx->cache_MRU = NULL;
2256
5.19k
        ctx->cache_entries = 0;
2257
5.19k
    }
2258
2259
    /* We can't free the font directory before the graphics library fonts fonts are freed, as they reference the font_dir.
2260
     * graphics library fonts are refrenced from pdf_font objects, and those may be in the cache, which means they
2261
     * won't be freed until we empty the cache. So we can't free 'font_dir' until after the cache has been cleared.
2262
     */
2263
6.24k
    if (ctx->font_dir)
2264
6.24k
        gx_purge_selected_cached_chars(ctx->font_dir, pdfi_fontdir_purge_all, (void *)NULL);
2265
2266
6.24k
    pdfi_countdown(ctx->pdffontmap);
2267
6.24k
    ctx->pdffontmap = NULL;
2268
6.24k
    pdfi_countdown(ctx->pdfnativefontmap);
2269
6.24k
    ctx->pdfnativefontmap = NULL;
2270
6.24k
    pdfi_countdown(ctx->pdf_substitute_fonts);
2271
6.24k
    ctx->pdf_substitute_fonts = NULL;
2272
2273
6.24k
    return 0;
2274
6.24k
}
2275
2276
int pdfi_free_context(pdf_context *ctx)
2277
6.24k
{
2278
#if PDFI_LEAK_CHECK
2279
    gs_memory_status_t mstat, ctxmstat = ctx->memstat;
2280
    gs_memory_t *mem = ctx->memory;
2281
#endif
2282
6.24k
    pdfi_clear_context(ctx);
2283
2284
6.24k
    gs_free_object(ctx->memory, ctx->stack_bot, "pdfi_free_context");
2285
2286
6.24k
    pdfi_free_name_table(ctx);
2287
2288
    /* And here we free the initial graphics state */
2289
6.24k
    while (ctx->pgs->saved)
2290
0
        gs_grestore_only(ctx->pgs);
2291
2292
6.24k
    gs_gstate_free(ctx->pgs);
2293
2294
6.24k
    ctx->pgs = NULL;
2295
2296
6.24k
    if (ctx->font_dir)
2297
6.24k
        gs_free_object(ctx->memory, ctx->font_dir, "pdfi_free_context");
2298
2299
    /* Currently this should never happen, but in future it might if we choose
2300
     * not to keep freeing and reallocating the array.
2301
     */
2302
6.24k
    if (ctx->loop_detection != NULL) {
2303
0
        dbgmprintf(ctx->memory, "Loop detection array exists at EOJ\n");
2304
0
        gs_free_object(ctx->memory, ctx->loop_detection, "pdfi_free_context");
2305
0
    }
2306
2307
6.24k
    pdfi_free_search_paths(ctx);
2308
6.24k
    pdfi_free_fontmapfiles(ctx);
2309
2310
6.24k
    if (ctx->pdfcidfmap != NULL) {
2311
459
        pdfi_countdown(ctx->pdfcidfmap);
2312
459
        ctx->pdfcidfmap = NULL;
2313
459
    }
2314
6.24k
    if (ctx->pdffontmap != NULL) {
2315
0
        pdfi_countdown(ctx->pdffontmap);
2316
0
        ctx->pdffontmap = NULL;
2317
0
    }
2318
6.24k
    rc_decrement(ctx->devbbox, "pdfi_free_context");
2319
2320
6.24k
    gs_free_object(ctx->memory, ctx, "pdfi_free_context");
2321
#if PDFI_LEAK_CHECK
2322
    gs_memory_status(mem, &mstat);
2323
    if (mstat.allocated > ctxmstat.allocated)
2324
        errprintf(mem, "\nMemory Leak Detected: Pre %d, Post %d\n", (int)ctxmstat.allocated, (int)mstat.allocated);
2325
    (void)gs_memory_chunk_unwrap(mem);
2326
#endif
2327
6.24k
    return 0;
2328
6.24k
}
2329
2330
/* These routines are used from the PostScript interpreter inteerface. It is important that
2331
 * the 'interpreter part of the graphics state' should be a pdfi interpreter context while pdfi is running
2332
 * but the PostScript itnerpreter context when the PostScript interpreter is running. If we are going
2333
 * to inherit the PostScript graphics state for pdfi, then we need to turn it into a 'pdfi'
2334
 * graphics state for the duration of the interpretation, and back to a PostScript one when
2335
 * we return to the PostScript interpreter.
2336
 *
2337
 * Bizarrely it appears that the interpreter part of the gstate does not obey grestore, instead we copy
2338
 * the 'current' context to the saved context when we do a grestore. This seems wrong to me, but
2339
 * it seems to be what happens, so we can't rely on grestore to put back the interpreter context, but must
2340
 * do so ourselves.
2341
 *
2342
 * Hence the 'from_PS' routine fills in pointers with the current context and procs, with the expectation that
2343
 * these will be saved and used to restore the data in the 'to_PS' routine.
2344
 */
2345
/* NOTE see the comments in zpdfops.c just under the declaration of the pdfi_switch_t strcuture regarding
2346
 * complications with the ICC profile cache.
2347
 */
2348
2349
int pdfi_gstate_from_PS(pdf_context *ctx, gs_gstate *pgs, pdfi_switch_t *i_switch, gsicc_profile_cache_t *profile_cache)
2350
30.0k
{
2351
30.0k
    int code;
2352
30.0k
    i_switch->pgs = ctx->pgs;
2353
30.0k
    i_switch->procs = pgs->client_procs;
2354
30.0k
    i_switch->client_data = (void *)pgs->client_data;
2355
30.0k
    i_switch->profile_cache = pgs->icc_profile_cache;
2356
30.0k
    code = pdfi_gstate_set_client(ctx, pgs);
2357
30.0k
    if (code < 0)
2358
0
        return code;
2359
30.0k
    i_switch->psfont = pgs->font;
2360
30.0k
    pgs->icc_profile_cache = profile_cache;
2361
30.0k
    rc_increment(pgs->icc_profile_cache);
2362
30.0k
    pgs->font = NULL;
2363
30.0k
    ctx->pgs = pgs;
2364
30.0k
    return code;
2365
30.0k
}
2366
2367
void pdfi_gstate_to_PS(pdf_context *ctx, gs_gstate *pgs, pdfi_switch_t *i_switch)
2368
30.0k
{
2369
30.0k
    pgs->client_procs.free(pgs->client_data, pgs->memory, pgs);
2370
30.0k
    pgs->client_data = NULL;
2371
30.0k
    rc_decrement(pgs->icc_profile_cache, "pdfi_gstate_to_PS");
2372
30.0k
    pgs->icc_profile_cache = i_switch->profile_cache;
2373
30.0k
    gs_gstate_set_client(pgs, i_switch->client_data, &i_switch->procs, true);
2374
30.0k
    ctx->pgs->font = NULL;
2375
30.0k
    ctx->pgs = i_switch->pgs;
2376
30.0k
    pgs->font = i_switch->psfont;
2377
30.0k
}