Coverage Report

Created: 2026-08-08 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pdf/ghostpdf.c
Line
Count
Source
1
/* Copyright (C) 2018-2026 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
37.2k
{
631
37.2k
    if (pdfi_error != 0)
632
37.2k
        ctx->pdf_errors[pdfi_error / (sizeof(char) * 8)] |= 1 << pdfi_error % (sizeof(char) * 8);
633
37.2k
    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
37.2k
    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
37.2k
    return 0;
650
37.2k
}
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
1.80M
{
654
1.80M
    ctx->pdf_warnings[pdfi_warning / (sizeof(char) * 8)] |= 1 << pdfi_warning % (sizeof(char) * 8);
655
1.80M
    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
1.80M
    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
1.80M
    return 0;
672
1.80M
}
673
674
void
675
pdfi_report_errors(pdf_context *ctx)
676
66.2k
{
677
66.2k
    int code, i, j;
678
66.2k
    bool warnings_exist = false, errors_exist = false;
679
680
66.2k
    if (ctx->args.QUIET)
681
66.2k
        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
35.0k
{
784
35.0k
    pdfi_name_entry_t *e = NULL, *last_entry = NULL, *new_entry = NULL;
785
35.0k
    int index = 0;
786
787
35.0k
    if (ctx->name_table == NULL) {
788
1.70k
        e = NULL;
789
33.3k
    } else {
790
33.3k
        e = ctx->name_table;
791
33.3k
    }
792
793
41.2k
    while(e != NULL) {
794
38.9k
        if (e->len == len) {
795
35.0k
            if (memcmp(e->name, name, e->len) == 0) {
796
32.8k
                *returned = e->index;
797
32.8k
                return 0;
798
32.8k
            }
799
35.0k
        }
800
6.17k
        last_entry = e;
801
6.17k
        index = e->index;
802
6.17k
        e = e->next;
803
6.17k
    }
804
805
2.24k
    new_entry = (pdfi_name_entry_t *)gs_alloc_bytes(ctx->memory, sizeof(pdfi_name_entry_t), "Alloc name table entry");
806
2.24k
    if (new_entry == NULL)
807
0
        return_error(gs_error_VMerror);
808
2.24k
    memset(new_entry, 0x00, sizeof(pdfi_name_entry_t));
809
2.24k
    new_entry->name = (char *)gs_alloc_bytes(ctx->memory, (size_t)len+1, "Alloc name table name");
810
2.24k
    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.24k
    memset(new_entry->name, 0x00, len+1);
815
2.24k
    memcpy(new_entry->name, name, len);
816
2.24k
    new_entry->len = len;
817
2.24k
    new_entry->index = ++index;
818
819
2.24k
    if (last_entry)
820
538
        last_entry->next = new_entry;
821
1.70k
    else
822
1.70k
        ctx->name_table = new_entry;
823
824
2.24k
    *returned = new_entry->index;
825
2.24k
    return 0;
826
2.24k
}
827
828
static int pdfi_free_name_table(pdf_context *ctx)
829
99.7k
{
830
99.7k
    if (ctx->name_table) {
831
1.70k
        pdfi_name_entry_t *next = NULL, *e = (pdfi_name_entry_t *)ctx->name_table;
832
833
3.95k
        while (e != NULL) {
834
2.24k
            next = (pdfi_name_entry_t *)e->next;
835
2.24k
            gs_free_object(ctx->memory, e->name, "free name table entries");
836
2.24k
            gs_free_object(ctx->memory, e, "free name table entries");
837
2.24k
            e = next;
838
2.24k
        }
839
1.70k
    }
840
99.7k
    ctx->name_table = NULL;
841
99.7k
    return 0;
842
99.7k
}
843
844
int pdfi_name_from_index(pdf_context *ctx, int index, unsigned char **name, unsigned int *len)
845
964
{
846
964
    pdfi_name_entry_t *e = (pdfi_name_entry_t *)ctx->name_table;
847
848
5.47k
    while (e != NULL) {
849
5.47k
        if (e->index == index) {
850
964
            *name = (unsigned char *)e->name;
851
964
            *len = e->len;
852
964
            return 0;
853
964
        }
854
4.51k
        e = e->next;
855
4.51k
    }
856
857
964
    return_error(gs_error_undefined);
858
964
}
859
860
int pdfi_separation_name_from_index(gs_gstate *pgs, gs_separation_name index, unsigned char **name, unsigned int *len)
861
5.05k
{
862
5.05k
    pdfi_int_gstate *igs = (pdfi_int_gstate *)pgs->client_data;
863
5.05k
    pdf_context *ctx = NULL;
864
5.05k
    pdfi_name_entry_t *e = NULL;
865
866
5.05k
    if (igs == NULL)
867
0
        return_error(gs_error_undefined);
868
869
5.05k
    ctx = igs->ctx;
870
5.05k
    if (ctx == NULL)
871
0
        return_error(gs_error_undefined);
872
873
5.05k
    e = (pdfi_name_entry_t *)ctx->name_table;
874
875
5.05k
    while (e != NULL) {
876
5.05k
        if (e->index == index) {
877
5.05k
            *name = (unsigned char *)e->name;
878
5.05k
            *len = e->len;
879
5.05k
            return 0;
880
5.05k
        }
881
0
        e = e->next;
882
0
    }
883
884
5.05k
    return_error(gs_error_undefined);
885
5.05k
}
886
887
int pdfi_finish_pdf_file(pdf_context *ctx)
888
65.9k
{
889
65.9k
    if (ctx->Root) {
890
65.9k
        if (ctx->device_state.writepdfmarks && ctx->device_state.WantsOptionalContent) {
891
3.55k
            pdf_obj *o = NULL;
892
3.55k
            int code = 0;
893
894
3.55k
            code = pdfi_dict_knownget_type(ctx, ctx->Root, "OCProperties", PDF_DICT, &o);
895
3.55k
            if (code > 0) {
896
                /* Build and send the OCProperties structure */
