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., 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
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"
41 #include "cairo-array-private.h"
42 #include "cairo-error-private.h"
43 #include "cairo-compiler-private.h"
48 /* Numbers printed with %f are printed with this number of significant
49 * digits after the decimal.
51 #define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
53 /* Numbers printed with %g are assumed to only have %CAIRO_FIXED_FRAC_BITS
54 * bits of precision available after the decimal point.
56 * FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal
57 * digits after the decimal point required to preserve the available
63 * FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) )
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.
69 #define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1))
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
)
77 stream
->write_func
= write_func
;
78 stream
->flush_func
= flush_func
;
79 stream
->close_func
= close_func
;
81 stream
->status
= CAIRO_STATUS_SUCCESS
;
82 stream
->closed
= FALSE
;
86 _cairo_output_stream_fini (cairo_output_stream_t
*stream
)
88 return _cairo_output_stream_close (stream
);
91 const cairo_output_stream_t _cairo_output_stream_nil
= {
92 NULL
, /* write_func */
93 NULL
, /* flush_func */
94 NULL
, /* close_func */
96 CAIRO_STATUS_NO_MEMORY
,
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 */
105 CAIRO_STATUS_WRITE_ERROR
,
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
;
114 } cairo_output_stream_with_closure_t
;
117 static cairo_status_t
118 closure_write (cairo_output_stream_t
*stream
,
119 const unsigned char *data
, unsigned int length
)
121 cairo_output_stream_with_closure_t
*stream_with_closure
=
122 (cairo_output_stream_with_closure_t
*) stream
;
124 if (stream_with_closure
->write_func
== NULL
)
125 return CAIRO_STATUS_SUCCESS
;
127 return stream_with_closure
->write_func (stream_with_closure
->closure
,
131 static cairo_status_t
132 closure_close (cairo_output_stream_t
*stream
)
134 cairo_output_stream_with_closure_t
*stream_with_closure
=
135 (cairo_output_stream_with_closure_t
*) stream
;
137 if (stream_with_closure
->close_func
!= NULL
)
138 return stream_with_closure
->close_func (stream_with_closure
->closure
);
140 return CAIRO_STATUS_SUCCESS
;
143 cairo_output_stream_t
*
144 _cairo_output_stream_create (cairo_write_func_t write_func
,
145 cairo_close_func_t close_func
,
148 cairo_output_stream_with_closure_t
*stream
;
150 stream
= 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
;
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
;
162 return &stream
->base
;
165 cairo_output_stream_t
*
166 _cairo_output_stream_create_in_error (cairo_status_t status
)
168 cairo_output_stream_t
*stream
;
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
;
176 stream
= 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
;
182 _cairo_output_stream_init (stream
, NULL
, NULL
, NULL
);
183 stream
->status
= status
;
189 _cairo_output_stream_flush (cairo_output_stream_t
*stream
)
191 cairo_status_t status
;
194 return stream
->status
;
196 if (stream
== &_cairo_output_stream_nil
||
197 stream
== &_cairo_output_stream_nil_write_error
)
199 return stream
->status
;
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
;
209 return stream
->status
;
213 _cairo_output_stream_close (cairo_output_stream_t
*stream
)
215 cairo_status_t status
;
218 return stream
->status
;
220 if (stream
== &_cairo_output_stream_nil
||
221 stream
== &_cairo_output_stream_nil_write_error
)
223 return stream
->status
;
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
;
233 stream
->closed
= TRUE
;
235 return stream
->status
;
239 _cairo_output_stream_destroy (cairo_output_stream_t
*stream
)
241 cairo_status_t status
;
243 assert (stream
!= NULL
);
245 if (stream
== &_cairo_output_stream_nil
||
246 stream
== &_cairo_output_stream_nil_write_error
)
248 return stream
->status
;
251 status
= _cairo_output_stream_fini (stream
);
258 _cairo_output_stream_write (cairo_output_stream_t
*stream
,
259 const void *data
, size_t length
)
267 stream
->status
= stream
->write_func (stream
, data
, length
);
268 stream
->position
+= length
;
272 _cairo_output_stream_write_hex_string (cairo_output_stream_t
*stream
,
273 const unsigned char *data
,
276 const char hex_chars
[] = "0123456789abcdef";
278 unsigned int i
, column
;
283 for (i
= 0, column
= 0; i
< length
; i
++, column
++) {
285 _cairo_output_stream_write (stream
, "\n", 1);
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);
294 /* Format a double in a locale independent way and trim trailing
295 * zeros. Based on code from Alex Larson <alexl@redhat.com>.
296 * http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
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>
303 _cairo_dtostr (char *buffer
, size_t size
, double d
, cairo_bool_t limited_precision
)
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 decimal_point
= cairo_get_locale_decimal_point ();
316 decimal_point_len
= strlen (decimal_point
);
318 assert (decimal_point_len
!= 0);
320 if (limited_precision
) {
321 snprintf (buffer
, size
, "%.*f", FIXED_POINT_DECIMAL_DIGITS
, d
);
323 /* Using "%f" to print numbers less than 0.1 will result in
324 * reduced precision due to the default 6 digits after the
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
334 if (fabs (d
) >= 0.1) {
335 snprintf (buffer
, size
, "%f", d
);
337 snprintf (buffer
, size
, "%.18f", d
);
340 if (*p
== '+' || *p
== '-')
343 while (_cairo_isdigit (*p
))
346 if (strncmp (p
, decimal_point
, decimal_point_len
) == 0)
347 p
+= decimal_point_len
;
353 decimal_digits
= num_zeros
+ SIGNIFICANT_DIGITS_AFTER_DECIMAL
;
355 if (decimal_digits
< 18)
356 snprintf (buffer
, size
, "%.*f", decimal_digits
, d
);
361 if (*p
== '+' || *p
== '-')
364 while (_cairo_isdigit (*p
))
367 if (strncmp (p
, decimal_point
, decimal_point_len
) == 0) {
369 decimal_len
= strlen (p
+ decimal_point_len
);
370 memmove (p
+ 1, p
+ decimal_point_len
, decimal_len
);
371 p
[1 + decimal_len
] = 0;
373 /* Remove trailing zeros and decimal point if possible. */
374 for (p
= p
+ decimal_len
; *p
== '0'; p
--)
385 LENGTH_MODIFIER_LONG
= 0x100
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.
397 _cairo_output_stream_vprintf (cairo_output_stream_t
*stream
,
398 const char *fmt
, va_list ap
)
400 #define SINGLE_FMT_BUFFER_SIZE 32
401 char buffer
[512], single_fmt
[SINGLE_FMT_BUFFER_SIZE
];
402 int single_fmt_length
;
404 const char *f
, *start
;
405 int length_modifier
, width
;
406 cairo_bool_t var_width
;
414 if (p
== buffer
+ sizeof (buffer
)) {
415 _cairo_output_stream_write (stream
, buffer
, sizeof (buffer
));
436 while (_cairo_isdigit (*f
))
441 length_modifier
= LENGTH_MODIFIER_LONG
;
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
);
451 /* Reuse the format string for this conversion. */
452 memcpy (single_fmt
, start
, single_fmt_length
);
453 single_fmt
[single_fmt_length
] = '\0';
455 /* Flush contents of buffer before snprintf()'ing into it. */
456 _cairo_output_stream_write (stream
, buffer
, p
- buffer
);
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
) {
472 width
= va_arg (ap
, int);
473 snprintf (buffer
, sizeof buffer
,
474 single_fmt
, width
, va_arg (ap
, int));
476 snprintf (buffer
, sizeof buffer
, single_fmt
, va_arg (ap
, int));
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
:
485 width
= va_arg (ap
, int);
486 snprintf (buffer
, sizeof buffer
,
487 single_fmt
, width
, va_arg (ap
, long int));
489 snprintf (buffer
, sizeof buffer
,
490 single_fmt
, va_arg (ap
, long int));
494 snprintf (buffer
, sizeof buffer
,
495 single_fmt
, va_arg (ap
, const char *));
498 _cairo_dtostr (buffer
, sizeof buffer
, va_arg (ap
, double), FALSE
);
501 _cairo_dtostr (buffer
, sizeof buffer
, va_arg (ap
, double), TRUE
);
504 buffer
[0] = va_arg (ap
, int);
510 p
= buffer
+ strlen (buffer
);
514 _cairo_output_stream_write (stream
, buffer
, p
- buffer
);
518 _cairo_output_stream_printf (cairo_output_stream_t
*stream
,
519 const char *fmt
, ...)
525 _cairo_output_stream_vprintf (stream
, fmt
, ap
);
530 /* Matrix elements that are smaller than the value of the largest element * MATRIX_ROUNDING_TOLERANCE
531 * are rounded down to zero. */
532 #define MATRIX_ROUNDING_TOLERANCE 1e-12
535 _cairo_output_stream_print_matrix (cairo_output_stream_t
*stream
,
536 const cairo_matrix_t
*matrix
)
550 e
= s
* MATRIX_ROUNDING_TOLERANCE
;
564 _cairo_output_stream_printf (stream
,
566 m
.xx
, m
.yx
, m
.xy
, m
.yy
, m
.x0
, m
.y0
);
570 _cairo_output_stream_get_position (cairo_output_stream_t
*stream
)
572 return stream
->position
;
576 _cairo_output_stream_get_status (cairo_output_stream_t
*stream
)
578 return stream
->status
;
581 /* Maybe this should be a configure time option, so embedded targets
582 * don't have to pull in stdio. */
585 typedef struct _stdio_stream
{
586 cairo_output_stream_t base
;
590 static cairo_status_t
591 stdio_write (cairo_output_stream_t
*base
,
592 const unsigned char *data
, unsigned int length
)
594 stdio_stream_t
*stream
= (stdio_stream_t
*) base
;
596 if (fwrite (data
, 1, length
, stream
->file
) != length
)
597 return _cairo_error (CAIRO_STATUS_WRITE_ERROR
);
599 return CAIRO_STATUS_SUCCESS
;
602 static cairo_status_t
603 stdio_flush (cairo_output_stream_t
*base
)
605 stdio_stream_t
*stream
= (stdio_stream_t
*) base
;
607 fflush (stream
->file
);
609 if (ferror (stream
->file
))
610 return _cairo_error (CAIRO_STATUS_WRITE_ERROR
);
612 return CAIRO_STATUS_SUCCESS
;
615 static cairo_status_t
616 stdio_close (cairo_output_stream_t
*base
)
618 cairo_status_t status
;
619 stdio_stream_t
*stream
= (stdio_stream_t
*) base
;
621 status
= stdio_flush (base
);
623 fclose (stream
->file
);
628 cairo_output_stream_t
*
629 _cairo_output_stream_create_for_file (FILE *file
)
631 stdio_stream_t
*stream
;
634 _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR
);
635 return (cairo_output_stream_t
*) &_cairo_output_stream_nil_write_error
;
638 stream
= malloc (sizeof *stream
);
639 if (unlikely (stream
== NULL
)) {
640 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
641 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
644 _cairo_output_stream_init (&stream
->base
,
645 stdio_write
, stdio_flush
, stdio_flush
);
648 return &stream
->base
;
651 cairo_output_stream_t
*
652 _cairo_output_stream_create_for_filename (const char *filename
)
654 stdio_stream_t
*stream
;
657 if (filename
== NULL
)
658 return _cairo_null_stream_create ();
660 file
= fopen (filename
, "wb");
664 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
665 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
667 _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR
);
668 return (cairo_output_stream_t
*) &_cairo_output_stream_nil_write_error
;
672 stream
= malloc (sizeof *stream
);
673 if (unlikely (stream
== NULL
)) {
675 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
676 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
679 _cairo_output_stream_init (&stream
->base
,
680 stdio_write
, stdio_flush
, stdio_close
);
683 return &stream
->base
;
687 typedef struct _memory_stream
{
688 cairo_output_stream_t base
;
692 static cairo_status_t
693 memory_write (cairo_output_stream_t
*base
,
694 const unsigned char *data
, unsigned int length
)
696 memory_stream_t
*stream
= (memory_stream_t
*) base
;
698 return _cairo_array_append_multiple (&stream
->array
, data
, length
);
701 static cairo_status_t
702 memory_close (cairo_output_stream_t
*base
)
704 memory_stream_t
*stream
= (memory_stream_t
*) base
;
706 _cairo_array_fini (&stream
->array
);
708 return CAIRO_STATUS_SUCCESS
;
711 cairo_output_stream_t
*
712 _cairo_memory_stream_create (void)
714 memory_stream_t
*stream
;
716 stream
= malloc (sizeof *stream
);
717 if (unlikely (stream
== NULL
)) {
718 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
719 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
722 _cairo_output_stream_init (&stream
->base
, memory_write
, NULL
, memory_close
);
723 _cairo_array_init (&stream
->array
, 1);
725 return &stream
->base
;
729 _cairo_memory_stream_destroy (cairo_output_stream_t
*abstract_stream
,
730 unsigned char **data_out
,
731 unsigned long *length_out
)
733 memory_stream_t
*stream
;
734 cairo_status_t status
;
736 status
= abstract_stream
->status
;
737 if (unlikely (status
))
738 return _cairo_output_stream_destroy (abstract_stream
);
740 stream
= (memory_stream_t
*) abstract_stream
;
742 *length_out
= _cairo_array_num_elements (&stream
->array
);
743 *data_out
= malloc (*length_out
);
744 if (unlikely (*data_out
== NULL
)) {
745 status
= _cairo_output_stream_destroy (abstract_stream
);
746 assert (status
== CAIRO_STATUS_SUCCESS
);
747 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
749 memcpy (*data_out
, _cairo_array_index (&stream
->array
, 0), *length_out
);
751 return _cairo_output_stream_destroy (abstract_stream
);
755 _cairo_memory_stream_copy (cairo_output_stream_t
*base
,
756 cairo_output_stream_t
*dest
)
758 memory_stream_t
*stream
= (memory_stream_t
*) base
;
764 dest
->status
= base
->status
;
768 _cairo_output_stream_write (dest
,
769 _cairo_array_index (&stream
->array
, 0),
770 _cairo_array_num_elements (&stream
->array
));
774 _cairo_memory_stream_length (cairo_output_stream_t
*base
)
776 memory_stream_t
*stream
= (memory_stream_t
*) base
;
778 return _cairo_array_num_elements (&stream
->array
);
781 static cairo_status_t
782 null_write (cairo_output_stream_t
*base
,
783 const unsigned char *data
, unsigned int length
)
785 return CAIRO_STATUS_SUCCESS
;
788 cairo_output_stream_t
*
789 _cairo_null_stream_create (void)
791 cairo_output_stream_t
*stream
;
793 stream
= malloc (sizeof *stream
);
794 if (unlikely (stream
== NULL
)) {
795 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
796 return (cairo_output_stream_t
*) &_cairo_output_stream_nil
;
799 _cairo_output_stream_init (stream
, null_write
, NULL
, NULL
);