Coverage Report

Created: 2025-08-28 07:06

/src/ghostpdl/pdf/ghostpdf.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2018-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
/* Top level PDF access routines */
17
#include "ghostpdf.h"
18
#include "pdf_types.h"
19
#include "pdf_dict.h"
20
#include "pdf_array.h"
21
#include "pdf_int.h"
22
#include "pdf_misc.h"
23
#include "pdf_stack.h"
24
#include "pdf_file.h"
25
#include "pdf_loop_detect.h"
26
#include "pdf_trans.h"
27
#include "pdf_font_types.h"
28
#include "pdf_gstate.h"
29
#include "stream.h"
30
#include "strmio.h"
31
#include "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
52.1k
{
631
52.1k
    if (pdfi_error != 0)
632
52.1k
        ctx->pdf_errors[pdfi_error / (sizeof(char) * 8)] |= 1 << pdfi_error % (sizeof(char) * 8);
633
52.1k
    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
52.1k
    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
52.1k
    return 0;
650
52.1k
}
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
2.63M
{
654
2.63M
    ctx->pdf_warnings[pdfi_warning / (sizeof(char) * 8)] |= 1 << pdfi_warning % (sizeof(char) * 8);
655
2.63M
    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
2.63M
    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
2.63M
    return 0;
672
2.63M
}
673
674
void
675
pdfi_report_errors(pdf_context *ctx)
676
85.2k
{
677
85.2k
    int code, i, j;
678
85.2k
    bool warnings_exist = false, errors_exist = false;
679
680
85.2k
    if (ctx->args.QUIET)
681
85.2k
        return;
682
683
0
    for (i = 0; i < PDF_ERROR_BYTE_SIZE; i++) {
684
0
        if (ctx->pdf_errors[i] != 0)
685
0
            errors_exist = true;
686
0
    }
687
688
0
    for (i = 0; i < PDF_WARNING_BYTE_SIZE; i++) {
689
0
        if (ctx->pdf_warnings[i] != 0)
690
0
            warnings_exist = true;
691
0
    }
692
693
0
    if (!errors_exist && !warnings_exist)
694
0
        return;
695
696
0
    if (errors_exist)
697
0
    {
698
0
        errprintf(ctx->memory, "\nThe following errors were encountered at least once while processing this file:\n");
699
0
        for (i = 0; i < PDF_ERROR_BYTE_SIZE; i++) {
700
0
            if (ctx->pdf_errors[i] != 0) {
701
0
                for (j=0;j < sizeof(char) * 8; j++) {
702
0
                    if (ctx->pdf_errors[i] & 1 << j) {
703
0
                        int error_num = (i * sizeof(char) * 8) + j;
704
705
                        /* Bits higher than E_PDF_MAX_ERROR - 1 in pdf_errors should never be set, but just in case */
706
0
                        assert(error_num < E_PDF_MAX_ERROR);
707
0
                        if (error_num < E_PDF_MAX_ERROR)
708
0
                            errprintf(ctx->memory, "\t%s\n", pdf_error_strings[error_num]);
709
0
                    }
710
0
                }
711
0
            }
712
0
        }
713
0
    }
714
715
0
    if (warnings_exist)
716
0
    {
717
0
        outprintf(ctx->memory, "\nThe following warnings were encountered at least once while processing this file:\n");
718
0
        for (i = 0; i < PDF_WARNING_BYTE_SIZE; i++) {
719
0
            if (ctx->pdf_warnings[i] != 0) {
720
0
                for (j=0;j < sizeof(char) * 8; j++) {
721
0
                    if (ctx->pdf_warnings[i] & 1 << j) {
722
0
                        int warning_num = (i * sizeof(char) * 8) + j;
723
724
                        /* Bits higher than W_PDF_MAX_WARNING - 1 in pdf_warnings should never be set, but just in case */
725
0
                        assert(warning_num < W_PDF_MAX_WARNING);
726
0
                        if (warning_num < W_PDF_MAX_WARNING)
727
0
                            outprintf(ctx->memory, "\t%s\n", pdf_warning_strings[warning_num]);
728
0
                    }
729
0
                }
730
0
            }
731
0
        }
732
0
    }
733
734
0
    if (errors_exist)
735
0
        errprintf(ctx->memory, "\n   **** This file had errors that were repaired or ignored.\n");
736
0
    else {
737
0
        if (warnings_exist)
738
0
            outprintf(ctx->memory, "\n   **** This file had errors that were repaired or ignored.\n");
739
0
    }
740
0
    if (ctx->Info) {
741
0
        pdf_string *s = NULL;
742
743
0
        code = pdfi_dict_knownget_type(ctx, ctx->Info, "Producer", PDF_STRING, (pdf_obj **)&s);
744
0
        if (code > 0) {
745
0
            char *cs;
746
747
0
            cs = (char *)gs_alloc_bytes(ctx->memory, (size_t)s->length + 1, "temporary string for error report");
748
0
            if (cs == NULL) {
749
0
                errprintf(ctx->memory, "   **** Out of memory while trying to display Producer ****\n");
750
0
            } else {
751
0
                memcpy(cs, s->data, s->length);
752
0
                cs[s->length] = 0x00;
753
0
                if (errors_exist)
754
0
                    errprintf(ctx->memory, "   **** The file was produced by: \n   **** >>>> %s <<<<\n", cs);
755
0
                else {
756
0
                    if (warnings_exist)
757
0
                    outprintf(ctx->memory, "   **** The file was produced by: \n   **** >>>> %s <<<<\n", cs);
758
0
                }
759
0
                gs_free_object(ctx->memory, cs, "temporary string for error report");
760
0
            }
761
0
        }
762
0
        pdfi_countdown(s);
763
0
    }
764
0
    if (errors_exist) {
765
0
        errprintf(ctx->memory, "   **** Please notify the author of the software that produced this\n");
766
0
        errprintf(ctx->memory, "   **** file that it does not conform to Adobe's published PDF\n");
767
0
        errprintf(ctx->memory, "   **** specification.\n\n");
768
0
    } else {
769
0
        outprintf(ctx->memory, "   **** Please notify the author of the software that produced this\n");
770
0
        outprintf(ctx->memory, "   **** file that it does not conform to Adobe's published PDF\n");
771
0
        outprintf(ctx->memory, "   **** specification.\n\n");
772
0
    }
773
0
}
774
775
/* Name table
776
 * I've been trying to avoid this for as long as possible, but it seems it cannot
777
 * be evaded. We need functions to get an index for a given string (which will
778
 * add the string to the table if its not present) and to cleear up the table
779
 * on finishing a PDF file.
780
 */
781
782
int pdfi_get_name_index(pdf_context *ctx, char *name, int len, unsigned int *returned)
783
42.9k
{
784
42.9k
    pdfi_name_entry_t *e = NULL, *last_entry = NULL, *new_entry = NULL;
785
42.9k
    int index = 0;
786
787
42.9k
    if (ctx->name_table == NULL) {
788
2.17k
        e = NULL;
789
40.7k
    } else {
790
40.7k
        e = ctx->name_table;
791
40.7k
    }
792
793
42.9k
    while(e != NULL) {
794
40.7k
        if (e->len == len) {
795
40.7k
            if (memcmp(e->name, name, e->len) == 0) {
796
40.7k
                *returned = e->index;
797
40.7k
                return 0;
798
40.7k
            }
799
40.7k
        }
800
0
        last_entry = e;
801
0
        index = e->index;
802
0
        e = e->next;
803
0
    }
804
805
2.17k
    new_entry = (pdfi_name_entry_t *)gs_alloc_bytes(ctx->memory, sizeof(pdfi_name_entry_t), "Alloc name table entry");
806
2.17k
    if (new_entry == NULL)
807
0
        return_error(gs_error_VMerror);
808
2.17k
    memset(new_entry, 0x00, sizeof(pdfi_name_entry_t));
809
2.17k
    new_entry->name = (char *)gs_alloc_bytes(ctx->memory, (size_t)len+1, "Alloc name table name");
810
2.17k
    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.17k
    memset(new_entry->name, 0x00, len+1);
815
2.17k
    memcpy(new_entry->name, name, len);
816
2.17k
    new_entry->len = len;
817
2.17k
    new_entry->index = ++index;
818
819
2.17k
    if (last_entry)
820
0
        last_entry->next = new_entry;
821
2.17k
    else
822
2.17k
        ctx->name_table = new_entry;
823
824
2.17k
    *returned = new_entry->index;
825
2.17k
    return 0;
826
2.17k
}
827
828
static int pdfi_free_name_table(pdf_context *ctx)
829
109k
{
830
109k
    if (ctx->name_table) {
831
2.17k
        pdfi_name_entry_t *next = NULL, *e = (pdfi_name_entry_t *)ctx->name_table;
832
833
4.35k
        while (e != NULL) {
834
2.17k
            next = (pdfi_name_entry_t *)e->next;
835
2.17k
            gs_free_object(ctx->memory, e->name, "free name table entries");
836
2.17k
            gs_free_object(ctx->memory, e, "free name table entries");
837
2.17k
            e = next;
838
2.17k
        }
839
2.17k
    }
840
109k
    ctx->name_table = NULL;
841
109k
    return 0;
842
109k
}
843
844
int pdfi_name_from_index(pdf_context *ctx, int index, unsigned char **name, unsigned int *len)
845
0
{
846
0
    pdfi_name_entry_t *e = (pdfi_name_entry_t *)ctx->name_table;
847
848
0
    while (e != NULL) {
849
0
        if (e->index == index) {
850
0
            *name = (unsigned char *)e->name;
851
0
            *len = e->len;
852
0
            return 0;
853
0
        }
854
0
        e = e->next;
855
0
    }
856
857
0
    return_error(gs_error_undefined);
858
0
}
859
860
int pdfi_separation_name_from_index(gs_gstate *pgs, gs_separation_name index, unsigned char **name, unsigned int *len)
861
7.33k
{
862
7.33k
    pdfi_int_gstate *igs = (pdfi_int_gstate *)pgs->client_data;
863
7.33k
    pdf_context *ctx = NULL;
864
7.33k
    pdfi_name_entry_t *e = NULL;
865
866
7.33k
    if (igs == NULL)
867
0
        return_error(gs_error_undefined);
868
869
7.33k
    ctx = igs->ctx;
870
7.33k
    if (ctx == NULL)
871
0
        return_error(gs_error_undefined);
872
873
7.33k
    e = (pdfi_name_entry_t *)ctx->name_table;
874
875
7.33k
    while (e != NULL) {
876
7.33k
        if (e->index == index) {
877
7.33k
            *name = (unsigned char *)e->name;
878
7.33k
            *len = e->len;
879
7.33k
            return 0;
880
7.33k
        }
881
0
        e = e->next;
882
0
    }
883
884
7.33k
    return_error(gs_error_undefined);
885
7.33k
}
886
887
int pdfi_finish_pdf_file(pdf_context *ctx)
888
85.2k
{
889
85.2k
    if (ctx->Root) {
890
85.2k
        if (ctx->device_state.writepdfmarks && ctx->device_state.WantsOptionalContent) {
891
10.0k
            pdf_obj *o = NULL;
892
10.0k
            int code = 0;
893
894
10.0k
            code = pdfi_dict_knownget_type(ctx, ctx->Root, "OCProperties", PDF_DICT, &o);
895
10.0k
            if (code > 0) {
896
                /* Build and send the OCProperties structure */
897
395
                code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "OCProperties");
898
395
                pdfi_countdown(o);
899
395
                if (code < 0)
900
                    /* Error message ? */
901
82
                ;
902
395
            }
903
10.0k
        }
904
85.2k
    }
