1 /* cairo-output-stream.c: Output stream abstraction
3 * Copyright © 2005 Red Hat, Inc
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
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/
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.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Red Hat, Inc.
33 * Kristian Høgsberg <krh@redhat.com>
36 #define _BSD_SOURCE /* for snprintf() */
39 #include "cairo-output-stream-private.h"
40 #include "cairo-compiler-private.h"
47 /* Numbers printed with %f are printed with this number of significant
48 * digits after the decimal.
50 #define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
52 /* Numbers printed with %g are assumed to only have %CAIRO_FIXED_FRAC_BITS
53 * bits of precision available after the decimal point.
55 * FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal
56 * digits after the decimal point required to preserve the available
62 * FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) )
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.
68 #define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1))
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
)
76 stream
->write_func
= write_func
;
77 stream
->flush_func
= flush_func
;
78 stream
->close_func
= close_func
;
80 stream
->status
= CAIRO_STATUS_SUCCESS
;
81 stream
->closed
= FALSE
;
85 _cairo_output_stream_fini (cairo_output_stream_t
*stream
)
87 return _cairo_output_stream_close (stream
);
90 const cairo_output_stream_t _cairo_output_stream_nil
= {
91 NULL
, /* write_func */
92 NULL
, /* flush_func */
93 NULL
, /* close_func */
95 CAIRO_STATUS_NO_MEMORY
,
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 */
104 CAIRO_STATUS_WRITE_ERROR
,
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
;
113 } cairo_output_stream_with_closure_t
;
116 static cairo_status_t
117 closure_write (cairo_output_stream_t
*stream
,
118 const unsigned char *data
, unsigned int length
)
120 cairo_output_stream_with_closure_t
*stream_with_closure
=
121 (cairo_output_stream_with_closure_t
*) stream
;
123 if (stream_with_closure
->write_func
== NULL
)
124 return CAIRO_STATUS_SUCCESS
;
126 return stream_with_closure
->write_func (stream_with_closure
->closure
,
130 static cairo_status_t
131 closure_close (cairo_output_stream_t
*stream
)
133 cairo_output_stream_with_closure_t
*stream_with_closure
=
134 (cairo_output_stream_with_closure_t
*) stream
;
136 if (stream_with_closure
->close_func
!= NULL
)
137 return stream_with_closure
->close_func (stream_with_closure
->closure
);
139 return CAIRO_STATUS_SUCCESS
;
142 cairo_output_stream_t
*
143 _cairo_output_stream_create (cairo_write_func_t write_func
,
144 cairo_close_func_t close_func
,
147 cairo_output_stream_with_closure_t
*stream
;
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
;
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
;
161 return &stream
->base
;
164 cairo_output_stream_t
*
165 _cairo_output_stream_create_in_error (cairo_status_t status
)
167 cairo_output_stream_t
*stream
;
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
;
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
;
181 _cairo_output_stream_init (stream
, NULL
, NULL
, NULL
);
182 stream
->status
= status
;
188 _cairo_output_stream_flush (cairo_output_stream_t
*stream
)
190 cairo_status_t status
;
193 return stream
->status
;
195 if (stream
== &_cairo_output_stream_nil
||
196 stream
== &_cairo_output_stream_nil_write_error
)
198 return stream
->status
;
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
;
208 return stream
->status
;
212 _cairo_output_stream_close (cairo_output_stream_t
*stream
)
214 cairo_status_t status
;
217 return stream
->status
;
219 if (stream
== &_cairo_output_stream_nil
||
220 stream
== &_cairo_output_stream_nil_write_error
)
222 return stream
->status
;
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
;
232 stream
->closed
= TRUE
;
234 return stream
->status
;
238 _cairo_output_stream_destroy (cairo_output_stream_t
*stream
)
240 cairo_status_t status
;
242 assert (stream
!= NULL
);
244 if (stream
== &_cairo_output_stream_nil
||
245 stream
== &_cairo_output_stream_nil_write_error
)
247 return stream
->status
;
250 status
= _cairo_output_stream_fini (stream
);
257 _cairo_output_stream_write (cairo_output_stream_t
*stream
,
258 const void *data
, size_t length
)
266 stream
->status
= stream
->write_func (stream
, data
, length
);
267 stream
->position
+= length
;
271 _cairo_output_stream_write_hex_string (cairo_output_stream_t
*stream
,
272 const unsigned char *data
,
275 const char hex_chars
[] = "0123456789abcdef";
277 unsigned int i
, column
;
282 for (i
= 0, column
= 0; i
< length
; i
++, column
++) {
284 _cairo_output_stream_write (stream
, "\n", 1);
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);
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
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>
302 _cairo_dtostr (char *buffer
, size_t size
, double d
, cairo_bool_t limited_precision
)
304 struct lconv
*locale_data
;
305 const char *decimal_point
;
306 int decimal_point_len
;
309 int num_zeros
, decimal_digits
;
311 /* Omit the minus sign from negative zero. */
315 locale_data
= localeconv ();
316 decimal_point
= locale_data
->decimal_point
;
317 decimal_point_len
= strlen (decimal_point
);
319 assert (decimal_point_len
!= 0);
321 if (limited_precision
) {
322 snprintf (buffer
, size
, "%.*f", FIXED_POINT_DECIMAL_DIGITS
, d
);
324 /* Using "%f" to print numbers less than 0.1 will result in
325 * reduced precision due to the default 6 digits after the
328 * For numbers is < 0.1, we print with maximum precision and count
329 * the number of zeros between the decimal point and the first
330 * significant digit. We then print the number again with the
331 * number of decimal places that gives us the required number of
332 * significant digits. This ensures the number is correctly
335 if (fabs (d
) >= 0.1) {
336 snprintf (buffer
, size
, "%f", d
);
338 snprintf (buffer
, size
, "%.18f", d
);
341 if (*p
== '+' || *p
== '-')
347 if (strncmp (p
, decimal_point
, decimal_point_len
) == 0)
348 p
+= decimal_point_len
;
354 decimal_digits
= num_zeros
+ SIGNIFICANT_DIGITS_AFTER_DECIMAL
;
356 if (decimal_digits
< 18)
357 snprintf (buffer
, size
, "%.*f", decimal_digits
, d
);
362 if (*p
== '+' || *p
== '-')
368 if (strncmp (p
, decimal_point
, decimal_point_len
) == 0) {
370 decimal_len
= strlen (p
+ decimal_point_len
);
371 memmove (p
+ 1, p
+ decimal_point_len
, decimal_len
);
372 p
[1 + decimal_len
] = 0;
374 /* Remove trailing zeros and decimal point if possible. */
375 for (p
= p
+ decimal_len
; *p
== '0'; p
--)
386 LENGTH_MODIFIER_LONG
= 0x100
389 /* Here's a limited reimplementation of printf. The reason for doing
390 * this is primarily to special case handling of doubles. We want
391 * locale independent formatting of doubles and we want to trim
392 * trailing zeros. This is handled by dtostr() above, and the code
393 * below handles everything else by calling snprintf() to do the
394 * formatting. This functionality is only for internal use and we
395 * only implement the formats we actually use.
398 _cairo_output_stream_vprintf (cairo_output_stream_t
*stream
,
399 const char *fmt
, va_list ap
)
401 #define SINGLE_FMT_BUFFER_SIZE 32
402 char buffer
[512], single_fmt
[SINGLE_FMT_BUFFER_SIZE
];
403 int single_fmt_length
;
405 const char *f
, *start
;
406 int length_modifier
, width
;
407 cairo_bool_t var_width
;
415 if (p
== buffer
+ sizeof (buffer
)) {
416 _cairo_output_stream_write (stream
, buffer
, sizeof (buffer
));
442 length_modifier
= LENGTH_MODIFIER_LONG
;
446 /* The only format strings exist in the cairo implementation
447 * itself. So there's an internal consistency problem if any
448 * of them is larger than our format buffer size. */
449 single_fmt_length
= f
- start
+ 1;
450 assert (single_fmt_length
+ 1 <= SINGLE_FMT_BUFFER_SIZE
);
452 /* Reuse the format string for this conversion. */
453 memcpy (single_fmt
, start
, single_fmt_length
);
454 single_fmt
[single_fmt_length
] = '\0';
456 /* Flush contents of buffer before snprintf()'ing into it. */
457 _cairo_output_stream_write (stream
, buffer
, p
- buffer
);
459 /* We group signed and unsigned together in this switch, the
460 * only thing that matters here is the size of the arguments,
461 * since we're just passing the data through to sprintf(). */
462 switch (*f
| length_modifier
) {
473 width
= va_arg (ap
, int);
474 snprintf (buffer
, sizeof buffer
,
475 single_fmt
, width
, va_arg (ap
, int));
477 snprintf (buffer
, sizeof buffer
, single_fmt
, va_arg (ap
, int));
480 case 'd' | LENGTH_MODIFIER_LONG
:
481 case 'u' | LENGTH_MODIFIER_LONG
:
482 case 'o' | LENGTH_MODIFIER_LONG
:
483 case 'x' | LENGTH_MODIFIER_LONG
:
484 case 'X' | LENGTH_MODIFIER_LONG
:
486 width
= va_arg (ap
, int);
487 snprintf (buffer
, sizeof buffer
,
488 single_fmt
, width
, va_arg (ap
, long int));
490 snprintf (buffer
, sizeof buffer
,
491 single_fmt
, va_arg (ap
, long int));
495 snprintf (buffer
, sizeof buffer
,
496 single_fmt
, va_arg (ap
, const char *));
499 _cairo_dtostr (buffer
, sizeof buffer
, va_arg (ap
, double), FALSE
);
502 _cairo_dtostr (buffer
, sizeof buffer
, va_arg (ap
, double), TRUE
);
505 buffer
[0] = va_arg (ap
, int);
511 p
= buffer
+ strlen (buffer
);
515 _cairo_output_stream_write (stream
, buffer
, p
- buffer
);
519 _cairo_output_stream_printf (cairo_output_stream_t
*stream
,
520 const char *fmt
, ...)
526 _cairo_output_stream_vprintf (stream
, fmt
, ap
);
532 _cairo_output_stream_get_position (cairo_output_stream_t
*stream
)
534 return stream
->position
;
538 _cairo_output_stream_get_status (cairo_output_stream_t
*stream
)
540 return stream
->status
;
543 /* Maybe this should be a configure time option, so embedded targets
544 * don't have to pull in stdio. */
547 typedef struct _stdio_stream
{
548 cairo_output_stream_t base
;
552 static cairo_status_t
553 stdio_write (cairo_output_stream_t
*base
,
554 const unsigned char *data
, unsigned int length
)
556 stdio_stream_t
*stream
= (stdio_stream_t
*) base
;
558 if (fwrite (data
, 1, length
, stream
->file
) != length
)
559 return _cairo_error (CAIRO_STATUS_WRITE_ERROR
);
561 return CAIRO_STATUS_SUCCESS
;
564 static cairo_status_t
565 stdio_flush (cairo_output_stream_t
*base
)
567 stdio_stream_t
*stream
= (stdio_stream_t
*) base
;
569 fflush (stream
->file
);
571 if (ferror (stream
->file
))
572 return _cairo_error (CAIRO_STATUS_WRITE_ERROR
);
574 return CAIRO_STATUS_SUCCESS
;
577 static cairo_status_t
578 stdio_close (cairo_output_stream_t
*base
)
580 cairo_status_t status
;
581 stdio_stream_t
*stream
= (stdio_stream_t
*) base
;
583 status
= stdio_flush (base
);
585 fclose (stream
->file
);
590 cairo_output_stream_t
*
591 _cairo_output_stream_create_for_file (FILE *file
)
593 stdio_stream_t
*stream
;
596 _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR
);
597 return (cairo_output_stream_t
*) &_cairo_output_stream_nil_write_error
;
600 stream
= malloc (sizeof *stream
);
601 if (unlikely (stream
== NULL
)) {
602 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
603 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
606 _cairo_output_stream_init (&stream
->base
,
607 stdio_write
, stdio_flush
, stdio_flush
);
610 return &stream
->base
;
613 cairo_output_stream_t
*
614 _cairo_output_stream_create_for_filename (const char *filename
)
616 stdio_stream_t
*stream
;
619 if (filename
== NULL
)
620 return _cairo_null_stream_create ();
622 file
= fopen (filename
, "wb");
626 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
627 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
629 _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR
);
630 return (cairo_output_stream_t
*) &_cairo_output_stream_nil_write_error
;
634 stream
= malloc (sizeof *stream
);
635 if (unlikely (stream
== NULL
)) {
637 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
638 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
641 _cairo_output_stream_init (&stream
->base
,
642 stdio_write
, stdio_flush
, stdio_close
);
645 return &stream
->base
;
649 typedef struct _memory_stream
{
650 cairo_output_stream_t base
;
654 static cairo_status_t
655 memory_write (cairo_output_stream_t
*base
,
656 const unsigned char *data
, unsigned int length
)
658 memory_stream_t
*stream
= (memory_stream_t
*) base
;
660 return _cairo_array_append_multiple (&stream
->array
, data
, length
);
663 static cairo_status_t
664 memory_close (cairo_output_stream_t
*base
)
666 memory_stream_t
*stream
= (memory_stream_t
*) base
;
668 _cairo_array_fini (&stream
->array
);
670 return CAIRO_STATUS_SUCCESS
;
673 cairo_output_stream_t
*
674 _cairo_memory_stream_create (void)
676 memory_stream_t
*stream
;
678 stream
= malloc (sizeof *stream
);
679 if (unlikely (stream
== NULL
)) {
680 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
681 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
684 _cairo_output_stream_init (&stream
->base
, memory_write
, NULL
, memory_close
);
685 _cairo_array_init (&stream
->array
, 1);
687 return &stream
->base
;
691 _cairo_memory_stream_destroy (cairo_output_stream_t
*abstract_stream
,
692 unsigned char **data_out
,
693 unsigned int *length_out
)
695 memory_stream_t
*stream
;
696 cairo_status_t status
;
698 status
= abstract_stream
->status
;
699 if (unlikely (status
))
700 return _cairo_output_stream_destroy (abstract_stream
);
702 stream
= (memory_stream_t
*) abstract_stream
;
704 *length_out
= _cairo_array_num_elements (&stream
->array
);
705 *data_out
= malloc (*length_out
);
706 if (unlikely (*data_out
== NULL
)) {
707 status
= _cairo_output_stream_destroy (abstract_stream
);
708 assert (status
== CAIRO_STATUS_SUCCESS
);
709 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
711 memcpy (*data_out
, _cairo_array_index (&stream
->array
, 0), *length_out
);
713 return _cairo_output_stream_destroy (abstract_stream
);
717 _cairo_memory_stream_copy (cairo_output_stream_t
*base
,
718 cairo_output_stream_t
*dest
)
720 memory_stream_t
*stream
= (memory_stream_t
*) base
;
726 dest
->status
= base
->status
;
730 _cairo_output_stream_write (dest
,
731 _cairo_array_index (&stream
->array
, 0),
732 _cairo_array_num_elements (&stream
->array
));
736 _cairo_memory_stream_length (cairo_output_stream_t
*base
)
738 memory_stream_t
*stream
= (memory_stream_t
*) base
;
740 return _cairo_array_num_elements (&stream
->array
);
743 static cairo_status_t
744 null_write (cairo_output_stream_t
*base
,
745 const unsigned char *data
, unsigned int length
)
747 return CAIRO_STATUS_SUCCESS
;
750 cairo_output_stream_t
*
751 _cairo_null_stream_create (void)
753 cairo_output_stream_t
*stream
;
755 stream
= malloc (sizeof *stream
);
756 if (unlikely (stream
== NULL
)) {
757 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
758 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
761 _cairo_output_stream_init (stream
, null_write
, NULL
, NULL
);