Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/devices/vector/gdevpdfo.c
Line
Count
Source (jump to first uncovered line)
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
231k
  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.34M
#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.38M
ENUM_PTRS_WITH(cos_value_enum_ptrs, cos_value_t *pcv) return 0;
96
715k
 case 0:
97
715k
    switch (pcv->value_type) {
98
463k
    case COS_VALUE_SCALAR:
99
463k
        return ENUM_STRING(&pcv->contents.chars);
100
42.4k
    case COS_VALUE_CONST:
101
42.4k
        break;
102
210k
    case COS_VALUE_OBJECT:
103
210k
    case COS_VALUE_RESOURCE:
104
210k
        return ENUM_OBJ(pcv->contents.object);
105
715k
    }
106
42.4k
    return 0;
107
1.38M
ENUM_PTRS_END
108
static
109
713k
RELOC_PTRS_WITH(cos_value_reloc_ptrs, cos_value_t *pcv)
110
713k
{
111
713k
    switch (pcv->value_type) {
112
461k
    case COS_VALUE_SCALAR:
113
461k
        RELOC_STRING_VAR(pcv->contents.chars);
114
504k
    case COS_VALUE_CONST:
115
504k
        break;
116
209k
    case COS_VALUE_OBJECT:
117
209k
    case COS_VALUE_RESOURCE:
118
209k
        RELOC_VAR(pcv->contents.object);
119
209k
        break;
120
713k
    }
121
713k
}
122
713k
RELOC_PTRS_END
123
static
124
427k
ENUM_PTRS_WITH(cos_array_element_enum_ptrs, cos_array_element_t *pcae)
125
427k
{
126
427k
    return (index < cos_element_num_ptrs ?
127
427k
            ENUM_USING_PREFIX(st_cos_element, 0) :
128
427k
            ENUM_USING(st_cos_value, &pcae->value, sizeof(cos_value_t),
129
427k
                       index - cos_element_num_ptrs));
130
0
}
131
427k
ENUM_PTRS_END
132
static
133
148k
RELOC_PTRS_WITH(cos_array_element_reloc_ptrs, cos_array_element_t *pcae)
134
148k
{
135
148k
    RELOC_PREFIX(st_cos_element);
136
148k
    RELOC_USING(st_cos_value, &pcae->value, sizeof(cos_value_t));
137
148k
}
138
148k
RELOC_PTRS_END
139
static
140
2.24M
ENUM_PTRS_WITH(cos_dict_element_enum_ptrs, cos_dict_element_t *pcde)
141
2.24M
{
142
2.24M
    return (index < cos_element_num_ptrs ?
143
2.24M
            ENUM_USING_PREFIX(st_cos_element, 0) :
144
2.24M
            (index -= cos_element_num_ptrs) > 0 ?
145
1.11M
            ENUM_USING(st_cos_value, &pcde->value, sizeof(cos_value_t),
146
1.67M
                       index - 1) :
147
1.67M
            pcde->owns_key ? ENUM_STRING(&pcde->key) : ENUM_OBJ(NULL));
148
0
}
149
2.24M
ENUM_PTRS_END
150
static
151
565k
RELOC_PTRS_WITH(cos_dict_element_reloc_ptrs, cos_dict_element_t *pcde)
152
565k
{
153
565k
    RELOC_PREFIX(st_cos_element);
154
565k
    if (pcde->owns_key)
155
186k
        RELOC_STRING_VAR(pcde->key);
156
565k
    RELOC_USING(st_cos_value, &pcde->value, sizeof(cos_value_t));
157
565k
}
158
565k
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.75M
{
167
1.75M
    if (pco) {
168
1.75M
        pco->cos_procs = procs;
169
1.75M
        pco->id = 0;
170
1.75M
        pco->elements = 0;
171
1.75M
        pco->pieces = 0;
172
1.75M
        pco->mem = pdev->pdf_memory;
173
1.75M
        pco->pres = 0;
174
1.75M
        pco->is_open = true;
175
1.75M
        pco->is_graphics = false;
176
1.75M
        pco->written = false;
177
1.75M
        pco->length = 0;
178
1.75M
        pco->input_strm = 0;
179
1.75M
        pco->md5_valid = 0;
180
1.75M
        pco->stream_md5_valid = 0;
181
1.75M
        memset(&pco->hash, 0x00, 16);
182
1.75M
    }
183
1.75M
}
184
185
/* Get the allocator for a Cos object. */
186
gs_memory_t *
187
cos_object_memory(const cos_object_t *pco)
188
19.0M
{
189
19.0M
    return pco->mem;
190
19.0M
}
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
373k
{
196
373k
    if (cos_type(pco) != cos_type_generic)
197
0
        return_error(gs_error_typecheck);
198
373k
    cos_type(pco) = cotype;
199
373k
    return 0;
200
373k
}
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.69M
{
207
1.69M
    pco->cos_procs->release(pco, cname);
208
1.69M
}
209
210
/* Free a cos object. */
211
void
212
cos_free(cos_object_t *pco, client_name_t cname)
213
1.35M
{
214
1.35M
    cos_release(pco, cname);
215
1.35M
    gs_free_object(cos_object_memory(pco), pco, cname);
216
1.35M
}
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
843k
{
223
843k
    return pco->cos_procs->write(pco, pdev, object_id);
224
843k
}
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
130k
{
233
130k
    int code;
234
235
130k
    if (pco->id == 0 || pco->written)
236
0
        return_error(gs_error_Fatal);
237
130k
    if (pco->cos_procs->write == cos_stream_write)
238
62.9k
        pdf_open_separate_noObjStm(pdev, pco->id, type);
239
67.7k
    else
240
67.7k
        pdf_open_separate(pdev, pco->id, type);
241
130k
    code = cos_write(pco, pdev, pco->id);
242
130k
    if (pco->cos_procs->write == cos_stream_write)
243
62.9k
        pdf_end_separate_noObjStm(pdev, type);
244
67.7k
    else
245
67.7k
        pdf_end_separate(pdev, type);
246
130k
    pco->written = true;
247
130k
    return code;
248
130k
}
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.18M
{
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.18M
    pcv->contents.chars.data = (byte *)data;
259
2.18M
    pcv->contents.chars.size = size;
260
2.18M
    pcv->value_type = COS_VALUE_SCALAR;
261
2.18M
    return pcv;
262
2.18M
}
263
const cos_value_t *
264
cos_c_string_value(cos_value_t *pcv, const char *str)
265
979k
{
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
979k
    pcv->contents.chars.data = (byte *)str;
272
979k
    pcv->contents.chars.size = strlen(str);
273
979k
    pcv->value_type = COS_VALUE_CONST;
274
979k
    return pcv;
275
979k
}
276
const cos_value_t *
277
cos_object_value(cos_value_t *pcv, cos_object_t *pco)
278
898k
{
279
898k
    pcv->contents.object = pco;
280
898k
    pcv->value_type = COS_VALUE_OBJECT;
281
898k
    return pcv;
282
898k
}
283
const cos_value_t *
284
cos_resource_value(cos_value_t *pcv, cos_object_t *pco)
285
57.1k
{
286
57.1k
    pcv->contents.object = pco;
287
57.1k
    pcv->value_type = COS_VALUE_RESOURCE;
288
57.1k
    return pcv;
289
57.1k
}
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.01M
{
296
4.01M
    switch (pcv->value_type) {
297
2.14M
    case COS_VALUE_SCALAR:
298
2.14M
        gs_free_string(mem, pcv->contents.chars.data,
299
2.14M
                       pcv->contents.chars.size, cname);
300
3.12M
    case COS_VALUE_CONST:
301
3.12M
        break;
302
892k
    case COS_VALUE_OBJECT:
303
        /* Free the object if this is the only reference to it. */
304
892k
        if (pcv->contents.object != NULL) /* see cos_dict_objects_delete. */
305
892k
            if (!pcv->contents.object->id)
306
847k
                cos_free(pcv->contents.object, cname);
307
894k
    case COS_VALUE_RESOURCE:
308
894k
        break;
309
4.01M
    }
310
4.01M
}
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.41M
{
317
3.41M
    stream *s = pdev->strm;
318
319
3.41M
    switch (pcv->value_type) {
320
1.86M
    case COS_VALUE_SCALAR:
321
2.65M
    case COS_VALUE_CONST:
322
2.65M
        if (do_space)
323
1.66M
            switch (pcv->contents.chars.data[0]) {
324
284k
            case '/': case '(': case '<': break;
325
1.38M
            default: stream_putc(s, ' ');
326
1.66M
            }
327
2.65M
        return pdf_write_value(pdev, pcv->contents.chars.data,
328
2.65M
                        pcv->contents.chars.size, object_id);
329
57.0k
    case COS_VALUE_RESOURCE:
330
57.0k
        pprinti64d1(s, "/R%"PRId64"", pcv->contents.object->id);
331
57.0k
        break;
332
703k
    case COS_VALUE_OBJECT: {
333
703k
        cos_object_t *pco = pcv->contents.object;
334
335
703k
        if (!pco->id) {
336
679k
            if (do_space &&
337
679k
                !(pco->cos_procs == cos_type_array ||
338
545k
                  pco->cos_procs == cos_type_dict)
339
679k
                ) {
340
                /* Arrays and dictionaries (only) are self-delimiting. */
341
0
                stream_putc(s, ' ');
342
0
            }
343
679k
            return cos_write(pco, pdev, object_id);
344
679k
        }
345
23.7k
        if (do_space)
346
20.5k
            stream_putc(s, ' ');
347
23.7k
        pprinti64d1(s, "%"PRId64" 0 R", pco->id);
348
23.7k
        if (pco->cos_procs == cos_type_reference)
349
0
            pco->id = 0;
350
23.7k
        break;
351
703k
    }
352
0
    default:      /* can't happen */
353
0
        return_error(gs_error_Fatal);
354
3.41M
    }
355
80.8k
    return 0;
356
3.41M
}
357
int
358
cos_value_write(const cos_value_t *pcv, gx_device_pdf *pdev)
359
60.8k
{
360
60.8k
    return cos_value_write_spaced(pcv, pdev, false, 0);
361
60.8k
}
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.01M
{
368
4.01M
    *pcv = *pvalue;
369
4.01M
    if (pvalue->value_type == COS_VALUE_SCALAR && copy) {
370
1.70M
        byte *value_data = gs_alloc_string(mem, pvalue->contents.chars.size,
371
1.70M
                                           "cos_copy_element_value");
372
373
1.70M
        if (value_data == 0)
374
0
            return_error(gs_error_VMerror);
375
1.70M
        memcpy(value_data, pvalue->contents.chars.data,
376
1.70M
               pvalue->contents.chars.size);
377
1.70M
        pcv->contents.chars.data = value_data;
378
1.70M
    }
379
4.01M
    return 0;
380
4.01M
}
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
917k
{
393
917k
    int code;
394
917k
    switch (pcv0->value_type) {
395
514k
        case COS_VALUE_SCALAR:
396
715k
        case COS_VALUE_CONST:
397
715k
            gs_md5_append(md5, pcv0->contents.chars.data, pcv0->contents.chars.size);
398
715k
            break;
399
400
202k
        case COS_VALUE_OBJECT:
401
202k
            code = pcv0->contents.object->cos_procs->hash(pcv0->contents.object, md5, hash, pdev);
402
202k
            if (code < 0)
403
0
                return code;
404
202k
            break;
405
202k
        case COS_VALUE_RESOURCE:
406
0
            break;
407
917k
    }
408
917k
    return 0;
409
917k
}
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
577k
{
430
577k
    gs_memory_t *mem = pdev->pdf_memory;
431
577k
    cos_object_t *pco =
432
577k
        gs_alloc_struct(mem, cos_object_t, &st_cos_object, cname);
433
434
577k
    cos_object_init(pco, pdev, &cos_generic_procs);
435
577k
    return pco;
436
577k
}
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
145k
{
458
    /* Do nothing. */
459
145k
}
460
461
static int
462
cos_generic_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
463
27
{
464
27
    return_error(gs_error_Fatal);
465
27
}
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
691k
{
492
691k
    gs_memory_t *mem = pdev->pdf_memory;
493
691k
    cos_array_t *pca =
494
691k
        gs_alloc_struct(mem, cos_array_t, &st_cos_object, cname);
495
496
691k
    cos_object_init((cos_object_t *)pca, pdev, &cos_array_procs);
497
691k
    return pca;
498
691k
}
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
26.4k
{
504
26.4k
    cos_array_t *pca = cos_array_alloc(pdev, cname);
505
26.4k
    uint i;
506
507
26.4k
    if (pca == 0)
508
0
        return 0;
509
157k
    for (i = 0; i < size; ++i) {
510
130k
        int code = cos_array_add_real(pca, pf[i]);
511
512
130k
        if (code < 0) {
513
0
            COS_FREE(pca, cname);
514
0
            return 0;
515
0
        }
516
130k
    }
517
26.4k
    return pca;
518
26.4k
}
519
520
static void
521
cos_array_release(cos_object_t *pco, client_name_t cname)
522
691k
{
523
691k
    cos_array_t *const pca = (cos_array_t *)pco;
524
691k
    cos_array_element_t *cur;
525
691k
    cos_array_element_t *next;
526
527
2.01M
    for (cur = pca->elements; cur; cur = next) {
528
1.32M
        next = cur->next;
529
1.32M
        cos_value_free(&cur->value, cos_object_memory(pco), cname);
530
1.32M
        gs_free_object(cos_object_memory(pco), cur, cname);
531
1.32M
    }
532
691k
    pca->elements = 0;
533
691k
}
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
530k
{
540
530k
    stream *s = pdev->strm;
541
530k
    const cos_array_t *const pca = (const cos_array_t *)pco;
542
530k
    cos_array_element_t *first = cos_array_reorder(pca, NULL);
543
530k
    cos_array_element_t *pcae;
544
530k
    uint last_index = 0, Element_Count = 0;
545
546
530k
    stream_puts(s, "[");
547
1.65M
    for (pcae = first; pcae; ++last_index, pcae = pcae->next) {
548
1.12M
        Element_Count++;
549
550
1.12M
        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.12M
        if (pcae != first)
581
591k
            stream_putc(s, '\n');
582
1.12M
        for (; pcae->index > last_index; ++last_index)
583
0
            stream_puts(s, "null\n");
584
1.12M
        cos_value_write_spaced(&pcae->value, pdev, false, object_id);
585
1.12M
    }
586
530k
    DISCARD(cos_array_reorder(pca, first));
587
530k
    stream_puts(s, "]");
588
530k
    if (pdev->PDFA != 0)
589
0
        stream_puts(s, "\n");
590
530k
    return 0;
591
530k
}
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
141k
{
625
141k
    const cos_array_t *const pca0 = (const cos_array_t *)pco0;
626
141k
    cos_array_element_t *first0 = pca0->elements;
627
141k
    cos_array_element_t *pcae0;
628
141k
    int code;
629
630
539k
    for (pcae0 = first0; pcae0;pcae0 = pcae0->next) {
631
397k
        code = cos_value_hash(&pcae0->value, md5, hash, pdev);
632
397k
        if (code < 0)
633
0
            return code;
634
397k
    }
635
141k
    return 0;
636
141k
}
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.32M
{
642
1.32M
    gs_memory_t *mem = COS_OBJECT_MEMORY(pca);
643
1.32M
    cos_value_t value;
644
1.32M
    int code = cos_copy_element_value(&value, mem, pvalue, true);
645
646
1.32M
    if (code >= 0) {
647
1.32M
        code = cos_array_put_no_copy(pca, index, &value);
648
1.32M
        if (code < 0)
649
0
            cos_uncopy_element_value(&value, mem, true);
650
1.32M
    }
651
1.32M
    pca->md5_valid = false;
652
1.32M
    return code;
653
1.32M
}
654
int
655
cos_array_put_no_copy(cos_array_t *pca, int64_t index, const cos_value_t *pvalue)
656
1.32M
{
657
1.32M
    gs_memory_t *mem = COS_OBJECT_MEMORY(pca);
658
1.32M
    cos_array_element_t **ppcae = &pca->elements;
659
1.32M
    cos_array_element_t *pcae;
660
1.32M
    cos_array_element_t *next;
661
662
1.32M
    while ((next = *ppcae) != 0 && next->index > index)
663
0
        ppcae = &next->next;
664
1.32M
    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.32M
    } else {
670
        /* Create a new element. */
671
1.32M
        pcae = gs_alloc_struct(mem, cos_array_element_t, &st_cos_array_element,
672
1.32M
                               "cos_array_put(element)");
673
1.32M
        if (pcae == 0)
674
0
            return_error(gs_error_VMerror);
675
1.32M
        pcae->index = index;
676
1.32M
        pcae->next = next;
677
1.32M
        *ppcae = pcae;
678
1.32M
    }
