Coverage Report

Created: 2025-06-10 07:27

/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
44.8k
{
630
44.8k
    if (pdfi_error != 0)
631
44.8k
        ctx->pdf_errors[pdfi_error / (sizeof(char) * 8)] |= 1 << pdfi_error % (sizeof(char) * 8);
632
44.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
44.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
44.8k
    return 0;
649
44.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
72.4k
{
676
72.4k
    int code, i, j;
677
72.4k
    bool warnings_exist = false, errors_exist = false;
678
679
72.4k
    if (ctx->args.QUIET)
680
72.4k
        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
20.0k
{
777
20.0k
    pdfi_name_entry_t *e = NULL, *last_entry = NULL, *new_entry = NULL;
778
20.0k
    int index = 0;
779
780
20.0k
    if (ctx->name_table == NULL) {
781
1.15k
        e = NULL;
782
18.8k
    } else {
783
18.8k
        e = ctx->name_table;
784
18.8k
    }
785
786
20.0k
    while(e != NULL) {
787
18.8k
        if (e->len == len) {
788
18.8k
            if (memcmp(e->name, name, e->len) == 0) {
789
18.8k
                *returned = e->index;
790
18.8k
                return 0;
791
18.8k
            }
792
18.8k
        }
793
0
        last_entry = e;
794
0
        index = e->index;
795
0
        e = e->next;
796
0
    }
797
798
1.15k
    new_entry = (pdfi_name_entry_t *)gs_alloc_bytes(ctx->memory, sizeof(pdfi_name_entry_t), "Alloc name table entry");
799
1.15k
    if (new_entry == NULL)
800
0
        return_error(gs_error_VMerror);
801
1.15k
    memset(new_entry, 0x00, sizeof(pdfi_name_entry_t));
802
1.15k
    new_entry->name = (char *)gs_alloc_bytes(ctx->memory, len+1, "Alloc name table name");
803
1.15k
    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.15k
    memset(new_entry->name, 0x00, len+1);
808
1.15k
    memcpy(new_entry->name, name, len);
809
1.15k
    new_entry->len = len;
810
1.15k
    new_entry->index = ++index;
811
812
1.15k
    if (last_entry)
813
0
        last_entry->next = new_entry;
814
1.15k
    else
815
1.15k
        ctx->name_table = new_entry;
816
817
1.15k
    *returned = new_entry->index;
818
1.15k
    return 0;
819
1.15k
}
820
821
static int pdfi_free_name_table(pdf_context *ctx)
822
92.4k
{
823
92.4k
    if (ctx->name_table) {
824
1.15k
        pdfi_name_entry_t *next = NULL, *e = (pdfi_name_entry_t *)ctx->name_table;
825
826
2.30k
        while (e != NULL) {
827
1.15k
            next = (pdfi_name_entry_t *)e->next;
828
1.15k
            gs_free_object(ctx->memory, e->name, "free name table entries");
829
1.15k
            gs_free_object(ctx->memory, e, "free name table entries");
830
1.15k
            e = next;
831
1.15k
        }
832
1.15k
    }
833
92.4k
    ctx->name_table = NULL;
834
92.4k
    return 0;
835
92.4k
}
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
4.15k
{
855
4.15k
    pdfi_int_gstate *igs = (pdfi_int_gstate *)pgs->client_data;
856
4.15k
    pdf_context *ctx = NULL;
857
4.15k
    pdfi_name_entry_t *e = NULL;
858
859
4.15k
    if (igs == NULL)
860
0
        return_error(gs_error_undefined);
861
862
4.15k
    ctx = igs->ctx;
863
4.15k
    if (ctx == NULL)
864
0
        return_error(gs_error_undefined);
865
866
4.15k
    e = (pdfi_name_entry_t *)ctx->name_table;
867
868
4.15k
    while (e != NULL) {
869
4.15k
        if (e->index == index) {
870
4.15k
            *name = (unsigned char *)e->name;
871
4.15k
            *len = e->len;
872
4.15k
            return 0;
873
4.15k
        }
874
0
        e = e->next;
875
0
    }
876
877
4.15k
    return_error(gs_error_undefined);
878
4.15k
}
879
880
int pdfi_finish_pdf_file(pdf_context *ctx)
881
72.4k
{
882
72.4k
    if (ctx->Root) {
883
72.4k
        if (ctx->device_state.writepdfmarks && ctx->device_state.WantsOptionalContent) {
884
8.16k
            pdf_obj *o = NULL;
885
8.16k
            int code = 0;
886
887
8.16k
            code = pdfi_dict_knownget_type(ctx, ctx->Root, "OCProperties", PDF_DICT, &o);
888
8.16k
            if (code > 0) {
889
                /* Build and send the OCProperties structure */
890
352
                code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "OCProperties");
891
352
                pdfi_countdown(o);
892
352
                if (code < 0)
893
                    /* Error message ? */
894
79
                ;
895
352
            }
896
8.16k
        }
897
72.4k
    }
898
72.4k
    return 0;
899
72.4k
}
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
92.3k
{
1242
92.3k
    int code = 0;
1243
92.3k
    pdf_obj *o = NULL;
1244
1245
92.3k
    code = pdfi_read_xref(ctx);
1246
92.3k
    if (code < 0) {
1247
8.28k
        if (ctx->is_hybrid) {
1248
4
            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
4
            pdfi_countdown(ctx->xref_table);
1255
4
            ctx->xref_table = NULL;
1256
4
            ctx->prefer_xrefstm = false;
1257
4
            code = pdfi_read_xref(ctx);
1258
4
            if (code < 0)
1259
0
                goto exit;
1260
8.27k
        } else {
1261
8.27k
            pdfi_set_error(ctx, code, NULL, E_PDF_BADXREFSTREAM, "pdfi_init_file", NULL);
1262
8.27k
            goto exit;
1263
8.27k
        }
1264
8.28k
    }
1265
1266
84.0k
    pdfi_device_set_flags(ctx);
1267
1268
84.0k
    if (ctx->Trailer) {
1269
        /* See comment in pdfi_read_Root() (pdf_doc.c) for details */
1270
37.0k
        pdf_dict *d = ctx->Trailer;
1271
1272
37.0k
        pdfi_countup(d);
1273
37.0k
        code = pdfi_dict_get(ctx, d, "Encrypt", &o);
1274
37.0k
        pdfi_countdown(d);
1275
37.0k
        if (code < 0 && code != gs_error_undefined)
1276
41
            goto exit;
1277
37.0k
        if (code == 0) {
1278
1.16k
            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.15k
                code = pdfi_initialise_Decryption(ctx);
1285
1.15k
                if (code < 0)
1286
228
                    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.15k
            } else {
1317
13
                if (pdfi_type_of(o) != PDF_NULL)
1318
9
                    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
13
            }
1321
1.16k
        }
1322
37.0k
    }
1323
1324
84.0k
read_root:
1325
84.0k
    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.02k
            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.02k
            } else {
1347
1.02k
                int code1 = pdfi_repair_file(ctx);
1348
1.02k
                if (code1 < 0)
1349
832
                    goto exit;
1350
195
                goto read_root;
1351
1.02k
            }
