Coverage Report

Created: 2022-10-31 07:00

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