Coverage Report

Created: 2026-02-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/devices/vector/gdevpdfo.c
Line
Count
Source
1
/* Copyright (C) 2001-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Cos object support */
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gsparam.h"
22
#include "gsutil.h"   /* for bytes_compare */
23
#include "gdevpdfx.h"
24
#include "gdevpdfo.h"
25
#include "strimpl.h"
26
#include "sa85x.h"
27
#include "sarc4.h"
28
#include "sstring.h"
29
30
#define CHECK(expr)\
31
304k
  BEGIN if ((code = (expr)) < 0) return code; END
32
33
/* ---------------- Structure definitions ---------------- */
34
35
/*
36
 * Define the generic structure for elements of arrays and
37
 * dictionaries/streams.
38
 */
39
#define cos_element_common(etype)\
40
    etype *next
41
struct cos_element_s {
42
    cos_element_common(cos_element_t);
43
};
44
#define private_st_cos_element()  /* in gdevpdfo.c */\
45
  gs_private_st_ptrs1(st_cos_element, cos_element_t, "cos_element_t",\
46
    cos_element_enum_ptrs, cos_element_reloc_ptrs, next)
47
6.92M
#define cos_element_num_ptrs 1
48
49
/*
50
 * Define the structure for a piece of stream contents.
51
 */
52
struct cos_stream_piece_s {
53
    cos_element_common(cos_stream_piece_t);
54
    gs_offset_t position;   /* in streams file */
55
    uint size;
56
};
57
#define private_st_cos_stream_piece() /* in gdevpdfo.c */\
58
  gs_private_st_suffix_add0_local(st_cos_stream_piece, cos_stream_piece_t,\
59
    "cos_stream_piece_t", cos_element_enum_ptrs, cos_element_reloc_ptrs,\
60
    st_cos_element)
61
62
/*
63
 * Define Cos arrays, dictionaries, and streams.
64
 */
65
     /* array */
66
struct cos_array_element_s {
67
    cos_element_common(cos_array_element_t);
68
    long index;
69
    cos_value_t value;
70
};
71
#define private_st_cos_array_element()  /* in gdevpdfo.c */\
72
  gs_private_st_composite(st_cos_array_element, cos_array_element_t,\
73
    "cos_array_element_t", cos_array_element_enum_ptrs, cos_array_element_reloc_ptrs)
74
    /* dict */
75
struct cos_dict_element_s {
76
    cos_element_common(cos_dict_element_t);
77
    gs_string key;
78
    bool owns_key;  /* if false, key is shared, do not trace or free */
79
    cos_value_t value;
80
};
81
#define private_st_cos_dict_element() /* in gdevpdfo.c */\
82
  gs_private_st_composite(st_cos_dict_element, cos_dict_element_t,\
83
    "cos_dict_element_t", cos_dict_element_enum_ptrs, cos_dict_element_reloc_ptrs)
84
85
/* GC descriptors */
86
private_st_cos_element();
87
private_st_cos_stream_piece();
88
private_st_cos_object();
89
private_st_cos_value();
90
private_st_cos_array_element();
91
private_st_cos_dict_element();
92
93
/* GC procedures */
94
static
95
2.29M
ENUM_PTRS_WITH(cos_value_enum_ptrs, cos_value_t *pcv) return 0;
96
1.20M
 case 0:
97
1.20M
    switch (pcv->value_type) {
98
723k
    case COS_VALUE_SCALAR:
99
723k
        return ENUM_STRING(&pcv->contents.chars);
100
108k
    case COS_VALUE_CONST:
101
108k
        break;
102
370k
    case COS_VALUE_OBJECT:
103
370k
    case COS_VALUE_RESOURCE:
104
370k
        return ENUM_OBJ(pcv->contents.object);
105
1.20M
    }
106
108k
    return 0;
107
2.29M
ENUM_PTRS_END
108
static
109
1.20M
RELOC_PTRS_WITH(cos_value_reloc_ptrs, cos_value_t *pcv)
110
1.20M
{
111
1.20M
    switch (pcv->value_type) {
112
722k
    case COS_VALUE_SCALAR:
113
722k
        RELOC_STRING_VAR(pcv->contents.chars);
114
831k
    case COS_VALUE_CONST:
115
831k
        break;
116
370k
    case COS_VALUE_OBJECT:
117
370k
    case COS_VALUE_RESOURCE:
118
370k
        RELOC_VAR(pcv->contents.object);
119
370k
        break;
120
1.20M
    }
121
1.20M
}
122
1.20M
RELOC_PTRS_END
123
static
124
949k
ENUM_PTRS_WITH(cos_array_element_enum_ptrs, cos_array_element_t *pcae)
125
949k
{
126
949k
    return (index < cos_element_num_ptrs ?
127
949k
            ENUM_USING_PREFIX(st_cos_element, 0) :
128
949k
            ENUM_USING(st_cos_value, &pcae->value, sizeof(cos_value_t),
129
949k
                       index - cos_element_num_ptrs));
130
0
}
131
949k
ENUM_PTRS_END
132
static
133
323k
RELOC_PTRS_WITH(cos_array_element_reloc_ptrs, cos_array_element_t *pcae)
134
323k
{
135
323k
    RELOC_PREFIX(st_cos_element);
136
323k
    RELOC_USING(st_cos_value, &pcae->value, sizeof(cos_value_t));
137
323k
}
138
323k
RELOC_PTRS_END
139
static
140
3.42M
ENUM_PTRS_WITH(cos_dict_element_enum_ptrs, cos_dict_element_t *pcde)
141
3.42M
{
142
3.42M
    return (index < cos_element_num_ptrs ?
143
3.42M
            ENUM_USING_PREFIX(st_cos_element, 0) :
144
3.42M
            (index -= cos_element_num_ptrs) > 0 ?
145
1.67M
            ENUM_USING(st_cos_value, &pcde->value, sizeof(cos_value_t),
146
2.54M
                       index - 1) :
147
2.54M
            pcde->owns_key ? ENUM_STRING(&pcde->key) : ENUM_OBJ(NULL));
148
0
}
149
3.42M
ENUM_PTRS_END
150
static
151
878k
RELOC_PTRS_WITH(cos_dict_element_reloc_ptrs, cos_dict_element_t *pcde)
152
878k
{
153
878k
    RELOC_PREFIX(st_cos_element);
154
878k
    if (pcde->owns_key)
155
282k
        RELOC_STRING_VAR(pcde->key);
156
878k
    RELOC_USING(st_cos_value, &pcde->value, sizeof(cos_value_t));
157
878k
}
158
878k
RELOC_PTRS_END
159
160
/* ---------------- Generic support ---------------- */
161
162
/* Initialize a just-allocated cos object. */
163
static void
164
cos_object_init(cos_object_t *pco, gx_device_pdf *pdev,
165
                const cos_object_procs_t *procs)
166
1.82M
{
167
1.82M
    if (pco) {
168
1.82M
        pco->cos_procs = procs;
169
1.82M
        pco->id = 0;
170
1.82M
        pco->elements = 0;
171
1.82M
        pco->pieces = 0;
172
1.82M
        pco->mem = pdev->pdf_memory;
173
1.82M
        pco->pres = 0;
174
1.82M
        pco->is_open = true;
175
1.82M
        pco->is_graphics = false;
176
1.82M
        pco->written = false;
177
1.82M
        pco->length = 0;
178
1.82M
        pco->input_strm = 0;
179
1.82M
        pco->md5_valid = 0;
180
1.82M
        pco->stream_md5_valid = 0;
181
1.82M
        memset(&pco->hash, 0x00, 16);
182
1.82M
    }
183
1.82M
}
184
185
/* Get the allocator for a Cos object. */
186
gs_memory_t *
187
cos_object_memory(const cos_object_t *pco)
188
19.2M
{
189
19.2M
    return pco->mem;
190
19.2M
}
191
192
/* Change a generic cos object into one of a specific type. */
193
int
194
cos_become(cos_object_t *pco, cos_type_t cotype)
195
546k
{
196
546k
    if (cos_type(pco) != cos_type_generic)
197
0
        return_error(gs_error_typecheck);
198
546k
    cos_type(pco) = cotype;
199
546k
    return 0;
200
546k
}
201
202
/* Release a cos object. */
203
cos_proc_release(cos_release);  /* check prototype */
204
void
205
cos_release(cos_object_t *pco, client_name_t cname)
206
1.79M
{
207
1.79M
    pco->cos_procs->release(pco, cname);
208
1.79M
}
209
210
/* Free a cos object. */
211
void
212
cos_free(cos_object_t *pco, client_name_t cname)
213
1.32M
{
214
1.32M
    cos_release(pco, cname);
215
1.32M
    gs_free_object(cos_object_memory(pco), pco, cname);
216
1.32M
}
217
218
/* Write a cos object on the output. */
219
cos_proc_write(cos_write);  /* check prototype */
220
int
221
cos_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
222
832k
{
223
832k
    return pco->cos_procs->write(pco, pdev, object_id);
224
832k
}
225
226
/* Write a cos object as a PDF object. */
227
int
228
cos_stream_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id);
229
230
int
231
cos_write_object(cos_object_t *pco, gx_device_pdf *pdev, pdf_resource_type_t type)
232
249k
{
233
249k
    int code;
234
235
249k
    if (pco->id == 0 || pco->written)
236
0
        return_error(gs_error_Fatal);
237
249k
    if (pco->cos_procs->write == cos_stream_write)
238
110k
        pdf_open_separate_noObjStm(pdev, pco->id, type);
239
139k
    else
240
139k
        pdf_open_separate(pdev, pco->id, type);
241
249k
    code = cos_write(pco, pdev, pco->id);
242
249k
    if (pco->cos_procs->write == cos_stream_write)
243
110k
        pdf_end_separate_noObjStm(pdev, type);
244
139k
    else
245
139k
        pdf_end_separate(pdev, type);
246
249k
    pco->written = true;
247
249k
    return code;
248
249k
}
249
250
/* Make a value to store into a composite object. */
251
const cos_value_t *
252
cos_string_value(cos_value_t *pcv, const byte *data, uint size)
253
2.48M
{
254
    /*
255
     * It's OK to break const here, because the value will be copied
256
     * before being stored in the collection.
257
     */
258
2.48M
    pcv->contents.chars.data = (byte *)data;
259
2.48M
    pcv->contents.chars.size = size;
260
2.48M
    pcv->value_type = COS_VALUE_SCALAR;
261
2.48M
    return pcv;
262
2.48M
}
263
const cos_value_t *
264
cos_c_string_value(cos_value_t *pcv, const char *str)
265
951k
{
266
    /*
267
     * We shouldn't break const here, because the value will not be copied
268
     * or freed (or traced), but that would require a lot of bothersome
269
     * casting elsewhere.
270
     */
271
951k
    pcv->contents.chars.data = (byte *)str;
272
951k
    pcv->contents.chars.size = strlen(str);
273
951k
    pcv->value_type = COS_VALUE_CONST;
274
951k
    return pcv;
275
951k
}
276
const cos_value_t *
277
cos_object_value(cos_value_t *pcv, cos_object_t *pco)
278
891k
{
279
891k
    pcv->contents.object = pco;
280
891k
    pcv->value_type = COS_VALUE_OBJECT;
281
891k
    return pcv;
282
891k
}
283
const cos_value_t *
284
cos_resource_value(cos_value_t *pcv, cos_object_t *pco)
285
45.7k
{
286
45.7k
    pcv->contents.object = pco;
287
45.7k
    pcv->value_type = COS_VALUE_RESOURCE;
288
45.7k
    return pcv;
289
45.7k
}
290
291
/* Free a value. */
292
void
293
cos_value_free(const cos_value_t *pcv, gs_memory_t *mem,
294
               client_name_t cname)
