Coverage Report

Created: 2026-04-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/devices/vector/gdevpdf.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* PDF-writing driver */
18
#include "fcntl_.h"
19
#include "memory_.h"
20
#include "time_.h"
21
#include "unistd_.h"
22
#include "gx.h"
23
#include "gp.h"     /* for gp_get_realtime */
24
#include "gserrors.h"
25
#include "gxdevice.h"
26
#include "gdevpdfx.h"
27
#include "gdevpdfg.h"   /* only for pdf_reset_graphics */
28
#include "gdevpdfo.h"
29
#include "smd5.h"
30
#include "sarc4.h"
31
#include "sbrotlix.h"
32
#include "gscms.h"
33
#include "gdevpdtf.h"
34
#include "gdevpdtx.h"
35
#include "gdevpdtd.h"
36
#include "gdevpdti.h"
37
#include "gsfcmap.h"        /* For gs_cmap_ToUnicode_free */
38
39
#include "gxfcache.h"
40
#include "gdevpdts.h"       /* for sync_text_state */
41
42
#include "gdevpdfo.h"
43
44
/* Define the default language level and PDF compatibility level. */
45
/* Acrobat 8 (PDF 1.7) is the default. (1.7 for ICC V4.2.0 profile support) */
46
#define PSDF_VERSION_INITIAL psdf_version_ll3
47
#define PDF_COMPATIBILITY_LEVEL_INITIAL 1.7
48
49
/* Define the size of internal stream buffers. */
50
/* (This is not a limitation, it only affects performance.) */
51
84.1k
#define sbuf_size 512
52
53
/* GC descriptors */
54
private_st_pdf_page();
55
gs_private_st_element(st_pdf_page_element, pdf_page_t, "pdf_page_t[]",
56
                      pdf_page_elt_enum_ptrs, pdf_page_elt_reloc_ptrs,
57
                      st_pdf_page);
58
private_st_pdf_linearisation_record();
59
gs_private_st_element(st_pdf_linearisation_record_element, pdf_linearisation_record_t, "pdf_linearstion_record_t[]",
60
                      pdf_linearisation_record_elt_enum_ptrs, pdf_linearisation_record_elt_reloc_ptrs,
61
                      st_pdf_linearisation_record);
62
private_st_device_pdfwrite();
63
private_st_pdf_substream_save();
64
private_st_pdf_substream_save_element();
65
66
/* GC procedures */
67
static
68
118M
ENUM_PTRS_WITH(device_pdfwrite_enum_ptrs, gx_device_pdf *pdev)
69
100M
{
70
100M
    index -= gx_device_pdf_num_ptrs + gx_device_pdf_num_param_strings;
71
100M
    if (index < NUM_RESOURCE_TYPES * NUM_RESOURCE_CHAINS)
72
92.1M
        ENUM_RETURN(pdev->resources[index / NUM_RESOURCE_CHAINS].chains[index % NUM_RESOURCE_CHAINS]);
73
8.08M
    index -= NUM_RESOURCE_TYPES * NUM_RESOURCE_CHAINS;
74
8.08M
    if (index <= pdev->outline_depth && pdev->outline_levels)
75
68.4k
        ENUM_RETURN(pdev->outline_levels[index].first.action);
76
8.02M
    index -= pdev->outline_depth + 1;
77
8.02M
    if (index <= pdev->outline_depth && pdev->outline_levels)
78
68.4k
        ENUM_RETURN(pdev->outline_levels[index].last.action);
79
7.95M
    index -= pdev->outline_depth + 1;
80
81
7.95M
    if (index < pdev->PatternDepth) {
82
0
       ENUM_RETURN(pdev->initial_pattern_states[index]);
83
0
    }
84
7.95M
    index -= pdev->PatternDepth;
85
7.95M
    ENUM_PREFIX(st_device_psdf, 0);
86
87
7.95M
}
88
7.95M
 ENUM_PTR(0, gx_device_pdf, asides.strm);
89
7.95M
 ENUM_PTR(1, gx_device_pdf, asides.strm_buf);
90
7.95M
 ENUM_PTR(2, gx_device_pdf, asides.save_strm);
91
7.95M
 ENUM_PTR(3, gx_device_pdf, streams.strm);
92
7.95M
 ENUM_PTR(4, gx_device_pdf, streams.strm_buf);
93
7.95M
 ENUM_PTR(5, gx_device_pdf, ObjStm.strm);
94
7.95M
 ENUM_PTR(6, gx_device_pdf, ObjStm.strm_buf);
95
7.95M
 ENUM_PTR(7, gx_device_pdf, ObjStm.save_strm);
96
7.95M
 ENUM_PTR(8, gx_device_pdf, Catalog);
97
7.95M
 ENUM_PTR(9, gx_device_pdf, Info);
98
7.95M
 ENUM_PTR(10, gx_device_pdf, Pages);
99
7.95M
 ENUM_PTR(11, gx_device_pdf, text);
100
7.95M
 ENUM_PTR(12, gx_device_pdf, pages);
101
7.95M
 ENUM_PTR(13, gx_device_pdf, cs_Patterns[0]);
102
7.95M
 ENUM_PTR(14, gx_device_pdf, cs_Patterns[1]);
103
7.95M
 ENUM_PTR(15, gx_device_pdf, cs_Patterns[3]);
104
7.95M
 ENUM_PTR(16, gx_device_pdf, cs_Patterns[4]);
105
7.95M
 ENUM_PTR(17, gx_device_pdf, last_resource);
106
7.95M
 ENUM_PTR(18, gx_device_pdf, articles);
107
7.95M
 ENUM_PTR(19, gx_device_pdf, Dests);
108
7.95M
 ENUM_PTR(20, gx_device_pdf, global_named_objects);
109
7.95M
 ENUM_PTR(21, gx_device_pdf, local_named_objects);
110
7.95M
 ENUM_PTR(22, gx_device_pdf, NI_stack);
111
7.95M
 ENUM_PTR(23, gx_device_pdf, Namespace_stack);
112
7.95M
 ENUM_PTR(24, gx_device_pdf, font_cache);
113
7.95M
 ENUM_PTR(25, gx_device_pdf, clip_path);
114
7.95M
 ENUM_PTR(26, gx_device_pdf, PageLabels);
115
7.95M
 ENUM_PTR(27, gx_device_pdf, PageLabels_current_label);
116
7.95M
 ENUM_PTR(28, gx_device_pdf, sbstack);
117
7.95M
 ENUM_PTR(29, gx_device_pdf, substream_Resources);
118
7.95M
 ENUM_PTR(30, gx_device_pdf, font3);
119
7.95M
 ENUM_PTR(31, gx_device_pdf, accumulating_substream_resource);
120
7.95M
 ENUM_PTR(32, gx_device_pdf, pres_soft_mask_dict);
121
7.95M
 ENUM_PTR(33, gx_device_pdf, PDFXTrimBoxToMediaBoxOffset.data);
122
7.95M
 ENUM_PTR(34, gx_device_pdf, PDFXBleedBoxToTrimBoxOffset.data);
123
7.95M
 ENUM_PTR(35, gx_device_pdf, Identity_ToUnicode_CMaps[0]);
124
7.95M
 ENUM_PTR(36, gx_device_pdf, Identity_ToUnicode_CMaps[1]);
125
7.95M
 ENUM_PTR(37, gx_device_pdf, vgstack);
126
7.95M
 ENUM_PTR(38, gx_device_pdf, outline_levels);
127
7.95M
 ENUM_PTR(39, gx_device_pdf, EmbeddedFiles);
128
7.95M
 ENUM_PTR(40, gx_device_pdf, AF);
129
7.95M
 ENUM_PTR(41, gx_device_pdf, pdf_font_dir);
130
7.95M
 ENUM_PTR(42, gx_device_pdf, ExtensionMetadata);
131
7.95M
 ENUM_PTR(43, gx_device_pdf, PassThroughWriter);
132
1.80M
#define e1(i,elt) ENUM_PARAM_STRING_PTR(i + gx_device_pdf_num_ptrs, gx_device_pdf, elt);
133
7.95M
gx_device_pdf_do_param_strings(e1)
134
0
#undef e1
135
361k
#define e1(i,elt) ENUM_STRING_PTR(i + gx_device_pdf_num_ptrs + gx_device_pdf_num_param_strings,\
136
361k
                                 gx_device_pdf, elt);
137
118M
gx_device_pdf_do_const_strings(e1)
138
118M
#undef e1
139
118M
ENUM_PTRS_END
140
361k
static RELOC_PTRS_WITH(device_pdfwrite_reloc_ptrs, gx_device_pdf *pdev)
141
361k
{
142
361k
    RELOC_PREFIX(st_device_psdf);
143
361k
 RELOC_PTR(gx_device_pdf, asides.strm);
144
361k
 RELOC_PTR(gx_device_pdf, asides.strm_buf);
145
361k
 RELOC_PTR(gx_device_pdf, asides.save_strm);
146
361k
 RELOC_PTR(gx_device_pdf, streams.strm);
147
361k
 RELOC_PTR(gx_device_pdf, streams.strm_buf);
148
361k
 RELOC_PTR(gx_device_pdf, ObjStm.strm);
149
361k
 RELOC_PTR(gx_device_pdf, ObjStm.strm_buf);
150
361k
 RELOC_PTR(gx_device_pdf, ObjStm.save_strm);
151
361k
 RELOC_PTR(gx_device_pdf, Catalog);
152
361k
 RELOC_PTR(gx_device_pdf, Info);
153
361k
 RELOC_PTR(gx_device_pdf, Pages);
154
361k
 RELOC_PTR(gx_device_pdf, text);
155
361k
 RELOC_PTR(gx_device_pdf, pages);
156
361k
 RELOC_PTR(gx_device_pdf, cs_Patterns[0]);
157
361k
 RELOC_PTR(gx_device_pdf, cs_Patterns[1]);
158
361k
 RELOC_PTR(gx_device_pdf, cs_Patterns[3]);
159
361k
 RELOC_PTR(gx_device_pdf, cs_Patterns[4]);
160
361k
 RELOC_PTR(gx_device_pdf, last_resource);
161
361k
 RELOC_PTR(gx_device_pdf, articles);
162
361k
 RELOC_PTR(gx_device_pdf, Dests);
163
361k
 RELOC_PTR(gx_device_pdf, global_named_objects);
164
361k
 RELOC_PTR(gx_device_pdf, local_named_objects);
165
361k
 RELOC_PTR(gx_device_pdf, NI_stack);
166
361k
 RELOC_PTR(gx_device_pdf, Namespace_stack);
167
361k
 RELOC_PTR(gx_device_pdf, font_cache);
168
361k
 RELOC_PTR(gx_device_pdf, clip_path);
169
361k
 RELOC_PTR(gx_device_pdf, PageLabels);
170
361k
 RELOC_PTR(gx_device_pdf, PageLabels_current_label);
171
361k
 RELOC_PTR(gx_device_pdf, sbstack);
172
361k
 RELOC_PTR(gx_device_pdf, substream_Resources);
173
361k
 RELOC_PTR(gx_device_pdf, font3);
174
361k
 RELOC_PTR(gx_device_pdf, accumulating_substream_resource);
175
361k
 RELOC_PTR(gx_device_pdf, pres_soft_mask_dict);
176
361k
 RELOC_PTR(gx_device_pdf, PDFXTrimBoxToMediaBoxOffset.data);
177
361k
 RELOC_PTR(gx_device_pdf, PDFXBleedBoxToTrimBoxOffset.data);
178
361k
 RELOC_PTR(gx_device_pdf, Identity_ToUnicode_CMaps[0]);
179
361k
 RELOC_PTR(gx_device_pdf, Identity_ToUnicode_CMaps[1]);
180
361k
 RELOC_PTR(gx_device_pdf, vgstack);
181
361k
 RELOC_PTR(gx_device_pdf, EmbeddedFiles);
182
361k
 RELOC_PTR(gx_device_pdf, AF);
183
361k
 RELOC_PTR(gx_device_pdf, pdf_font_dir);
184
361k
 RELOC_PTR(gx_device_pdf, ExtensionMetadata);
185
361k
 RELOC_PTR(gx_device_pdf, PassThroughWriter);
186
1.80M
#define r1(i,elt) RELOC_PARAM_STRING_PTR(gx_device_pdf,elt);
187
1.80M
        gx_device_pdf_do_param_strings(r1)
188
361k
#undef r1
189
361k
#define r1(i,elt) RELOC_CONST_STRING_PTR(gx_device_pdf,elt);
190
361k
        gx_device_pdf_do_const_strings(r1)
191
361k
#undef r1
192
361k
    {
193
361k
        int i, j;
194
195
6.14M
        for (i = 0; i < NUM_RESOURCE_TYPES; ++i)
196
98.3M
            for (j = 0; j < NUM_RESOURCE_CHAINS; ++j)
197
92.5M
                RELOC_PTR(gx_device_pdf, resources[i].chains[j]);
198
361k
        if (pdev->outline_levels) {
199
136k
            for (i = 0; i <= pdev->outline_depth; ++i) {
200
68.4k
                RELOC_PTR(gx_device_pdf, outline_levels[i].first.action);
201
68.4k
                RELOC_PTR(gx_device_pdf, outline_levels[i].last.action);
202
68.4k
            }
203
68.4k
        }
204
361k
        for (i = 0; i < pdev->PatternDepth; i++) {
205
0
            RELOC_PTR(gx_device_pdf, initial_pattern_states[i]);
206
0
        }
207
361k
    }
208
361k
 RELOC_PTR(gx_device_pdf, outline_levels);
209
361k
}
210
361k
RELOC_PTRS_END
211
/* Even though device_pdfwrite_finalize is the same as gx_device_finalize, */
212
/* we need to implement it separately because st_composite_final */
213
/* declares all 3 procedures as private. */
214
static void
215
device_pdfwrite_finalize(const gs_memory_t *cmem, void *vpdev)
216
174k
{
217
174k
    gx_device_finalize(cmem, vpdev);
218
174k
}
219
220
/* Driver procedures */
221
static dev_proc_initialize_device(pdfwrite_initialize_device);
222
static dev_proc_open_device(pdf_open);
223
static dev_proc_output_page(pdf_output_page);
224
static dev_proc_close_device(pdf_close);
225
/* Driver procedures defined in other files are declared in gdevpdfx.h. */
226
227
#ifndef X_DPI
228
#  define X_DPI 720
229
#endif
230
#ifndef Y_DPI
231
#  define Y_DPI 720
232
#endif
233
234
/* ---------------- Device prototype ---------------- */
235
236
static void
237
pdfwrite_initialize_device_procs(gx_device *dev)
238
174k
{
239
174k
    set_dev_proc(dev, initialize_device, pdfwrite_initialize_device);
240
174k
    set_dev_proc(dev, open_device, pdf_open);
241
174k
    set_dev_proc(dev, get_initial_matrix, gx_upright_get_initial_matrix);
242
174k
    set_dev_proc(dev, output_page, pdf_output_page);
243
174k
    set_dev_proc(dev, close_device, pdf_close);
244
174k
    set_dev_proc(dev, map_rgb_color, gx_default_rgb_map_rgb_color);
245
174k
    set_dev_proc(dev, map_color_rgb, gx_default_rgb_map_color_rgb);
246
174k
    set_dev_proc(dev, fill_rectangle, gdev_pdf_fill_rectangle);
247
174k
    set_dev_proc(dev, copy_mono, gdev_pdf_copy_mono);
248
174k
    set_dev_proc(dev, copy_color, gdev_pdf_copy_color);
249
174k
    set_dev_proc(dev, get_params, gdev_pdf_get_params);
250
174k
    set_dev_proc(dev, put_params, gdev_pdf_put_params);
251
174k
    set_dev_proc(dev, get_page_device, gx_page_device_get_page_device);
252
174k
    set_dev_proc(dev, fill_path, gdev_pdf_fill_path);
253
174k
    set_dev_proc(dev, stroke_path, gdev_pdf_stroke_path);
254
174k
    set_dev_proc(dev, fill_mask, gdev_pdf_fill_mask);
255
174k
    set_dev_proc(dev, strip_tile_rectangle, gdev_pdf_strip_tile_rectangle);
256
174k
    set_dev_proc(dev, begin_typed_image, gdev_pdf_begin_typed_image);
257
174k
    set_dev_proc(dev, get_bits_rectangle, psdf_get_bits_rectangle);
258
174k
    set_dev_proc(dev, composite, gdev_pdf_composite);
259
174k
    set_dev_proc(dev, text_begin, gdev_pdf_text_begin);
260
174k
    set_dev_proc(dev, begin_transparency_group, gdev_pdf_begin_transparency_group);
261
174k
    set_dev_proc(dev, end_transparency_group, gdev_pdf_end_transparency_group);
262
174k
    set_dev_proc(dev, begin_transparency_mask ,gdev_pdf_begin_transparency_mask);
263
174k
    set_dev_proc(dev, end_transparency_mask, gdev_pdf_end_transparency_mask);
264
174k
    set_dev_proc(dev, fill_rectangle_hl_color, gdev_pdf_fill_rectangle_hl_color);
265
174k
    set_dev_proc(dev, include_color_space, gdev_pdf_include_color_space);
266
174k
    set_dev_proc(dev, fillpage, gdev_pdf_fillpage);
267
174k
    set_dev_proc(dev, dev_spec_op, gdev_pdf_dev_spec_op);
268
174k
    set_dev_proc(dev, fill_stroke_path, gdev_pdf_fill_stroke_path);
269
174k
}
270
271
#define PDF_DEVICE_NAME "pdfwrite"
272
#define PDF_DEVICE_IDENT gs_pdfwrite_device
273
#define PDF_DEVICE_MaxInlineImageSize 4000
274
#define PDF_FOR_OPDFREAD 0
275
#define PDF_FOR_EPS2WRITE 0
276
277
#include "gdevpdfb.h"
278
279
#undef PDF_DEVICE_NAME
280
#undef PDF_DEVICE_IDENT
281
#undef PDF_DEVICE_MaxInlineImageSize
282
#undef PDF_FOR_OPDFREAD
283
284
#define PDF_DEVICE_NAME "ps2write"
285
#define PDF_DEVICE_IDENT gs_ps2write_device
286
#define PDF_DEVICE_MaxInlineImageSize max_long
287
#define PDF_FOR_OPDFREAD 1
288
#define PDF_FOR_EPS2WRITE 0
289
290
#include "gdevpdfb.h"
291
292
#undef PDF_DEVICE_NAME
293
#undef PDF_DEVICE_IDENT
294
#undef PDF_DEVICE_MaxInlineImageSize
295
#undef PDF_FOR_OPDFREAD
296
#undef PDF_FOR_EPS2WRITE
297
298
#define PDF_DEVICE_NAME "eps2write"
299
#define PDF_DEVICE_IDENT gs_eps2write_device
300
#define PDF_DEVICE_MaxInlineImageSize max_long
301
#define PDF_FOR_OPDFREAD 1
302
#define PDF_FOR_EPS2WRITE 1
303
304
#include "gdevpdfb.h"
305
306
#undef PDF_DEVICE_NAME
307
#undef PDF_DEVICE_IDENT
308
#undef PDF_DEVICE_MaxInlineImageSize
309
#undef PDF_FOR_OPDFREAD
310
#undef PDF_FOR_EPS2WRITE
311
/* ---------------- Device open/close ---------------- */
312
313
/* Close and remove temporary files. */
314
int
315
pdf_close_temp_file(gx_device_pdf *pdev, pdf_temp_file_t *ptf, int code)
316
149k
{
317
149k
    int err = 0;
318
149k
    gp_file *file = ptf->file;
319
320
    /*
321
     * ptf->strm == 0 or ptf->file == 0 is only possible if this procedure
322
     * is called to clean up during initialization failure, but ptf->strm
323
     * might not be open if it was finalized before the device was closed.
324
     */
325
149k
    if (ptf->strm) {
326
84.1k
        if (s_is_valid(ptf->strm)) {
327
84.1k
            sflush(ptf->strm);
328
            /* Prevent freeing the stream from closing the file. */
329
84.1k
            ptf->strm->file = 0;
330
84.1k
        } else
331
0
            ptf->file = file = 0; /* file was closed by finalization */
332
84.1k
        gs_free_object(pdev->pdf_memory, ptf->strm_buf,
333
84.1k
                       "pdf_close_temp_file(strm_buf)");
334
84.1k
        ptf->strm_buf = 0;
335
84.1k
        gs_free_object(pdev->pdf_memory, ptf->strm,
336
84.1k
                       "pdf_close_temp_file(strm)");
337
84.1k
        ptf->strm = 0;
338
84.1k
    }
339
149k
    if (file) {
340
117k
        err = gp_ferror(file) | gp_fclose(file);
341
117k
        gp_unlink(pdev->memory, ptf->file_name);
342
117k
        ptf->file = 0;
343
117k
    }
344
149k
    ptf->save_strm = 0;
345
149k
    return
346
149k
        (code < 0 ? code : err != 0 ? gs_note_error(gs_error_ioerror) : code);
347
149k
}
348
static int
349
pdf_close_files(gx_device_pdf * pdev, int code)
350
32.9k
{
351
32.9k
    code = pdf_close_temp_file(pdev, &pdev->ObjStm, code);
352
32.9k
    code = pdf_close_temp_file(pdev, &pdev->streams, code);
353
32.9k
    code = pdf_close_temp_file(pdev, &pdev->asides, code);
354
32.9k
    return pdf_close_temp_file(pdev, &pdev->xref, code);
355
32.9k
}
356
357
/* Reset the state of the current page. */
358
static void
359
pdf_reset_page(gx_device_pdf * pdev)
360
75.5k
{
361
75.5k
    pdev->page_dsc_info = gs_pdfwrite_device.page_dsc_info;
362
75.5k
    pdev->contents_id = 0;
363
75.5k
    pdf_reset_graphics(pdev);
364
75.5k
    pdev->procsets = NoMarks;
365
75.5k
    memset(pdev->cs_Patterns, 0, sizeof(pdev->cs_Patterns));  /* simplest to create for each page */
366
75.5k
    pdf_reset_text_page(pdev->text);
367
75.5k
    pdf_remember_clip_path(pdev, 0);
368
75.5k
    pdev->clip_path_id = pdev->no_clip_path_id;
369
75.5k
}
370
371
/* Open a temporary file, with or without a stream. */
372
int
373
pdf_open_temp_file(gx_device_pdf *pdev, pdf_temp_file_t *ptf)
374
117k
{
375
117k
    char fmode[4];
376
377
117k
    if (strlen(gp_fmode_binary_suffix) > 2)
378
0
        return_error(gs_error_invalidfileaccess);
379
380
117k
    strcpy(fmode, "w+");
381
117k
    strcat(fmode, gp_fmode_binary_suffix);
382
117k
    ptf->file = gp_open_scratch_file(pdev->memory,
383
117k
                                     gp_scratch_file_name_prefix,
384
117k
                                     ptf->file_name,
385
117k
                                     fmode);
386
117k
    if (ptf->file == 0)
387
0
        return_error(gs_error_invalidfileaccess);
388
117k
    return 0;
389
117k
}
390
int
391
pdf_open_temp_stream(gx_device_pdf *pdev, pdf_temp_file_t *ptf)
392
84.1k
{
393
84.1k
    int code = pdf_open_temp_file(pdev, ptf);
394
395
84.1k
    if (code < 0)
396
0
        return code;
397
84.1k
    ptf->strm = s_alloc(pdev->pdf_memory, "pdf_open_temp_stream(strm)");
398
84.1k
    if (ptf->strm == 0)
399
0
        return_error(gs_error_VMerror);
400
84.1k
    ptf->strm_buf = gs_alloc_bytes(pdev->pdf_memory, sbuf_size,
401
84.1k
                                   "pdf_open_temp_stream(strm_buf)");
402
84.1k
    if (ptf->strm_buf == 0) {
403
0
        gs_free_object(pdev->pdf_memory, ptf->strm,
404
0
                       "pdf_open_temp_stream(strm)");
405
0
        ptf->strm = 0;
406
0
        return_error(gs_error_VMerror);
407
0
    }
408
84.1k
    swrite_file(ptf->strm, ptf->file, ptf->strm_buf, sbuf_size);
409
84.1k
    return 0;
410
84.1k
}
411
412
/* Initialize the IDs allocated at startup. */
413
void
414
pdf_initialize_ids(gx_device_pdf * pdev)
415
32.9k
{
416
32.9k
    gs_param_string nstr;
417
418
32.9k
    pdev->next_id = pdev->FirstObjectNumber;
419
420
    /* Initialize the Catalog. */
421
422
32.9k
    param_string_from_string(nstr, "{Catalog}");
423
32.9k
    pdf_create_named_dict(pdev, &nstr, &pdev->Catalog, 0L);
424
425
    /* Initialize the Info dictionary. */
426
427
32.9k
    param_string_from_string(nstr, "{DocInfo}");
428
32.9k
    pdf_create_named_dict(pdev, &nstr, &pdev->Info, 0L);
429
32.9k
    {
430
32.9k
        char buf[PDF_MAX_PRODUCER];
431
432
        /* This comment, the delimiting comments below, and the lines of
433
         * source code between the delimiting comments may not be altered,
434
         * replaced, changed, or otherwise modified for the purpose of
435
         * misrepresenting the origin of works generated using this
436
         * software.
437
         *
438
         * The supplemental term above has been added in accordance with
439
         * Section 7(b) of the Affero General Public License version 3.
440
         */
441
442
        /*  BEGIN -- CHANGES RESTRICTED UNDER 7(b) */
443
32.9k
        pdf_store_default_Producer(buf);
444
32.9k
        cos_dict_put_c_key_string(pdev->Info, "/Producer", (byte *)buf,
445
32.9k
                                  strlen(buf));
446
        /*  END -- CHANGES RESTRICTED UNDER 7(b) */
447
32.9k
    }
448
    /*
449
     * Acrobat Distiller sets CreationDate and ModDate to the current
450
     * date and time, rather than (for example) %%CreationDate from the
451
     * PostScript file.  We think this is wrong, but we do the same.
452
     */
453
32.9k
    if (!pdev->OmitInfoDate)
454
32.9k
    {
455
32.9k
        struct tm tms;
456
32.9k
        time_t t;
457
32.9k
        char buf[1+2+4+2+2+2+2+2+1+2+1+2+1+1+1]; /* (D:yyyymmddhhmmssZhh'mm')\0 */
458
32.9k
        int timeoffset;
459
32.9k
        char timesign;
460
461
#ifdef CLUSTER
462
        memset(&t, 0, sizeof(t));
463
        memset(&tms, 0, sizeof(tms));
464
        timesign = 'Z';
465
        timeoffset = 0;
466
#else
467
32.9k
        time(&t);
468
32.9k
        tms = *gmtime(&t);
469
32.9k
        tms.tm_isdst = -1;
470
32.9k
        timeoffset = (int)difftime(t, mktime(&tms)); /* tz+dst in seconds */
471
32.9k
        timesign = (timeoffset == 0 ? 'Z' : timeoffset < 0 ? '-' : '+');
472
32.9k
        timeoffset = any_abs(timeoffset) / 60;
473
32.9k
        tms = *localtime(&t);
474
32.9k
#endif
475
476
32.9k
        gs_snprintf(buf, sizeof(buf), "(D:%04d%02d%02d%02d%02d%02d%c%02d\'%02d\')",
477
32.9k
            tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
478
32.9k
            tms.tm_hour, tms.tm_min, tms.tm_sec,
479
32.9k
            timesign, timeoffset / 60, timeoffset % 60);
480
481
32.9k
        cos_dict_put_c_key_string(pdev->Info, "/CreationDate", (byte *)buf,
482
32.9k
                                  strlen(buf));
483
32.9k
        cos_dict_put_c_key_string(pdev->Info, "/ModDate", (byte *)buf,
484
32.9k
                                  strlen(buf));
485
32.9k
    }
486
487
    /* Allocate the root of the pages tree. */
488
489
32.9k
    pdf_create_named_dict(pdev, NULL, &pdev->Pages, 0L);
490
32.9k
}
491
492
static int
493
pdf_compute_fileID(gx_device_pdf * pdev)
494
32.9k
{
495
496
    /* We compute a file identifier when beginning a document
497
       to allow its usage with PDF encryption. Due to that,
498
       in contradiction to the Adobe recommendation, our
499
       ID doesn't depend on the document size.
500
    */
501
32.9k
    gs_memory_t *mem = pdev->pdf_memory;
502
32.9k
    stream *strm = pdev->strm;
503
32.9k
    uint ignore;
504
32.9k
    int code;
505
32.9k
    stream *s = s_MD5E_make_stream(mem, pdev->fileID, sizeof(pdev->fileID));
506
32.9k
    long secs_ns[2];
507
32.9k
    uint KeyLength = pdev->KeyLength;
508
509
32.9k
    if (s == NULL)
510
0
        return_error(gs_error_VMerror);
511
32.9k
    pdev->KeyLength = 0; /* Disable encryption. Not so important though. */
512
#ifdef CLUSTER
513
    secs_ns[0] = 0;
514
    secs_ns[1] = 0;
515
#else
516
32.9k
    gp_get_realtime(secs_ns);
517
32.9k
#endif
518
32.9k
    sputs(s, (byte *)secs_ns, sizeof(secs_ns), &ignore);
519
#ifdef CLUSTER
520
    /* Don't have the ID's vary by filename output in the cluster testing.
521
     * This prevents us comparing gs to gpdl results, and makes it harder
522
     * to manually reproduce results. */
523
    sputs(s, (const byte *)"ClusterTest.pdf", strlen("ClusterTest.pdf"), &ignore);
524
#else
525
32.9k
    sputs(s, (const byte *)pdev->fname, strlen(pdev->fname), &ignore);
526
32.9k
#endif
527
32.9k
    pdev->strm = s;
528
32.9k
    code = cos_dict_elements_write(pdev->Info, pdev);
529
32.9k
    pdev->strm = strm;
530
32.9k
    pdev->KeyLength = KeyLength;
531
32.9k
    if (code < 0)
532
0
        return code;
533
    /* Generally we would call s_close_filters() here in order to free the data buffer
534
     * associated with the MD5 filter, but the data buffer we passed in to s_MD5E_make_stream()
535
     * is part of the device structure, so we must *NOT* free that buffer. Therefore we must
536
     * instead call sclose(). This confusion over ownership of the stream buffers causes
537
     * a lot of problems......
538
     */
539
32.9k
    sclose(s);
540
32.9k
    gs_free_object(mem, s, "pdf_compute_fileID");
541
32.9k
    return 0;
542
32.9k
}
543
544
static const byte pad[32] = { 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
545
                               0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
546
                               0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
547
                               0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A};