1352
1.02k
        }
1353
37.0k
    }
1354
1355
82.9k
    if (ctx->Trailer) {
1356
35.9k
        code = pdfi_read_Info(ctx);
1357
35.9k
        if (code < 0 && code != gs_error_undefined) {
1358
1.10k
            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.10k
            pdfi_clearstack(ctx);
1361
1.10k
        }
1362
35.9k
    }
1363
1364
82.9k
    if (!ctx->Root) {
1365
7.44k
        errprintf(ctx->memory, "Catalog dictionary not located in file, unable to proceed\n");
1366
7.44k
        return_error(gs_error_syntaxerror);
1367
7.44k
    }
1368
1369
75.5k
    code = pdfi_read_Pages(ctx);
1370
75.5k
    if (code < 0)
1371
2.73k
        goto exit;
1372
1373
72.8k
    code = pdfi_doc_page_array_init(ctx);
1374
72.8k
    if (code < 0)
1375
1
        goto exit;
1376
1377
72.8k
    if (ctx->num_pages == 0)
1378
184
        errprintf(ctx->memory, "\n   **** Warning: PDF document has no pages.\n");
1379
1380
72.8k
    code = pdfi_doc_trailer(ctx);
1381
72.8k
    if (code < 0)
1382
0
        goto exit;