905
85.2k
    return 0;
906
85.2k
}
907
908
int pdfi_close_pdf_file(pdf_context *ctx)
909
0
{
910
0
    if (ctx->Root) {
911
0
        if (ctx->device_state.writepdfmarks && ctx->device_state.WantsOptionalContent) {
912
0
            pdf_obj *o = NULL;
913
0
            int code = 0;
914
915
0
            code = pdfi_dict_knownget(ctx, ctx->Root, "OCProperties", &o);
916
0
            if (code > 0) {
917
                /* Build and send the OCProperties structure */
918
0
                code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "OCProperties");
919
0
                pdfi_countdown(o);
920
0
                if (code < 0)
921
                    /* Error message ? */
922
0
                    ;
923
0
            }
924
0
        }
925
0
    }
926
927
0
    if (ctx->main_stream) {
928
0
        if (ctx->main_stream->s) {
929
0
            sfclose(ctx->main_stream->s);
930
0
        }
931
0
        gs_free_object(ctx->memory, ctx->main_stream, "Closing main PDF file");
932
0
        ctx->main_stream = NULL;
933
0
    }
934
0
    ctx->main_stream_length = 0;
935
936
0
    if (ctx->filename) {
937
0
        gs_free_object(ctx->memory, ctx->filename, "pdfi_close_pdf_file, free copy of filename");
938
0
        ctx->filename = NULL;
939
0
    }
940
941
0
    pdfi_clear_context(ctx);
942
0
    return 0;
943
0
}
944
945
static int pdfi_process(pdf_context *ctx)
946
0
{
947
0
    int code = 0, i;
948
949
    /* Loop over each page and either render it or output the
950
     * required information.
951
     */
952
0
    for (i=0;i < ctx->num_pages;i++) {
953
0
        if (ctx->args.first_page != 0) {
954
0
            if (i < ctx->args.first_page - 1)
955
0
                continue;
956
0
        }
957
0
        if (ctx->args.last_page != 0) {
958
0
            if (i > ctx->args.last_page - 1)
959
0
                break;
960
0
        }
961
0
        if (ctx->args.pdfinfo)
962
0
            code = pdfi_output_page_info(ctx, i);
963
0
        else
964
0
            code = pdfi_page_render(ctx, i, true);
965
966
0
        if (code < 0)
967
0
            code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_process", NULL);
968
0
    }
969
0
    pdfi_report_errors(ctx);
970
971
0
    return code;
972
0
}
973
974
/* This works by reading each embedded file referenced by the collection. If it
975
 * has a MIME type indicating it's a PDF file, or somewhere in the first 2KB it
976
 * has the PDF header (%PDF-) then we treat it as a PDF file. We read the contents
977
 * of the refrenced stream and write them to disk in a scratch file.
978
 *
979
 * We then process each scratch file in turn. Note that we actually return an
980
 * array of strings; the first string is the temporary filename, the second is
981
 * the entry from the names tree. Since this can be in UTF16-BE format, it can
982
 * contain embedded single byte NULL characters, so we can't use a regular C
983
 * string. Instead we use a triple byte NULL termination.
984
 *
985
 * It ought to be possible to do all the processing without creating scratch files, by saving the
986
 * current file state, and opening a new 'file' on the stream in the original PDF
987
 * file. But I couldn't immediately get that to work.
988
 * So this is a FIXME future enhancement.
989
 */
990
int pdfi_prep_collection(pdf_context *ctx, uint64_t *TotalFiles, char ***names_array)
991
0
{
992
0
    int code = 0, i, NumEmbeddedFiles = 0;
993
0
    pdf_obj *Names = NULL, *EmbeddedFiles = NULL;
994
0
    pdf_array *FileNames = NULL;
995
0
    pdf_obj *EF = NULL, *F = NULL;
996
0
    char **working_array = NULL;
997
998
0
    if (pdfi_dict_knownget_type(ctx, ctx->Root, "Names", PDF_DICT, &Names) > 0) {
999
0
        if(pdfi_dict_knownget_type(ctx, (pdf_dict *)Names, "EmbeddedFiles", PDF_DICT, &EmbeddedFiles) > 0) {
1000
0
            if (pdfi_dict_knownget_type(ctx, (pdf_dict *)EmbeddedFiles, "Names", PDF_ARRAY, (pdf_obj **)&FileNames) > 0) {
1001
0
                int ix = 0, index = 0;
1002
0
                gp_file *scratch_file = NULL;
1003
0
                char scratch_name[gp_file_name_sizeof];
1004
1005
0
                NumEmbeddedFiles = pdfi_array_size(FileNames) / 2;
1006
1007
0
                working_array = (char **)gs_alloc_bytes(ctx->memory, (size_t)NumEmbeddedFiles * 2 * sizeof(char *), "Collection file working names array");
1008
0
                if (working_array == NULL) {
1009
0
                    code = gs_note_error(gs_error_VMerror);
1010
0
                    goto exit;
1011
0
                }
1012
0
                memset(working_array, 0x00, NumEmbeddedFiles * 2 * sizeof(char *));
1013
1014
0
                for (ix = 0;ix < NumEmbeddedFiles;ix++) {
1015
0
                    pdf_obj *File = NULL;
1016
0
                    pdf_obj *Subtype = NULL;
1017
1018
0
                    code = pdfi_array_get(ctx, FileNames, (ix * 2) + 1, &File);
1019
0
                    if (code < 0)
1020
0
                        goto exit;
1021
1022
0
                    if (pdfi_type_of(File) == PDF_DICT) {
1023
0
                        if (pdfi_dict_knownget_type(ctx, (pdf_dict *)File, "EF", PDF_DICT, &EF) > 0) {
1024
0
                            if (pdfi_dict_knownget_type(ctx, (pdf_dict *)EF, "F", PDF_STREAM, &F) > 0) {
1025
0
                                pdf_dict *stream_dict = NULL;
1026
0
                                pdf_c_stream *s = NULL;
1027
1028
                                /* pdfi_dict_from_object does not increment the reference count of the stream dictionary
1029
                                 * so we do not need to count it down later.
1030
                                 */
1031
0
                                code = pdfi_dict_from_obj(ctx, F, &stream_dict);
1032
0
                                if (code >= 0) {
1033
0
                                    if (pdfi_dict_knownget_type(ctx, stream_dict, "Subtype", PDF_NAME, &Subtype) <= 0) {
1034
                                        /* No Subtype, (or not a name) we can't check the Mime type, so try to read the first 2Kb
1035
                                         * and look for a %PDF- in that. If not present, assume its not a PDF
1036
                                         */
1037
0
                                        code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, (pdf_stream *)F), SEEK_SET);
1038
0
                                        if (code >= 0) {
1039
0
                                            code = pdfi_filter(ctx, (pdf_stream *)F, ctx->main_stream, &s, false);
1040
0
                                            if (code >= 0) {
1041
0
                                                char Buffer[2048];
1042
0
                                                int bytes;
1043
1044
0
                                                bytes = pdfi_read_bytes(ctx, (byte *)Buffer, 1, 2048, 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
                                                    if (strstr(Buffer, "%PDF-") == NULL)
1050
0
                                                        code = -1;
1051
0
                                                } else
1052
0
                                                    code = -1;
1053
0
                                            }
1054
0
                                        }
1055
0
                                    } else {
1056
0
                                        if (!pdfi_name_is((const pdf_name *)Subtype, "application/pdf"))
1057
0
                                            code = -1;
1058
0
                                    }
1059
1060
0
                                    if (code >= 0) {
1061
                                        /* Appears to be a PDF file. Create a scratch file to hold it, and then
1062
                                         * read the file from the PDF, and write it to the scratch file. Record
1063
                                         * the scratch filename in the working_array for later processing.
1064
                                         */
1065
0
                                        scratch_file = gp_open_scratch_file(ctx->memory, "gpdf-collection-", scratch_name, "wb");
1066
0
                                        if (scratch_file != NULL) {
1067
0
                                            code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, (pdf_stream *)F), SEEK_SET);
1068
0
                                            if (code >= 0) {
1069
0
                                                double L;
1070
0
                                                pdf_c_stream *SubFile_stream = NULL;
1071
1072
                                                /* Start by setting up the file to be read. Apply a SubFileDecode so that, if the input stream
1073
                                                 * is not compressed we will stop reading when we get to the end of the stream.
1074
                                                 */
1075
0
                                                if (pdfi_dict_knownget_number(ctx, stream_dict, "Length", &L) > 0) {
1076
1077
0
                                                    code = pdfi_apply_SubFileDecode_filter(ctx, (int)L, NULL, ctx->main_stream, &SubFile_stream, false);
1078
0
                                                    if (code >= 0)
1079
0
                                                        code = pdfi_filter(ctx, (pdf_stream *)F, SubFile_stream, &s, false);
1080
0
                                                } else
1081
0
                                                    code = pdfi_filter(ctx, (pdf_stream *)F, ctx->main_stream, &s, false);
1082
1083
0
                                                if (code >= 0) {
1084
0
                                                    char Buffer[2048];
1085
0
                                                    int bytes;
1086
0
                                                    pdf_string *Name = NULL;
1087
1088
                                                    /* Read the stream contents and write them to the scratch file */
1089
0
                                                    do {
1090
0
                                                        bytes = pdfi_read_bytes(ctx, (byte *)Buffer, 1, 2048, s);
1091
0
                                                        (void)gp_fwrite(Buffer, 1, bytes, scratch_file);
1092
0
                                                    } while (bytes > 0);
1093
1094
                                                    /* Create an entry for the Description in the names array */
1095
0
                                                    code = pdfi_array_get(ctx, FileNames, ix * 2, (pdf_obj **)&Name);
1096
0
                                                    if (code >= 0) {
1097
0
                                                        if (pdfi_type_of((pdf_obj *)Name) == PDF_STRING) {
1098
0
                                                            working_array[(index * 2) + 1] = (char *)gs_alloc_bytes(ctx->memory, (size_t)Name->length + 3, "Collection file names array entry");
1099
0
                                                            if (working_array[(index * 2) + 1] != NULL) {
1100
0
                                                                memset(working_array[(index * 2) + 1], 0x00, Name->length + 3);
1101
0
                                                                memcpy(working_array[(index * 2) + 1], Name->data, Name->length);
1102
0
                                                            }
1103
0
                                                        }
1104
0
                                                        pdfi_countdown(Name);
1105
0
                                                        Name = NULL;
1106
0
                                                    }
1107
1108
                                                    /* And now the scratch file name */
1109
0
                                                    working_array[index * 2] = (char *)gs_alloc_bytes(ctx->memory, (size_t)strlen(scratch_name) + 3, "Collection file names array entry");
1110
0
                                                    if (working_array[index * 2] != NULL) {
1111
0
                                                        memset(working_array[index * 2], 0x00, strlen(scratch_name) + 3);
1112
0
                                                        strcpy(working_array[index * 2], scratch_name);
1113
0
                                                    }
1114
1115
0
                                                    index++;
1116
0
                                                    (*TotalFiles)++;
1117
0
                                                    pdfi_close_file(ctx, s);
1118
0
                                                    s = NULL;
1119
0
                                                }
1120
0
                                                if (SubFile_stream != NULL)
1121
0
                                                    pdfi_close_file(ctx, SubFile_stream);
1122
0
                                                SubFile_stream = NULL;
1123
0
                                            }
1124
0
                                            gp_fclose(scratch_file);
1125
0
                                        } else
1126
0
                                            errprintf(ctx->memory, "\n   **** Warning: Failed to open a scratch file.\n");
1127
0
                                    }
1128
0
                                }
1129
0
                            }
1130
0
                        }
1131
0
                    }
1132
0
                    pdfi_countdown(Subtype);
1133
0
                    Subtype = NULL;
1134
0
                    pdfi_countdown(F);
1135
0
                    F = NULL;
1136
0
                    pdfi_countdown(EF);
1137
0
                    EF = NULL;
1138
0
                    pdfi_countdown(File);
1139
0
                    File = NULL;
1140
0
                }