548
549
static inline void
550
copy_padded(byte buf[32], gs_param_string *str)
551
0
{
552
0
    memcpy(buf, str->data, min(str->size, 32));
553
0
    if (32 > str->size)
554
0
        memcpy(buf + str->size, pad, 32 - str->size);
555
0
}
556
557
static void
558
Adobe_magic_loop_50(byte digest[16], int key_length)
559
0
{
560
0
    gs_md5_state_t md5;
561
0
    int i;
562
563
0
    for (i = 0; i < 50; i++) {
564
0
        gs_md5_init(&md5);
565
0
        gs_md5_append(&md5, digest, key_length);
566
0
        gs_md5_finish(&md5, digest);
567
0
    }
568
0
}
569
570
static void
571
Adobe_magic_loop_19(byte *data, int data_size, const byte *key, int key_size)
572
0
{
573
0
    stream_arcfour_state sarc4;
574
0
    byte key_buf[16];
575
0
    int i, j;
576
577
0
    for (i = 1; i <= 19; i++) {
578
0
        for (j = 0; j < key_size; j++)
579
0
            key_buf[j] = key[j] ^ (byte)i;
580
0
        s_arcfour_set_key(&sarc4, key_buf, key_size);
581
0
        s_arcfour_process_buffer(&sarc4, data, data_size);
582
0
    }
583
0
}
584
585
static int
586
pdf_compute_encryption_data(gx_device_pdf * pdev)
587
0
{
588
0
    gs_md5_state_t md5;
589
0
    byte digest[16], buf[32], t;
590
0
    stream_arcfour_state sarc4;
591
592
0
    if (pdev->PDFX > 1 && pdev->KeyLength != 0) {
593
0
        emprintf(pdev->memory,
594
0
                 "Encryption is not allowed in a PDF/X-3 doucment.\n");
595
0
        return_error(gs_error_rangecheck);
596
0
    }
597
0
    if (pdev->KeyLength == 0)
598
0
        pdev->KeyLength = 40;
599
0
    if (pdev->EncryptionV == 0 && pdev->KeyLength == 40)
600
0
        pdev->EncryptionV = 1;
601
0
    if (pdev->EncryptionV == 0 && pdev->KeyLength > 40)
602
0
        pdev->EncryptionV = 2;
603
0
    if (pdev->EncryptionV > 1 && pdev->CompatibilityLevel < 1.4) {
604
0
        emprintf(pdev->memory, "PDF 1.3 only supports 40 bits keys.\n");
605
0
        return_error(gs_error_rangecheck);
606
0
    }
607
0
    if (pdev->EncryptionR == 0)
608
0
        pdev->EncryptionR = 2;
609
0
    if (pdev->EncryptionR < 2 || pdev->EncryptionR > 3) {
610
0
        emprintf(pdev->memory,
611
0
                 "Encryption revisions 2 and 3 are only supported.\n");
612
0
        return_error(gs_error_rangecheck);
613
0
    }
614
0
    if (pdev->EncryptionR > 2 && pdev->CompatibilityLevel < 1.4) {
615
0
        emprintf(pdev->memory,
616
0
                 "PDF 1.3 only supports the encryption revision 2.\n");
617
0
        return_error(gs_error_rangecheck);
618
0
    }
619
0
    if (pdev->KeyLength > 128) {
620
0
        emprintf(pdev->memory,
621
0
                 "The maximal length of PDF encryption key is 128 bits.\n");
622
0
        return_error(gs_error_rangecheck);
623
0
    }
624
0
    if (pdev->KeyLength % 8) {
625
0
        emprintf(pdev->memory,
626
0
                 "PDF encryption key length must be a multiple of 8.\n");
627
0
        return_error(gs_error_rangecheck);
628
0
    }
629
0
    if (pdev->EncryptionR == 2 &&
630
0
        ((pdev->Permissions & (0xFFFFFFC3)) != 0xFFFFFFC0)) {
631
0
        emprintf(pdev->memory,
632
0
                 "Some of Permissions are not allowed with R=2.\n");
633
0
        return_error(gs_error_rangecheck);
634
0
    }
635
0
    if (pdev->EncryptionV == 2 && pdev->EncryptionR == 2 && pdev->KeyLength > 40) {
636
0
        emprintf(pdev->memory, "Encryption version 2 revision 2 with "
637
0
                 "KeyLength > 40 appears incompatible to some viewers. With "
638
0
                 "long keys use revision 3.\n");
639
0
        return_error(gs_error_rangecheck);
640
0
    }
641
    /* Compute O : */
642
0
    gs_md5_init(&md5);
643
0
    copy_padded(buf, &pdev->OwnerPassword);
644
0
    gs_md5_append(&md5, buf, sizeof(buf));
645
0
    gs_md5_finish(&md5, digest);
646
0
    if (pdev->EncryptionR == 3)
647
0
        Adobe_magic_loop_50(digest, pdev->KeyLength / 8);
648
0
    copy_padded(buf, &pdev->UserPassword);
649
0
    s_arcfour_set_key(&sarc4, digest, pdev->KeyLength / 8);
650
0
    s_arcfour_process_buffer(&sarc4, buf, sizeof(buf));
651
0
    if (pdev->EncryptionR == 3)
652
0
        Adobe_magic_loop_19(buf, sizeof(buf), digest, pdev->KeyLength / 8);
653
0
    memcpy(pdev->EncryptionO, buf, sizeof(pdev->EncryptionO));
654
    /* Compute Key : */
655
0
    gs_md5_init(&md5);
656
0
    copy_padded(buf, &pdev->UserPassword);
657
0
    gs_md5_append(&md5, buf, sizeof(buf));
658
0
    gs_md5_append(&md5, pdev->EncryptionO, sizeof(pdev->EncryptionO));
659
0
    t = (byte)(pdev->Permissions >>  0);  gs_md5_append(&md5, &t, 1);
660
0
    t = (byte)(pdev->Permissions >>  8);  gs_md5_append(&md5, &t, 1);
661
0
    t = (byte)(pdev->Permissions >> 16);  gs_md5_append(&md5, &t, 1);
662
0
    t = (byte)(pdev->Permissions >> 24);  gs_md5_append(&md5, &t, 1);
663
0
    gs_md5_append(&md5, pdev->fileID, sizeof(pdev->fileID));
664
0
    if (pdev->EncryptionR == 3)
665
0
        if (!pdev->EncryptMetadata) {
666
0
            const byte v[4] = {0xFF, 0xFF, 0xFF, 0xFF};
667
668
0
            gs_md5_append(&md5, v, 4);
669
0
        }
670
0
    gs_md5_finish(&md5, digest);
671
0
    if (pdev->EncryptionR == 3)
672
0
        Adobe_magic_loop_50(digest, pdev->KeyLength / 8);
673
0
    memcpy(pdev->EncryptionKey, digest, pdev->KeyLength / 8);
674
    /* Compute U : */
675
0
    if (pdev->EncryptionR == 3) {
676
0
        gs_md5_init(&md5);
677
0
        gs_md5_append(&md5, pad, sizeof(pad));
678
0
        gs_md5_append(&md5, pdev->fileID, sizeof(pdev->fileID));
679
0
        gs_md5_finish(&md5, digest);
680
0
        s_arcfour_set_key(&sarc4, pdev->EncryptionKey, pdev->KeyLength / 8);
681
0
        s_arcfour_process_buffer(&sarc4, digest, sizeof(digest));
682
0
        Adobe_magic_loop_19(digest, sizeof(digest), pdev->EncryptionKey, pdev->KeyLength / 8);
683
0
        memcpy(pdev->EncryptionU, digest, sizeof(digest));
684
0
        memcpy(pdev->EncryptionU + sizeof(digest), pad,
685
0
                sizeof(pdev->EncryptionU) - sizeof(digest));
686
0
    } else {
687
0
        memcpy(pdev->EncryptionU, pad, sizeof(pdev->EncryptionU));
688
0
        s_arcfour_set_key(&sarc4, pdev->EncryptionKey, pdev->KeyLength / 8);
689
0
        s_arcfour_process_buffer(&sarc4, pdev->EncryptionU, sizeof(pdev->EncryptionU));
690
0
    }
691
0
    return 0;
692
0
}
693
694
#ifdef __DECC
695
/* The ansi alias rules are violated in this next routine.  Tell the compiler
696
   to ignore this.
697
 */
698
#pragma optimize save
699
#pragma optimize ansi_alias=off
700
#endif
701
/*
702
 * Update the color mapping procedures after setting ProcessColorModel.
703
 *
704
 * The 'index' value indicates the ProcessColorModel.
705
 *  0 = DeviceGray
706
 *  1 = DeviceRGB
707
 *  2 = DeviceCMYK
708
 *  3 = DeviceN (treat like CMYK except for color model name)
709
 */
710
void
711
pdf_set_process_color_model(gx_device_pdf * pdev, int index)
712
19.7k
{
713
19.7k
    const static gx_device_color_info pcm_color_info[] = {
714
19.7k
        dci_values(1, 8, 255, 0, 256, 0),   /* Gray */
715
19.7k
        dci_values(3, 24, 255, 255, 256, 256),    /* RGB */
716
19.7k
        dci_values(4, 32, 255, 255, 256, 256),    /* CMYK */
717
19.7k
        dci_values(4, 32, 255, 255, 256, 256) /* Treat DeviceN like CMYK */
718
19.7k
    };
719
    /* Don't blow away the ICC information */
720
721
19.7k
    pdev->pcm_color_info_index = index;
722
19.7k
    pdev->color_info = pcm_color_info[index];
723
    /* Set the separable and linear shift, masks, bits. */
724
19.7k
    set_linear_color_bits_mask_shift((gx_device *)pdev);
725
19.7k
    pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
726
    /*
727
     * The conversion from PS to PDF should be transparent as possible.
728
     * Particularly it should not change representation of colors.
729
     * Perhaps due to historical reasons the source color information
730
     * sometimes isn't accessible from device methods, and
731
     * therefore they perform a mapping of colors to
732
     * an output color model. Here we handle some color models,
733
     * which were selected almost due to antique reasons.
734
     */
735
19.7k
    switch (index) {
736
0
        case 0:   /* DeviceGray */
737
0
            set_dev_proc(pdev, map_rgb_color, gx_default_gray_map_rgb_color);
738
0
            set_dev_proc(pdev, map_color_rgb, gx_default_gray_map_color_rgb);
739
0
            set_dev_proc(pdev, map_cmyk_color, NULL);
740
0
            set_dev_proc(pdev, get_color_mapping_procs,
741
0
                        gx_default_DevGray_get_color_mapping_procs);
742
0
            set_dev_proc(pdev, get_color_comp_index,
743
0
                        gx_default_DevGray_get_color_comp_index);
744
0
            set_dev_proc(pdev, encode_color, gx_default_gray_encode);
745
0
            set_dev_proc(pdev, decode_color, gx_default_decode_color);
746
0
            break;
747
19.7k
        case 1:   /* DeviceRGB */
748
19.7k
            set_dev_proc(pdev, map_rgb_color, gx_default_rgb_map_rgb_color);
749
19.7k
            set_dev_proc(pdev, map_color_rgb, gx_default_rgb_map_color_rgb);
750
19.7k
            set_dev_proc(pdev, map_cmyk_color, NULL);
751
19.7k
            set_dev_proc(pdev, get_color_mapping_procs,
752
19.7k
                        gx_default_DevRGB_get_color_mapping_procs);
753
19.7k
            set_dev_proc(pdev, get_color_comp_index,
754
19.7k
                        gx_default_DevRGB_get_color_comp_index);
755
19.7k
            set_dev_proc(pdev, encode_color, gx_default_rgb_map_rgb_color);
756
19.7k
            set_dev_proc(pdev, decode_color, gx_default_rgb_map_color_rgb);
757
19.7k
            break;
758
0
        case 3:   /* DeviceN - treat like DeviceCMYK except for cm_name */
759
0
            pdev->color_info.cm_name = "DeviceN";
760
0
        case 2:   /* DeviceCMYK */
761
0
            set_dev_proc(pdev, map_rgb_color, NULL);
762
0
            set_dev_proc(pdev, map_color_rgb, cmyk_8bit_map_color_rgb);
763
           /* possible problems with aliassing on next statement */
764
0
            set_dev_proc(pdev, map_cmyk_color, cmyk_8bit_map_cmyk_color);
765
0
            set_dev_proc(pdev, get_color_mapping_procs,
766
0
                        gx_default_DevCMYK_get_color_mapping_procs);
767
0
            set_dev_proc(pdev, get_color_comp_index,
768
0
                        gx_default_DevCMYK_get_color_comp_index);
769
0
            set_dev_proc(pdev, encode_color, cmyk_8bit_map_cmyk_color);
770
0
            set_dev_proc(pdev, decode_color, cmyk_8bit_map_color_cmyk);
771
0
            break;
772
0
        default:  /* can't happen - see the call from gdev_pdf_put_params. */
773
0
            DO_NOTHING;
774
19.7k
    }
775
19.7k
}
776
#ifdef __DECC
777
#pragma optimize restore
778
#endif
779
780
/*
781
 * Reset the text state parameters to initial values.
782
 */
