Coverage Report

Created: 2025-06-10 07:26

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