897
102
                code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "OCProperties");
898
102
                pdfi_countdown(o);
899
102
                if (code < 0)
900
                    /* Error message ? */
901
30
                ;
902
102
            }
903
3.55k
        }
904
65.9k
    }
905
65.9k
    return 0;
906
65.9k
}
907
908
int pdfi_close_pdf_file(pdf_context *ctx)
909
293
{
910
293
    if (ctx->Root) {
911
109
        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
109
    }
926
927
293
    if (ctx->main_stream) {
928
293
        if (ctx->main_stream->s) {
929
293
            sfclose(ctx->main_stream->s);
930
293
        }
931
293
        gs_free_object(ctx->memory, ctx->main_stream, "Closing main PDF file");
932
293
        ctx->main_stream = NULL;
933
293
    }
934
293
    ctx->main_stream_length = 0;
935
936
293
    if (ctx->filename) {
937
293
        gs_free_object(ctx->memory, ctx->filename, "pdfi_close_pdf_file, free copy of filename");
938
293
        ctx->filename = NULL;
939
293
    }
940
941
293
    pdfi_clear_context(ctx);
942
293
    return 0;
943
293
}
944
945
static int pdfi_process(pdf_context *ctx)
946
109
{
947
109
    int code = 0, i;
948
949
    /* Loop over each page and either render it or output the
950
     * required information.
951
     */
952
218
    for (i=0;i < ctx->num_pages;i++) {
953
109
        if (ctx->args.first_page != 0) {
954
0
            if (i < ctx->args.first_page - 1)
955
0
                continue;
956
0
        }
957
109
        if (ctx->args.last_page != 0) {
958
0
            if (i > ctx->args.last_page - 1)
959
0
                break;
960
0
        }
961
109
        if (ctx->args.pdfinfo)
962
0
            code = pdfi_output_page_info(ctx, i);
963
109
        else
964
109
            code = pdfi_page_render(ctx, i, true);
965
966
109
        if (code < 0)
967
12
            code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_process", NULL);
968
109
    }
969
109
    pdfi_report_errors(ctx);
970
971
109
    return code;
972
109
}
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
293
{
1225
293
    int code = 0;
1226
1227
293
    code = pdfi_open_pdf_file(ctx, filename);
1228
293
    if (code < 0) {
1229
184
        pdfi_report_errors(ctx);
1230
184
        return code;
1231
184
    }
1232
1233
    /* Do any custom device configuration */
1234
109
    pdfi_device_misc_config(ctx);
1235
1236
109
    if (ctx->Collection != NULL)
1237
0
        code = pdfi_process_collection(ctx);
1238
109
    else
1239
109
        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
109
    ctx->Pdfmark_InitialPage += ctx->num_pages;
1247
1248
109
    pdfi_close_pdf_file(ctx);
1249
109
    return code;
1250
293
}
1251
1252
static int pdfi_init_file(pdf_context *ctx)
1253
83.8k
{
1254
83.8k
    int code = 0;
1255
83.8k
    pdf_obj *o = NULL;
1256
1257
83.8k
    code = pdfi_read_xref(ctx);
1258
83.8k
    if (code < 0) {
1259
6.99k
        if (ctx->is_hybrid) {
1260
2
            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
2
            pdfi_countdown(ctx->xref_table);
1267
2
            ctx->xref_table = NULL;
1268
2
            ctx->prefer_xrefstm = false;
1269
2
            code = pdfi_read_xref(ctx);
1270
2
            if (code < 0)
1271
0
                goto exit;
1272
6.99k
        } else {
1273
6.99k
            pdfi_set_error(ctx, code, NULL, E_PDF_BADXREFSTREAM, "pdfi_init_file", NULL);
1274
6.99k
            goto exit;
1275
6.99k
        }
1276
6.99k
    }
1277
1278
76.8k
    pdfi_device_set_flags(ctx);
1279
1280
76.8k
    if (ctx->Trailer) {
1281
        /* See comment in pdfi_read_Root() (pdf_doc.c) for details */
1282
32.8k
        pdf_dict *d = ctx->Trailer;
1283
1284
32.8k
        pdfi_countup(d);
1285
32.8k
        code = pdfi_dict_get(ctx, d, "Encrypt", &o);
1286
32.8k
        pdfi_countdown(d);
1287
32.8k
        if (code < 0 && code != gs_error_undefined)
1288
34
            goto exit;
1289
32.8k
        if (code == 0) {
1290
1.11k
            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.09k
                code = pdfi_initialise_Decryption(ctx);
1297
1.09k
                if (code < 0)
1298
257
                    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.09k
            } else {
1329
23
                if (pdfi_type_of(o) != PDF_NULL)
1330
15
                    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
23
            }
1333
1.11k
        }
1334
32.8k
    }