783
void
784
pdf_reset_text(gx_device_pdf * pdev)
785
383k
{
786
    /* we need to flush the text buffer, in case we have (eg) Tr set,
787
     * but have reset it to 0 for the current (buffered) text. If we restore to a
788
     * graphics state which also has Tr 0 then we won't ever write out the change.
789
     * I suspect this can theoretically happen with other graphics state values too
790
     * See PCL file enter.test.
791
     */
792
383k
    sync_text_state(pdev);
793
383k
    pdf_reset_text_state(pdev->text);
794
383k
}
795
796
static int
797
pdfwrite_initialize_device(gx_device *dev)
798
174k
{
799
#if OCR_VERSION > 0
800
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
801
    const char *default_ocr_lang = "eng";
802
    pdev->ocr_language[0] = '\0';
803
    strcpy(pdev->ocr_language, default_ocr_lang);
804
#endif
805
174k
    return 0;
806
174k
}
807
808
809
/* Open the device. */
810
static int
811
pdf_open(gx_device * dev)
812
32.9k
{
813
32.9k
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
814
32.9k
    gs_memory_t *mem = pdev->pdf_memory = gs_memory_stable(pdev->memory);
815
32.9k
    int code;
816
817
32.9k
    pdev->InOutputPage = false;
818
819
32.9k
    if ((code = pdf_open_temp_file(pdev, &pdev->xref)) < 0 ||
820
32.9k
        (code = pdf_open_temp_stream(pdev, &pdev->asides)) < 0 ||
821
32.9k
        (code = pdf_open_temp_stream(pdev, &pdev->streams))
822
32.9k
        )
823
0
        goto fail;
824
32.9k
    code = gdev_vector_open_file((gx_device_vector *) pdev, sbuf_size);
825
32.9k
    if (code < 0)
826
0
        goto fail;
827
32.9k
    while (pdev->child) {
828
        /* we've been subclassed by gdev_vector_open_file. Ordinarily we would want to call
829
         * open_file last, in order to make sure that we don't care if we are subclessed
830
         * but we want to set up the stream, so we can't do that....
831
         */
832
0
        pdev = (gx_device_pdf *)pdev->child;
833
0
    }
834
32.9k
    if (pdev->ComputeDocumentDigest) {
835
32.9k
        stream *s = s_MD5C_make_stream(pdev->pdf_memory, pdev->strm);
836
837
32.9k
        if (s == NULL)
838
0
            return_error(gs_error_VMerror);
839
32.9k
        pdev->strm = s;
840
32.9k
    }
841
32.9k
    gdev_vector_init((gx_device_vector *) pdev);
842
#ifdef CLUSTER
843
    memset(&pdev->uuid_time, 0, sizeof(pdev->uuid_time));
844
#else
845
32.9k
    gp_get_realtime(pdev->uuid_time);
846
32.9k
#endif
847
32.9k
    pdev->vec_procs = &pdf_vector_procs;
848
32.9k
    pdev->fill_options = pdev->stroke_options = gx_path_type_optimize;
849
    /* Set in_page so the vector routines won't try to call */
850
    /* any vector implementation procedures. */
851
32.9k
    pdev->in_page = true;
852
    /*
853
     * pdf_initialize_ids allocates some (global) named objects, so we must
854
     * initialize the named objects dictionary now.
855
     */
856
32.9k
    pdev->local_named_objects =
857
32.9k
        pdev->global_named_objects =
858
32.9k
        cos_dict_alloc(pdev, "pdf_open(global_named_objects)");
859
32.9k
    if (pdev->local_named_objects == NULL) {
860
0
        code = gs_error_VMerror;
861
0
        goto fail;
862
0
    }
863
    /* Initialize internal structures that don't have IDs. */
864
32.9k
    pdev->NI_stack = cos_array_alloc(pdev, "pdf_open(NI stack)");
865
32.9k
    if (pdev->NI_stack == NULL) {
866
0
        code = gs_error_VMerror;
867
0
        goto fail;
868
0
    }
869
32.9k
    pdev->vgstack = (pdf_viewer_state *)gs_alloc_bytes(pdev->pdf_memory, 11 * sizeof(pdf_viewer_state), "pdf_open(graphics state stack)");
870
32.9k
    if (pdev->vgstack == 0) {
871
0
        code = gs_error_VMerror;
872
0
        goto fail;
873
0
    }
874
32.9k
    memset(pdev->vgstack, 0x00, 11 * sizeof(pdf_viewer_state));
875
32.9k
    pdev->vgstack_size = 11;
876
32.9k
    pdev->Namespace_stack = cos_array_alloc(pdev, "pdf_open(Namespace stack)");
877
32.9k
    if (pdev->Namespace_stack == NULL) {
878
0
        code = gs_error_VMerror;
879
0
        goto fail;
880
0
    }
881
32.9k
    pdf_initialize_ids(pdev);
882
32.9k
    code = pdf_compute_fileID(pdev);
883
32.9k
    if (code < 0)
884
0
        goto fail;
885
32.9k
    if (pdev->OwnerPassword.size > 0) {
886
0
        code = pdf_compute_encryption_data(pdev);
887
0
        if (code < 0)
888
0
            goto fail;
889
32.9k
    } else if(pdev->UserPassword.size > 0) {
890
0
        emprintf(pdev->memory,
891
0
                 "User password is specified. Need an Owner password or both.\n");
892
0
        return_error(gs_error_rangecheck);
893
32.9k
    } else if (pdev->KeyLength) {
894
0
        emprintf(pdev->memory,
895
0
                 "Can't accept encryption options without a password.\n");
896
0
        return_error(gs_error_rangecheck);
897
0
    }
898
    /* Now create a new dictionary for the local named objects. */
899
32.9k
    pdev->local_named_objects =
900
32.9k
        cos_dict_alloc(pdev, "pdf_open(local_named_objects)");
901
32.9k
    if (pdev->local_named_objects == NULL) {
902
0
        code = gs_error_VMerror;
903
0
        goto fail;
904
0
    }
905
32.9k
    pdev->outlines_id = 0;
906
32.9k
    pdev->next_page = 0;
907
32.9k
    pdev->text = pdf_text_data_alloc(mem);
908
32.9k
    pdev->sbstack_size = pdev->vgstack_size; /* Overestimated a few. */
909
32.9k
    pdev->sbstack = gs_alloc_struct_array(mem, pdev->sbstack_size, pdf_substream_save,
910
32.9k
                                 &st_pdf_substream_save_element, "pdf_open");
911
32.9k
    pdev->pages =
912
32.9k
        gs_alloc_struct_array(mem, initial_num_pages, pdf_page_t,
913
32.9k
                              &st_pdf_page_element, "pdf_open(pages)");
914
32.9k
    if (pdev->text == 0 || pdev->pages == 0 || pdev->sbstack == 0) {
915
0
        code = gs_error_VMerror;
916
0
        goto fail;
917
0
    }
918
32.9k
    memset(pdev->sbstack, 0, pdev->sbstack_size * sizeof(pdf_substream_save));
919
32.9k
    memset(pdev->pages, 0, initial_num_pages * sizeof(pdf_page_t));
920
32.9k
    pdev->num_pages = initial_num_pages;
921
32.9k
    {
922
32.9k
        int i, j;
923
924
559k
        for (i = 0; i < NUM_RESOURCE_TYPES; ++i)
925
8.94M
            for (j = 0; j < NUM_RESOURCE_CHAINS; ++j)
926
8.42M
                pdev->resources[i].chains[j] = 0;
927
32.9k
    }
928
32.9k
    pdev->outline_levels = (pdf_outline_level_t *)gs_alloc_bytes(mem, INITIAL_MAX_OUTLINE_DEPTH * sizeof(pdf_outline_level_t), "outline_levels array");
929
32.9k
    if (pdev->outline_levels == NULL) {
930
0
        code = gs_error_VMerror;
931
0
        goto fail;
932
0
    }
933
934
32.9k
    memset(pdev->outline_levels, 0x00, INITIAL_MAX_OUTLINE_DEPTH * sizeof(pdf_outline_level_t));
935
32.9k
    pdev->max_outline_depth = INITIAL_MAX_OUTLINE_DEPTH;
936
32.9k
    pdev->outline_levels[0].first.id = 0;
937
32.9k
    pdev->outline_levels[0].left = max_int;
938
32.9k
    pdev->outline_levels[0].first.action = 0;
939
32.9k
    pdev->outline_levels[0].last.action = 0;
940
32.9k
    pdev->outline_depth = 0;
941
32.9k
    pdev->closed_outline_depth = 0;
942
32.9k
    pdev->outlines_open = 0;
943
32.9k
    pdev->articles = 0;
944
32.9k
    pdev->Dests = 0;
945
32.9k
    pdev->EmbeddedFiles = 0;
946
32.9k
    pdev->AF = 0;
947
    /* {global,local}_named_objects was initialized above */
948
32.9k
    pdev->PageLabels = 0;
949
32.9k
    pdev->PageLabels_current_page = 0;
950
32.9k
    pdev->PageLabels_current_label = 0;
951
32.9k
    pdev->pte = NULL;
952
32.9k
    pdf_reset_page(pdev);
953
32.9k
    pdev->BBox.p.x = pdev->width;
954
32.9k
    pdev->BBox.p.y = pdev->height;
955
32.9k
    pdev->BBox.q.x = 0;
956
32.9k
    pdev->BBox.q.y = 0;
957
958
32.9k
    if(pdev->UseCIEColor) {
959
0
        emprintf(pdev->memory, "\n\nUse of -dUseCIEColor detected!\nSince the release of version 9.11 of Ghostscript we recommend you do not set\n-dUseCIEColor with the pdfwrite/ps2write device family.\n\n");
960
0
    }
961
962
    /* Build a font cache for pdfwrite, see 'pdf_free_pdf_font_cache' for why we need this. */
963
32.9k
    pdev->pdf_font_dir = gs_font_dir_alloc2(pdev->memory->stable_memory, pdev->memory->non_gc_memory);
964
32.9k
    if (pdev->pdf_font_dir == 0) {
965
0
        code = gs_error_VMerror;
966
0
        goto fail;
967
0
    }
968
    /* If we have a gs_lib_ctx, then we need to copy these function pointers from it (we are in PostScript).
969
     * We can't fill them in otherwise, as the functions are declared static in gsfont.c.
970
     * If we don't have one then we are in PCL/PXL/XPS, and cannot copy these function pointers. Fortunately
971
     * we don't need them for fonts in these languages.
972
     */
973
32.9k
    if (pdev->memory->gs_lib_ctx->font_dir) {
974
32.9k
        pdev->pdf_font_dir->ccache.mark_glyph = pdev->memory->gs_lib_ctx->font_dir->ccache.mark_glyph;
975
32.9k
        pdev->pdf_font_dir->global_glyph_code = pdev->memory->gs_lib_ctx->font_dir->global_glyph_code;
976
32.9k
    }
977
978
    /* gs_opendevice() sets the device 'is_open' flag which is now of course the parent. We
979
     * still need to set the child's flag, we'll do it here to avoid setting it if we get any
980
     * failures, as those will also leave the parent not open.
981
     */
982
32.9k
    if (pdev->parent)
983
0
        pdev->is_open = true;
984
985
32.9k
    return 0;
986
0
  fail:
987
0
    gdev_vector_close_file((gx_device_vector *) pdev);
988
0
    return pdf_close_files(pdev, code);
989
32.9k
}
990
991
/* Detect I/O errors. */
992
static int
993
pdf_ferror(gx_device_pdf *pdev)
994
109k
{
995
109k
    int code = 0;
996
997
109k
    if (pdev->file != NULL) {
998
109k
        gp_fflush(pdev->file);
999
109k
        code = gp_ferror(pdev->file);
1000
109k
    }
1001
109k
    gp_fflush(pdev->xref.file);
1002
109k
    if (pdev->strm->file != NULL)
1003
0
        sflush(pdev->strm);
1004
109k
    if (pdev->asides.strm->file != NULL)
1005
109k
        sflush(pdev->asides.strm);
1006
109k
    if (pdev->streams.strm->file != NULL)
1007
109k
        sflush(pdev->streams.strm);
1008
109k
    if (pdev->ObjStm.strm != NULL && pdev->ObjStm.strm->file != NULL) {
1009
31.5k
        int code2;
1010
31.5k
        sflush(pdev->ObjStm.strm);
1011
31.5k
        code2 = gp_ferror(pdev->ObjStm.file);
1012
31.5k
        if (code >= 0) code = code2;
1013
31.5k
    }
1014
109k
    return gp_ferror(pdev->xref.file) || gp_ferror(pdev->asides.file) ||
1015
109k
           gp_ferror(pdev->streams.file) || code;
1016
109k
}
1017
1018
/* Compute the dominant text orientation of a page. */
1019
static int
1020
pdf_dominant_rotation(const pdf_text_rotation_t *ptr)
1021
21.5k
{
1022
21.5k
    int i, imax = -1;
1023
21.5k
    int64_t max_count = 0;
1024
21.5k
    static const int angles[] = { pdf_text_rotation_angle_values };
1025
1026
129k
    for (i = 0; i < countof(ptr->counts); ++i) {
1027
107k
        int64_t count = ptr->counts[i];
1028
1029
107k
        if (count > max_count)
1030
6.47k
            imax = i, max_count = count;
1031
107k
    }
1032
21.5k
    return (imax < 0 ? imax : angles[imax]);
1033
21.5k
}
1034
1035
/* Print a Rotate command, if requested and possible. */
1036
static void
1037
pdf_print_orientation(gx_device_pdf * pdev, pdf_page_t *page)
1038
51.4k
{
1039
51.4k
    stream *s = pdev->strm;
1040
51.4k
    int dsc_orientation = -1;
1041
51.4k
    const pdf_page_dsc_info_t *ppdi;
1042
1043
51.4k
    if (pdev->params.AutoRotatePages == arp_None)
1044
29.9k
        return; /* Not requested. */
1045
1046
21.5k
    ppdi = (page != NULL ? &page->dsc_info : &pdev->doc_dsc_info);
1047
1048
    /* Determine DSC orientation : */
1049
21.5k
    if (ppdi->viewing_orientation >= 0)
1050
0
        dsc_orientation = ppdi->viewing_orientation;
1051
21.5k
    else if (ppdi->orientation >= 0)
1052
0
        dsc_orientation = ppdi->orientation;
1053
21.5k
    if ((page == NULL && pdev->params.AutoRotatePages == arp_All) || /* document */
1054
21.5k
        (page != NULL && page->text_rotation.Rotate >= 0) || /* page */
1055
17.7k
        dsc_orientation >= 0 /* have DSC */) {
1056
3.82k
        const pdf_text_rotation_t *ptr =
1057
3.82k
            (page != NULL ? &page->text_rotation : &pdev->text_rotation);
1058
3.82k
        int angle = -1;
1059
1060
        /* Combine DSC rotation with text rotation : */
1061
3.82k
        if (dsc_orientation == 0) {
1062
0
            if (ptr->Rotate == 0 || ptr->Rotate == 180)
1063
0
                angle = ptr->Rotate;
1064
3.82k
        } else if (dsc_orientation == 1) {
1065
0
            if (ptr->Rotate == 90 || ptr->Rotate == 270)
1066
0
                angle = ptr->Rotate;
1067
0
            else
1068
0
                angle = 90;
1069
0
        }
1070
1071
3.82k
        if (angle < 0) {
1072
        /* If DSC and heuristic disagree, prefer dsc rotation to match the documented Adobe behaviour */
1073
3.82k
            if (dsc_orientation >= 0)
1074
0
                angle = dsc_orientation * 90;
1075
3.82k
            else
1076
3.82k
                angle = ptr->Rotate;
1077
3.82k
        }
1078
1079
        /* If got some, write it out : */
1080
3.82k
        if (angle >= 0)
1081
3.82k
            pprintd1(s, "/Rotate %d", angle);
1082
3.82k
    }
1083
21.5k
}
1084
1085
/* Close the current page. */
1086
static int
1087
pdf_close_page(gx_device_pdf * pdev, int num_copies)
1088
42.6k
{
1089
42.6k
    int page_num;
1090
42.6k
    pdf_page_t *page;
1091
42.6k
    int code, i;
1092
1093
42.6k
    while (pdev->FormDepth > 0) {
1094
0
        pdev->FormDepth--;
1095
0
        code = pdf_exit_substream(pdev);
1096
0
        if (code < 0)
1097
0
            return code;
1098
0
    }
1099
1100
    /*
1101
     * If the very first page is blank, we need to open the document
1102
     * before doing anything else.
1103
     */
1104
1105
42.6k
    code = pdfwrite_pdf_open_document(pdev);
1106
42.6k
    if (code < 0)
1107
0
        return code;
1108
42.6k
    if (pdev->ForOPDFRead && pdev->context == PDF_IN_NONE) {
1109
        /* Must create a context stream for empty pages. */
1110
10
        code = pdf_open_contents(pdev, PDF_IN_STREAM);
1111
10
        if (code < 0)
1112
3
            return code;
1113
10
    }
1114
42.6k
    pdf_close_contents(pdev, true);
1115
1116
42.6k
    if (!pdev->DoNumCopies)
1117
42.6k
        num_copies = 1;
1118
1119
85.2k
    for(i=0;i<num_copies;i++) {
1120
42.6k
        bool clear_resource_use = i < num_copies - 1 ? 0 : 1;
1121
1122
42.6k
        page_num = ++(pdev->next_page);
1123
        /*
1124
         * We can't write the page object or the annotations array yet, because
1125
         * later pdfmarks might add elements to them.  Write the other objects
1126
         * that the page references, and record what we'll need later.
1127
         *
1128
         * Start by making sure the pages array element exists.
1129
         */
1130
1131
42.6k
        pdf_page_id(pdev, page_num);
1132
42.6k
        page = &pdev->pages[page_num - 1];
1133
42.6k
        page->MediaBox.x = pdev->MediaSize[0];
1134
42.6k
        page->MediaBox.y = pdev->MediaSize[1];
1135
42.6k
        page->contents_id = pdev->contents_id;
1136
42.6k
        page->NumCopies_set = pdev->NumCopies_set;
1137
42.6k
        page->NumCopies = pdev->NumCopies;
1138
42.6k
        page->UserUnit = pdev->UserUnit;
1139
42.6k
        pdf_record_usage(pdev, pdev->contents_id, pdev->next_page);
1140
42.6k
        pdf_record_usage(pdev, pdev->contents_length_id, pdev->next_page);
1141
42.6k
        pdf_record_usage(pdev, page->Page->id, pdev->next_page);
1142
1143
        /* pdf_store_page_resources sets procsets, resource_ids[]. */
1144
42.6k
        code = pdf_store_page_resources(pdev, page, clear_resource_use);
1145
42.6k
        if (code < 0)
1146
0
            return code;
1147
1148
        /* Write the Functions. */
1149
1150
42.6k
        code = pdf_write_resource_objects(pdev, resourceFunction);
1151
42.6k
        if (code < 0)
1152
0
            return code;
1153
1154
        /* Close use of text on the page. */
1155
1156
42.6k
        pdf_close_text_page(pdev);
1157
1158
        /* Accumulate text rotation. */
1159
1160
42.6k
        page->text_rotation.Rotate =
1161
42.6k
            (pdev->params.AutoRotatePages == arp_PageByPage ?
1162
30.2k
            pdf_dominant_rotation(&page->text_rotation) : -1);
1163
42.6k
        {
1164
42.6k
            int i;
1165
1166
255k
            for (i = 0; i < countof(page->text_rotation.counts); ++i)
1167
213k
                pdev->text_rotation.counts[i] += page->text_rotation.counts[i];
1168
42.6k
        }
1169
1170
        /* Record information from DSC comments. */
1171
1172
42.6k
        page->dsc_info = pdev->page_dsc_info;
1173
42.6k
        if (page->dsc_info.orientation < 0)
1174
42.6k
            page->dsc_info.orientation = pdev->doc_dsc_info.orientation;
1175
        /* Bug 688793 */
1176
42.6k
        if (page->dsc_info.viewing_orientation < 0)
1177
42.6k
        page->dsc_info.viewing_orientation =
1178
42.6k
           pdev->doc_dsc_info.viewing_orientation;
1179
42.6k
        if (page->dsc_info.bounding_box.p.x >= page->dsc_info.bounding_box.q.x ||
1180
0
            page->dsc_info.bounding_box.p.y >= page->dsc_info.bounding_box.q.y
1181
42.6k
            )
1182
42.6k
            page->dsc_info.bounding_box = pdev->doc_dsc_info.bounding_box;
1183
1184
        /* Finish up. */
1185
1186
42.6k
        if(pdf_ferror(pdev))
1187
0
            return(gs_note_error(gs_error_ioerror));
1188
42.6k
    }
1189
42.6k
    pdf_reset_page(pdev);
1190
42.6k
    return (pdf_ferror(pdev) ? gs_note_error(gs_error_ioerror) : 0);
1191
42.6k
}
1192
1193
/* Write the page object. */
1194
static double
1195
round_box_coord(double xy)
1196
84.6k
{
1197
84.6k
    return (int)(xy * 100 + 0.5) / 100.0;
1198
84.6k
}
1199
static int check_annot_in_named(void *client_data, const byte *key_data, uint key_size, const cos_value_t *value)
1200
391k
{
1201
391k
    cos_value_t *v = (cos_value_t *)client_data;
1202
1203
391k
    if (value->contents.object == v->contents.object)
1204
0
        return 1;
1205
391k
    return 0;
1206
391k
}
1207
1208
static int
1209
pdf_write_page(gx_device_pdf *pdev, int page_num)
1210
42.3k
{
1211
42.3k
    int64_t page_id;
1212
42.3k
    pdf_page_t *page;
1213
42.3k
    double mediabox[4] = {0, 0};
1214
42.3k
    stream *s;
1215
42.3k
    const cos_value_t *v_mediabox = NULL;
1216
1217
42.3k
    if (pdev->pages == NULL)
1218
0
        return_error(gs_error_undefined);
1219
1220
42.3k
    page = &pdev->pages[page_num - 1];
1221
42.3k
    if (page->Page != NULL)
1222
42.3k
        v_mediabox = cos_dict_find_c_key(page->Page, "/MediaBox");
1223
42.3k
    page_id = pdf_page_id(pdev, page_num);
1224
1225
    /* If we have not been given a MediaBox overriding pdfmark, use the current media size. */
1226
42.3k
    s = pdev->strm;
1227
42.3k
    pdf_open_obj(pdev, page_id, resourcePage);
1228
1229
42.3k
    if (v_mediabox == NULL ) {
1230
42.3k
        mediabox[2] = round_box_coord(page->MediaBox.x);
1231
42.3k
        mediabox[3] = round_box_coord(page->MediaBox.y);
1232
42.3k
        pprintg2(s, "<</Type/Page/MediaBox [0 0 %g %g]\n",
1233
42.3k
                mediabox[2], mediabox[3]);
1234
42.3k
    } else {
1235
0
        const byte *p = v_mediabox->contents.chars.data;
1236
0
        char buf[100];
1237
0
        int i, l = min (v_mediabox->contents.chars.size, sizeof(buf) - 1);
1238
0
        float temp[4]; /* the type is float for sscanf. */
1239
1240
0
        temp[0] = temp[1] = 0;
1241
0
        temp[2] = round_box_coord(page->MediaBox.x);
1242
0
        temp[3] = round_box_coord(page->MediaBox.y);
1243
0
        memcpy(buf, p, l);
1244
0
        buf[l] = 0;
1245
0
        if (sscanf(buf, "[ %g %g %g %g ]",
1246
0
                &temp[0], &temp[1], &temp[2], &temp[3]) == 4) {
1247
0
            if (page->Page)
1248
0
             cos_dict_delete_c_key(page->Page, "/MediaBox");
1249
0
        }
1250
0
        pprintg4(s, "<</Type/Page/MediaBox [%g %g %g %g]\n",
1251
0
                temp[0], temp[1], temp[2], temp[3]);
1252
0
        for (i=0;i<4;i++)
1253
0
            mediabox[i] = temp[i];
1254
0
    }
1255
42.3k
    if (pdev->PDFX != 0) {
1256
0
        const cos_value_t *v_trimbox = NULL;
1257
0
        const cos_value_t *v_artbox = NULL;
1258
0
        const cos_value_t *v_cropbox = NULL;
1259
0
        const cos_value_t *v_bleedbox = NULL;
1260
0
        float trimbox[4] = {0, 0}, bleedbox[4] = {0, 0}, artbox[4] = {0, 0}, cropbox[4] = {0, 0};
1261
0
        bool print_bleedbox = false;
1262
1263
0
        if (page->Page != NULL) {
1264
0
            v_trimbox = cos_dict_find_c_key(page->Page, "/TrimBox");
1265
0
            v_artbox = cos_dict_find_c_key(page->Page, "/ArtBox");
1266
0
            v_cropbox = cos_dict_find_c_key(page->Page, "/CropBox");
1267
0
            v_bleedbox = cos_dict_find_c_key(page->Page, "/BleedBox");
1268
0
        }
1269
1270
0
        cropbox[2] = trimbox[2] = bleedbox[2] = mediabox[2];
1271
0
        cropbox[3] = trimbox[3] = bleedbox[3] = mediabox[3];
1272
        /* Offsets are [left right top bottom] according to the Acrobat 7.0
1273
           distiller parameters manual, 12/7/2004, pp. 102-103. */
1274
0
        if (v_trimbox != NULL && v_trimbox->value_type == COS_VALUE_SCALAR) {
1275
0
            const byte *p = v_trimbox->contents.chars.data;
1276
0
            char buf[100];
1277
0
            int l = min (v_trimbox->contents.chars.size, sizeof(buf) - 1);
1278
0
            float temp[4]; /* the type is float for sscanf. */
1279
1280
0
            memcpy(buf, p, l);
1281
0
            buf[l] = 0;
1282
0
            if (sscanf(buf, "[ %g %g %g %g ]",
1283
0
                    &temp[0], &temp[1], &temp[2], &temp[3]) == 4) {
1284
0
                trimbox[0] = temp[0];
1285
0
                trimbox[1] = temp[1];
1286
0
                trimbox[2] = temp[2];
1287
0
                trimbox[3] = temp[3];
1288
0
                if (page->Page != NULL)
1289
0
                    cos_dict_delete_c_key(page->Page, "/TrimBox");
1290
0
            }
1291
0
            if (v_artbox != NULL && v_artbox->value_type == COS_VALUE_SCALAR && page->Page != NULL)
1292
0
                cos_dict_delete_c_key(page->Page, "/ArtBox");
1293
1294
0
        } else if (v_artbox != NULL && v_artbox->value_type == COS_VALUE_SCALAR) {
1295
            /* We have no TrimBox, but we ahve an ArtBox, set the TrimBox to be
1296
             * the supplied ArtBox (TrimBox is preferred for PDF/X)
1297
             */
1298
0
            const byte *p = v_artbox->contents.chars.data;
1299
0
            char buf[100];
1300
0
            int l = min (v_artbox->contents.chars.size, sizeof(buf) - 1);
1301
0
            float temp[4]; /* the type is float for sscanf. */
1302
1303
0
            memcpy(buf, p, l);
1304
0
            buf[l] = 0;
1305
0
            if (sscanf(buf, "[ %g %g %g %g ]",
1306
0
                    &temp[0], &temp[1], &temp[2], &temp[3]) == 4) {
1307
0
                if (pdev->PDFX == 3) {
1308
0
                    trimbox[0] = temp[0];
1309
0
                    trimbox[1] = temp[1];
1310
0
                    trimbox[2] = temp[2];
1311
0
                    trimbox[3] = temp[3];
1312
0
                    if (page->Page != NULL)
1313
0
                        cos_dict_delete_c_key(page->Page, "/ArtBox");
1314
0
                } else {
1315
0
                    artbox[0] = temp[0];
1316
0
                    artbox[1] = temp[1];
1317
0
                    artbox[2] = temp[2];
1318
0
                    artbox[3] = temp[3];
1319
0
                }
1320
0
            }
1321
0
        } else {
1322
0
            if (pdev->PDFXTrimBoxToMediaBoxOffset.size >= 4 &&
1323
0
                    pdev->PDFXTrimBoxToMediaBoxOffset.data[0] >= 0 &&
1324
0
                    pdev->PDFXTrimBoxToMediaBoxOffset.data[1] >= 0 &&
1325
0
                    pdev->PDFXTrimBoxToMediaBoxOffset.data[2] >= 0 &&
1326
0
                    pdev->PDFXTrimBoxToMediaBoxOffset.data[3] >= 0) {
1327
0
                trimbox[0] = mediabox[0] + pdev->PDFXTrimBoxToMediaBoxOffset.data[0];
1328
0
                trimbox[1] = mediabox[1] + pdev->PDFXTrimBoxToMediaBoxOffset.data[3];
1329
0
                trimbox[2] = mediabox[2] - pdev->PDFXTrimBoxToMediaBoxOffset.data[1];
1330
0
                trimbox[3] = mediabox[3] - pdev->PDFXTrimBoxToMediaBoxOffset.data[2];
1331
0
            }
1332
0
        }
1333
1334
0
        if (v_bleedbox != NULL && v_bleedbox->value_type == COS_VALUE_SCALAR) {
1335
0
            const byte *p = v_bleedbox->contents.chars.data;
1336
0
            char buf[100];
1337
0
            int l = min (v_bleedbox->contents.chars.size, sizeof(buf) - 1);
1338
0
            float temp[4]; /* the type is float for sscanf. */
1339
1340
0
            memcpy(buf, p, l);
1341
0
            buf[l] = 0;
1342
0
            if (sscanf(buf, "[ %g %g %g %g ]",
1343
0
                    &temp[0], &temp[1], &temp[2], &temp[3]) == 4) {
1344
0
                if (temp[0] < mediabox[0])
1345
0
                    bleedbox[0] = mediabox[0];
1346
0
                else
1347
0
                    bleedbox[0] = temp[0];
1348
0
                if (temp[1] < mediabox[1])
1349
0
                    bleedbox[1] = mediabox[1];
1350
0
                else
1351
0
                    bleedbox[1] = temp[1];
1352
0
                if (temp[2] > mediabox[2])
1353
0
                    bleedbox[2] = mediabox[2];
1354
0
                else
1355
0
                    bleedbox[2] = temp[2];
1356
0
                if (temp[3] > mediabox[3])
1357
0
                    bleedbox[3] = mediabox[3];
1358
0
                else
1359
0
                    bleedbox[3] = temp[3];
1360
0
                print_bleedbox = true;
1361
0
                if (page->Page != NULL)
1362
0
                    cos_dict_delete_c_key(page->Page, "/BleedBox");
1363
0
            }
1364
0
        } else if (pdev->PDFXSetBleedBoxToMediaBox)
1365
0
            print_bleedbox = true;
1366
0
        else if (pdev->PDFXBleedBoxToTrimBoxOffset.size >= 4 &&
1367
0
                pdev->PDFXBleedBoxToTrimBoxOffset.data[0] >= 0 &&
1368
0
                pdev->PDFXBleedBoxToTrimBoxOffset.data[1] >= 0 &&
1369
0
                pdev->PDFXBleedBoxToTrimBoxOffset.data[2] >= 0 &&
1370
0
                pdev->PDFXBleedBoxToTrimBoxOffset.data[3] >= 0) {
1371
0
            bleedbox[0] = trimbox[0] - pdev->PDFXBleedBoxToTrimBoxOffset.data[0];
1372
0
            bleedbox[1] = trimbox[1] - pdev->PDFXBleedBoxToTrimBoxOffset.data[3];
1373
0
            bleedbox[2] = trimbox[2] + pdev->PDFXBleedBoxToTrimBoxOffset.data[1];
1374
0
            bleedbox[3] = trimbox[3] + pdev->PDFXBleedBoxToTrimBoxOffset.data[2];
1375
0
            print_bleedbox = true;
1376
0
        }
1377
1378
0
        if (print_bleedbox == true) {
1379
0
            if (trimbox[0] < bleedbox[0] || trimbox[1] < bleedbox[1] ||
1380
0
                trimbox[2] > bleedbox[2] || trimbox[3] > bleedbox[3]) {
1381
0
                switch (pdev->PDFACompatibilityPolicy) {
1382
0
                    case 0:
1383
0
                        emprintf(pdev->memory,
1384
0
                         "TrimBox does not fit inside BleedBox, not permitted in PDF/X-3, reverting to normal PDF output\n");
1385
0
                        pdev->AbortPDFAX = true;
1386
0
                        pdev->PDFX = 0;
1387
0
                        break;
1388
0
                    case 1:
1389
0
                        emprintf(pdev->memory,
1390
0
                         "TrimBox does not fit inside BleedBox, not permitted in PDF/X-3, reducing TrimBox\n");
1391
0
                        if (trimbox[0] < bleedbox[0])
1392
0
                            trimbox[0] = bleedbox[0];
1393
0
                        if (trimbox[1] < bleedbox[1])
1394
0
                            trimbox[1] = bleedbox[1];
1395
0
                        if (trimbox[2] > bleedbox[2])
1396
0
                            trimbox[2] = bleedbox[2];
1397
0
                        if (trimbox[3] > bleedbox[3])
1398
0
                            trimbox[3] = bleedbox[3];
1399
0
                        break;
1400
0
                    case 2:
1401
0
                        emprintf(pdev->memory,
1402
0
                         "TrimBox does not fit inside BleedBox, not permitted in PDF/X-3, aborting conversion\n");
1403
0
      return_error(gs_error_unknownerror);
1404
0
                        break;
1405
0
                    default:
1406
0
                        emprintf(pdev->memory,
1407
0
                         "TrimBox does not fit inside BleedBox, not permitted in PDF/X-3\nunrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
1408
0
                        pdev->AbortPDFAX = true;
1409
0
                        pdev->PDFX = 0;
1410
0
                        break;
1411
0
                }
1412
0
            }
1413
0
        }
1414
1415
0
        if (v_cropbox != NULL && v_cropbox->value_type == COS_VALUE_SCALAR) {
1416
0
            const byte *p = v_cropbox->contents.chars.data;
1417
0
            char buf[100];
1418
0
            int l = min (v_cropbox->contents.chars.size, sizeof(buf) - 1);
1419
0
            float temp[4]; /* the type is float for sscanf. */
1420
1421
0
            memcpy(buf, p, l);
1422
0
            buf[l] = 0;
1423
0
            if (sscanf(buf, "[ %g %g %g %g ]",
1424
0
                    &temp[0], &temp[1], &temp[2], &temp[3]) == 4) {
1425
0
                if (page->Page != NULL)
1426
0
                    cos_dict_delete_c_key(page->Page, "/CropBox");
1427
                /* Ensure that CropBox is no larger than MediaBox. The spec says *nothing* about
1428
                 * this, but Acrobat Preflight complains if it is larger. This can happen because
1429
                 * we apply 'round_box_coord' to the mediabox at the start of this rouinte.
1430
                 */
1431
0
                if (temp[0] < mediabox[0])
1432
0
                    temp[0] = mediabox[0];
1433
0
                if (temp[1] < mediabox[1])
1434
0
                    temp[1] = mediabox[1];
1435
0
                if (temp[2] > mediabox[2])
1436
0
                    temp[2] = mediabox[2];
1437
0
                if (temp[3] > mediabox[3])
1438
0
                    temp[3] = mediabox[3];
1439
0
                cropbox[0] = temp[0];
1440
0
                cropbox[1] = temp[1];
1441
0
                cropbox[2] = temp[2];
1442
0
                cropbox[3] = temp[3];
1443
0
                pprintg4(s, "/CropBox [%g %g %g %g]\n",
1444
0
                    temp[0], temp[1], temp[2], temp[3]);
1445
                /* Make sure TrimBox fits inside CropBox. Spec says 'must not extend
1446
                 * beyond the boundaries' but Acrobat Preflight complains if they
1447
                 * are the same value.
1448
                 */
1449
0
                if (trimbox[0] < temp[0] || trimbox[1] < temp[1] ||
1450
0
                    trimbox[2] > temp[2] || trimbox[3] > temp[3]) {
1451
0
                    switch (pdev->PDFACompatibilityPolicy) {
1452
0
                        case 0:
1453
0
                            emprintf(pdev->memory,
1454
0
                             "TrimBox does not fit inside CropBox, not permitted in PDF/X-3, reverting to normal PDF output\n");
1455
0
                            pdev->AbortPDFAX = true;
1456
0
                            pdev->PDFX = 0;
1457
0
                            break;
1458
0
                        case 1:
1459
0
                            emprintf(pdev->memory,
1460
0
                             "TrimBox does not fit inside CropBox, not permitted in PDF/X-3, reducing TrimBox\n");
1461
0
                            if (trimbox[0] < temp[0])
1462
0
                                trimbox[0] = temp[0];
1463
0
                            if (trimbox[1] < temp[1])
1464
0
                                trimbox[1] = temp[1];
1465
0
                            if (trimbox[2] > temp[2])
1466
0
                                trimbox[2] = temp[2];
1467
0
                            if (trimbox[3] > temp[3])
1468
0
                                trimbox[3] = temp[3];
1469
0
                            break;
1470
0
                        case 2:
1471
0
                            emprintf(pdev->memory,
1472
0
                             "TrimBox does not fit inside CropBox, not permitted in PDF/X-3, aborting conversion\n");
1473
0
          return_error(gs_error_unknownerror);
1474
0
                            break;
1475
0
                        default:
1476
0
                            emprintf(pdev->memory,
1477
0
                             "TrimBox does not fit inside CropBox, not permitted in PDF/X-3\nunrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
1478
0
                            pdev->AbortPDFAX = true;
1479
0
                            pdev->PDFX = 0;
1480
0
                            break;
1481
0
                    }
1482
0
                }
1483
0
            }
1484
0
        }
1485
1486
0
        if (pdev->PDFX > 1 && page->Page != NULL) {
1487
0
            if (cos_dict_find_c_key(page->Page, "/TrimBox") == NULL &&
1488
0
                cos_dict_find_c_key(page->Page, "/ArtBox") == NULL)
1489
0
                pprintg4(s, "/TrimBox [%g %g %g %g]\n",
1490
0
                    trimbox[0], trimbox[1], trimbox[2], trimbox[3]);
1491
0
            if (print_bleedbox &&
1492
0
                cos_dict_find_c_key(page->Page, "/BleedBox") == NULL)
1493
0
                pprintg4(s, "/BleedBox [%g %g %g %g]\n",
1494
0
                    bleedbox[0], bleedbox[1], bleedbox[2], bleedbox[3]);
1495
0
        }
1496
0
        if (pdev->PDFX == 1 && page->Page != NULL) {
1497
0
            if (cos_dict_find_c_key(page->Page, "/ArtBox") == NULL) {
1498
0
                artbox[0] = mediabox[0];
1499
0
                artbox[1] = mediabox[1];
1500
0
                artbox[2] = mediabox[2];
1501
0
                artbox[3] = mediabox[3];
1502
0
            }
1503
0
            if (cos_dict_find_c_key(page->Page, "/CropBox") != NULL) {
1504
0
                if (artbox[0] < cropbox[0])
1505
0
                    artbox[0] = cropbox[0];
1506
0
                if (artbox[1] < cropbox[1])
1507
0
                    artbox[1] = cropbox[1];
1508
0
                if (artbox[2] < cropbox[2])
1509
0
                    artbox[2] = cropbox[2];
1510
0
                if (artbox[3] < cropbox[3])
1511
0
                    artbox[3] = cropbox[3];
1512
0
            }
1513
0
            if (cos_dict_find_c_key(page->Page, "/BleedBox") != NULL) {
1514
0
                if (artbox[0] < bleedbox[0])
1515
0
                    artbox[0] = bleedbox[0];
1516
0
                if (artbox[1] < bleedbox[1])
1517
0
                    artbox[1] = bleedbox[1];
1518
0
                if (artbox[2] < bleedbox[2])
1519
0
                    artbox[2] = bleedbox[2];
1520
0
                if (artbox[3] < bleedbox[3])
1521
0
                    artbox[3] = bleedbox[3];
1522
0
            }
1523
0
            pprintg4(s, "/ArtBox [%g %g %g %g]\n",
1524
0
                artbox[0], artbox[1], artbox[2], artbox[3]);
1525
0
        }
1526
0
    }
1527
42.3k
    pdf_print_orientation(pdev, page);
1528
42.3k
    if (page->UserUnit != 1)
1529
4
        pprintg1(s, "/UserUnit %g\n", page->UserUnit);
1530
1531
42.3k
    pprinti64d1(s, "/Parent %"PRId64" 0 R\n", pdev->Pages->id);
1532
42.3k
    if (pdev->ForOPDFRead && pdev->DoNumCopies && !pdev->ProduceDSC) {
1533
0
        if (page->NumCopies_set)
1534
0
            pprinti64d1(s, "/NumCopies %"PRId64"\n", page->NumCopies);
1535
0
    }
1536
42.3k
    if (page->group_id > 0) {
1537
255
        pprinti64d1(s, "/Group %"PRId64" 0 R\n", page->group_id);
1538
255
    }
1539
42.3k
    if (pdev->CompatibilityLevel <= 1.7) {
1540
42.3k
            stream_puts(s, "/Resources<</ProcSet[/PDF");
1541
42.3k
        if (page->procsets & ImageB)
1542
62
            stream_puts(s, " /ImageB");
1543
42.3k
        if (page->procsets & ImageC)
1544
1.53k
            stream_puts(s, " /ImageC");
1545
42.3k
        if (page->procsets & ImageI)
1546
619
            stream_puts(s, " /ImageI");
1547
42.3k
        if (page->procsets & Text)
1548
3.75k
            stream_puts(s, " /Text");
1549
42.3k
        stream_puts(s, "]\n");
1550
42.3k
    } else {
1551
0
        stream_puts(s, "/Resources<<");
1552
0
    }
1553
42.3k
    {
1554
42.3k
        int i;
1555
1556
380k
        for (i = 0; i < countof(page->resource_ids); ++i)
1557
338k
            if (page->resource_ids[i] && pdf_resource_type_names[i]) {
1558
21.5k
                stream_puts(s, pdf_resource_type_names[i]);
1559
21.5k
                pprinti64d1(s, " %"PRId64" 0 R\n", page->resource_ids[i]);
1560
21.5k
            }
1561
42.3k
    }
1562
42.3k
    stream_puts(s, ">>\n");
1563
1564
    /* Write the annotations array if any. */
1565
1566
42.3k
    if (page->Annots) {
1567
481
        const cos_value_t *value = NULL;
1568
481
        const cos_array_element_t *e = NULL, *next = NULL;
1569
481
        int64_t index = 0;
1570
1571
481
        stream_puts(s, "/Annots");
1572
481
        COS_WRITE(page->Annots, pdev);
1573
        /* More complications caused by cos objects. Simply calling COS_FREE
1574
         * will free the array, but it won't free the elements of the array
1575
         * if they have non-zero IDs (see the comments regarding cleanup of
1576
         * resources in pdf_close at around line 1090 below). Because we've
1577
         * already written out the annotations, the dictionary contents have
1578
         * already been freed, but we need the IDs until this point when we
1579
         * write out the array in the page dictionary. So after using them,
1580
         * we must go through the array and set the ids to 0 so that COS_FREE
1581
         * will free the array elements as well as the array itself.
1582
         */
1583
481
        e = cos_array_element_first(page->Annots);
1584
7.72k
        while (e != NULL) {
1585
7.24k
            next = cos_array_element_next(e, &index, &value);
1586
7.24k
            if (value->contents.object != NULL) {
1587
                /* Check to see if this is a local named object, if it is do not
1588
                 * zero the ID! This object has not yet been written, because it
1589
                 * is a named object it can be modified after creation. We must
1590
                 * allow the named object code to write out the object and free it.
1591
                 */
1592
7.24k
                if (cos_dict_forall(pdev->local_named_objects, (void *)value,
1593
7.24k
                                    check_annot_in_named) == 0)
1594
7.24k
                    value->contents.object->id = 0;
1595
7.24k
            }
1596
7.24k
            e = next;
1597
7.24k
        }
1598
481
        COS_FREE(page->Annots, "pdf_write_page(Annots)");
1599
481
        page->Annots = 0;
1600
481
    }
1601
    /*
1602
     * The PDF documentation allows, and this code formerly emitted,
1603
     * a Contents entry whose value was an empty array.  Acrobat Reader
1604
     * 3 and 4 accept this, but Acrobat Reader 5.0 rejects it.
1605
     * Fortunately, the Contents entry is optional.
1606
     */
1607
42.3k
    if (page->contents_id != 0)
1608
42.3k
        pprinti64d1(s, "/Contents %"PRId64" 0 R\n", page->contents_id);
1609
1610
    /* Write any elements stored by pdfmarks. */
1611
1612
42.3k
    if (page->Page != NULL)
1613
42.3k
        cos_dict_elements_write(page->Page, pdev);
1614
1615
42.3k
    stream_puts(s, ">>\n");
1616
42.3k
    pdf_end_obj(pdev, resourcePage);
1617
42.3k
    return 0;
1618
42.3k
}
1619
1620
/* Wrap up ("output") a page. */
1621
/* if we are doing separate pages, call pdf_close to emit the file, then */
1622
/* pdf_open to open the next page as a new file */
1623
/* NB: converting an input PDF with offpage links will generate warnings */
1624
static int
1625
pdf_output_page(gx_device * dev, int num_copies, int flush)
1626
27.2k
{
1627
27.2k
    gx_device_pdf *const pdev = (gx_device_pdf *) dev;
1628
27.2k
    int code;
1629
1630
27.2k
    if (pdev->Eps2Write && pdev->next_page != 0 && !gx_outputfile_is_separate_pages(pdev->fname, dev->memory)) {
1631
3.02k
       emprintf(pdev->memory, "\n   *** EPS files may not contain multiple pages.\n   *** Use of the %%d filename format is required to output pages to multiple EPS files.\n");
1632
3.02k
       return_error(gs_error_ioerror);
1633
3.02k
    }
1634
1635
24.1k
    if (pdev->ForOPDFRead) {
1636
17.3k
        code = pdf_close_page(pdev, num_copies);
1637
17.3k
        if (code < 0)
1638
0
            return code;
1639
1640
17.4k
        while (pdev->sbstack_depth) {
1641
12
            code = pdf_exit_substream(pdev);
1642
12
            if (code < 0)
1643
6
                return code;
1644
12
        }
1645
17.3k
    } else {
1646
6.78k
        while (pdev->sbstack_depth) {
1647
0
            code = pdf_exit_substream(pdev);
1648
0
            if (code < 0)
1649
0
                return code;
1650
0
        }
1651
6.78k
        code = pdf_close_page(pdev, num_copies);
1652
6.78k
        if (code < 0)
1653
0
            return code;
1654
6.78k
    }
1655
1656
24.1k
    if(pdev->UseCIEColor) {
1657
0
        emprintf(pdev->memory, "\n\nUse of -dUseCIEColor detected!\nSince the release of version 9.11 of Ghostscript we recommend you do not set\n-dUseCIEColor with the pdfwrite/ps2write device family.\n\n");
1658
0
    }
1659
24.1k
    if (pdf_ferror(pdev))
1660
0
        return_error(gs_error_ioerror);
1661
1662
24.1k
    if ((code = gx_finish_output_page(dev, num_copies, flush)) < 0)
1663
0
        return code;
1664
1665
24.1k
    if (gx_outputfile_is_separate_pages(((gx_device_vector *)dev)->fname, dev->memory)) {
1666
0
        pdev->InOutputPage = true;
1667
0
        if ((code = pdf_close(dev)) < 0)
1668
0
            return code;
1669
0
        code = pdf_open(dev);
1670
0
        dev->is_open = true;
1671
0
    }
1672
24.1k
    return code;
1673
24.1k
}
1674
1675
static int find_end_xref_section (gx_device_pdf *pdev, gp_file *tfile, int64_t start, gs_offset_t resource_pos)
1676
27.5k
{
1677
27.5k
    int64_t start_offset;
1678
1679
27.5k
    if (pdev->doubleXref)
1680
27.5k
        start_offset = (start - pdev->FirstObjectNumber) * sizeof(gs_offset_t) * 2;
1681
0
    else
1682
0
        start_offset = (start - pdev->FirstObjectNumber) * sizeof(gs_offset_t);
1683
1684
27.5k
    if (gp_fseek(tfile, start_offset, SEEK_SET) == 0)
1685
27.5k
    {
1686
27.5k
        int64_t i, r;
1687
1688
491k
        for (i = start; i < pdev->next_id; ++i) {
1689
464k
            gs_offset_t pos, index = -1;
1690
1691
464k
            r = gp_fread(&pos, sizeof(pos), 1, tfile);
1692
464k
            if (r != 1)
1693
0
                return(gs_note_error(gs_error_ioerror));
1694
464k
            if (pdev->doubleXref) {
1695
464k
                index = pos;
1696
464k
                r = gp_fread(&pos, sizeof(pos), 1, tfile);
1697
464k
                if (r != 1)
1698
0
                    return(gs_note_error(gs_error_ioerror));
1699
464k
            } else
1700
0
                index = 0;
1701
464k
            if (pos & ASIDES_BASE_POSITION) {
1702
120k
                pos &= ~ASIDES_BASE_POSITION;
1703
120k
                pos += resource_pos;
1704
120k
            }
1705
464k
            pos -= pdev->OPDFRead_procset_length;
1706
464k
            if (pos == 0 && index == 0) {
1707
20
                return i;
1708
20
            }
1709
464k
        }
1710
27.5k
    }
1711
27.4k
    return pdev->next_id;
1712
27.5k
}
1713
1714
static int write_xref_section(gx_device_pdf *pdev, gp_file *tfile, int64_t start, int end, gs_offset_t resource_pos, gs_offset_t *Offsets)
1715
0
{
1716
0
    int64_t start_offset;
1717
1718
0
    if (pdev->doubleXref)
1719
0
        start_offset = (start - pdev->FirstObjectNumber) * sizeof(gs_offset_t) * 2;
1720
0
    else
1721
0
        start_offset = (start - pdev->FirstObjectNumber) * sizeof(gs_offset_t);
1722
1723
0
    if (gp_fseek(tfile, start_offset, SEEK_SET) == 0)
1724
0
    {
1725
0
        int64_t i, r;
1726
1727
0
        for (i = start; i < end; ++i) {
1728
0
            gs_offset_t pos;
1729
0
            char str[21];
1730
1731
0
            r = gp_fread(&pos, sizeof(pos), 1, tfile);
1732
0
            if (r != 1)
1733
0
                return(gs_note_error(gs_error_ioerror));
1734
0
            if (pdev->doubleXref) {
1735
0
                r = gp_fread(&pos, sizeof(pos), 1, tfile);
1736
0
                if (r != 1)
1737
0
                    return(gs_note_error(gs_error_ioerror));
1738
0
            }
1739
1740
0
            if (pos & ASIDES_BASE_POSITION) {
1741
0
                pos &= ~ASIDES_BASE_POSITION;
1742
0
                pos += resource_pos;
1743
0
            }
1744
0
            pos -= pdev->OPDFRead_procset_length;
1745
1746
            /* check to see we haven't got an offset which is too large to represent
1747
             * in an xref (10 digits). Throw an error if we do.
1748
             */
1749
0
            if (pos > 9999999999) {
1750
0
                emprintf(pdev->pdf_memory, "ERROR - Attempt to create an xref entry with more than 10 digits which is illegal.\n");
1751
0
                emprintf(pdev->pdf_memory, "PDF file production has been aborted.\n");
1752
0
                return_error(gs_error_rangecheck);
1753
0
            }
1754
1755
            /* If we are linearising there's no point in writing an xref we will
1756
             * later replace. Also makes the file slightly smaller reducing the
1757
             * chances of needing to write white space to pad the file out.
1758
             */
1759
0
            if (!pdev->Linearise) {
1760
0
                gs_snprintf(str, sizeof(str), "%010"PRId64" 00000 n \n", pos);
1761
0
                stream_puts(pdev->strm, str);
1762
0
            }
1763
0
            if (Offsets)
1764
0
                Offsets[i] = pos;
1765
0
        }
1766
0
    }
1767
0
    return 0;
1768
0
}
1769
1770
static int write_xrefstm_section(gx_device_pdf *pdev, gp_file *tfile, int64_t start, int end, gs_offset_t resource_pos, int offset_size, stream *s)
1771
9.17k
{
1772
9.17k
    int64_t start_offset;
1773
1774
9.17k
    if (pdev->doubleXref)
1775
9.17k
        start_offset = (start - pdev->FirstObjectNumber) * sizeof(gs_offset_t) * 2;
1776
0
    else
1777
0
        start_offset = (start - pdev->FirstObjectNumber) * sizeof(gs_offset_t);
1778
1779
9.17k
    if (gp_fseek(tfile, start_offset, SEEK_SET) == 0)
1780
9.17k
    {
1781
9.17k
        int64_t i, j, r;
1782
1783
164k
        for (i = start; i < end; ++i) {
1784
154k
            gs_offset_t pos, objstm = -1, index = 0;
1785
1786
154k
            r = gp_fread(&pos, sizeof(pos), 1, tfile);
1787
154k
            if (r != 1)
1788
0
                return(gs_note_error(gs_error_ioerror));
1789
1790
154k
            if (pdev->doubleXref) {
1791
154k
                objstm = pos;
1792
154k
                r = gp_fread(&index, sizeof(pos), 1, tfile);
1793
154k
                if (r != 1)
1794
0
                    return(gs_note_error(gs_error_ioerror));
1795
154k
                pos = index;
1796
154k
            }
1797
1798
154k
            if (!pdev->doubleXref || objstm == 0) {
1799
83.5k
                if (pos & ASIDES_BASE_POSITION) {
1800
40.2k
                    pos &= ~ASIDES_BASE_POSITION;
1801
40.2k
                    pos += resource_pos;
1802
40.2k
                }
1803
83.5k
                pos -= pdev->OPDFRead_procset_length;
1804
1805
                /* check to see we haven't got an offset which is too large to represent
1806
                 * in an xref (10 digits). Throw an error if we do.
1807
                 */
1808
83.5k
                if (pos > 9999999999) {
1809
0
                    emprintf(pdev->pdf_memory, "ERROR - Attempt to create an xref entry with more than 10 digits which is illegal.\n");
1810
0
                    emprintf(pdev->pdf_memory, "PDF file production has been aborted.\n");
1811
0
                    return_error(gs_error_rangecheck);
1812
0
                }
1813
83.5k
            }
1814
1815
154k
            if (objstm > 0) {
1816
71.3k
                stream_putc(s, 0x02);
1817
71.3k
                pos = objstm;
1818
71.3k
            }
1819
83.5k
            else
1820
83.5k
                stream_putc(s, 0x01);
1821
493k
            for (j = 1; j <= offset_size; j++)
1822
338k
                stream_putc(s, (pos >> ((offset_size - j) * 8)) & 0xFF);
1823
154k
            stream_putc(s, 0x00);
1824
154k
            if (objstm > 0)
1825
71.3k
                stream_putc(s, index);
1826
83.5k
            else
1827
83.5k
                stream_putc(s, 0x00);
1828
154k
        }
1829
9.17k
    }
1830
9.17k
    return 0;
1831
9.17k
}
1832
1833
static int
1834
rewrite_object(gx_device_pdf *const pdev, pdf_linearisation_t *linear_params, int object)
1835
0
{
1836
0
    uint64_t read, Size;
1837
0
    char c, *Scratch, *source, *target, Buf[280], *next;
1838
0
    int code, ID, ScratchSize=16384;
1839
1840
0
    Size = pdev->ResourceUsage[object].Length;
1841
1842
0
    Scratch = (char *)gs_alloc_bytes(pdev->pdf_memory, ScratchSize, "Working memory for object rewriting");
1843
0
    if (Scratch == 0L)
1844
0
        return (gs_note_error(gs_error_VMerror));
1845
1846
0
    pdev->ResourceUsage[object].LinearisedOffset = gp_ftell(linear_params->Lin_File.file);
1847
0
    code = gp_fseek(linear_params->sfile, pdev->ResourceUsage[object].OriginalOffset, SEEK_SET);
1848
0
    if (code < 0)
1849
0
        return code;
1850
1851
0
    read = 0;
1852
0
    do {
1853
0
        code = gp_fread(&c, 1, 1, linear_params->sfile);
1854
0
        read++;
1855
0
    } while (c != '\n' && code > 0);
1856
0
    gs_snprintf(Scratch, ScratchSize, "%d 0 obj\n", pdev->ResourceUsage[object].NewObjectNumber);
1857
0
    gp_fwrite(Scratch, strlen(Scratch), 1, linear_params->Lin_File.file);
1858
1859
0
    code = gp_fread(&c, 1, 1, linear_params->sfile);
1860
0
    if (code != 1)
1861
0
        return_error(gs_error_ioerror);
1862
1863
0
    read++;
1864
0
    if (c == '<' || c == '[') {
1865
0
        int index = 0;
1866
0
        Scratch[index++] = c;
1867
0
        do {
1868
0
            do {
1869
0
                code = gp_fread(&c, 1, 1, linear_params->sfile);
1870
0
                Scratch[index++] = c;
1871
0
                read++;
1872
0
                if (index == ScratchSize - 2) {
1873
0
                    char *Temp;
1874
1875
0
                    Temp = (char *)gs_alloc_bytes(pdev->pdf_memory, ScratchSize * 2, "Working memory for object rewriting");
1876
0
                    if (Temp == 0L) {
1877
0
                        gs_free_object(pdev->pdf_memory, Scratch, "Free working memory for object rewriting");
1878
0
                        return (gs_note_error(gs_error_VMerror));
1879
0
                    }
1880
0
                    memcpy(Temp, Scratch, ScratchSize);
1881
0
                    gs_free_object(pdev->pdf_memory, Scratch, "Increase working memory for object rewriting");
1882
0
                    Scratch = Temp;
1883
0
                    ScratchSize *= 2;
1884
0
                }
1885
0
            }while (c != '\r' && c != '\n');
1886
0
            Scratch[index] = 0;
1887
0
            if (strncmp(&Scratch[index - 7], "endobj", 6) == 0  || strncmp(&Scratch[index - 7], "stream", 6) == 0)
1888
0
                break;
1889
0
        } while (code);
1890
0
    } else {
1891
0
        Scratch[0] = 0;
1892
0
        gp_fwrite(&c, 1, 1, linear_params->Lin_File.file);
1893
0
    }
1894
1895
0
    Size -= read;
1896
1897
0
    source = Scratch;
1898
0
    do {
1899
0
        target = strstr(source, " 0 R");
1900
0
        if (target) {
1901
0
            next = target + 4;
1902
0
            do {
1903
0
                target--;
1904
0
            }while (*target >= '0' && *target <= '9');
1905
0
            target++;
1906
0
            (void)sscanf(target, "%d 0 R", &ID);
1907
0
            gp_fwrite(source, target - source, 1, linear_params->Lin_File.file);
1908
0
            gs_snprintf(Buf, sizeof(Buf), "%d 0 R", pdev->ResourceUsage[ID].NewObjectNumber);
1909
0
            gp_fwrite(Buf, strlen(Buf), 1, linear_params->Lin_File.file);
1910
0
            source = next;
1911
0
        } else {
1912
0
            gp_fwrite(source, strlen(source), 1, linear_params->Lin_File.file);
1913
0
        }
1914
0
    } while (target);
1915
1916
0
    while (Size) {
1917
0
        if (Size > ScratchSize) {
1918
0
            code = gp_fread(Scratch, ScratchSize, 1, linear_params->sfile);
1919
0
            if (code != 1)
1920
0
        return_error(gs_error_ioerror);
1921
0
            gp_fwrite(Scratch, ScratchSize, 1, linear_params->Lin_File.file);
1922
0
            Size -= ScratchSize;
1923
0
        } else {
1924
0
            code = gp_fread(Scratch, Size, 1, linear_params->sfile);
1925
0
            if (code != 1)
1926
0
        return_error(gs_error_ioerror);
1927
0
            gp_fwrite(Scratch, Size, 1, linear_params->Lin_File.file);
1928
0
            Size = 0;
1929
0
        }
1930
0
    };
1931
1932
0
    gs_free_object(pdev->pdf_memory, Scratch, "Free working memory for object rewriting");
1933
0
    return 0;
1934
0
}
1935
1936
static int flush_hint_stream(pdf_linearisation_t *linear_params)
1937
0
{
1938
0
    int code;
1939
1940
0
    code = gp_fwrite(linear_params->HintBuffer, linear_params->HintByte, 1, linear_params->sfile);
1941
0
    linear_params->HintBits = 0;
1942
0
    linear_params->HintByte = 0;
1943
0
    return code;
1944
0
}
1945
1946
static int write_hint_stream(pdf_linearisation_t *linear_params, gs_offset_t val, char size_bits)
1947
0
{
1948
0
    unsigned int input_mask, output_mask;
1949
1950
0
    if (size_bits == 0)
1951
0
        return 0;
1952
1953
0
    while(size_bits) {
1954
0
        input_mask = 1 << (size_bits - 1);
1955
0
        output_mask = 0x80 >> linear_params->HintBits;
1956
0
        if (input_mask & val)
1957
0
            linear_params->HintBuffer[linear_params->HintByte] |= output_mask;
1958
0
        else
1959
0
            linear_params->HintBuffer[linear_params->HintByte] &= ~output_mask;
1960
0
        size_bits--;
1961
0
        linear_params->HintBits++;
1962
0
        if (linear_params->HintBits == 8) {
1963
0
            linear_params->HintByte++;
1964
0
            if (linear_params->HintByte > 254) {
1965
0
                flush_hint_stream(linear_params);
1966
0
                memset(linear_params->HintBuffer, 0x00, 256);
1967
0
            }
1968
0
            linear_params->HintBits = 0;
1969
0
        }
1970
0
    }
1971
0
    return 0;
1972
0
}
1973
1974
static int pdf_linearise(gx_device_pdf *pdev, pdf_linearisation_t *linear_params)
1975
0
{
1976
0
    char Buffer[1024];
1977
0
    char Header[32], Binary[9] = "%\307\354\217\242\n", LDict[1024], fileID[35], Pad;
1978
0
    int level = (int)(pdev->CompatibilityLevel * 10 + 0.5), i, j;
1979
0
    int code=0, Part1To6 = 2; /* Include space for linearisation dict */
1980
0
    int Part7To8 = 1;
1981
0
    int PartNone = 1;
1982
0
    int Part9 = 1;
1983
0
    int LDictObj, HintStreamObj, k;
1984
0
    char T;
1985
0
    int64_t mainxref, Length, HintStreamLen, HintStreamStart, HintLength, SharedHintOffset;
1986
1987
0
    fileID[0] = '<';
1988
0
    fileID[33] = '>';
1989
0
    fileID[34] = 0x00;
1990
0
    for (i = 0;i< sizeof(pdev->fileID);i++) {
1991
0
        T = pdev->fileID[i] >> 4;
1992
0
        if (T > 9) {
1993
0
            fileID[(i*2) + 1] = T - 10 + 'A';
1994
0
        } else {
1995
0
            fileID[(i*2) + 1] = T + '0';
1996
0
        }
1997
0
        T = pdev->fileID[i] & 0x0f;
1998
0
        if (T > 9) {
1999
0
            fileID[(i*2) + 2] = T - 10 + 'A';
2000
0
        } else {
2001
0
            fileID[(i*2) + 2] = T + '0';
2002
0
        }
2003
0
    }
2004
2005
    /* Make sure we've written everything to the main file */
2006
0
    sflush(pdev->strm);
2007
0
    linear_params->sfile = pdev->file;
2008
0
    linear_params->MainFileEnd = gp_ftell(pdev->file);
2009
2010
0
    linear_params->PageHints = NULL;
2011
0
    linear_params->SharedHints = NULL;
2012
2013
#ifdef LINEAR_DEBUGGING
2014
    code = gx_device_open_output_file((gx_device *)pdev, "/temp/linear.pdf",
2015
                                   true, true, &linear_params->Lin_File.file);
2016
#else
2017
0
    code = pdf_open_temp_file(pdev, &linear_params->Lin_File);
2018
0
#endif
2019
0
    if (code < 0)
2020
0
        return code;
2021
2022
0
    linear_params->Lin_File.strm = 0x0;
2023
2024
    /* Count resources used by page 1 */
2025
0
    linear_params->NumPage1Resources=0;
2026
0
    for (i = 0;i < pdev->ResourceUsageSize; i++) {
2027
0
        if (pdev->ResourceUsage[i].PageUsage == 1)
2028
0
            linear_params->NumPage1Resources++;
2029
0
        if (pdev->ResourceUsage[i].PageUsage == resource_usage_part1_structure)
2030
0
            linear_params->NumPart1StructureResources++;
2031
0
    }
2032
2033
    /* Count resources associated with pages */
2034
0
    linear_params->NumUniquePageResources=0;
2035
0
    linear_params->NumSharedResources=0;
2036
0
    for (i = 0;i < pdev->ResourceUsageSize; i++) {
2037
0
        if (pdev->ResourceUsage[i].PageUsage > 1)
2038
0
            linear_params->NumUniquePageResources++;
2039
0
        if (pdev->ResourceUsage[i].PageUsage == resource_usage_page_shared)
2040
0
            linear_params->NumSharedResources++;
2041
0
    }
2042
2043
    /* Count resources not associated with pages */
2044
0
    linear_params->NumNonPageResources=0;
2045
0
    for (i = 1;i < pdev->ResourceUsageSize; i++) {
2046
0
        if (pdev->ResourceUsage[i].PageUsage == 0)
2047
0
            linear_params->NumNonPageResources++;
2048
0
    }
2049
2050
    /* Count resources not associated with pages */
2051
0
    linear_params->NumPart9Resources=0;
2052
0
    for (i = 0;i < pdev->ResourceUsageSize; i++) {
2053
0
        if (pdev->ResourceUsage[i].PageUsage == resource_usage_part9_structure)
2054
0
            linear_params->NumPart9Resources++;
2055
0
    }
2056
2057
0
    Part1To6 += linear_params->NumUniquePageResources + linear_params->NumSharedResources + linear_params->NumNonPageResources + linear_params->NumPart9Resources;
2058
0
    PartNone += linear_params->NumUniquePageResources + linear_params->NumSharedResources;
2059
0
    Part9 += linear_params->NumUniquePageResources + linear_params->NumSharedResources + linear_params->NumNonPageResources;
2060
0
    LDictObj = linear_params->NumUniquePageResources + linear_params->NumSharedResources + linear_params->NumNonPageResources + linear_params->NumPart9Resources + 1;
2061
2062
    /* Record length and positions of all the objects and calculate the new object number */
2063
0
    for (i = 1;i < pdev->ResourceUsageSize; i++) {
2064
0
        int j;
2065
0
        gs_offset_t end;
2066
2067
0
        pdev->ResourceUsage[i].OriginalOffset = linear_params->Offsets[i];
2068
2069
0
        end = linear_params->xref;
2070
0
        for (j=0;j<=linear_params->LastResource;j++) {
2071
0
            if (linear_params->Offsets[j] > linear_params->Offsets[i] && linear_params->Offsets[j] < end)
2072
0
                end = linear_params->Offsets[j];
2073
0
        }
2074
0
        pdev->ResourceUsage[i].Length = end - linear_params->Offsets[i];
2075
2076
0
        if (pdev->ResourceUsage[i].PageUsage == 1 || pdev->ResourceUsage[i].PageUsage == resource_usage_part1_structure)
2077
0
            pdev->ResourceUsage[i].NewObjectNumber = Part1To6++;
2078
0
        else {
2079
0
            if (pdev->ResourceUsage[i].PageUsage == resource_usage_not_referenced)
2080
0
                pdev->ResourceUsage[i].NewObjectNumber = PartNone++;
2081
0
            else {
2082
0
                if (pdev->ResourceUsage[i].PageUsage == resource_usage_part9_structure)
2083
0
                    pdev->ResourceUsage[i].NewObjectNumber = Part9++;
2084
0
                else
2085
0
                    pdev->ResourceUsage[i].NewObjectNumber = Part7To8++;
2086
0
            }
2087
0
        }
2088
0
    }
2089
0
    gs_free_object(pdev->pdf_memory, linear_params->Offsets, "free temp xref storage");
2090
2091
#ifdef LINEAR_DEBUGGING
2092
    {
2093
    dmprintf6(pdev->pdf_memory, "NumPage1Resources %ld\tNumPart1StructureResources %ld\t\tNumUniquePageResources %ld\tNumSharedResources %ld\t\tNumNonPageResources %d\nNumPart9Resources %ld\n", linear_params->NumPage1Resources, linear_params->NumPart1StructureResources, linear_params->NumUniquePageResources, linear_params->NumSharedResources, linear_params->NumNonPageResources, linear_params->NumPart9Resources);
2094
    dmprintf(pdev->pdf_memory, "Old ID\tPage Usage\tNew ID\n");
2095
    for (i = 1;i < pdev->ResourceUsageSize; i++) {
2096
        dmprintf3(pdev->pdf_memory, "%d\t%d\t%d\n", i, pdev->ResourceUsage[i].PageUsage, pdev->ResourceUsage[i].NewObjectNumber);
2097
    }
2098
    }
2099
#endif
2100
    /* Linearisation. Part 1, file header */
2101
0
    gs_snprintf(Header, sizeof(Header), "%%PDF-%d.%d\n", level / 10, level % 10);
2102
0
    gp_fwrite(Header, strlen(Header), 1, linear_params->Lin_File.file);
2103
0
    if (pdev->binary_ok)
2104
0
        gp_fwrite(Binary, strlen(Binary), 1, linear_params->Lin_File.file);
2105
0
    pdfwrite_fwrite_args_comment(pdev, linear_params->Lin_File.file);
2106
2107
0
    pdf_record_usage(pdev, linear_params->LastResource + 1, resource_usage_part1_structure);
2108
0
    pdev->ResourceUsage[linear_params->LastResource + 1].OriginalOffset = 0;
2109
0
    pdev->ResourceUsage[linear_params->LastResource + 1].NewObjectNumber = LDictObj;
2110
0
    pdev->ResourceUsage[linear_params->LastResource + 1].LinearisedOffset = gp_ftell(linear_params->Lin_File.file);
2111
2112
    /* Linearisation. Part 2, the Linearisation dictioanry */
2113
0
    linear_params->LDictOffset = gp_ftell(linear_params->Lin_File.file);
2114
0
    gs_snprintf(LDict, sizeof(LDict), "%d 0 obj\n<<                                                                                                                        \n",
2115
0
        LDictObj);
2116
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->Lin_File.file);
2117
2118
    /* First page cross-reference table here (Part 3) */
2119
0
    linear_params->FirstxrefOffset = gp_ftell(linear_params->Lin_File.file);
2120
0
    gs_snprintf(Header, sizeof(Header), "xref\n%d %d\n", LDictObj, Part1To6 - LDictObj + 1); /* +1 for the primary hint stream */
2121
0
    gp_fwrite(Header, strlen(Header), 1, linear_params->Lin_File.file);
2122
2123
0
    gs_snprintf(Header, sizeof(Header), "0000000000 00000 n \n");
2124
2125
0
    for (i = LDictObj;i <= linear_params->LastResource + 2; i++) {
2126
0
        gp_fwrite(Header, 20, 1, linear_params->Lin_File.file);
2127
0
    }
2128
2129
    /* Size below is given as the Last Resource in the original file, +1 for object 0 (always free)
2130
     * +1 for the linearisation dict and +1 for the primary hint stream.
2131
     */
2132
0
    linear_params->FirsttrailerOffset = gp_ftell(linear_params->Lin_File.file);
2133
0
    if (pdev->OmitID)
2134
0
        gs_snprintf(LDict, sizeof(LDict), "\ntrailer\n<</Size %"PRId64"/Info %d 0 R/Root %d 0 R/Prev %d>>\nstartxref\r\n0\n%%%%EOF\n        \n",
2135
0
        linear_params->LastResource + 3, pdev->ResourceUsage[linear_params->Info_id].NewObjectNumber, pdev->ResourceUsage[linear_params->Catalog_id].NewObjectNumber, 0);
2136
0
    else
2137
0
        gs_snprintf(LDict, sizeof(LDict), "\ntrailer\n<</Size %"PRId64"/Info %d 0 R/Root %d 0 R/ID[%s%s]/Prev %d>>\nstartxref\r\n0\n%%%%EOF\n        \n",
2138
0
        linear_params->LastResource + 3, pdev->ResourceUsage[linear_params->Info_id].NewObjectNumber, pdev->ResourceUsage[linear_params->Catalog_id].NewObjectNumber, fileID, fileID, 0);
2139
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->Lin_File.file);
2140
2141
    /* Write document catalog (Part 4) */
2142
0
    code = rewrite_object(pdev, linear_params, linear_params->Catalog_id);
2143
0
    if (code < 0)
2144
0
        goto error;
2145
2146
    /* In here we need the ViewerPreferences (don't think we support this),
2147
     * the PageMode entry (I think this would be direct in the catalog), The
2148
     * Threads entry (if any), The OpenAction (again, direct object ?) The
2149
     * AcroForm object (don't think we support this) and (TaDa) the Encrypt entry
2150
     * in the first page trailer dictionary.
2151
     */
2152
2153
    /* First page section (Part 6) NB we do not currently support the OpenAction
2154
     * In the Catalogso this is always page 0, this needs to change if we ever
2155
     * support the OpenAction. The 1.7 PDF Reference says in implementation note 181
2156
     * that Acrobat always treats page 0 as the first page for linearisation purposes
2157
     * EVEN IF there is an OpenAction, so we are Acrobat-compatible :-)
2158
     */
2159
0
    code = rewrite_object(pdev, linear_params, pdev->pages[0].Page->id);
2160
0
    if (code < 0)
2161
0
        goto error;
2162
0
    for (i = 0;i < pdev->ResourceUsageSize; i++) {
2163
        /* we explicitly write the page objct above, make sure when writing the
2164
         * 'objects uniquely used on the page' that we don't write the page object again!
2165
         */
2166
0
        if (pdev->ResourceUsage[i].PageUsage == 1 && i != pdev->pages[0].Page->id) {
2167
0
            code = rewrite_object(pdev, linear_params, i);
2168
0
            if (code < 0)
2169
0
                goto error;
2170
0
        }
2171
0
    }
2172
0
    linear_params->E = gp_ftell(linear_params->Lin_File.file);
2173
2174
    /* Primary Hint Stream here (Part 5)
2175
     * this is a FIXME
2176
     */
2177
0
    HintStreamObj = linear_params->LastResource + 2;
2178
0
    pdf_record_usage(pdev, HintStreamObj, resource_usage_part1_structure);
2179
0
    pdev->ResourceUsage[HintStreamObj].OriginalOffset = 0;
2180
0
    pdev->ResourceUsage[HintStreamObj].NewObjectNumber = HintStreamObj;
2181
0
    pdev->ResourceUsage[HintStreamObj].LinearisedOffset = gp_ftell(linear_params->Lin_File.file);
2182
2183
    /* We don't actually embed the hint stream yet. We will do this when we copy the 'linearised'
2184
     * PDF file from the temp file back to the main file, and will insert the hint stream at this point.
2185
     * We will then know all the offsets of all the objects following the hint stream, so we can
2186
     * write these correctly into the hint stream. Since we will then know the size of the hint
2187
     * stream, we can add this to the stored offsets to generate the 'real' offsets for teh xref.
2188
     */
2189
2190
    /* All remaining pages (part 7) */
2191
0
    for (i = 1;i < pdev->next_page;i++) {
2192
0
        code = rewrite_object(pdev, linear_params, pdev->pages[i].Page->id);
2193
0
        if (code < 0)
2194
0
            goto error;
2195
0
        for (j = 0;j < pdev->ResourceUsageSize; j++) {
2196
            /* we explicitly write the page objct above, make sure when writing the
2197
             * 'objects uniquely used on the page' that we don't write the page object again!
2198
             */
2199
0
            if (pdev->ResourceUsage[j].PageUsage - 1 == i && j != pdev->pages[i].Page->id) {
2200
0
                code = rewrite_object(pdev, linear_params, j);
2201
0
                if (code < 0)
2202
0
                    goto error;
2203
0
            }
2204
0
        }
2205
0
    }
2206
2207
    /* Shared objects for all pages except the first (part 8) */
2208
0
    for (i = 0;i < pdev->ResourceUsageSize; i++) {
2209
0
        if (pdev->ResourceUsage[i].PageUsage == resource_usage_page_shared) {
2210
0
            code = rewrite_object(pdev, linear_params, i);
2211
0
            if (code < 0)
2212
0
                goto error;
2213
0
        }
2214
0
    }
2215
2216
    /* All objects not on any page (Part 9) */
2217
0
    for (i = 1;i < pdev->ResourceUsageSize; i++) {
2218
0
        if (pdev->ResourceUsage[i].PageUsage == resource_usage_not_referenced ||
2219
0
            pdev->ResourceUsage[i].PageUsage == resource_usage_part9_structure) {
2220
0
            code = rewrite_object(pdev, linear_params, i);
2221
0
            if (code < 0)
2222
0
                goto error;
2223
0
        }
2224
0
    }
2225
2226
    /* We won't bother with an overflow hint stream (I Hope) (part 10)
2227
     * Implementation Note 181 in the 1.7 PDF Reference Manual says Acrobat
2228
     * doesn't support overflow hint streams anyway....
2229
     */
2230
2231
    /* Now copy the linearised data back to the main file, as far as the offset of the
2232
     * primary hint stream
2233
     */
2234
0
    if (gp_fseek(linear_params->Lin_File.file, 0, SEEK_SET) != 0) {
2235
0
        code = gs_error_ioerror;
2236
0
        goto error;
2237
0
    }
2238
0
    if (gp_fseek(linear_params->sfile, 0, SEEK_SET) != 0){
2239
0
        code = gs_error_ioerror;
2240
0
        goto error;
2241
0
    }
2242
0
    Length = pdev->ResourceUsage[HintStreamObj].LinearisedOffset;
2243
0
    while (Length && code >= 0) {
2244
0
        if (Length > 1024) {
2245
0
            code = gp_fread(Buffer, 1024, 1, linear_params->Lin_File.file);
2246
0
            gp_fwrite(Buffer, 1024, 1, linear_params->sfile);
2247
0
            Length -= 1024;
2248
0
        } else {
2249
0
            code = gp_fread(Buffer, Length, 1, linear_params->Lin_File.file);
2250
0
            gp_fwrite(Buffer, Length, 1, linear_params->sfile);
2251
0
            Length = 0;
2252
0
        }
2253
0
    }
2254
    /* insert the primary hint stream */
2255
0
    gs_snprintf(LDict, sizeof(LDict), "%d 0 obj\n<</Length           \n/S           >>\nstream\n", HintStreamObj);
2256
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2257
2258
0
    HintStreamStart = gp_ftell(linear_params->sfile);
2259
0
    memset(linear_params->HintBuffer, 0x00, 256);
2260
0
    linear_params->HintBits = linear_params->HintByte = 0;
2261
2262
0
    linear_params->PageHints = (page_hint_stream_t *)gs_alloc_bytes(pdev->pdf_memory, (size_t)(pdev->next_page) * sizeof(page_hint_stream_t), "Hints for the pages");
2263
0
    if (linear_params->PageHints == NULL) {
2264
0
        code = gs_error_VMerror;
2265
0
        goto error;
2266
0
    }
2267
0
    memset(linear_params->PageHints, 0x00, pdev->next_page * sizeof(page_hint_stream_t));
2268
0
    linear_params->NumPageHints = pdev->next_page;
2269
2270
0
    linear_params->SharedHints = (shared_hint_stream_t *)gs_alloc_bytes(pdev->pdf_memory, (size_t)(linear_params->NumPage1Resources + linear_params->NumSharedResources) * sizeof(shared_hint_stream_t), "Hints for the shared objects");
2271
0
    if (linear_params->SharedHints == NULL) {
2272
0
        code = gs_error_VMerror;
2273
0
        goto error;
2274
0
    }
2275
0
    memset(linear_params->SharedHints, 0x00, (linear_params->NumPage1Resources + linear_params->NumSharedResources) * sizeof(shared_hint_stream_t));
2276
0
    linear_params->NumSharedHints = linear_params->NumPage1Resources + linear_params->NumSharedResources;
2277
2278
0
    memset(&linear_params->PageHintHeader,0x00, sizeof(page_hint_stream_header_t));
2279
0
    memset(&linear_params->SharedHintHeader,0x00, sizeof(shared_hint_stream_header_t));
2280
2281
0
    linear_params->PageHintHeader.LeastObjectsPerPage = 0x7fffffff;
2282
0
    linear_params->PageHintHeader.LeastPageLength = 0x7fffffff;
2283
0
    linear_params->PageHintHeader.LeastPageOffset = 0x7fffffff;
2284
0
    linear_params->PageHintHeader.LeastContentLength = 0x7fffffff;
2285
2286
    /* Record the offset and length of the content stream for each page */
2287
0
    for (i=0;i<pdev->next_page;i++) {
2288
0
        int PageContentID = pdev->pages[i].contents_id;
2289
0
        pdf_linearisation_record_t *record = &pdev->ResourceUsage[PageContentID];
2290
0
        page_hint_stream_t *pagehint = &linear_params->PageHints[i];
2291
2292
0
        pagehint->ContentOffset = record->LinearisedOffset;
2293
0
        pagehint->ContentLength = record->Length;
2294
0
    }
2295
2296
    /* For every object, record it in the page hints and shared hints. k is a counter
2297
     * of the current shared object, we increment it each time we find a new one.
2298
     */
2299
0
    k = 0;
2300
0
    for (i = 1;i < pdev->ResourceUsageSize; i++) {
2301
0
        pdf_linearisation_record_t *record = &pdev->ResourceUsage[i];
2302
2303
0
        if (record->PageUsage < resource_usage_page_shared || record->PageUsage == resource_usage_not_referenced)
2304
0
            continue;
2305
0
        if (record->PageUsage == resource_usage_page_shared) {
2306
            /* shared objects are recorded in the shared object hints, and also the page hints */
2307
0
            for (j=0;j<record->NumPagesUsing;j++) {
2308
0
                int page = record->PageList[j];
2309
0
                page_hint_stream_t *pagehint;
2310
2311
0
                if (page >= pdev->next_page)
2312
                    /* This can happen if the job makes marks, but does not call showpage */
2313
0
                    continue;
2314
2315
0
                pagehint = &linear_params->PageHints[page - 1];
2316
0
                if (pagehint->SharedObjectRef){
2317
0
                    int *Temp = (int *)gs_alloc_bytes(pdev->pdf_memory, (size_t)(pagehint->NumSharedObjects + 1) * sizeof(int), "realloc shared object hints");
2318
0
                    if (Temp == NULL) {
2319
0
                        code = gs_note_error(gs_error_VMerror);
2320
0
                        goto error;
2321
0
                    }
2322
0
                    memcpy(Temp, pagehint->SharedObjectRef, (pagehint->NumSharedObjects) * sizeof(int));
2323
0
                    gs_free_object(pdev->pdf_memory, pagehint->SharedObjectRef, "realloc shared object hints");
2324
0
                    pagehint->SharedObjectRef = (unsigned int *)Temp;
2325
0
                } else {
2326
0
                    pagehint->SharedObjectRef = (unsigned int *)gs_alloc_bytes(pdev->pdf_memory, (size_t)(pagehint->NumSharedObjects + 1) * sizeof(int), "shared object hints");
2327
0
                    if (pagehint->SharedObjectRef == NULL) {
2328
0
                        code = gs_note_error(gs_error_VMerror);
2329
0
                        goto error;
2330
0
                    }
2331
0
                }
2332
0
                pagehint->SharedObjectRef[pagehint->NumSharedObjects] = i;
2333
0
                pagehint->NumSharedObjects++;
2334
0
            }
2335
0
            linear_params->SharedHints[k].ObjectNumber = record->NewObjectNumber;
2336
0
            linear_params->SharedHints[k].ObjectOffset = record->LinearisedOffset;
2337
0
            linear_params->SharedHints[k++].ObjectLength = record->Length;
2338
0
        } else {
2339
            /* Objects uniquely used on a page are stored in the page hints table, except
2340
             * page 1 whose objects are *also* stored in the shared objects hints.
2341
             */
2342
0
            int page = record->PageUsage, pageID = pdev->pages[page - 1].Page->id;
2343
0
            int64_t LinearisedPageOffset = pdev->ResourceUsage[pageID].LinearisedOffset;
2344
0
            page_hint_stream_t *pagehint;
2345
2346
            /* If the final page makes marks but does not call showpage we don't emit it
2347
             * which can lead to references to non-existent pages.
2348
             */
2349
0
            if (page <= pdev->next_page) {
2350
0
                pagehint = &linear_params->PageHints[page - 1];
2351
0
                pagehint->NumUniqueObjects++;
2352
0
                if (record->LinearisedOffset - LinearisedPageOffset > pagehint->PageLength)
2353
0
                    pagehint->PageLength = (record->LinearisedOffset + record->Length) - LinearisedPageOffset;
2354
0
                if (page == 1) {
2355
0
                    linear_params->SharedHintHeader.FirstPageEntries++;
2356
0
                }
2357
0
            }
2358
0
        }
2359
0
    }
2360
2361
0
    linear_params->PageHintHeader.LargestSharedObject = k;
2362
2363
0
    for (i = 0;i < linear_params->NumPageHints;i++) {
2364
0
        page_hint_stream_t *hint = &linear_params->PageHints[i];
2365
2366
0
        if (hint->NumUniqueObjects + hint->NumSharedObjects < linear_params->PageHintHeader.LeastObjectsPerPage)
2367
0
            linear_params->PageHintHeader.LeastObjectsPerPage = hint->NumUniqueObjects + hint->NumSharedObjects;
2368
0
        if (hint->NumUniqueObjects + hint->NumSharedObjects > linear_params->PageHintHeader.MostObjectsPerPage)
2369
0
            linear_params->PageHintHeader.MostObjectsPerPage = hint->NumUniqueObjects + hint->NumSharedObjects;
2370
0
        if (hint->PageLength < linear_params->PageHintHeader.LeastPageLength)
2371
0
            linear_params->PageHintHeader.LeastPageLength = hint->PageLength;
2372
0
        if (hint->PageLength > linear_params->PageHintHeader.MostPageLength)
2373
0
            linear_params->PageHintHeader.MostPageLength = hint->PageLength;
2374
0
        if (hint->ContentOffset < linear_params->PageHintHeader.LeastPageOffset)
2375
0
            linear_params->PageHintHeader.LeastPageOffset = hint->ContentOffset;
2376
0
        if (hint->ContentOffset > linear_params->PageHintHeader.MostPageOffset)
2377
0
            linear_params->PageHintHeader.MostPageOffset = hint->ContentOffset;
2378
0
        if (hint->ContentLength < linear_params->PageHintHeader.LeastContentLength)
2379
0
            linear_params->PageHintHeader.LeastContentLength = hint->ContentLength;
2380
0
        if (hint->ContentLength > linear_params->PageHintHeader.MostContentLength)
2381
0
            linear_params->PageHintHeader.MostContentLength = hint->ContentLength;
2382
0
        if (hint->NumSharedObjects > linear_params->PageHintHeader.MostSharedObjects)
2383
0
            linear_params->PageHintHeader.MostSharedObjects = hint->NumSharedObjects;
2384
0
    }
2385
2386
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->PageHintHeader.LeastObjectsPerPage, 32);
2387
0
    write_hint_stream(linear_params, (gs_offset_t)pdev->ResourceUsage[pdev->pages[0].Page->id].LinearisedOffset, 32);