1141
0
            } else {
1142
0
                errprintf(ctx->memory, "\n   **** Warning: Failed to read EmbeededFiles Names tree.\n");
1143
0
            }
1144
0
        } else {
1145
0
            errprintf(ctx->memory, "\n   **** Warning: Failed to read EmbeddedFiles.\n");
1146
0
        }
1147
0
    } else {
1148
0
        errprintf(ctx->memory, "\n   **** Warning: Failed to find Names tree.\n");
1149
0
    }
1150
0
    code = 0;
1151
1152
0
exit:
1153
0
    if (code >= 0) {
1154
0
        uint64_t ix = 0;
1155
1156
0
        (*names_array) = (char **)gs_alloc_bytes(ctx->memory, *TotalFiles * (size_t)2 * sizeof(char *), "Collection file namesarray");
1157
0
        if (*names_array == NULL)
1158
0
            code = gs_note_error(gs_error_VMerror);
1159
0
        else {
1160
0
            for (i = 0; i < NumEmbeddedFiles;i++) {
1161
0
                if (working_array[i * 2] != NULL && working_array[(i * 2) + 1] != NULL) {
1162
0
                    (*names_array)[ix * 2] = working_array[i * 2];
1163
0
                    working_array[i * 2] = NULL;
1164
0
                    (*names_array)[(ix * 2) + 1] = working_array[(i * 2) + 1];
1165
0
                    working_array[(i * 2) + 1] = NULL;
1166
0
                    ix++;
1167
0
                }
1168
0
            }
1169
0
        }
1170
0
    }
1171
1172
0
    if (working_array != NULL) {
1173
0
        for (i = 0; i < NumEmbeddedFiles;i++)
1174
0
            gs_free_object(ctx->memory, working_array[i], "free collection temporary filenames");
1175
0
        gs_free_object(ctx->memory, working_array, "free collection working array");
1176
0
    }
1177
0
    pdfi_countdown(F);
1178
0
    pdfi_countdown(EF);
1179
0
    pdfi_countdown(FileNames);
1180
0
    pdfi_countdown(EmbeddedFiles);
1181
0
    pdfi_countdown(Names);
1182
0
    return code;
1183
0
}
1184
1185
static int pdfi_process_collection(pdf_context *ctx)
1186
0
{
1187
0
    int code, i;
1188
0
    uint64_t TotalFiles = 0, ix = 0;
1189
0
    char **names_array = NULL;
1190
1191
0
    code = pdfi_prep_collection(ctx, &TotalFiles, &names_array);
1192
0
    if (code >= 0 && TotalFiles > 0)
1193
0
    {
1194
        /* names_array is full of pointers to the scratch file names containing PDF files.
1195
         * Now we need to run each PDF file. First we close down the current file.
1196
         */
1197
0
        (void)pdfi_close_pdf_file(ctx);
1198
1199
0
        for (ix = 0;ix < TotalFiles * 2;ix+=2) {
1200
0
            if (names_array[ix] != NULL) {
1201
0
                (void)pdfi_process_pdf_file(ctx, names_array[ix]);
1202
0
                (void)pdfi_close_pdf_file(ctx);
1203
0
            }
1204
0
        }
1205
0
    } else
1206
        /* We didn't find any PDF files in the Embedded Files. So just run the
1207
         * pages in the container file (the original PDF file)
1208
         */
1209
0
        pdfi_process(ctx);
1210
1211
0
    for (i = 0; i < TotalFiles * 2;i++)
1212
0
        gs_free_object(ctx->memory, names_array[i], "free collection temporary filenames");
1213
0
    gs_free_object(ctx->memory, names_array, "free collection names array");
1214
1215
0
    return 0;
1216
0
}
1217
1218
int pdfi_process_pdf_file(pdf_context *ctx, char *filename)
1219
0
{
1220
0
    int code = 0;
1221
1222
0
    code = pdfi_open_pdf_file(ctx, filename);
1223
0
    if (code < 0) {
1224
0
        pdfi_report_errors(ctx);
1225
0
        return code;
1226
0
    }
1227
1228
    /* Do any custom device configuration */
1229
0
    pdfi_device_misc_config(ctx);
1230
1231
0
    if (ctx->Collection != NULL)
1232
0
        code = pdfi_process_collection(ctx);
1233
0
    else
1234
0
        code = pdfi_process(ctx);
1235
1236
    /* Pdfmark_InitialPage is the offset for Page Dests in
1237
     * /Outlines and Link annotations. It is the count of pages
1238
     * processed so far. Update it by the number of pages in
1239
     * this file.
1240
     */
1241
0
    ctx->Pdfmark_InitialPage += ctx->num_pages;
1242
1243
0
    pdfi_close_pdf_file(ctx);
1244
0
    return code;
1245
0
}
1246
1247
static int pdfi_init_file(pdf_context *ctx)
1248
108k
{
1249
108k
    int code = 0;
1250
108k
    pdf_obj *o = NULL;
1251
1252
108k
    code = pdfi_read_xref(ctx);
1253
108k
    if (code < 0) {
1254
9.94k
        if (ctx->is_hybrid) {
1255
5
            if ((code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_BADXREFSTREAM, "pdfi_init_file", NULL)) < 0) {
1256
0
                goto exit;
1257
0
            }
1258
            /* If its a hybrid file, and we failed to read the XrefStm, try
1259
             * again, but this time read the xref table instead.
1260
             */
1261
5
            pdfi_countdown(ctx->xref_table);
1262
5
            ctx->xref_table = NULL;
1263
5
            ctx->prefer_xrefstm = false;
1264
5
            code = pdfi_read_xref(ctx);
1265
5
            if (code < 0)
1266
0
                goto exit;
1267
9.94k
        } else {
1268
9.94k
            pdfi_set_error(ctx, code, NULL, E_PDF_BADXREFSTREAM, "pdfi_init_file", NULL);
1269
9.94k
            goto exit;
1270
9.94k
        }
1271
9.94k
    }
1272
1273
98.9k
    pdfi_device_set_flags(ctx);
1274
1275
98.9k
    if (ctx->Trailer) {
1276
        /* See comment in pdfi_read_Root() (pdf_doc.c) for details */
1277
43.7k
        pdf_dict *d = ctx->Trailer;
1278
1279
43.7k
        pdfi_countup(d);
1280
43.7k
        code = pdfi_dict_get(ctx, d, "Encrypt", &o);
1281
43.7k
        pdfi_countdown(d);
1282
43.7k
        if (code < 0 && code != gs_error_undefined)
1283
50
            goto exit;
1284
43.6k
        if (code == 0) {
1285
1.39k
            if (pdfi_type_of(o) == PDF_DICT) {
1286
#if USE_PDF_PERMISSIONS
1287
              double Permissions = 0;
1288
              uint32_t P = 0;
1289
#endif
1290
1291
1.36k
                code = pdfi_initialise_Decryption(ctx);
1292
1.36k
                if (code < 0)
1293
296
                    goto exit;
1294
1295
                /* This section is commetned out but deliberately retained. This code
1296
                 * prevents us from processing any PDF file where the 'print' permission
1297
                 * is not set. Additionally, if the 'print' permission is set, but bit 12
1298
                 * 'faitful digital copy' is not set, *and* we are writing to a high level
1299
                 * device, then we will throw an error..
1300
                 */
1301
#if USE_PDF_PERMISSIONS
1302
                code = pdfi_dict_knownget_number(ctx, (pdf_dict *)o, "P", &Permissions);
1303
                if (code < 0)
1304
                    goto exit;
1305
                if (Permissions > ((unsigned long)1 << 31)) {
1306
                    code = gs_note_error(gs_error_rangecheck);
1307
                    goto exit;
1308
                }
1309
                P = (uint32_t)Permissions;
1310
                if ((P & 0x04) == 0) {
1311
                    errprintf(ctx->memory, "   ****The owner of this file has requested you do not print it.\n");
1312
                    code = gs_note_error(gs_error_invalidfileaccess);
1313
                    goto exit;
1314
                }
1315
                if (ctx->device_state.HighLevelDevice) {
1316
                    if ((P & 0x800) == 0) {
1317
                        errprintf(ctx->memory, "   ****The owner of this file has requested you do not make a digital copy of it.\n");
1318
                        code = gs_note_error(gs_error_invalidfileaccess);
1319
                        goto exit;
1320
                    }
1321
                }
1322
#endif
1323
1.36k
            } else {
1324
22
                if (pdfi_type_of(o) != PDF_NULL)
1325
14
                    if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_typecheck), NULL, E_PDF_BADENCRYPT, "pdfi_init_file", NULL)) < 0)
