Coverage Report

Created: 2025-11-16 07:40

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