2388
0
    i = (linear_params->PageHintHeader.MostObjectsPerPage - linear_params->PageHintHeader.MostObjectsPerPage + 1);
2389
0
    j = 0;
2390
0
    while (i) {
2391
0
        i = i / 2;
2392
0
        j++;
2393
0
    }
2394
0
    linear_params->PageHintHeader.ObjectNumBits = j;
2395
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->PageHintHeader.ObjectNumBits, 16);
2396
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->PageHintHeader.LeastPageLength, 32);
2397
0
    i = (linear_params->PageHintHeader.MostPageLength - linear_params->PageHintHeader.LeastPageLength + 1);
2398
0
    j = 0;
2399
0
    while (i) {
2400
0
        i = i / 2;
2401
0
        j++;
2402
0
    }
2403
0
    linear_params->PageHintHeader.PageLengthNumBits = j;
2404
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->PageHintHeader.PageLengthNumBits, 16);
2405
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->PageHintHeader.LeastPageOffset, 32);
2406
0
    i = (linear_params->PageHintHeader.MostPageOffset - linear_params->PageHintHeader.LeastPageOffset + 1);
2407
0
    j = 0;
2408
0
    while (i) {
2409
0
        i = i / 2;
2410
0
        j++;
2411
0
    }
2412
0
    linear_params->PageHintHeader.PageOffsetNumBits = j;