1326
0
                        goto exit;
1327
22
            }
1328
1.39k
        }
1329
43.6k
    }
1330
1331
98.8k
read_root:
1332
98.8k
    if (ctx->Trailer) {
1333
43.5k
        code = pdfi_read_Root(ctx);
1334
43.5k
        if (code < 0) {
1335
            /* If we couldn#'t find the Root object, and we were using the XrefStm
1336
             * from a hybrid file, then try again, but this time use the xref table
1337
             */
1338
1.23k
            if (code == gs_error_undefined && ctx->is_hybrid && ctx->prefer_xrefstm) {
1339
0
                pdfi_countdown(ctx->xref_table);
1340
0
                ctx->xref_table = NULL;
1341
0
                if ((code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_BADXREFSTREAM, "pdfi_init_file", NULL)) < 0)
1342
0
                    goto exit;
1343
1344
0
                ctx->prefer_xrefstm = false;
1345
0
                code = pdfi_read_xref(ctx);
1346
0
                if (code < 0) {
1347
0
                    pdfi_set_error(ctx, 0, NULL, E_PDF_BADXREF, "pdfi_init_file", NULL);
1348
0
                    goto exit;
1349
0
                }
1350
0
                code = pdfi_read_Root(ctx);
1351
0
                if (code < 0)
1352
0
                    goto exit;
1353
1.23k
            } else {
1354
1.23k
                int code1 = pdfi_repair_file(ctx);
1355
1.23k
                if (code1 < 0)
1356
1.00k
                    goto exit;
1357
232
                goto read_root;
1358
1.23k
            }
1359
1.23k
        }
1360
43.5k
    }
1361
1362
97.6k
    if (ctx->Trailer) {
1363
42.3k
        code = pdfi_read_Info(ctx);
1364
42.3k
        if (code < 0 && code != gs_error_undefined) {
1365
1.33k
            if ((code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_init_file", NULL)) < 0)
1366
0
                goto exit;
1367
1.33k
            pdfi_clearstack(ctx);
1368
1.33k
        }
1369
42.3k
    }
1370
1371
97.6k
    if (!ctx->Root) {
1372
8.92k
        errprintf(ctx->memory, "Catalog dictionary not located in file, unable to proceed\n");
1373
8.92k
        return_error(gs_error_syntaxerror);
1374
8.92k
    }
1375
1376
88.7k
    code = pdfi_read_Pages(ctx);
1377
88.7k
    if (code < 0)
1378
3.02k
        goto exit;
1379
1380
85.6k
    code = pdfi_doc_page_array_init(ctx);
1381
85.6k
    if (code < 0)
1382
1
        goto exit;
1383
1384
85.6k
    if (ctx->num_pages == 0)
1385
218
        errprintf(ctx->memory, "\n   **** Warning: PDF document has no pages.\n");
1386
1387
85.6k
    code = pdfi_doc_trailer(ctx);
1388
85.6k
    if (code < 0)
1389
0
        goto exit;
1390
1391
85.6k
    pdfi_read_OptionalRoot(ctx);
1392
1393
85.6k
    if (ctx->args.pdfinfo) {
1394
0
        code = pdfi_output_metadata(ctx);
1395
0
        if (code < 0 && (code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_init_file", NULL)) < 0)
1396
0
            goto exit;
1397
0
    }
1398
1399
99.9k
exit:
1400
99.9k
    if (code < 0)
1401
14.3k
        pdfi_set_error(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_init_file", NULL);
1402
99.9k
    pdfi_countdown(o);
1403
99.9k
    return code;
1404
85.6k
}
1405
1406
int pdfi_set_input_stream(pdf_context *ctx, stream *stm)
1407
109k
{
1408
109k
    byte *Buffer = NULL;
1409
109k
    char *s = NULL, *test = NULL;
1410
109k
    float version = 0.0;
1411
109k
    gs_offset_t Offset = 0;
1412
109k
    int64_t bytes = 0, leftover = 0, bytes_left = 0;
1413
109k
    bool found = false;
1414
109k
    int code;
1415
1416
    /* In case of broken PDF files, the repair could run off the end of the
1417
     * file, so make sure that doing so does *not* automagically close the file
1418
     */
1419
109k
    stm->close_at_eod = false;
1420
1421
109k
    ctx->main_stream = (pdf_c_stream *)gs_alloc_bytes(ctx->memory, sizeof(pdf_c_stream), "PDF interpreter allocate main PDF stream");
1422
109k
    if (ctx->main_stream == NULL)
1423
0
        return_error(gs_error_VMerror);
1424
109k
    memset(ctx->main_stream, 0x00, sizeof(pdf_c_stream));
1425
109k
    ctx->main_stream->s = stm;
1426
1427
109k
    Buffer = gs_alloc_bytes(ctx->memory, BUF_SIZE, "PDF interpreter - allocate working buffer for file validation");
1428
109k
    if (Buffer == NULL) {
1429
0
        code = gs_error_VMerror;
1430
0
        goto error;
1431
0
    }
1432
1433
    /* Determine file size */
1434
109k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
1435
109k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_END);
1436
109k
    ctx->main_stream_length = pdfi_tell(ctx->main_stream);
1437
109k
    Offset = BUF_SIZE;
1438
109k
    bytes = BUF_SIZE;
1439
109k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
1440
1441
109k
    bytes = Offset = min(BUF_SIZE - 1, ctx->main_stream_length);
1442
1443
109k
    if (ctx->args.pdfdebug)
1444
0
        outprintf(ctx->memory, "%% Reading header\n");
1445
1446
109k
    bytes = pdfi_read_bytes(ctx, Buffer, 1, Offset, ctx->main_stream);
1447
109k
    if (bytes <= 0) {
1448
7
        errprintf(ctx->memory, "Failed to read any bytes from input stream\n");
1449
7
        code = gs_error_ioerror;
1450
7
        goto error;
1451
7
    }
1452
108k
    if (bytes < 8) {
1453
70
        errprintf(ctx->memory, "Failed to read enough bytes for a valid PDF header from input stream\n");
1454
70
        code = gs_error_ioerror;
1455
70
        goto error;
1456
70
    }
1457
108k
    Buffer[Offset] = 0x00;
1458
1459
    /* First check for existence of header */
1460
108k
    test = (char *)Buffer;
1461
108k
    bytes_left = bytes;
1462
108k
    s = strstr((char *)test, "%PDF-");
1463
108k
    if (s == NULL) {
1464
0
        if ((code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, W_PDF_GARBAGE_B4HDR, "pdfi_set_input_stream", "")) < 0) {
1465
0
            goto error;
1466
0
        }
1467
0
    }
1468
    /* Garbage before the header can be anything, including binary and NULL (0x00) characters
1469
     * which can defeat using strstr, so if we fail to find a header, try moving on by the length
1470
     * of the C string + 1 and try again.
1471
     */
1472
108k
    while (s == NULL) {
1473
0
        bytes_left -= (strlen(test) + 1);
1474
0
        if (bytes_left < 5)
1475
0
            break;
1476
0
        test += strlen(test) + 1;
1477
0
        s = strstr((char *)test, "%PDF-");
1478
0
    };
1479
108k
    if (s == NULL) {
1480
0
        char extra_info[gp_file_name_sizeof];
1481
1482
0
        if (ctx->filename)
1483
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);
1484
0
        else
1485
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");
1486
1487
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)
1488
0
            goto error;
1489
108k
    } else {
1490
        /* Now extract header version (may be overridden later) */
1491
108k
        if (sscanf(s + 5, "%f", &version) != 1) {
1492
4.50k
            ctx->HeaderVersion = 0;
1493
4.50k
            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)
1494
0
                goto error;
1495
4.50k
        }
1496
104k
        else {
1497
104k
            ctx->HeaderVersion = version;
1498
104k
            s += 5;
1499
439k
            while (((*s >= '0' && *s <= '9') || *s == '.') && *s != 0x00)
1500
334k
                s++;
1501
108k
            while (*s != 0x00) {
1502
108k
                if (*s == 0x09 || *s== 0x0c || *s == 0x20) {
1503
4.03k
                    s++;
1504
4.03k
                    continue;
1505
4.03k
                }
1506
103k
                if (*s != 0x0A && *s != 0x0D) {
1507
5.07k
                    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)
1508
0
                        goto error;
1509
5.07k
                }
1510
103k
                break;
1511
103k
            }
1512
104k
        }
1513
108k
        if (ctx->args.pdfdebug)
1514
0
            outprintf(ctx->memory, "%% Found header, PDF version is %f\n", ctx->HeaderVersion);
1515
108k
    }
1516
1517
    /* Jump to EOF and scan backwards looking for startxref */
1518
108k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_END);
1519
1520
108k
    if (ctx->args.pdfdebug)
1521
0
        outprintf(ctx->memory, "%% Searching for 'startxref' keyword\n");
1522
1523
    /* Initially read min(BUF_SIZE, file_length) bytes of data to the buffer */
1524
108k
    bytes = Offset;
1525
1526
896k
    do {
1527
896k
        byte *last_lineend = NULL;
1528
896k
        uint32_t read;
1529
1530
896k
        if (pdfi_seek(ctx, ctx->main_stream, ctx->main_stream_length - Offset, SEEK_SET) != 0) {
1531
11
            char msg[128];
1532
11
            gs_snprintf(msg, 128, "%% File is smaller than %"PRIi64" bytes\n", (int64_t)Offset);
1533
11
            code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_ioerror), NULL, E_PDF_GS_LIB_ERROR, "pdfi_set_input_stream", msg);
1534
11
            goto error;
1535
11
        }
1536
896k
        read = pdfi_read_bytes(ctx, Buffer, 1, bytes, ctx->main_stream);
1537
1538
896k
        if (read <= 0) {
1539
0
            char msg[128];
1540
0
            gs_snprintf(msg, 128, "Failed to read %"PRIi64" bytes from file\n", (int64_t)bytes);
1541
0
            code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_ioerror), NULL, E_PDF_GS_LIB_ERROR, "pdfi_set_input_stream", msg);
