Coverage Report

Created: 2026-07-24 07:44

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