2413
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->PageHintHeader.PageOffsetNumBits, 16);
2414
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->PageHintHeader.LeastContentLength, 32);
2415
0
    i = (linear_params->PageHintHeader.MostContentLength - linear_params->PageHintHeader.LeastContentLength + 1);
2416
0
    j = 0;
2417
0
    while (i) {
2418
0
        i = i / 2;
2419
0
        j++;
2420
0
    }
2421
0
    linear_params->PageHintHeader.ContentLengthNumBits = j;
2422
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->PageHintHeader.ContentLengthNumBits, 16);
2423
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->PageHintHeader.MostSharedObjects, 16);
2424
0
    i = (linear_params->PageHintHeader.LargestSharedObject + 1);
2425
0
    j = 0;
2426
0
    while (i) {
2427
0
        i = i / 2;
2428
0
        j++;
2429
0
    }
2430
0
    linear_params->PageHintHeader.SharedObjectNumBits = j;
2431
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->PageHintHeader.SharedObjectNumBits, 16);
2432
0
    j = 1;
2433
0
    write_hint_stream(linear_params, (gs_offset_t)j, 16);
2434
0
    write_hint_stream(linear_params, (gs_offset_t)j, 16);
2435
2436
#ifdef LINEAR_DEBUGGING
2437
    dmprintf1(pdev->pdf_memory, "LeastObjectsPerPage %d\n", linear_params->PageHintHeader.LeastObjectsPerPage);
2438
    dmprintf1(pdev->pdf_memory, "Page 1 Offset %"PRId64"\n", pdev->ResourceUsage[pdev->pages[0].Page->id].LinearisedOffset);
2439
    dmprintf1(pdev->pdf_memory, "ObjectNumBits %d\n", linear_params->PageHintHeader.ObjectNumBits);
2440
    dmprintf1(pdev->pdf_memory, "LeastPageLength %d\n", linear_params->PageHintHeader.LeastPageLength);
2441
    dmprintf1(pdev->pdf_memory, "MostPagelength %d\n", linear_params->PageHintHeader.MostPageLength);
2442
    dmprintf1(pdev->pdf_memory, "PaegLengthNumBits %d\n", linear_params->PageHintHeader.PageLengthNumBits);
2443
    dmprintf1(pdev->pdf_memory, "LeastPageOffset %d\n", linear_params->PageHintHeader.LeastPageOffset);
2444
    dmprintf1(pdev->pdf_memory, "MostPageOffset %d\n", linear_params->PageHintHeader.MostPageOffset);
2445
    dmprintf1(pdev->pdf_memory, "PageOffsetNumBits %d\n", linear_params->PageHintHeader.PageOffsetNumBits);
2446
    dmprintf1(pdev->pdf_memory, "LeastContentLength %d\n", linear_params->PageHintHeader.LeastContentLength);
2447
    dmprintf1(pdev->pdf_memory, "MostContentLength %d\n", linear_params->PageHintHeader.MostContentLength);
2448
    dmprintf1(pdev->pdf_memory, "COntentLengthNumBits %d\n", linear_params->PageHintHeader.ContentLengthNumBits);
2449
    dmprintf1(pdev->pdf_memory, "MostSharedObjects %d\n", linear_params->PageHintHeader.MostSharedObjects);
2450
    dmprintf1(pdev->pdf_memory, "LargetsSharedObject %d\n", linear_params->PageHintHeader.LargestSharedObject);
2451
    dmprintf1(pdev->pdf_memory, "SharedObjectNumBits %d\n", linear_params->PageHintHeader.SharedObjectNumBits);
2452
    dmprintf(pdev->pdf_memory, "Position Numerator 1\n");
2453
    dmprintf(pdev->pdf_memory, "Position Denominator 1\n\n");
2454
#endif
2455
2456
0
    for (i=0;i < pdev->next_page;i++) {
2457
0
        page_hint_stream_t *hint = &linear_params->PageHints[i];
2458
0
        int Num;
2459
2460
0
        Num = hint->NumUniqueObjects - linear_params->PageHintHeader.LeastObjectsPerPage;
2461
0
        write_hint_stream(linear_params, (gs_offset_t)Num, linear_params->PageHintHeader.ObjectNumBits);
2462
0
        dmprintf2(pdev->pdf_memory, "Page %d NumUniqueObjects %d\n", i, Num);
2463
0
    }
2464
0
    for (i=0;i < pdev->next_page;i++) {
2465
0
        page_hint_stream_t *hint = &linear_params->PageHints[i];
2466
0
        int Num;
2467
2468
0
        Num = hint->PageLength - linear_params->PageHintHeader.LeastPageLength;
2469
0
        write_hint_stream(linear_params, (gs_offset_t)Num, linear_params->PageHintHeader.PageLengthNumBits);
2470
0
        dmprintf2(pdev->pdf_memory, "Page %d PageLength %d\n", i, Num);
2471
0
    }
2472
0
    for (i=0;i < pdev->next_page;i++) {
2473
0
        page_hint_stream_t *hint = &linear_params->PageHints[i];
2474
2475
0
        if (i == 0) {
2476
0
            write_hint_stream(linear_params, (gs_offset_t)i, linear_params->PageHintHeader.SharedObjectNumBits);
2477
0
            dmprintf2(pdev->pdf_memory, "Page %d NumSharedObjects %d\n", i, 1);
2478
0
        }
2479
0
        else {
2480
0
            write_hint_stream(linear_params, (gs_offset_t)hint->NumSharedObjects, linear_params->PageHintHeader.SharedObjectNumBits);
2481
0
            dmprintf2(pdev->pdf_memory, "Page %d NumSharedObjects %d\n", i, hint->NumSharedObjects);
2482
0
        }
2483
0
    }
2484
0
    for (i=1;i < pdev->next_page;i++) {
2485
0
        page_hint_stream_t *hint = &linear_params->PageHints[i];
2486
2487
0
        for (j=0;j < hint->NumSharedObjects;j++) {
2488
0
            write_hint_stream(linear_params, (gs_offset_t)hint->SharedObjectRef[j], linear_params->PageHintHeader.SharedObjectNumBits);
2489
0
            dmprintf3(pdev->pdf_memory, "Page %d SharedObject %d ObjectRef %d\n", i, j, hint->SharedObjectRef[j]);
2490
0
        }
2491
0
    }
2492
2493
0
    for (i=0;i < pdev->next_page;i++) {
2494
0
        page_hint_stream_t *hint = &linear_params->PageHints[i];
2495
2496
0
        for (j=0;j < hint->NumSharedObjects;j++) {
2497
0
            write_hint_stream(linear_params, (gs_offset_t)j, 1);
2498
0
            dmprintf2(pdev->pdf_memory, "Page %d SharedObject %d Position Numerator 1\n", i, j);
2499
0
        }
2500
0
    }
2501
0
    for (i=1;i < pdev->next_page;i++) {
2502
0
        page_hint_stream_t *hint = &linear_params->PageHints[i];
2503
0
        int Num;
2504
2505
0
        Num = hint->ContentOffset - linear_params->PageHintHeader.LeastPageOffset;
2506
0
        write_hint_stream(linear_params, (gs_offset_t)Num, linear_params->PageHintHeader.PageOffsetNumBits);
2507
0
        dmprintf2(pdev->pdf_memory, "Page %d ContentStreamOffset %d\n", i, Num);
2508
0
    }
2509
0
    for (i=1;i < pdev->next_page;i++) {
2510
0
        page_hint_stream_t *hint = &linear_params->PageHints[i];
2511
0
        int Num;
2512
2513
0
        Num = hint->ContentLength - linear_params->PageHintHeader.LeastContentLength;
2514
0
        write_hint_stream(linear_params, (gs_offset_t)Num, linear_params->PageHintHeader.ContentLengthNumBits);
2515
0
        dmprintf2(pdev->pdf_memory, "Page %d ContentStreamLength %d\n", i, Num);
2516
0
    }
2517
0
    flush_hint_stream(linear_params);
2518
2519
0
    SharedHintOffset = gp_ftell(linear_params->sfile) - HintStreamStart;
2520
0
    linear_params->SharedHintHeader.FirstSharedObject = linear_params->SharedHints[0].ObjectNumber;
2521
0
    linear_params->SharedHintHeader.LeastObjectLength = linear_params->SharedHints[0].ObjectLength;
2522
0
    linear_params->SharedHintHeader.MostObjectLength = linear_params->SharedHints[0].ObjectLength;
2523
2524
0
    for (i = 1; i< linear_params->NumSharedHints; i++) {
2525
0
        if (linear_params->SharedHints[i].ObjectNumber < linear_params->SharedHintHeader.FirstSharedObject) {
2526
0
            linear_params->SharedHintHeader.FirstSharedObject = linear_params->SharedHints[1].ObjectNumber;
2527
0
            linear_params->SharedHintHeader.FirstObjectOffset = linear_params->SharedHints[1].ObjectOffset;
2528
0
        }
2529
0
        if (linear_params->SharedHints[i].ObjectLength < linear_params->SharedHintHeader.LeastObjectLength) {
2530
0
            linear_params->SharedHintHeader.LeastObjectLength = linear_params->SharedHints[i].ObjectLength;
2531
0
        }
2532
0
        if (linear_params->SharedHints[i].ObjectLength > linear_params->SharedHintHeader.MostObjectLength) {
2533
0
            linear_params->SharedHintHeader.MostObjectLength = linear_params->SharedHints[i].ObjectLength;
2534
0
        }
2535
0
    }
2536
2537
0
    linear_params->SharedHintHeader.FirstPageEntries = linear_params->NumPage1Resources;
2538
0
    linear_params->SharedHintHeader.NumSharedObjects = linear_params->NumSharedResources + linear_params->SharedHintHeader.FirstPageEntries;
2539
2540
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->SharedHintHeader.FirstSharedObject, 32);
2541
0
    dmprintf1(pdev->pdf_memory, "\nFirstSharedObject %d\n", linear_params->SharedHintHeader.FirstSharedObject);
