Coverage Report

Created: 2022-10-31 07:00

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