1542
0
            goto error;
1543
0
        }
1544
1545
        /* When reading backwards, if we ran out of data in the last buffer while looking
1546
         * for a 'startxref, but we had found a linefeed, then we preserved everything
1547
         * from the beginning of the buffer up to that linefeed, by copying it to the end
1548
         * of the buffer and reducing the number of bytes to read so that it should have filled
1549
         * in the gap. If we didn't read enough bytes, then we have a gap between the end of
1550
         * the data we just read and the leftover data from teh last buffer. Move the preserved
1551
         * data down to meet the end of the data we just read.
1552
         */
1553
896k
        if (bytes != read && leftover != 0)
1554
0
            memcpy(Buffer + read, Buffer + bytes, leftover);
1555
1556
        /* As above, if we had any leftover data from the last buffer then increase the
1557
         * number of bytes available by that amount. We increase 'bytes' (the number of bytes
1558
         * to read) to the same value, which should mean we read an entire buffer's worth. Of
1559
         * course if we have any data left out of this buffer we'll reduce bytes again...
1560
         */
1561
896k
        read = bytes = read + leftover;
1562
1563
        /* Now search backwards in the buffer for the startxref token */
1564
1.70G
        while(read) {
1565
1.70G
            if (memcmp(Buffer + read - 9, "startxref", 9) == 0) {
1566
52.5k
                found = true;
1567
52.5k
                break;
1568
1.70G
            } else {
1569
1.70G
                if (Buffer[read - 1] == 0x0a || Buffer[read - 1] == 0x0d)
1570
28.1M
                    last_lineend = Buffer + read;
1571
1.70G
            }
1572
1.70G
            read--;
1573
1.70G
        }
1574
896k
        if (found) {
1575
52.5k
            byte *b = Buffer + read;
1576
1577
            /* Success! stop now */
1578
52.5k
            if(sscanf((char *)b, " %"PRIdOFFSET"", &ctx->startxref) != 1) {
1579
822
                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)
1580
0
                    goto error;
1581
822
            }
1582
52.5k
            break;
1583
843k
        } else {
1584
            /* Our file read could conceivably have read back to the point where we read
1585
             * part of the 'startxref' token, but not all of it. So we want to preserve
1586
             * the data in the buffer, but not all of it obviously! The 'startxref' should be followed
1587
             * by a line ending, so above we keep a note of the last line ending. If we found one, then
1588
             * we preserve from the start of the buffer to that point. This could slow us up if the file
1589
             * Is broken, or has a load of junk after the EOF, because we could potentially be saving a
1590
             * lot of data on each pass, but that's only going to happen with bad files.
1591
             * Note we reduce the number of bytes to read so that it just fits into the buffer up to the
1592
             * beginning of the data we preserved.
1593
             */
1594
843k
            if (last_lineend) {
1595
778k
                leftover = last_lineend - Buffer;
1596
                /* Ensure we don't try to copy more than half a buffer, because that will
1597
                 * end up overrunning the buffer end. Since we are only doing this to
1598
                 * ensure we don't drop a partial 'startxref' that's far more than enough.
1599
                 */
1600
778k
                if (leftover < BUF_SIZE / 2) {
1601
762k
                    memmove(Buffer + bytes - leftover, last_lineend, leftover);
1602
762k
                    bytes -= leftover;
1603
762k
                } else
1604
15.9k
                    leftover = 0;
1605
778k
            } else
1606
65.7k
                leftover = 0;
1607
843k
        }
1608
1609
843k
        Offset += bytes;
1610
843k
    } while(Offset < ctx->main_stream_length);
1611
1612
108k
    if (!found) {
1613
56.3k
        if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_undefined), NULL, E_PDF_NOSTARTXREF, "pdfi_set_input_stream", NULL)) < 0)
1614
0
            goto error;
1615
56.3k
    }
1616
1617
108k
    code = pdfi_init_file(ctx);
1618
1619
109k
error:
1620
109k
    gs_free_object(ctx->memory, Buffer, "PDF interpreter - allocate working buffer for file validation");
1621
109k
    return code;
1622
108k
}
1623
1624
int pdfi_open_pdf_file(pdf_context *ctx, char *filename)
1625
0
{
1626
0
    stream *s = NULL;
1627
0
    int code;
1628
1629
0
    if (ctx->args.pdfdebug)
1630
0
        outprintf(ctx->memory, "%% Attempting to open %s as a PDF file\n", filename);
1631
1632
0
    ctx->filename = (char *)gs_alloc_bytes(ctx->memory, (size_t)strlen(filename) + 1, "copy of filename");
1633
0
    if (ctx->filename == NULL)
1634
0
        return_error(gs_error_VMerror);
1635
0
    strcpy(ctx->filename, filename);
1636
1637
0
    s = sfopen(filename, "r", ctx->memory);
1638
0
    if (s == NULL) {
1639
0
        emprintf1(ctx->memory, "Failed to open file %s\n", filename);
1640
0
        return_error(gs_error_ioerror);
1641
0
    }
1642
0
    code = pdfi_set_input_stream(ctx, s);
1643
0
    return code;
1644
0
}
1645
1646
static size_t pdfi_grdir_path_string_match(const byte *str, size_t sl0, byte *pat, size_t pl)
1647
0
{
1648
0
    bool found = false;
1649
0
    size_t sl = sl0;
1650
1651
0
    while (found == false) {
1652
0
        if (pl > sl)
1653
0
            break;
1654
0
        if (*str == *pat && memcmp(str, pat, pl) == 0)
1655
0
            found = true;
1656
0
        else {
1657
0
            str++;
1658
0
            sl--;
1659
0
        }
1660
0
    }
1661
0
    if (found)
1662
0
        return (sl0 - sl) + pl;
1663
0
    else
1664
0
        return 0;
1665
0
}
1666
1667
int pdfi_add_paths_to_search_paths(pdf_context *ctx, const char *ppath, int l, bool fontpath)
1668
0
{
1669
0
    int i, slen, npaths = (l > 0) ? 1 : 0;
1670
0
    const char *p = ppath;
1671
0
    char *ps;
1672
0
    const char *pe = p + l + 1;
1673
0
    int code = 0;
1674
0
    static const char *resstr = "Resource";
1675
0
    const int restrlen = strlen(resstr);
1676
0
    const char *dirsepstr = gp_file_name_directory_separator();
1677
0
    const int dirsepstrlen = strlen(dirsepstr);
1678
0
    char genresstr[64];
1679
1680
0
    for (ps = (char *)p; ps < pe; ps++) {
1681
0
        if (*ps == gp_file_name_list_separator)
1682
0
           npaths++;
1683
0
    }
1684
1685
0
    if (npaths > 0) {
1686
0
        gs_param_string *pathstrings;
1687
0
        int new_npaths = ctx->search_paths.num_resource_paths + npaths;
1688
1689
0
        if (fontpath != true) {
1690
0
            pathstrings = (gs_param_string *)gs_alloc_bytes(ctx->memory, (size_t)sizeof(gs_param_string) * new_npaths, "array of paths");
1691
0
            if (pathstrings == NULL)
1692
0
                return_error(gs_error_VMerror);
1693
1694
0
            memset(pathstrings, 0x00, sizeof(gs_param_string) * new_npaths);
1695
1696
0
            for (i = 1; i <= ctx->search_paths.num_init_resource_paths; i++) {
1697
0
                pathstrings[new_npaths - i] = ctx->search_paths.resource_paths[ctx->search_paths.num_resource_paths - i];
1698
0
            }
1699
1700
0
            for (i = 0; i < ctx->search_paths.num_resource_paths - ctx->search_paths.num_init_resource_paths; i++) {
1701
0
                pathstrings[i] = ctx->search_paths.resource_paths[i];
1702
0
            }
1703
            /* DO NOT CHANGE "i" BETWEEN HERE....... */
1704
0
            gs_free_object(ctx->memory, ctx->search_paths.resource_paths, "old array of paths");
1705
0
            ctx->search_paths.resource_paths = pathstrings;
1706
0
            ctx->search_paths.num_resource_paths += npaths;
1707
1708
            /* .....AND HERE */
1709
0
            for (ps = (char *)p; ps < pe; ps++) {
1710
0
                if (*ps == gp_file_name_list_separator || ps == pe - 1) {
1711
0
                    if (*p == gp_file_name_list_separator) p++; /* move past the separator */
1712
0
                    slen = ps - p;
1713
0
                    pathstrings[i].data = (byte *)gs_alloc_bytes(ctx->memory, slen, "path string body");
1714
1715
0
                    if (pathstrings[i].data == NULL) {
1716
0
                        code = gs_note_error(gs_error_VMerror);
1717
0
                        break;
1718
0
                    }
1719
1720
0
                    memcpy((char *)pathstrings[i].data, p, slen);
1721
0
                    pathstrings[i].size = slen;
1722
0
                    pathstrings[i].persistent = false;
1723
0
                    i++;
1724
0
                    p = ps++;
1725
0
                }
1726
0
            }
1727
0
            if ((restrlen + 2 * dirsepstrlen) < 64) {
1728
0
                size_t grdlen;
1729
1730
0
                memcpy(genresstr, resstr, restrlen  +1); /* +1 So we get the null terminator */
1731
0
                strncat(genresstr, dirsepstr, dirsepstrlen);
1732
1733
0
                for (i = 0; i < ctx->search_paths.num_resource_paths; i++) {
1734
0
                    if ((grdlen = pdfi_grdir_path_string_match(ctx->search_paths.resource_paths[i].data, ctx->search_paths.resource_paths[i].size, (byte *)genresstr, restrlen + dirsepstrlen)) > 0) {
1735
0
                        ctx->search_paths.genericresourcedir.data = ctx->search_paths.resource_paths[i].data;
1736
0
                        ctx->search_paths.genericresourcedir.size = grdlen;
1737
0
                        ctx->search_paths.genericresourcedir.persistent = true;
1738
0
                        break;
1739
0
                    }
1740
0
                }
1741
0
            }
1742
0
        }
1743
0
        else {
1744
0
            p = ppath;
1745
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");
1746
0
            if (pathstrings == NULL)
1747
0
                return_error(gs_error_VMerror);
1748
1749
0
            memset(pathstrings, 0x00, sizeof(gs_param_string) * (npaths + ctx->search_paths.num_font_paths));
1750
1751
0
            for (i = 0; i < ctx->search_paths.num_font_paths; i++) {
1752
0
                pathstrings[ctx->search_paths.num_font_paths + i] = ctx->search_paths.font_paths[i];
1753
0
            }
1754
0
            gs_free_object(ctx->memory, ctx->search_paths.font_paths, "old array of paths");
1755
0
            ctx->search_paths.font_paths = pathstrings;
1756
0
            ctx->search_paths.num_font_paths += npaths;
1757
1758
0
            i = 0;
1759
0
            for (ps = (char *)p; ps < pe; ps++) {
1760
0
                if (*ps == gp_file_name_list_separator || ps == pe - 1) {
1761
0
                    slen = ps - p;
1762
0
                    pathstrings[i].data = (byte *)gs_alloc_bytes(ctx->memory, slen, "path string body");
1763
1764
0
                    if (pathstrings[i].data == NULL) {
1765
0
                        code = gs_note_error(gs_error_VMerror);
1766
0
                        break;
1767
0
                    }
1768
1769
0
                    memcpy((char *)pathstrings[i].data, p, slen);
1770
0
                    pathstrings[i].size = slen;
1771
0
                    pathstrings[i].persistent = false;
1772
0
                    i++;
1773
0
                    p = ps++;
1774
0
                }
1775
0
            }
1776
0
        }
1777
0
    }
1778
1779
0
    return code;
1780
0
}
1781
1782
int pdfi_add_initial_paths_to_search_paths(pdf_context *ctx, const char *ppath, int l)
1783
0
{
1784
0
    int code;
1785
0
    if (ctx->search_paths.num_resource_paths != 0)
1786
0
        return_error(gs_error_invalidaccess);
1787
1788
0
    code = pdfi_add_paths_to_search_paths(ctx, ppath, l, false);
1789
0
    ctx->search_paths.num_init_resource_paths = ctx->search_paths.num_resource_paths;
1790
1791
0
    return code;
1792
0
}
1793
1794
static void pdfi_free_search_paths(pdf_context *ctx)
1795
109k
{
1796
109k
    int i;
1797
1.52M
    for (i = 0; i < ctx->search_paths.num_resource_paths; i++) {
1798
1.41M
        if (ctx->search_paths.resource_paths[i].persistent == false)
1799
1.41M
            gs_free_object(ctx->memory, (byte *)ctx->search_paths.resource_paths[i].data, "path string body");
1800
1.41M
    }
1801
109k
    for (i = 0; i < ctx->search_paths.num_font_paths; i++) {
1802
0
        if (ctx->search_paths.font_paths[i].persistent == false)
1803
0
            gs_free_object(ctx->memory, (byte *)ctx->search_paths.font_paths[i].data, "path string body");
1804
0
    }
1805
109k
    gs_free_object(ctx->memory, (byte *)ctx->search_paths.resource_paths, "array of paths");
1806
109k
    gs_free_object(ctx->memory, (byte *)ctx->search_paths.font_paths, "array of font paths");
1807
1808
109k
    if (ctx->search_paths.genericresourcedir.persistent == false)
1809
109k
        gs_free_object(ctx->memory, (byte *)ctx->search_paths.genericresourcedir.data, "generic resource directory");
1810
109k
}
1811
1812
static void pdfi_free_fontmapfiles(pdf_context *ctx)
1813
109k
{
1814
109k
    int i;
1815
109k
    for (i = 0; i < ctx->num_fontmapfiles; i++) {
1816
0
        gs_free_object(ctx->memory, ctx->fontmapfiles[i].data, "fontmapfiles string body");
1817
0
    }
1818
109k
    gs_free_object(ctx->memory, ctx->fontmapfiles, "fontmapfiles array");
1819
109k
}
1820
1821
/* The fontmap file list doesn't extend, later settings in the command line override earlier ones
1822
   (Unlike the "-I" search paths above).
1823
 */