2542
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->SharedHintHeader.FirstObjectOffset, 32);
2543
0
    dmprintf1(pdev->pdf_memory, "FirstObjectOffset %"PRId64"\n", linear_params->SharedHintHeader.FirstObjectOffset);
2544
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->SharedHintHeader.FirstPageEntries, 32);
2545
0
    dmprintf1(pdev->pdf_memory, "FirstPageEntries %d\n", linear_params->SharedHintHeader.FirstPageEntries);
2546
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->SharedHintHeader.NumSharedObjects, 32);
2547
0
    dmprintf1(pdev->pdf_memory, "NumSharedObjects %d\n", linear_params->SharedHintHeader.NumSharedObjects);
2548
0
    j = 1;
2549
0
    write_hint_stream(linear_params, (gs_offset_t)j, 32);
2550
0
    dmprintf(pdev->pdf_memory, "GreatestObjectsNumBits 1\n");
2551
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->SharedHintHeader.FirstObjectOffset, 16);
2552
0
    dmprintf1(pdev->pdf_memory, "FirstObjectOffset %"PRId64"\n", linear_params->SharedHintHeader.FirstObjectOffset);
2553
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->SharedHintHeader.LeastObjectLength, 32);
2554
0
    dmprintf1(pdev->pdf_memory, "LeastObjectLength %d\n", linear_params->SharedHintHeader.LeastObjectLength);
2555
2556
0
    i = (linear_params->SharedHintHeader.MostObjectLength - linear_params->SharedHintHeader.LeastObjectLength + 1) / 2;
2557
0
    j = 0;
2558
0
    while (i) {
2559
0
        i = i / 2;
2560
0
        j++;
2561
0
    }
2562
0
    linear_params->SharedHintHeader.LengthNumBits = j + 1;
2563
0
    write_hint_stream(linear_params, (gs_offset_t)linear_params->SharedHintHeader.LengthNumBits, 16);
2564
2565
0
    for (i = 0; i< linear_params->NumSharedHints; i++) {
2566
0
        unsigned int Length = linear_params->SharedHints[i].ObjectLength - linear_params->SharedHintHeader.LeastObjectLength;
2567
2568
0
        write_hint_stream(linear_params, (gs_offset_t)Length, linear_params->SharedHintHeader.LengthNumBits);
2569
0
        dmprintf2(pdev->pdf_memory, "Shared Object group %d, Length %d\n", i, Length);
2570
0
    }
2571
2572
0
    j = 0;
2573
0
    for (i = 0; i< linear_params->NumSharedHints; i++) {
2574
0
        write_hint_stream(linear_params, (gs_offset_t)j, 1);
2575
0
        dmprintf1(pdev->pdf_memory, "Shared Object group %d, SignatureFlag false\n", i);
2576
0
    }
2577
0
    for (i = 0; i< linear_params->NumSharedHints; i++) {
2578
0
        write_hint_stream(linear_params, (gs_offset_t)j, 1);
2579
0
        dmprintf1(pdev->pdf_memory, "Shared Object group %d, NumObjects 1\n", i);
2580
0
    }
2581
2582
0
    flush_hint_stream(linear_params);
2583
0
    HintLength = gp_ftell(linear_params->sfile) - HintStreamStart;
2584
2585
0
    gs_snprintf(LDict, sizeof(LDict), "\nendstream\nendobj\n");
2586
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2587
    /* Calculate the length of the primary hint stream */
2588
0
    HintStreamLen = gp_ftell(linear_params->sfile) - pdev->ResourceUsage[HintStreamObj].LinearisedOffset;
2589
    /* Read remainder of linearised file and write to the final file */
2590
0
    do {
2591
0
        code = gp_fread(Buffer, 1, 1024, linear_params->Lin_File.file);
2592
0
        if (code > 0)
2593
0
            gp_fwrite(Buffer, 1, code, linear_params->sfile);
2594
0
    } while (code > 0);
2595
2596
    /* Main xref (part 11) */
2597
0
    mainxref = gp_ftell(linear_params->sfile);
2598
    /* Acrobat 9 and X (possibly other versions) won't recognise a file as
2599
     * optimised unless the file is at least 4k bytes in length (!!!)
2600
     * Also, it is possible that the new file might be smaller than the old one, If a
2601
     * frequently used object changed to a lower number (eg form object 100 to object 10)
2602
     * We don't close and reopen the file, so we need to make sure that any difference
2603
     * is filled in with white space.
2604
     */
2605
0
    if (linear_params->MainFileEnd < 4096)
2606
0
        Length = 4096 - (mainxref + strlen(LDict) + strlen(Header) + LDictObj * 20);
2607
0
    else
2608
0
        Length = linear_params->MainFileEnd - (mainxref + strlen(LDict) + strlen(Header) + LDictObj * 20);
2609
0
    Pad = ' ';
2610
2611
0
    while(Length > 0) {
2612
0
        gp_fwrite(&Pad, 1, 1, linear_params->sfile);
2613
0
        Length--;
2614
0
    }
2615
2616
    /* Now the file is long enough, write the xref */
2617
0
    mainxref = gp_ftell(linear_params->sfile);
2618
0
    gs_snprintf(Header, sizeof(Header), "xref\n0 %d\n", LDictObj);
2619
0
    gp_fwrite(Header, strlen(Header), 1, linear_params->sfile);
2620
2621
0
    linear_params->T = gp_ftell(linear_params->sfile) - 1;
2622
0
    gs_snprintf(Header, sizeof(Header), "0000000000 65535 f \n");
2623
0
    gp_fwrite(Header, strlen(Header), 1, linear_params->sfile);
2624
2625
0
    for (i = 1;i < LDictObj; i++) {
2626
0
        for (j = 0; j < pdev->ResourceUsageSize;j++) {
2627
0
            if (pdev->ResourceUsage[j].NewObjectNumber == i) {
2628
0
                gs_snprintf(Header, sizeof(Header), "%010"PRId64" 00000 n \n", pdev->ResourceUsage[j].LinearisedOffset + HintStreamLen);
2629
0
                gp_fwrite(Header, 20, 1, linear_params->sfile);
2630
0
            }
2631
0
        }
2632
0
    }
2633
2634
0
    gs_snprintf(LDict, sizeof(LDict), "trailer\n<</Size %d>>\nstartxref\n%"PRId64"\n%%%%EOF\n",
2635
0
        LDictObj, linear_params->FirstxrefOffset);
2636
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2637
2638
0
    linear_params->FileLength = gp_ftell(linear_params->sfile);
2639
    /* Return to the linearisation dictionary and write it again filling
2640
     * in the missing data.
2641
     */
2642
    /* Implementation Note 178 in the PDF Reference 1.7 says that Acrobat requires
2643
     * a white space after the '[' for the hint stream offset. This appears not to be true
2644
     * for current versions, but we follow it anyway for the possible benefit of older
2645
     * versions.
2646
     */
2647
0
    gp_fseek(linear_params->sfile, linear_params->LDictOffset, SEEK_SET);
2648
0
    gs_snprintf(LDict, sizeof(LDict), "%d 0 obj\n<</Linearized 1/L %"PRId64"/H[ ", LDictObj, linear_params->FileLength);
2649
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2650
2651
0
    gs_snprintf(LDict, sizeof(LDict), "%"PRId64"", pdev->ResourceUsage[HintStreamObj].LinearisedOffset);
2652
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2653
0
    gs_snprintf(LDict, sizeof(LDict), " %"PRId64"]", HintStreamLen);
2654
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2655
    /* Implementation Note 180 in hte PDF Reference 1.7 says that Acrobat
2656
     * gets the 'E' value wrong. So its probably not important....
2657
     */
2658
0
    gs_snprintf(LDict, sizeof(LDict), "/O %d/E %"PRId64"",pdev->ResourceUsage[pdev->pages[0].Page->id].NewObjectNumber, linear_params->E);
2659
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2660
0
    gs_snprintf(LDict, sizeof(LDict), "/N %d/T %"PRId64">>\nendobj\n", pdev->next_page, linear_params->T);
2661
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2662
2663
    /* Return to the secondary xref and write it again filling
2664
     * in the missing offsets.
2665
     */
2666
0
    if (gp_fseek(linear_params->sfile, linear_params->FirstxrefOffset, SEEK_SET) != 0) {
2667
0
        code = gs_error_ioerror;
2668
0
        goto error;
2669
0
    }
2670
0
    gs_snprintf(Header, sizeof(Header), "xref\n%d %d\n", LDictObj, Part1To6 - LDictObj + 1); /* +1 for the primary hint stream */
2671
0
    gp_fwrite(Header, strlen(Header), 1, linear_params->sfile);
2672
2673
0
    for (i = LDictObj;i <= linear_params->LastResource + 2; i++) {
2674
0
        for (j = 0; j < pdev->ResourceUsageSize;j++) {
2675
0
            if (pdev->ResourceUsage[j].NewObjectNumber == i) {
2676
0
                gs_snprintf(Header, sizeof(Header), "%010"PRId64" 00000 n \n", pdev->ResourceUsage[j].LinearisedOffset);
2677
0
                gp_fwrite(Header, 20, 1, linear_params->sfile);
2678
0
            }
2679
0
        }
2680
0
    }
2681
2682
    /* Return to the secondary trailer dict and write it again filling
2683
     * in the missing values.
2684
     */
2685
0
    code = gp_fseek(linear_params->sfile, linear_params->FirsttrailerOffset, SEEK_SET);
2686
0
    if (code != 0)
2687
0
        return_error(gs_error_ioerror);
2688
2689
0
    if (pdev->OmitID)
2690
0
        gs_snprintf(LDict, sizeof(LDict), "\ntrailer\n<</Size %"PRId64"/Info %d 0 R/Root %d 0 R/Prev %"PRId64">>\nstartxref\r\n0\n%%%%EOF\n",
2691
0
        linear_params->LastResource + 3, pdev->ResourceUsage[linear_params->Info_id].NewObjectNumber, pdev->ResourceUsage[linear_params->Catalog_id].NewObjectNumber, mainxref);
2692
0
    else
2693
0
        gs_snprintf(LDict, sizeof(LDict), "\ntrailer\n<</Size %"PRId64"/Info %d 0 R/Root %d 0 R/ID[%s%s]/Prev %"PRId64">>\nstartxref\r\n0\n%%%%EOF\n",
2694
0
        linear_params->LastResource + 3, pdev->ResourceUsage[linear_params->Info_id].NewObjectNumber, pdev->ResourceUsage[linear_params->Catalog_id].NewObjectNumber, fileID, fileID, mainxref);
2695
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2696
2697
0
    code = gp_fseek(linear_params->sfile, pdev->ResourceUsage[HintStreamObj].LinearisedOffset, SEEK_SET);
2698
0
    if (code != 0)
2699
0
        return_error(gs_error_ioerror);
2700
2701
0
    gs_snprintf(LDict, sizeof(LDict), "%d 0 obj\n<</Length %10"PRId64"", HintStreamObj, HintLength);
2702
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2703
0
    gs_snprintf(LDict, sizeof(LDict), "\n/S %10"PRId64">>\nstream\n", SharedHintOffset);
2704
0
    gp_fwrite(LDict, strlen(LDict), 1, linear_params->sfile);
2705
2706
0
error:
2707
#ifdef LINEAR_DEBUGGING
2708
    fclose(linear_params->Lin_File.file);
2709
#else
2710
0
    pdf_close_temp_file(pdev, &linear_params->Lin_File, code);
2711
0
#endif
2712
        /* FIXME free all the linearisation records */
2713
2714
0
    if (linear_params->PageHints != NULL) {
2715
0
        for (i=0;i<pdev->next_page;i++) {
2716
0
            page_hint_stream_t *pagehint = &linear_params->PageHints[i];
2717
2718
0
            if (pagehint && pagehint->SharedObjectRef)
2719
0
                gs_free_object(pdev->pdf_memory, pagehint->SharedObjectRef, "Free Shared object references");
2720
0
        }
2721
0
    }
2722
2723
0
    gs_free_object(pdev->pdf_memory, linear_params->PageHints, "Free Page Hint data");
2724
0
    gs_free_object(pdev->pdf_memory, linear_params->SharedHints, "Free Shared hint data");
2725
2726
0
    return code;
2727
0
}
2728
2729
int pdf_record_usage(gx_device_pdf *const pdev, int64_t resource_id, int page_num)
2730
247k
{
2731
247k
    int i;
2732
247k
    void *Temp;
2733
247k
    pdf_linearisation_record_t *resize;
2734
2735
247k
    if (!pdev->Linearise)
2736
247k
        return 0;
2737
2738
0
    if (resource_id < 0)
2739
0
        return 0;
2740
2741
0
    if (resource_id >= pdev->ResourceUsageSize) {
2742
0
        if (pdev->ResourceUsageSize == 0) {
2743
0
            pdev->ResourceUsageSize = resource_id + 1;
2744
0
            pdev->ResourceUsage = gs_alloc_struct_array(pdev->pdf_memory->non_gc_memory, resource_id + 1, pdf_linearisation_record_t,
2745
0
                              &st_pdf_linearisation_record_element, "start resource usage array");
2746
0
            if (pdev->ResourceUsage == NULL)
2747
0
                return_error(gs_error_VMerror);
2748
0
            memset((char *)pdev->ResourceUsage, 0x00, (resource_id + 1) * sizeof(pdf_linearisation_record_t));
2749
0
        } else {
2750
0
            resize = gs_resize_object(pdev->pdf_memory->non_gc_memory, pdev->ResourceUsage, resource_id + 1, "resize resource usage array");
2751
0
            if (resize == NULL)
2752
0
                return_error(gs_error_VMerror);
2753
0
            memset(&resize[pdev->ResourceUsageSize], 0x00, sizeof(pdf_linearisation_record_t) * (resource_id - pdev->ResourceUsageSize + 1));
2754
0
            pdev->ResourceUsageSize = resource_id + 1;
2755
0
            pdev->ResourceUsage = resize;
2756
0
        }
2757
0
    }
2758
0
    if (page_num > 0) {
2759
0
        if (pdev->ResourceUsage[resource_id].PageUsage == 0)
2760
0
            pdev->ResourceUsage[resource_id].PageUsage = page_num;
2761
0
        else {
2762
0
            if (pdev->ResourceUsage[resource_id].PageUsage > 1)
2763
0
                pdev->ResourceUsage[resource_id].PageUsage = resource_usage_page_shared;
2764
0
            else {
2765
                /* Should not happen, raise an error */
2766
0
            }
2767
0
        }
2768
0
    } else {
2769
0
        if (pdev->ResourceUsage[resource_id].PageUsage != 0)
2770
           /* Should not happen, raise an error */
2771
0
            ;
2772
0
        pdev->ResourceUsage[resource_id].PageUsage = page_num;
2773
0
    }
2774
2775
    /* First check we haven't already recorded this Resource being used by this page */
2776
0
    if (pdev->ResourceUsage[resource_id].NumPagesUsing != 0) {
2777
0
        for (i=0;i < pdev->ResourceUsage[resource_id].NumPagesUsing; i++) {
2778
0
            if (pdev->ResourceUsage[resource_id].PageList[i] == page_num)
2779
0
                return 0;
2780
0
        }
2781
0
    }
2782
0
    Temp = gs_alloc_bytes(pdev->pdf_memory->non_gc_memory, (size_t)(pdev->ResourceUsage[resource_id].NumPagesUsing + 1) * sizeof (int), "Page usage records");
2783
0
    if (Temp == NULL)
2784
0
        return_error(gs_error_VMerror);
2785
0
    memset((char *)Temp, 0x00, (pdev->ResourceUsage[resource_id].NumPagesUsing + 1) * sizeof (int));
2786
0
    memcpy((char *)Temp, pdev->ResourceUsage[resource_id].PageList, pdev->ResourceUsage[resource_id].NumPagesUsing * sizeof (int));
2787
0
    gs_free_object(pdev->pdf_memory->non_gc_memory, (byte *)pdev->ResourceUsage[resource_id].PageList, "Free old page usage records");
2788
0
    pdev->ResourceUsage[resource_id].PageList = (int *)Temp;
2789
0
    pdev->ResourceUsage[resource_id].PageList[pdev->ResourceUsage[resource_id].NumPagesUsing] = page_num;
2790
0
    pdev->ResourceUsage[resource_id].NumPagesUsing++;
2791
2792
0
    return 0;
2793
0
}
2794
2795
int pdf_record_usage_by_parent(gx_device_pdf *const pdev, int64_t resource_id, int64_t parent_id)
2796
97.9k
{
2797
97.9k
    int i;
2798
97.9k
    if (!pdev->Linearise)
2799
97.9k
        return 0;
2800
2801
0
    if (pdev->ResourceUsage[parent_id].PageUsage >= 0)
2802
0
        pdf_record_usage(pdev, resource_id, pdev->ResourceUsage[parent_id].PageUsage);
2803
0
    else {
2804
0
        for (i = 0; i < pdev->ResourceUsage[parent_id].NumPagesUsing; i++) {
2805
0
            pdf_record_usage(pdev, resource_id, pdev->ResourceUsage[parent_id].PageList[i]);
2806
0
        }
2807
0
    }
2808
0
    return 0;
2809
97.9k
}
2810
2811
/* This routine is related to the PCL interpreter. Because of the way that
2812
 * PCL pass through works, the PCL interpreter can shut down and free its font cache
2813
 * while still running. This leaves us with copies of fonts, which point to a now
2814
 * freed font cache. Large parts of the code which retrieve font information require
2815
 * that the font cache be present, and fail badly if it isn't. So we construct a
2816
 * font cache of our own, and when we copy fonts from the interpreter we point the
2817
 * copied font at this font cache, instead of the one the original font used.
2818
 * This allows the PCL interpreter to shut down and free its cache, thus eliminating
2819
 * a memory leak, while still allowing pdfwrite to retrieve the information it needs
2820
 * from the copied fonts.
2821
 * Here we need to shut down and free our font cache.
2822
 */
2823
static void pdf_free_pdf_font_cache(gx_device_pdf *pdev)
2824
32.9k
{
2825
32.9k
    if (pdev->pdf_font_dir == NULL)
2826
0
        return;
2827
32.9k
    gs_free_object(pdev->pdf_font_dir->memory, pdev->pdf_font_dir, "pdf_free_pdf_font_cache");
2828
32.9k
    pdev->pdf_font_dir = NULL;
2829
32.9k
}
2830
2831
static int discard_dict_refs(void *client_data, const byte *key_data, uint key_size, const cos_value_t *v);
2832
2833
static int discard_array_refs(gx_device_pdf *pdev, cos_object_t *pco)
2834
1.12k
{
2835
1.12k
    int i;
2836
1.12k
    int64_t index;
2837
1.12k
    cos_array_t *pca = (cos_array_t *)pco;
2838
1.12k
    const cos_array_element_t *element = cos_array_element_first(pca);
2839
1.12k
    cos_value_t *v;
2840
2841
5.62k
    while (element) {
2842
4.50k
        element = cos_array_element_next(element, &index, (const cos_value_t **)&v);
2843
4.50k
        if (v->value_type == COS_VALUE_OBJECT) {
2844
0
            for (i=0;i<NUM_RESOURCE_TYPES;i++) {
2845
0
                if (i == resourceOther)
2846
0
                    continue;
2847
0
                if (pdf_find_resource_by_resource_id(pdev, i, v->contents.object->id)){
2848
0
                    v->value_type = COS_VALUE_CONST;
2849
0
                    break;
2850
0
                }
2851
0
                if (cos_type(v->contents.object) == cos_type_array) {
2852
0
                    discard_array_refs(pdev, v->contents.object);
2853
0
                }
2854
0
                if (cos_type(v->contents.object) == cos_type_dict) {
2855
0
                    cos_dict_forall((const cos_dict_t *)v->contents.object, pdev, discard_dict_refs);
2856
0
                }
2857
0
            }
2858
0
        }
2859
4.50k
    }
2860
1.12k
    return 0;
2861
1.12k
}
2862
2863
static int discard_dict_refs(void *client_data, const byte *key_data, uint key_size, const cos_value_t *v)
2864
160
{
2865
160
    int i;
2866
160
    gx_device_pdf *pdev = (gx_device_pdf *)client_data;
2867
160
    cos_value_t *v1 = (cos_value_t *)v;
2868
2869
160
    if (v->value_type == COS_VALUE_OBJECT) {
2870
1.36k
        for (i=0;i<NUM_RESOURCE_TYPES;i++) {
2871
1.28k
            if (i == resourceOther)
2872
80
                continue;
2873
1.20k
            if (pdf_find_resource_by_resource_id(pdev, i, v->contents.object->id)){
2874
0
                v1->value_type = COS_VALUE_CONST;
2875
0
                break;
2876
0
            }
2877
1.20k
            if (cos_type(v->contents.object) == cos_type_array) {
2878
1.12k
                discard_array_refs(pdev, v->contents.object);
2879
1.12k
            }
2880
1.20k
            if (cos_type(v->contents.object) == cos_type_dict) {
2881
75
                cos_dict_forall((const cos_dict_t *)v->contents.object, pdev, discard_dict_refs);
2882
75
            }
2883
1.20k
        }
2884
80
    }
2885
160
    return 0;
2886
160
}
2887
2888
/* Count up the maximum size of all the keys in the /Info dictionary (including NULL terminators) */
2889
static int count_Info(void *client_data, const byte *key_data, uint key_size, const cos_value_t *v)
2890
0
{
2891
0
    int *Size = (int *)client_data;
2892
0
    *Size += key_size + 1;
2893
0
    return 0;
2894
0
}
2895
2896
/* Retrieve a copy of all the keys in the /Info dictionary, each key is NULL terminated and the whole is double NULL terminated.
2897
 * We assume the buffer is large enough to hold all the keys, and has been initialised with all NULLs. We do not return the
2898
 * ModDate and CreationDate keys, because those are still permitted in the Info dictionary in PDF 2.0.
2899
 */
2900
static int get_Info(void *client_data, const byte *key_data, uint key_size, const cos_value_t *v)
2901
0
{
2902
0
    char *Buffer = (char *)client_data, *ptr = Buffer;
2903
2904
0
    if (key_size == 8 && !strncmp((const char *)key_data, "/ModDate", 7))
2905
0
        return 0;
2906
0
    if (key_size == 13 && !strncmp((const char *)key_data, "/CreationDate", 12))
2907
0
        return 0;
2908
0
    if (Buffer[0] == 0x00) {
2909
0
        memcpy(Buffer, key_data, key_size);
2910
0
        return 0;
2911
0
    }
2912
0
    while (*ptr != 0x00 || *(ptr + 1) != 0x00)
2913
0
        ptr++;
2914
0
    memcpy(ptr + 1, key_data, key_size);
2915
0
    return 0;
2916
0
}
2917
2918
/* Remove all the keys *except* ModDate and CreationDtae from the Info dictionary. This is used for production of
2919
 * PDF 2.0 where only these keys 'should' be used. We need to keep them in the Info dictionary until the last minute
2920
 * because the XMP Metadata uses them, if we delete them before writing the XMP metadata then they won't get written
2921
 * out there either, and we want them in the XMP block.
2922
 */