679
1.32M
    pcae->value = *pvalue;
680
1.32M
    pca->md5_valid = false;
681
1.32M
    return 0;
682
1.32M
}
683
static long
684
cos_array_next_index(const cos_array_t *pca)
685
1.32M
{
686
1.32M
    return (pca->elements ? pca->elements->index + 1 : 0L);
687
1.32M
}
688
int
689
cos_array_add(cos_array_t *pca, const cos_value_t *pvalue)
690
1.32M
{
691
1.32M
    pca->md5_valid = false;
692
1.32M
    return cos_array_put(pca, cos_array_next_index(pca), pvalue);
693
1.32M
}
694
int
695
cos_array_add_no_copy(cos_array_t *pca, const cos_value_t *pvalue)
696
724
{
697
724
    pca->md5_valid = false;
698
724
    return cos_array_put_no_copy(pca, cos_array_next_index(pca), pvalue);
699
724
}
700
int
701
cos_array_add_c_string(cos_array_t *pca, const char *str)
702
555k
{
703
555k
    cos_value_t value;
704
705
555k
    return cos_array_add(pca, cos_c_string_value(&value, str));
706
555k
}
707
int
708
cos_array_add_int(cos_array_t *pca, int i)
709
19.0k
{
710
19.0k
    char str[sizeof(int) * 8 / 3 + 3]; /* sign, rounding, 0 terminator */
711
19.0k
    cos_value_t v;
712
713
19.0k
    gs_snprintf(str, sizeof(str), "%d", i);
714
19.0k
    return cos_array_add(pca, cos_string_value(&v, (byte *)str, strlen(str)));
715
19.0k
}
716
int
717
cos_array_add_real(cos_array_t *pca, double r)
718
606k
{
719
606k
    byte str[50];   /****** ADHOC ******/
720
606k
    stream s;
721
606k
    cos_value_t v;
722
723
606k
    s_init(&s, NULL);
724
606k
    swrite_string(&s, str, sizeof(str));
725
606k
    pprintg1(&s, "%g", r);
726
606k
    return cos_array_add(pca, cos_string_value(&v, str, stell(&s)));
727
606k
}
728
int
729
cos_array_add_object(cos_array_t *pca, cos_object_t *pco)
730
135k
{
731
135k
    cos_value_t value;
732
733
135k
    value.contents.chars.size = 0; /* Quiet a warning appeared with MSVC6 inline optimization. */
734
135k
    return cos_array_add(pca, cos_object_value(&value, pco));
735
135k
}
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
112k
{
745
112k
    cos_array_element_t *pcae = pca->elements;
746
747
112k
    if (pcae == 0 ||
748
112k
        pcae->index != (pcae->next == 0 ? 0 : pcae->next->index + 1)
749
112k
        )
750
112k
        return_error(gs_error_rangecheck);
751
107
    *pvalue = pcae->value;
752
107
    pca->elements = pcae->next;
753
107
    gs_free_object(COS_OBJECT_MEMORY(pca), pcae, "cos_array_unadd");
754
107
    pca->md5_valid = false;
755
107
    return 0;
756
112k
}
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
3.44k
{
762
3.44k
    return pca->elements;
763
3.44k
}
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
10.2k
{
768
10.2k
    *pindex = pca->index;
769
10.2k
    *ppvalue = &pca->value;
770
10.2k
    return pca->next;
771
10.2k
}
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
1.06M
{
782
1.06M
    cos_array_element_t *last;
783
1.06M
    cos_array_element_t *next;
784
1.06M
    cos_array_element_t *pcae;
785
786
3.30M
    for (pcae = (first ? first : pca->elements), last = NULL; pcae;
787
2.24M
         pcae = next)
788
2.24M
        next = pcae->next, pcae->next = last, last = pcae;
789
1.06M
    return last;
790
1.06M
}
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
272k
{
805
272k
    gs_memory_t *mem = pdev->pdf_memory;
806
272k
    cos_dict_t *pcd =
807
272k
        gs_alloc_struct(mem, cos_dict_t, &st_cos_object, cname);
808
809
272k
    cos_object_init((cos_object_t *)pcd, pdev, &cos_dict_procs);
810
272k
    return pcd;
811
272k
}
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.68M
{
817
2.68M
    gs_memory_t *mem = COS_OBJECT_MEMORY(pcd);
818
819
2.68M
    cos_value_free(&pcde->value, mem, cname);
820
2.68M
    if (pcde->owns_key)
821
595k
        gs_free_string(mem, pcde->key.data, pcde->key.size, cname);
822
2.68M
    gs_free_object(mem, pcde, cname);
823
2.68M
}
824
825
static int
826
cos_dict_delete(cos_dict_t *pcd, const byte *key_data, uint key_size)
827
0
{
828
0
    cos_dict_element_t *pcde = pcd->elements, *prev = 0;
829
830
0
    for (; pcde; pcde = pcde->next) {
831
0
        if (!bytes_compare(key_data, key_size, pcde->key.data, pcde->key.size)) {
832
0
            if (prev != 0)
833
0
                prev->next = pcde->next;
834
0
            else
835
0
                pcd->elements = pcde->next;
836
0
            cos_dict_element_free(pcd, pcde, "cos_dict_delete");
837
0
            return 0;
838
0
        }
839
0
        prev = pcde;
840
0
    }
841
0
    return -1;
842
0
}
843
int
844
cos_dict_delete_c_key(cos_dict_t *pcd, const char *key)
845
0
{
846
0
    return cos_dict_delete(pcd, (const byte *)key, strlen(key));
847
0
}
848
849
static void
850
cos_dict_release(cos_object_t *pco, client_name_t cname)
851
860k
{
852
860k
    cos_dict_t *const pcd = (cos_dict_t *)pco;
853
860k
    cos_dict_element_t *cur;
854
860k
    cos_dict_element_t *next;
855
856
3.54M
    for (cur = pcd->elements; cur; cur = next) {
857
2.68M
        next = cur->next;
858
2.68M
        cos_dict_element_free(pcd, cur, cname);
859
2.68M
    }
860
860k
    pcd->elements = 0;
861
860k
}
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
615k
{
868
615k
    int Element_Count = 0;
869
870
615k
    if (pcde) {
871
        /* Temporarily replace the output stream in pdev. */
872
503k
        stream *save = pdev->strm;
873
874
503k
        pdev->strm = s;
875
2.23M
        for (;;) {
876
2.23M
            gs_id object_id1 = (pdev->NoEncrypt.size == 0 ||
877
2.23M
                                bytes_compare(pdev->NoEncrypt.data, pdev->NoEncrypt.size,
878
0
                                    pcde->key.data, pcde->key.size)
879
2.23M
                                ? object_id : (gs_id)-1);
880
881
2.23M
            Element_Count++;
882
883
2.23M
            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.23M
            pdf_write_value(pdev, pcde->key.data, pcde->key.size, object_id1);
915
2.23M
            cos_value_write_spaced(&pcde->value, pdev, true, object_id1);
916
2.23M
            pcde = pcde->next;
917
2.23M
            if (pcde || do_space)
918
1.97M
                stream_putc(s, '\n');
919
2.23M
            if (!pcde)
920
503k
                break;
921
2.23M
        }
922
503k
        pdev->strm = save;
923
503k
    }
924
615k
    return 0;
925
615k
}
926
int
927
cos_dict_elements_write(const cos_dict_t *pcd, gx_device_pdf *pdev)
928
97.9k
{
929
97.9k
    return cos_elements_write(pdev->strm, pcd->elements, pdev, true, pcd->id);
930
97.9k
}
931
932
static int
933
cos_dict_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
934
216k
{
935
216k
    stream *s = pdev->strm;
936
937
216k
    stream_puts(s, "<<");
938
216k
    cos_elements_write(s, ((const cos_dict_t *)pco)->elements, pdev, false, object_id);
939
216k
    stream_puts(s, ">>");
940
216k
    if (pdev->PDFA != 0)
941
0
        stream_puts(s, "\n");
942
216k
    return 0;
943
216k
}
944
945
static int find_first_dict_entry(const cos_dict_t *d, const cos_dict_element_t **element)
946
17
{
947
17
    const cos_dict_element_t *pcde = d->elements, *First;
948
17
    int code, length, length1, length2, offset1 = 0, offset2 = 0, i;
949
950
17
    *element = 0L;
951
952
17
    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
17
    for (i = 0;First->key.data[i] == 0x00; i++)
959
0
        ;
960
961
17
    length1 = First->key.size - i;
962
17
    offset1 = i;
963
964
17
    if (First->key.data[offset1] == '/') {
965
0
        length1 -= 1;
966
0
        offset1 += 1;
967
17
    } else {
968
17
        if (First->key.data[offset1] == '(') {
969
17
            length1 = First->key.size - 2;
970
17
            offset1 = 1;
971
17
        } else {
972
0
            return_error(gs_error_typecheck);
973
0
        }
974
17
    }
975
976
17
    pcde = pcde->next;
977
17
    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
17
    *element = First;
1014
17
    return 0;
1015
17
}
1016
1017
static int find_next_dict_entry(const cos_dict_t *d, const cos_dict_element_t **element)
1018
34
{
1019
34
    const cos_dict_element_t *pcde = d->elements, *Current = *element, *Next = 0L;
1020
34
    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
34
    for (i = 0;Current->key.data[i] == 0x00; i++)
1027
0
        ;
1028
34
    length1 = Current->key.size - i;
1029
34
    offset1 = i;
1030
34
    if (Current->key.data[offset1] == '/') {
1031
0
        length1 -= 1;
1032
0
        offset1 += 1;
1033
34
    } else {
1034
34
        if (Current->key.data[0] == '(') {
1035
34
            length1 -= 2;
1036
34
            offset1 = 1;
1037
34
        } else {
1038
0
            return_error(gs_error_typecheck);
1039
0
        }
1040
34
    }
1041
1042
68
    while (pcde) {
1043
34
        for (i = 0;pcde->key.data[i] == 0x00; i++)
1044
0
            ;
1045
34
        length2 = pcde->key.size - i;
1046
34
        offset2 = i;
1047
34
        if (pcde->key.data[offset2] == '/') {
1048
0
            length2 -= 1;
1049
0
            offset2 += 1;
1050
34
        } else {
1051
34
            if (pcde->key.data[0] == '(') {
1052
34
                length2 -= 2;
1053
34
                offset2 = 1;
1054
34
            } else {
1055
0
                return_error(gs_error_typecheck);
1056
0
            }
1057
34
        }
1058
1059
34
        if (length2 < length1)
1060
0
            length = length2;
1061
34
        else
1062
34
            length = length1;
1063
34
        code = strncmp((const char *)&pcde->key.data[offset2], (const char *)&Current->key.data[offset1], length);
1064
34
        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
34
        pcde = pcde->next;
1096
34
    }
1097
34
    *element = Next;
1098
34
    return 0;
1099
34
}
1100
1101
static int find_last_dict_entry(const cos_dict_t *d, const cos_dict_element_t **element)
1102
17
{
1103
17
    const cos_dict_element_t *pcde = d->elements, *Last, *Next;
1104
1105
17
    *element = 0L;
1106
1107
17
    Next = Last = pcde;
1108
1109
17
    do {
1110
17
        Last = Next;
1111
17
        find_next_dict_entry(d, &Next);
1112
17
    } while (Next);
1113
1114
17
    *element = Last;
1115
1116
17
    return 0;
1117
17
}
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 * 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
51
{
1160
51
    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
51
    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
51
    } else {
1172
51
        offset = 0;
1173
51
        length = element->key.size;
1174
51
    }