1335
1336
76.7k
read_root:
1337
76.7k
    if (ctx->Trailer) {
1338
32.7k
        code = pdfi_read_Root(ctx);
1339
32.7k
        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
977
            if (code == gs_error_undefined && ctx->is_hybrid && ctx->prefer_xrefstm) {
1344
1
                pdfi_countdown(ctx->xref_table);
1345
1
                ctx->xref_table = NULL;
1346
1
                if ((code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_BADXREFSTREAM, "pdfi_init_file", NULL)) < 0)
1347
0
                    goto exit;
1348
1349
1
                ctx->prefer_xrefstm = false;
1350
1
                code = pdfi_read_xref(ctx);
1351
1
                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
1
                code = pdfi_read_Root(ctx);
1356
1
                if (code < 0)
1357
1
                    goto exit;
1358
976
            } else {
1359
976
                int code1 = pdfi_repair_file(ctx);
1360
976
                if (code1 < 0)
1361
788
                    goto exit;
1362
188
                goto read_root;
1363
976
            }
1364
977
        }
1365
32.7k
    }
1366
1367
75.7k
    if (ctx->Trailer) {
1368
31.7k
        code = pdfi_read_Info(ctx);
1369
31.7k
        if (code < 0 && code != gs_error_undefined) {
1370
1.00k
            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.00k
            pdfi_clearstack(ctx);
1373
1.00k
        }
1374
31.7k
    }
1375
1376
75.7k
    if (!ctx->Root) {
1377
6.84k
        errprintf(ctx->memory, "Catalog dictionary not located in file, unable to proceed\n");
1378
6.84k
        return_error(gs_error_syntaxerror);
1379
6.84k
    }
1380
1381
68.9k
    code = pdfi_read_Pages(ctx);
1382
68.9k
    if (code < 0)
1383
2.52k
        goto exit;
1384
1385
66.4k
    code = pdfi_doc_page_array_init(ctx);
1386
66.4k
    if (code < 0)
1387
1
        goto exit;
1388
1389
66.4k
    if (ctx->num_pages == 0)
1390
164
        errprintf(ctx->memory, "\n   **** Warning: PDF document has no pages.\n");
1391
1392
66.4k
    code = pdfi_doc_trailer(ctx);
1393
66.4k
    if (code < 0)
1394
0
        goto exit;
1395
1396
66.4k
    pdfi_read_OptionalRoot(ctx);
1397
1398
66.4k
    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
77.0k
exit:
1405
77.0k
    if (code < 0)
1406
10.6k
        pdfi_set_error(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_init_file", NULL);
1407
77.0k
    pdfi_countdown(o);
1408
77.0k
    return code;
1409
66.4k
}
1410
1411
int pdfi_set_input_stream(pdf_context *ctx, stream *stm)
1412
83.9k
{
1413
83.9k
    byte *Buffer = NULL;
1414
83.9k
    char *s = NULL, *test = NULL;
1415
83.9k
    float version = 0.0;
1416
83.9k
    gs_offset_t Offset = 0;
1417
83.9k
    int64_t bytes = 0, leftover = 0, bytes_left = 0;
1418
83.9k
    bool found = false;
1419
83.9k
    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
83.9k
    stm->close_at_eod = false;
1425
1426
83.9k
    ctx->main_stream = (pdf_c_stream *)gs_alloc_bytes(ctx->memory, sizeof(pdf_c_stream), "PDF interpreter allocate main PDF stream");
1427
83.9k
    if (ctx->main_stream == NULL)
1428
0
        return_error(gs_error_VMerror);
1429
83.9k
    memset(ctx->main_stream, 0x00, sizeof(pdf_c_stream));
1430
83.9k
    ctx->main_stream->s = stm;
1431
1432
83.9k
    Buffer = gs_alloc_bytes(ctx->memory, BUF_SIZE, "PDF interpreter - allocate working buffer for file validation");
1433
83.9k
    if (Buffer == NULL) {
1434
0
        code = gs_error_VMerror;
1435
0
        goto error;
1436
0
    }
1437
1438
    /* Determine file size */
1439
83.9k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
1440
83.9k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_END);
1441
83.9k
    ctx->main_stream_length = pdfi_tell(ctx->main_stream);
1442
83.9k
    Offset = BUF_SIZE;
1443
83.9k
    bytes = BUF_SIZE;
1444
83.9k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
1445
1446
83.9k
    bytes = Offset = min(BUF_SIZE - 1, ctx->main_stream_length);
1447
1448
83.9k
    if (ctx->args.pdfdebug)