2923
static int reduce_Info(gx_device_pdf *pdev)
2924
0
{
2925
0
    int Size = 0, code;
2926
0
    char *Buffer, *ptr;
2927
2928
0
    code = cos_dict_forall(pdev->Info, &Size, count_Info);
2929
0
    if (code >= 0) {
2930
0
        Buffer = (char *)gs_alloc_bytes(pdev->pdf_memory, Size + 1, "working Info buffer");
2931
0
        if (Buffer == NULL)
2932
0
            return 0;
2933
0
        memset(Buffer, 0x00, Size + 1);
2934
0
        code = cos_dict_forall(pdev->Info, Buffer, get_Info);
2935
0
        if (code >= 0) {
2936
0
            ptr = Buffer;
2937
0
            while (*ptr != 0x00 && ptr < Buffer + Size) {
2938
0
                (void)cos_dict_delete_c_key(pdev->Info, ptr);
2939
0
                ptr += strlen(ptr) + 1;
2940
0
            }
2941
0
        }
2942
0
        gs_free_object(pdev->pdf_memory, Buffer, "working Info buffer");
2943
0
    }
2944
0
    return 0;
2945
0
}
2946
2947
/* Close the device. */
2948
static int
2949
pdf_close(gx_device * dev)
2950
32.9k
{
2951
32.9k
    gx_device_pdf *const pdev = (gx_device_pdf *) dev;
2952
32.9k
    gs_memory_t *mem = pdev->pdf_memory;
2953
32.9k
    stream *s = NULL;
2954
32.9k
    gp_file *tfile = pdev->xref.file;
2955
32.9k
    gs_offset_t xref = 0;
2956
32.9k
    gs_offset_t resource_pos = 0;
2957
32.9k
    int64_t Catalog_id = 0, Info_id = 0,
2958
32.9k
        Pages_id = 0, Encrypt_id = 0;
2959
32.9k
    int64_t Threads_id = 0;
2960
32.9k
    bool partial_page = (pdev->contents_id != 0 && pdev->next_page != 0);
2961
32.9k
    int code = 0, code1, pagecount=0;
2962
32.9k
    int64_t start_section, end_section;
2963
32.9k
    char str[256];
2964
32.9k
    pdf_linearisation_t linear_params;
2965
32.9k
    bool file_per_page = false;
2966
32.9k
    int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
2967
2968
32.9k
    if (!dev->is_open)
2969
0
        return_error(gs_error_undefined);
2970
32.9k
    dev->is_open = false;
2971
2972
32.9k
    if (pdev->sbstack_depth > bottom) {
2973
18
        emprintf(pdev->pdf_memory, "Error closing device; open substreams detected!\n");
2974
18
        emprintf(pdev->pdf_memory, "Probably due to errors in the input. Output file is incorrect/invalid.\n");
2975
18
    }
2976
2977
32.9k
    while(pdev->sbstack_depth > bottom)
2978
        /* This is an error, and we are trying to recover, so ignore any further errors */
2979
18
        (void)pdf_exit_substream(pdev);
2980
2981
32.9k
    if (pdev->initial_pattern_states != NULL) {
2982
0
        int pdepth = 0;
2983
2984
0
        while (pdev->initial_pattern_states[pdepth] != 0x00) {
2985
0
            gs_free_object(pdev->pdf_memory, pdev->initial_pattern_states[pdepth], "Freeing dangling pattern state");
2986
0
            pdev->initial_pattern_states[pdepth] = NULL;
2987
0
            pdepth++;
2988
0
        }
2989
0
        gs_free_object(pdev->pdf_memory->non_gc_memory, pdev->initial_pattern_states, "Freeing dangling pattern state stack");
2990
0
        pdev->initial_pattern_states = NULL;
2991
0
    }
2992
2993
32.9k
    if (pdev->Catalog)
2994
32.9k
        Catalog_id = pdev->Catalog->id;
2995
32.9k
    if (pdev->Info)
2996
32.9k
        Info_id = pdev->Info->id;
2997
32.9k
    if (pdev->Pages)
2998
32.9k
        Pages_id = pdev->Pages->id;
2999
3000
32.9k
    memset(&linear_params, 0x00, sizeof(linear_params));
3001
32.9k
    linear_params.Info_id = Info_id;
3002
32.9k
    linear_params.Pages_id = Pages_id;
3003
32.9k
    linear_params.Catalog_id = Catalog_id;
3004
3005
    /*
3006
     * If this is an EPS file, or if the file didn't end with a showpage for
3007
     * some other reason, or if the file has produced no marks at all, we
3008
     * need to tidy up a little so as not to produce illegal PDF.  However,
3009
     * if there is at least one complete page, we discard any leftover
3010
     * marks.
3011
     */
3012
32.9k
    if (pdev->next_page == 0) {
3013
17.6k
        file_per_page = !pdev->InOutputPage &&
3014
17.6k
            gx_outputfile_is_separate_pages(pdev->fname, pdev->memory);
3015
17.6k
        if (!file_per_page) {
3016
17.6k
            code = pdf_open_page(pdev, PDF_IN_STREAM);
3017
3018
17.6k
            if (code < 0)
3019
0
                return code;
3020
17.6k
        }
3021
17.6k
    }
3022
32.9k
    if (pdev->contents_id != 0)
3023
18.4k
        pdf_close_page(pdev, 1);
3024
3025
    /* Write the page objects. */
3026
32.9k
    if (!(pdev->ForOPDFRead && pdev->ProduceDSC)) {
3027
21.5k
        for (pagecount = 1; pagecount <= pdev->next_page; ++pagecount)
3028
12.3k
            pdf_write_page(pdev, pagecount);
3029
9.16k
    }
3030
3031
32.9k
    if (pdev->PrintStatistics)
3032
0
        pdf_print_resource_statistics(pdev);
3033
3034
    /* Write the font resources and related resources. */
3035
32.9k
    code1 = pdf_write_resource_objects(pdev, resourceXObject);
3036
32.9k
    if (code >= 0)
3037
32.9k
        code = code1;
3038
32.9k
    code1 = pdf_free_resource_objects(pdev, resourceXObject);
3039
32.9k
    if (code >= 0)
3040
32.9k
        code = code1;
3041
32.9k
    code1 = pdf_free_resource_objects(pdev, resourceProperties);
3042
32.9k
    if (code >= 0)
3043
32.9k
        code = code1;
3044
32.9k
    code1 = pdf_write_resource_objects(pdev, resourceGroup);
3045
32.9k
    if (code >= 0)
3046
32.9k
        code = code1;
3047
32.9k
    code1 = pdf_free_resource_objects(pdev, resourceGroup);
3048
32.9k
    if (code >= 0)
3049
32.9k
        code = code1;
3050
32.9k
    code1 = pdf_write_resource_objects(pdev, resourceSoftMaskDict);
3051
32.9k
    if (code >= 0)
3052
32.9k
        code = code1;
3053
32.9k
    code1 = pdf_free_resource_objects(pdev, resourceSoftMaskDict);
3054
32.9k
    if (code >= 0)
3055
32.9k
        code = code1;
3056
    /* This was in pdf_close_document, but that made no sense, so moved here
3057
     * for more consistency (and ease of finding it). This code deals with
3058
     * emitting fonts and FontDescriptors
3059
     */
3060
32.9k
    pdf_clean_standard_fonts(pdev);
3061
32.9k
    code1 = pdf_free_font_cache(pdev);
3062
32.9k
    if (code >= 0)
3063
32.9k
        code = code1;
3064
32.9k
    code1 = pdf_write_resource_objects(pdev, resourceCharProc);
3065
32.9k
    if (code >= 0)
3066
32.9k
        code = code1;
3067
32.9k
    code1 = pdf_finish_resources(pdev, resourceFont, pdf_convert_truetype_font);
3068
32.9k
    if (code >= 0)
3069
32.9k
        code = code1;
3070
32.9k
    code1 = pdf_finish_resources(pdev, resourceFontDescriptor, pdf_finish_FontDescriptor);
3071
32.9k
    if (code >= 0)
3072
32.9k
        code = code1;
3073
32.9k
    code1 = write_font_resources(pdev, &pdev->resources[resourceCIDFont]);
3074
32.9k
    if (code >= 0)
3075
32.5k
        code = code1;
3076
32.9k
    code1 = write_font_resources(pdev, &pdev->resources[resourceFont]);
3077
32.9k
    if (code >= 0)
3078
32.5k
        code = code1;
3079
32.9k
    code1 = pdf_finish_resources(pdev, resourceFontDescriptor, pdf_write_FontDescriptor);
3080
32.9k
    if (code >= 0)
3081
32.5k
        code = code1;
3082
    /* If required, write the Encoding for Type 3 bitmap fonts. */
3083
32.9k
    code1 = pdf_write_bitmap_fonts_Encoding(pdev);
3084
32.9k
    if (code >= 0)
3085
32.5k
        code = code1;
3086
3087
32.9k
    code1 = pdf_write_resource_objects(pdev, resourceCMap);
3088
32.9k
    if (code >= 0)
3089
32.5k
        code = code1;
3090
32.9k
    code1 = pdf_free_resource_objects(pdev, resourceCMap);
3091
32.9k
    if (code >= 0)
3092
32.5k
        code = code1;
3093
32.9k
    if (!(pdev->ForOPDFRead && pdev->ProduceDSC)) {
3094
9.16k
        if (pdev->ResourcesBeforeUsage)
3095
0
            pdf_reverse_resource_chain(pdev, resourcePage);
3096
9.16k
        code1 = pdf_write_resource_objects(pdev, resourcePage);
3097
9.16k
        if (code >= 0)
3098
9.01k
            code = code1;
3099
9.16k
        code1 = pdf_free_resource_objects(pdev, resourcePage);
3100
9.16k
        if (code >= 0)
3101
9.01k
            code = code1;
3102
9.16k
    }
3103
3104
    /* Create the Pages tree. */
3105
32.9k
    if (!(pdev->ForOPDFRead && pdev->ProduceDSC) && pdev->strm != NULL) {
3106
9.16k
        pdf_open_obj(pdev, Pages_id, resourcePagesTree);
3107
9.16k
        pdf_record_usage(pdev, Pages_id, resource_usage_part9_structure);
3108
3109
9.16k
        s = pdev->strm;
3110
9.16k
        stream_puts(s, "<< /Type /Pages /Kids [\n");
3111
        /* Omit the last page if it was incomplete. */
3112
9.16k
        if (partial_page)
3113
15
            --(pdev->next_page);
3114
9.16k
        {
3115
9.16k
            int i;
3116
3117
21.5k
            for (i = 0; i < pdev->next_page; ++i)
3118
12.3k
                pprinti64d1(s, "%"PRId64" 0 R\n", pdev->pages[i].Page->id);
3119
9.16k
        }
3120
9.16k
        pprintd1(s, "] /Count %d\n", pdev->next_page);
3121
3122
        /* If the last file was PostScript, its possible that DSC comments might be lying around
3123
         * and pdf_print_orientation will use that if its present. So make sure we get rid of those
3124
         * before considering the dominant page direction for the Pages tree.
3125
         */
3126
9.16k
        pdev->doc_dsc_info.viewing_orientation = pdev->doc_dsc_info.orientation = -1;
3127
9.16k
        pdev->text_rotation.Rotate = pdf_dominant_rotation(&pdev->text_rotation);
3128
9.16k
        pdf_print_orientation(pdev, NULL);
3129
3130
9.16k
        cos_dict_elements_write(pdev->Pages, pdev);
3131
9.16k
        stream_puts(s, ">>\n");
3132
9.16k
        pdf_end_obj(pdev, resourcePagesTree);
3133
3134
        /* Close outlines and articles. */
3135
3136
9.16k
        if (pdev->outlines_id != 0) {
3137
154
            pdf_record_usage(pdev, pdev->outlines_id, resource_usage_part9_structure);
3138
            /* depth > 0 is only possible for an incomplete outline tree. */
3139
159
            while (pdev->outline_depth > 0) {
3140
5
                code1 = pdfmark_close_outline(pdev);
3141
5
                if (code >= 0)
3142
5
                    code = code1;
3143
5
            }
3144
154
            code = pdfmark_close_outline(pdev);
3145
154
            if (code >= 0)
3146
154
                code = code1;
3147
154
            pdf_open_obj(pdev, pdev->outlines_id, resourceOutline);
3148
154
            pprintd1(s, "<< /Type /Outlines /Count %d", pdev->outlines_open);
3149
154
            pprinti64d2(s, " /First %"PRId64" 0 R /Last %"PRId64" 0 R >>\n",
3150
154
                  pdev->outline_levels[0].first.id,
3151
154
                  pdev->outline_levels[0].last.id);
3152
154
            pdf_end_obj(pdev, resourceOutline);
3153
154
        }
3154
9.16k
        if (pdev->articles != 0) {
3155
0
            pdf_article_t *part;
3156
3157
            /* Write the remaining information for each article. */
3158
0
            for (part = pdev->articles; part != 0; part = part->next)
3159
0
                pdfmark_write_article(pdev, part);
3160
0
        }
3161
3162
        /* Write named destinations.  (We can't free them yet.) */
3163
3164
9.16k
        if (pdev->CompatibilityLevel < 1.2) {
3165
0
            if (pdev->Dests) {
3166
0
                pdf_record_usage(pdev, pdev->Dests->id, resource_usage_part9_structure);
3167
0
                COS_WRITE_OBJECT(pdev->Dests, pdev, resourceDests);
3168
0
            }
3169
9.16k
        } else {
3170
9.16k
            if (pdev->Dests) {
3171
0
                pdf_record_usage(pdev, pdev->Dests->id, resource_usage_part9_structure);
3172
0
                cos_write_dict_as_ordered_array((cos_object_t *)pdev->Dests, pdev, resourceDests);
3173
0
            }
3174
            /* Write Embedded files.  (We can't free them yet.) */
3175
3176
9.16k
            if (pdev->EmbeddedFiles) {
3177
17
                pdf_record_usage(pdev, pdev->EmbeddedFiles->id, resource_usage_part9_structure);
3178
17
                cos_write_dict_as_ordered_array((cos_object_t *)pdev->EmbeddedFiles, pdev, resourceEmbeddedFiles);
3179
17
            }
3180
9.16k
            if (pdev->AF) {
3181
0
                pdf_record_usage(pdev, pdev->AF->id, resource_usage_part9_structure);
3182
0
                COS_WRITE_OBJECT(pdev->AF, pdev, resourceEmbeddedFiles);
3183
0
            }
3184
9.16k
        }
3185
3186
        /* Write the PageLabel array */
3187
9.16k
        pdfmark_end_pagelabels(pdev);
3188
9.16k
        if (pdev->PageLabels) {
3189
0
            pdf_record_usage(pdev, pdev->PageLabels->id, resource_usage_part9_structure);
3190
0
            COS_WRITE_OBJECT(pdev->PageLabels, pdev, resourceLabels);
3191
0
        }
3192
3193
9.16k
        if (!pdev->OmitXMP) {
3194
9.16k
            bool saved = pdev->WriteObjStms;
3195
3196
9.16k
            if (pdev->WriteObjStms)
3197
9.16k
                pdev->WriteObjStms = false;
3198
            /* Write the document metadata. */
3199
9.16k
            code1 = pdf_document_metadata(pdev);
3200
9.16k
            pdev->WriteObjStms = saved;
3201
9.16k
            if (code >= 0)
3202
9.04k
                code = code1;
3203
9.16k
        }
3204
        /* We don't want to write some key/value pairs into the document information dictionary when we are producing
3205
         * PDF 2.0, because the 2.0 spec deprecates the /Info dictionary (Bah) and states we 'should' only write
3206
         * ModDate and CreationDate. But if we don't put the keys in the dictionary then the XMP metadata
3207
         * won't contain them either, and we do want things like the Producer in there.
3208
         * So, now that we've written the XMP metadata, we can remove any keys we don't want in the /Info dictionary.
3209
         */
3210
9.16k
        if (pdev->CompatibilityLevel >= 2.0)
3211
0
            reduce_Info(pdev);
3212
3213
        /* Write the Catalog. */
3214
3215
        /*
3216
         * The PDF specification requires Threads to be an indirect object.
3217
         * Write the threads now, if any.
3218
         */
3219
9.16k
        if (pdev->articles != 0) {
3220
0
            pdf_article_t *part;
3221
3222
0
            Threads_id = pdf_begin_obj(pdev, resourceThread);
3223
0
            pdf_record_usage(pdev, Threads_id, resource_usage_part9_structure);
3224
0
            s = pdev->strm;
3225
0
            stream_puts(s, "[ ");
3226
0
            while ((part = pdev->articles) != 0) {
3227
0
                pdev->articles = part->next;
3228
0
                pprinti64d1(s, "%"PRId64" 0 R\n", part->contents->id);
3229
0
                COS_FREE(part->contents, "pdf_close(article contents)");
3230
0
                gs_free_object(mem, part, "pdf_close(article)");
3231
0
            }
3232
0
            stream_puts(s, "]\n");
3233
0
            pdf_end_obj(pdev, resourceThread);
3234
0
        }
3235
9.16k
        pdf_open_obj(pdev, Catalog_id, resourceCatalog);
3236
9.16k
        pdf_record_usage(pdev, Catalog_id, resource_usage_part1_structure);
3237
3238
9.16k
        s = pdev->strm;
3239
9.16k
        stream_puts(s, "<<");
3240
9.16k
        pprinti64d1(s, "/Type /Catalog /Pages %"PRId64" 0 R\n", Pages_id);
3241
9.16k
        if (pdev->outlines_id != 0)
3242
154
            pprinti64d1(s, "/Outlines %"PRId64" 0 R\n", pdev->outlines_id);
3243
9.16k
        if (Threads_id) {
3244
0
            pprinti64d1(s, "/Threads %"PRId64" 0 R\n", Threads_id);
3245
0
            pdf_record_usage(pdev, Threads_id, resource_usage_part1_structure);
3246
0
        }
3247
9.16k
        if (pdev->CompatibilityLevel < 1.2) {
3248
0
            if (pdev->Dests)
3249
0
                pprinti64d1(s, "/Dests %"PRId64" 0 R\n", pdev->Dests->id);
3250
9.16k
        } else {
3251
9.16k
            if (pdev->Dests || pdev->EmbeddedFiles) {
3252
17
                stream_puts(s, "/Names <<\n");
3253
17
                if (pdev->Dests)
3254
0
                    pprinti64d1(s, "/Dests <</Kids [%"PRId64" 0 R]>>\n", pdev->Dests->id);
3255
17
                if (pdev->EmbeddedFiles)
3256
17
                    pprinti64d1(s, "/EmbeddedFiles << /Kids [%"PRId64" 0 R]>>\n", pdev->EmbeddedFiles->id);
3257
17
                stream_puts(s, ">>\n");
3258
17
            }
3259
9.16k
            if (pdev->AF)
3260
0
                if (!cos_dict_find_c_key(pdev->Catalog, "/AF"))
3261
0
                    pprinti64d1(s, "/AF %"PRId64" 0 R\n", pdev->AF->id);
3262
9.16k
        }
3263
9.16k
        if (pdev->PageLabels)
3264
0
            pprinti64d1(s, "/PageLabels << /Nums  %"PRId64" 0 R >>\n",
3265
0
                  pdev->PageLabels->id);
3266
9.16k
        cos_dict_elements_write(pdev->Catalog, pdev);
3267
9.16k
        stream_puts(s, ">>\n");
3268
9.16k
        pdf_end_obj(pdev, resourceCatalog);
3269
9.16k
        if (pdev->Dests) {
3270
0
            COS_FREE(pdev->Dests, "pdf_close(Dests)");
3271
0
            pdev->Dests = 0;
3272
0
        }
3273
9.16k
        if (pdev->EmbeddedFiles) {
3274
17
            COS_FREE(pdev->EmbeddedFiles, "pdf_close(EmbeddFiles)");
3275
17
            pdev->EmbeddedFiles = 0;
3276
17
        }
3277
9.16k
        if (pdev->AF) {
3278
0
            COS_FREE(pdev->AF, "pdf_close(AF)");
3279
0
            pdev->AF = 0;
3280
0
        }
3281
9.16k
        if (pdev->PageLabels) {
3282
0
            COS_FREE(pdev->PageLabels, "pdf_close(PageLabels)");
3283
0
            pdev->PageLabels = 0;
3284
0
            pdev->PageLabels_current_label = 0;
3285
0
        }
3286
3287
        /* Prevent writing special named objects twice. */
3288
3289
9.16k
        pdev->Catalog->id = 0;
3290
        /*pdev->Info->id = 0;*/ /* Info should get written */
3291
9.16k
        pdf_record_usage(pdev, pdev->Info->id, resource_usage_part9_structure);
3292
3293
23.7k
    } else {
3294
23.7k
        if (pdev->Info != NULL)
3295
23.7k
            pdev->Info->id = 0; /* Don't write Info dict for DSC PostScript */
3296
23.7k
    }
3297
    /*
3298
     * Write the definitions of the named objects.
3299
     * Note that this includes Form XObjects created by BP/EP, named PS
3300
     * XObjects, and images named by NI.
3301
     */
3302
3303
32.9k
    if(pdev->local_named_objects != NULL) {
3304
32.9k
        do {
3305
32.9k
            cos_dict_objects_write(pdev->local_named_objects, pdev);
3306
32.9k
        } while (pdf_pop_namespace(pdev) >= 0);
3307
32.9k
    }
3308
32.9k
    if (pdev->global_named_objects != NULL)
3309
32.9k
        cos_dict_objects_write(pdev->global_named_objects, pdev);
3310
3311
32.9k
    if (pdev->ForOPDFRead && pdev->ProduceDSC) {
3312
23.7k
        int pages;
3313
3314
77.7k
        for (pages = 0; pages <= pdev->next_page; ++pages)
3315
53.9k
            ;
3316
3317
23.7k
        code1 = ps2write_dsc_header(pdev, pages - 1);
3318
23.7k
        if (code >= 0)
3319
23.5k
            code = code1;
3320
23.7k
    }
3321
3322
    /* Copy the resources into the main file. */
3323
3324
32.9k
    if (pdev->WriteObjStms) {
3325
9.16k
        FlushObjStm(pdev);
3326
9.16k
        pdev->WriteObjStms = false;
3327
9.16k
    }
3328
32.9k
    if (pdev->strm != NULL) {
3329
32.9k
        s = pdev->strm;
3330
32.9k
        resource_pos = stell(s);
3331
32.9k
        sflush(pdev->asides.strm);
3332
32.9k
        {
3333
32.9k
            gp_file *rfile = pdev->asides.file;
3334
32.9k
            int64_t res_end = gp_ftell(rfile);
3335
3336
32.9k
            gp_fseek(rfile, 0L, SEEK_SET);
3337
32.9k
            code1 = pdf_copy_data(s, rfile, res_end, NULL);
3338
32.9k
            if (code >= 0)
3339
32.5k
                code = code1;
3340
32.9k
        }
3341
32.9k
    }
3342
3343
32.9k
    if (pdev->ForOPDFRead && pdev->ProduceDSC && s != NULL) {
3344
23.7k
        int j;
3345
3346
23.7k
        pagecount = 1;
3347
3348
        /* All resources and procsets written, end the prolog */
3349
23.7k
        stream_puts(pdev->strm, "%%EndProlog\n");
3350
3351
23.7k
        if (pdev->params.PSDocOptions.data) {
3352
0
            int i;
3353
0
            char *p = (char *)pdev->params.PSDocOptions.data;
3354
3355
0
            stream_puts(pdev->strm, "%%BeginSetup\n");
3356
0
            for (i=0;i<pdev->params.PSDocOptions.size;i++)
3357
0
                stream_putc(s, *p++);
3358
0
            stream_puts(pdev->strm, "\n");
3359
0
            stream_puts(pdev->strm, "\n%%EndSetup\n");
3360
0
        }
3361
3362
23.7k
        if (pdev->ResourcesBeforeUsage)
3363
23.7k
            pdf_reverse_resource_chain(pdev, resourcePage);
3364
400k
        for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) {
3365
377k
            pdf_resource_t *pres = pdev->resources[resourcePage].chains[j];
3366
3367
406k
            for (; pres != 0; pres = pres->next)
3368
29.9k
                if ((!pres->named || pdev->ForOPDFRead)
3369
29.9k
                    && !pres->object->written) {
3370
29.9k
                    pdf_page_t *page = &pdev->pages[pagecount - 1];
3371
3372
29.9k
                    pprintd2(pdev->strm, "%%%%Page: %d %d\n",
3373
29.9k
                        pagecount, pagecount);
3374
29.9k
                    if (!pdev->Eps2Write)
3375
17.3k
                        pprintd2(pdev->strm, "%%%%PageBoundingBox: 0 0 %d %d\n", (int)page->MediaBox.x, (int)page->MediaBox.y);
3376
29.9k
                    stream_puts(pdev->strm, "%%BeginPageSetup\n");
3377
3378
29.9k
                    if (pdev->params.PSPageOptions.size) {
3379
0
                        if (pdev->params.PSPageOptionsWrap || (pagecount - 1) < pdev->params.PSPageOptions.size) {
3380
0
                            int i, index = (pagecount - 1) % pdev->params.PSPageOptions.size;
3381
0
                            char *p = (char *)pdev->params.PSPageOptions.data[index].data;
3382
3383
0
                            for (i=0;i<pdev->params.PSPageOptions.data[index].size;i++)
3384
0
                                stream_putc(s, *p++);
3385
0
                            stream_puts(pdev->strm, "\n");
3386
0
                        }
3387
0
                    }
3388
3389
29.9k
                    pdf_write_page(pdev, pagecount++);
3390
3391
29.9k
                    stream_puts(pdev->strm, "%%EndPageSetup\n");
3392
29.9k
                    pprinti64d1(pdev->strm, "%"PRId64" 0 obj\n", pres->object->id);
3393
29.9k
                    code = cos_write(pres->object, pdev, pres->object->id);
3394
29.9k
                    stream_puts(pdev->strm, "endobj\n");
3395
29.9k
                    pres->object->written = true;
3396
29.9k
                    stream_puts(pdev->strm, "%%PageTrailer\n");
3397
29.9k
                }
3398
377k
        }
3399
23.7k
        code1 = pdf_free_resource_objects(pdev, resourcePage);
3400
23.7k
        if (code >= 0)
3401
23.5k
            code = code1;
3402
23.7k
        stream_puts(pdev->strm, "%%Trailer\n");
3403
23.7k
        stream_puts(pdev->strm, "end\n");
3404
23.7k
        stream_puts(pdev->strm, "%%EOF\n");
3405
23.7k
    }
3406
3407
32.9k
    if (pdev->params.PSPageOptions.size) {
3408
0
        int ix;
3409
3410
0
        for (ix = 0; ix < pdev->params.PSPageOptions.size;ix++)
3411
0
            gs_free_object(mem->non_gc_memory, (byte *)pdev->params.PSPageOptions.data[ix].data, "freeing old string array copy");
3412
0
        gs_free_object(mem->non_gc_memory, (byte *)pdev->params.PSPageOptions.data, "freeing old string array");
3413
0
    }
3414
3415
32.9k
    if (pdev->Linearise) {
3416
0
        linear_params.LastResource = pdev->next_id - 1;
3417
0
        linear_params.Offsets = (gs_offset_t *)gs_alloc_bytes(pdev->pdf_memory, pdev->next_id * sizeof(gs_offset_t), "temp xref storage");
3418
0
        if (linear_params.Offsets == NULL) {
3419
0
            code = gs_error_VMerror;
3420
0
            goto error_cleanup;
3421
0
        }
3422
0
        memset(linear_params.Offsets, 0x00, linear_params.LastResource * sizeof(gs_offset_t));
3423
0
    }