295
4.27M
{
296
4.27M
    switch (pcv->value_type) {
297
2.44M
    case COS_VALUE_SCALAR:
298
2.44M
        gs_free_string(mem, pcv->contents.chars.data,
299
2.44M
                       pcv->contents.chars.size, cname);
300
3.39M
    case COS_VALUE_CONST:
301
3.39M
        break;
302
879k
    case COS_VALUE_OBJECT:
303
        /* Free the object if this is the only reference to it. */
304
879k
        if (pcv->contents.object != NULL) /* see cos_dict_objects_delete. */
305
879k
            if (!pcv->contents.object->id)
306
832k
                cos_free(pcv->contents.object, cname);
307
880k
    case COS_VALUE_RESOURCE:
308
880k
        break;
309
4.27M
    }
310
4.27M
}
311
312
/* Write a value on the output. */
313
static int
314
cos_value_write_spaced(const cos_value_t *pcv, gx_device_pdf *pdev,
315
                       bool do_space, gs_id object_id)
316
3.50M
{
317
3.50M
    stream *s = pdev->strm;
318
319
3.50M
    switch (pcv->value_type) {
320
2.15M
    case COS_VALUE_SCALAR:
321
2.83M
    case COS_VALUE_CONST:
322
2.83M
        if (do_space)
323
1.95M
            switch (pcv->contents.chars.data[0]) {
324
656k
            case '/': case '(': case '<': break;
325
1.29M
            default: stream_putc(s, ' ');
326
1.95M
            }
327
2.83M
        return pdf_write_value(pdev, pcv->contents.chars.data,
328
2.83M
                        pcv->contents.chars.size, object_id);
329
45.6k
    case COS_VALUE_RESOURCE:
330
45.6k
        pprinti64d1(s, "/R%"PRId64"", pcv->contents.object->id);
331
45.6k
        break;
332
624k
    case COS_VALUE_OBJECT: {
333
624k
        cos_object_t *pco = pcv->contents.object;
334
335
624k
        if (!pco->id) {
336
548k
            if (do_space &&
337
458k
                !(pco->cos_procs == cos_type_array ||
338
45.1k
                  pco->cos_procs == cos_type_dict)
339
548k
                ) {
340
                /* Arrays and dictionaries (only) are self-delimiting. */
341
0
                stream_putc(s, ' ');
342
0
            }
343
548k
            return cos_write(pco, pdev, object_id);
344
548k
        }
345
75.8k
        if (do_space)
346
27.4k
            stream_putc(s, ' ');
347
75.8k
        pprinti64d1(s, "%"PRId64" 0 R", pco->id);
348
75.8k
        if (pco->cos_procs == cos_type_reference)
349
0
            pco->id = 0;
350
75.8k
        break;
351
624k
    }
352
0
    default:      /* can't happen */
353
0
        return_error(gs_error_Fatal);
354
3.50M
    }
355
121k
    return 0;
356
3.50M
}
357
int
358
cos_value_write(const cos_value_t *pcv, gx_device_pdf *pdev)
359
50.1k
{
360
50.1k
    return cos_value_write_spaced(pcv, pdev, false, 0);
361
50.1k
}
362
363
/* Copy a value if necessary for putting into an array or dictionary. */
364
static int
365
cos_copy_element_value(cos_value_t *pcv, gs_memory_t *mem,
366
                       const cos_value_t *pvalue, bool copy)
367
4.27M
{
368
4.27M
    *pcv = *pvalue;
369
4.27M
    if (pvalue->value_type == COS_VALUE_SCALAR && copy) {
370
2.12M
        byte *value_data = gs_alloc_string(mem, pvalue->contents.chars.size,
371
2.12M
                                           "cos_copy_element_value");
372
373
2.12M
        if (value_data == 0)
374
0
            return_error(gs_error_VMerror);
375
2.12M
        memcpy(value_data, pvalue->contents.chars.data,
376
2.12M
               pvalue->contents.chars.size);
377
2.12M
        pcv->contents.chars.data = value_data;
378
2.12M
    }
379
4.27M
    return 0;
380
4.27M
}
381
382
/* Release a value copied for putting, if the operation fails. */
383
static void
384
cos_uncopy_element_value(cos_value_t *pcv, gs_memory_t *mem, bool copy)
385
0
{
386
0
    if (pcv->value_type == COS_VALUE_SCALAR && copy)
387
0
        gs_free_string(mem, pcv->contents.chars.data, pcv->contents.chars.size,
388
0
                       "cos_uncopy_element_value");
389
0
}
390
391
static int cos_value_hash(cos_value_t *pcv0, gs_md5_state_t *md5, gs_md5_byte_t *hash, gx_device_pdf *pdev)
392
1.20M
{
393
1.20M
    int code;
394
1.20M
    switch (pcv0->value_type) {
395
691k
        case COS_VALUE_SCALAR:
396
929k
        case COS_VALUE_CONST:
397
929k
            gs_md5_append(md5, pcv0->contents.chars.data, pcv0->contents.chars.size);
398
929k
            break;
399
400
275k
        case COS_VALUE_OBJECT:
401
275k
            code = pcv0->contents.object->cos_procs->hash(pcv0->contents.object, md5, hash, pdev);
402
275k
            if (code < 0)
403
0
                return code;
404
275k
            break;
405
275k
        case COS_VALUE_RESOURCE:
406
0
            break;
407
1.20M
    }
408
1.20M
    return 0;
409
1.20M
}
410
411
/* ---------------- Specific object types ---------------- */
412
413
/* ------ Generic objects ------ */
414
415
static cos_proc_release(cos_reference_release);
416
static cos_proc_release(cos_generic_release);
417
static cos_proc_write(cos_generic_write);
418
static cos_proc_equal(cos_generic_equal);
419
static cos_proc_hash(cos_generic_hash);
420
const cos_object_procs_t cos_generic_procs = {
421
    cos_generic_release, cos_generic_write, cos_generic_equal, cos_generic_hash
422
};
423
const cos_object_procs_t cos_reference_procs = {
424
    cos_reference_release, cos_generic_write, cos_generic_equal, cos_generic_hash
425
};
426
427
cos_object_t *
428
cos_object_alloc(gx_device_pdf *pdev, client_name_t cname)
429
721k
{
430
721k
    gs_memory_t *mem = pdev->pdf_memory;
431
721k
    cos_object_t *pco =
432
721k
        gs_alloc_struct(mem, cos_object_t, &st_cos_object, cname);
433
434
721k
    cos_object_init(pco, pdev, &cos_generic_procs);
435
721k
    return pco;
436
721k
}
437
438
cos_object_t *
439
cos_reference_alloc(gx_device_pdf *pdev, client_name_t cname)
440
0
{
441
0
    gs_memory_t *mem = pdev->pdf_memory;
442
0
    cos_object_t *pco =
443
0
        gs_alloc_struct(mem, cos_object_t, &st_cos_object, cname);
444
445
0
    cos_object_init(pco, pdev, &cos_reference_procs);
446
0
    return pco;
447
0
}
448
449
static void
450
cos_reference_release(cos_object_t *pco, client_name_t cname)
451
0
{
452
    /* Do nothing. */
453
0
}
454
455
static void
456
cos_generic_release(cos_object_t *pco, client_name_t cname)
457
107k
{
458
    /* Do nothing. */
459
107k
}
460
461
static int
462
cos_generic_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
463
61
{
464
61
    return_error(gs_error_Fatal);
465
61
}
466
467
static int
468
cos_generic_equal(const cos_object_t *pco0, const cos_object_t *pco1, gx_device_pdf *pdev)
469
0
{
470
0
    return_error(gs_error_Fatal);
471
0
}
472
473
static int
474
cos_generic_hash(const cos_object_t *pco0, gs_md5_state_t *md5, gs_md5_byte_t *hash, gx_device_pdf *pdev)
475
0
{
476
0
    return_error(gs_error_Fatal);
477
0
}
478
479
/* ------ Arrays ------ */
480
481
static cos_proc_release(cos_array_release);
482
static cos_proc_write(cos_array_write);
483
static cos_proc_equal(cos_array_equal);
484
static cos_proc_hash(cos_array_hash);
485
const cos_object_procs_t cos_array_procs = {
486
    cos_array_release, cos_array_write, cos_array_equal, cos_array_hash
487
};
488
489
cos_array_t *
490
cos_array_alloc(gx_device_pdf *pdev, client_name_t cname)
491
638k
{
492
638k
    gs_memory_t *mem = pdev->pdf_memory;
493
638k
    cos_array_t *pca =
494
638k
        gs_alloc_struct(mem, cos_array_t, &st_cos_object, cname);
495
496
638k
    cos_object_init((cos_object_t *)pca, pdev, &cos_array_procs);
497
638k
    return pca;
498
638k
}
499
500
cos_array_t *
501
cos_array_from_floats(gx_device_pdf *pdev, const float *pf, uint size,
502
                      client_name_t cname)
503
47.5k
{
504
47.5k
    cos_array_t *pca = cos_array_alloc(pdev, cname);
505
47.5k
    uint i;
506
507
47.5k
    if (pca == 0)
508
0
        return 0;
509
282k
    for (i = 0; i < size; ++i) {
510
235k
        int code = cos_array_add_real(pca, pf[i]);
511
512
235k
        if (code < 0) {
513
0
            COS_FREE(pca, cname);
514
0
            return 0;
515
0
        }
516
235k
    }
517
47.5k
    return pca;
518
47.5k
}
519
520
static void
521
cos_array_release(cos_object_t *pco, client_name_t cname)
522
638k
{
523
638k
    cos_array_t *const pca = (cos_array_t *)pco;
524
638k
    cos_array_element_t *cur;
525
638k
    cos_array_element_t *next;
526
527
1.92M
    for (cur = pca->elements; cur; cur = next) {
528
1.28M
        next = cur->next;
529
1.28M
        cos_value_free(&cur->value, cos_object_memory(pco), cname);
530
1.28M
        gs_free_object(cos_object_memory(pco), cur, cname);
531
1.28M
    }
532
638k
    pca->elements = 0;
533
638k
}
534
535
static cos_array_element_t *cos_array_reorder(const cos_array_t *pca,
536
                                               cos_array_element_t *first);