1383
1384
72.8k
    pdfi_read_OptionalRoot(ctx);
1385
1386
72.8k
    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
84.9k
exit:
1393
84.9k
    if (code < 0)
1394
12.1k
        pdfi_set_error(ctx, code, NULL, E_PDF_GS_LIB_ERROR, "pdfi_init_file", NULL);
1395
84.9k
    pdfi_countdown(o);
1396
84.9k
    return code;
1397
72.8k
}
1398
1399
int pdfi_set_input_stream(pdf_context *ctx, stream *stm)
1400
92.4k
{
1401
92.4k
    byte *Buffer = NULL;
1402
92.4k
    char *s = NULL, *test = NULL;
1403
92.4k
    float version = 0.0;
1404
92.4k
    gs_offset_t Offset = 0;
1405
92.4k
    int64_t bytes = 0, leftover = 0, bytes_left = 0;
1406
92.4k
    bool found = false;
1407
92.4k
    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
92.4k
    stm->close_at_eod = false;
1413
1414
92.4k
    ctx->main_stream = (pdf_c_stream *)gs_alloc_bytes(ctx->memory, sizeof(pdf_c_stream), "PDF interpreter allocate main PDF stream");
1415
92.4k
    if (ctx->main_stream == NULL)
1416
0
        return_error(gs_error_VMerror);
1417
92.4k
    memset(ctx->main_stream, 0x00, sizeof(pdf_c_stream));
1418
92.4k
    ctx->main_stream->s = stm;
1419
1420
92.4k
    Buffer = gs_alloc_bytes(ctx->memory, BUF_SIZE, "PDF interpreter - allocate working buffer for file validation");
1421
92.4k
    if (Buffer == NULL) {
1422
0
        code = gs_error_VMerror;
1423
0
        goto error;
1424
0
    }
1425
1426
    /* Determine file size */
1427
92.4k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
1428
92.4k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_END);
1429
92.4k
    ctx->main_stream_length = pdfi_tell(ctx->main_stream);
1430
92.4k
    Offset = BUF_SIZE;
1431
92.4k
    bytes = BUF_SIZE;
1432
92.4k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
1433
1434
92.4k
    bytes = Offset = min(BUF_SIZE - 1, ctx->main_stream_length);
1435
1436
92.4k
    if (ctx->args.pdfdebug)
1437
0
        outprintf(ctx->memory, "%% Reading header\n");
1438
1439
92.4k
    bytes = pdfi_read_bytes(ctx, Buffer, 1, Offset, ctx->main_stream);
1440
92.4k
    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
92.4k
    if (bytes < 8) {
1446
64
        errprintf(ctx->memory, "Failed to read enough bytes for a valid PDF header from input stream\n");
1447
64
        code = gs_error_ioerror;
1448
64
        goto error;
1449
64
    }
1450
92.3k
    Buffer[Offset] = 0x00;
1451
1452
    /* First check for existence of header */
1453
92.3k
    test = (char *)Buffer;
1454
92.3k
    bytes_left = bytes;
1455
92.3k
    s = strstr((char *)test, "%PDF-");
1456
92.3k
    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
92.3k
    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
92.3k
    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
