Coverage Report

Created: 2025-06-10 07:27

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