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