1175
1176
51
    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
51
    } else {
1195
51
        if (!pdev->KeyLength || object_id == (gs_id)-1)
1196
51
            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
51
    }
1200
51
    return 0;
1201
51
}
1202
1203
int
1204
cos_write_dict_as_ordered_array(cos_object_t *pco, gx_device_pdf *pdev, pdf_resource_type_t type)
1205
17
{
1206
17
    stream *s;
1207
17
    int code;
1208
17
    const cos_dict_t *d;
1209
17
    const cos_dict_element_t *pcde, *First, *Last;
1210
1211
17
    if (cos_type(pco) != cos_type_dict)
1212
0
        return_error(gs_error_typecheck);
1213
1214
17
    d = (const cos_dict_t *)pco;
1215
1216
17
    if (pco->id == 0 || pco->written)
1217
0
        return_error(gs_error_Fatal);
1218
17
    pdf_open_separate(pdev, pco->id, type);
1219
1220
17
    s = pdev->strm;
1221
17
    pcde = d->elements;
1222
17
    if (!pcde){
1223
0
        stream_puts(s, "<<>>\n");
1224
0
        pdf_end_separate(pdev, type);
1225
0
        return 0;
1226
0
    }
1227
1228
17
    code = find_first_dict_entry(d, &First);
1229
17
    if (code < 0) {
1230
0
        pdf_end_separate(pdev, type);
1231
0
        return code;
1232
0
    }
1233
1234
17
    code = find_last_dict_entry(d, &Last);
1235
17
    if (code < 0) {
1236
0
        pdf_end_separate(pdev, type);
1237
0
        return code;
1238
0
    }
1239
1240
17
    stream_puts(s, "<<\n/Limits [\n");
1241
17
    write_key_as_string(pdev, s, First, pco->id);
1242
17
    stream_puts(s, "\n");
1243
17
    write_key_as_string(pdev, s, Last, pco->id);
1244
17
    stream_puts(s, "\n]\n");
1245
17
    stream_puts(s, "/Names [");
1246
17
    do {
1247
17
        stream_puts(s, "\n");
1248
17
        write_key_as_string(pdev, s, First, pco->id);
1249
17
        cos_value_write_spaced(&First->value, pdev, true, -1);
1250
17
        find_next_dict_entry(d, &First);
1251
17
    } while (First);
1252
17
    stream_puts(s, "]\n>>\n");
1253
1254
17
    pdf_end_separate(pdev, type);
1255
17
    pco->written = true;
1256
17
    return code;
1257
17
}
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
68.0k
{
1264
68.0k
    const cos_dict_element_t *pcde = pcd->elements;
1265
1266
137k
    for (; pcde; pcde = pcde->next)
1267
69.3k
        if (COS_VALUE_IS_OBJECT(&pcde->value) &&
1268
69.3k
            pcde->value.contents.object->id  &&
1269
69.3k
            !pcde->value.contents.object->written /* ForOPDFRead only. */)
1270
35.2k
            cos_write_object(pcde->value.contents.object, pdev, resourceOther);
1271
68.0k
    return 0;
1272
68.0k
}
1273
int
1274
cos_dict_objects_delete(cos_dict_t *pcd)
1275
68.0k
{
1276
68.0k
    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
137k
    for (; pcde; pcde = pcde->next) {
1284
69.3k
        if (pcde->value.contents.object) {
1285
69.3k
            cos_dict_element_t *pcde1 = pcde->next;
1286
1287
115k
            for (; pcde1; pcde1 = pcde1->next)
1288
46.0k
                if (pcde->value.contents.object == pcde1->value.contents.object)
1289
0
                    pcde1->value.contents.object = NULL;
1290
69.3k
            pcde->value.contents.object->id = 0;
1291
69.3k
        }
1292
69.3k
    }
1293
68.0k
    return 0;
1294
68.0k
}
1295
1296
/* Put an element in a dictionary. */
1297
3.30M
#define DICT_COPY_KEY 1
1298
4.91M
#define DICT_COPY_VALUE 2
1299
3.30M
#define DICT_FREE_KEY 4
1300
119k
#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
2.72M
{
1305
2.72M
    gs_memory_t *mem = COS_OBJECT_MEMORY(pcd);
1306
2.72M
    cos_dict_element_t **ppcde = &pcd->elements;
1307
2.72M
    cos_dict_element_t *pcde;
1308
2.72M
    cos_dict_element_t *next;
1309
2.72M
    cos_value_t value;
1310
2.72M
    int code;
1311
1312
14.8M
    while ((next = *ppcde) != 0 &&
1313
14.8M
           bytes_compare(next->key.data, next->key.size, key_data, key_size)
1314
2.72M
           )
1315
12.1M
        ppcde = &next->next;
1316
2.72M
    if (next) {
1317
        /* We're replacing an existing element. */
1318
36.4k
        if ((pvalue->value_type == COS_VALUE_SCALAR ||
1319
36.4k
             pvalue->value_type == COS_VALUE_CONST) &&
1320
36.4k
            pvalue->value_type == next->value.value_type &&
1321
36.4k
            !bytes_compare(pvalue->contents.chars.data, pvalue->contents.chars.size,
1322
35.9k
                next->value.contents.chars.data, next->value.contents.chars.size))
1323
27.7k
            return 0; /* Same as old value. */
1324
8.67k
        if ((pvalue->value_type == COS_VALUE_OBJECT ||
1325
8.67k
             pvalue->value_type == COS_VALUE_RESOURCE) &&
1326
8.67k
            pvalue->value_type == next->value.value_type &&
1327
8.67k
            pvalue->contents.object == next->value.contents.object)
1328
0
            return 0; /* Same as old value. */
1329
8.67k
        code = cos_copy_element_value(&value, mem, pvalue,
1330
8.67k
                                      (flags & DICT_COPY_VALUE) != 0);
1331
8.67k
        if (code < 0)
1332
0
            return code;
1333
8.67k
        cos_value_free(&next->value, mem,
1334
8.67k
                       "cos_dict_put(old value)");
1335
8.67k
        pcde = next;
1336
2.68M
    } else {
1337
        /* Create a new element. */
1338
2.68M
        byte *copied_key_data;
1339
1340
2.68M
        if (flags & DICT_COPY_KEY) {
1341
595k
            copied_key_data = gs_alloc_string(mem, key_size,
1342
595k
                                              "cos_dict_put(key)");
1343
595k
            if (copied_key_data == 0)
1344
0
                return_error(gs_error_VMerror);
1345
595k
            memcpy(copied_key_data, key_data, key_size);
1346
595k
        } else
1347
2.08M
            copied_key_data = (byte *)key_data; /* OK to break const */
1348
2.68M
        pcde = gs_alloc_struct(mem, cos_dict_element_t, &st_cos_dict_element,
1349
2.68M
                               "cos_dict_put(element)");
1350
2.68M
        code = cos_copy_element_value(&value, mem, pvalue,
1351
2.68M
                                      (flags & DICT_COPY_VALUE) != 0);
1352
2.68M
        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.68M
        pcde->key.data = copied_key_data;
1363
2.68M
        pcde->key.size = key_size;
1364
2.68M
        pcde->owns_key = (flags & DICT_FREE_KEY) != 0;
1365
2.68M
        pcde->next = next;
1366
2.68M
        *ppcde = pcde;
1367
2.68M
    }
1368
2.69M
    pcde->value = value;
1369
2.69M
    pcd->md5_valid = false;
1370
2.69M
    return 0;
1371
2.72M
}
1372
int
1373
cos_dict_put(cos_dict_t *pcd, const byte *key_data, uint key_size,
1374
             const cos_value_t *pvalue)
