Coverage Report

Created: 2026-10-28 08:05

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