1449
0
        outprintf(ctx->memory, "%% Reading header\n");
1450
1451
83.9k
    bytes = pdfi_read_bytes(ctx, Buffer, 1, Offset, ctx->main_stream);
1452
83.9k
    if (bytes <= 0) {
1453
5
        errprintf(ctx->memory, "Failed to read any bytes from input stream\n");
1454
5
        code = gs_error_ioerror;
1455
5
        goto error;
1456
5
    }
1457
83.9k
    if (bytes < 8) {
1458
52
        errprintf(ctx->memory, "Failed to read enough bytes for a valid PDF header from input stream\n");
1459
52
        code = gs_error_ioerror;
1460
52
        goto error;
1461
52
    }
1462
83.8k
    Buffer[Offset] = 0x00;
1463
1464
    /* First check for existence of header */
1465
83.8k
    test = (char *)Buffer;
1466
83.8k
    bytes_left = bytes;
1467
83.8k
    s = strstr((char *)test, "%PDF-");
1468
83.8k
    if (s == NULL) {
1469
308
        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
308
    }
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
89.9k
    while (s == NULL) {
1478
6.07k
        bytes_left -= (strlen(test) + 1);
1479
6.07k
        if (bytes_left < 5)
1480
0
            break;
1481
6.07k
        test += strlen(test) + 1;
1482
6.07k
        s = strstr((char *)test, "%PDF-");
1483
6.07k
    };
1484
83.8k
    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
83.8k
    } else {
1495
        /* Now extract header version (may be overridden later) */
1496
83.8k
        if (sscanf(s + 5, "%f", &version) != 1) {
1497
3.09k
            ctx->HeaderVersion = 0;
1498
3.09k
            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
3.09k
        }
1501
80.7k
        else {
1502
80.7k
            ctx->HeaderVersion = version;
1503
80.7k
            s += 5;
1504
344k
            while (((*s >= '0' && *s <= '9') || *s == '.') && *s != 0x00)
1505
263k
                s++;
1506
84.2k
            while (*s != 0x00) {
1507
83.8k
                if (*s == 0x09 || *s== 0x0c || *s == 0x20) {
1508
3.47k
                    s++;
1509
3.47k
                    continue;
1510
3.47k
                }
1511
80.4k
                if (*s != 0x0A && *s != 0x0D) {
1512
3.80k
                    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
3.80k
                }
1515
80.4k
                break;
1516
80.4k
            }
1517
80.7k
        }
1518
83.8k
        if (ctx->args.pdfdebug)
1519
0
            outprintf(ctx->memory, "%% Found header, PDF version is %f\n", ctx->HeaderVersion);
1520
83.8k
    }
1521
1522
    /* Jump to EOF and scan backwards looking for startxref */
1523
83.8k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_END);
1524
1525
83.8k
    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
83.8k
    bytes = Offset;
1530
1531
644k
    do {
1532
644k
        byte *last_lineend = NULL;
1533
644k
        uint32_t read;
1534
1535
644k
        if (pdfi_seek(ctx, ctx->main_stream, ctx->main_stream_length - Offset, SEEK_SET) != 0) {
1536
7
            char msg[128];
1537
7
            gs_snprintf(msg, 128, "%% File is smaller than %"PRIi64" bytes\n", (int64_t)Offset);
1538
7
            code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_ioerror), NULL, E_PDF_GS_LIB_ERROR, "pdfi_set_input_stream", msg);
1539
7
            goto error;
1540
7
        }
1541
644k
        read = pdfi_read_bytes(ctx, Buffer, 1, bytes, ctx->main_stream);
1542
1543
644k
        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
644k
        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
644k
        read = bytes = read + leftover;
1567
1568
        /* Now search backwards in the buffer for the startxref token */
1569
1.22G
        while(read) {
1570
1.21G
            if (memcmp(Buffer + read - 9, "startxref", 9) == 0) {
1571
38.6k
                found = true;
1572
38.6k
                break;
1573
1.21G
            } else {
1574
1.21G
                if (Buffer[read - 1] == 0x0a || Buffer[read - 1] == 0x0d)
1575
18.7M
                    last_lineend = Buffer + read;
1576
1.21G
            }
1577
1.21G
            read--;
1578
1.21G
        }
1579
644k
        if (found) {
1580
38.6k
            byte *b = Buffer + read;
1581
1582
            /* Success! stop now */
1583
38.6k
            if(sscanf((char *)b, " %"PRIdOFFSET"", &ctx->startxref) != 1) {
1584
591
                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
591
            }
1587
38.6k
            break;
1588
605k
        } 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
605k
            if (last_lineend) {
1600
557k
                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
557k
                if (leftover < BUF_SIZE / 2) {
1606
545k
                    memmove(Buffer + bytes - leftover, last_lineend, leftover);
1607
545k
                    bytes -= leftover;
1608
545k
                } else
1609
11.4k
                    leftover = 0;
1610
557k
            } else
1611
48.5k
                leftover = 0;
1612
605k
        }
1613
1614
605k
        Offset += bytes;
1615
605k
    } while(Offset < ctx->main_stream_length);
