1 /* Copyright (C) 2001-2006 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, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: gdevpdfo.c 9607 2009-03-31 14:30:14Z ken $ */
15 /* Cos object support */
16 #include "memory_.h"
17 #include "gx.h"
18 #include "gserrors.h"
19 #include "gsparam.h"
20 #include "gsutil.h" /* for bytes_compare */
21 #include "gdevpdfx.h"
22 #include "gdevpdfo.h"
23 #include "strimpl.h"
24 #include "sa85x.h"
25 #include "sarc4.h"
26
27 #define CHECK(expr)\
28 BEGIN if ((code = (expr)) < 0) return code; END
29
30 /* ---------------- Structure definitions ---------------- */
31
32 /*
33 * Define the generic structure for elements of arrays and
34 * dictionaries/streams.
35 */
36 #define cos_element_common(etype)\
37 etype *next
38 struct cos_element_s {
39 cos_element_common(cos_element_t);
40 };
41 #define private_st_cos_element() /* in gdevpdfo.c */\
42 gs_private_st_ptrs1(st_cos_element, cos_element_t, "cos_element_t",\
43 cos_element_enum_ptrs, cos_element_reloc_ptrs, next)
44 #define cos_element_num_ptrs 1
45
46 /*
47 * Define the structure for a piece of stream contents.
48 */
49 struct cos_stream_piece_s {
50 cos_element_common(cos_stream_piece_t);
51 long position; /* in streams file */
52 uint size;
53 };
54 #define private_st_cos_stream_piece() /* in gdevpdfo.c */\
55 gs_private_st_suffix_add0_local(st_cos_stream_piece, cos_stream_piece_t,\
56 "cos_stream_piece_t", cos_element_enum_ptrs, cos_element_reloc_ptrs,\
57 st_cos_element)
58
59 /*
60 * Define Cos arrays, dictionaries, and streams.
61 */
62 /* array */
63 struct cos_array_element_s {
64 cos_element_common(cos_array_element_t);
65 long index;
66 cos_value_t value;
67 };
68 #define private_st_cos_array_element() /* in gdevpdfo.c */\
69 gs_private_st_composite(st_cos_array_element, cos_array_element_t,\
70 "cos_array_element_t", cos_array_element_enum_ptrs, cos_array_element_reloc_ptrs)
71 /* dict */
72 struct cos_dict_element_s {
73 cos_element_common(cos_dict_element_t);
74 gs_string key;
75 bool owns_key; /* if false, key is shared, do not trace or free */
76 cos_value_t value;
77 };
78 #define private_st_cos_dict_element() /* in gdevpdfo.c */\
79 gs_private_st_composite(st_cos_dict_element, cos_dict_element_t,\
80 "cos_dict_element_t", cos_dict_element_enum_ptrs, cos_dict_element_reloc_ptrs)
81
82 /* GC descriptors */
83 private_st_cos_element();
84 private_st_cos_stream_piece();
85 private_st_cos_object();
86 private_st_cos_value();
87 private_st_cos_array_element();
88 private_st_cos_dict_element();
89
90 /* GC procedures */
91 static
92 ENUM_PTRS_WITH(cos_value_enum_ptrs, cos_value_t *pcv) return 0;
93 case 0:
94 switch (pcv->value_type) {
95 case COS_VALUE_SCALAR:
96 return ENUM_STRING(&pcv->contents.chars);
97 case COS_VALUE_CONST:
98 break;
99 case COS_VALUE_OBJECT:
100 case COS_VALUE_RESOURCE:
101 return ENUM_OBJ(pcv->contents.object);
102 }
103 return 0;
104 ENUM_PTRS_END
105 static
RELOC_PTRS_WITH(cos_value_reloc_ptrs,cos_value_t * pcv)106 RELOC_PTRS_WITH(cos_value_reloc_ptrs, cos_value_t *pcv)
107 {
108 switch (pcv->value_type) {
109 case COS_VALUE_SCALAR:
110 RELOC_STRING_VAR(pcv->contents.chars);
111 case COS_VALUE_CONST:
112 break;
113 case COS_VALUE_OBJECT:
114 case COS_VALUE_RESOURCE:
115 RELOC_VAR(pcv->contents.object);
116 break;
117 }
118 }
119 RELOC_PTRS_END
120 static
ENUM_PTRS_WITH(cos_array_element_enum_ptrs,cos_array_element_t * pcae)121 ENUM_PTRS_WITH(cos_array_element_enum_ptrs, cos_array_element_t *pcae)
122 {
123 return (index < cos_element_num_ptrs ?
124 ENUM_USING_PREFIX(st_cos_element, 0) :
125 ENUM_USING(st_cos_value, &pcae->value, sizeof(cos_value_t),
126 index - cos_element_num_ptrs));
127 }
128 ENUM_PTRS_END
129 static
RELOC_PTRS_WITH(cos_array_element_reloc_ptrs,cos_array_element_t * pcae)130 RELOC_PTRS_WITH(cos_array_element_reloc_ptrs, cos_array_element_t *pcae)
131 {
132 RELOC_PREFIX(st_cos_element);
133 RELOC_USING(st_cos_value, &pcae->value, sizeof(cos_value_t));
134 }
135 RELOC_PTRS_END
136 static
ENUM_PTRS_WITH(cos_dict_element_enum_ptrs,cos_dict_element_t * pcde)137 ENUM_PTRS_WITH(cos_dict_element_enum_ptrs, cos_dict_element_t *pcde)
138 {
139 return (index < cos_element_num_ptrs ?
140 ENUM_USING_PREFIX(st_cos_element, 0) :
141 (index -= cos_element_num_ptrs) > 0 ?
142 ENUM_USING(st_cos_value, &pcde->value, sizeof(cos_value_t),
143 index - 1) :
144 pcde->owns_key ? ENUM_STRING(&pcde->key) : ENUM_OBJ(NULL));
145 }
146 ENUM_PTRS_END
147 static
RELOC_PTRS_WITH(cos_dict_element_reloc_ptrs,cos_dict_element_t * pcde)148 RELOC_PTRS_WITH(cos_dict_element_reloc_ptrs, cos_dict_element_t *pcde)
149 {
150 RELOC_PREFIX(st_cos_element);
151 if (pcde->owns_key)
152 RELOC_STRING_VAR(pcde->key);
153 RELOC_USING(st_cos_value, &pcde->value, sizeof(cos_value_t));
154 }
155 RELOC_PTRS_END
156
157 /* ---------------- Generic support ---------------- */
158
159 /* Initialize a just-allocated cos object. */
160 static void
cos_object_init(cos_object_t * pco,gx_device_pdf * pdev,const cos_object_procs_t * procs)161 cos_object_init(cos_object_t *pco, gx_device_pdf *pdev,
162 const cos_object_procs_t *procs)
163 {
164 if (pco) {
165 pco->cos_procs = procs;
166 pco->id = 0;
167 pco->elements = 0;
168 pco->pieces = 0;
169 pco->pdev = pdev;
170 pco->pres = 0;
171 pco->is_open = true;
172 pco->is_graphics = false;
173 pco->written = false;
174 pco->length = 0;
175 pco->input_strm = 0;
176 }
177 }
178
179 /* Get the allocator for a Cos object. */
180 gs_memory_t *
cos_object_memory(const cos_object_t * pco)181 cos_object_memory(const cos_object_t *pco)
182 {
183 return pco->pdev->pdf_memory;
184 }
185
186 /* Change a generic cos object into one of a specific type. */
187 int
cos_become(cos_object_t * pco,cos_type_t cotype)188 cos_become(cos_object_t *pco, cos_type_t cotype)
189 {
190 if (cos_type(pco) != cos_type_generic)
191 return_error(gs_error_typecheck);
192 cos_type(pco) = cotype;
193 return 0;
194 }
195
196 /* Release a cos object. */
197 cos_proc_release(cos_release); /* check prototype */
198 void
cos_release(cos_object_t * pco,client_name_t cname)199 cos_release(cos_object_t *pco, client_name_t cname)
200 {
201 pco->cos_procs->release(pco, cname);
202 }
203
204 /* Free a cos object. */
205 void
cos_free(cos_object_t * pco,client_name_t cname)206 cos_free(cos_object_t *pco, client_name_t cname)
207 {
208 cos_release(pco, cname);
209 gs_free_object(cos_object_memory(pco), pco, cname);
210 }
211
212 /* Write a cos object on the output. */
213 cos_proc_write(cos_write); /* check prototype */
214 int
cos_write(const cos_object_t * pco,gx_device_pdf * pdev,gs_id object_id)215 cos_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
216 {
217 return pco->cos_procs->write(pco, pdev, object_id);
218 }
219
220 /* Write a cos object as a PDF object. */
221 int
cos_write_object(cos_object_t * pco,gx_device_pdf * pdev)222 cos_write_object(cos_object_t *pco, gx_device_pdf *pdev)
223 {
224 int code;
225
226 if (pco->id == 0 || pco->written)
227 return_error(gs_error_Fatal);
228 pdf_open_separate(pdev, pco->id);
229 code = cos_write(pco, pdev, pco->id);
230 pdf_end_separate(pdev);
231 pco->written = true;
232 return code;
233 }
234
235 /* Make a value to store into a composite object. */
236 const cos_value_t *
cos_string_value(cos_value_t * pcv,const byte * data,uint size)237 cos_string_value(cos_value_t *pcv, const byte *data, uint size)
238 {
239 /*
240 * It's OK to break const here, because the value will be copied
241 * before being stored in the collection.
242 */
243 pcv->contents.chars.data = (byte *)data;
244 pcv->contents.chars.size = size;
245 pcv->value_type = COS_VALUE_SCALAR;
246 return pcv;
247 }
248 const cos_value_t *
cos_c_string_value(cos_value_t * pcv,const char * str)249 cos_c_string_value(cos_value_t *pcv, const char *str)
250 {
251 /*
252 * We shouldn't break const here, because the value will not be copied
253 * or freed (or traced), but that would require a lot of bothersome
254 * casting elsewhere.
255 */
256 pcv->contents.chars.data = (byte *)str;
257 pcv->contents.chars.size = strlen(str);
258 pcv->value_type = COS_VALUE_CONST;
259 return pcv;
260 }
261 const cos_value_t *
cos_object_value(cos_value_t * pcv,cos_object_t * pco)262 cos_object_value(cos_value_t *pcv, cos_object_t *pco)
263 {
264 pcv->contents.object = pco;
265 pcv->value_type = COS_VALUE_OBJECT;
266 return pcv;
267 }
268 const cos_value_t *
cos_resource_value(cos_value_t * pcv,cos_object_t * pco)269 cos_resource_value(cos_value_t *pcv, cos_object_t *pco)
270 {
271 pcv->contents.object = pco;
272 pcv->value_type = COS_VALUE_RESOURCE;
273 return pcv;
274 }
275
276 /* Free a value. */
277 void
cos_value_free(const cos_value_t * pcv,const cos_object_t * pco,client_name_t cname)278 cos_value_free(const cos_value_t *pcv, const cos_object_t *pco,
279 client_name_t cname)
280 {
281 switch (pcv->value_type) {
282 case COS_VALUE_SCALAR:
283 gs_free_string(cos_object_memory(pco), pcv->contents.chars.data,
284 pcv->contents.chars.size, cname);
285 case COS_VALUE_CONST:
286 break;
287 case COS_VALUE_OBJECT:
288 /* Free the object if this is the only reference to it. */
289 if (pcv->contents.object != NULL) /* see cos_dict_objects_delete. */
290 if (!pcv->contents.object->id)
291 cos_free(pcv->contents.object, cname);
292 case COS_VALUE_RESOURCE:
293 break;
294 }
295 }
296
297 /* Write a value on the output. */
298 static int
cos_value_write_spaced(const cos_value_t * pcv,gx_device_pdf * pdev,bool do_space,gs_id object_id)299 cos_value_write_spaced(const cos_value_t *pcv, gx_device_pdf *pdev,
300 bool do_space, gs_id object_id)
301 {
302 stream *s = pdev->strm;
303
304 switch (pcv->value_type) {
305 case COS_VALUE_SCALAR:
306 case COS_VALUE_CONST:
307 if (do_space)
308 switch (pcv->contents.chars.data[0]) {
309 case '/': case '(': case '<': break;
310 default: stream_putc(s, ' ');
311 }
312 return pdf_write_value(pdev, pcv->contents.chars.data,
313 pcv->contents.chars.size, object_id);
314 case COS_VALUE_RESOURCE:
315 pprintld1(s, "/R%ld", pcv->contents.object->id);
316 break;
317 case COS_VALUE_OBJECT: {
318 const cos_object_t *pco = pcv->contents.object;
319
320 if (!pco->id) {
321 if (do_space &&
322 !(pco->cos_procs == cos_type_array ||
323 pco->cos_procs == cos_type_dict)
324 ) {
325 /* Arrays and dictionaries (only) are self-delimiting. */
326 stream_putc(s, ' ');
327 }
328 return cos_write(pco, pdev, object_id);
329 }
330 if (do_space)
331 stream_putc(s, ' ');
332 pprintld1(s, "%ld 0 R", pco->id);
333 break;
334 }
335 default: /* can't happen */
336 return_error(gs_error_Fatal);
337 }
338 return 0;
339 }
340 int
cos_value_write(const cos_value_t * pcv,gx_device_pdf * pdev)341 cos_value_write(const cos_value_t *pcv, gx_device_pdf *pdev)
342 {
343 return cos_value_write_spaced(pcv, pdev, false, 0);
344 }
345
346 /* Copy a value if necessary for putting into an array or dictionary. */
347 static int
cos_copy_element_value(cos_value_t * pcv,gs_memory_t * mem,const cos_value_t * pvalue,bool copy)348 cos_copy_element_value(cos_value_t *pcv, gs_memory_t *mem,
349 const cos_value_t *pvalue, bool copy)
350 {
351 *pcv = *pvalue;
352 if (pvalue->value_type == COS_VALUE_SCALAR && copy) {
353 byte *value_data = gs_alloc_string(mem, pvalue->contents.chars.size,
354 "cos_copy_element_value");
355
356 if (value_data == 0)
357 return_error(gs_error_VMerror);
358 memcpy(value_data, pvalue->contents.chars.data,
359 pvalue->contents.chars.size);
360 pcv->contents.chars.data = value_data;
361 }
362 return 0;
363 }
364
365 /* Release a value copied for putting, if the operation fails. */
366 static void
cos_uncopy_element_value(cos_value_t * pcv,gs_memory_t * mem,bool copy)367 cos_uncopy_element_value(cos_value_t *pcv, gs_memory_t *mem, bool copy)
368 {
369 if (pcv->value_type == COS_VALUE_SCALAR && copy)
370 gs_free_string(mem, pcv->contents.chars.data, pcv->contents.chars.size,
371 "cos_uncopy_element_value");
372 }
373
374 /* Compare 2 cos values for equality. */
375 static int
cos_value_equal(const cos_value_t * pcv0,const cos_value_t * pcv1,gx_device_pdf * pdev)376 cos_value_equal(const cos_value_t *pcv0, const cos_value_t *pcv1, gx_device_pdf *pdev)
377 {
378 if (pcv0->value_type != pcv1->value_type)
379 return false;
380 switch (pcv0->value_type) {
381 case COS_VALUE_SCALAR:
382 case COS_VALUE_CONST:
383 if (bytes_compare(pcv0->contents.chars.data, pcv0->contents.chars.size,
384 pcv1->contents.chars.data, pcv1->contents.chars.size))
385 return false;
386 break;
387 case COS_VALUE_OBJECT:
388 if (pcv0->contents.object != pcv1->contents.object) {
389 int code = pcv0->contents.object->cos_procs->equal(
390 pcv0->contents.object, pcv1->contents.object, pdev);
391
392 if (code < 0)
393 return code;
394 if (!code)
395 return false;
396 }
397 break;
398 case COS_VALUE_RESOURCE:
399 if (pcv0->contents.object != pcv1->contents.object)
400 return false;
401 break;
402 }
403 return true;
404 }
405
406 /* ---------------- Specific object types ---------------- */
407
408 /* ------ Generic objects ------ */
409
410 static cos_proc_release(cos_generic_release);
411 static cos_proc_write(cos_generic_write);
412 static cos_proc_equal(cos_generic_equal);
413 const cos_object_procs_t cos_generic_procs = {
414 cos_generic_release, cos_generic_write, cos_generic_equal
415 };
416
417 cos_object_t *
cos_object_alloc(gx_device_pdf * pdev,client_name_t cname)418 cos_object_alloc(gx_device_pdf *pdev, client_name_t cname)
419 {
420 gs_memory_t *mem = pdev->pdf_memory;
421 cos_object_t *pco =
422 gs_alloc_struct(mem, cos_object_t, &st_cos_object, cname);
423
424 cos_object_init(pco, pdev, &cos_generic_procs);
425 return pco;
426 }
427
428 static void
cos_generic_release(cos_object_t * pco,client_name_t cname)429 cos_generic_release(cos_object_t *pco, client_name_t cname)
430 {
431 /* Do nothing. */
432 }
433
434 static int
cos_generic_write(const cos_object_t * pco,gx_device_pdf * pdev,gs_id object_id)435 cos_generic_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
436 {
437 return_error(gs_error_Fatal);
438 }
439
440 static int
cos_generic_equal(const cos_object_t * pco0,const cos_object_t * pco1,gx_device_pdf * pdev)441 cos_generic_equal(const cos_object_t *pco0, const cos_object_t *pco1, gx_device_pdf *pdev)
442 {
443 return_error(gs_error_Fatal);
444 }
445
446 /* ------ Arrays ------ */
447
448 static cos_proc_release(cos_array_release);
449 static cos_proc_write(cos_array_write);
450 static cos_proc_equal(cos_array_equal);
451 const cos_object_procs_t cos_array_procs = {
452 cos_array_release, cos_array_write, cos_array_equal
453 };
454
455 cos_array_t *
cos_array_alloc(gx_device_pdf * pdev,client_name_t cname)456 cos_array_alloc(gx_device_pdf *pdev, client_name_t cname)
457 {
458 gs_memory_t *mem = pdev->pdf_memory;
459 cos_array_t *pca =
460 gs_alloc_struct(mem, cos_array_t, &st_cos_object, cname);
461
462 cos_object_init((cos_object_t *)pca, pdev, &cos_array_procs);
463 return pca;
464 }
465
466 cos_array_t *
cos_array_from_floats(gx_device_pdf * pdev,const float * pf,uint size,client_name_t cname)467 cos_array_from_floats(gx_device_pdf *pdev, const float *pf, uint size,
468 client_name_t cname)
469 {
470 cos_array_t *pca = cos_array_alloc(pdev, cname);
471 uint i;
472
473 if (pca == 0)
474 return 0;
475 for (i = 0; i < size; ++i) {
476 int code = cos_array_add_real(pca, pf[i]);
477
478 if (code < 0) {
479 COS_FREE(pca, cname);
480 return 0;
481 }
482 }
483 return pca;
484 }
485
486 static void
cos_array_release(cos_object_t * pco,client_name_t cname)487 cos_array_release(cos_object_t *pco, client_name_t cname)
488 {
489 gs_memory_t *mem = cos_object_memory(pco);
490 cos_array_t *const pca = (cos_array_t *)pco;
491 cos_array_element_t *cur;
492 cos_array_element_t *next;
493
494 for (cur = pca->elements; cur; cur = next) {
495 next = cur->next;
496 cos_value_free(&cur->value, pco, cname);
497 gs_free_object(mem, cur, cname);
498 }
499 pca->elements = 0;
500 }
501
502 static cos_array_element_t *cos_array_reorder(const cos_array_t *pca,
503 cos_array_element_t *first);
504 static int
cos_array_write(const cos_object_t * pco,gx_device_pdf * pdev,gs_id object_id)505 cos_array_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
506 {
507 stream *s = pdev->strm;
508 const cos_array_t *const pca = (const cos_array_t *)pco;
509 cos_array_element_t *first = cos_array_reorder(pca, NULL);
510 cos_array_element_t *pcae;
511 uint last_index = 0;
512
513 stream_puts(s, "[");
514 for (pcae = first; pcae; ++last_index, pcae = pcae->next) {
515 if (pcae != first)
516 stream_putc(s, '\n');
517 for (; pcae->index > last_index; ++last_index)
518 stream_puts(s, "null\n");
519 cos_value_write_spaced(&pcae->value, pdev, false, object_id);
520 }
521 DISCARD(cos_array_reorder(pca, first));
522 stream_puts(s, "]");
523 if (pdev->PDFA)
524 stream_puts(s, "\n");
525 return 0;
526 }
527
528 static int
cos_array_equal(const cos_object_t * pco0,const cos_object_t * pco1,gx_device_pdf * pdev)529 cos_array_equal(const cos_object_t *pco0, const cos_object_t *pco1, gx_device_pdf *pdev)
530 {
531 const cos_array_t *const pca0 = (const cos_array_t *)pco0;
532 const cos_array_t *const pca1 = (const cos_array_t *)pco1;
533 cos_array_element_t *first0 = pca0->elements;
534 cos_array_element_t *first1 = pca1->elements;
535 cos_array_element_t *pcae0, *pcae1;
536 int code;
537
538 for (pcae0 = first0, pcae1 = first1; pcae0 && pcae1;
539 pcae0 = pcae0->next, pcae1 = pcae1->next) {
540 if (pcae0->index != pcae1->index)
541 return false;
542 code = cos_value_equal(&pcae0->value, &pcae1->value, pdev);
543 if (code < 0)
544 return code;
545 if (!code)
546 return false;
547 }
548 if (pcae0 || pcae1)
549 return false;
550 return true;
551 }
552
553
554 /* Put/add an element in/to an array. */
555 int
cos_array_put(cos_array_t * pca,long index,const cos_value_t * pvalue)556 cos_array_put(cos_array_t *pca, long index, const cos_value_t *pvalue)
557 {
558 gs_memory_t *mem = COS_OBJECT_MEMORY(pca);
559 cos_value_t value;
560 int code = cos_copy_element_value(&value, mem, pvalue, true);
561
562 if (code >= 0) {
563 code = cos_array_put_no_copy(pca, index, &value);
564 if (code < 0)
565 cos_uncopy_element_value(&value, mem, true);
566 }
567 return code;
568 }
569 int
cos_array_put_no_copy(cos_array_t * pca,long index,const cos_value_t * pvalue)570 cos_array_put_no_copy(cos_array_t *pca, long index, const cos_value_t *pvalue)
571 {
572 gs_memory_t *mem = COS_OBJECT_MEMORY(pca);
573 cos_array_element_t **ppcae = &pca->elements;
574 cos_array_element_t *pcae;
575 cos_array_element_t *next;
576
577 while ((next = *ppcae) != 0 && next->index > index)
578 ppcae = &next->next;
579 if (next && next->index == index) {
580 /* We're replacing an existing element. */
581 cos_value_free(&next->value, COS_OBJECT(pca),
582 "cos_array_put(old value)");
583 pcae = next;
584 } else {
585 /* Create a new element. */
586 pcae = gs_alloc_struct(mem, cos_array_element_t, &st_cos_array_element,
587 "cos_array_put(element)");
588 if (pcae == 0)
589 return_error(gs_error_VMerror);
590 pcae->index = index;
591 pcae->next = next;
592 *ppcae = pcae;
593 }
594 pcae->value = *pvalue;
595 return 0;
596 }
597 static long
cos_array_next_index(const cos_array_t * pca)598 cos_array_next_index(const cos_array_t *pca)
599 {
600 return (pca->elements ? pca->elements->index + 1 : 0L);
601 }
602 int
cos_array_add(cos_array_t * pca,const cos_value_t * pvalue)603 cos_array_add(cos_array_t *pca, const cos_value_t *pvalue)
604 {
605 return cos_array_put(pca, cos_array_next_index(pca), pvalue);
606 }
607 int
cos_array_add_no_copy(cos_array_t * pca,const cos_value_t * pvalue)608 cos_array_add_no_copy(cos_array_t *pca, const cos_value_t *pvalue)
609 {
610 return cos_array_put_no_copy(pca, cos_array_next_index(pca), pvalue);
611 }
612 int
cos_array_add_c_string(cos_array_t * pca,const char * str)613 cos_array_add_c_string(cos_array_t *pca, const char *str)
614 {
615 cos_value_t value;
616
617 return cos_array_add(pca, cos_c_string_value(&value, str));
618 }
619 int
cos_array_add_int(cos_array_t * pca,int i)620 cos_array_add_int(cos_array_t *pca, int i)
621 {
622 char str[sizeof(int) * 8 / 3 + 3]; /* sign, rounding, 0 terminator */
623 cos_value_t v;
624
625 sprintf(str, "%d", i);
626 return cos_array_add(pca, cos_string_value(&v, (byte *)str, strlen(str)));
627 }
628 int
cos_array_add_real(cos_array_t * pca,floatp r)629 cos_array_add_real(cos_array_t *pca, floatp r)
630 {
631 byte str[50]; /****** ADHOC ******/
632 stream s;
633 cos_value_t v;
634
635 s_init(&s, NULL);
636 swrite_string(&s, str, sizeof(str));
637 pprintg1(&s, "%g", r);
638 return cos_array_add(pca, cos_string_value(&v, str, stell(&s)));
639 }
640 int
cos_array_add_object(cos_array_t * pca,cos_object_t * pco)641 cos_array_add_object(cos_array_t *pca, cos_object_t *pco)
642 {
643 cos_value_t value;
644
645 value.contents.chars.size = 0; /* Quiet a warning appeared with MSVC6 inline optimization. */
646 return cos_array_add(pca, cos_object_value(&value, pco));
647 }
648
649 /*
650 * Remove and return the last element of an array. Since this is intended
651 * specifically for arrays used as stacks, it gives an error if there is a
652 * gap in indices between the last element and the element before it.
653 */
654 int
cos_array_unadd(cos_array_t * pca,cos_value_t * pvalue)655 cos_array_unadd(cos_array_t *pca, cos_value_t *pvalue)
656 {
657 cos_array_element_t *pcae = pca->elements;
658
659 if (pcae == 0 ||
660 pcae->index != (pcae->next == 0 ? 0 : pcae->next->index + 1)
661 )
662 return_error(gs_error_rangecheck);
663 *pvalue = pcae->value;
664 pca->elements = pcae->next;
665 gs_free_object(COS_OBJECT_MEMORY(pca), pcae, "cos_array_unadd");
666 return 0;
667 }
668
669 /* Get the first / next element for enumerating an array. */
670 const cos_array_element_t *
cos_array_element_first(const cos_array_t * pca)671 cos_array_element_first(const cos_array_t *pca)
672 {
673 return pca->elements;
674 }
675 const cos_array_element_t *
cos_array_element_next(const cos_array_element_t * pca,long * pindex,const cos_value_t ** ppvalue)676 cos_array_element_next(const cos_array_element_t *pca, long *pindex,
677 const cos_value_t **ppvalue)
678 {
679 *pindex = pca->index;
680 *ppvalue = &pca->value;
681 return pca->next;
682 }
683
684 /*
685 * Reorder the elements of an array for writing or after writing. Usage:
686 * first_element = cos_array_reorder(pca, NULL);
687 * ...
688 * cos_array_reorder(pca, first_element);
689 */
690 static cos_array_element_t *
cos_array_reorder(const cos_array_t * pca,cos_array_element_t * first)691 cos_array_reorder(const cos_array_t *pca, cos_array_element_t *first)
692 {
693 cos_array_element_t *last;
694 cos_array_element_t *next;
695 cos_array_element_t *pcae;
696
697 for (pcae = (first ? first : pca->elements), last = NULL; pcae;
698 pcae = next)
699 next = pcae->next, pcae->next = last, last = pcae;
700 return last;
701 }
702
703 /* ------ Dictionaries ------ */
704
705 static cos_proc_release(cos_dict_release);
706 static cos_proc_write(cos_dict_write);
707 static cos_proc_equal(cos_dict_equal);
708 const cos_object_procs_t cos_dict_procs = {
709 cos_dict_release, cos_dict_write, cos_dict_equal
710 };
711
712 cos_dict_t *
cos_dict_alloc(gx_device_pdf * pdev,client_name_t cname)713 cos_dict_alloc(gx_device_pdf *pdev, client_name_t cname)
714 {
715 gs_memory_t *mem = pdev->pdf_memory;
716 cos_dict_t *pcd =
717 gs_alloc_struct(mem, cos_dict_t, &st_cos_object, cname);
718
719 cos_object_init((cos_object_t *)pcd, pdev, &cos_dict_procs);
720 return pcd;
721 }
722
723 static void
cos_dict_element_free(cos_dict_t * pcd,cos_dict_element_t * pcde,client_name_t cname)724 cos_dict_element_free(cos_dict_t *pcd, cos_dict_element_t *pcde,
725 client_name_t cname)
726 {
727 gs_memory_t *mem = COS_OBJECT_MEMORY(pcd);
728
729 cos_value_free(&pcde->value, COS_OBJECT(pcd), cname);
730 if (pcde->owns_key)
731 gs_free_string(mem, pcde->key.data, pcde->key.size, cname);
732 gs_free_object(mem, pcde, cname);
733 }
734
735 static void
cos_dict_release(cos_object_t * pco,client_name_t cname)736 cos_dict_release(cos_object_t *pco, client_name_t cname)
737 {
738 cos_dict_t *const pcd = (cos_dict_t *)pco;
739 cos_dict_element_t *cur;
740 cos_dict_element_t *next;
741
742 for (cur = pcd->elements; cur; cur = next) {
743 next = cur->next;
744 cos_dict_element_free(pcd, cur, cname);
745 }
746 pcd->elements = 0;
747 }
748
749 /* Write the elements of a dictionary. */
750 static int
cos_elements_write(stream * s,const cos_dict_element_t * pcde,gx_device_pdf * pdev,bool do_space,gs_id object_id)751 cos_elements_write(stream *s, const cos_dict_element_t *pcde,
752 gx_device_pdf *pdev, bool do_space, gs_id object_id)
753 {
754 if (pcde) {
755 /* Temporarily replace the output stream in pdev. */
756 stream *save = pdev->strm;
757
758 pdev->strm = s;
759 for (;;) {
760 gs_id object_id1 = (pdev->NoEncrypt.size == 0 ||
761 bytes_compare(pdev->NoEncrypt.data, pdev->NoEncrypt.size,
762 pcde->key.data, pcde->key.size)
763 ? object_id : (gs_id)-1);
764
765 pdf_write_value(pdev, pcde->key.data, pcde->key.size, object_id1);
766 cos_value_write_spaced(&pcde->value, pdev, true, object_id1);
767 pcde = pcde->next;
768 if (pcde || do_space)
769 stream_putc(s, '\n');
770 if (!pcde)
771 break;
772 }
773 pdev->strm = save;
774 }
775 return 0;
776 }
777 int
cos_dict_elements_write(const cos_dict_t * pcd,gx_device_pdf * pdev)778 cos_dict_elements_write(const cos_dict_t *pcd, gx_device_pdf *pdev)
779 {
780 return cos_elements_write(pdev->strm, pcd->elements, pdev, true, pcd->id);
781 }
782
783 static int
cos_dict_write(const cos_object_t * pco,gx_device_pdf * pdev,gs_id object_id)784 cos_dict_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
785 {
786 stream *s = pdev->strm;
787
788 stream_puts(s, "<<");
789 cos_elements_write(s, ((const cos_dict_t *)pco)->elements, pdev, false, object_id);
790 stream_puts(s, ">>");
791 if (pdev->PDFA)
792 stream_puts(s, "\n");
793 return 0;
794 }
795
796 /* Write/delete definitions of named objects. */
797 /* This is a special-purpose facility for pdf_close. */
798 int
cos_dict_objects_write(const cos_dict_t * pcd,gx_device_pdf * pdev)799 cos_dict_objects_write(const cos_dict_t *pcd, gx_device_pdf *pdev)
800 {
801 const cos_dict_element_t *pcde = pcd->elements;
802
803 for (; pcde; pcde = pcde->next)
804 if (COS_VALUE_IS_OBJECT(&pcde->value) &&
805 pcde->value.contents.object->id &&
806 !pcde->value.contents.object->written /* ForOPDFRead only. */)
807 cos_write_object(pcde->value.contents.object, pdev);
808 return 0;
809 }
810 int
cos_dict_objects_delete(cos_dict_t * pcd)811 cos_dict_objects_delete(cos_dict_t *pcd)
812 {
813 cos_dict_element_t *pcde = pcd->elements;
814
815 /*
816 * Delete duplicate references to prevent a dual object freeing.
817 * Delete the objects' IDs so that freeing the dictionary will
818 * free them.
819 */
820 for (; pcde; pcde = pcde->next) {
821 if (pcde->value.contents.object) {
822 cos_dict_element_t *pcde1 = pcde->next;
823
824 for (; pcde1; pcde1 = pcde1->next)
825 if (pcde->value.contents.object == pcde1->value.contents.object)
826 pcde1->value.contents.object = NULL;
827 pcde->value.contents.object->id = 0;
828 }
829 }
830 return 0;
831 }
832
833 /* Put an element in a dictionary. */
834 #define DICT_COPY_KEY 1
835 #define DICT_COPY_VALUE 2
836 #define DICT_FREE_KEY 4
837 #define DICT_COPY_ALL (DICT_COPY_KEY | DICT_COPY_VALUE | DICT_FREE_KEY)
838 static int
cos_dict_put_copy(cos_dict_t * pcd,const byte * key_data,uint key_size,const cos_value_t * pvalue,int flags)839 cos_dict_put_copy(cos_dict_t *pcd, const byte *key_data, uint key_size,
840 const cos_value_t *pvalue, int flags)
841 {
842 gs_memory_t *mem = COS_OBJECT_MEMORY(pcd);
843 cos_dict_element_t **ppcde = &pcd->elements;
844 cos_dict_element_t *pcde;
845 cos_dict_element_t *next;
846 cos_value_t value;
847 int code;
848
849 while ((next = *ppcde) != 0 &&
850 bytes_compare(next->key.data, next->key.size, key_data, key_size)
851 )
852 ppcde = &next->next;
853 if (next) {
854 /* We're replacing an existing element. */
855 if ((pvalue->value_type == COS_VALUE_SCALAR ||
856 pvalue->value_type == COS_VALUE_CONST) &&
857 pvalue->value_type == next->value.value_type &&
858 !bytes_compare(pvalue->contents.chars.data, pvalue->contents.chars.size,
859 next->value.contents.chars.data, next->value.contents.chars.size))
860 return 0; /* Same as old value. */
861 if ((pvalue->value_type == COS_VALUE_OBJECT ||
862 pvalue->value_type == COS_VALUE_RESOURCE) &&
863 pvalue->value_type == next->value.value_type &&
864 pvalue->contents.object == next->value.contents.object)
865 return 0; /* Same as old value. */
866 code = cos_copy_element_value(&value, mem, pvalue,
867 (flags & DICT_COPY_VALUE) != 0);
868 if (code < 0)
869 return code;
870 if (flags & DICT_FREE_KEY)
871 gs_free_const_string(mem, key_data, key_size,
872 "cos_dict_put(new key)");
873 cos_value_free(&next->value, COS_OBJECT(pcd),
874 "cos_dict_put(old value)");
875 pcde = next;
876 } else {
877 /* Create a new element. */
878 byte *copied_key_data;
879
880 if (flags & DICT_COPY_KEY) {
881 copied_key_data = gs_alloc_string(mem, key_size,
882 "cos_dict_put(key)");
883 if (copied_key_data == 0)
884 return_error(gs_error_VMerror);
885 memcpy(copied_key_data, key_data, key_size);
886 } else
887 copied_key_data = (byte *)key_data; /* OK to break const */
888 pcde = gs_alloc_struct(mem, cos_dict_element_t, &st_cos_dict_element,
889 "cos_dict_put(element)");
890 code = cos_copy_element_value(&value, mem, pvalue,
891 (flags & DICT_COPY_VALUE) != 0);
892 if (pcde == 0 || code < 0) {
893 if (code >= 0)
894 cos_uncopy_element_value(&value, mem,
895 (flags & DICT_COPY_VALUE) != 0);
896 gs_free_object(mem, pcde, "cos_dict_put(element)");
897 if (flags & DICT_COPY_KEY)
898 gs_free_string(mem, copied_key_data, key_size,
899 "cos_dict_put(key)");
900 return (code < 0 ? code : gs_note_error(gs_error_VMerror));
901 }
902 pcde->key.data = copied_key_data;
903 pcde->key.size = key_size;
904 pcde->owns_key = (flags & DICT_FREE_KEY) != 0;
905 pcde->next = next;
906 *ppcde = pcde;
907 }
908 pcde->value = value;
909 return 0;
910 }
911 int
cos_dict_put(cos_dict_t * pcd,const byte * key_data,uint key_size,const cos_value_t * pvalue)912 cos_dict_put(cos_dict_t *pcd, const byte *key_data, uint key_size,
913 const cos_value_t *pvalue)
914 {
915 return cos_dict_put_copy(pcd, key_data, key_size, pvalue, DICT_COPY_ALL);
916 }
917 int
cos_dict_put_no_copy(cos_dict_t * pcd,const byte * key_data,uint key_size,const cos_value_t * pvalue)918 cos_dict_put_no_copy(cos_dict_t *pcd, const byte *key_data, uint key_size,
919 const cos_value_t *pvalue)
920 {
921 return cos_dict_put_copy(pcd, key_data, key_size, pvalue,
922 DICT_COPY_KEY | DICT_FREE_KEY);
923 }
924 int
cos_dict_put_c_key(cos_dict_t * pcd,const char * key,const cos_value_t * pvalue)925 cos_dict_put_c_key(cos_dict_t *pcd, const char *key, const cos_value_t *pvalue)
926 {
927 return cos_dict_put_copy(pcd, (const byte *)key, strlen(key), pvalue,
928 DICT_COPY_VALUE);
929 }
930 int
cos_dict_put_c_key_string(cos_dict_t * pcd,const char * key,const byte * data,uint size)931 cos_dict_put_c_key_string(cos_dict_t *pcd, const char *key,
932 const byte *data, uint size)
933 {
934 cos_value_t value;
935
936 cos_string_value(&value, data, size);
937 return cos_dict_put_c_key(pcd, key, &value);
938 }
939 int
cos_dict_put_c_key_int(cos_dict_t * pcd,const char * key,int value)940 cos_dict_put_c_key_int(cos_dict_t *pcd, const char *key, int value)
941 {
942 char str[sizeof(int) * 8 / 3 + 3]; /* sign, rounding, 0 terminator */
943
944 sprintf(str, "%d", value);
945 return cos_dict_put_c_key_string(pcd, key, (byte *)str, strlen(str));
946 }
947 int
cos_dict_put_c_key_bool(cos_dict_t * pcd,const char * key,bool value)948 cos_dict_put_c_key_bool(cos_dict_t *pcd, const char *key, bool value)
949 {
950 return cos_dict_put_c_key_string(pcd, key,
951 (const byte *)(value ? "true" : "false"),
952 (value ? 4 : 5));
953 }
954 int
cos_dict_put_c_key_real(cos_dict_t * pcd,const char * key,floatp value)955 cos_dict_put_c_key_real(cos_dict_t *pcd, const char *key, floatp value)
956 {
957 byte str[50]; /****** ADHOC ******/
958 stream s;
959
960 s_init(&s, NULL);
961 swrite_string(&s, str, sizeof(str));
962 pprintg1(&s, "%g", value);
963 return cos_dict_put_c_key_string(pcd, key, str, stell(&s));
964 }
965 int
cos_dict_put_c_key_floats(cos_dict_t * pcd,const char * key,const float * pf,uint size)966 cos_dict_put_c_key_floats(cos_dict_t *pcd, const char *key, const float *pf,
967 uint size)
968 {
969 cos_array_t *pca = cos_array_from_floats(pcd->pdev, pf, size,
970 "cos_dict_put_c_key_floats");
971 int code;
972
973 if (pca == 0)
974 return_error(gs_error_VMerror);
975 code = cos_dict_put_c_key_object(pcd, key, COS_OBJECT(pca));
976 if (code < 0)
977 COS_FREE(pca, "cos_dict_put_c_key_floats");
978 return code;
979 }
980 int
cos_dict_put_c_key_object(cos_dict_t * pcd,const char * key,cos_object_t * pco)981 cos_dict_put_c_key_object(cos_dict_t *pcd, const char *key, cos_object_t *pco)
982 {
983 cos_value_t value;
984
985 return cos_dict_put_c_key(pcd, key, cos_object_value(&value, pco));
986 }
987 int
cos_dict_put_string(cos_dict_t * pcd,const byte * key_data,uint key_size,const byte * value_data,uint value_size)988 cos_dict_put_string(cos_dict_t *pcd, const byte *key_data, uint key_size,
989 const byte *value_data, uint value_size)
990 {
991 cos_value_t cvalue;
992
993 return cos_dict_put(pcd, key_data, key_size,
994 cos_string_value(&cvalue, value_data, value_size));
995 }
996 int
cos_dict_put_string_copy(cos_dict_t * pcd,const char * key,const char * value)997 cos_dict_put_string_copy(cos_dict_t *pcd, const char *key, const char *value)
998 {
999 return cos_dict_put_c_key_string(pcd, key, (byte *)value, strlen(value));
1000 }
1001 int
cos_dict_put_c_strings(cos_dict_t * pcd,const char * key,const char * value)1002 cos_dict_put_c_strings(cos_dict_t *pcd, const char *key, const char *value)
1003 {
1004 cos_value_t cvalue;
1005
1006 return cos_dict_put_c_key(pcd, key, cos_c_string_value(&cvalue, value));
1007 }
1008
1009 /* Move all the elements from one dict to another. */
1010 int
cos_dict_move_all(cos_dict_t * pcdto,cos_dict_t * pcdfrom)1011 cos_dict_move_all(cos_dict_t *pcdto, cos_dict_t *pcdfrom)
1012 {
1013 cos_dict_element_t *pcde = pcdfrom->elements;
1014 cos_dict_element_t *head = pcdto->elements;
1015
1016 while (pcde) {
1017 cos_dict_element_t *next = pcde->next;
1018
1019 if (cos_dict_find(pcdto, pcde->key.data, pcde->key.size)) {
1020 /* Free the element, which has been superseded. */
1021 cos_dict_element_free(pcdfrom, pcde, "cos_dict_move_all_from");
1022 } else {
1023 /* Move the element. */
1024 pcde->next = head;
1025 head = pcde;
1026 }
1027 pcde = next;
1028 }
1029 pcdto->elements = head;
1030 pcdfrom->elements = 0;
1031 return 0;
1032 }
1033
1034 /* Look up a key in a dictionary. */
1035 const cos_value_t *
cos_dict_find(const cos_dict_t * pcd,const byte * key_data,uint key_size)1036 cos_dict_find(const cos_dict_t *pcd, const byte *key_data, uint key_size)
1037 {
1038 cos_dict_element_t *pcde = pcd->elements;
1039
1040 for (; pcde; pcde = pcde->next)
1041 if (!bytes_compare(key_data, key_size, pcde->key.data, pcde->key.size))
1042 return &pcde->value;
1043 return 0;
1044 }
1045 const cos_value_t *
cos_dict_find_c_key(const cos_dict_t * pcd,const char * key)1046 cos_dict_find_c_key(const cos_dict_t *pcd, const char *key)
1047 {
1048 return cos_dict_find(pcd, (const byte *)key, strlen(key));
1049 }
1050
1051 /* Compare two dictionaries. */
1052 int
cos_dict_equal(const cos_object_t * pco0,const cos_object_t * pco1,gx_device_pdf * pdev)1053 cos_dict_equal(const cos_object_t *pco0, const cos_object_t *pco1, gx_device_pdf *pdev)
1054 {
1055 const cos_dict_t *pcd0 = (const cos_dict_t *)pco0;
1056 const cos_dict_t *pcd1 = (const cos_dict_t *)pco1;
1057 cos_dict_element_t *pcde0 = pcd0->elements;
1058 cos_dict_element_t *pcde1 = pcd1->elements;
1059
1060 for (; pcde1; pcde1 = pcde1->next) {
1061 if (cos_dict_find(pcd0, pcde1->key.data, pcde1->key.size) == NULL)
1062 return false;
1063 }
1064 for (; pcde0; pcde0 = pcde0->next) {
1065 const cos_value_t *v = cos_dict_find(pcd1, pcde0->key.data, pcde0->key.size);
1066 int code;
1067
1068 if (v == NULL)
1069 return false;
1070 code = cos_value_equal(&pcde0->value, v, pdev);
1071 if (code < 0)
1072 return code;
1073 if (!code)
1074 return false;
1075 }
1076 return true;
1077 }
1078
1079 /* Process all entries in a dictionary. */
1080 int
cos_dict_forall(const cos_dict_t * pcd,void * client_data,int (* proc)(void * client_data,const byte * key_data,uint key_size,const cos_value_t * v))1081 cos_dict_forall(const cos_dict_t *pcd, void *client_data,
1082 int (*proc)(void *client_data, const byte *key_data, uint key_size, const cos_value_t *v))
1083 {
1084 cos_dict_element_t *pcde = pcd->elements;
1085
1086 for (; pcde; pcde = pcde->next) {
1087 int code = proc(client_data, pcde->key.data, pcde->key.size, &pcde->value);
1088
1089 if (code != 0)
1090 return code;
1091 }
1092 return 0;
1093 }
1094
1095 /* Set up a parameter list that writes into a Cos dictionary. */
1096
1097 /* We'll implement the other printers later if we have to. */
1098 static param_proc_xmit_typed(cos_param_put_typed);
1099 static const gs_param_list_procs cos_param_list_writer_procs = {
1100 cos_param_put_typed,
1101 NULL /* begin_collection */ ,
1102 NULL /* end_collection */ ,
1103 NULL /* get_next_key */ ,
1104 gs_param_request_default,
1105 gs_param_requested_default
1106 };
1107 static int
cos_param_put_typed(gs_param_list * plist,gs_param_name pkey,gs_param_typed_value * pvalue)1108 cos_param_put_typed(gs_param_list * plist, gs_param_name pkey,
1109 gs_param_typed_value * pvalue)
1110 {
1111 cos_param_list_writer_t *const pclist =
1112 (cos_param_list_writer_t *)plist;
1113 gx_device_pdf *pdev = pclist->pcd->pdev;
1114 gs_memory_t *mem = pclist->memory;
1115 cos_value_t value;
1116 cos_array_t *pca;
1117 int key_len = strlen(pkey);
1118 byte key_chars[100]; /****** ADHOC ******/
1119 int code;
1120
1121 if (key_len > sizeof(key_chars) - 1)
1122 return_error(gs_error_limitcheck);
1123 switch (pvalue->type) {
1124 default: {
1125 param_printer_params_t ppp;
1126 printer_param_list_t pplist;
1127 stream s;
1128 int len, skip;
1129 byte *str;
1130
1131 s_init(&s, NULL);
1132 ppp = param_printer_params_default;
1133 ppp.prefix = ppp.suffix = ppp.item_prefix = ppp.item_suffix = 0;
1134 ppp.print_ok = pclist->print_ok;
1135 s_init_param_printer(&pplist, &ppp, &s);
1136 swrite_position_only(&s);
1137 param_write_typed((gs_param_list *)&pplist, "", pvalue);
1138 len = stell(&s);
1139 str = gs_alloc_string(mem, len, "cos_param_put(string)");
1140 if (str == 0)
1141 return_error(gs_error_VMerror);
1142 swrite_string(&s, str, len);
1143 param_write_typed((gs_param_list *)&pplist, "", pvalue);
1144 /*
1145 * The string starts with an initial / or /<space>, which
1146 * we need to remove.
1147 */
1148 skip = (str[1] == ' ' ? 2 : 1);
1149 memmove(str, str + skip, len - skip);
1150 str = gs_resize_string(mem, str, len, len - skip,
1151 "cos_param_put(string)");
1152 cos_string_value(&value, str, len - skip);
1153 }
1154 break;
1155 case gs_param_type_int_array: {
1156 uint i;
1157
1158 pca = cos_array_alloc(pdev, "cos_param_put(array)");
1159 if (pca == 0)
1160 return_error(gs_error_VMerror);
1161 for (i = 0; i < pvalue->value.ia.size; ++i)
1162 CHECK(cos_array_add_int(pca, pvalue->value.ia.data[i]));
1163 }
1164 av:
1165 cos_object_value(&value, COS_OBJECT(pca));
1166 break;
1167 case gs_param_type_float_array: {
1168 uint i;
1169
1170 pca = cos_array_alloc(pdev, "cos_param_put(array)");
1171 if (pca == 0)
1172 return_error(gs_error_VMerror);
1173 for (i = 0; i < pvalue->value.ia.size; ++i)
1174 CHECK(cos_array_add_real(pca, pvalue->value.fa.data[i]));
1175 }
1176 goto av;
1177 case gs_param_type_string_array:
1178 case gs_param_type_name_array:
1179 /****** NYI ******/
1180 return_error(gs_error_typecheck);
1181 }
1182 memcpy(key_chars + 1, pkey, key_len);
1183 key_chars[0] = '/';
1184 return cos_dict_put_no_copy(pclist->pcd, key_chars, key_len + 1, &value);
1185 }
1186
1187 int
cos_param_list_writer_init(cos_param_list_writer_t * pclist,cos_dict_t * pcd,int print_ok)1188 cos_param_list_writer_init(cos_param_list_writer_t *pclist, cos_dict_t *pcd,
1189 int print_ok)
1190 {
1191 gs_param_list_init((gs_param_list *)pclist, &cos_param_list_writer_procs,
1192 COS_OBJECT_MEMORY(pcd));
1193 pclist->pcd = pcd;
1194 pclist->print_ok = print_ok;
1195 return 0;
1196 }
1197
1198 /* ------ Streams ------ */
1199
1200 static cos_proc_release(cos_stream_release);
1201 static cos_proc_write(cos_stream_write);
1202 static cos_proc_equal(cos_stream_equal);
1203 const cos_object_procs_t cos_stream_procs = {
1204 cos_stream_release, cos_stream_write, cos_stream_equal
1205 };
1206
1207 cos_stream_t *
cos_stream_alloc(gx_device_pdf * pdev,client_name_t cname)1208 cos_stream_alloc(gx_device_pdf *pdev, client_name_t cname)
1209 {
1210 gs_memory_t *mem = pdev->pdf_memory;
1211 cos_stream_t *pcs =
1212 gs_alloc_struct(mem, cos_stream_t, &st_cos_object, cname);
1213
1214 cos_object_init((cos_object_t *)pcs, pdev, &cos_stream_procs);
1215 return pcs;
1216 }
1217
1218 static void
cos_stream_release(cos_object_t * pco,client_name_t cname)1219 cos_stream_release(cos_object_t *pco, client_name_t cname)
1220 {
1221 gs_memory_t *mem = cos_object_memory(pco);
1222 cos_stream_t *const pcs = (cos_stream_t *)pco;
1223 cos_stream_piece_t *cur;
1224 cos_stream_piece_t *next;
1225
1226 for (cur = pcs->pieces; cur; cur = next) {
1227 next = cur->next;
1228 gs_free_object(mem, cur, cname);
1229 }
1230 pcs->pieces = 0;
1231 cos_dict_release(pco, cname);
1232 }
1233
1234 static int
cos_stream_equal(const cos_object_t * pco0,const cos_object_t * pco1,gx_device_pdf * pdev)1235 cos_stream_equal(const cos_object_t *pco0, const cos_object_t *pco1, gx_device_pdf *pdev)
1236 {
1237 const cos_stream_t *pcs0 = (const cos_stream_t *)pco0;
1238 const cos_stream_t *pcs1 = (const cos_stream_t *)pco1;
1239 bool result = false;
1240 int code;
1241
1242 code = cos_dict_equal(pco0, pco1, pdev);
1243 if (code < 0)
1244 return code;
1245 if (!code)
1246 return false;
1247 {
1248 /* fixme : this assumes same segmentation for both streams.
1249 In general it is not true. */
1250 FILE *sfile = pdev->streams.file;
1251 cos_stream_piece_t *pcsp0 = pcs0->pieces, *pcsp1 = pcs1->pieces;
1252 long position_save = ftell(sfile);
1253
1254 for (; pcsp0 && pcsp1; pcsp0 = pcsp0->next, pcsp1 = pcsp1->next) {
1255 long position0 = pcsp0->position;
1256 long position1 = pcsp1->position;
1257 uint size0 = pcsp0->size;
1258 uint size1 = pcsp1->size;
1259 byte buf0[512], buf1[sizeof(buf0)];
1260
1261 if (size0 != size1)
1262 goto notequal;
1263 for(; size0; position0 += size1, position1 += size1, size0 -= size1) {
1264 size1 = min(sizeof(buf0), size0);
1265 fseek(sfile, position0, SEEK_SET);
1266 if (fread(buf0, 1, size1, sfile) != size1) {
1267 result = gs_note_error(gs_error_ioerror);
1268 goto notequal;
1269 }
1270 fseek(sfile, position1, SEEK_SET);
1271 if (fread(buf1, 1, size1, sfile) != size1) {
1272 result = gs_note_error(gs_error_ioerror);
1273 goto notequal;
1274 }
1275 if (memcmp(buf0, buf1, size1))
1276 goto notequal;
1277 }
1278 }
1279 if (pcsp0 || pcsp1)
1280 goto notequal;
1281 result = true;
1282 notequal:
1283 fseek(sfile, position_save, SEEK_SET);
1284 return result;
1285 }
1286 }
1287
1288 /* Find the total length of a stream. */
1289 long
cos_stream_length(const cos_stream_t * pcs)1290 cos_stream_length(const cos_stream_t *pcs)
1291 {
1292 return pcs->length;
1293 }
1294
1295 /* Write the (dictionary) elements of a stream. */
1296 /* (This procedure is exported.) */
1297 int
cos_stream_elements_write(const cos_stream_t * pcs,gx_device_pdf * pdev)1298 cos_stream_elements_write(const cos_stream_t *pcs, gx_device_pdf *pdev)
1299 {
1300 return cos_elements_write(pdev->strm, pcs->elements, pdev, true, pcs->id);
1301 }
1302
1303 /* Write the contents of a stream. (This procedure is exported.) */
1304 int
cos_stream_contents_write(const cos_stream_t * pcs,gx_device_pdf * pdev)1305 cos_stream_contents_write(const cos_stream_t *pcs, gx_device_pdf *pdev)
1306 {
1307 stream *s = pdev->strm;
1308 cos_stream_piece_t *pcsp;
1309 cos_stream_piece_t *last;
1310 cos_stream_piece_t *next;
1311 FILE *sfile = pdev->streams.file;
1312 long end_pos;
1313 bool same_file = (pdev->sbstack_depth > 0);
1314 int code;
1315 stream_arcfour_state sarc4, *ss = NULL;
1316
1317 if (pdev->KeyLength) {
1318 code = pdf_encrypt_init(pdev, pcs->id, &sarc4);
1319 if (code < 0)
1320 return code;
1321 ss = &sarc4;
1322 }
1323 sflush(s);
1324 sflush(pdev->streams.strm);
1325
1326 /* Reverse the elements temporarily. */
1327 for (pcsp = pcs->pieces, last = NULL; pcsp; pcsp = next)
1328 next = pcsp->next, pcsp->next = last, last = pcsp;
1329 for (pcsp = last, code = 0; pcsp && code >= 0; pcsp = pcsp->next) {
1330 if (same_file)
1331 pdf_copy_data_safe(s, sfile, pcsp->position, pcsp->size);
1332 else {
1333 end_pos = ftell(sfile);
1334 fseek(sfile, pcsp->position, SEEK_SET);
1335 pdf_copy_data(s, sfile, pcsp->size, ss);
1336 fseek(sfile, end_pos, SEEK_SET);
1337 }
1338 }
1339 /* Reverse the elements back. */
1340 for (pcsp = last, last = NULL; pcsp; pcsp = next)
1341 next = pcsp->next, pcsp->next = last, last = pcsp;
1342
1343 return code;
1344 }
1345
1346 static int
cos_stream_write(const cos_object_t * pco,gx_device_pdf * pdev,gs_id object_id)1347 cos_stream_write(const cos_object_t *pco, gx_device_pdf *pdev, gs_id object_id)
1348 {
1349 stream *s = pdev->strm;
1350 const cos_stream_t *const pcs = (const cos_stream_t *)pco;
1351 int code;
1352
1353 if (pcs->input_strm != NULL) {
1354 stream *s = pco->input_strm;
1355 int status = s_close_filters(&s, NULL);
1356
1357 if (status < 0)
1358 return_error(gs_error_ioerror);
1359 /* We have to break const here to clear the input_strm. */
1360 ((cos_object_t *)pco)->input_strm = 0;
1361 }
1362 stream_puts(s, "<<");
1363 cos_elements_write(s, pcs->elements, pdev, false, object_id);
1364 pprintld1(s, "/Length %ld>>stream\n", cos_stream_length(pcs));
1365 code = cos_stream_contents_write(pcs, pdev);
1366 stream_puts(s, "\nendstream\n");
1367
1368 return code;
1369 }
1370
1371 /* Return a stream's dictionary (just a cast). */
1372 cos_dict_t *
cos_stream_dict(cos_stream_t * pcs)1373 cos_stream_dict(cos_stream_t *pcs)
1374 {
1375 return (cos_dict_t *)pcs;
1376 }
1377
1378 /* Add a contents piece to a stream object: size bytes just written on */
1379 /* streams.strm. */
1380 int
cos_stream_add(cos_stream_t * pcs,uint size)1381 cos_stream_add(cos_stream_t *pcs, uint size)
1382 {
1383 gx_device_pdf *pdev = pcs->pdev;
1384 stream *s = pdev->streams.strm;
1385 long position = stell(s);
1386 cos_stream_piece_t *prev = pcs->pieces;
1387
1388 /* Check for consecutive writing -- just an optimization. */
1389 if (prev != 0 && prev->position + prev->size + size == position) {
1390 prev->size += size;
1391 } else {
1392 gs_memory_t *mem = pdev->pdf_memory;
1393 cos_stream_piece_t *pcsp =
1394 gs_alloc_struct(mem, cos_stream_piece_t, &st_cos_stream_piece,
1395 "cos_stream_add");
1396
1397 if (pcsp == 0)
1398 return_error(gs_error_VMerror);
1399 pcsp->position = position - size;
1400 pcsp->size = size;
1401 pcsp->next = pcs->pieces;
1402 pcs->pieces = pcsp;
1403 }
1404 pcs->length += size;
1405 return 0;
1406 }
1407
1408 /* Add bytes to a stream object. */
1409 int
cos_stream_add_bytes(cos_stream_t * pcs,const byte * data,uint size)1410 cos_stream_add_bytes(cos_stream_t *pcs, const byte *data, uint size)
1411 {
1412 stream_write(pcs->pdev->streams.strm, data, size);
1413 return cos_stream_add(pcs, size);
1414 }
1415
1416 /* Add the contents of a stream to a stream object. */
1417 int
cos_stream_add_stream_contents(cos_stream_t * pcs,stream * s)1418 cos_stream_add_stream_contents(cos_stream_t *pcs, stream *s)
1419 {
1420 int code = 0;
1421 byte sbuff[200]; /* arbitrary */
1422 uint cnt;
1423 int status = sseek(s, 0);
1424
1425 if (status < 0)
1426 return_error(gs_error_ioerror);
1427 do {
1428 status = sgets(s, sbuff, sizeof(sbuff), &cnt);
1429
1430 if (cnt == 0) {
1431 if (status == EOFC)
1432 break;
1433 return_error(gs_error_ioerror);
1434 }
1435 } while ((code = cos_stream_add_bytes(pcs, sbuff, cnt)) >= 0);
1436 return code;
1437 }
1438
1439 /* Release the last contents piece of a stream object. */
1440 /* Warning : this function can't release pieces if another stream is written after them. */
1441 int
cos_stream_release_pieces(cos_stream_t * pcs)1442 cos_stream_release_pieces(cos_stream_t *pcs)
1443 {
1444 gx_device_pdf *pdev = pcs->pdev;
1445 stream *s = pdev->streams.strm;
1446 long position = stell(s), position0 = position;
1447 gs_memory_t *mem = cos_object_memory((cos_object_t *)pcs);
1448
1449 while (pcs->pieces != NULL &&
1450 position == pcs->pieces->position + pcs->pieces->size) {
1451 cos_stream_piece_t *p = pcs->pieces;
1452
1453 position -= p->size;
1454 pcs->pieces = p->next;
1455 gs_free_object(mem, p, "cos_stream_release_pieces");
1456 }
1457 if (position0 != position)
1458 if (sseek(s, position) < 0)
1459 return_error(gs_error_ioerror);
1460 return 0;
1461 }
1462
1463 /* Create a stream that writes into a Cos stream. */
1464 /* Closing the stream will free it. */
1465 /* Note that this is not a filter. */
1466 typedef struct cos_write_stream_state_s {
1467 stream_state_common;
1468 cos_stream_t *pcs;
1469 gx_device_pdf *pdev;
1470 stream *s; /* pointer back to stream */
1471 stream *target; /* use this instead of strm */
1472 } cos_write_stream_state_t;
1473 gs_private_st_suffix_add4(st_cos_write_stream_state, cos_write_stream_state_t,
1474 "cos_write_stream_state_t",
1475 cos_ws_state_enum_ptrs, cos_ws_state_reloc_ptrs,
1476 st_stream_state, pcs, pdev, s, target);
1477
1478 static int
cos_write_stream_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * ignore_pw,bool last)1479 cos_write_stream_process(stream_state * st, stream_cursor_read * pr,
1480 stream_cursor_write * ignore_pw, bool last)
1481 {
1482 uint count = pr->limit - pr->ptr;
1483 cos_write_stream_state_t *ss = (cos_write_stream_state_t *)st;
1484 gx_device_pdf *pdev = ss->pdev;
1485 stream *target = ss->target;
1486 long start_pos = stell(pdev->streams.strm);
1487 int code;
1488
1489 stream_write(target, pr->ptr + 1, count);
1490 pr->ptr = pr->limit;
1491 sflush(target);
1492 code = cos_stream_add(ss->pcs, (uint)(stell(pdev->streams.strm) - start_pos));
1493 return (code < 0 ? ERRC : 0);
1494 }
1495 static int
cos_write_stream_close(stream * s)1496 cos_write_stream_close(stream *s)
1497 {
1498 cos_write_stream_state_t *ss = (cos_write_stream_state_t *)s->state;
1499 int status;
1500
1501 sflush(s);
1502 status = s_close_filters(&ss->target, ss->pdev->streams.strm);
1503 return (status < 0 ? status : s_std_close(s));
1504 }
1505
1506 static const stream_procs cos_s_procs = {
1507 s_std_noavailable, s_std_noseek, s_std_write_reset,
1508 s_std_write_flush, cos_write_stream_close, cos_write_stream_process
1509 };
1510 static const stream_template cos_write_stream_template = {
1511 &st_cos_write_stream_state, 0, cos_write_stream_process, 1, 1
1512 };
1513 stream *
cos_write_stream_alloc(cos_stream_t * pcs,gx_device_pdf * pdev,client_name_t cname)1514 cos_write_stream_alloc(cos_stream_t *pcs, gx_device_pdf *pdev,
1515 client_name_t cname)
1516 {
1517 gs_memory_t *mem = pdev->pdf_memory;
1518 stream *s = s_alloc(mem, cname);
1519 cos_write_stream_state_t *ss = (cos_write_stream_state_t *)
1520 s_alloc_state(mem, &st_cos_write_stream_state, cname);
1521 #define CWS_BUF_SIZE 512 /* arbitrary */
1522 byte *buf = gs_alloc_bytes(mem, CWS_BUF_SIZE, cname);
1523
1524 if (s == 0 || ss == 0 || buf == 0)
1525 goto fail;
1526 ss->template = &cos_write_stream_template;
1527 ss->pcs = pcs;
1528 ss->pdev = pdev;
1529 ss->s = s;
1530 ss->target = pdev->streams.strm; /* not s->strm */
1531 s_std_init(s, buf, CWS_BUF_SIZE, &cos_s_procs, s_mode_write);
1532 s->state = (stream_state *)ss;
1533 return s;
1534 #undef CWS_BUF_SIZE
1535 fail:
1536 gs_free_object(mem, buf, cname);
1537 gs_free_object(mem, ss, cname);
1538 gs_free_object(mem, s, cname);
1539 return 0;
1540 }
1541
1542 /* Get cos stream from pipeline. */
1543 cos_stream_t *
cos_stream_from_pipeline(stream * s)1544 cos_stream_from_pipeline(stream *s)
1545 {
1546 cos_write_stream_state_t *ss;
1547
1548 while(s->procs.process != cos_s_procs.process)
1549 s = s->strm;
1550 ss = (cos_write_stream_state_t *)s->state;
1551 return ss->pcs;
1552 }
1553
1554 /* Get cos write stream from pipeline. */
1555 stream *
cos_write_stream_from_pipeline(stream * s)1556 cos_write_stream_from_pipeline(stream *s)
1557 {
1558 while(s->procs.process != cos_s_procs.process)
1559 s = s->strm;
1560 return s;
1561 }
1562
1563