3424
3425
32.9k
    if (!(pdev->ForOPDFRead && pdev->ProduceDSC) && pdev->strm != NULL) {
3426
        /* Write Encrypt. */
3427
9.16k
        if (pdev->OwnerPassword.size > 0) {
3428
0
            Encrypt_id = pdf_obj_ref(pdev);
3429
3430
0
            pdf_open_obj(pdev, Encrypt_id, resourceEncrypt);
3431
0
            s = pdev->strm;
3432
0
            stream_puts(s, "<<");
3433
0
            stream_puts(s, "/Filter /Standard ");
3434
0
            pprintld1(s, "/V %ld ", pdev->EncryptionV);
3435
0
            pprintld1(s, "/Length %ld ", pdev->KeyLength);
3436
0
            pprintld1(s, "/R %ld ", pdev->EncryptionR);
3437
0
            pprintd1(s, "/P %d ", pdev->Permissions);
3438
0
            stream_puts(s, "/O ");
3439
0
            pdf_put_string(pdev, pdev->EncryptionO, sizeof(pdev->EncryptionO));
3440
0
            stream_puts(s, "\n/U ");
3441
0
            pdf_put_string(pdev, pdev->EncryptionU, sizeof(pdev->EncryptionU));
3442
0
            stream_puts(s, ">>\n");
3443
0
            pdf_end_obj(pdev, resourceEncrypt);
3444
0
            s = pdev->strm;
3445
0
        }
3446
3447
        /* Write the cross-reference section. */
3448
3449
9.16k
        start_section = pdev->FirstObjectNumber;
3450
9.16k
        end_section = find_end_xref_section(pdev, tfile, start_section, resource_pos);
3451
3452
9.16k
        xref = pdf_stell(pdev) - pdev->OPDFRead_procset_length;
3453
9.16k
        if (pdev->Linearise)
3454
0
            linear_params.xref = xref;
3455
3456
9.16k
        if (!pdev->WriteXRefStm) {
3457
0
            if (pdev->FirstObjectNumber == 1) {
3458
0
                gs_snprintf(str, sizeof(str), "xref\n0 %"PRId64"\n0000000000 65535 f \n",
3459
0
                      end_section);
3460
0
                stream_puts(s, str);
3461
0
            }
3462
0
            else {
3463
0
                gs_snprintf(str, sizeof(str), "xref\n0 1\n0000000000 65535 f \n%"PRId64" %"PRId64"\n",
3464
0
                      start_section,
3465
0
                      end_section - start_section);
3466
0
                stream_puts(s, str);
3467
0
            }
3468
3469
0
            do {
3470
0
                code = write_xref_section(pdev, tfile, start_section, end_section, resource_pos, linear_params.Offsets);
3471
0
                if (code < 0)
3472
0
                    goto error_cleanup;
3473
3474
0
                if (end_section >= pdev->next_id)
3475
0
                    break;
3476
0
                do {
3477
0
                    start_section = end_section + 1;
3478
0
                    end_section = find_end_xref_section(pdev, tfile, start_section, resource_pos);
3479
0
                    if (end_section < 0)
3480
0
                        return end_section;
3481
0
                } while (start_section == end_section);
3482
0
                gs_snprintf(str, sizeof(str), "%"PRId64" %"PRId64"\n", start_section, end_section - start_section);
3483
0
                stream_puts(s, str);
3484
0
            } while (1);
3485
3486
            /* Write the trailer. */
3487
0
            if (!pdev->Linearise) {
3488
0
                char xref_str[32];
3489
0
                stream_puts(s, "trailer\n");
3490
0
                pprinti64d3(s, "<< /Size %"PRId64" /Root %"PRId64" 0 R /Info %"PRId64" 0 R\n",
3491
0
                      pdev->next_id, Catalog_id, Info_id);
3492
0
                if (!pdev->OmitID) {
3493
0
                    stream_puts(s, "/ID [");
3494
0
                    psdf_write_string(pdev->strm, pdev->fileID, sizeof(pdev->fileID), 0);
3495
0
                    psdf_write_string(pdev->strm, pdev->fileID, sizeof(pdev->fileID), 0);
3496
0
                    stream_puts(s, "]\n");
3497
0
                }
3498
0
                if (pdev->OwnerPassword.size > 0) {
3499
0
                    pprinti64d1(s, "/Encrypt %"PRId64" 0 R ", Encrypt_id);
3500
0
                }
3501
0
                stream_puts(s, ">>\n");
3502
0
                gs_snprintf(xref_str, sizeof(xref_str), "startxref\n%"PRId64"\n%%%%EOF\n", xref);
3503
0
                stream_puts(s, xref_str);
3504
0
            }
3505
9.16k
        } else {
3506
9.16k
            char xref_str[32];
3507
9.16k
            gs_offset_t maxoffs = xref, offs_bytes = 0, length = 0;
3508
9.16k
            int i;
3509
3510
27.8k
            while(maxoffs > 0) {
3511
18.7k
                maxoffs = maxoffs >> 8;
3512
18.7k
                offs_bytes++;
3513
18.7k
            }
3514
3515
9.16k
            gs_snprintf(str, sizeof(str), "%"PRId64" 0 obj\n<<\n/Type /XRef\n", (int64_t)pdev->next_id);
3516
9.16k
            stream_puts(s, str);
3517
9.16k
            gs_snprintf(str, sizeof(str), "/Size %"PRId64"\n", (int64_t)(pdev->next_id + 1));
3518
9.16k
            stream_puts(s, str);
3519
3520
9.16k
            pprinti64d2(s, "/Root %"PRId64" 0 R /Info %"PRId64" 0 R\n", Catalog_id, Info_id);
3521
9.16k
            if (!pdev->OmitID) {
3522
9.16k
                stream_puts(s, "/ID [");
3523
9.16k
                psdf_write_string(pdev->strm, pdev->fileID, sizeof(pdev->fileID), 0);
3524
9.16k
                psdf_write_string(pdev->strm, pdev->fileID, sizeof(pdev->fileID), 0);
3525
9.16k
                stream_puts(s, "]\n");
3526
9.16k
            }
3527
9.16k
            if (pdev->OwnerPassword.size > 0) {
3528
0
                pprinti64d1(s, "/Encrypt %"PRId64" 0 R ", Encrypt_id);
3529
0
            }
3530
3531
9.16k
            end_section = find_end_xref_section(pdev, tfile, start_section, resource_pos);
3532
9.16k
            if (end_section == pdev->next_id)
3533
9.16k
                end_section++;
3534
3535
9.16k
            length += (end_section - start_section) * (offs_bytes + 3);
3536
3537
9.16k
            if (pdev->FirstObjectNumber == 1) {
3538
9.16k
                gs_snprintf(str, sizeof(str), "/Index [0 %"PRId64" ", end_section);
3539
9.16k
                stream_puts(s, str);
3540
9.16k
            } else {
3541
0
                gs_snprintf(str, sizeof(str), "/Index [0 1 %"PRId64" %"PRId64" ", pdev->FirstObjectNumber, end_section);
3542
0
                stream_puts(s, str);
3543
0
            }
3544
3545
9.17k
            do {
3546
9.17k
                if (end_section >= pdev->next_id)
3547
9.16k
                    break;
3548
3549
8
                do {
3550
8
                    start_section = end_section + 1;
3551
8
                    end_section = find_end_xref_section(pdev, tfile, start_section, resource_pos);
3552
8
                    if (end_section < 0)
3553
0
                        return end_section;
3554
8
                } while (start_section == end_section);
3555
5
                gs_snprintf(str, sizeof(str), "%"PRId64" %"PRId64" ", start_section, end_section - start_section);
3556
5
                stream_puts(s, str);
3557
5
            }while (1);
3558
3559
9.16k
            {
3560
9.16k
                pdf_temp_file_t xref_temp;
3561
9.16k
                stream *xs = NULL, *xs1;
3562
9.16k
                char xrefbuf[256];
3563
9.16k
                int read = 0;
3564
9.16k
                stream_state *st = NULL;
3565
9.16k
                code = pdf_open_temp_stream(pdev, &xref_temp);
3566
9.16k
                if (code < 0)
3567
0
                    return code;
3568
3569
9.16k
                xs1 = xref_temp.strm;
3570
9.16k
                if (pdev->CompressStreams) {
3571
9.16k
                    if (pdev->UseBrotli) {
3572
0
                        st = s_alloc_state(pdev->pdf_memory, s_brotliE_template.stype, "write_xref_strm");
3573
0
                        if (st == NULL)
3574
0
                            return_error(gs_error_VMerror);
3575
0
                        s_brotliE_template.set_defaults (st);
3576
0
                        xs = s_add_filter(&xref_temp.strm, &s_brotliE_template, st, pdev->pdf_memory);
3577
0
                        if (xs == NULL)
3578
0
                            xs = xref_temp.strm;
3579
9.16k
                    } else {
3580
9.16k
                        st = s_alloc_state(pdev->pdf_memory, s_zlibE_template.stype, "write_xref_strm");
3581
9.16k
                        if (st == NULL)
3582
0
                            return_error(gs_error_VMerror);
3583
9.16k
                        s_zlibE_template.set_defaults (st);
3584
9.16k
                        xs = s_add_filter(&xref_temp.strm, &s_zlibE_template, st, pdev->pdf_memory);
3585
9.16k
                        if (xs == NULL)
3586
0
                            xs = xref_temp.strm;
3587
9.16k
                    }
3588
9.16k
                } else
3589
0
                    xs = xref_temp.strm;
3590
3591
                /* write the free entry */
3592
9.16k
                stream_putc(xs, 0x00);
3593
27.8k
                for (i = 0; i < offs_bytes; i++)
3594
18.7k
                    stream_putc(xs, 0x00);
3595
9.16k
                stream_putc(xs, 0xFF);
3596
9.16k
                stream_putc(xs, 0xFF);
3597
3598
9.16k
                start_section = pdev->FirstObjectNumber;
3599
9.17k
                do {
3600
9.17k
                    end_section = find_end_xref_section(pdev, tfile, start_section, resource_pos);
3601
9.17k
                    if (end_section < 0)
3602
0
                    {
3603
0
                        gs_free_object(pdev->memory, st, "write_xref_strm");
3604
0
                        return end_section;
3605
0
                    }
3606
3607
9.17k
                    code = write_xrefstm_section(pdev, tfile, start_section, end_section, resource_pos, offs_bytes, xs);
3608
9.17k
                    if (code < 0)
3609
0
                    {
3610
0
                        gs_free_object(pdev->memory, st, "write_xref_strm");
3611
0
                        goto error_cleanup;
3612
0
                    }
3613
3614
9.17k
                    start_section = end_section + 1;
3615
9.17k
                } while (end_section < pdev->next_id);
3616
3617
                /* write the entry for this XRefStm */
3618
9.16k
                stream_putc(xs, 0x01);
3619
27.8k
                for (i = 1; i <= offs_bytes; i++)
3620
18.7k
                    stream_putc(xs, (xref >> ((offs_bytes - i) * 8)) & 0xFF);
3621
9.16k
                stream_putc(xs, 0x00);
3622
9.16k
                stream_putc(xs, 0x00);
3623
3624
9.16k
                sflush(xs);
3625
9.16k
                if (pdev->CompressStreams)
3626
9.16k
                    s_close_filters(&xref_temp.strm, xs1);
3627
9.16k
                sflush(xref_temp.strm);
3628
9.16k
                length = stell(xref_temp.strm);
3629
3630
9.16k
                if (pdev->CompressStreams) {
3631
9.16k
                    if (pdev->UseBrotli)
3632
0
                        gs_snprintf(str, sizeof(str), "]\n/W [1 %"PRId64" 2]\n/Filter /BrotliDecode/Length %"PRId64"\n>>\nstream\n", offs_bytes, length);
3633
9.16k
                    else
3634
9.16k
                        gs_snprintf(str, sizeof(str), "]\n/W [1 %"PRId64" 2]\n/Filter /FlateDecode/Length %"PRId64"\n>>\nstream\n", offs_bytes, length);
3635
9.16k
                }
3636
0
                else
3637
0
                    gs_snprintf(str, sizeof(str), "]\n/W [1 %"PRId64" 2]\n/Length %"PRId64"\n>>\nstream\n", offs_bytes, length);
3638
9.16k
                stream_puts(s, str);
3639
3640
9.16k
                code = gp_fseek(xref_temp.file , 0, SEEK_SET);
3641
9.16k
                if (code < 0)
3642
0
                    return code;
3643
9.47k
                do {
3644
9.47k
                    read = gp_fread(&xrefbuf, 1, 256, xref_temp.file);
3645
9.47k
                    if (read < 0)
3646
0
                    {
3647
0
                        gs_free_object(pdev->memory, st, "write_xref_strm");
3648
0
                        return_error(gs_error_VMerror);
3649
0
                    }
3650
9.47k
                    stream_write(s, xrefbuf, read);
3651
9.47k
                } while (read == 256);
3652
3653
9.16k
                pdf_close_temp_file(pdev, &xref_temp, 0);
3654
9.16k
            }
3655
3656
0
            gs_snprintf(str, sizeof(str), "\nendstream\nendobj\n");
3657
9.16k
            stream_puts(s, str);
3658
9.16k
            pdev->next_id++;
3659
3660
9.16k
            gs_snprintf(str, sizeof(xref_str), "startxref\n%"PRId64"\n%%%%EOF\n", xref);
3661
9.16k
            stream_puts(s, str);
3662
9.16k
        }
3663
9.16k
    }
3664
3665
32.9k
    if (pdev->Linearise && pdev->strm != NULL) {
3666
0
        int i;
3667
3668
0
        code = pdf_linearise(pdev, &linear_params);
3669
0
        for (i=0; i<pdev->ResourceUsageSize; i++) {
3670
0
            if (pdev->ResourceUsage[i].PageList)
3671
0
                gs_free_object(pdev->pdf_memory->non_gc_memory, pdev->ResourceUsage[i].PageList, "Free linearisation Page Usage list records");
3672
0
        }
3673
0
        gs_free_object(pdev->pdf_memory->non_gc_memory, pdev->ResourceUsage, "Free linearisation resource usage records");
3674
0
    }
3675
3676
32.9k
error_cleanup:
3677
    /* Require special handling for Fonts, ColorSpace and Pattern resources
3678
     * These are tracked in pdev->last_resource, and are complex structures which may
3679
     * contain other memory allocations. All other resource types can be simply dicarded
3680
     * as above.
3681
     */
3682
3683
    /* Memory management of resources in pdfwrite is bizarre and complex. Originally there was no means
3684
     * to free any resources on completion, pdfwrite simply relied on the garbage collector to clean up
3685
     * and all the resource objects are GC-visible. However, this doesn't work well when the interpreter
3686
     * does not use GC, ie PCL or XPS, and even when GC is available, the time taken to clean up the
3687
     * (sometimes enormous numbers) of objects can be surprisingly significant. So code was added above
3688
     * to handle the simple cases using pdf_free_resource_object(), and below to handle the more complex
3689
     * situations.
3690
     * The way this works is that for each resource type we free the 'object', if the object is itself
3691
     * a 'cos' object (array, dictionary) then we free each of its members. However, if any of the objects
3692
     * have an ID which is not zero, then we don't free them (this is true only for contents, all the
3693
     * objects of a given type are freed regardless of whether their ID is 0). These are taken to be
3694
     * references to resource objects of a type which has not yet been freed, and will be freed when
3695
     * that resource type is freed. For the simple resources, which is most of them, this works well.
3696
     *
3697
     * However, there are complications; colour spaces and functions can contain cos objects
3698
     * whose members pointers to other objects of the same resource type (eg a type 3 stitching function
3699
     * can point to an array of type 0 functions). We can't afford to have these free the object, because
3700
     * the resource chain is still pointing at it, and will try to free it again. The same is also true if
3701
     * we should encounter the object which is referenced before we find the reference. So for these cases
3702
     * we first scan the members of each resource (if present) to see if they are references to another
3703
     * resource of the same type. If they are we simply 'corrupt' the reference by changing the object type.
3704
     * The resource has already been written, and the reference will free the memory, so this is safe to do.
3705
     *
3706
     * The final case is 'resourceOther' which can contain pretty much anything. In particular it can contain
3707
     * Colorant dictionaries for colour spaces, but technically it could contain cos objects pointing at any
3708
     * resource type. So far I have only found this to be possible with colorspace and function resources, but
3709
     * the routines 'discard_array_refs' and 'discard_dict_refs' actually check for *all* the resource types except
3710
     * resourceOther. We can't free the resourceOther types because they cvan contain resources that are being used
3711
     * by resources, eg the spot colour names for /Separation and DeviceN spaces.
3712
     *
3713
     * There is a 'gotcha' here; previously we used to free the 'resourceOther' resources *before* calling
3714
     * pdf_document_metadata(), now we call it after. The problem is that the metadata is stored as a resourceOther
3715
     * resource *and* referenced from the Catalog dictionary, which is a 'global named resource'. We free global
3716
     * named resoruces as the absolute last action. Previously because we had free resourceOther resources before
3717
     * creating the new reference to the Metadata, the fact that it was freed by the action of releasing the
3718
     * global named resources wasn't a problem, now it is. If we free the metadata as a 'resourceOther' then when
3719
     * we try to free it as a global named resource we will run into trouble again. So pdf_document_metadata() has been
3720
     * specifically altered to remove the reference to the metadata from the resourceOther resource chain immediately
3721
     * after it has been created. Ick.....
3722
     */
3723
32.9k
    {
3724
32.9k
        int j;
3725
3726
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3727
526k
            pdf_resource_t *pres = pdev->resources[resourceOther].chains[j];
3728
3729
564k
            for (; pres != 0;) {
3730
38.4k
                if (pres->object) {
3731
38.4k
                    if (cos_type(pres->object) == cos_type_array) {
3732
0
                        discard_array_refs(pdev, pres->object);
3733
0
                    }
3734
38.4k
                    if (cos_type(pres->object) == cos_type_dict) {
3735
5
                        cos_dict_forall((const cos_dict_t *)pres->object, pdev, discard_dict_refs);
3736
5
                    }
3737
38.4k
                }
3738
38.4k
                pres = pres->next;
3739
38.4k
            }
3740
526k
        }
3741
32.9k
    }
3742
3743
32.9k
    {
3744
        /* PDF font records and all their associated contents need to be
3745
         * freed by means other than the garbage collector, or the memory
3746
         * usage will increase with languages other than PostScript. In addition
3747
         * debug builds of non-PS languages take a long time to close down
3748
         * due to reporting the dangling memory allocations.
3749
         */
3750
32.9k
        int j;
3751
3752
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3753
526k
            pdf_resource_t *pres = pdev->resources[resourceFont].chains[j];
3754
3755
551k
            for (; pres != 0;) {
3756
25.1k
                pdf_font_resource_t *pdfont = (pdf_font_resource_t *)pres;
3757
3758
25.1k
                font_resource_free(pdev, pdfont);
3759
25.1k
                pres = pres->next;
3760
25.1k
            }
3761
526k
        }
3762
32.9k
    }
3763
3764
32.9k
    {
3765
32.9k
        int j;
3766
3767
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3768
526k
            pdf_resource_t *pres = pdev->resources[resourceCIDFont].chains[j];
3769
3770
526k
            for (; pres != 0;) {
3771
313
                pdf_font_resource_t *pdfont = (pdf_font_resource_t *)pres;
3772
3773
313
                font_resource_free(pdev, pdfont);
3774
313
                pres = pres->next;
3775
313
            }
3776
526k
        }
3777
32.9k
    }
3778
3779
32.9k
    {
3780
32.9k
        int j;
3781
3782
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3783
526k
            pdf_resource_t *pres = pdev->resources[resourceFontDescriptor].chains[j];
3784
545k
            for (; pres != 0;) {
3785
19.2k
                pdf_font_descriptor_free(pdev, pres);
3786
19.2k
                pres = pres->next;
3787
19.2k
            }
3788
526k
        }
3789
32.9k
    }
3790
3791
32.9k
    {
3792
32.9k
        int j;
3793
3794
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3795
526k
            pdf_resource_t *pres = pdev->resources[resourceCharProc].chains[j];
3796
3797
609k
            for (; pres != 0;) {
3798
82.9k
                if (pres->object) {
3799
82.9k
                    cos_free(pres->object, "free CharProc resource");
3800
82.9k
                    pres->object = 0;
3801
82.9k
                }
3802
82.9k
                pres = pres->next;
3803
82.9k
            }
3804
526k
        }
3805
32.9k
    }
3806
3807
32.9k
    {
3808
32.9k
        int j;
3809
3810
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3811
526k
            pdf_resource_t *pres = pdev->resources[resourceExtGState].chains[j];
3812
3813
540k
            for (; pres != 0;) {
3814
14.3k
                if (pres->object) {
3815
14.3k
                    cos_release(pres->object, "release ExtGState object");
3816
14.3k
                    gs_free_object(pdev->pdf_memory, pres->object, "free ExtGState");
3817
14.3k
                    pres->object = 0;
3818
14.3k
                }
3819
14.3k
                pres = pres->next;
3820
14.3k
            }
3821
526k
        }
3822
32.9k
    }
3823
3824
32.9k
    {
3825
32.9k
        int j;
3826
3827
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3828
526k
            pdf_resource_t *pres = pdev->resources[resourcePattern].chains[j];
3829
3830
529k
            for (; pres != 0;) {
3831
3.27k
                if (pres->object) {
3832
2.30k
                    cos_release(pres->object, "free pattern dict");
3833
2.30k
                    gs_free_object(pdev->pdf_memory, pres->object, "free pattern resources");
3834
2.30k
                    pres->object = 0;
3835
2.30k
                }
3836
3.27k
                pres = pres->next;
3837
3.27k
            }
3838
526k
        }
3839
32.9k
    }
3840
3841
32.9k
    {
3842
32.9k
        int j;
3843
3844
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3845
526k
            pdf_resource_t *pres = pdev->resources[resourceShading].chains[j];
3846
3847
526k
            for (; pres != 0;) {
3848
192
                if (pres->object) {
3849
192
                    cos_release(pres->object, "free Shading dict");
3850
192
                    gs_free_object(pdev->pdf_memory, pres->object, "free Shading resources");
3851
192
                    pres->object = 0;
3852
192
                }
3853
192
                pres = pres->next;
3854
192
            }
3855
526k
        }
3856
32.9k
    }
3857
3858
32.9k
    {
3859
32.9k
        int j;
3860
3861
        /* prescan the colour space arrays to see if any of them reference other colour
3862
         * spaces. If they do, then remove the reference by changing it from a COS_VALUE_OBJECT
3863
         * into a COS_VALUE_CONST, see comment at the start of this section as to why this is safe.
3864
         */
3865
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3866
526k
            pdf_resource_t *pres = pdev->resources[resourceColorSpace].chains[j];
3867
530k
            for (; pres != 0;) {
3868
3.65k
                if (cos_type(pres->object) == cos_type_array) {
3869
3.37k
                    int64_t index;
3870
3.37k
                    cos_array_t *pca = (cos_array_t *)pres->object;
3871
3.37k
                    const cos_array_element_t *element = cos_array_element_first(pca);
3872
3.37k
                    cos_value_t *v;
3873
3874
13.4k
                    while (element) {
3875
10.0k
                        element = cos_array_element_next(element, &index, (const cos_value_t **)&v);
3876
10.0k
                        if (v->value_type == COS_VALUE_OBJECT) {
3877
2.85k
                            if (pdf_find_resource_by_resource_id(pdev, resourceColorSpace, v->contents.object->id)){
3878
189
                                v->value_type = COS_VALUE_CONST;
3879
189
                            }
3880
2.85k
                        }
3881
10.0k
                    }
3882
3.37k
                }
3883
3.65k
                pres = pres->next;
3884
3.65k
            }
3885
526k
        }
3886
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3887
526k
            pdf_resource_t *pres = pdev->resources[resourceColorSpace].chains[j];
3888
530k
            for (; pres != 0;) {
3889
3.65k
                free_color_space(pdev, pres);
3890
3.65k
                pres = pres->next;
3891
3.65k
            }
3892
526k
        }
3893
32.9k
    }
3894
3895
32.9k
    {
3896
32.9k
        int j;
3897
3898
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3899
526k
            pdf_resource_t *pres = pdev->resources[resourceGroup].chains[j];
3900
3901
526k
            for (; pres != 0;) {
3902
0
                if (pres->object) {
3903
0
                    cos_release(pres->object, "free Group dict");
3904
0
                    gs_free_object(pdev->pdf_memory, pres->object, "free Group resources");
3905
0
                    pres->object = 0;
3906
0
                }
3907
0
                pres = pres->next;
3908
0
            }
3909
526k
        }
3910
32.9k
    }
3911
3912
32.9k
    {
3913
32.9k
        int j;
3914
3915
        /* prescan the function arrays and dictionariesto see if any of them reference other
3916
         * functions. If they do, then remove the reference by changing it from a COS_VALUE_OBJECT
3917
         * into a COS_VALUE_CONST, see comment at the start of this section as to why this is safe.
3918
         */
3919
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3920
526k
            pdf_resource_t *pnext = 0, *pres = pdev->resources[resourceFunction].chains[j];
3921
3922
529k
            for (; pres != 0;) {
3923
3.32k
                if (pres->object) {
3924
3.32k
                    free_function_refs(pdev, pres->object);
3925
3.32k
                }
3926
3.32k
                pnext = pres->next;
3927
3.32k
                pres = pnext;
3928
3.32k
            }
3929
526k
        }
3930
559k
        for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3931
526k
            pdf_resource_t *pnext = 0, *pres = pdev->resources[resourceFunction].chains[j];
3932
3933
529k
            for (; pres != 0;) {
3934
3.32k
                if (pres->object) {
3935
3.32k
                    cos_release(pres->object, "free function dict");
3936
3.32k
                    gs_free_object(pdev->pdf_memory, pres->object, "free function resources");
3937
3.32k
                    pres->object = 0;
3938
3.32k
                }
3939
3.32k
                pnext = pres->next;
3940
3.32k
                pres = pnext;
3941
3.32k
            }
3942
526k
        }
3943
32.9k
    }
3944
3945
    /* Free named objects. */
3946
3947
32.9k
    if (pdev->NI_stack != NULL) {
3948
32.9k
        cos_release((cos_object_t *)pdev->NI_stack, "Release Name Index stack");
3949
32.9k
        gs_free_object(mem, pdev->NI_stack, "Free Name Index stack");
3950
32.9k
        pdev->NI_stack = 0;
3951
32.9k
    }
3952
3953
32.9k
    if (pdev->local_named_objects != NULL) {
3954
32.9k
        cos_dict_objects_delete(pdev->local_named_objects);
3955
32.9k
        COS_FREE(pdev->local_named_objects, "pdf_close(local_named_objects)");
3956
32.9k
        pdev->local_named_objects = 0;
3957
32.9k
    }
3958
3959
32.9k
    if (pdev->global_named_objects != NULL) {
3960
        /* global resources include the Catalog object and apparently the Info dict */
3961
32.9k
        cos_dict_objects_delete(pdev->global_named_objects);
3962
32.9k
        COS_FREE(pdev->global_named_objects, "pdf_close(global_named_objects)");
3963
32.9k
        pdev->global_named_objects = 0;
3964
32.9k
    }
3965
3966
32.9k
    code1 = pdf_free_resource_objects(pdev, resourceOther);
3967
32.9k
    if (code >= 0)
3968
32.7k
        code = code1;
3969
3970
32.9k
    if (code >= 0) {
3971
32.7k
        int i, j;
3972
3973
556k
        for (i = 0; i < NUM_RESOURCE_TYPES; i++) {
3974
8.90M
            for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
3975
8.37M
                pdev->resources[i].chains[j] = 0;
3976
8.37M
            }
3977
523k
        }
3978
32.7k
    }
3979
3980
    /* Release the resource records. */
3981
    /* So what exactly is stored in this list ? I believe the following types of resource:
3982
     *
3983
     * resourceCharProc
3984
     * resourceFont
3985
     * resourceCIDFont
3986
     * resourceFontDescriptor
3987
     * resourceColorSpace
3988
     * resourceExtGState
3989
     * resourceXObject
3990
     * resourceSoftMaskDict
3991
     * resourceGroup
3992
     * resourcePattern
3993
     * resourceShading
3994
     *
3995
     * resourceCMap resourcePage and resourceFunction don't appear to be tracked. I note
3996
     * that resourcePage and resourceCMap are freed above, as is resourceXObject and resourceSoftmaskDict.
3997
     * So presumably reourceFunction just leaks.
3998
     *
3999
     * It seems that all these types of resources are added when they are created
4000
     * in addition there are 'pdf_forget_resource' and pdf_cancel_resource which
4001
     * remove entries from this list.
4002
     */
4003
32.9k
    {
4004
32.9k
        pdf_resource_t *pres;
4005
32.9k
        pdf_resource_t *prev;
4006
4007
264k
        for (prev = pdev->last_resource; (pres = prev) != 0;) {
4008
231k
            prev = pres->prev;
4009
231k
            gs_free_object(mem, pres, "pdf_resource_t");
4010
231k
        }
4011
32.9k
        pdev->last_resource = 0;
4012
32.9k
    }
4013
4014
    /* Wrap up. */
4015
4016
32.9k
    pdev->font_cache = 0;
4017
4018
32.9k
    if (pdev->pages != NULL)
4019
32.9k
    {
4020
32.9k
        int i;
4021
75.4k
        for (i=0;i < pdev->next_page;i++) {
4022
42.5k
            cos_release((cos_object_t *)pdev->pages[i].Page, "Free page dict");
4023
42.5k
            if (pdev->pages[i].Annots) {
4024
0
                cos_release((cos_object_t *)pdev->pages[i].Annots, "Release Annots dict");
4025
0
                gs_free_object(mem, pdev->pages[i].Annots, "Free Annots dict");
4026
0
            }
4027
42.5k
            gs_free_object(mem, pdev->pages[i].Page, "Free Page object");
4028
42.5k
            pdev->pages[i].Page = NULL;
4029
42.5k
        }
4030
1.68M
        for (i=0;i < pdev->num_pages;i++) {
4031
1.64M
            if (pdev->pages[i].Page != NULL) {
4032
18
                emprintf(pdev->memory,
4033
18
                         "Page object was reserved for an Annotation destination, but no such page was drawn, annotation in output will be invalid.\n");
4034
18
                gs_free_object(mem, pdev->pages[i].Page, "Free Page object");
4035
18
                pdev->pages[i].Page = NULL;
4036
18
            }
4037
1.64M
        }
4038
32.9k
    }
4039
32.9k
    gs_free_object(mem, pdev->pages, "pages");
4040
32.9k
    pdev->pages = 0;
4041
4042
32.9k
    pdev->num_pages = 0;
4043
4044
32.9k
    gs_free_object(mem, pdev->sbstack, "Free sbstack");
4045
32.9k
    pdev->sbstack = 0;
4046
4047
32.9k
    if (pdev->text != NULL)
4048
32.9k
        text_data_free(mem, pdev->text);
4049
32.9k
    pdev->text = 0;
4050
4051
32.9k
    if (pdev->Pages != NULL) {
4052
32.9k
        cos_release((cos_object_t *)pdev->Pages, "release Pages dict");
4053
32.9k
        gs_free_object(mem, pdev->Pages, "Free Pages dict");
4054
32.9k
        pdev->Pages = 0;
4055
32.9k
    }
4056
4057
32.9k
    if (pdev->vgstack != NULL)
4058
32.9k
    {
4059
32.9k
        int i;
4060
394k
        for (i=0;i < pdev->vgstack_size;i++) {
4061
361k
            if (pdev->vgstack[i].dash_pattern != NULL)
4062
176
                gs_free_object(pdev->memory->non_gc_memory, pdev->vgstack[i].dash_pattern, "pdfwrite final free stored dash in gstate");
4063
361k
            if (pdev->vgstack[i].clip_path != 0)
4064
2.99k
                gx_path_free(pdev->vgstack[i].clip_path, "pdf clip path");
4065
361k
        }
4066
32.9k
        gs_free_object(pdev->pdf_memory, pdev->vgstack, "pdf_close(graphics state stack)");
4067
32.9k
        pdev->vgstack = 0;
4068
32.9k
    }
4069
4070
32.9k
    if (pdev->Namespace_stack != NULL) {
4071
32.9k
        cos_release((cos_object_t *)pdev->Namespace_stack, "release Name space stack");
4072
32.9k
        gs_free_object(mem, pdev->Namespace_stack, "Free Name space stack");
4073
32.9k
        pdev->Namespace_stack = 0;
4074
32.9k
    }
4075
4076
32.9k
    pdev->Catalog = 0;
4077
32.9k
    pdev->Info = 0;
4078
4079
32.9k
    gs_free_object(mem, pdev->outline_levels, "outline_levels array");
4080
32.9k
    pdev->outline_levels = 0;
4081
32.9k
    pdev->outline_depth = -1;
4082
32.9k
    pdev->max_outline_depth = 0;
4083
4084
32.9k
    if (s != NULL)
4085
32.9k
    {
4086
        /* pdf_open_dcument could set up filters for entire document.
4087
           Removing them now. */
4088
32.9k
        int status;
4089
4090
32.9k
        if (!pdev->ProduceDSC)
4091
0
            stream_putc(s, 0x04);
4092
65.8k
        while (s->strm) {
4093
32.9k
            s = s->strm;
4094
32.9k
        }
4095
32.9k
        status = s_close_filters(&pdev->strm, s);
4096
32.9k
        if (status < 0 && code == 0)
4097
0
            code = gs_error_ioerror;
4098
32.9k
    }
4099
4100
32.9k
    pdf_free_pdf_font_cache(pdev);
4101
4102
32.9k
    code1 = gdev_vector_close_file((gx_device_vector *) pdev);
4103
32.9k
    if (code >= 0)
4104
32.7k
        code = code1;
4105
32.9k
    if (pdev->max_referred_page >= pdev->next_page + 1 && pdev->next_page != 0 && !file_per_page) {
4106
        /* Note : pdev->max_referred_page counts from 1,
4107
           and pdev->next_page counts from 0. */
4108
0
        emprintf2(pdev->memory, "ERROR: A pdfmark destination page %d "
4109
0
                  "points beyond the last page %d.\n",
4110
0
                  pdev->max_referred_page, pdev->next_page);
4111
0
    }
4112
32.9k
    code = pdf_close_files(pdev, code);
4113
32.9k
    if (code < 0)
4114
173
        return code;
4115
4116
    /* If we didn't get called from pdf_output_page, and we are doign file-per-page
4117
     * output, then the call from close_device will leave an empty file which we don't
4118
     * want. So here we delete the file.
4119
     * NOTE: We needed to let it process the whole page in order to make sure everything
4120
     * got properly freed.
4121
     */
4122
32.7k
    if (file_per_page) {
4123
0
        code = gx_device_delete_output_file((const gx_device *)pdev, pdev->fname);
4124
0
        if (code != 0)
4125
0
            code = gs_note_error(gs_error_ioerror);
4126
0
    }
4127
4128
32.7k
    return code;
4129
32.9k
}