1824
int pdfi_add_fontmapfiles(pdf_context *ctx, const char *ppath, int l)
1825
0
{
1826
0
    int i, nfilenames = (l > 0) ? 1 : 0;
1827
0
    const char *p = ppath;
1828
0
    char *ps;
1829
0
    const char *pe = p + l + 1;
1830
0
    int code = 0;
1831
1832
0
    pdfi_free_fontmapfiles(ctx);
1833
1834
0
    for (ps = (char *)p; ps < pe; ps++) {
1835
0
        if (*ps == gp_file_name_list_separator)
1836
0
           nfilenames++;
1837
0
    }
1838
0
    if (nfilenames > 0) {
1839
0
        ctx->fontmapfiles = (gs_string *)gs_alloc_bytes(ctx->memory, (size_t)sizeof(gs_string) * nfilenames, "array of fontmap files");
1840
0
        if (ctx->fontmapfiles == NULL) {
1841
0
            return_error(gs_error_VMerror);
1842
0
        }
1843
0
        else {
1844
0
           memset(ctx->fontmapfiles, 0x00, sizeof(gs_string) * nfilenames);
1845
0
           ctx->num_fontmapfiles = nfilenames;
1846
1847
0
           for (i = 0; i < nfilenames; i++) {
1848
0
               for (ps = (char *)p; ps < pe; ps++) {
1849
0
                   if (*ps == gp_file_name_list_separator)
1850
0
                       break;
1851
0
               }
1852
0
               ctx->fontmapfiles[i].data = gs_alloc_bytes(ctx->memory, ps - p, "fontmap file name body");
1853
0
               if (ctx->fontmapfiles[i].data == NULL) {
1854
0
                    code = gs_note_error(gs_error_VMerror);
1855
0
                    goto done;
1856
0
               }
1857
0
               memcpy(ctx->fontmapfiles[i].data, p, ps - p);
1858
0
               ctx->fontmapfiles[i].size = ps - p;
1859
0
               p = ps + 1;
1860
0
           }
1861
0
        }
1862
0
    }
1863
0
done:
1864
0
    return code;
1865
0
}
1866
1867
/***********************************************************************************/
1868
/* Highest level functions. The context we create here is returned to the 'PL'     */
1869
/* implementation, in future we plan to return it to PostScript by wrapping a      */
1870
/* gargabe collected object 'ref' around it and returning that to the PostScript   */
1871
/* world. custom PostScript operators will then be able to render pages, annots,   */
1872
/* AcroForms etc by passing the opaque object back to functions here, allowing     */
1873
/* the interpreter access to its context.                                          */
1874
1875
/* We start with routines for creating and destroying the interpreter context */
1876
pdf_context *pdfi_create_context(gs_memory_t *mem)
1877
109k
{
1878
109k
    pdf_context *ctx = NULL;
1879
109k
    gs_gstate *pgs = NULL;
1880
109k
    int code = 0;
1881
109k
    gs_memory_t *pmem = mem->non_gc_memory;
1882
#if PDFI_LEAK_CHECK
1883
    gs_memory_status_t mstat;
1884
    code = gs_memory_chunk_wrap(&pmem, mem->non_gc_memory);
1885
    if (code < 0)
1886
        return NULL;
1887
    gs_memory_status(pmem, &mstat);
1888
#endif
1889
1890
109k
    ctx = (pdf_context *) gs_alloc_bytes(pmem, sizeof(pdf_context), "pdf_create_context");
1891
1892
109k
    pgs = gs_gstate_alloc(pmem);
1893
1894
109k
    if (!ctx || !pgs)
1895
0
    {
1896
0
        if (ctx)
1897
0
            gs_free_object(pmem, ctx, "pdf_create_context");
1898
0
        if (pgs)
1899
0
            gs_gstate_free(pgs);
1900
0
        return NULL;
1901
0
    }
1902
1903
109k
    memset(ctx, 0, sizeof(pdf_context));
1904
109k
    ctx->memory = pmem;
1905
109k
    ctx->type = PDF_CTX;
1906
109k
    ctx->flags = 0;
1907
109k
    ctx->refcnt = 1;
1908
109k
    ctx->ctx = ctx;
1909
1910
#if PDFI_LEAK_CHECK
1911
    ctx->memstat = mstat;
1912
#endif
1913
1914
109k
    ctx->stack_bot = (pdf_obj **)gs_alloc_bytes(ctx->memory, INITIAL_STACK_SIZE * sizeof (pdf_obj *), "pdf_imp_allocate_interp_stack");
1915
109k
    if (ctx->stack_bot == NULL) {
1916
0
        gs_free_object(pmem, ctx, "pdf_create_context");
1917
0
        gs_gstate_free(pgs);
1918
0
        return NULL;
1919
0
    }
1920
109k
    ctx->stack_size = INITIAL_STACK_SIZE;
1921
109k
    ctx->stack_top = ctx->stack_bot - 1;
1922
109k
    code = sizeof(pdf_obj *);
1923
109k
    code *= ctx->stack_size;
1924
109k
    ctx->stack_limit = ctx->stack_bot + ctx->stack_size;
1925
1926
109k
    code = pdfi_init_font_directory(ctx);
1927
109k
    if (code < 0) {
1928
0
        gs_free_object(pmem, ctx->stack_bot, "pdf_create_context");
1929
0
        gs_free_object(pmem, ctx, "pdf_create_context");
1930
0
        gs_gstate_free(pgs);
1931
0
        return NULL;
1932
0
    }
1933
1934
109k
    code = gsicc_init_iccmanager(pgs);
1935
109k
    if (code < 0) {
1936
0
        gs_free_object(ctx->memory, ctx->font_dir, "pdf_create_context");
1937
0
        gs_free_object(pmem, ctx->stack_bot, "pdf_create_context");
1938
0
        gs_free_object(pmem, ctx, "pdf_create_context");
1939
0
        gs_gstate_free(pgs);
1940
0
        return NULL;
1941
0
    }
1942
1943
109k
    ctx->pgs = pgs;
1944
109k
    code = pdfi_gstate_set_client(ctx, pgs);
1945
109k
    if (code < 0) {
1946
0
        gs_free_object(ctx->memory, ctx->font_dir, "pdf_create_context");
1947
0
        gs_free_object(pmem, ctx->stack_bot, "pdf_create_context");
1948
0
        gs_free_object(pmem, ctx, "pdf_create_context");
1949
0
        gs_gstate_free(pgs);
1950
0
        return NULL;
1951
0
    }
1952
1953
    /* Some (but not all) path construction operations can either return
1954
     * an error or clamp values when out of range. In order to match Ghostscript's
1955
     * PDF interpreter written in PostScript, we need to clamp them.
1956
     */
1957
109k
    gs_setlimitclamp(pgs, true);
1958
1959
    /* Declare PDL client support for high level patterns, for the benefit
1960
     * of pdfwrite and other high-level devices
1961
     */
1962
109k
    ctx->pgs->have_pattern_streams = true;
1963
109k
    ctx->device_state.preserve_tr_mode = 0;
1964
109k
    ctx->args.notransparency = false;
1965
1966
109k
    ctx->main_stream = NULL;
1967
1968
    /* Setup some flags that don't default to 'false' */
1969
109k
    ctx->args.showannots = true;
1970
109k
    ctx->args.preserveannots = true;
1971
109k
    ctx->args.preservemarkedcontent = true;
1972
109k
    ctx->args.preserveembeddedfiles = true;
1973
109k
    ctx->args.preservedocview = true;
1974
109k
    ctx->args.PDFCacheSize = MAX_OBJECT_CACHE_SIZE;
1975
    /* NOTE: For testing certain annotations on cluster, might want to set this to false */
1976
109k
    ctx->args.printed = false; /* True if OutputFile is set, false otherwise see pdftop.c, pdf_impl_set_param() */
1977
1978
    /* Initially, prefer the XrefStm in a hybrid file */
1979
109k
    ctx->prefer_xrefstm = true;
1980
1981
    /* We decrypt strings from encrypted files until we start a page */
1982
109k
    ctx->encryption.decrypt_strings = true;
1983
109k
    ctx->get_glyph_name = pdfi_glyph_name;
1984
109k
    ctx->get_glyph_index = pdfi_glyph_index;
1985
1986
109k
    ctx->job_gstate_level = ctx->pgs->level;
1987
    /* Weirdly the graphics library wants us to always have two gstates, the
1988
     * initial state and at least one saved state. if we don't then when we
1989
     * grestore back to the initial state, it immediately saves another one.
1990
     */
1991
109k
    code = gs_gsave(ctx->pgs);
1992
109k
    if (code < 0) {
1993
0
        gs_free_object(ctx->memory, ctx->font_dir, "pdf_create_context");
1994
0
        gs_free_object(pmem, ctx->stack_bot, "pdf_create_context");
1995
0
        gs_gstate_free(ctx->pgs);
1996
0
        gs_free_object(pmem, ctx, "pdf_create_context");
1997
0
        return NULL;
1998
0
    }
1999
#if REFCNT_DEBUG
2000
    ctx->UID = 1;
2001
#endif
2002
#if CACHE_STATISTICS
2003
    ctx->hits = 0;
2004
    ctx->misses = 0;
2005
    ctx->compressed_hits = 0;
2006
    ctx->compressed_misses = 0;
2007
#endif
2008
#ifdef DEBUG
2009
    ctx->args.verbose_errors = ctx->args.verbose_warnings = 1;
2010
#endif
2011
109k
    return ctx;
2012
109k
}
2013
2014
/* Purge all */
2015
static bool
2016
pdfi_fontdir_purge_all(const gs_memory_t * mem, cached_char * cc, void *dummy)
2017
1.43M
{
2018
1.43M
    return true;
2019
1.43M
}
2020
2021
#if DEBUG_CACHE
2022
#if DEBUG_CACHE_FREE
2023
static void
2024
pdfi_print_cache(pdf_context *ctx)
2025
{
2026
    pdf_obj_cache_entry *entry = ctx->cache_LRU, *next;
2027
2028
    outprintf(ctx->memory, "CACHE: #entries=%d\n", ctx->cache_entries);
2029
    while(entry) {
2030
        next = entry->next;
2031
#if REFCNT_DEBUG
2032
        outprintf(ctx->memory, "UID:%ld, Object:%d, refcnt:%d, next=%p, prev=%p\n",
2033
                  entry->o->UID, entry->o->object_num, entry->o->refcnt,
2034
                  entry->next, entry->previous);
2035
#else
2036
        outprintf(ctx->memory, "Object:%d, refcnt:%d, next=%p, prev=%p\n",
2037
                  entry->o->object_num, entry->o->refcnt,
2038
                  entry->next, entry->previous);
2039
#endif
2040
        entry = next;
2041
    }
2042
}
2043
#else
2044
static void
2045
pdfi_print_cache(pdf_context *ctx)
2046
{}
2047
#endif
2048
#endif /* DEBUG */
2049
2050
#if PURGE_CACHE_PER_PAGE
2051
void
2052
pdfi_purge_obj_cache(pdf_context *ctx)
2053
{
2054
    if (ctx->cache_entries != 0) {
2055
        pdf_obj_cache_entry *entry = ctx->cache_LRU, *next;
2056
2057
        while(entry) {
2058
            next = entry->next;
2059
            if (entry->o->object_num != 0) {
2060
                ctx->xref_table->xref[entry->o->object_num].cache = NULL;
2061
            }
2062
            pdfi_countdown(entry->o);
2063
            ctx->cache_entries--;
2064
            gs_free_object(ctx->memory, entry, "pdfi_clear_context, free LRU");
2065
            entry = next;
2066
#if REFCNT_DEBUG
2067
            ctx->cache_LRU = entry;
2068
#endif
2069
        }
2070
        ctx->cache_LRU = ctx->cache_MRU = NULL;
2071
        ctx->cache_entries = 0;
2072
    }
2073
}
2074
#endif
2075
2076
/* pdfi_clear_context frees all the PDF objects associated with interpreting a given
2077
 * PDF file. Once we've called this we can happily run another file. This function is
2078
 * called by pdf_free_context (in case of errors during the file leaving state around)
2079
 * and by pdfi_close_pdf_file.
2080
 */
