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