Coverage Report

Created: 2026-10-28 08:05

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