92.3k
    } else {
1483
        /* Now extract header version (may be overridden later) */
1484
92.3k
        if (sscanf(s + 5, "%f", &version) != 1) {
1485
3.65k
            ctx->HeaderVersion = 0;
1486
3.65k
            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.65k
        }
1489
88.7k
        else {
1490
88.7k
            ctx->HeaderVersion = version;
1491
88.7k
            s += 5;
1492
373k
            while (((*s >= '0' && *s <= '9') || *s == '.') && *s != 0x00)
1493
284k
                s++;
1494
92.1k
            while (*s != 0x00) {
1495
91.7k
                if (*s == 0x09 || *s== 0x0c || *s == 0x20) {
1496
3.42k
                    s++;
1497
3.42k
                    continue;
1498
3.42k
                }
1499
88.3k
                if (*s != 0x0A && *s != 0x0D) {
1500
4.21k
                    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.21k
                }
1503
88.3k
                break;
1504
88.3k
            }
1505
88.7k
        }
1506
92.3k
        if (ctx->args.pdfdebug)
1507
0
            outprintf(ctx->memory, "%% Found header, PDF version is %f\n", ctx->HeaderVersion);
1508
92.3k
    }
1509
1510
    /* Jump to EOF and scan backwards looking for startxref */
1511
92.3k
    pdfi_seek(ctx, ctx->main_stream, 0, SEEK_END);
1512
1513
92.3k
    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
92.3k
    bytes = Offset;
1518
1519
799k
    do {
1520
799k
        byte *last_lineend = NULL;
1521
799k
        uint32_t read;
1522
1523
799k
        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
799k
        read = pdfi_read_bytes(ctx, Buffer, 1, bytes, ctx->main_stream);
1530
1531
799k
        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
799k
        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
799k
        read = bytes = read + leftover;
1555
1556
        /* Now search backwards in the buffer for the startxref token */
1557
1.52G
        while(read) {
1558
1.52G
            if (memcmp(Buffer + read - 9, "startxref", 9) == 0) {
1559
43.9k
                found = true;
1560
43.9k
                break;
1561
1.52G
            } else {
1562
1.52G
                if (Buffer[read - 1] == 0x0a || Buffer[read - 1] == 0x0d)
1563
24.4M
                    last_lineend = Buffer + read;
1564
1.52G
            }
1565
1.52G
            read--;
1566
1.52G
        }
1567
799k
        if (found) {
1568
43.9k
            byte *b = Buffer + read;
1569
1570
            /* Success! stop now */
1571
43.9k
            if(sscanf((char *)b, " %"PRIdOFFSET"", &ctx->startxref) != 1) {
1572
681
                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
681
            }
1575
43.9k
            break;
1576
755k
        } 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
755k
            if (last_lineend) {
1588
694k
                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
694k
                if (leftover < BUF_SIZE / 2) {
1594
680k
                    memmove(Buffer + bytes - leftover, last_lineend, leftover);
1595
680k
                    bytes -= leftover;
1596
680k
                } else
1597
14.3k
                    leftover = 0;
1598
694k
            } else
1599
60.5k
                leftover = 0;
1600
755k
        }
1601
1602
755k
        Offset += bytes;
1603
755k
    } while(Offset < ctx->main_stream_length);
1604
1605
92.3k
    if (!found) {
1606
48.4k
        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
48.4k
    }
1609
1610
92.3k
    code = pdfi_init_file(ctx);
1611
1612
92.4k
error:
1613
92.4k
    gs_free_object(ctx->memory, Buffer, "PDF interpreter - allocate working buffer for file validation");
1614
92.4k
    return code;
