Coverage Report

Created: 2026-09-14 07:34

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