1616
1617
83.8k
    if (!found) {
1618
45.2k
        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
45.2k
    }
1621
1622
83.8k
    code = pdfi_init_file(ctx);
1623
1624
83.9k
error:
1625
83.9k
    gs_free_object(ctx->memory, Buffer, "PDF interpreter - allocate working buffer for file validation");
1626
83.9k
    return code;
1627
83.8k
}
1628
1629
int pdfi_open_pdf_file(pdf_context *ctx, char *filename)
1630
293
{
1631
293
    stream *s = NULL;
1632
293
    int code;
1633
1634
293
    if (ctx->args.pdfdebug)
1635
0
        outprintf(ctx->memory, "%% Attempting to open %s as a PDF file\n", filename);
1636
1637
293
    ctx->filename = (char *)gs_alloc_bytes(ctx->memory, (size_t)strlen(filename) + 1, "copy of filename");
1638
293
    if (ctx->filename == NULL)
1639
0
        return_error(gs_error_VMerror);
1640
293
    strcpy(ctx->filename, filename);
1641
1642
293
    s = sfopen(filename, "r", ctx->memory);
1643
293
    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
293
    code = pdfi_set_input_stream(ctx, s);
1648
293
    return code;
1649
293
}
1650
1651
static size_t pdfi_grdir_path_string_match(const byte *str, size_t sl0, byte *pat, size_t pl)
1652
16.1k
{
1653
16.1k
    bool found = false;
1654
16.1k
    size_t sl = sl0;
1655
1656
112k
    while (found == false) {
1657
96.6k
        if (pl > sl)
1658
0
            break;
1659
96.6k
        if (*str == *pat && memcmp(str, pat, pl) == 0)
1660
16.1k
            found = true;
1661
80.5k
        else {
1662
80.5k
            str++;
1663
80.5k
            sl--;
1664
80.5k
        }
1665
96.6k
    }
1666
16.1k
    if (found)
1667
16.1k
        return (sl0 - sl) + pl;
1668
0
    else
1669
0
        return 0;
1670
16.1k
}
1671
1672
int pdfi_add_paths_to_search_paths(pdf_context *ctx, const char *ppath, int l, bool fontpath)
1673
16.1k
{
1674
16.1k
    int i, slen, npaths = (l > 0) ? 1 : 0;
1675
16.1k
    const char *p = ppath;
1676
16.1k
    char *ps;
1677
16.1k
    const char *pe = p + l + 1;
1678
16.1k
    int code = 0;
1679
16.1k
    static const char *resstr = "Resource";
1680
16.1k
    const int restrlen = strlen(resstr);
1681
16.1k
    const char *dirsepstr = gp_file_name_directory_separator();
1682
16.1k
    const int dirsepstrlen = strlen(dirsepstr);
1683
16.1k
    char genresstr[64];
1684
1685
7.02M
    for (ps = (char *)p; ps < pe; ps++) {
1686
7.00M
        if (*ps == gp_file_name_list_separator)
1687
177k
           npaths++;
1688
7.00M
    }
1689
1690
16.1k
    if (npaths > 0) {
1691
16.1k
        gs_param_string *pathstrings;
1692
16.1k
        int new_npaths = ctx->search_paths.num_resource_paths + npaths;
1693
1694
16.1k
        if (fontpath != true) {
1695
16.1k
            pathstrings = (gs_param_string *)gs_alloc_bytes(ctx->memory, (size_t)sizeof(gs_param_string) * new_npaths, "array of paths");
1696
16.1k
            if (pathstrings == NULL)
1697
0
                return_error(gs_error_VMerror);
1698
1699
16.1k
            memset(pathstrings, 0x00, sizeof(gs_param_string) * new_npaths);
1700
1701
16.1k
            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
16.1k
            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
16.1k
            gs_free_object(ctx->memory, ctx->search_paths.resource_paths, "old array of paths");
1710
16.1k
            ctx->search_paths.resource_paths = pathstrings;
1711
16.1k
            ctx->search_paths.num_resource_paths += npaths;
1712
1713
            /* .....AND HERE */
1714
6.84M
            for (ps = (char *)p; ps < pe; ps++) {
1715
6.82M
                if (*ps == gp_file_name_list_separator || ps == pe - 1) {
1716
193k
                    if (*p == gp_file_name_list_separator) p++; /* move past the separator */
1717
193k
                    slen = ps - p;
1718
193k
                    pathstrings[i].data = (byte *)gs_alloc_bytes(ctx->memory, slen, "path string body");
1719
1720
193k
                    if (pathstrings[i].data == NULL) {
1721
0
                        code = gs_note_error(gs_error_VMerror);
1722
0
                        break;
1723
0
                    }
1724
1725
193k
                    memcpy((char *)pathstrings[i].data, p, slen);
1726
193k
                    pathstrings[i].size = slen;
1727
193k
                    pathstrings[i].persistent = false;
1728
193k
                    i++;
1729
193k
                    p = ps++;
1730
193k
                }
1731
6.82M
            }
1732
16.1k
            if ((restrlen + 2 * dirsepstrlen) < 64) {
1733
16.1k
                size_t grdlen;
1734
1735
16.1k
                memcpy(genresstr, resstr, restrlen  +1); /* +1 So we get the null terminator */
1736
16.1k
                strncat(genresstr, dirsepstr, dirsepstrlen);
1737
1738
16.1k
                for (i = 0; i < ctx->search_paths.num_resource_paths; i++) {
1739
16.1k
                    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
16.1k
                        ctx->search_paths.genericresourcedir.data = ctx->search_paths.resource_paths[i].data;
1741
16.1k
                        ctx->search_paths.genericresourcedir.size = grdlen;
1742
16.1k
                        ctx->search_paths.genericresourcedir.persistent = true;
1743
16.1k
                        break;
1744
16.1k
                    }
1745
16.1k
                }
1746
16.1k
            }
1747
16.1k
        }
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[npaths + 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
16.1k
    }
1783
1784
16.1k
    return code;
1785
16.1k
}
1786
1787
int pdfi_add_initial_paths_to_search_paths(pdf_context *ctx, const char *ppath, int l)
1788
16.1k
{
1789
16.1k
    int code;
1790
16.1k
    if (ctx->search_paths.num_resource_paths != 0)
1791
0
        return_error(gs_error_invalidaccess);
1792
1793
16.1k
    code = pdfi_add_paths_to_search_paths(ctx, ppath, l, false);
1794
16.1k
    ctx->search_paths.num_init_resource_paths = ctx->search_paths.num_resource_paths;
1795
1796
16.1k
    return code;
1797
16.1k
}
1798
1799
static void pdfi_free_search_paths(pdf_context *ctx)
1800
99.7k
{
1801
99.7k
    int i;
1802
1.38M
    for (i = 0; i < ctx->search_paths.num_resource_paths; i++) {
1803
1.28M
        if (ctx->search_paths.resource_paths[i].persistent == false)
1804
1.28M
            gs_free_object(ctx->memory, (byte *)ctx->search_paths.resource_paths[i].data, "path string body");
1805
1.28M
    }
1806
99.7k
    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
99.7k
    gs_free_object(ctx->memory, (byte *)ctx->search_paths.resource_paths, "array of paths");
1811
99.7k
    gs_free_object(ctx->memory, (byte *)ctx->search_paths.font_paths, "array of font paths");
1812
1813
99.7k
    if (ctx->search_paths.genericresourcedir.persistent == false)
1814
83.6k
        gs_free_object(ctx->memory, (byte *)ctx->search_paths.genericresourcedir.data, "generic resource directory");
1815
99.7k
}
1816
1817
static void pdfi_free_fontmapfiles(pdf_context *ctx)
1818
99.7k
{
1819
99.7k
    int i;
1820
99.7k
    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
99.7k
    gs_free_object(ctx->memory, ctx->fontmapfiles, "fontmapfiles array");
1824
99.7k
}
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
99.7k
{
1883
99.7k
    pdf_context *ctx = NULL;
1884
99.7k
    gs_gstate *pgs = NULL;
1885
99.7k
    int code = 0;
1886
99.7k
    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
99.7k
    ctx = (pdf_context *) gs_alloc_bytes(pmem, sizeof(pdf_context), "pdf_create_context");
1896
1897
99.7k
    pgs = gs_gstate_alloc(pmem);
1898
1899
99.7k
    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
99.7k
    memset(ctx, 0, sizeof(pdf_context));
1909
99.7k
    ctx->memory = pmem;
1910
99.7k
    ctx->type = PDF_CTX;
1911
99.7k
    ctx->flags = 0;
1912
99.7k
    ctx->refcnt = 1;
1913
99.7k
    ctx->ctx = ctx;
1914
1915
#if PDFI_LEAK_CHECK
1916
    ctx->memstat = mstat;
1917
#endif
1918
1919
99.7k
    ctx->stack_bot = (pdf_obj **)gs_alloc_bytes(ctx->memory, INITIAL_STACK_SIZE * sizeof (pdf_obj *), "pdf_imp_allocate_interp_stack");
1920
99.7k
    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
99.7k
    ctx->stack_size = INITIAL_STACK_SIZE;
1926
99.7k
    ctx->stack_top = ctx->stack_bot - 1;
1927
99.7k
    code = sizeof(pdf_obj *);
1928
99.7k
    code *= ctx->stack_size;
1929
99.7k
    ctx->stack_limit = ctx->stack_bot + ctx->stack_size;
1930
1931
99.7k
    code = pdfi_init_font_directory(ctx);
1932
99.7k
    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
99.7k
    code = gsicc_init_iccmanager(pgs);
1940
99.7k
    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
99.7k
    ctx->pgs = pgs;
1949
99.7k
    code = pdfi_gstate_set_client(ctx, pgs);
1950
99.7k
    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
99.7k
    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
99.7k
    ctx->pgs->have_pattern_streams = true;
1968
99.7k
    ctx->device_state.preserve_tr_mode = 0;
1969
99.7k
    ctx->args.notransparency = false;
1970
1971
99.7k
    ctx->main_stream = NULL;
1972
1973
    /* Setup some flags that don't default to 'false' */
1974
99.7k
    ctx->args.showannots = true;
1975
99.7k
    ctx->args.preserveannots = true;
1976
99.7k
    ctx->args.preservemarkedcontent = true;
1977
99.7k
    ctx->args.preserveembeddedfiles = true;
1978
99.7k
    ctx->args.preservedocview = true;
1979
99.7k
    ctx->args.PDFCacheSize = MAX_OBJECT_CACHE_SIZE;
1980
    /* NOTE: For testing certain annotations on cluster, might want to set this to false */
1981
99.7k
    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
99.7k
    ctx->prefer_xrefstm = true;
1985
1986
    /* We decrypt strings from encrypted files until we start a page */
1987
99.7k
    ctx->encryption.decrypt_strings = true;
1988
99.7k
    ctx->get_glyph_name = pdfi_glyph_name;
1989
99.7k
    ctx->get_glyph_index = pdfi_glyph_index;
1990
1991
99.7k
    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
99.7k
    code = gs_gsave(ctx->pgs);
1997
99.7k
    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
99.7k
    return ctx;
2017
99.7k
}
2018
2019
/* Purge all */
2020
static bool
2021
pdfi_fontdir_purge_all(const gs_memory_t * mem, cached_char * cc, void *dummy)
2022
797k
{
2023
797k
    return true;
2024
797k
}
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
100k
{
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
100k
    if (ctx->PathSegments != NULL) {
2104
4.71k
        gs_free_object(ctx->memory, ctx->PathSegments, "pdfi_clear_context");
2105
4.71k
        ctx->PathSegments = NULL;
2106
4.71k
    }
2107
100k
    if (ctx->PathPts != NULL) {
2108
4.71k
        gs_free_object(ctx->memory, ctx->PathPts, "pdfi_clear_context");
2109
4.71k
        ctx->PathPts = NULL;
2110
4.71k
    }
2111
2112
100k
    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
100k
    if (ctx->Trailer) {
2117
32.8k
        pdfi_countdown(ctx->Trailer);
2118
32.8k
        ctx->Trailer = NULL;
2119
32.8k
    }
2120
2121
100k
    if (ctx->AcroForm) {
2122
5.67k
        pdfi_countdown(ctx->AcroForm);
2123
5.67k
        ctx->AcroForm = NULL;
2124
5.67k
    }
2125
2126
100k
    if(ctx->Root) {
2127
69.1k
        pdfi_countdown(ctx->Root);
2128
69.1k
        ctx->Root = NULL;
2129
69.1k
    }
2130
2131
100k
    if (ctx->Info) {
2132
19.1k
        pdfi_countdown(ctx->Info);
2133
19.1k
        ctx->Info = NULL;
2134
19.1k
    }
2135
2136
100k
    if (ctx->PagesTree) {
2137
65.9k
        pdfi_countdown(ctx->PagesTree);
2138
65.9k
        ctx->PagesTree = NULL;
2139
65.9k
    }
2140
2141
100k
    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
100k
    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
100k
    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
100k
    pdfi_free_cstring_array(ctx, &ctx->args.showannottypes);
2157
100k
    pdfi_free_cstring_array(ctx, &ctx->args.preserveannottypes);
2158
2159
100k
    pdfi_doc_page_array_free(ctx);
2160
2161
100k
    if (ctx->xref_table) {
2162
76.9k
        pdfi_countdown(ctx->xref_table);
2163
76.9k
        ctx->xref_table = NULL;
2164
76.9k
    }
2165
2166
100k
    pdfi_free_OptionalRoot(ctx);
2167
2168
100k
    if (ctx->stack_bot)
2169
100k
        pdfi_clearstack(ctx);
2170
2171
100k
    if (ctx->filename) {
2172
        /* This should already be closed! */
2173
184
        pdfi_close_pdf_file(ctx);
2174
184
        gs_free_object(ctx->memory, ctx->filename, "pdfi_clear_context, free copy of filename");
2175
184
        ctx->filename = NULL;
2176
184
    }
2177
2178
100k
    if (ctx->main_stream) {
2179
83.6k
        gs_free_object(ctx->memory, ctx->main_stream, "pdfi_clear_context, free main PDF stream");
2180
83.6k
        ctx->main_stream = NULL;
2181
83.6k
    }
2182
100k
    ctx->main_stream_length = 0;
2183
2184
100k
    if(ctx->pgs != NULL) {
2185
100k
        gx_pattern_cache_free(ctx->pgs->pattern_cache);
2186
100k
        ctx->pgs->pattern_cache = NULL;
2187
100k
        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
199k
        while (ctx->pgs->level != ctx->job_gstate_level && ctx->pgs->saved)
2195
99.7k
            gs_grestore_only(ctx->pgs);
2196
100k
    }
2197
2198
100k
    pdfi_free_DefaultQState(ctx);
2199
100k
    pdfi_oc_free(ctx);
2200
2201
100k
    if(ctx->encryption.EKey) {
2202
838
        pdfi_countdown(ctx->encryption.EKey);
2203
838
        ctx->encryption.EKey = NULL;
2204
838
    }
2205
100k
    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
100k
    if (ctx->cache_entries != 0) {
2211
67.6k
        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
1.51M
        while(entry) {
2258
1.45M
            next = entry->next;
2259
1.45M
            pdfi_countdown(entry->o);
2260
1.45M
            ctx->cache_entries--;
2261
1.45M
            gs_free_object(ctx->memory, entry, "pdfi_clear_context, free LRU");
2262
1.45M
            entry = next;
2263
#if REFCNT_DEBUG
2264
            ctx->cache_LRU = entry;
2265
#endif
2266
1.45M
        }
2267
67.6k
#endif
2268
67.6k
        ctx->cache_LRU = ctx->cache_MRU = NULL;
2269
67.6k
        ctx->cache_entries = 0;
2270
67.6k
    }
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
100k
    if (ctx->font_dir)
2277
100k
        gx_purge_selected_cached_chars(ctx->font_dir, pdfi_fontdir_purge_all, (void *)NULL);
2278
2279
100k
    pdfi_countdown(ctx->pdffontmap);
2280
100k
    ctx->pdffontmap = NULL;
2281
100k
    pdfi_countdown(ctx->pdfnativefontmap);
2282
100k
    ctx->pdfnativefontmap = NULL;
2283
100k
    pdfi_countdown(ctx->pdf_substitute_fonts);
2284
100k
    ctx->pdf_substitute_fonts = NULL;
2285
2286
100k
    return 0;
2287
100k
}
2288
2289
int pdfi_free_context(pdf_context *ctx)
2290
99.7k
{
2291
#if PDFI_LEAK_CHECK
2292
    gs_memory_status_t mstat, ctxmstat = ctx->memstat;
2293
    gs_memory_t *mem = ctx->memory;
2294
#endif
2295
99.7k
    pdfi_clear_context(ctx);
2296
2297
99.7k
    gs_free_object(ctx->memory, ctx->stack_bot, "pdfi_free_context");
2298
2299
99.7k
    pdfi_free_name_table(ctx);
2300
2301
    /* And here we free the initial graphics state */
2302
99.7k
    while (ctx->pgs->saved)
2303
0
        gs_grestore_only(ctx->pgs);
2304
2305
99.7k
    gs_gstate_free(ctx->pgs);
2306
2307
99.7k
    ctx->pgs = NULL;
2308
2309
99.7k
    if (ctx->font_dir)
2310
99.7k
        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
99.7k
    if (ctx->loop_detection != NULL) {
2316
12
        dbgmprintf(ctx->memory, "Loop detection array exists at EOJ\n");
2317
12
        gs_free_object(ctx->memory, ctx->loop_detection, "pdfi_free_context");
2318
12
    }
2319
2320
99.7k
    pdfi_free_search_paths(ctx);
2321
99.7k
    pdfi_free_fontmapfiles(ctx);
2322
2323
99.7k
    if (ctx->pdfcidfmap != NULL) {
2324
5.20k
        pdfi_countdown(ctx->pdfcidfmap);
2325
5.20k
        ctx->pdfcidfmap = NULL;
2326
5.20k
    }
2327
99.7k
    if (ctx->pdffontmap != NULL) {
2328
0
        pdfi_countdown(ctx->pdffontmap);
2329
0
        ctx->pdffontmap = NULL;
2330
0
    }
2331
99.7k
    rc_decrement(ctx->devbbox, "pdfi_free_context");
2332
2333
99.7k
    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
99.7k
    return 0;
2341
99.7k
}
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
368k
{
2364
368k
    int code;
2365
368k
    i_switch->pgs = ctx->pgs;
2366
368k
    i_switch->procs = pgs->client_procs;
2367
368k
    i_switch->client_data = (void *)pgs->client_data;
2368
368k
    i_switch->profile_cache = pgs->icc_profile_cache;
2369
368k
    code = pdfi_gstate_set_client(ctx, pgs);
2370
368k
    if (code < 0)
2371
0
        return code;
2372
368k
    i_switch->psfont = pgs->font;
2373
368k
    pgs->icc_profile_cache = profile_cache;
2374
368k
    rc_increment(pgs->icc_profile_cache);
2375
368k
    pgs->font = NULL;
2376
368k
    ctx->pgs = pgs;
2377
368k
    return code;
2378
368k
}
2379
2380
void pdfi_gstate_to_PS(pdf_context *ctx, gs_gstate *pgs, pdfi_switch_t *i_switch)
2381
368k
{
2382
368k
    pgs->client_procs.free(pgs->client_data, pgs->memory, pgs);
2383
368k
    pgs->client_data = NULL;
2384
368k
    rc_decrement(pgs->icc_profile_cache, "pdfi_gstate_to_PS");
2385
368k
    pgs->icc_profile_cache = i_switch->profile_cache;
2386
368k
    gs_gstate_set_client(pgs, i_switch->client_data, &i_switch->procs, true);
2387
    ctx->pgs->font = NULL;
2388
368k
    ctx->pgs = i_switch->pgs;
2389
368k
    pgs->font = i_switch->psfont;
2390
368k
}