1 /* cairo-output-stream.c: Output stream abstraction
2 *
3 * Copyright © 2005 Red Hat, Inc
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
12 *
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
18 *
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
23 *
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
27 *
28 * The Original Code is the cairo graphics library.
29 *
30 * The Initial Developer of the Original Code is Red Hat, Inc.
31 *
32 * Author(s):
33 * Kristian Høgsberg <krh@redhat.com>
34 */
35
36 #define _BSD_SOURCE /* for snprintf() */
37 #include "cairoint.h"
38
39 #include "cairo-output-stream-private.h"
40 #include "cairo-error-private.h"
41 #include "cairo-compiler-private.h"
42
43 #include <stdio.h>
44 #include <locale.h>
45 #include <errno.h>
46
47 /* Numbers printed with %f are printed with this number of significant
48 * digits after the decimal.
49 */
50 #define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
51
52 /* Numbers printed with %g are assumed to only have %CAIRO_FIXED_FRAC_BITS
53 * bits of precision available after the decimal point.
54 *
55 * FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal
56 * digits after the decimal point required to preserve the available
57 * precision.
58 *
59 * The conversion is:
60 *
61 * <programlisting>
62 * FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) )
63 * </programlisting>
64 *
65 * We can replace ceil(x) with (int)(x+1) since x will never be an
66 * integer for any likely value of %CAIRO_FIXED_FRAC_BITS.
67 */
68 #define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1))
69
70 void
_cairo_output_stream_init(cairo_output_stream_t * stream,cairo_output_stream_write_func_t write_func,cairo_output_stream_flush_func_t flush_func,cairo_output_stream_close_func_t close_func)71 _cairo_output_stream_init (cairo_output_stream_t *stream,
72 cairo_output_stream_write_func_t write_func,
73 cairo_output_stream_flush_func_t flush_func,
74 cairo_output_stream_close_func_t close_func)
75 {
76 stream->write_func = write_func;
77 stream->flush_func = flush_func;
78 stream->close_func = close_func;
79 stream->position = 0;
80 stream->status = CAIRO_STATUS_SUCCESS;
81 stream->closed = FALSE;
82 }
83
84 cairo_status_t
_cairo_output_stream_fini(cairo_output_stream_t * stream)85 _cairo_output_stream_fini (cairo_output_stream_t *stream)
86 {
87 return _cairo_output_stream_close (stream);
88 }
89
90 const cairo_output_stream_t _cairo_output_stream_nil = {
91 NULL, /* write_func */
92 NULL, /* flush_func */
93 NULL, /* close_func */
94 0, /* position */
95 CAIRO_STATUS_NO_MEMORY,
96 FALSE /* closed */
97 };
98
99 static const cairo_output_stream_t _cairo_output_stream_nil_write_error = {
100 NULL, /* write_func */
101 NULL, /* flush_func */
102 NULL, /* close_func */
103 0, /* position */
104 CAIRO_STATUS_WRITE_ERROR,
105 FALSE /* closed */
106 };
107
108 typedef struct _cairo_output_stream_with_closure {
109 cairo_output_stream_t base;
110 cairo_write_func_t write_func;
111 cairo_close_func_t close_func;
112 void *closure;
113 } cairo_output_stream_with_closure_t;
114
115
116 static cairo_status_t
closure_write(cairo_output_stream_t * stream,const unsigned char * data,unsigned int length)117 closure_write (cairo_output_stream_t *stream,
118 const unsigned char *data, unsigned int length)
119 {
120 cairo_output_stream_with_closure_t *stream_with_closure =
121 (cairo_output_stream_with_closure_t *) stream;
122
123 if (stream_with_closure->write_func == NULL)
124 return CAIRO_STATUS_SUCCESS;
125
126 return stream_with_closure->write_func (stream_with_closure->closure,
127 data, length);
128 }
129
130 static cairo_status_t
closure_close(cairo_output_stream_t * stream)131 closure_close (cairo_output_stream_t *stream)
132 {
133 cairo_output_stream_with_closure_t *stream_with_closure =
134 (cairo_output_stream_with_closure_t *) stream;
135
136 if (stream_with_closure->close_func != NULL)
137 return stream_with_closure->close_func (stream_with_closure->closure);
138 else
139 return CAIRO_STATUS_SUCCESS;
140 }
141
142 cairo_output_stream_t *
_cairo_output_stream_create(cairo_write_func_t write_func,cairo_close_func_t close_func,void * closure)143 _cairo_output_stream_create (cairo_write_func_t write_func,
144 cairo_close_func_t close_func,
145 void *closure)
146 {
147 cairo_output_stream_with_closure_t *stream;
148
149 stream = malloc (sizeof (cairo_output_stream_with_closure_t));
150 if (unlikely (stream == NULL)) {
151 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
152 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
153 }
154
155 _cairo_output_stream_init (&stream->base,
156 closure_write, NULL, closure_close);
157 stream->write_func = write_func;
158 stream->close_func = close_func;
159 stream->closure = closure;
160
161 return &stream->base;
162 }
163
164 cairo_output_stream_t *
_cairo_output_stream_create_in_error(cairo_status_t status)165 _cairo_output_stream_create_in_error (cairo_status_t status)
166 {
167 cairo_output_stream_t *stream;
168
169 /* check for the common ones */
170 if (status == CAIRO_STATUS_NO_MEMORY)
171 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
172 if (status == CAIRO_STATUS_WRITE_ERROR)
173 return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
174
175 stream = malloc (sizeof (cairo_output_stream_t));
176 if (unlikely (stream == NULL)) {
177 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
178 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
179 }
180
181 _cairo_output_stream_init (stream, NULL, NULL, NULL);
182 stream->status = status;
183
184 return stream;
185 }
186
187 cairo_status_t
_cairo_output_stream_flush(cairo_output_stream_t * stream)188 _cairo_output_stream_flush (cairo_output_stream_t *stream)
189 {
190 cairo_status_t status;
191
192 if (stream->closed)
193 return stream->status;
194
195 if (stream == &_cairo_output_stream_nil ||
196 stream == &_cairo_output_stream_nil_write_error)
197 {
198 return stream->status;
199 }
200
201 if (stream->flush_func) {
202 status = stream->flush_func (stream);
203 /* Don't overwrite a pre-existing status failure. */
204 if (stream->status == CAIRO_STATUS_SUCCESS)
205 stream->status = status;
206 }
207
208 return stream->status;
209 }
210
211 cairo_status_t
_cairo_output_stream_close(cairo_output_stream_t * stream)212 _cairo_output_stream_close (cairo_output_stream_t *stream)
213 {
214 cairo_status_t status;
215
216 if (stream->closed)
217 return stream->status;
218
219 if (stream == &_cairo_output_stream_nil ||
220 stream == &_cairo_output_stream_nil_write_error)
221 {
222 return stream->status;
223 }
224
225 if (stream->close_func) {
226 status = stream->close_func (stream);
227 /* Don't overwrite a pre-existing status failure. */
228 if (stream->status == CAIRO_STATUS_SUCCESS)
229 stream->status = status;
230 }
231
232 stream->closed = TRUE;
233
234 return stream->status;
235 }
236
237 cairo_status_t
_cairo_output_stream_destroy(cairo_output_stream_t * stream)238 _cairo_output_stream_destroy (cairo_output_stream_t *stream)
239 {
240 cairo_status_t status;
241
242 assert (stream != NULL);
243
244 if (stream == &_cairo_output_stream_nil ||
245 stream == &_cairo_output_stream_nil_write_error)
246 {
247 return stream->status;
248 }
249
250 status = _cairo_output_stream_fini (stream);
251 free (stream);
252
253 return status;
254 }
255
256 void
_cairo_output_stream_write(cairo_output_stream_t * stream,const void * data,size_t length)257 _cairo_output_stream_write (cairo_output_stream_t *stream,
258 const void *data, size_t length)
259 {
260 if (length == 0)
261 return;
262
263 if (stream->status)
264 return;
265
266 stream->status = stream->write_func (stream, data, length);
267 stream->position += length;
268 }
269
270 void
_cairo_output_stream_write_hex_string(cairo_output_stream_t * stream,const unsigned char * data,size_t length)271 _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
272 const unsigned char *data,
273 size_t length)
274 {
275 const char hex_chars[] = "0123456789abcdef";
276 char buffer[2];
277 unsigned int i, column;
278
279 if (stream->status)
280 return;
281
282 for (i = 0, column = 0; i < length; i++, column++) {
283 if (column == 38) {
284 _cairo_output_stream_write (stream, "\n", 1);
285 column = 0;
286 }
287 buffer[0] = hex_chars[(data[i] >> 4) & 0x0f];
288 buffer[1] = hex_chars[data[i] & 0x0f];
289 _cairo_output_stream_write (stream, buffer, 2);
290 }
291 }
292
293 /* Format a double in a locale independent way and trim trailing
294 * zeros. Based on code from Alex Larson <alexl@redhat.com>.
295 * http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
296 *
297 * The code in the patch is copyright Red Hat, Inc under the LGPL, but
298 * has been relicensed under the LGPL/MPL dual license for inclusion
299 * into cairo (see COPYING). -- Kristian Høgsberg <krh@redhat.com>
300 */
301 static void
_cairo_dtostr(char * buffer,size_t size,double d,cairo_bool_t limited_precision)302 _cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precision)
303 {
304 struct lconv *locale_data;
305 const char *decimal_point;
306 int decimal_point_len;
307 char *p;
308 int decimal_len;
309 int num_zeros, decimal_digits;
310
311 /* Omit the minus sign from negative zero. */
312 if (d == 0.0)
313 d = 0.0;
314
315 #ifdef HAVE_LOCALECONV
316 locale_data = localeconv ();
317 decimal_point = locale_data->decimal_point;
318 decimal_point_len = strlen (decimal_point);
319 #else
320 decimal_point = ".";
321 decimal_point_len = 1;
322 #endif
323
324 assert (decimal_point_len != 0);
325
326 if (limited_precision) {
327 snprintf (buffer, size, "%.*f", FIXED_POINT_DECIMAL_DIGITS, d);
328 } else {
329 /* Using "%f" to print numbers less than 0.1 will result in
330 * reduced precision due to the default 6 digits after the
331 * decimal point.
332 *
333 * For numbers is < 0.1, we print with maximum precision and count
334 * the number of zeros between the decimal point and the first
335 * significant digit. We then print the number again with the
336 * number of decimal places that gives us the required number of
337 * significant digits. This ensures the number is correctly
338 * rounded.
339 */
340 if (fabs (d) >= 0.1) {
341 snprintf (buffer, size, "%f", d);
342 } else {
343 snprintf (buffer, size, "%.18f", d);
344 p = buffer;
345
346 if (*p == '+' || *p == '-')
347 p++;
348
349 while (_cairo_isdigit (*p))
350 p++;
351
352 if (strncmp (p, decimal_point, decimal_point_len) == 0)
353 p += decimal_point_len;
354
355 num_zeros = 0;
356 while (*p++ == '0')
357 num_zeros++;
358
359 decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL;
360
361 if (decimal_digits < 18)
362 snprintf (buffer, size, "%.*f", decimal_digits, d);
363 }
364 }
365 p = buffer;
366
367 if (*p == '+' || *p == '-')
368 p++;
369
370 while (_cairo_isdigit (*p))
371 p++;
372
373 if (strncmp (p, decimal_point, decimal_point_len) == 0) {
374 *p = '.';
375 decimal_len = strlen (p + decimal_point_len);
376 memmove (p + 1, p + decimal_point_len, decimal_len);
377 p[1 + decimal_len] = 0;
378
379 /* Remove trailing zeros and decimal point if possible. */
380 for (p = p + decimal_len; *p == '0'; p--)
381 *p = 0;
382
383 if (*p == '.') {
384 *p = 0;
385 p--;
386 }
387 }
388 }
389
390 enum {
391 LENGTH_MODIFIER_LONG = 0x100
392 };
393
394 /* Here's a limited reimplementation of printf. The reason for doing
395 * this is primarily to special case handling of doubles. We want
396 * locale independent formatting of doubles and we want to trim
397 * trailing zeros. This is handled by dtostr() above, and the code
398 * below handles everything else by calling snprintf() to do the
399 * formatting. This functionality is only for internal use and we
400 * only implement the formats we actually use.
401 */
402 void
_cairo_output_stream_vprintf(cairo_output_stream_t * stream,const char * fmt,va_list ap)403 _cairo_output_stream_vprintf (cairo_output_stream_t *stream,
404 const char *fmt, va_list ap)
405 {
406 #define SINGLE_FMT_BUFFER_SIZE 32
407 char buffer[512], single_fmt[SINGLE_FMT_BUFFER_SIZE];
408 int single_fmt_length;
409 char *p;
410 const char *f, *start;
411 int length_modifier, width;
412 cairo_bool_t var_width;
413
414 if (stream->status)
415 return;
416
417 f = fmt;
418 p = buffer;
419 while (*f != '\0') {
420 if (p == buffer + sizeof (buffer)) {
421 _cairo_output_stream_write (stream, buffer, sizeof (buffer));
422 p = buffer;
423 }
424
425 if (*f != '%') {
426 *p++ = *f++;
427 continue;
428 }
429
430 start = f;
431 f++;
432
433 if (*f == '0')
434 f++;
435
436 var_width = FALSE;
437 if (*f == '*') {
438 var_width = TRUE;
439 f++;
440 }
441
442 while (_cairo_isdigit (*f))
443 f++;
444
445 length_modifier = 0;
446 if (*f == 'l') {
447 length_modifier = LENGTH_MODIFIER_LONG;
448 f++;
449 }
450
451 /* The only format strings exist in the cairo implementation
452 * itself. So there's an internal consistency problem if any
453 * of them is larger than our format buffer size. */
454 single_fmt_length = f - start + 1;
455 assert (single_fmt_length + 1 <= SINGLE_FMT_BUFFER_SIZE);
456
457 /* Reuse the format string for this conversion. */
458 memcpy (single_fmt, start, single_fmt_length);
459 single_fmt[single_fmt_length] = '\0';
460
461 /* Flush contents of buffer before snprintf()'ing into it. */
462 _cairo_output_stream_write (stream, buffer, p - buffer);
463
464 /* We group signed and unsigned together in this switch, the
465 * only thing that matters here is the size of the arguments,
466 * since we're just passing the data through to sprintf(). */
467 switch (*f | length_modifier) {
468 case '%':
469 buffer[0] = *f;
470 buffer[1] = 0;
471 break;
472 case 'd':
473 case 'u':
474 case 'o':
475 case 'x':
476 case 'X':
477 if (var_width) {
478 width = va_arg (ap, int);
479 snprintf (buffer, sizeof buffer,
480 single_fmt, width, va_arg (ap, int));
481 } else {
482 snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int));
483 }
484 break;
485 case 'd' | LENGTH_MODIFIER_LONG:
486 case 'u' | LENGTH_MODIFIER_LONG:
487 case 'o' | LENGTH_MODIFIER_LONG:
488 case 'x' | LENGTH_MODIFIER_LONG:
489 case 'X' | LENGTH_MODIFIER_LONG:
490 if (var_width) {
491 width = va_arg (ap, int);
492 snprintf (buffer, sizeof buffer,
493 single_fmt, width, va_arg (ap, long int));
494 } else {
495 snprintf (buffer, sizeof buffer,
496 single_fmt, va_arg (ap, long int));
497 }
498 break;
499 case 's':
500 snprintf (buffer, sizeof buffer,
501 single_fmt, va_arg (ap, const char *));
502 break;
503 case 'f':
504 _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), FALSE);
505 break;
506 case 'g':
507 _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), TRUE);
508 break;
509 case 'c':
510 buffer[0] = va_arg (ap, int);
511 buffer[1] = 0;
512 break;
513 default:
514 ASSERT_NOT_REACHED;
515 }
516 p = buffer + strlen (buffer);
517 f++;
518 }
519
520 _cairo_output_stream_write (stream, buffer, p - buffer);
521 }
522
523 void
_cairo_output_stream_printf(cairo_output_stream_t * stream,const char * fmt,...)524 _cairo_output_stream_printf (cairo_output_stream_t *stream,
525 const char *fmt, ...)
526 {
527 va_list ap;
528
529 va_start (ap, fmt);
530
531 _cairo_output_stream_vprintf (stream, fmt, ap);
532
533 va_end (ap);
534 }
535
536 long
_cairo_output_stream_get_position(cairo_output_stream_t * stream)537 _cairo_output_stream_get_position (cairo_output_stream_t *stream)
538 {
539 return stream->position;
540 }
541
542 cairo_status_t
_cairo_output_stream_get_status(cairo_output_stream_t * stream)543 _cairo_output_stream_get_status (cairo_output_stream_t *stream)
544 {
545 return stream->status;
546 }
547
548 /* Maybe this should be a configure time option, so embedded targets
549 * don't have to pull in stdio. */
550
551
552 typedef struct _stdio_stream {
553 cairo_output_stream_t base;
554 FILE *file;
555 } stdio_stream_t;
556
557 static cairo_status_t
stdio_write(cairo_output_stream_t * base,const unsigned char * data,unsigned int length)558 stdio_write (cairo_output_stream_t *base,
559 const unsigned char *data, unsigned int length)
560 {
561 stdio_stream_t *stream = (stdio_stream_t *) base;
562
563 if (fwrite (data, 1, length, stream->file) != length)
564 return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
565
566 return CAIRO_STATUS_SUCCESS;
567 }
568
569 static cairo_status_t
stdio_flush(cairo_output_stream_t * base)570 stdio_flush (cairo_output_stream_t *base)
571 {
572 stdio_stream_t *stream = (stdio_stream_t *) base;
573
574 fflush (stream->file);
575
576 if (ferror (stream->file))
577 return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
578 else
579 return CAIRO_STATUS_SUCCESS;
580 }
581
582 static cairo_status_t
stdio_close(cairo_output_stream_t * base)583 stdio_close (cairo_output_stream_t *base)
584 {
585 cairo_status_t status;
586 stdio_stream_t *stream = (stdio_stream_t *) base;
587
588 status = stdio_flush (base);
589
590 fclose (stream->file);
591
592 return status;
593 }
594
595 cairo_output_stream_t *
_cairo_output_stream_create_for_file(FILE * file)596 _cairo_output_stream_create_for_file (FILE *file)
597 {
598 stdio_stream_t *stream;
599
600 if (file == NULL) {
601 _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
602 return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
603 }
604
605 stream = malloc (sizeof *stream);
606 if (unlikely (stream == NULL)) {
607 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
608 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
609 }
610
611 _cairo_output_stream_init (&stream->base,
612 stdio_write, stdio_flush, stdio_flush);
613 stream->file = file;
614
615 return &stream->base;
616 }
617
618 cairo_output_stream_t *
_cairo_output_stream_create_for_filename(const char * filename)619 _cairo_output_stream_create_for_filename (const char *filename)
620 {
621 stdio_stream_t *stream;
622 FILE *file;
623
624 if (filename == NULL)
625 return _cairo_null_stream_create ();
626
627 file = fopen (filename, "wb");
628 if (file == NULL) {
629 switch (errno) {
630 case ENOMEM:
631 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
632 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
633 default:
634 _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
635 return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
636 }
637 }
638
639 stream = malloc (sizeof *stream);
640 if (unlikely (stream == NULL)) {
641 fclose (file);
642 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
643 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
644 }
645
646 _cairo_output_stream_init (&stream->base,
647 stdio_write, stdio_flush, stdio_close);
648 stream->file = file;
649
650 return &stream->base;
651 }
652
653
654 typedef struct _memory_stream {
655 cairo_output_stream_t base;
656 cairo_array_t array;
657 } memory_stream_t;
658
659 static cairo_status_t
memory_write(cairo_output_stream_t * base,const unsigned char * data,unsigned int length)660 memory_write (cairo_output_stream_t *base,
661 const unsigned char *data, unsigned int length)
662 {
663 memory_stream_t *stream = (memory_stream_t *) base;
664
665 return _cairo_array_append_multiple (&stream->array, data, length);
666 }
667
668 static cairo_status_t
memory_close(cairo_output_stream_t * base)669 memory_close (cairo_output_stream_t *base)
670 {
671 memory_stream_t *stream = (memory_stream_t *) base;
672
673 _cairo_array_fini (&stream->array);
674
675 return CAIRO_STATUS_SUCCESS;
676 }
677
678 cairo_output_stream_t *
_cairo_memory_stream_create(void)679 _cairo_memory_stream_create (void)
680 {
681 memory_stream_t *stream;
682
683 stream = malloc (sizeof *stream);
684 if (unlikely (stream == NULL)) {
685 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
686 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
687 }
688
689 _cairo_output_stream_init (&stream->base, memory_write, NULL, memory_close);
690 _cairo_array_init (&stream->array, 1);
691
692 return &stream->base;
693 }
694
695 cairo_status_t
_cairo_memory_stream_destroy(cairo_output_stream_t * abstract_stream,unsigned char ** data_out,unsigned long * length_out)696 _cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
697 unsigned char **data_out,
698 unsigned long *length_out)
699 {
700 memory_stream_t *stream;
701 cairo_status_t status;
702
703 status = abstract_stream->status;
704 if (unlikely (status))
705 return _cairo_output_stream_destroy (abstract_stream);
706
707 stream = (memory_stream_t *) abstract_stream;
708
709 *length_out = _cairo_array_num_elements (&stream->array);
710 *data_out = malloc (*length_out);
711 if (unlikely (*data_out == NULL)) {
712 status = _cairo_output_stream_destroy (abstract_stream);
713 assert (status == CAIRO_STATUS_SUCCESS);
714 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
715 }
716 memcpy (*data_out, _cairo_array_index (&stream->array, 0), *length_out);
717
718 return _cairo_output_stream_destroy (abstract_stream);
719 }
720
721 void
_cairo_memory_stream_copy(cairo_output_stream_t * base,cairo_output_stream_t * dest)722 _cairo_memory_stream_copy (cairo_output_stream_t *base,
723 cairo_output_stream_t *dest)
724 {
725 memory_stream_t *stream = (memory_stream_t *) base;
726
727 if (dest->status)
728 return;
729
730 if (base->status) {
731 dest->status = base->status;
732 return;
733 }
734
735 _cairo_output_stream_write (dest,
736 _cairo_array_index (&stream->array, 0),
737 _cairo_array_num_elements (&stream->array));
738 }
739
740 int
_cairo_memory_stream_length(cairo_output_stream_t * base)741 _cairo_memory_stream_length (cairo_output_stream_t *base)
742 {
743 memory_stream_t *stream = (memory_stream_t *) base;
744
745 return _cairo_array_num_elements (&stream->array);
746 }
747
748 static cairo_status_t
null_write(cairo_output_stream_t * base,const unsigned char * data,unsigned int length)749 null_write (cairo_output_stream_t *base,
750 const unsigned char *data, unsigned int length)
751 {
752 return CAIRO_STATUS_SUCCESS;
753 }
754
755 cairo_output_stream_t *
_cairo_null_stream_create(void)756 _cairo_null_stream_create (void)
757 {
758 cairo_output_stream_t *stream;
759
760 stream = malloc (sizeof *stream);
761 if (unlikely (stream == NULL)) {
762 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
763 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
764 }
765
766 _cairo_output_stream_init (stream, null_write, NULL, NULL);
767
768 return stream;
769 }
770