Coverage Report

Created: 2025-06-10 06:56

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