1615
92.3k
}
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
92.4k
{
1789
92.4k
    int i;
1790
1.29M
    for (i = 0; i < ctx->search_paths.num_resource_paths; i++) {
1791
1.20M
        if (ctx->search_paths.resource_paths[i].persistent == false)
1792
1.20M
            gs_free_object(ctx->memory, (byte *)ctx->search_paths.resource_paths[i].data, "path string body");
1793
1.20M
    }
1794
92.4k
    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
92.4k
    gs_free_object(ctx->memory, (byte *)ctx->search_paths.resource_paths, "array of paths");
1799
92.4k
    gs_free_object(ctx->memory, (byte *)ctx->search_paths.font_paths, "array of font paths");
1800
1801
92.4k
    if (ctx->search_paths.genericresourcedir.persistent == false)
1802
92.4k
        gs_free_object(ctx->memory, (byte *)ctx->search_paths.genericresourcedir.data, "generic resource directory");
1803
92.4k
}
1804
1805
static void pdfi_free_fontmapfiles(pdf_context *ctx)
1806
92.4k
{
1807
92.4k
    int i;
1808
92.4k
    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
92.4k
    gs_free_object(ctx->memory, ctx->fontmapfiles, "fontmapfiles array");
1812
92.4k
}
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
92.4k
{
1871
92.4k
    pdf_context *ctx = NULL;
1872
92.4k
    gs_gstate *pgs = NULL;
1873
92.4k
    int code = 0;
1874
92.4k
    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
92.4k
    ctx = (pdf_context *) gs_alloc_bytes(pmem, sizeof(pdf_context), "pdf_create_context");
1884
1885
92.4k
    pgs = gs_gstate_alloc(pmem);
1886
1887
92.4k
    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
92.4k
    memset(ctx, 0, sizeof(pdf_context));
1897
92.4k
    ctx->memory = pmem;
1898
92.4k
    ctx->type = PDF_CTX;
1899
92.4k
    ctx->flags = 0;
1900
92.4k
    ctx->refcnt = 1;
1901
92.4k
    ctx->ctx = ctx;
1902
1903
#if PDFI_LEAK_CHECK
1904
    ctx->memstat = mstat;
1905
#endif
1906
1907
92.4k
    ctx->stack_bot = (pdf_obj **)gs_alloc_bytes(ctx->memory, INITIAL_STACK_SIZE * sizeof (pdf_obj *), "pdf_imp_allocate_interp_stack");
1908
92.4k
    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
92.4k
    ctx->stack_size = INITIAL_STACK_SIZE;
1914
92.4k
    ctx->stack_top = ctx->stack_bot - 1;
1915
92.4k
    code = sizeof(pdf_obj *);
1916
92.4k
    code *= ctx->stack_size;
1917
92.4k
    ctx->stack_limit = ctx->stack_bot + ctx->stack_size;
1918
1919
92.4k
    code = pdfi_init_font_directory(ctx);
1920
92.4k
    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
92.4k
    code = gsicc_init_iccmanager(pgs);
1928
92.4k
    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
92.4k
    ctx->pgs = pgs;
1937
92.4k
    code = pdfi_gstate_set_client(ctx, pgs);
1938
92.4k
    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
92.4k
    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
92.4k
    ctx->pgs->have_pattern_streams = true;
1956
92.4k
    ctx->device_state.preserve_tr_mode = 0;
1957
92.4k
    ctx->args.notransparency = false;
1958
1959
92.4k
    ctx->main_stream = NULL;
1960
1961
    /* Setup some flags that don't default to 'false' */
1962
92.4k
    ctx->args.showannots = true;
1963
92.4k
    ctx->args.preserveannots = true;
1964
92.4k
    ctx->args.preservemarkedcontent = true;
1965
92.4k
    ctx->args.preserveembeddedfiles = true;
1966
92.4k
    ctx->args.preservedocview = true;
1967
    /* NOTE: For testing certain annotations on cluster, might want to set this to false */
1968
92.4k
    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
92.4k
    ctx->prefer_xrefstm = true;
1972
1973
    /* We decrypt strings from encrypted files until we start a page */
1974
92.4k
    ctx->encryption.decrypt_strings = true;
1975
92.4k
    ctx->get_glyph_name = pdfi_glyph_name;
1976
92.4k
    ctx->get_glyph_index = pdfi_glyph_index;
1977
1978
92.4k
    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
92.4k
    code = gs_gsave(ctx->pgs);
1984
92.4k
    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
92.4k
    return ctx;
2004
92.4k
}
2005
2006
/* Purge all */
2007
static bool
2008
pdfi_fontdir_purge_all(const gs_memory_t * mem, cached_char * cc, void *dummy)
2009
1.26M
{
2010
1.26M
    return true;
2011
1.26M
}
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
92.4k
{
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
92.4k
    if (ctx->PathSegments != NULL) {
2091
4.99k
        gs_free_object(ctx->memory, ctx->PathSegments, "pdfi_clear_context");
2092
4.99k
        ctx->PathSegments = NULL;
2093
4.99k
    }
2094
92.4k
    if (ctx->PathPts != NULL) {
2095
4.99k
        gs_free_object(ctx->memory, ctx->PathPts, "pdfi_clear_context");
2096
4.99k
        ctx->PathPts = NULL;
2097
4.99k
    }
2098
2099
92.4k
    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
92.4k
    if (ctx->Trailer) {
2104
37.1k
        pdfi_countdown(ctx->Trailer);
2105
37.1k
        ctx->Trailer = NULL;
2106
37.1k
    }
2107
2108
92.4k
    if (ctx->AcroForm) {
2109
5.99k
        pdfi_countdown(ctx->AcroForm);
2110
5.99k
        ctx->AcroForm = NULL;
2111
5.99k
    }
2112
2113
92.4k
    if(ctx->Root) {
2114
75.7k
        pdfi_countdown(ctx->Root);
2115
75.7k
        ctx->Root = NULL;
2116
75.7k
    }
2117
2118
92.4k
    if (ctx->Info) {
2119
22.2k
        pdfi_countdown(ctx->Info);
2120
22.2k
        ctx->Info = NULL;
2121
22.2k
    }
2122
2123
92.4k
    if (ctx->PagesTree) {
2124
72.2k
        pdfi_countdown(ctx->PagesTree);
2125
72.2k
        ctx->PagesTree = NULL;
2126
72.2k
    }
2127
2128
92.4k
    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
92.4k
    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
92.4k
    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
92.4k
    pdfi_free_cstring_array(ctx, &ctx->args.showannottypes);
2144
92.4k
    pdfi_free_cstring_array(ctx, &ctx->args.preserveannottypes);
2145
2146
92.4k
    pdfi_doc_page_array_free(ctx);
2147
2148
92.4k
    if (ctx->xref_table) {
2149
84.2k
        pdfi_countdown(ctx->xref_table);
2150
84.2k
        ctx->xref_table = NULL;
2151
84.2k
    }
2152
2153
92.4k
    pdfi_free_OptionalRoot(ctx);
2154
2155
92.4k
    if (ctx->stack_bot)
2156
92.4k
        pdfi_clearstack(ctx);
2157
2158
92.4k
    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
92.4k
    if (ctx->main_stream) {
2166
92.4k
        gs_free_object(ctx->memory, ctx->main_stream, "pdfi_clear_context, free main PDF stream");
2167
92.4k
        ctx->main_stream = NULL;
2168
92.4k
    }
2169
92.4k
    ctx->main_stream_length = 0;
2170
2171
92.4k
    if(ctx->pgs != NULL) {
2172
92.4k
        gx_pattern_cache_free(ctx->pgs->pattern_cache);
2173
92.4k
        ctx->pgs->pattern_cache = NULL;
2174
92.4k
        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
184k
        while (ctx->pgs->level != ctx->job_gstate_level && ctx->pgs->saved)
2182
92.4k
            gs_grestore_only(ctx->pgs);
2183
92.4k
    }
2184
2185
92.4k
    pdfi_free_DefaultQState(ctx);
2186
92.4k
    pdfi_oc_free(ctx);
2187
2188
92.4k
    if(ctx->encryption.EKey) {
2189
922
        pdfi_countdown(ctx->encryption.EKey);
2190
922
        ctx->encryption.EKey = NULL;
2191
922
    }
2192
92.4k
    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
92.4k
    if (ctx->cache_entries != 0) {
2198
74.1k
        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.82M
        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
74.1k
#endif
2255
74.1k
        ctx->cache_LRU = ctx->cache_MRU = NULL;
2256
74.1k
        ctx->cache_entries = 0;
2257
74.1k
    }
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
92.4k
    if (ctx->font_dir)
2264
92.4k
        gx_purge_selected_cached_chars(ctx->font_dir, pdfi_fontdir_purge_all, (void *)NULL);
2265
2266
92.4k
    pdfi_countdown(ctx->pdffontmap);
2267
92.4k
    ctx->pdffontmap = NULL;
2268
92.4k
    pdfi_countdown(ctx->pdfnativefontmap);
2269
92.4k
    ctx->pdfnativefontmap = NULL;
2270
92.4k
    pdfi_countdown(ctx->pdf_substitute_fonts);
2271
92.4k
    ctx->pdf_substitute_fonts = NULL;
2272
2273
92.4k
    return 0;
2274
92.4k
}
2275
2276
int pdfi_free_context(pdf_context *ctx)
2277
92.4k
{
2278
#if PDFI_LEAK_CHECK
2279
    gs_memory_status_t mstat, ctxmstat = ctx->memstat;
2280
    gs_memory_t *mem = ctx->memory;
2281
#endif
2282
92.4k
    pdfi_clear_context(ctx);
2283
2284
92.4k
    gs_free_object(ctx->memory, ctx->stack_bot, "pdfi_free_context");
2285
2286
92.4k
    pdfi_free_name_table(ctx);
2287
2288
    /* And here we free the initial graphics state */
2289
92.4k
    while (ctx->pgs->saved)
2290
0
        gs_grestore_only(ctx->pgs);
2291
2292
92.4k
    gs_gstate_free(ctx->pgs);
2293
2294
92.4k
    ctx->pgs = NULL;
2295
2296
92.4k
    if (ctx->font_dir)
2297
92.4k
        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
92.4k
    if (ctx->loop_detection != NULL) {
2303
7
        dbgmprintf(ctx->memory, "Loop detection array exists at EOJ\n");
2304
7
        gs_free_object(ctx->memory, ctx->loop_detection, "pdfi_free_context");
2305
7
    }
2306
2307
92.4k
    pdfi_free_search_paths(ctx);
2308
92.4k
    pdfi_free_fontmapfiles(ctx);
2309
2310
92.4k
    if (ctx->pdfcidfmap != NULL) {
2311
5.93k
        pdfi_countdown(ctx->pdfcidfmap);
2312
5.93k
        ctx->pdfcidfmap = NULL;
2313
5.93k
    }
2314
92.4k
    if (ctx->pdffontmap != NULL) {
2315
0
        pdfi_countdown(ctx->pdffontmap);
2316
0
        ctx->pdffontmap = NULL;
2317
0
    }
2318
92.4k
    rc_decrement(ctx->devbbox, "pdfi_free_context");
2319
2320
92.4k
    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
92.4k
    return 0;
2328
92.4k
}
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
410k
{
2351
410k
    int code;
2352
410k
    i_switch->pgs = ctx->pgs;
2353
410k
    i_switch->procs = pgs->client_procs;
2354
410k
    i_switch->client_data = (void *)pgs->client_data;
2355
410k
    i_switch->profile_cache = pgs->icc_profile_cache;
2356
410k
    code = pdfi_gstate_set_client(ctx, pgs);
2357
410k
    if (code < 0)
2358
0
        return code;
2359
410k
    i_switch->psfont = pgs->font;
2360
410k
    pgs->icc_profile_cache = profile_cache;
2361
410k
    rc_increment(pgs->icc_profile_cache);
2362
410k
    pgs->font = NULL;
2363
410k
    ctx->pgs = pgs;
2364
410k
    return code;
2365
410k
}
2366
2367
void pdfi_gstate_to_PS(pdf_context *ctx, gs_gstate *pgs, pdfi_switch_t *i_switch)
2368
410k
{
2369
410k
    pgs->client_procs.free(pgs->client_data, pgs->memory, pgs);
2370
410k
    pgs->client_data = NULL;
2371
410k
    rc_decrement(pgs->icc_profile_cache, "pdfi_gstate_to_PS");
2372
410k
    pgs->icc_profile_cache = i_switch->profile_cache;
2373
410k
    gs_gstate_set_client(pgs, i_switch->client_data, &i_switch->procs, true);
2374
410k
    ctx->pgs->font = NULL;
2375
410k
    ctx->pgs = i_switch->pgs;
2376
410k
    pgs->font = i_switch->psfont;
2377
410k
}