Coverage Report

Created: 2025-06-24 07:01

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