2081
int pdfi_clear_context(pdf_context *ctx)
2082
109k
{
2083
#if CACHE_STATISTICS
2084
    float compressed_hit_rate = 0.0, hit_rate = 0.0;
2085
2086
    if (ctx->compressed_hits > 0 || ctx->compressed_misses > 0)
2087
        compressed_hit_rate = (float)ctx->compressed_hits / (float)(ctx->compressed_hits + ctx->compressed_misses);
2088
    if (ctx->hits > 0 || ctx->misses > 0)
2089
        hit_rate = (float)ctx->hits / (float)(ctx->hits + ctx->misses);
2090
2091
    outprintf(ctx->memory, "Number of normal object cache hits: %"PRIi64"\n", ctx->hits);
2092
    outprintf(ctx->memory, "Number of normal object cache misses: %"PRIi64"\n", ctx->misses);
2093
    outprintf(ctx->memory, "Number of compressed object cache hits: %"PRIi64"\n", ctx->compressed_hits);
2094
    outprintf(ctx->memory, "Number of compressed object cache misses: %"PRIi64"\n", ctx->compressed_misses);
2095
    outprintf(ctx->memory, "Normal object cache hit rate: %f\n", hit_rate);
2096
    outprintf(ctx->memory, "Compressed object cache hit rate: %f\n", compressed_hit_rate);
2097
#endif
2098
109k
    if (ctx->PathSegments != NULL) {
2099
5.93k
        gs_free_object(ctx->memory, ctx->PathSegments, "pdfi_clear_context");
2100
5.93k
        ctx->PathSegments = NULL;
2101
5.93k
    }
2102
109k
    if (ctx->PathPts != NULL) {
2103
5.93k
        gs_free_object(ctx->memory, ctx->PathPts, "pdfi_clear_context");
2104
5.93k
        ctx->PathPts = NULL;
2105
5.93k
    }
2106
2107
109k
    if (ctx->args.PageList) {
2108
0
        gs_free_object(ctx->memory, ctx->args.PageList, "pdfi_clear_context");
2109
0
        ctx->args.PageList = NULL;
2110
0
    }
2111
109k
    if (ctx->Trailer) {
2112
43.7k
        pdfi_countdown(ctx->Trailer);
2113
43.7k
        ctx->Trailer = NULL;
2114
43.7k
    }
2115
2116
109k
    if (ctx->AcroForm) {
2117
7.61k
        pdfi_countdown(ctx->AcroForm);
2118
7.61k
        ctx->AcroForm = NULL;
2119
7.61k
    }
2120
2121
109k
    if(ctx->Root) {
2122
88.9k
        pdfi_countdown(ctx->Root);
2123
88.9k
        ctx->Root = NULL;
2124
88.9k
    }
2125
2126
109k
    if (ctx->Info) {
2127
26.8k
        pdfi_countdown(ctx->Info);
2128
26.8k
        ctx->Info = NULL;
2129
26.8k
    }
2130
2131
109k
    if (ctx->PagesTree) {
2132
85.0k
        pdfi_countdown(ctx->PagesTree);
2133
85.0k
        ctx->PagesTree = NULL;
2134
85.0k
    }
2135
2136
109k
    if (ctx->args.cidfsubstpath.data != NULL) {
2137
0
        gs_free_object(ctx->memory, ctx->args.cidfsubstpath.data, "cidfsubstpath.data");
2138
0
        ctx->args.cidfsubstpath.data = NULL;
2139
0
    }
2140
2141
109k
    if (ctx->args.cidfsubstfont.data != NULL) {
2142
0
        gs_free_object(ctx->memory, ctx->args.cidfsubstfont.data, "cidfsubstfont.data");
2143
0
        ctx->args.cidfsubstfont.data = NULL;
2144
0
    }
2145
2146
109k
    if (ctx->args.defaultfont.data != NULL) {
2147
0
        gs_free_object(ctx->memory, ctx->args.defaultfont.data, "cidfsubstfont.data");
2148
0
        ctx->args.defaultfont.data = NULL;
2149
0
    }
2150
2151
109k
    pdfi_free_cstring_array(ctx, &ctx->args.showannottypes);
2152
109k
    pdfi_free_cstring_array(ctx, &ctx->args.preserveannottypes);
2153
2154
109k
    pdfi_doc_page_array_free(ctx);
2155
2156
109k
    if (ctx->xref_table) {
2157
99.1k
        pdfi_countdown(ctx->xref_table);
2158
99.1k
        ctx->xref_table = NULL;
2159
99.1k
    }
2160
2161
109k
    pdfi_free_OptionalRoot(ctx);
2162
2163
109k
    if (ctx->stack_bot)
2164
109k
        pdfi_clearstack(ctx);
2165
2166
109k
    if (ctx->filename) {
2167
        /* This should already be closed! */
2168
0
        pdfi_close_pdf_file(ctx);
2169
0
        gs_free_object(ctx->memory, ctx->filename, "pdfi_clear_context, free copy of filename");
2170
0
        ctx->filename = NULL;
2171
0
    }
2172
2173
109k
    if (ctx->main_stream) {
2174
109k
        gs_free_object(ctx->memory, ctx->main_stream, "pdfi_clear_context, free main PDF stream");
2175
109k
        ctx->main_stream = NULL;
2176
109k
    }
2177
109k
    ctx->main_stream_length = 0;
2178
2179
109k
    if(ctx->pgs != NULL) {
2180
109k
        gx_pattern_cache_free(ctx->pgs->pattern_cache);
2181
109k
        ctx->pgs->pattern_cache = NULL;
2182
109k
        if (ctx->pgs->font)
2183
0
            pdfi_countdown_current_font(ctx);
2184
2185
        /* We use gs_grestore_only() instead of gs_grestore, because gs_grestore
2186
         * will not restore below two gstates and we want to clear the entire
2187
         * stack of saved states, back to the initial state.
2188
         */
2189
218k
        while (ctx->pgs->level != ctx->job_gstate_level && ctx->pgs->saved)
2190
109k
            gs_grestore_only(ctx->pgs);
2191
109k
    }
2192
2193
109k
    pdfi_free_DefaultQState(ctx);
2194
109k
    pdfi_oc_free(ctx);
2195
2196
109k
    if(ctx->encryption.EKey) {
2197
1.07k
        pdfi_countdown(ctx->encryption.EKey);
2198
1.07k
        ctx->encryption.EKey = NULL;
2199
1.07k
    }
2200
109k
    if (ctx->encryption.Password) {
2201
0
        gs_free_object(ctx->memory, ctx->encryption.Password, "PDF Password from params");
2202
0
        ctx->encryption.Password = NULL;
2203
0
    }
2204
2205
109k
    if (ctx->cache_entries != 0) {
2206
87.1k
        pdf_obj_cache_entry *entry = ctx->cache_LRU, *next;
2207
2208
#if DEBUG_CACHE
2209
        int count;
2210
        bool stop = true;
2211
        pdf_obj_cache_entry *prev;
2212
2213
        do {
2214
            pdfi_print_cache(ctx);
2215
            entry = ctx->cache_LRU;
2216
            stop = true;
2217
            while(entry) {
2218
                pdfi_print_cache(ctx);
2219
                next = entry->next;
2220
                prev = entry->previous;
2221
2222
                /* pass through the cache, count down any objects which are only referenced by the cache (refcnt == 1)
2223
                 * this may cause other objects (referred to by the newly freed object) to decrement their refcnt
2224
                 * until they are also only pointed at by the cache.
2225
                 */
2226
                if (entry->o->refcnt == 1) {
2227
                    stop = false;
2228
                    pdfi_countdown(entry->o);
2229
                    if (prev != NULL)
2230
                        prev->next = next;
2231
                    else
2232
                        ctx->cache_LRU = next;
2233
                    if (next)
2234
                        next->previous = prev;
2235
                    ctx->cache_entries--;
2236
                    gs_free_object(ctx->memory, entry, "pdfi_clear_context, free LRU");
2237
                }
2238
                entry = next;
2239
            }
2240
        } while (stop == false);
2241
2242
        entry = ctx->cache_LRU;
2243
        while(entry) {
2244
            next = entry->next;
2245
            prev = entry->previous;
2246
            count = entry->o->refcnt;
2247
            dbgmprintf1(ctx->memory, "CLEANUP cache entry obj %d", entry->o->object_num);
2248
            dbgmprintf1(ctx->memory, " has refcnt %d\n", count);
2249
            entry = next;
2250
        }
2251
#else
2252
2.25M
        while(entry) {
2253
2.17M
            next = entry->next;
2254
2.17M
            pdfi_countdown(entry->o);
2255
2.17M
            ctx->cache_entries--;
2256
2.17M
            gs_free_object(ctx->memory, entry, "pdfi_clear_context, free LRU");
2257
2.17M
            entry = next;
2258
#if REFCNT_DEBUG
2259
            ctx->cache_LRU = entry;
2260
#endif
2261
2.17M
        }
2262
87.1k
#endif
2263
87.1k
        ctx->cache_LRU = ctx->cache_MRU = NULL;
2264
87.1k
        ctx->cache_entries = 0;
2265
87.1k
    }
2266
2267
    /* We can't free the font directory before the graphics library fonts fonts are freed, as they reference the font_dir.
2268
     * graphics library fonts are refrenced from pdf_font objects, and those may be in the cache, which means they
2269
     * won't be freed until we empty the cache. So we can't free 'font_dir' until after the cache has been cleared.
2270
     */
2271
109k
    if (ctx->font_dir)
2272
109k
        gx_purge_selected_cached_chars(ctx->font_dir, pdfi_fontdir_purge_all, (void *)NULL);
2273
2274
109k
    pdfi_countdown(ctx->pdffontmap);
2275
109k
    ctx->pdffontmap = NULL;
2276
109k
    pdfi_countdown(ctx->pdfnativefontmap);
2277
109k
    ctx->pdfnativefontmap = NULL;
2278
109k
    pdfi_countdown(ctx->pdf_substitute_fonts);
2279
109k
    ctx->pdf_substitute_fonts = NULL;
2280
2281
109k
    return 0;
2282
109k
}
2283
2284
int pdfi_free_context(pdf_context *ctx)
2285
109k
{
2286
#if PDFI_LEAK_CHECK
2287
    gs_memory_status_t mstat, ctxmstat = ctx->memstat;
2288
    gs_memory_t *mem = ctx->memory;
2289
#endif
2290
109k
    pdfi_clear_context(ctx);
2291
2292
109k
    gs_free_object(ctx->memory, ctx->stack_bot, "pdfi_free_context");
2293
2294
109k
    pdfi_free_name_table(ctx);
2295
2296
    /* And here we free the initial graphics state */
2297
109k
    while (ctx->pgs->saved)
2298
0
        gs_grestore_only(ctx->pgs);
2299
2300
109k
    gs_gstate_free(ctx->pgs);
2301
2302
109k
    ctx->pgs = NULL;
2303
2304
109k
    if (ctx->font_dir)
2305
109k
        gs_free_object(ctx->memory, ctx->font_dir, "pdfi_free_context");
2306
2307
    /* Currently this should never happen, but in future it might if we choose
2308
     * not to keep freeing and reallocating the array.
2309
     */
2310
109k
    if (ctx->loop_detection != NULL) {
2311
8
        dbgmprintf(ctx->memory, "Loop detection array exists at EOJ\n");
2312
8
        gs_free_object(ctx->memory, ctx->loop_detection, "pdfi_free_context");
2313
8
    }
2314
2315
109k
    pdfi_free_search_paths(ctx);
2316
109k
    pdfi_free_fontmapfiles(ctx);
2317
2318
109k
    if (ctx->pdfcidfmap != NULL) {
2319
6.67k
        pdfi_countdown(ctx->pdfcidfmap);
2320
6.67k
        ctx->pdfcidfmap = NULL;
2321
6.67k
    }
2322
109k
    if (ctx->pdffontmap != NULL) {
2323
0
        pdfi_countdown(ctx->pdffontmap);
2324
0
        ctx->pdffontmap = NULL;
2325
0
    }
2326
109k
    rc_decrement(ctx->devbbox, "pdfi_free_context");
2327
2328
109k
    gs_free_object(ctx->memory, ctx, "pdfi_free_context");
2329
#if PDFI_LEAK_CHECK
2330
    gs_memory_status(mem, &mstat);
2331
    if (mstat.allocated > ctxmstat.allocated)
2332
        errprintf(mem, "\nMemory Leak Detected: Pre %d, Post %d\n", (int)ctxmstat.allocated, (int)mstat.allocated);
2333
    (void)gs_memory_chunk_unwrap(mem);
2334
#endif
2335
109k
    return 0;
2336
109k
}
2337
2338
/* These routines are used from the PostScript interpreter inteerface. It is important that
2339
 * the 'interpreter part of the graphics state' should be a pdfi interpreter context while pdfi is running
2340
 * but the PostScript itnerpreter context when the PostScript interpreter is running. If we are going
2341
 * to inherit the PostScript graphics state for pdfi, then we need to turn it into a 'pdfi'
2342
 * graphics state for the duration of the interpretation, and back to a PostScript one when
2343
 * we return to the PostScript interpreter.
2344
 *
2345
 * Bizarrely it appears that the interpreter part of the gstate does not obey grestore, instead we copy
2346
 * the 'current' context to the saved context when we do a grestore. This seems wrong to me, but
2347
 * it seems to be what happens, so we can't rely on grestore to put back the interpreter context, but must
2348
 * do so ourselves.
2349
 *
2350
 * Hence the 'from_PS' routine fills in pointers with the current context and procs, with the expectation that
2351
 * these will be saved and used to restore the data in the 'to_PS' routine.
2352
 */
