Line data Source code
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
71 0 : _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 0 : stream->write_func = write_func;
77 0 : stream->flush_func = flush_func;
78 0 : stream->close_func = close_func;
79 0 : stream->position = 0;
80 0 : stream->status = CAIRO_STATUS_SUCCESS;
81 0 : stream->closed = FALSE;
82 0 : }
83 :
84 : cairo_status_t
85 0 : _cairo_output_stream_fini (cairo_output_stream_t *stream)
86 : {
87 0 : 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
117 0 : closure_write (cairo_output_stream_t *stream,
118 : const unsigned char *data, unsigned int length)
119 : {
120 0 : cairo_output_stream_with_closure_t *stream_with_closure =
121 : (cairo_output_stream_with_closure_t *) stream;
122 :
123 0 : if (stream_with_closure->write_func == NULL)
124 0 : return CAIRO_STATUS_SUCCESS;
125 :
126 0 : return stream_with_closure->write_func (stream_with_closure->closure,
127 : data, length);
128 : }
129 :
130 : static cairo_status_t
131 0 : closure_close (cairo_output_stream_t *stream)
132 : {
133 0 : cairo_output_stream_with_closure_t *stream_with_closure =
134 : (cairo_output_stream_with_closure_t *) stream;
135 :
136 0 : if (stream_with_closure->close_func != NULL)
137 0 : return stream_with_closure->close_func (stream_with_closure->closure);
138 : else
139 0 : return CAIRO_STATUS_SUCCESS;
140 : }
141 :
142 : cairo_output_stream_t *
143 0 : _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 0 : stream = malloc (sizeof (cairo_output_stream_with_closure_t));
150 0 : if (unlikely (stream == NULL)) {
151 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
152 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil;
153 : }
154 :
155 0 : _cairo_output_stream_init (&stream->base,
156 : closure_write, NULL, closure_close);
157 0 : stream->write_func = write_func;
158 0 : stream->close_func = close_func;
159 0 : stream->closure = closure;
160 :
161 0 : return &stream->base;
162 : }
163 :
164 : cairo_output_stream_t *
165 0 : _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 0 : if (status == CAIRO_STATUS_NO_MEMORY)
171 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil;
172 0 : if (status == CAIRO_STATUS_WRITE_ERROR)
173 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
174 :
175 0 : stream = malloc (sizeof (cairo_output_stream_t));
176 0 : if (unlikely (stream == NULL)) {
177 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
178 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil;
179 : }
180 :
181 0 : _cairo_output_stream_init (stream, NULL, NULL, NULL);
182 0 : stream->status = status;
183 :
184 0 : return stream;
185 : }
186 :
187 : cairo_status_t
188 0 : _cairo_output_stream_flush (cairo_output_stream_t *stream)
189 : {
190 : cairo_status_t status;
191 :
192 0 : if (stream->closed)
193 0 : return stream->status;
194 :
195 0 : if (stream == &_cairo_output_stream_nil ||
196 : stream == &_cairo_output_stream_nil_write_error)
197 : {
198 0 : return stream->status;
199 : }
200 :
201 0 : if (stream->flush_func) {
202 0 : status = stream->flush_func (stream);
203 : /* Don't overwrite a pre-existing status failure. */
204 0 : if (stream->status == CAIRO_STATUS_SUCCESS)
205 0 : stream->status = status;
206 : }
207 :
208 0 : return stream->status;
209 : }
210 :
211 : cairo_status_t
212 0 : _cairo_output_stream_close (cairo_output_stream_t *stream)
213 : {
214 : cairo_status_t status;
215 :
216 0 : if (stream->closed)
217 0 : return stream->status;
218 :
219 0 : if (stream == &_cairo_output_stream_nil ||
220 : stream == &_cairo_output_stream_nil_write_error)
221 : {
222 0 : return stream->status;
223 : }
224 :
225 0 : if (stream->close_func) {
226 0 : status = stream->close_func (stream);
227 : /* Don't overwrite a pre-existing status failure. */
228 0 : if (stream->status == CAIRO_STATUS_SUCCESS)
229 0 : stream->status = status;
230 : }
231 :
232 0 : stream->closed = TRUE;
233 :
234 0 : return stream->status;
235 : }
236 :
237 : cairo_status_t
238 0 : _cairo_output_stream_destroy (cairo_output_stream_t *stream)
239 : {
240 : cairo_status_t status;
241 :
242 0 : assert (stream != NULL);
243 :
244 0 : if (stream == &_cairo_output_stream_nil ||
245 : stream == &_cairo_output_stream_nil_write_error)
246 : {
247 0 : return stream->status;
248 : }
249 :
250 0 : status = _cairo_output_stream_fini (stream);
251 0 : free (stream);
252 :
253 0 : return status;
254 : }
255 :
256 : void
257 0 : _cairo_output_stream_write (cairo_output_stream_t *stream,
258 : const void *data, size_t length)
259 : {
260 0 : if (length == 0)
261 0 : return;
262 :
263 0 : if (stream->status)
264 0 : return;
265 :
266 0 : stream->status = stream->write_func (stream, data, length);
267 0 : stream->position += length;
268 : }
269 :
270 : void
271 0 : _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
272 : const unsigned char *data,
273 : size_t length)
274 : {
275 0 : const char hex_chars[] = "0123456789abcdef";
276 : char buffer[2];
277 : unsigned int i, column;
278 :
279 0 : if (stream->status)
280 0 : return;
281 :
282 0 : for (i = 0, column = 0; i < length; i++, column++) {
283 0 : if (column == 38) {
284 0 : _cairo_output_stream_write (stream, "\n", 1);
285 0 : column = 0;
286 : }
287 0 : buffer[0] = hex_chars[(data[i] >> 4) & 0x0f];
288 0 : buffer[1] = hex_chars[data[i] & 0x0f];
289 0 : _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
302 0 : _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 0 : if (d == 0.0)
313 0 : d = 0.0;
314 :
315 : #ifdef HAVE_LOCALECONV
316 0 : locale_data = localeconv ();
317 0 : decimal_point = locale_data->decimal_point;
318 0 : decimal_point_len = strlen (decimal_point);
319 : #else
320 : decimal_point = ".";
321 : decimal_point_len = 1;
322 : #endif
323 :
324 0 : assert (decimal_point_len != 0);
325 :
326 0 : if (limited_precision) {
327 0 : 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 0 : if (fabs (d) >= 0.1) {
341 0 : snprintf (buffer, size, "%f", d);
342 : } else {
343 0 : snprintf (buffer, size, "%.18f", d);
344 0 : p = buffer;
345 :
346 0 : if (*p == '+' || *p == '-')
347 0 : p++;
348 :
349 0 : while (_cairo_isdigit (*p))
350 0 : p++;
351 :
352 0 : if (strncmp (p, decimal_point, decimal_point_len) == 0)
353 0 : p += decimal_point_len;
354 :
355 0 : num_zeros = 0;
356 0 : while (*p++ == '0')
357 0 : num_zeros++;
358 :
359 0 : decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL;
360 :
361 0 : if (decimal_digits < 18)
362 0 : snprintf (buffer, size, "%.*f", decimal_digits, d);
363 : }
364 : }
365 0 : p = buffer;
366 :
367 0 : if (*p == '+' || *p == '-')
368 0 : p++;
369 :
370 0 : while (_cairo_isdigit (*p))
371 0 : p++;
372 :
373 0 : if (strncmp (p, decimal_point, decimal_point_len) == 0) {
374 0 : *p = '.';
375 0 : decimal_len = strlen (p + decimal_point_len);
376 0 : memmove (p + 1, p + decimal_point_len, decimal_len);
377 0 : p[1 + decimal_len] = 0;
378 :
379 : /* Remove trailing zeros and decimal point if possible. */
380 0 : for (p = p + decimal_len; *p == '0'; p--)
381 0 : *p = 0;
382 :
383 0 : if (*p == '.') {
384 0 : *p = 0;
385 0 : p--;
386 : }
387 : }
388 0 : }
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
403 0 : _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 0 : if (stream->status)
415 0 : return;
416 :
417 0 : f = fmt;
418 0 : p = buffer;
419 0 : while (*f != '\0') {
420 0 : if (p == buffer + sizeof (buffer)) {
421 0 : _cairo_output_stream_write (stream, buffer, sizeof (buffer));
422 0 : p = buffer;
423 : }
424 :
425 0 : if (*f != '%') {
426 0 : *p++ = *f++;
427 0 : continue;
428 : }
429 :
430 0 : start = f;
431 0 : f++;
432 :
433 0 : if (*f == '0')
434 0 : f++;
435 :
436 0 : var_width = FALSE;
437 0 : if (*f == '*') {
438 0 : var_width = TRUE;
439 0 : f++;
440 : }
441 :
442 0 : while (_cairo_isdigit (*f))
443 0 : f++;
444 :
445 0 : length_modifier = 0;
446 0 : if (*f == 'l') {
447 0 : length_modifier = LENGTH_MODIFIER_LONG;
448 0 : 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 0 : single_fmt_length = f - start + 1;
455 0 : assert (single_fmt_length + 1 <= SINGLE_FMT_BUFFER_SIZE);
456 :
457 : /* Reuse the format string for this conversion. */
458 0 : memcpy (single_fmt, start, single_fmt_length);
459 0 : single_fmt[single_fmt_length] = '\0';
460 :
461 : /* Flush contents of buffer before snprintf()'ing into it. */
462 0 : _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 0 : switch (*f | length_modifier) {
468 : case '%':
469 0 : buffer[0] = *f;
470 0 : buffer[1] = 0;
471 0 : break;
472 : case 'd':
473 : case 'u':
474 : case 'o':
475 : case 'x':
476 : case 'X':
477 0 : if (var_width) {
478 0 : width = va_arg (ap, int);
479 0 : snprintf (buffer, sizeof buffer,
480 : single_fmt, width, va_arg (ap, int));
481 : } else {
482 0 : snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int));
483 : }
484 0 : 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 0 : if (var_width) {
491 0 : width = va_arg (ap, int);
492 0 : snprintf (buffer, sizeof buffer,
493 : single_fmt, width, va_arg (ap, long int));
494 : } else {
495 0 : snprintf (buffer, sizeof buffer,
496 : single_fmt, va_arg (ap, long int));
497 : }
498 0 : break;
499 : case 's':
500 0 : snprintf (buffer, sizeof buffer,
501 : single_fmt, va_arg (ap, const char *));
502 0 : break;
503 : case 'f':
504 0 : _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), FALSE);
505 0 : break;
506 : case 'g':
507 0 : _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), TRUE);
508 0 : break;
509 : case 'c':
510 0 : buffer[0] = va_arg (ap, int);
511 0 : buffer[1] = 0;
512 0 : break;
513 : default:
514 0 : ASSERT_NOT_REACHED;
515 : }
516 0 : p = buffer + strlen (buffer);
517 0 : f++;
518 : }
519 :
520 0 : _cairo_output_stream_write (stream, buffer, p - buffer);
521 : }
522 :
523 : void
524 0 : _cairo_output_stream_printf (cairo_output_stream_t *stream,
525 : const char *fmt, ...)
526 : {
527 : va_list ap;
528 :
529 0 : va_start (ap, fmt);
530 :
531 0 : _cairo_output_stream_vprintf (stream, fmt, ap);
532 :
533 0 : va_end (ap);
534 0 : }
535 :
536 : long
537 0 : _cairo_output_stream_get_position (cairo_output_stream_t *stream)
538 : {
539 0 : return stream->position;
540 : }
541 :
542 : cairo_status_t
543 0 : _cairo_output_stream_get_status (cairo_output_stream_t *stream)
544 : {
545 0 : 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
558 0 : stdio_write (cairo_output_stream_t *base,
559 : const unsigned char *data, unsigned int length)
560 : {
561 0 : stdio_stream_t *stream = (stdio_stream_t *) base;
562 :
563 0 : if (fwrite (data, 1, length, stream->file) != length)
564 0 : return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
565 :
566 0 : return CAIRO_STATUS_SUCCESS;
567 : }
568 :
569 : static cairo_status_t
570 0 : stdio_flush (cairo_output_stream_t *base)
571 : {
572 0 : stdio_stream_t *stream = (stdio_stream_t *) base;
573 :
574 0 : fflush (stream->file);
575 :
576 0 : if (ferror (stream->file))
577 0 : return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
578 : else
579 0 : return CAIRO_STATUS_SUCCESS;
580 : }
581 :
582 : static cairo_status_t
583 0 : stdio_close (cairo_output_stream_t *base)
584 : {
585 : cairo_status_t status;
586 0 : stdio_stream_t *stream = (stdio_stream_t *) base;
587 :
588 0 : status = stdio_flush (base);
589 :
590 0 : fclose (stream->file);
591 :
592 0 : return status;
593 : }
594 :
595 : cairo_output_stream_t *
596 0 : _cairo_output_stream_create_for_file (FILE *file)
597 : {
598 : stdio_stream_t *stream;
599 :
600 0 : if (file == NULL) {
601 0 : _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
602 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
603 : }
604 :
605 0 : stream = malloc (sizeof *stream);
606 0 : if (unlikely (stream == NULL)) {
607 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
608 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil;
609 : }
610 :
611 0 : _cairo_output_stream_init (&stream->base,
612 : stdio_write, stdio_flush, stdio_flush);
613 0 : stream->file = file;
614 :
615 0 : return &stream->base;
616 : }
617 :
618 : cairo_output_stream_t *
619 0 : _cairo_output_stream_create_for_filename (const char *filename)
620 : {
621 : stdio_stream_t *stream;
622 : FILE *file;
623 :
624 0 : if (filename == NULL)
625 0 : return _cairo_null_stream_create ();
626 :
627 0 : file = fopen (filename, "wb");
628 0 : if (file == NULL) {
629 0 : switch (errno) {
630 : case ENOMEM:
631 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
632 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil;
633 : default:
634 0 : _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
635 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
636 : }
637 : }
638 :
639 0 : stream = malloc (sizeof *stream);
640 0 : if (unlikely (stream == NULL)) {
641 0 : fclose (file);
642 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
643 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil;
644 : }
645 :
646 0 : _cairo_output_stream_init (&stream->base,
647 : stdio_write, stdio_flush, stdio_close);
648 0 : stream->file = file;
649 :
650 0 : 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
660 0 : memory_write (cairo_output_stream_t *base,
661 : const unsigned char *data, unsigned int length)
662 : {
663 0 : memory_stream_t *stream = (memory_stream_t *) base;
664 :
665 0 : return _cairo_array_append_multiple (&stream->array, data, length);
666 : }
667 :
668 : static cairo_status_t
669 0 : memory_close (cairo_output_stream_t *base)
670 : {
671 0 : memory_stream_t *stream = (memory_stream_t *) base;
672 :
673 0 : _cairo_array_fini (&stream->array);
674 :
675 0 : return CAIRO_STATUS_SUCCESS;
676 : }
677 :
678 : cairo_output_stream_t *
679 0 : _cairo_memory_stream_create (void)
680 : {
681 : memory_stream_t *stream;
682 :
683 0 : stream = malloc (sizeof *stream);
684 0 : if (unlikely (stream == NULL)) {
685 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
686 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil;
687 : }
688 :
689 0 : _cairo_output_stream_init (&stream->base, memory_write, NULL, memory_close);
690 0 : _cairo_array_init (&stream->array, 1);
691 :
692 0 : return &stream->base;
693 : }
694 :
695 : cairo_status_t
696 0 : _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 0 : status = abstract_stream->status;
704 0 : if (unlikely (status))
705 0 : return _cairo_output_stream_destroy (abstract_stream);
706 :
707 0 : stream = (memory_stream_t *) abstract_stream;
708 :
709 0 : *length_out = _cairo_array_num_elements (&stream->array);
710 0 : *data_out = malloc (*length_out);
711 0 : if (unlikely (*data_out == NULL)) {
712 0 : status = _cairo_output_stream_destroy (abstract_stream);
713 0 : assert (status == CAIRO_STATUS_SUCCESS);
714 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
715 : }
716 0 : memcpy (*data_out, _cairo_array_index (&stream->array, 0), *length_out);
717 :
718 0 : return _cairo_output_stream_destroy (abstract_stream);
719 : }
720 :
721 : void
722 0 : _cairo_memory_stream_copy (cairo_output_stream_t *base,
723 : cairo_output_stream_t *dest)
724 : {
725 0 : memory_stream_t *stream = (memory_stream_t *) base;
726 :
727 0 : if (dest->status)
728 0 : return;
729 :
730 0 : if (base->status) {
731 0 : dest->status = base->status;
732 0 : return;
733 : }
734 :
735 0 : _cairo_output_stream_write (dest,
736 0 : _cairo_array_index (&stream->array, 0),
737 0 : _cairo_array_num_elements (&stream->array));
738 : }
739 :
740 : int
741 0 : _cairo_memory_stream_length (cairo_output_stream_t *base)
742 : {
743 0 : memory_stream_t *stream = (memory_stream_t *) base;
744 :
745 0 : return _cairo_array_num_elements (&stream->array);
746 : }
747 :
748 : static cairo_status_t
749 0 : null_write (cairo_output_stream_t *base,
750 : const unsigned char *data, unsigned int length)
751 : {
752 0 : return CAIRO_STATUS_SUCCESS;
753 : }
754 :
755 : cairo_output_stream_t *
756 0 : _cairo_null_stream_create (void)
757 : {
758 : cairo_output_stream_t *stream;
759 :
760 0 : stream = malloc (sizeof *stream);
761 0 : if (unlikely (stream == NULL)) {
762 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
763 0 : return (cairo_output_stream_t *) &_cairo_output_stream_nil;
764 : }
765 :
766 0 : _cairo_output_stream_init (stream, null_write, NULL, NULL);
767 :
768 0 : return stream;
769 : }
|