1375
119k
{
1376
119k
    return cos_dict_put_copy(pcd, key_data, key_size, pvalue, DICT_COPY_ALL);
1377
119k
}
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
498k
{
1382
498k
    return cos_dict_put_copy(pcd, key_data, key_size, pvalue,
1383
498k
                             DICT_COPY_KEY | DICT_FREE_KEY);
1384
498k
}
1385
int
1386
cos_dict_put_c_key(cos_dict_t *pcd, const char *key, const cos_value_t *pvalue)
1387
2.10M
{
1388
2.10M
    return cos_dict_put_copy(pcd, (const byte *)key, strlen(key), pvalue,
1389
2.10M
                             DICT_COPY_VALUE);
1390
2.10M
}
1391
int
1392
cos_dict_put_c_key_string(cos_dict_t *pcd, const char *key,
1393
                          const byte *data, uint size)
1394
1.05M
{
1395
1.05M
    cos_value_t value;
1396
1397
1.05M
    cos_string_value(&value, data, size);
1398
1.05M
    return cos_dict_put_c_key(pcd, key, &value);
1399
1.05M
}
1400
int
1401
cos_dict_put_c_key_int(cos_dict_t *pcd, const char *key, int value)
1402
788k
{
1403
788k
    char str[sizeof(int) * 8 / 3 + 3]; /* sign, rounding, 0 terminator */
1404
1405
788k
    gs_snprintf(str, sizeof(str), "%d", value);
1406
788k
    return cos_dict_put_c_key_string(pcd, key, (byte *)str, strlen(str));
1407
788k
}
1408
int
1409
cos_dict_put_c_key_bool(cos_dict_t *pcd, const char *key, bool value)
1410
15.8k
{
1411
15.8k
    return cos_dict_put_c_key_string(pcd, key,
1412
15.8k
                (const byte *)(value ? "true" : "false"),
1413
15.8k
                              (value ? 4 : 5));
1414
15.8k
}
1415
int
1416
cos_dict_put_c_key_real(cos_dict_t *pcd, const char *key, double value)
1417
10.1k
{
1418
10.1k
    byte str[50];   /****** ADHOC ******/
1419
10.1k
    stream s;
1420
1421
10.1k
    s_init(&s, NULL);
1422
10.1k
    swrite_string(&s, str, sizeof(str));
1423
10.1k
    pprintg1(&s, "%g", value);
1424
10.1k
    return cos_dict_put_c_key_string(pcd, key, str, stell(&s));
1425
10.1k
}
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
25.2k
{
1430
25.2k
    cos_array_t *pca = cos_array_from_floats(pdev, pf, size,
1431
25.2k
                                             "cos_dict_put_c_key_floats");
1432
25.2k
    int code;
1433
1434
25.2k
    if (pca == 0)
1435
0
        return_error(gs_error_VMerror);
1436
25.2k
    code = cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
1437
25.2k
    if (code < 0)
1438
0
        COS_FREE(pca, "cos_dict_put_c_key_floats");
1439
25.2k
    return code;
1440
25.2k
}
1441
int
1442
cos_dict_put_c_key_object(cos_dict_t *pcd, const char *key, cos_object_t *pco)
1443
602k
{
1444
602k
    cos_value_t value;
1445
1446
602k
    return cos_dict_put_c_key(pcd, key, cos_object_value(&value, pco));
1447
602k
}
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
50.3k
{
1452
50.3k
    cos_value_t cvalue;
1453
1454
50.3k
    return cos_dict_put(pcd, key_data, key_size,
1455
50.3k
                        cos_string_value(&cvalue, value_data, value_size));
1456
50.3k
}
1457
int
1458
cos_dict_put_string_copy(cos_dict_t *pcd, const char *key, const char *value)
1459
39.8k
{
1460
39.8k
    return cos_dict_put_c_key_string(pcd, key, (byte *)value, strlen(value));
1461
39.8k
}
1462
int
1463
cos_dict_put_c_strings(cos_dict_t *pcd, const char *key, const char *value)
1464
393k
{
1465
393k
    cos_value_t cvalue;
1466
1467
393k
    return cos_dict_put_c_key(pcd, key, cos_c_string_value(&cvalue, value));
1468
393k
}
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
6
{
1474
6
    cos_dict_element_t *pcde = pcdfrom->elements;
1475
6
    cos_dict_element_t *head = pcdto->elements;
1476
1477
12
    while (pcde) {
1478
6
        cos_dict_element_t *next = pcde->next;
1479
1480
6
        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
6
        } else {
1484
            /* Move the element. */
1485
6
            pcde->next = head;
1486
6
            head = pcde;
1487
6
        }
1488
6
        pcde = next;
1489
6
    }