2353
/* NOTE see the comments in zpdfops.c just under the declaration of the pdfi_switch_t strcuture regarding
2354
 * complications with the ICC profile cache.
2355
 */
2356
2357
int pdfi_gstate_from_PS(pdf_context *ctx, gs_gstate *pgs, pdfi_switch_t *i_switch, gsicc_profile_cache_t *profile_cache)
2358
485k
{
2359
485k
    int code;
2360
485k
    i_switch->pgs = ctx->pgs;
2361
485k
    i_switch->procs = pgs->client_procs;
2362
485k
    i_switch->client_data = (void *)pgs->client_data;
2363
485k
    i_switch->profile_cache = pgs->icc_profile_cache;
2364
485k
    code = pdfi_gstate_set_client(ctx, pgs);
2365
485k
    if (code < 0)
2366
0
        return code;
2367
485k
    i_switch->psfont = pgs->font;
2368
485k
    pgs->icc_profile_cache = profile_cache;
2369
485k
    rc_increment(pgs->icc_profile_cache);
2370
485k
    pgs->font = NULL;
2371
485k
    ctx->pgs = pgs;
2372
485k
    return code;
2373
485k
}
2374
2375
void pdfi_gstate_to_PS(pdf_context *ctx, gs_gstate *pgs, pdfi_switch_t *i_switch)
2376
485k
{
2377
485k
    pgs->client_procs.free(pgs->client_data, pgs->memory, pgs);
2378
485k
    pgs->client_data = NULL;
2379
485k
    rc_decrement(pgs->icc_profile_cache, "pdfi_gstate_to_PS");
2380
485k
    pgs->icc_profile_cache = i_switch->profile_cache;
2381
485k
    gs_gstate_set_client(pgs, i_switch->client_data, &i_switch->procs, true);
2382
485k
    ctx->pgs->font = NULL;
2383
485k
    ctx->pgs = i_switch->pgs;
2384
485k
    pgs->font = i_switch->psfont;
2385
485k
}