537
static int
538
cos_array_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
539
420k
{
540
420k
    stream *s = pdev->strm;
541
420k
    const cos_array_t *const pca = (const cos_array_t *)pco;
542
420k
    cos_array_element_t *first = cos_array_reorder(pca, NULL);
543
420k
    cos_array_element_t *pcae;
544
420k
    uint last_index = 0, Element_Count = 0;
545
546
420k
    stream_puts(s, "[");
547
1.43M
    for (pcae = first; pcae; ++last_index, pcae = pcae->next) {
548
1.01M
        Element_Count++;
549
550
1.01M
        if(pdev->PDFA != 0 && Element_Count > 8191) {
551
0
            switch (pdev->PDFACompatibilityPolicy) {
552
0
            case 0:
553
0
                emprintf(pdev->memory,
554
0
                    "Too many entries in array,\n max 8191 in PDF/A, reverting to normal PDF output\n");
555
0
                pdev->AbortPDFAX = true;
556
0
                pdev->PDFA = 0;
557
0
                break;
558
0
            case 1:
559
0
                emprintf(pdev->memory,
560
0
                     "Too many entries in array,\n max 8191 in PDF/A. Cannot simply elide dictionary, reverting to normal output\n");
561
0
                pdev->AbortPDFAX = true;
562
0
                pdev->PDFA = 0;
563
0
                break;
564
0
            case 2:
565
0
                emprintf(pdev->memory,
566
0
                     "Too many entries in array,\n max 8191 in PDF/A. aborting conversion\n");
567
                /* Careful here, only certain errors will bubble up
568
                 * through the text processing.
569
                 */
570
0
                return_error(gs_error_limitcheck);
571
0
                break;
572
0
            default:
573
0
                emprintf(pdev->memory,
574
0
                     "Too many entries in array,\n max 8191 in PDF/A. Unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
575
0
                pdev->AbortPDFAX = true;
576
0
                pdev->PDFA = 0;
577
0
                break;
578
0
            }
579
0
        }
580
1.01M
        if (pcae != first)
581
589k
            stream_putc(s, '\n');
582
1.01M
        for (; pcae->index > last_index; ++last_index)
583
0
            stream_puts(s, "null\n");
584
1.01M
        cos_value_write_spaced(&pcae->value, pdev, false, object_id);
585
1.01M
    }
586
420k
    DISCARD(cos_array_reorder(pca, first));
587
420k
    stream_puts(s, "]");
588
420k
    if (pdev->PDFA != 0)
589
0
        stream_puts(s, "\n");
590
420k
    return 0;
591
420k
}
592
593
static int
594
cos_array_equal(const cos_object_t *pco0, const cos_object_t *pco1, gx_device_pdf *pdev)
595
0
{
596
0
    const cos_array_t *const pca0 = (const cos_array_t *)pco0;
597
0
    const cos_array_t *const pca1 = (const cos_array_t *)pco1;
598
0
    int code;
599
600
0
    if (!pca0->md5_valid) {
601
0
        gs_md5_init((gs_md5_state_t *)&pca0->md5);
602
0
        code = cos_array_hash(pco0, (gs_md5_state_t *)&pca0->md5, (gs_md5_byte_t *)pca0->hash, pdev);
603
0
        if (code < 0)
604
0
            return code;
605
0
        gs_md5_finish((gs_md5_state_t *)&pca0->md5, (gs_md5_byte_t *)pca0->hash);
606
0
        ((cos_object_t *)pca0)->md5_valid = true;
607
0
    }
608
0
    if (!pca1->md5_valid) {
609
0
        gs_md5_init((gs_md5_state_t *)&pca1->md5);
610
0
        code = cos_array_hash(pco1, (gs_md5_state_t *)&pca1->md5, (gs_md5_byte_t *)pca1->hash, pdev);
611
0
        if (code < 0)
612
0
            return code;
613
0
        gs_md5_finish((gs_md5_state_t *)&pca1->md5, (gs_md5_byte_t *)pca1->hash);
614
0
        ((cos_object_t *)pca1)->md5_valid = true;
615
0
    }
616
0
    if (memcmp(&pca0->hash, &pca1->hash, 16) != 0)
617
0
        return false;
618
619
0
    return true;
620
0
}
621
622
static int
623
cos_array_hash(const cos_object_t *pco0, gs_md5_state_t *md5, gs_md5_byte_t *hash, gx_device_pdf *pdev)
624
223k
{
625
223k
    const cos_array_t *const pca0 = (const cos_array_t *)pco0;
626
223k
    cos_array_element_t *first0 = pca0->elements;
627
223k
    cos_array_element_t *pcae0;
628
223k
    int code;
629
630
771k
    for (pcae0 = first0; pcae0;pcae0 = pcae0->next) {
631
547k
        code = cos_value_hash(&pcae0->value, md5, hash, pdev);
632
547k
        if (code < 0)
633
0
            return code;
634
547k
    }
635
223k
    return 0;
636
223k
}
637
638
/* Put/add an element in/to an array. */
639
int
640
cos_array_put(cos_array_t *pca, int64_t index, const cos_value_t *pvalue)
641
1.28M
{
642
1.28M
    gs_memory_t *mem = COS_OBJECT_MEMORY(pca);
643
1.28M
    cos_value_t value;
644
1.28M
    int code = cos_copy_element_value(&value, mem, pvalue, true);
645
646
1.28M
    if (code >= 0) {
647
1.28M
        code = cos_array_put_no_copy(pca, index, &value);
648
1.28M
        if (code < 0)
649
0
            cos_uncopy_element_value(&value, mem, true);
650
1.28M
    }
651
1.28M
    pca->md5_valid = false;
652
1.28M
    return code;
653
1.28M
}
654
int
655
cos_array_put_no_copy(cos_array_t *pca, int64_t index, const cos_value_t *pvalue)
656
1.28M
{
657
1.28M
    gs_memory_t *mem = COS_OBJECT_MEMORY(pca);
658
1.28M
    cos_array_element_t **ppcae = &pca->elements;
659
1.28M
    cos_array_element_t *pcae;
660
1.28M
    cos_array_element_t *next;
661
662
1.28M
    while ((next = *ppcae) != 0 && next->index > index)
663
0
        ppcae = &next->next;
664
1.28M
    if (next && next->index == index) {
665
        /* We're replacing an existing element. */
666
0
        cos_value_free(&next->value, mem,
667
0
                       "cos_array_put(old value)");
668
0
        pcae = next;
669
1.28M
    } else {
670
        /* Create a new element. */
671
1.28M
        pcae = gs_alloc_struct(mem, cos_array_element_t, &st_cos_array_element,
672
1.28M
                               "cos_array_put(element)");
673
1.28M
        if (pcae == 0)
674
0
            return_error(gs_error_VMerror);
675
1.28M
        pcae->index = index;
676
1.28M
        pcae->next = next;
677
1.28M
        *ppcae = pcae;
678
1.28M
    }
679
1.28M
    pcae->value = *pvalue;
680
1.28M
    pca->md5_valid = false;
681
1.28M
    return 0;
682
1.28M
}
683
static long
684
cos_array_next_index(const cos_array_t *pca)
685
1.28M
{
686
1.28M
    return (pca->elements ? pca->elements->index + 1 : 0L);
687
1.28M
}
688
int
689
cos_array_add(cos_array_t *pca, const cos_value_t *pvalue)
690
1.28M
{
691
1.28M
    pca->md5_valid = false;
692
1.28M
    return cos_array_put(pca, cos_array_next_index(pca), pvalue);
693
1.28M
}
694
int
695
cos_array_add_no_copy(cos_array_t *pca, const cos_value_t *pvalue)
696
929
{
697
929
    pca->md5_valid = false;
698
929
    return cos_array_put_no_copy(pca, cos_array_next_index(pca), pvalue);
699
929
}
700
int
701
cos_array_add_c_string(cos_array_t *pca, const char *str)
702
446k
{
703
446k
    cos_value_t value;
704
705
446k
    return cos_array_add(pca, cos_c_string_value(&value, str));
706
446k
}
707
int
708
cos_array_add_int(cos_array_t *pca, int i)
709
15.9k
{
710
15.9k
    char str[sizeof(int) * 8 / 3 + 3]; /* sign, rounding, 0 terminator */
711
15.9k
    cos_value_t v;
712
713
15.9k
    gs_snprintf(str, sizeof(str), "%d", i);
714
15.9k
    return cos_array_add(pca, cos_string_value(&v, (byte *)str, strlen(str)));
715
15.9k
}
716
int
717
cos_array_add_real(cos_array_t *pca, double r)
718
673k
{
719
673k
    byte str[50];   /****** ADHOC ******/
720
673k
    stream s;
721
673k
    cos_value_t v;
722
723
673k
    s_init(&s, NULL);
724
673k
    swrite_string(&s, str, sizeof(str));
725
673k
    pprintg1(&s, "%g", r);
726
673k
    return cos_array_add(pca, cos_string_value(&v, str, stell(&s)));
727
673k
}
728
int
729
cos_array_add_object(cos_array_t *pca, cos_object_t *pco)
730
93.2k
{
731
93.2k
    cos_value_t value;
732
733
93.2k
    value.contents.chars.size = 0; /* Quiet a warning appeared with MSVC6 inline optimization. */
734
93.2k
    return cos_array_add(pca, cos_object_value(&value, pco));
735
93.2k
}
736
737
/*
738
 * Remove and return the last element of an array.  Since this is intended
739
 * specifically for arrays used as stacks, it gives an error if there is a
740
 * gap in indices between the last element and the element before it.
741
 */
742
int
743
cos_array_unadd(cos_array_t *pca, cos_value_t *pvalue)
744
136k
{
745
136k
    cos_array_element_t *pcae = pca->elements;
746
747
136k
    if (pcae == 0 ||
748
1.51k
        pcae->index != (pcae->next == 0 ? 0 : pcae->next->index + 1)
749
136k
        )
750
135k
        return_error(gs_error_rangecheck);
751
1.51k
    *pvalue = pcae->value;
752
1.51k
    pca->elements = pcae->next;
753
1.51k
    gs_free_object(COS_OBJECT_MEMORY(pca), pcae, "cos_array_unadd");
754
1.51k
    pca->md5_valid = false;
755
1.51k
    return 0;
756
136k
}
757
758
/* Get the first / next element for enumerating an array. */
759
const cos_array_element_t *
760
cos_array_element_first(const cos_array_t *pca)
761
11.6k
{
762
11.6k
    return pca->elements;
763
11.6k
}
764
const cos_array_element_t *
765
cos_array_element_next(const cos_array_element_t *pca, int64_t *pindex,
766
                       const cos_value_t **ppvalue)
767
74.4k
{
768
74.4k
    *pindex = pca->index;
769
74.4k
    *ppvalue = &pca->value;
770
74.4k
    return pca->next;
771
74.4k
}
772
773
/*
774
 * Reorder the elements of an array for writing or after writing.  Usage:
775
 *  first_element = cos_array_reorder(pca, NULL);
776
 *  ...
777
 *  cos_array_reorder(pca, first_element);
778
 */
779
static cos_array_element_t *
780
cos_array_reorder(const cos_array_t *pca, cos_array_element_t *first)
781
841k
{
782
841k
    cos_array_element_t *last;
783
841k
    cos_array_element_t *next;
784
841k
    cos_array_element_t *pcae;
785
786
2.86M
    for (pcae = (first ? first : pca->elements), last = NULL; pcae;
787
2.02M
         pcae = next)
788
2.02M
        next = pcae->next, pcae->next = last, last = pcae;
789
841k
    return last;
790
841k
}
791
792
/* ------ Dictionaries ------ */
793
794
static cos_proc_release(cos_dict_release);
795
static cos_proc_write(cos_dict_write);
796
static cos_proc_equal(cos_dict_equal);
797
static cos_proc_hash(cos_dict_hash);
798
const cos_object_procs_t cos_dict_procs = {
799
    cos_dict_release, cos_dict_write, cos_dict_equal, cos_dict_hash
800
};
801
802
cos_dict_t *
803
cos_dict_alloc(gx_device_pdf *pdev, client_name_t cname)
804
293k
{
805
293k
    gs_memory_t *mem = pdev->pdf_memory;
806
293k
    cos_dict_t *pcd =
807
293k
        gs_alloc_struct(mem, cos_dict_t, &st_cos_object, cname);
808
809
293k
    cos_object_init((cos_object_t *)pcd, pdev, &cos_dict_procs);
810
293k
    return pcd;
811
293k
}
812
813
static void
814
cos_dict_element_free(cos_dict_t *pcd, cos_dict_element_t *pcde,
815
                      client_name_t cname)
816
2.94M
{
817
2.94M
    gs_memory_t *mem = COS_OBJECT_MEMORY(pcd);
818
819
2.94M
    cos_value_free(&pcde->value, mem, cname);
820
2.94M
    if (pcde->owns_key)
821
720k
        gs_free_string(mem, pcde->key.data, pcde->key.size, cname);
822
2.94M
    gs_free_object(mem, pcde, cname);
823
2.94M
}
824
825
static int
826
cos_dict_delete(cos_dict_t *pcd, const byte *key_data, uint key_size)
827
3
{
828
3
    cos_dict_element_t *pcde = pcd->elements, *prev = 0;
829
830
3
    for (; pcde; pcde = pcde->next) {
831
3
        if (!bytes_compare(key_data, key_size, pcde->key.data, pcde->key.size)) {
832
3
            if (prev != 0)
833
0
                prev->next = pcde->next;
834
3
            else
835
3
                pcd->elements = pcde->next;
836
3
            cos_dict_element_free(pcd, pcde, "cos_dict_delete");
837
3
            return 0;
838
3
        }
839
0
        prev = pcde;
840
0
    }
841
0
    return -1;
842
3
}
843
int
844
cos_dict_delete_c_key(cos_dict_t *pcd, const char *key)
845
3
{
846
3
    return cos_dict_delete(pcd, (const byte *)key, strlen(key));
847
3
}
848
849
static void
850
cos_dict_release(cos_object_t *pco, client_name_t cname)
851
1.05M
{
852
1.05M
    cos_dict_t *const pcd = (cos_dict_t *)pco;
853
1.05M
    cos_dict_element_t *cur;
854
1.05M
    cos_dict_element_t *next;
855
856
3.99M
    for (cur = pcd->elements; cur; cur = next) {
857
2.94M
        next = cur->next;
858
2.94M
        cos_dict_element_free(pcd, cur, cname);
859
2.94M
    }
860
1.05M
    pcd->elements = 0;
861
1.05M
}
862
863
/* Write the elements of a dictionary. */
864
static int
865
cos_elements_write(stream *s, const cos_dict_element_t *pcde,
866
                   gx_device_pdf *pdev, bool do_space, gs_id object_id)
867
720k
{
868
720k
    int Element_Count = 0;
869
870
720k
    if (pcde) {
871
        /* Temporarily replace the output stream in pdev. */
872
587k
        stream *save = pdev->strm;
873
874
587k
        pdev->strm = s;
875
2.44M
        for (;;) {
876
2.44M
            gs_id object_id1 = (pdev->NoEncrypt.size == 0 ||
877
0
                                bytes_compare(pdev->NoEncrypt.data, pdev->NoEncrypt.size,
878
0
                                    pcde->key.data, pcde->key.size)
879
2.44M
                                ? object_id : (gs_id)-1);
880
881
2.44M
            Element_Count++;
882
883
2.44M
            if(pdev->PDFA != 0 && Element_Count > 4095) {
884
0
                switch (pdev->PDFACompatibilityPolicy) {
885
0
                    case 0:
886
0
                        emprintf(pdev->memory,
887
0
                             "Too many entries in dictionary,\n max 4095 in PDF/A, reverting to normal PDF output\n");
888
0
                        pdev->AbortPDFAX = true;
889
0
                        pdev->PDFA = 0;
890
0
                        break;
891
0
                    case 1:
892
0
                        emprintf(pdev->memory,
893
0
                             "Too many entries in dictionary,\n max 4095 in PDF/A. Cannot simply elide dictionary, reverting to normal output\n");
894
0
                        pdev->AbortPDFAX = true;
895
0
                        pdev->PDFA = 0;
896
0
                        break;
897
0
                    case 2:
898
0
                        emprintf(pdev->memory,
899
0
                             "Too many entries in dictionary,\n max 4095 in PDF/A. aborting conversion\n");
900
                        /* Careful here, only certain errors will bubble up
901
                         * through the text processing.
902
                         */
903
0
                        return_error(gs_error_limitcheck);
904
0
                        break;
905
0
                    default:
906
0
                        emprintf(pdev->memory,
907
0
                             "Too many entries in dictionary,\n max 4095 in PDF/A. Unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
908
0
                        pdev->AbortPDFAX = true;
909
0
                        pdev->PDFA = 0;
910
0
                        break;
911
0
                }
912
0
            }
913
914
2.44M
            pdf_write_value(pdev, pcde->key.data, pcde->key.size, object_id1);
915
2.44M
            cos_value_write_spaced(&pcde->value, pdev, true, object_id1);
916
2.44M
            pcde = pcde->next;
917
2.44M
            if (pcde || do_space)
918
2.08M
                stream_putc(s, '\n');
919
2.44M
            if (!pcde)
920
587k
                break;
921
2.44M
        }
922
587k
        pdev->strm = save;
923
587k
    }
924
720k
    return 0;
925
720k
}
926
int
927
cos_dict_elements_write(const cos_dict_t *pcd, gx_device_pdf *pdev)
928
144k
{
929
144k
    return cos_elements_write(pdev->strm, pcd->elements, pdev, true, pcd->id);
930
144k
}
931
932
static int
933
cos_dict_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
934
269k
{
935
269k
    stream *s = pdev->strm;
936
937
269k
    stream_puts(s, "<<");
938
269k
    cos_elements_write(s, ((const cos_dict_t *)pco)->elements, pdev, false, object_id);
939
269k
    stream_puts(s, ">>");
940
269k
    if (pdev->PDFA != 0)
941
0
        stream_puts(s, "\n");
942
269k
    return 0;
943
269k
}
944
945
static int find_first_dict_entry(const cos_dict_t *d, const cos_dict_element_t **element)
946
23
{
947
23
    const cos_dict_element_t *pcde = d->elements, *First;
948
23
    int code, length, length1, length2, offset1 = 0, offset2 = 0, i;
949
950
23
    *element = 0L;
951
952
23
    First = pcde;
953
954
    /*
955
     * If the name has any 'unusual' characters, it is 'escaped' by starting with NULLs
956
     * I suspect we no longer need that, but here we remove the escaping NULLs
957
     */
958
23
    for (i = 0;First->key.data[i] == 0x00; i++)
959
0
        ;
960
961
23
    length1 = First->key.size - i;
962
23
    offset1 = i;
963
964
23
    if (First->key.data[offset1] == '/') {
965
0
        length1 -= 1;
966
0
        offset1 += 1;
967
23
    } else {
968
23
        if (First->key.data[offset1] == '(') {
969
23
            length1 = First->key.size - 2;
970
23
            offset1 = 1;
971
23
        } else {
972
0
            return_error(gs_error_typecheck);
973
0
        }
974
23
    }
975
976
23
    pcde = pcde->next;
977
23
    while (pcde){
978
0
        for (i = 0;pcde->key.data[i] == 0x00; i++)
979
0
            ;
980
0
        length2 = pcde->key.size - i;
981
0
        offset2 = i;
982
983
0
        if (pcde->key.data[offset2] == '/') {
984
0
            length2 -= 1;
985
0
            offset2 += 1;
986
0
        } else {
987
0
            if (pcde->key.data[offset2] == '(') {
988
0
                length2 = pcde->key.size - 2;
989
0
                offset2 = 1;
990
0
            } else {
991
0
                return_error(gs_error_typecheck);
992
0
            }
993
0
        }
994
995
0
        if (length2 < length1)
996
0
            length = length2;
997
0
        else
998
0
            length = length1;
999
0
        code = strncmp((const char *)&pcde->key.data[offset2], (const char *)&First->key.data[offset1], length);
1000
0
        if (code == 0) {
1001
0
            if (length2 < length1) {
1002
0
                First = pcde;
1003
0
                length1 = length2;
1004
0
                offset1 = offset2;
1005
0
            }
1006
0
        } else if (code < 0) {
1007
0
            First = pcde;
1008
0
            length1 = length2;
1009
0
            offset1 = offset2;
1010
0
        }
1011
0
        pcde = pcde->next;
1012
0
    }
1013
23
    *element = First;
1014
23
    return 0;
1015
23
}
1016
1017
static int find_next_dict_entry(const cos_dict_t *d, const cos_dict_element_t **element)
1018
46
{
1019
46
    const cos_dict_element_t *pcde = d->elements, *Current = *element, *Next = 0L;
1020
46
    int code, length, length1, length2, length3, offset1 = 0, offset2 = 0, offset3 = 0, i;
1021
1022
    /*
1023
     * If the name has any 'unusual' characters, it is 'escaped' by starting with NULLs
1024
     * I suspect we no longer need that, but here we remove the escaping NULLs
1025
     */
1026
46
    for (i = 0;Current->key.data[i] == 0x00; i++)
1027
0
        ;
1028
46
    length1 = Current->key.size - i;
1029
46
    offset1 = i;
1030
46
    if (Current->key.data[offset1] == '/') {
1031
0
        length1 -= 1;
1032
0
        offset1 += 1;
1033
46
    } else {
1034
46
        if (Current->key.data[0] == '(') {
1035
46
            length1 -= 2;
1036
46
            offset1 = 1;
1037
46
        } else {
1038
0
            return_error(gs_error_typecheck);
1039
0
        }
1040
46
    }
1041
1042
92
    while (pcde) {
1043
46
        for (i = 0;pcde->key.data[i] == 0x00; i++)
1044
0
            ;
1045
46
        length2 = pcde->key.size - i;
1046
46
        offset2 = i;
1047
46
        if (pcde->key.data[offset2] == '/') {
1048
0
            length2 -= 1;
1049
0
            offset2 += 1;
1050
46
        } else {
1051
46
            if (pcde->key.data[0] == '(') {
1052
46
                length2 -= 2;
1053
46
                offset2 = 1;
1054
46
            } else {
1055
0
                return_error(gs_error_typecheck);
1056
0
            }
1057
46
        }
1058
1059
46
        if (length2 < length1)
1060
0
            length = length2;
1061
46
        else
1062
46
            length = length1;
1063
46
        code = strncmp((const char *)&pcde->key.data[offset2], (const char *)&Current->key.data[offset1], length);
1064
46
        if (code > 0 || (code == 0 && length2 > length1)) {
1065
0
            if (Next) {
1066
0
                if (length3 < length2)
1067
0
                    length = length3;
1068
0
                else
1069
0
                    length = length2;
1070
0
                code = strncmp((const char *)&pcde->key.data[offset2], (const char *)&Next->key.data[offset3], length);
1071
0
                if (code < 0 || (code == 0 && length3 > length2)) {
1072
0
                    Next = pcde;
1073
0
                    length3 = length2;
1074
0
                    offset3 = offset2;
1075
0
                }
1076
0
            } else {
1077
0
                Next = pcde;
1078
0
                for (i = 0;Next->key.data[i] == 0x00; i++)
1079
0
                    ;
1080
0
                length3 = Next->key.size - i;
1081
0
                offset3 = i;
1082
0
                if (Next->key.data[offset3] == '/') {
1083
0
                    length3 -= 1;
1084
0
                    offset3 += 1;
1085
0
                } else {
1086
0
                    if (Next->key.data[0] == '(') {
1087
0
                        length3 -= 2;
1088
0
                        offset3 += 1;
1089
0
                    } else {
1090
0
                        return_error(gs_error_typecheck);
1091
0
                    }
1092
0
                }
1093
0
            }
1094
0
        }
1095
46
        pcde = pcde->next;
1096
46
    }
1097
46
    *element = Next;
1098
46
    return 0;
1099
46
}
1100
1101
static int find_last_dict_entry(const cos_dict_t *d, const cos_dict_element_t **element)
1102
23
{
1103
23
    const cos_dict_element_t *pcde = d->elements, *Last, *Next;
1104
1105
23
    *element = 0L;
1106
1107
23
    Next = Last = pcde;
1108
1109
23
    do {
1110
23
        Last = Next;
1111
23
        find_next_dict_entry(d, &Next);
1112
23
    } while (Next);
1113
1114
23
    *element = Last;
1115
1116
23
    return 0;
1117
23
}
1118
static int write_key_as_string_encrypted(const gx_device_pdf *pdev, const byte *str, uint size, gs_id object_id)
1119
0
{
1120
0
    stream sout;
1121
0
    stream_PSSD_state st;
1122
0
    stream_state so;
1123
0
    byte bufo[100], *buffer;
1124
0
    stream_arcfour_state sarc4;
1125
0
    int i, j = 0;
1126
1127
0
    buffer = gs_alloc_bytes(pdev->pdf_memory, (size_t)size * 2, "encryption buffer");
1128
0
    if (buffer == 0L)
1129
0
        return 0;
1130
1131
0
    if (pdf_encrypt_init(pdev, object_id, &sarc4) < 0) {
1132
0
        gs_free_object(pdev->pdf_memory, buffer, "Free encryption buffer");
1133
        /* The interface can't pass an error. */
1134
0
        stream_write(pdev->strm, str, size);
1135
0
        return size;
1136
0
    }
1137
0
    s_init_state((stream_state *)&st, &s_PSSD_template, NULL);
1138
0
    s_init(&sout, NULL);
1139
0
    s_init_state(&so, &s_PSSE_template, NULL);
1140
0
    s_init_filter(&sout, &so, bufo, sizeof(bufo), pdev->strm);
1141
0
    stream_putc(pdev->strm, '(');
1142
0
    for (i = 0;i < size;i++) {
1143
0
        if (str[i] == '(' || str[i] == ')' || str[i] == '\\')
1144
0
            buffer[j++] = '\\';
1145
0
        buffer[j++] = str[i];
1146
0
    }
1147
0
    s_arcfour_process_buffer(&sarc4, buffer, j);
1148
0
    stream_write(&sout, buffer, j);
1149
    /* Another case where we use sclose() and not s_close_filters(), because the
1150
     * buffer we supplied to s_init_filter is a heap based C object, so we
1151
     * must not free it.
1152
     */
1153
0
    sclose(&sout); /* Writes ')'. */
1154
0
    gs_free_object(pdev->pdf_memory, buffer, "Free encryption buffer");
1155
0
    return 0;
1156
0
}
1157
1158
static int write_key_as_string(const gx_device_pdf *pdev, stream *s, const cos_dict_element_t *element, gs_id object_id)
1159
69
{
1160
69
    int i, length, offset;
1161
1162
    /*
1163
     * If the name has any 'unusual' characters, it is 'escaped' by starting with NULLs
1164
     * I suspect we no longer need that, but here we remove the escaping NULLs
1165
     */
1166
69
    if (element->key.data[0] == 0x00) {
1167
0
        for (i = 0;element->key.data[i] == 0x00; i++)
1168
0
            ;
1169
0
        length = element->key.size - (i + 1);
1170
0
        offset = i;
1171
69
    } else {
1172
69
        offset = 0;
1173
69
        length = element->key.size;
1174
69
    }
1175
1176
69
    if (element->key.data[offset] == '/') {
1177
0
        offset++;
1178
0
        length--;
1179
0
        if (!pdev->KeyLength || object_id == (gs_id)-1) {
1180
0
            int i = 0;
1181
1182
0
            spputc(s, '(');
1183
            /* We need to escape some character codes */
1184
0
            for (i = 0;i < length;i++) {
1185
0
                if (element->key.data[offset + i] == '(' || element->key.data[offset + i] == ')' ||
1186
0
                    element->key.data[offset + i] == '\\')
1187
0
                    spputc(s, '\\');
1188
0
                spputc(s, element->key.data[offset + i]);
1189
0
            }
1190
0
            spputc(s, ')');
1191
0
        }
1192
0
        else
1193
0
            write_key_as_string_encrypted(pdev, &element->key.data[offset], length, object_id);
1194
69
    } else {
1195
69
        if (!pdev->KeyLength || object_id == (gs_id)-1)
1196
69
            stream_write(s, element->key.data, element->key.size);
1197
0
        else
1198
0
            write_key_as_string_encrypted(pdev, &element->key.data[1], element->key.size - 2, object_id);
1199
69
    }
1200
69
    return 0;
1201
69
}
1202
1203
int
1204
cos_write_dict_as_ordered_array(cos_object_t *pco, gx_device_pdf *pdev, pdf_resource_type_t type)
1205
23
{
1206
23
    stream *s;
1207
23
    int code;
1208
23
    const cos_dict_t *d;
1209
23
    const cos_dict_element_t *pcde, *First, *Last;
1210
1211
23
    if (cos_type(pco) != cos_type_dict)
1212
0
        return_error(gs_error_typecheck);
1213
1214
23
    d = (const cos_dict_t *)pco;
1215
1216
23
    if (pco->id == 0 || pco->written)
1217
0
        return_error(gs_error_Fatal);
1218
23
    pdf_open_separate(pdev, pco->id, type);
1219
1220
23
    s = pdev->strm;
1221
23
    pcde = d->elements;
1222
23
    if (!pcde){
1223
0
        stream_puts(s, "<<>>\n");
1224
0
        pdf_end_separate(pdev, type);
1225
0
        return 0;
1226
0
    }
1227
1228
23
    code = find_first_dict_entry(d, &First);
1229
23
    if (code < 0) {
1230
0
        pdf_end_separate(pdev, type);
1231
0
        return code;
1232
0
    }
1233
1234
23
    code = find_last_dict_entry(d, &Last);
1235
23
    if (code < 0) {
1236
0
        pdf_end_separate(pdev, type);
1237
0
        return code;
1238
0
    }
1239
1240
23
    stream_puts(s, "<<\n/Limits [\n");
1241
23
    write_key_as_string(pdev, s, First, pco->id);
1242
23
    stream_puts(s, "\n");
1243
23
    write_key_as_string(pdev, s, Last, pco->id);
1244
23
    stream_puts(s, "\n]\n");
1245
23
    stream_puts(s, "/Names [");
1246
23
    do {
1247
23
        stream_puts(s, "\n");
1248
23
        write_key_as_string(pdev, s, First, pco->id);
1249
23
        cos_value_write_spaced(&First->value, pdev, true, -1);
1250
23
        find_next_dict_entry(d, &First);
1251
23
    } while (First);
1252
23
    stream_puts(s, "]\n>>\n");
1253
1254
23
    pdf_end_separate(pdev, type);
1255
23
    pco->written = true;
1256
23
    return code;
1257
23
}
1258
1259
/* Write/delete definitions of named objects. */
1260
/* This is a special-purpose facility for pdf_close. */
1261
int
1262
cos_dict_objects_write(const cos_dict_t *pcd, gx_device_pdf *pdev)
1263
90.9k
{
1264
90.9k
    const cos_dict_element_t *pcde = pcd->elements;
1265
1266
198k
    for (; pcde; pcde = pcde->next)
1267
107k
        if (COS_VALUE_IS_OBJECT(&pcde->value) &&
1268
107k
            pcde->value.contents.object->id  &&
1269
62.4k
            !pcde->value.contents.object->written /* ForOPDFRead only. */)
1270
62.4k
            cos_write_object(pcde->value.contents.object, pdev, resourceOther);
1271
90.9k
    return 0;
1272
90.9k
}
1273
int
1274
cos_dict_objects_delete(cos_dict_t *pcd)
1275
90.9k
{
1276
90.9k
    cos_dict_element_t *pcde = pcd->elements;
1277
1278
    /*
1279
     * Delete duplicate references to prevent a dual object freeing.
1280
     * Delete the objects' IDs so that freeing the dictionary will
1281
     * free them.
1282
     */
1283
198k
    for (; pcde; pcde = pcde->next) {
1284
107k
        if (pcde->value.contents.object) {
1285
107k
            cos_dict_element_t *pcde1 = pcde->next;
1286
1287
558k
            for (; pcde1; pcde1 = pcde1->next)
1288
450k
                if (pcde->value.contents.object == pcde1->value.contents.object)
1289
0
                    pcde1->value.contents.object = NULL;
1290
107k
            pcde->value.contents.object->id = 0;
1291
107k
        }
1292
107k
    }
1293
90.9k
    return 0;
1294
90.9k
}
1295
1296
/* Put an element in a dictionary. */
1297
3.72M
#define DICT_COPY_KEY 1
1298
5.62M
#define DICT_COPY_VALUE 2
1299
3.72M
#define DICT_FREE_KEY 4
1300
396k
#define DICT_COPY_ALL (DICT_COPY_KEY | DICT_COPY_VALUE | DICT_FREE_KEY)
1301
static int
1302
cos_dict_put_copy(cos_dict_t *pcd, const byte *key_data, uint key_size,
1303
                  const cos_value_t *pvalue, int flags)
1304
3.02M
{
1305
3.02M
    gs_memory_t *mem = COS_OBJECT_MEMORY(pcd);
1306
3.02M
    cos_dict_element_t **ppcde = &pcd->elements;
1307
3.02M
    cos_dict_element_t *pcde;
1308
3.02M
    cos_dict_element_t *next;
1309
3.02M
    cos_value_t value;
1310
3.02M
    int code;
1311
1312
9.97M
    while ((next = *ppcde) != 0 &&
1313
7.03M
           bytes_compare(next->key.data, next->key.size, key_data, key_size)
1314
3.02M
           )
1315
6.95M
        ppcde = &next->next;
1316
3.02M
    if (next) {
1317
        /* We're replacing an existing element. */
1318
81.4k
        if ((pvalue->value_type == COS_VALUE_SCALAR ||
1319
0
             pvalue->value_type == COS_VALUE_CONST) &&
1320
81.4k
            pvalue->value_type == next->value.value_type &&
1321
39.3k
            !bytes_compare(pvalue->contents.chars.data, pvalue->contents.chars.size,
1322
39.3k
                next->value.contents.chars.data, next->value.contents.chars.size))
1323
30.1k
            return 0; /* Same as old value. */
1324
51.3k
        if ((pvalue->value_type == COS_VALUE_OBJECT ||
1325
51.3k
             pvalue->value_type == COS_VALUE_RESOURCE) &&
1326
0
            pvalue->value_type == next->value.value_type &&
1327
0
            pvalue->contents.object == next->value.contents.object)
1328
0
            return 0; /* Same as old value. */
1329
51.3k
        code = cos_copy_element_value(&value, mem, pvalue,
1330
51.3k
                                      (flags & DICT_COPY_VALUE) != 0);
1331
51.3k
        if (code < 0)
1332
0
            return code;
1333
51.3k
        cos_value_free(&next->value, mem,
1334
51.3k
                       "cos_dict_put(old value)");
1335
51.3k
        pcde = next;
1336
2.94M
    } else {
1337
        /* Create a new element. */
1338
2.94M
        byte *copied_key_data;
1339
1340
2.94M
        if (flags & DICT_COPY_KEY) {
1341
720k
            copied_key_data = gs_alloc_string(mem, key_size,
1342
720k
                                              "cos_dict_put(key)");
1343
720k
            if (copied_key_data == 0)
1344
0
                return_error(gs_error_VMerror);
1345
720k
            memcpy(copied_key_data, key_data, key_size);
1346
720k
        } else
1347
2.21M
            copied_key_data = (byte *)key_data; /* OK to break const */
1348
2.94M
        pcde = gs_alloc_struct(mem, cos_dict_element_t, &st_cos_dict_element,
1349
2.94M
                               "cos_dict_put(element)");
1350
2.94M
        code = cos_copy_element_value(&value, mem, pvalue,
1351
2.94M
                                      (flags & DICT_COPY_VALUE) != 0);
1352
2.94M
        if (pcde == 0 || code < 0) {
1353
0
            if (code >= 0)
1354
0
                cos_uncopy_element_value(&value, mem,
1355
0
                                         (flags & DICT_COPY_VALUE) != 0);
1356
0
            gs_free_object(mem, pcde, "cos_dict_put(element)");
1357
0
            if (flags & DICT_COPY_KEY)
1358
0
                gs_free_string(mem, copied_key_data, key_size,
1359
0
                               "cos_dict_put(key)");
1360
0
            return (code < 0 ? code : gs_note_error(gs_error_VMerror));
1361
0
        }
1362
2.94M
        pcde->key.data = copied_key_data;
1363
2.94M
        pcde->key.size = key_size;
1364
2.94M
        pcde->owns_key = (flags & DICT_FREE_KEY) != 0;
1365
2.94M
        pcde->next = next;
1366
2.94M
        *ppcde = pcde;
1367
2.94M
    }
1368
2.99M
    pcde->value = value;
1369
2.99M
    pcd->md5_valid = false;
1370
2.99M
    return 0;
1371
3.02M
}
1372
int
1373
cos_dict_put(cos_dict_t *pcd, const byte *key_data, uint key_size,
1374
             const cos_value_t *pvalue)
1375
396k
{
1376
396k
    return cos_dict_put_copy(pcd, key_data, key_size, pvalue, DICT_COPY_ALL);
1377
396k
}
1378
int
1379
cos_dict_put_no_copy(cos_dict_t *pcd, const byte *key_data, uint key_size,
1380
                     const cos_value_t *pvalue)
1381
390k
{
1382
390k
    return cos_dict_put_copy(pcd, key_data, key_size, pvalue,
1383
390k
                             DICT_COPY_KEY | DICT_FREE_KEY);
1384
390k
}
1385
int
1386
cos_dict_put_c_key(cos_dict_t *pcd, const char *key, const cos_value_t *pvalue)
1387
2.23M
{
1388
2.23M
    return cos_dict_put_copy(pcd, (const byte *)key, strlen(key), pvalue,
1389
2.23M
                             DICT_COPY_VALUE);
1390
2.23M
}
1391
int
1392
cos_dict_put_c_key_string(cos_dict_t *pcd, const char *key,
1393
                          const byte *data, uint size)
1394
1.16M
{
1395
1.16M
    cos_value_t value;
1396
1397
1.16M
    cos_string_value(&value, data, size);
1398
1.16M
    return cos_dict_put_c_key(pcd, key, &value);
1399
1.16M
}
1400
int
1401
cos_dict_put_c_key_int(cos_dict_t *pcd, const char *key, int value)
1402
673k
{
1403
673k
    char str[sizeof(int) * 8 / 3 + 3]; /* sign, rounding, 0 terminator */
1404
1405
673k
    gs_snprintf(str, sizeof(str), "%d", value);
1406
673k
    return cos_dict_put_c_key_string(pcd, key, (byte *)str, strlen(str));
1407
673k
}
1408
int
1409
cos_dict_put_c_key_bool(cos_dict_t *pcd, const char *key, bool value)
1410
33.6k
{
1411
33.6k
    return cos_dict_put_c_key_string(pcd, key,
1412
33.6k
                (const byte *)(value ? "true" : "false"),
1413
33.6k
                              (value ? 4 : 5));
1414
33.6k
}
1415
int
1416
cos_dict_put_c_key_real(cos_dict_t *pcd, const char *key, double value)
1417
15.3k
{
1418
15.3k
    byte str[50];   /****** ADHOC ******/
1419
15.3k
    stream s;
1420
1421
15.3k
    s_init(&s, NULL);
1422
15.3k
    swrite_string(&s, str, sizeof(str));
1423
15.3k
    pprintg1(&s, "%g", value);
1424
15.3k
    return cos_dict_put_c_key_string(pcd, key, str, stell(&s));
1425
15.3k
}
1426
int
1427
cos_dict_put_c_key_floats(gx_device_pdf *pdev, cos_dict_t *pcd, const char *key, const float *pf,
1428
                          uint size)
1429
44.5k
{
1430
44.5k
    cos_array_t *pca = cos_array_from_floats(pdev, pf, size,
1431
44.5k
                                             "cos_dict_put_c_key_floats");
1432
44.5k
    int code;
1433
1434
44.5k
    if (pca == 0)
1435
0
        return_error(gs_error_VMerror);
1436
44.5k
    code = cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
1437
44.5k
    if (code < 0)
1438
0
        COS_FREE(pca, "cos_dict_put_c_key_floats");
1439
44.5k
    return code;
1440
44.5k
}
1441
int
1442
cos_dict_put_c_key_object(cos_dict_t *pcd, const char *key, cos_object_t *pco)
1443
544k
{
1444
544k
    cos_value_t value;
1445
1446
544k
    return cos_dict_put_c_key(pcd, key, cos_object_value(&value, pco));
1447
544k
}
1448
int
1449
cos_dict_put_string(cos_dict_t *pcd, const byte *key_data, uint key_size,
1450
                    const byte *value_data, uint value_size)
1451
288k
{
1452
288k
    cos_value_t cvalue;
1453
1454
288k
    return cos_dict_put(pcd, key_data, key_size,
1455
288k
                        cos_string_value(&cvalue, value_data, value_size));
1456
288k
}
1457
int
1458
cos_dict_put_string_copy(cos_dict_t *pcd, const char *key, const char *value)
1459
49.0k
{
1460
49.0k
    return cos_dict_put_c_key_string(pcd, key, (byte *)value, strlen(value));
1461
49.0k
}
1462
int
1463
cos_dict_put_c_strings(cos_dict_t *pcd, const char *key, const char *value)
1464
470k
{
1465
470k
    cos_value_t cvalue;
1466
1467
470k
    return cos_dict_put_c_key(pcd, key, cos_c_string_value(&cvalue, value));
1468
470k
}
1469
1470
/* Move all the elements from one dict to another. */
1471
int
1472
cos_dict_move_all(cos_dict_t *pcdto, cos_dict_t *pcdfrom)
1473
7
{
1474
7
    cos_dict_element_t *pcde = pcdfrom->elements;
1475
7
    cos_dict_element_t *head = pcdto->elements;
1476
1477
14
    while (pcde) {
1478
7
        cos_dict_element_t *next = pcde->next;
1479
1480
7
        if (cos_dict_find(pcdto, pcde->key.data, pcde->key.size)) {
1481
            /* Free the element, which has been superseded. */
1482
0
            cos_dict_element_free(pcdfrom, pcde, "cos_dict_move_all_from");
1483
7
        } else {
1484
            /* Move the element. */
1485
7
            pcde->next = head;
1486
7
            head = pcde;
1487
7
        }
1488
7
        pcde = next;
1489
7
    }
1490
7
    pcdto->elements = head;
1491
7
    pcdfrom->elements = 0;
1492
7
    pcdto->md5_valid = false;
1493
7
    return 0;
1494
7
}
1495
1496
/* Look up a key in a dictionary. */
1497
const cos_value_t *
1498
cos_dict_find(const cos_dict_t *pcd, const byte *key_data, uint key_size)
1499
371k
{
1500
371k
    cos_dict_element_t *pcde = pcd->elements;
1501
1502
1.38M
    for (; pcde; pcde = pcde->next)
1503
1.16M
        if (!bytes_compare(key_data, key_size, pcde->key.data, pcde->key.size))
1504
154k
            return &pcde->value;
1505
217k
    return 0;
1506
371k
}
1507
const cos_value_t *
1508
cos_dict_find_c_key(const cos_dict_t *pcd, const char *key)
1509
94.4k
{
1510
94.4k
    if (pcd == NULL)
1511
0
        return NULL;
1512
94.4k
    return cos_dict_find(pcd, (const byte *)key, strlen(key));
1513
94.4k
}
1514
1515
int cos_dict_hash(const cos_object_t *pco0, gs_md5_state_t *md5, gs_md5_byte_t *hash, gx_device_pdf *pdev)
1516
257k
{
1517
257k
    cos_dict_t *dict = (cos_dict_t *) pco0;
1518
257k
    cos_dict_element_t *pcde0 = dict->elements;
1519
1520
914k
    for (; pcde0; pcde0 = pcde0->next) {
1521
657k
        gs_md5_append(md5, pcde0->key.data, pcde0->key.size);
1522
657k
        cos_value_hash(&pcde0->value, md5, hash, pdev);
1523
657k
    }
1524
257k
    return 0;
1525
257k
}
1526
1527
/* Compare two dictionaries. */
1528
int
1529
cos_dict_equal(const cos_object_t *pco0, const cos_object_t *pco1, gx_device_pdf *pdev)
1530
693k
{
1531
693k
    int code = 0;
1532
1533
693k
    if (!pco0->md5_valid) {
1534
91.5k
        gs_md5_init((gs_md5_state_t *)&pco0->md5);
1535
91.5k
        code = cos_dict_hash(pco0, (gs_md5_state_t *)&pco0->md5, (gs_md5_byte_t *)pco0->hash, pdev);
1536
91.5k
        if (code < 0)
1537
0
            return code;
1538
91.5k
        gs_md5_finish((gs_md5_state_t *)&pco0->md5, (gs_md5_byte_t *)pco0->hash);
1539
91.5k
        ((cos_object_t *)pco0)->md5_valid = true;
1540
91.5k
    }
1541
693k
    if (!pco1->md5_valid) {
1542
123k
        gs_md5_init((gs_md5_state_t *)&pco1->md5);
1543
123k
        code = cos_dict_hash(pco1, (gs_md5_state_t *)&pco1->md5, (gs_md5_byte_t *)pco1->hash, pdev);
1544
123k
        if (code < 0)
1545
0
            return code;
1546
123k
        gs_md5_finish((gs_md5_state_t *)&pco1->md5, (gs_md5_byte_t *)pco1->hash);
1547
123k
        ((cos_object_t *)pco1)->md5_valid = true;
1548
123k
    }
1549
693k
    if (memcmp(&pco0->hash, &pco1->hash, 16) != 0)
1550
511k
        return false;
1551
1552
181k
    return true;
1553
693k
}
1554
1555
/* Process all entries in a dictionary. */
1556
int
1557
cos_dict_forall(const cos_dict_t *pcd, void *client_data,
1558
                int (*proc)(void *client_data, const byte *key_data, uint key_size, const cos_value_t *v))
1559
42.5k
{
1560
42.5k
    cos_dict_element_t *pcde = pcd->elements;
1561
1562
2.01M
    for (; pcde; pcde = pcde->next) {
1563
1.97M
        int code = proc(client_data, pcde->key.data, pcde->key.size, &pcde->value);
1564
1565
1.97M
        if (code != 0)
1566
0
            return code;
1567
1.97M
    }
1568
42.5k
    return 0;
1569
42.5k
}
1570
1571
/* Set up a parameter list that writes into a Cos dictionary. */
1572
1573
/* We'll implement the other printers later if we have to. */
1574
static param_proc_xmit_typed(cos_param_put_typed);
1575
static const gs_param_list_procs cos_param_list_writer_procs = {
1576
    cos_param_put_typed,
1577
    NULL /* begin_collection */ ,
1578
    NULL /* end_collection */ ,
1579
    NULL /* get_next_key */ ,
1580
    gs_param_request_default,
1581
    gs_param_requested_default
1582
};
1583
static int
1584
cos_param_put_typed(gs_param_list * plist, gs_param_name pkey,
1585
                    gs_param_typed_value * pvalue)
1586
390k
{
1587
390k
    cos_param_list_writer_t *const pclist =
1588
390k
        (cos_param_list_writer_t *)plist;
1589
390k
    gx_device_pdf *pdev = pclist->pdev;
1590
390k
    gs_memory_t *mem = pclist->memory;
1591
390k
    cos_value_t value;
1592
390k
    cos_array_t *pca;
1593
390k
    int key_len = strlen(pkey);
1594
390k
    byte key_chars[100];    /****** ADHOC ******/
1595
390k
    int code;
1596
1597
390k
    while(pdev->child)
1598
0
        pdev = (gx_device_pdf *)pdev->child;
1599
1600
390k
    if (key_len > sizeof(key_chars) - 1)
1601
0
        return_error(gs_error_limitcheck);
1602
390k
    switch (pvalue->type) {
1603
317k
    default: {
1604
317k
        param_printer_params_t ppp;
1605
317k
        printer_param_list_t pplist;
1606
317k
        stream s;
1607
317k
        int len, skip;
1608
317k
        byte *str;
1609
1610
317k
        s_init(&s, NULL);
1611
317k
        ppp = param_printer_params_default;
1612
317k
        ppp.prefix = ppp.suffix = ppp.item_prefix = ppp.item_suffix = 0;
1613
317k
        ppp.print_ok = pclist->print_ok;
1614
317k
        s_init_param_printer(&pplist, &ppp, &s);
1615
317k
        swrite_position_only(&s);
1616
317k
        param_write_typed((gs_param_list *)&pplist, "", pvalue);
1617
317k
        len = stell(&s);
1618
317k
        str = gs_alloc_string(mem, len, "cos_param_put(string)");
1619
317k
        if (str == 0)
1620
0
            return_error(gs_error_VMerror);
1621
317k
        swrite_string(&s, str, len);
1622
317k
        param_write_typed((gs_param_list *)&pplist, "", pvalue);
1623
        /*
1624
         * The string starts with an initial / or /<space>, which
1625
         * we need to remove.
1626
         */
1627
317k
        skip = (str[1] == ' ' ? 2 : 1);
1628
317k
        memmove(str, str + skip, len - skip);
1629
317k
        str = gs_resize_string(mem, str, len, len - skip,
1630
317k
                               "cos_param_put(string)");
1631
317k
        cos_string_value(&value, str, len - skip);
1632
317k
    }
1633
0
        break;
1634
13.9k
    case gs_param_type_int_array: {
1635
13.9k
        uint i;
1636
1637
13.9k
        pca = cos_array_alloc(pdev, "cos_param_put(array)");
1638
13.9k
        if (pca == 0)
1639
0
            return_error(gs_error_VMerror);
1640
28.8k
        for (i = 0; i < pvalue->value.ia.size; ++i)
1641
14.9k
            CHECK(cos_array_add_int(pca, pvalue->value.ia.data[i]));
1642
13.9k
    }
1643
72.3k
    av:
1644
72.3k
        cos_object_value(&value, COS_OBJECT(pca));
1645
72.3k
        break;
1646
58.3k
    case gs_param_type_float_array: {
1647
58.3k
        uint i;
1648
1649
58.3k
        pca = cos_array_alloc(pdev, "cos_param_put(array)");
1650
58.3k
        if (pca == 0)
1651
0
            return_error(gs_error_VMerror);
1652
195k
        for (i = 0; i < pvalue->value.ia.size; ++i)
1653
137k
            CHECK(cos_array_add_real(pca, pvalue->value.fa.data[i]));
1654
58.3k
    }
1655
58.3k
        goto av;
1656
58.3k
    case gs_param_type_string_array:
1657
0
    case gs_param_type_name_array:
1658
        /****** NYI ******/
1659
0
        return_error(gs_error_typecheck);
1660
390k
    }
1661
390k
    if (key_len > 99)
1662
0
        return_error(gs_error_rangecheck);
1663
390k
    memcpy(key_chars + 1, pkey, key_len);
1664
390k
    key_chars[0] = '/';
1665
390k
    return cos_dict_put_no_copy(pclist->pcd, key_chars, key_len + 1, &value);
1666
390k
}
1667
1668
int
1669
cos_param_list_writer_init(gx_device_pdf *pdev, cos_param_list_writer_t *pclist, cos_dict_t *pcd,
1670
                           int print_ok)
1671
118k
{
1672
118k
    gs_param_list_init((gs_param_list *)pclist, &cos_param_list_writer_procs,
1673
118k
                       COS_OBJECT_MEMORY(pcd));
1674
118k
    pclist->pcd = pcd;
1675
118k
    pclist->pdev = pdev;
1676
118k
    pclist->print_ok = print_ok;
1677
118k
    return 0;
1678
118k
}
1679
1680
/* ------ Streams ------ */
1681
1682
static cos_proc_release(cos_stream_release);
1683
cos_proc_write(cos_stream_write);
1684
static cos_proc_equal(cos_stream_equal);
1685
static cos_proc_hash(cos_stream_hash);
1686
const cos_object_procs_t cos_stream_procs = {
1687
    cos_stream_release, cos_stream_write, cos_stream_equal, cos_stream_hash
1688
};
1689
1690
cos_stream_t *
1691
cos_stream_alloc(gx_device_pdf *pdev, client_name_t cname)
1692
175k
{
1693
175k
    gs_memory_t *mem = pdev->pdf_memory;
1694
175k
    cos_stream_t *pcs =
1695
175k
        gs_alloc_struct(mem, cos_stream_t, &st_cos_object, cname);
1696
1697
175k
    cos_object_init((cos_object_t *)pcs, pdev, &cos_stream_procs);
1698
175k
    return pcs;
1699
175k
}
1700
1701
static void
1702
cos_stream_release(cos_object_t *pco, client_name_t cname)
1703
448k
{
1704
448k
    cos_stream_t *const pcs = (cos_stream_t *)pco;
1705
448k
    cos_stream_piece_t *cur;
1706
448k
    cos_stream_piece_t *next;
1707
1708
838k
    for (cur = pcs->pieces; cur; cur = next) {
1709
390k
        next = cur->next;
1710
390k
        gs_free_object(cos_object_memory(pco), cur, cname);
1711
390k
    }
1712
448k
    pcs->pieces = 0;
1713
448k
    cos_dict_release(pco, cname);
1714
448k
}
1715
1716
static int hash_cos_stream(const cos_object_t *pco0, gs_md5_state_t *md5, gs_md5_byte_t *hash, gx_device_pdf *pdev)
1717
3.19k
{
1718
3.19k
    const cos_stream_t *pcs = (const cos_stream_t *)pco0;
1719
3.19k
    cos_stream_piece_t *pcsp = pcs->pieces;
1720
3.19k
    gp_file *sfile = pdev->streams.file;
1721
3.19k
    byte *ptr;
1722
3.19k
    int64_t position_save;
1723
3.19k
    int result;
1724
1725
3.19k
    sflush(pdev->strm);
1726
3.19k
    sflush(pdev->streams.strm);
1727
3.19k
    position_save = gp_ftell(sfile);
1728
1729
3.19k
    if (!pcsp)
1730
2.68k
        return -1;
1731
1732
508
    gs_md5_init(md5);
1733
1.20k
    while(pcsp) {
1734
699
        ptr = gs_malloc(pdev->memory, sizeof (byte), pcsp->size, "hash_cos_stream");
1735
699
        if (ptr == 0L) {
1736
0
            result = gs_note_error(gs_error_VMerror);
1737
0
            return result;
1738
0
        }
1739
699
        if (gp_fseek(sfile, pcsp->position, SEEK_SET) != 0)
1740
0
    return_error(gs_error_ioerror);
1741
1742
699
        if (gp_fread(ptr, 1, pcsp->size, sfile) != pcsp->size) {
1743
0
            gs_free(pdev->memory, ptr, sizeof (byte), pcsp->size, "hash_cos_stream");
1744
0
            result = gs_note_error(gs_error_ioerror);
1745
0
            return result;
1746
0
        }
1747
699
        gs_md5_append(md5, ptr, pcsp->size);
1748
699
        gs_free(pdev->memory, ptr, sizeof (byte), pcsp->size, "hash_cos_stream");
1749
699
        pcsp = pcsp->next;
1750
699
    }
1751
508
    gs_md5_finish(md5, (gs_md5_byte_t *)hash);
1752
508
    if (gp_fseek(sfile, position_save, SEEK_SET) != 0)
1753
0
      return_error(gs_error_ioerror);
1754
1755
508
    return 0;
1756
508
}
1757
1758
static int cos_stream_hash(const cos_object_t *pco0, gs_md5_state_t *md5, gs_md5_byte_t *hash, gx_device_pdf *pdev)
1759
13.4k
{
1760
13.4k
    cos_stream_t *pcs0 = (cos_stream_t *)pco0;
1761
13.4k
    int code=0;
1762
13.4k
    if (!pco0->stream_md5_valid) {
1763
3.19k
        code = hash_cos_stream(pco0, (gs_md5_state_t *)&pco0->md5, (gs_md5_byte_t *)&pco0->stream_hash, pdev);
1764
3.19k
        if (code < 0)
1765
2.68k
            return code;
1766
508
        pcs0->stream_md5_valid = 1;
1767
508
    }
1768
10.7k
    gs_md5_append(md5, (byte *)&pco0->stream_hash, sizeof(pco0->stream_hash));
1769
10.7k
    if (!pco0->md5_valid) {
1770
586
        gs_md5_init((gs_md5_state_t *)&pco0->md5);
1771
586
        code = cos_dict_hash(pco0, (gs_md5_state_t *)&pco0->md5, (gs_md5_byte_t *)pco0->hash, pdev);
1772
586
        if (code < 0)
1773
0
            return code;
1774
586
        gs_md5_finish((gs_md5_state_t *)&pco0->md5, (gs_md5_byte_t *)pco0->hash);
1775
586
        pcs0->md5_valid = 1;
1776
586
    }
1777
10.7k
    gs_md5_append(md5, (byte *)&pco0->hash, sizeof(pco0->hash));
1778
10.7k
    return code;
1779
10.7k
}
1780
1781
static int
1782
cos_stream_equal(const cos_object_t *pco0, const cos_object_t *pco1, gx_device_pdf *pdev)
1783
546k
{
1784
546k
    cos_stream_t *pcs0 = (cos_stream_t *)pco0;
1785
546k
    cos_stream_t *pcs1 = (cos_stream_t *)pco1;
1786
546k
    int code;
1787
546k
    gs_md5_state_t md5;
1788
546k
    gs_md5_byte_t hash[16];
1789
1790
546k
    gs_md5_init(&md5);
1791
1792
546k
    if (!pco0->stream_md5_valid) {
1793
41
        code = cos_stream_hash(pco0, &md5, (gs_md5_byte_t *)hash, pdev);
1794
41
        if (code < 0)
1795
0
            return false;
1796
41
    }
1797
546k
    if (!pco1->stream_md5_valid) {
1798
3.04k
        code = cos_stream_hash(pco1, &md5, (gs_md5_byte_t *)hash, pdev);
1799
3.04k
        if (code < 0)
1800
2.68k
            return false;
1801
3.04k
    }
1802
544k
    if (memcmp(&pcs0->stream_hash, &pcs1->stream_hash, 16) != 0)
1803
393k
        return false;
1804
151k
    code = cos_dict_equal(pco0, pco1, pdev);
1805
151k
    if (code < 0)
1806
0
        return false;
1807
151k
    if (!code)
1808
17.9k
        return false;
1809
133k
    return true;
1810
151k
}
1811
1812
/* Find the total length of a stream. */
1813
int64_t
1814
cos_stream_length(const cos_stream_t *pcs)
1815
526k
{
1816
526k
    return pcs->length;
1817
526k
}
1818
1819
/* Write the (dictionary) elements of a stream. */
1820
/* (This procedure is exported.) */
1821
int
1822
cos_stream_elements_write(const cos_stream_t *pcs, gx_device_pdf *pdev)
1823
164k
{
1824
164k
    return cos_elements_write(pdev->strm, pcs->elements, pdev, true, pcs->id);
1825
164k
}
1826
1827
/* Write the contents of a stream.  (This procedure is exported.) */
1828
int
1829
cos_stream_contents_write(const cos_stream_t *pcs, gx_device_pdf *pdev)
1830
306k
{
1831
306k
    stream *s = pdev->strm;
1832
306k
    cos_stream_piece_t *pcsp;
1833
306k
    cos_stream_piece_t *last;
1834
306k
    cos_stream_piece_t *next;
1835
306k
    gp_file *sfile = pdev->streams.file;
1836
306k
    int64_t end_pos;
1837
306k
    bool same_file = (pdev->sbstack_depth > 0);
1838
306k
    int code;
1839
306k
    stream_arcfour_state sarc4, *ss = NULL;
1840
1841
306k
    if (pdev->KeyLength) {
1842
0
        code = pdf_encrypt_init(pdev, pcs->id, &sarc4);
1843
0
        if (code < 0)
1844
0
            return code;
1845
0
        ss = &sarc4;
1846
0
    }
1847
306k
    sflush(s);
1848
306k
    sflush(pdev->streams.strm);
1849
1850
    /* Reverse the elements temporarily. */
1851
669k
    for (pcsp = pcs->pieces, last = NULL; pcsp; pcsp = next)
1852
362k
        next = pcsp->next, pcsp->next = last, last = pcsp;
1853
669k
    for (pcsp = last, code = 0; pcsp && code >= 0; pcsp = pcsp->next) {
1854
362k
        if (same_file) {
1855
137k
            code = pdf_copy_data_safe(s, sfile, pcsp->position, pcsp->size);
1856
137k
            if (code < 0)
1857
0
                return code;
1858
225k
        } else {
1859
225k
            end_pos = gp_ftell(sfile);
1860
225k
            if (gp_fseek(sfile, pcsp->position, SEEK_SET) != 0)
1861
0
        return_error(gs_error_ioerror);
1862
225k
            code = pdf_copy_data(s, sfile, pcsp->size, ss);
1863
225k
            if (code < 0)
1864
0
                return code;
1865
225k
            if (gp_fseek(sfile, end_pos, SEEK_SET) != 0)
1866
0
        return_error(gs_error_ioerror);
1867
225k
        }
1868
362k
    }
1869
    /* Reverse the elements back. */
1870
669k
    for (pcsp = last, last = NULL; pcsp; pcsp = next)
1871
362k
        next = pcsp->next, pcsp->next = last, last = pcsp;
1872
1873
306k
    return code;
1874
306k
}
1875
1876
int
1877
cos_stream_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
1878
142k
{
1879
142k
    stream *s = pdev->strm;
1880
142k
    const cos_stream_t *const pcs = (const cos_stream_t *)pco;
1881
142k
    int code;
1882
1883
142k
    if (pcs->input_strm != NULL) {
1884
476
        stream *s = pco->input_strm;
1885
476
        int status = s_close_filters(&s, NULL);
1886
1887
476
        if (status < 0)
1888
0
            return_error(gs_error_ioerror);
1889
        /* We have to break const here to clear the input_strm. */
1890
476
        ((cos_object_t *)pco)->input_strm = 0;
1891
476
    }
1892
142k
    stream_puts(s, "<<");
1893
142k
    cos_elements_write(s, pcs->elements, pdev, false, object_id);
1894
142k
    pprinti64d1(s, "/Length %"PRId64">>stream\n", cos_stream_length(pcs));
1895
142k
    code = cos_stream_contents_write(pcs, pdev);
1896
142k
    stream_puts(s, "\nendstream\n");
1897
1898
142k
    return code;
1899
142k
}
1900
1901
/* Return a stream's dictionary (just a cast). */
1902
cos_dict_t *
1903
cos_stream_dict(cos_stream_t *pcs)
1904
247k
{
1905
247k
    return (cos_dict_t *)pcs;
1906
247k
}
1907
1908
/* Add a contents piece to a stream object: size bytes just written on */
1909
/* streams.strm. */
1910
int
1911
cos_stream_add(gx_device_pdf *pdev, cos_stream_t *pcs, uint size)
1912
3.25M
{
1913
3.25M
    stream *s;
1914
3.25M
    gs_offset_t position;
1915
3.25M
    cos_stream_piece_t *prev = pcs->pieces;
1916
1917
    /* Beware of subclassed devices. This is mad IMO, we should store
1918
     * 's' in the stream state somewhere.
1919
     */
1920
3.25M
    while (pdev->child)
1921
0
        pdev = (gx_device_pdf *)pdev->child;
1922
1923
3.25M
    s = pdev->streams.strm;
1924
3.25M
    position = stell(s);
1925
1926
    /* Check for consecutive writing -- just an optimization. */
1927
3.25M
    if (prev != 0 && prev->position + prev->size + size == position) {
1928
2.74M
        prev->size += size;
1929
2.74M
    } else {
1930
508k
        gs_memory_t *mem = pdev->pdf_memory;
1931
508k
        cos_stream_piece_t *pcsp =
1932
508k
            gs_alloc_struct(mem, cos_stream_piece_t, &st_cos_stream_piece,
1933
508k
                            "cos_stream_add");
1934
1935
508k
        if (pcsp == 0)
1936
0
            return_error(gs_error_VMerror);
1937
508k
        pcsp->position = position - size;
1938
508k
        pcsp->size = size;
1939
508k
        pcsp->next = pcs->pieces;
1940
508k
        pcs->pieces = pcsp;
1941
508k
    }
1942
3.25M
    pcs->length += size;
1943
3.25M
    return 0;
1944
3.25M
}
1945
1946
/* Add bytes to a stream object. */
1947
int
1948
cos_stream_add_bytes(gx_device_pdf *pdev, cos_stream_t *pcs, const byte *data, uint size)
1949
10.8k
{
1950
10.8k
    stream_write(pdev->streams.strm, data, size);
1951
10.8k
    return cos_stream_add(pdev, pcs, size);
1952
10.8k
}
1953
1954
/* Add the contents of a stream to a stream object. */
1955
int
1956
cos_stream_add_stream_contents(gx_device_pdf *pdev, cos_stream_t *pcs, stream *s)
1957
102
{
1958
102
    int code = 0;
1959
102
    byte sbuff[200];  /* arbitrary */
1960
102
    uint cnt;
1961
102
    int status = sseek(s, 0);
1962
1963
102
    if (status < 0)
1964
0
        return_error(gs_error_ioerror);
1965
7.76k
    do {
1966
7.76k
        status = sgets(s, sbuff, sizeof(sbuff), &cnt);
1967
1968
7.76k
        if (cnt == 0) {
1969
102
            if (status == EOFC)
1970
102
                break;
1971
102
            return_error(gs_error_ioerror);
1972
102
        }
1973
7.76k
    } while ((code = cos_stream_add_bytes(pdev, pcs, sbuff, cnt)) >= 0);
1974
102
    return code;
1975
102
}
1976
1977
/* Release the last contents piece of a stream object. */
1978
/* Warning : this function can't release pieces if another stream is written after them. */
1979
int
1980
cos_stream_release_pieces(gx_device_pdf *pdev, cos_stream_t *pcs)
1981
120k
{
1982
120k
    stream *s = pdev->streams.strm;
1983
120k
    gs_offset_t position = stell(s), position0 = position;
1984
1985
238k
    while (pcs->pieces != NULL &&
1986
121k
                position == pcs->pieces->position + pcs->pieces->size) {
1987
117k
        cos_stream_piece_t *p = pcs->pieces;
1988
1989
117k
        position -= p->size;
1990
117k
        pcs->pieces = p->next;
1991
117k
        gs_free_object(cos_object_memory((cos_object_t *)pcs), p, "cos_stream_release_pieces");
1992
117k
    }
1993
120k
    if (position0 != position)
1994
117k
        if (sseek(s, position) < 0)
1995
0
            return_error(gs_error_ioerror);
1996
120k
    return 0;
1997
120k
}
1998
1999
/* Create a stream that writes into a Cos stream. */
2000
/* Closing the stream will free it. */
2001
/* Note that this is not a filter. */
2002
typedef struct cos_write_stream_state_s {
2003
    stream_state_common;
2004
    cos_stream_t *pcs;
2005
    gx_device_pdf *pdev;
2006
    stream *s;      /* pointer back to stream */
2007
    stream *target;   /* use this instead of strm */
2008
} cos_write_stream_state_t;
2009
gs_private_st_suffix_add4(st_cos_write_stream_state, cos_write_stream_state_t,
2010
                          "cos_write_stream_state_t",
2011
                          cos_ws_state_enum_ptrs, cos_ws_state_reloc_ptrs,
2012
                          st_stream_state, pcs, pdev, s, target);
2013
2014
static int
2015
cos_write_stream_process(stream_state * st, stream_cursor_read * pr,
2016
                         stream_cursor_write * ignore_pw, bool last)
2017
3.24M
{
2018
3.24M
    uint count = pr->limit - pr->ptr;
2019
3.24M
    cos_write_stream_state_t *ss = (cos_write_stream_state_t *)st;
2020
3.24M
    stream *target = ss->target;
2021
3.24M
    gx_device_pdf *pdev = ss->pdev;
2022
3.24M
    gs_offset_t start_pos;
2023
3.24M
    int code;
2024
2025
3.24M
    while(pdev->child != NULL)
2026
0
        pdev = (gx_device_pdf *)pdev->child;
2027
2028
3.24M
    start_pos = stell(pdev->streams.strm);
2029
3.24M
    stream_write(target, pr->ptr + 1, count);
2030
3.24M
    gs_md5_append(&ss->pcs->md5, pr->ptr + 1, count);
2031
3.24M
    pr->ptr = pr->limit;
2032
3.24M
    sflush(target);
2033
3.24M
    code = cos_stream_add(pdev, ss->pcs, (uint)(stell(pdev->streams.strm) - start_pos));
2034
3.24M
    return (code < 0 ? ERRC : 0);
2035
3.24M
}
2036
static int
2037
cos_write_stream_close(stream *s)
2038
445k
{
2039
445k
    cos_write_stream_state_t *ss = (cos_write_stream_state_t *)s->state;
2040
445k
    int status;
2041
445k
    gx_device_pdf *target_dev = (gx_device_pdf *)ss->pdev;
2042
2043
445k
    while (target_dev->child != NULL)
2044
0
        target_dev = (gx_device_pdf *)target_dev->child;
2045
2046
445k
    sflush(s);
2047
445k
    status = s_close_filters(&ss->target, target_dev->streams.strm);
2048
445k
    gs_md5_finish(&ss->pcs->md5, (gs_md5_byte_t *)ss->pcs->stream_hash);
2049
445k
    ss->pcs->stream_md5_valid = 1;
2050
445k
    return (status < 0 ? status : s_std_close(s));
2051
445k
}
2052
2053
static const stream_procs cos_s_procs = {
2054
    s_std_noavailable, s_std_noseek, s_std_write_reset,
2055
    s_std_write_flush, cos_write_stream_close, cos_write_stream_process
2056
};
2057
static const stream_template cos_write_stream_template = {
2058
    &st_cos_write_stream_state, 0, cos_write_stream_process, 1, 1
2059
};
2060
stream *
2061
cos_write_stream_alloc(cos_stream_t *pcs, gx_device_pdf *pdev,
2062
                       client_name_t cname)
2063
445k
{
2064
445k
    gs_memory_t *mem = pdev->pdf_memory;
2065
445k
    stream *s = s_alloc(mem, cname);
2066
445k
    cos_write_stream_state_t *ss = (cos_write_stream_state_t *)
2067
445k
        s_alloc_state(mem, &st_cos_write_stream_state, cname);
2068
445k
#define CWS_BUF_SIZE 512  /* arbitrary */
2069
445k
    byte *buf = gs_alloc_bytes(mem, CWS_BUF_SIZE, cname);
2070
2071
445k
    if (s == 0 || ss == 0 || buf == 0)
2072
0
        goto fail;
2073
445k
    ss->templat = &cos_write_stream_template;
2074
445k
    ss->pcs = pcs;
2075
445k
    ss->pcs->stream_md5_valid = 0;
2076
445k
    gs_md5_init(&ss->pcs->md5);
2077
445k
    memset(&ss->pcs->hash, 0x00, 16);
2078
445k
    ss->pdev = pdev;
2079
445k
    while(ss->pdev->parent)
2080
0
        ss->pdev = (gx_device_pdf *)ss->pdev->parent;
2081
445k
    ss->s = s;
2082
445k
    ss->target = pdev->streams.strm; /* not s->strm */
2083
445k
    s_std_init(s, buf, CWS_BUF_SIZE, &cos_s_procs, s_mode_write);
2084
445k
    s->state = (stream_state *)ss;
2085
445k
    return s;
2086
0
#undef CWS_BUF_SIZE
2087
0
 fail:
2088
0
    gs_free_object(mem, buf, cname);
2089
0
    gs_free_object(mem, ss, cname);
2090
0
    gs_free_object(mem, s, cname);
2091
0
    return 0;
2092
445k
}
2093
2094
/* Get cos stream from pipeline. */
2095
cos_stream_t *
2096
cos_stream_from_pipeline(stream *s)
2097
816k
{
2098
816k
    cos_write_stream_state_t *ss;
2099
2100
2.29M
    while(s->procs.process != cos_s_procs.process) {
2101
1.48M
        s = s->strm;
2102
1.48M
        if (s == 0L)
2103
0
            return 0L;
2104
1.48M
    }
2105
2106
816k
    ss = (cos_write_stream_state_t *)s->state;
2107
816k
    return ss->pcs;
2108
816k
}