1490
6
    pcdto->elements = head;
1491
6
    pcdfrom->elements = 0;
1492
6
    pcdto->md5_valid = false;
1493
6
    return 0;
1494
6
}
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
218k
{
1500
218k
    cos_dict_element_t *pcde = pcd->elements;
1501
1502
899k
    for (; pcde; pcde = pcde->next)
1503
782k
        if (!bytes_compare(key_data, key_size, pcde->key.data, pcde->key.size))
1504
101k
            return &pcde->value;
1505
117k
    return 0;
1506
218k
}
1507
const cos_value_t *
1508
cos_dict_find_c_key(const cos_dict_t *pcd, const char *key)
1509
56.8k
{
1510
56.8k
    if (pcd == NULL)
1511
0
        return NULL;
1512
56.8k
    return cos_dict_find(pcd, (const byte *)key, strlen(key));
1513
56.8k
}
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
197k
{
1517
197k
    cos_dict_t *dict = (cos_dict_t *) pco0;
1518
197k
    cos_dict_element_t *pcde0 = dict->elements;
1519
1520
717k
    for (; pcde0; pcde0 = pcde0->next) {
1521
520k
        gs_md5_append(md5, pcde0->key.data, pcde0->key.size);
1522
520k
        cos_value_hash(&pcde0->value, md5, hash, pdev);
1523
520k
    }
1524
197k
    return 0;
1525
197k
}
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
6.20M
{
1531
6.20M
    int code = 0;
1532
1533
6.20M
    if (!pco0->md5_valid) {
1534
79.3k
        gs_md5_init((gs_md5_state_t *)&pco0->md5);
1535
79.3k
        code = cos_dict_hash(pco0, (gs_md5_state_t *)&pco0->md5, (gs_md5_byte_t *)pco0->hash, pdev);
1536
79.3k
        if (code < 0)
1537
0
            return code;
1538
79.3k
        gs_md5_finish((gs_md5_state_t *)&pco0->md5, (gs_md5_byte_t *)pco0->hash);
1539
79.3k
        ((cos_object_t *)pco0)->md5_valid = true;
1540
79.3k
    }
1541
6.20M
    if (!pco1->md5_valid) {
1542
94.0k
        gs_md5_init((gs_md5_state_t *)&pco1->md5);
1543
94.0k
        code = cos_dict_hash(pco1, (gs_md5_state_t *)&pco1->md5, (gs_md5_byte_t *)pco1->hash, pdev);
1544
94.0k
        if (code < 0)
1545
0
            return code;
1546
94.0k
        gs_md5_finish((gs_md5_state_t *)&pco1->md5, (gs_md5_byte_t *)pco1->hash);
1547
94.0k
        ((cos_object_t *)pco1)->md5_valid = true;
1548
94.0k
    }
1549
6.20M
    if (memcmp(&pco0->hash, &pco1->hash, 16) != 0)
1550
6.06M
        return false;
1551
1552
146k
    return true;
1553
6.20M
}
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
548
{
1560
548
    cos_dict_element_t *pcde = pcd->elements;
1561
1562
3.52k
    for (; pcde; pcde = pcde->next) {
1563
2.97k
        int code = proc(client_data, pcde->key.data, pcde->key.size, &pcde->value);
1564
1565
2.97k
        if (code != 0)
1566
0
            return code;
1567
2.97k
    }
1568
548
    return 0;
1569
548
}
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
498k
{
1587
498k
    cos_param_list_writer_t *const pclist =
1588
498k
        (cos_param_list_writer_t *)plist;
1589
498k
    gx_device_pdf *pdev = pclist->pdev;
1590
498k
    gs_memory_t *mem = pclist->memory;
1591
498k
    cos_value_t value;
1592
498k
    cos_array_t *pca;
1593
498k
    int key_len = strlen(pkey);
1594
498k
    byte key_chars[100];    /****** ADHOC ******/
1595
498k
    int code;
1596
1597
498k
    while(pdev->child)
1598
0
        pdev = (gx_device_pdf *)pdev->child;
1599
1600
498k
    if (key_len > sizeof(key_chars) - 1)
1601
0
        return_error(gs_error_limitcheck);
1602
498k
    switch (pvalue->type) {
1603
438k
    default: {
1604
438k
        param_printer_params_t ppp;
1605
438k
        printer_param_list_t pplist;
1606
438k
        stream s;
1607
438k
        int len, skip;
1608
438k
        byte *str;
1609
1610
438k
        s_init(&s, NULL);
1611
438k
        ppp = param_printer_params_default;
1612
438k
        ppp.prefix = ppp.suffix = ppp.item_prefix = ppp.item_suffix = 0;
1613
438k
        ppp.print_ok = pclist->print_ok;
1614
438k
        s_init_param_printer(&pplist, &ppp, &s);
1615
438k
        swrite_position_only(&s);
1616
438k
        param_write_typed((gs_param_list *)&pplist, "", pvalue);
1617
438k
        len = stell(&s);
1618
438k
        str = gs_alloc_string(mem, len, "cos_param_put(string)");
1619
438k
        if (str == 0)
1620
0
            return_error(gs_error_VMerror);
1621
438k
        swrite_string(&s, str, len);
1622
438k
        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
438k
        skip = (str[1] == ' ' ? 2 : 1);
1628
438k
        memmove(str, str + skip, len - skip);
1629
438k
        str = gs_resize_string(mem, str, len, len - skip,
1630
438k
                               "cos_param_put(string)");
1631
438k
        cos_string_value(&value, str, len - skip);
1632
438k
    }
1633
0
        break;
1634
17.4k
    case gs_param_type_int_array: {
1635
17.4k
        uint i;
1636
1637
17.4k
        pca = cos_array_alloc(pdev, "cos_param_put(array)");
1638
17.4k
        if (pca == 0)
1639
0
            return_error(gs_error_VMerror);
1640
35.7k
        for (i = 0; i < pvalue->value.ia.size; ++i)
1641
18.2k
            CHECK(cos_array_add_int(pca, pvalue->value.ia.data[i]));
1642
17.4k
    }
1643
59.7k
    av:
1644
59.7k
        cos_object_value(&value, COS_OBJECT(pca));
1645
59.7k
        break;
1646
42.3k
    case gs_param_type_float_array: {
1647
42.3k
        uint i;
1648
1649
42.3k
        pca = cos_array_alloc(pdev, "cos_param_put(array)");
1650
42.3k
        if (pca == 0)
1651
0
            return_error(gs_error_VMerror);
1652
139k
        for (i = 0; i < pvalue->value.ia.size; ++i)
1653
97.2k
            CHECK(cos_array_add_real(pca, pvalue->value.fa.data[i]));
1654
42.3k
    }
1655
42.3k
        goto av;
1656
42.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
498k
    }
1661
498k
    if (key_len > 99)
1662
0
        return_error(gs_error_rangecheck);
1663
498k
    memcpy(key_chars + 1, pkey, key_len);
1664
498k
    key_chars[0] = '/';
1665
498k
    return cos_dict_put_no_copy(pclist->pcd, key_chars, key_len + 1, &value);
1666
498k
}
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
152k
{
1672
152k
    gs_param_list_init((gs_param_list *)pclist, &cos_param_list_writer_procs,
1673
152k
                       COS_OBJECT_MEMORY(pcd));
1674
152k
    pclist->pcd = pcd;
1675
152k
    pclist->pdev = pdev;
1676
152k
    pclist->print_ok = print_ok;
1677
152k
    return 0;
1678
152k
}
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
214k
{
1693
214k
    gs_memory_t *mem = pdev->pdf_memory;
1694
214k
    cos_stream_t *pcs =
1695
214k
        gs_alloc_struct(mem, cos_stream_t, &st_cos_object, cname);
1696
1697
214k
    cos_object_init((cos_object_t *)pcs, pdev, &cos_stream_procs);
1698
214k
    return pcs;
1699
214k
}
1700
1701
static void
1702
cos_stream_release(cos_object_t *pco, client_name_t cname)
1703
420k
{
1704
420k
    cos_stream_t *const pcs = (cos_stream_t *)pco;
1705
420k
    cos_stream_piece_t *cur;
1706
420k
    cos_stream_piece_t *next;
1707
1708
828k
    for (cur = pcs->pieces; cur; cur = next) {
1709
408k
        next = cur->next;
1710
408k
        gs_free_object(cos_object_memory(pco), cur, cname);
1711
408k
    }
1712
420k
    pcs->pieces = 0;
1713
420k
    cos_dict_release(pco, cname);
1714
420k
}
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.31k
{
1718
3.31k
    const cos_stream_t *pcs = (const cos_stream_t *)pco0;
1719
3.31k
    cos_stream_piece_t *pcsp = pcs->pieces;
1720
3.31k
    gp_file *sfile = pdev->streams.file;
1721
3.31k
    byte *ptr;
1722
3.31k
    int64_t position_save;
1723
3.31k
    int result;
1724
1725
3.31k
    sflush(pdev->strm);
1726
3.31k
    sflush(pdev->streams.strm);
1727
3.31k
    position_save = gp_ftell(sfile);
1728
1729
3.31k
    if (!pcsp)
1730
3.14k
        return -1;
1731
1732
165
    gs_md5_init(md5);
1733
352
    while(pcsp) {
1734
187
        ptr = gs_malloc(pdev->memory, sizeof (byte), pcsp->size, "hash_cos_stream");
1735
187
        if (ptr == 0L) {
1736
0
            result = gs_note_error(gs_error_VMerror);
1737
0
            return result;
1738
0
        }
1739
187
        if (gp_fseek(sfile, pcsp->position, SEEK_SET) != 0)
1740
0
    return_error(gs_error_ioerror);
1741
1742
187
        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
187
        gs_md5_append(md5, ptr, pcsp->size);
1748
187
        gs_free(pdev->memory, ptr, sizeof (byte), pcsp->size, "hash_cos_stream");
1749
187
        pcsp = pcsp->next;
1750
187
    }
1751
165
    gs_md5_finish(md5, (gs_md5_byte_t *)hash);
1752
165
    if (gp_fseek(sfile, position_save, SEEK_SET) != 0)
1753
0
      return_error(gs_error_ioerror);
1754
1755
165
    return 0;
1756
165
}
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
40.2k
{
1760
40.2k
    cos_stream_t *pcs0 = (cos_stream_t *)pco0;
1761
40.2k
    int code=0;
1762
40.2k
    if (!pco0->stream_md5_valid) {
1763
3.31k
        code = hash_cos_stream(pco0, (gs_md5_state_t *)&pco0->md5, (gs_md5_byte_t *)&pco0->stream_hash, pdev);
1764
3.31k
        if (code < 0)
1765
3.14k
            return code;
1766
165
        pcs0->stream_md5_valid = 1;
1767
165
    }
1768
37.1k
    gs_md5_append(md5, (byte *)&pco0->stream_hash, sizeof(pco0->stream_hash));
1769
37.1k
    if (!pco0->md5_valid) {
1770
279
        gs_md5_init((gs_md5_state_t *)&pco0->md5);
1771
279
        code = cos_dict_hash(pco0, (gs_md5_state_t *)&pco0->md5, (gs_md5_byte_t *)pco0->hash, pdev);
1772
279
        if (code < 0)
1773
0
            return code;
1774
279
        gs_md5_finish((gs_md5_state_t *)&pco0->md5, (gs_md5_byte_t *)pco0->hash);
1775
279
        pcs0->md5_valid = 1;
1776
279
    }
1777
37.1k
    gs_md5_append(md5, (byte *)&pco0->hash, sizeof(pco0->hash));
1778
37.1k
    return code;
1779
37.1k
}
1780
1781
static int
1782
cos_stream_equal(const cos_object_t *pco0, const cos_object_t *pco1, gx_device_pdf *pdev)
1783
589k
{
1784
589k
    cos_stream_t *pcs0 = (cos_stream_t *)pco0;
1785
589k
    cos_stream_t *pcs1 = (cos_stream_t *)pco1;
1786
589k
    int code;
1787
589k
    gs_md5_state_t md5;
1788
589k
    gs_md5_byte_t hash[16];
1789
1790
589k
    gs_md5_init(&md5);
1791
1792
589k
    if (!pco0->stream_md5_valid) {
1793
0
        code = cos_stream_hash(pco0, &md5, (gs_md5_byte_t *)hash, pdev);
1794
0
        if (code < 0)
1795
0
            return false;
1796
0
    }
1797
589k
    if (!pco1->stream_md5_valid) {
1798
3.25k
        code = cos_stream_hash(pco1, &md5, (gs_md5_byte_t *)hash, pdev);
1799
3.25k
        if (code < 0)
1800
3.14k
            return false;
1801
3.25k
    }
1802
586k
    if (memcmp(&pcs0->stream_hash, &pcs1->stream_hash, 16) != 0)
1803
449k
        return false;
1804
136k
    code = cos_dict_equal(pco0, pco1, pdev);
1805
136k
    if (code < 0)
1806
0
        return false;
1807
136k
    if (!code)
1808
25.4k
        return false;
1809
110k
    return true;
1810
136k
}
1811
1812
/* Find the total length of a stream. */
1813
int64_t
1814
cos_stream_length(const cos_stream_t *pcs)
1815
1.12M
{
1816
1.12M
    return pcs->length;
1817
1.12M
}
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
205k
{
1824
205k
    return cos_elements_write(pdev->strm, pcs->elements, pdev, true, pcs->id);
1825
205k
}
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
301k
{
1831
301k
    stream *s = pdev->strm;
1832
301k
    cos_stream_piece_t *pcsp;
1833
301k
    cos_stream_piece_t *last;
1834
301k
    cos_stream_piece_t *next;
1835
301k
    gp_file *sfile = pdev->streams.file;
1836
301k
    int64_t end_pos;
1837
301k
    bool same_file = (pdev->sbstack_depth > 0);
1838
301k
    int code;
1839
301k
    stream_arcfour_state sarc4, *ss = NULL;
1840
1841
301k
    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
301k
    sflush(s);
1848
301k
    sflush(pdev->streams.strm);
1849
1850
    /* Reverse the elements temporarily. */
1851
678k
    for (pcsp = pcs->pieces, last = NULL; pcsp; pcsp = next)
1852
377k
        next = pcsp->next, pcsp->next = last, last = pcsp;
1853
678k
    for (pcsp = last, code = 0; pcsp && code >= 0; pcsp = pcsp->next) {
1854
377k
        if (same_file) {
1855
200k
            code = pdf_copy_data_safe(s, sfile, pcsp->position, pcsp->size);
1856
200k
            if (code < 0)
1857
0
                return code;
1858
200k
        } else {
1859
176k
            end_pos = gp_ftell(sfile);
1860
176k
            if (gp_fseek(sfile, pcsp->position, SEEK_SET) != 0)
1861
0
        return_error(gs_error_ioerror);
1862
176k
            code = pdf_copy_data(s, sfile, pcsp->size, ss);
1863
176k
            if (code < 0)
1864
0
                return code;
1865
176k
            if (gp_fseek(sfile, end_pos, SEEK_SET) != 0)
1866
0
        return_error(gs_error_ioerror);
1867
176k
        }
1868
377k
    }
1869
    /* Reverse the elements back. */
1870
678k
    for (pcsp = last, last = NULL; pcsp; pcsp = next)
1871
377k
        next = pcsp->next, pcsp->next = last, last = pcsp;
1872
1873
301k
    return code;
1874
301k
}
1875
1876
int
1877
cos_stream_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
1878
96.1k
{
1879
96.1k
    stream *s = pdev->strm;
1880
96.1k
    const cos_stream_t *const pcs = (const cos_stream_t *)pco;
1881
96.1k
    int code;
1882
1883
96.1k
    if (pcs->input_strm != NULL) {
1884
204
        stream *s = pco->input_strm;
1885
204
        int status = s_close_filters(&s, NULL);
1886
1887
204
        if (status < 0)
1888
0
            return_error(gs_error_ioerror);
1889
        /* We have to break const here to clear the input_strm. */
1890
204
        ((cos_object_t *)pco)->input_strm = 0;
1891
204
    }
1892
96.1k
    stream_puts(s, "<<");
1893
96.1k
    cos_elements_write(s, pcs->elements, pdev, false, object_id);
1894
96.1k
    pprinti64d1(s, "/Length %"PRId64">>stream\n", cos_stream_length(pcs));
1895
96.1k
    code = cos_stream_contents_write(pcs, pdev);
1896
96.1k
    stream_puts(s, "\nendstream\n");
1897
1898
96.1k
    return code;
1899
96.1k
}
1900
1901
/* Return a stream's dictionary (just a cast). */
1902
cos_dict_t *
1903
cos_stream_dict(cos_stream_t *pcs)
1904
269k
{
1905
269k
    return (cos_dict_t *)pcs;
1906
269k
}
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
9.85M
{
1913
9.85M
    stream *s;
1914
9.85M
    gs_offset_t position;
1915
9.85M
    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
9.85M
    while (pdev->child)
1921
0
        pdev = (gx_device_pdf *)pdev->child;
1922
1923
9.85M
    s = pdev->streams.strm;
1924
9.85M
    position = stell(s);
1925
1926
    /* Check for consecutive writing -- just an optimization. */
1927
9.85M
    if (prev != 0 && prev->position + prev->size + size == position) {
1928
9.35M
        prev->size += size;
1929
9.35M
    } else {
1930
498k
        gs_memory_t *mem = pdev->pdf_memory;
1931
498k
        cos_stream_piece_t *pcsp =
1932
498k
            gs_alloc_struct(mem, cos_stream_piece_t, &st_cos_stream_piece,
1933
498k
                            "cos_stream_add");
1934
1935
498k
        if (pcsp == 0)
1936
0
            return_error(gs_error_VMerror);
1937
498k
        pcsp->position = position - size;
1938
498k
        pcsp->size = size;
1939
498k
        pcsp->next = pcs->pieces;
1940
498k
        pcs->pieces = pcsp;
1941
498k
    }
1942
9.85M
    pcs->length += size;
1943
9.85M
    return 0;
1944
9.85M
}
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
1.75k
{
1950
1.75k
    stream_write(pdev->streams.strm, data, size);
1951
1.75k
    return cos_stream_add(pdev, pcs, size);
1952
1.75k
}
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
11
{
1958
11
    int code = 0;
1959
11
    byte sbuff[200];  /* arbitrary */
1960
11
    uint cnt;
1961
11
    int status = sseek(s, 0);
1962
1963
11
    if (status < 0)
1964
0
        return_error(gs_error_ioerror);
1965
297
    do {
1966
297
        status = sgets(s, sbuff, sizeof(sbuff), &cnt);
1967
1968
297
        if (cnt == 0) {
1969
11
            if (status == EOFC)
1970
11
                break;
1971
11
            return_error(gs_error_ioerror);
1972
11
        }
1973
297
    } while ((code = cos_stream_add_bytes(pdev, pcs, sbuff, cnt)) >= 0);
1974
11
    return code;
1975
11
}
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
94.6k
{
1982
94.6k
    stream *s = pdev->streams.strm;
1983
94.6k
    gs_offset_t position = stell(s), position0 = position;
1984
1985
185k
    while (pcs->pieces != NULL &&
1986
185k
                position == pcs->pieces->position + pcs->pieces->size) {
1987
90.5k
        cos_stream_piece_t *p = pcs->pieces;
1988
1989
90.5k
        position -= p->size;
1990
90.5k
        pcs->pieces = p->next;
1991
90.5k
        gs_free_object(cos_object_memory((cos_object_t *)pcs), p, "cos_stream_release_pieces");
1992
90.5k
    }
1993
94.6k
    if (position0 != position)
1994
90.5k
        if (sseek(s, position) < 0)
1995
0
            return_error(gs_error_ioerror);
1996
94.6k
    return 0;
1997
94.6k
}
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
9.85M
{
2018
9.85M
    uint count = pr->limit - pr->ptr;
2019
9.85M
    cos_write_stream_state_t *ss = (cos_write_stream_state_t *)st;
2020
9.85M
    stream *target = ss->target;
2021
9.85M
    gx_device_pdf *pdev = ss->pdev;
2022
9.85M
    gs_offset_t start_pos;
2023
9.85M
    int code;
2024
2025
9.85M
    while(pdev->child != NULL)
2026
0
        pdev = (gx_device_pdf *)pdev->child;
2027
2028
9.85M
    start_pos = stell(pdev->streams.strm);
2029
9.85M
    stream_write(target, pr->ptr + 1, count);
2030
9.85M
    gs_md5_append(&ss->pcs->md5, pr->ptr + 1, count);
2031
9.85M
    pr->ptr = pr->limit;
2032
9.85M
    sflush(target);
2033
9.85M
    code = cos_stream_add(pdev, ss->pcs, (uint)(stell(pdev->streams.strm) - start_pos));
2034
9.85M
    return (code < 0 ? ERRC : 0);
2035
9.85M
}
2036
static int
2037
cos_write_stream_close(stream *s)
2038
418k
{
2039
418k
    cos_write_stream_state_t *ss = (cos_write_stream_state_t *)s->state;
2040
418k
    int status;
2041
418k
    gx_device_pdf *target_dev = (gx_device_pdf *)ss->pdev;
2042
2043
418k
    while (target_dev->child != NULL)
2044
0
        target_dev = (gx_device_pdf *)target_dev->child;
2045
2046
418k
    sflush(s);
2047
418k
    status = s_close_filters(&ss->target, target_dev->streams.strm);
2048
418k
    gs_md5_finish(&ss->pcs->md5, (gs_md5_byte_t *)ss->pcs->stream_hash);
2049
418k
    ss->pcs->stream_md5_valid = 1;
2050
418k
    return (status < 0 ? status : s_std_close(s));
2051
418k
}
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
418k
{
2064
418k
    gs_memory_t *mem = pdev->pdf_memory;
2065
418k
    stream *s = s_alloc(mem, cname);
2066
418k
    cos_write_stream_state_t *ss = (cos_write_stream_state_t *)
2067
418k
        s_alloc_state(mem, &st_cos_write_stream_state, cname);
2068
418k
#define CWS_BUF_SIZE 512  /* arbitrary */
2069
418k
    byte *buf = gs_alloc_bytes(mem, CWS_BUF_SIZE, cname);
2070
2071
418k
    if (s == 0 || ss == 0 || buf == 0)
2072
0
        goto fail;
2073
418k
    ss->templat = &cos_write_stream_template;
2074
418k
    ss->pcs = pcs;
2075
418k
    ss->pcs->stream_md5_valid = 0;
2076
418k
    gs_md5_init(&ss->pcs->md5);
2077
418k
    memset(&ss->pcs->hash, 0x00, 16);
2078
418k
    ss->pdev = pdev;
2079
418k
    while(ss->pdev->parent)
2080
0
        ss->pdev = (gx_device_pdf *)ss->pdev->parent;
2081
418k
    ss->s = s;
2082
418k
    ss->target = pdev->streams.strm; /* not s->strm */
2083
418k
    s_std_init(s, buf, CWS_BUF_SIZE, &cos_s_procs, s_mode_write);
2084
418k
    s->state = (stream_state *)ss;
2085
418k
    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
418k
}
2093
2094
/* Get cos stream from pipeline. */
2095
cos_stream_t *
2096
cos_stream_from_pipeline(stream *s)
2097
1.42M
{
2098
1.42M
    cos_write_stream_state_t *ss;
2099
2100
4.25M
    while(s->procs.process != cos_s_procs.process) {
2101
2.83M
        s = s->strm;
2102
2.83M
        if (s == 0L)
2103
0
            return 0L;
2104
2.83M
    }
2105
2106
1.42M
    ss = (cos_write_stream_state_t *)s->state;
2107
1.42M
    return ss->pcs;
2108
1.42M
}