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