Coverage Report

Created: 2022-10-31 07:00

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