Updated: Sudoku no longer crashes
[moon.git] / cairo / src / cairo-output-stream.c
blobbae6ac4fe83b369e5d2a414953b5263f8e9c1efa
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.
32 * Author(s):
33 * Kristian Høgsberg <krh@redhat.com>
36 #define _BSD_SOURCE /* for snprintf() */
37 #include "cairoint.h"
39 #include "cairo-output-stream-private.h"
40 #include "cairo-compiler-private.h"
42 #include <stdio.h>
43 #include <locale.h>
44 #include <ctype.h>
45 #include <errno.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
57 * precision.
59 * The conversion is:
61 * <programlisting>
62 * FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) )
63 * </programlisting>
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))
70 void
71 _cairo_output_stream_init (cairo_output_stream_t *stream,
72 cairo_output_stream_write_func_t write_func,
73 cairo_output_stream_close_func_t close_func)
75 stream->write_func = write_func;
76 stream->close_func = close_func;
77 stream->position = 0;
78 stream->status = CAIRO_STATUS_SUCCESS;
79 stream->closed = FALSE;
82 cairo_status_t
83 _cairo_output_stream_fini (cairo_output_stream_t *stream)
85 return _cairo_output_stream_close (stream);
88 const cairo_output_stream_t _cairo_output_stream_nil = {
89 NULL, /* write_func */
90 NULL, /* close_func */
91 0, /* position */
92 CAIRO_STATUS_NO_MEMORY,
93 FALSE /* closed */
96 static const cairo_output_stream_t _cairo_output_stream_nil_write_error = {
97 NULL, /* write_func */
98 NULL, /* close_func */
99 0, /* position */
100 CAIRO_STATUS_WRITE_ERROR,
101 FALSE /* closed */
104 typedef struct _cairo_output_stream_with_closure {
105 cairo_output_stream_t base;
106 cairo_write_func_t write_func;
107 cairo_close_func_t close_func;
108 void *closure;
109 } cairo_output_stream_with_closure_t;
112 static cairo_status_t
113 closure_write (cairo_output_stream_t *stream,
114 const unsigned char *data, unsigned int length)
116 cairo_output_stream_with_closure_t *stream_with_closure =
117 (cairo_output_stream_with_closure_t *) stream;
119 if (stream_with_closure->write_func == NULL)
120 return CAIRO_STATUS_SUCCESS;
122 return stream_with_closure->write_func (stream_with_closure->closure,
123 data, length);
126 static cairo_status_t
127 closure_close (cairo_output_stream_t *stream)
129 cairo_output_stream_with_closure_t *stream_with_closure =
130 (cairo_output_stream_with_closure_t *) stream;
132 if (stream_with_closure->close_func != NULL)
133 return stream_with_closure->close_func (stream_with_closure->closure);
134 else
135 return CAIRO_STATUS_SUCCESS;
138 cairo_output_stream_t *
139 _cairo_output_stream_create (cairo_write_func_t write_func,
140 cairo_close_func_t close_func,
141 void *closure)
143 cairo_output_stream_with_closure_t *stream;
145 stream = malloc (sizeof (cairo_output_stream_with_closure_t));
146 if (stream == NULL) {
147 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
148 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
151 _cairo_output_stream_init (&stream->base, closure_write, closure_close);
152 stream->write_func = write_func;
153 stream->close_func = close_func;
154 stream->closure = closure;
156 return &stream->base;
159 cairo_output_stream_t *
160 _cairo_output_stream_create_in_error (cairo_status_t status)
162 cairo_output_stream_t *stream;
164 /* check for the common ones */
165 if (status == CAIRO_STATUS_NO_MEMORY)
166 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
167 if (status == CAIRO_STATUS_WRITE_ERROR)
168 return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
170 stream = malloc (sizeof (cairo_output_stream_t));
171 if (stream == NULL) {
172 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
173 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
176 _cairo_output_stream_init (stream, NULL, NULL);
177 stream->status = status;
179 return stream;
182 cairo_status_t
183 _cairo_output_stream_close (cairo_output_stream_t *stream)
185 cairo_status_t status;
187 if (stream->closed)
188 return stream->status;
190 if (stream == &_cairo_output_stream_nil ||
191 stream == &_cairo_output_stream_nil_write_error)
193 return stream->status;
196 if (stream->close_func) {
197 status = stream->close_func (stream);
198 /* Don't overwrite a pre-existing status failure. */
199 if (stream->status == CAIRO_STATUS_SUCCESS)
200 stream->status = status;
203 stream->closed = TRUE;
205 return stream->status;
208 cairo_status_t
209 _cairo_output_stream_destroy (cairo_output_stream_t *stream)
211 cairo_status_t status;
213 assert (stream != NULL);
215 if (stream == &_cairo_output_stream_nil ||
216 stream == &_cairo_output_stream_nil_write_error)
218 return stream->status;
221 status = _cairo_output_stream_fini (stream);
222 free (stream);
224 return status;
227 void
228 _cairo_output_stream_write (cairo_output_stream_t *stream,
229 const void *data, size_t length)
231 if (length == 0)
232 return;
234 if (stream->status)
235 return;
237 stream->status = stream->write_func (stream, data, length);
238 stream->position += length;
241 void
242 _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
243 const unsigned char *data,
244 size_t length)
246 const char hex_chars[] = "0123456789abcdef";
247 char buffer[2];
248 unsigned int i, column;
250 if (stream->status)
251 return;
253 for (i = 0, column = 0; i < length; i++, column++) {
254 if (column == 38) {
255 _cairo_output_stream_write (stream, "\n", 1);
256 column = 0;
258 buffer[0] = hex_chars[(data[i] >> 4) & 0x0f];
259 buffer[1] = hex_chars[data[i] & 0x0f];
260 _cairo_output_stream_write (stream, buffer, 2);
264 /* Format a double in a locale independent way and trim trailing
265 * zeros. Based on code from Alex Larson <alexl@redhat.com>.
266 * http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
268 * The code in the patch is copyright Red Hat, Inc under the LGPL, but
269 * has been relicensed under the LGPL/MPL dual license for inclusion
270 * into cairo (see COPYING). -- Kristian Høgsberg <krh@redhat.com>
272 static void
273 _cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precision)
275 struct lconv *locale_data;
276 const char *decimal_point;
277 int decimal_point_len;
278 char *p;
279 int decimal_len;
280 int num_zeros, decimal_digits;
282 /* Omit the minus sign from negative zero. */
283 if (d == 0.0)
284 d = 0.0;
286 locale_data = localeconv ();
287 decimal_point = locale_data->decimal_point;
288 decimal_point_len = strlen (decimal_point);
290 assert (decimal_point_len != 0);
292 if (limited_precision) {
293 snprintf (buffer, size, "%.*f", FIXED_POINT_DECIMAL_DIGITS, d);
294 } else {
295 /* Using "%f" to print numbers less than 0.1 will result in
296 * reduced precision due to the default 6 digits after the
297 * decimal point.
299 * For numbers is < 0.1, we print with maximum precision and count
300 * the number of zeros between the decimal point and the first
301 * significant digit. We then print the number again with the
302 * number of decimal places that gives us the required number of
303 * significant digits. This ensures the number is correctly
304 * rounded.
306 if (fabs (d) >= 0.1) {
307 snprintf (buffer, size, "%f", d);
308 } else {
309 snprintf (buffer, size, "%.18f", d);
310 p = buffer;
312 if (*p == '+' || *p == '-')
313 p++;
315 while (isdigit (*p))
316 p++;
318 if (strncmp (p, decimal_point, decimal_point_len) == 0)
319 p += decimal_point_len;
321 num_zeros = 0;
322 while (*p++ == '0')
323 num_zeros++;
325 decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL;
327 if (decimal_digits < 18)
328 snprintf (buffer, size, "%.*f", decimal_digits, d);
331 p = buffer;
333 if (*p == '+' || *p == '-')
334 p++;
336 while (isdigit (*p))
337 p++;
339 if (strncmp (p, decimal_point, decimal_point_len) == 0) {
340 *p = '.';
341 decimal_len = strlen (p + decimal_point_len);
342 memmove (p + 1, p + decimal_point_len, decimal_len);
343 p[1 + decimal_len] = 0;
345 /* Remove trailing zeros and decimal point if possible. */
346 for (p = p + decimal_len; *p == '0'; p--)
347 *p = 0;
349 if (*p == '.') {
350 *p = 0;
351 p--;
356 enum {
357 LENGTH_MODIFIER_LONG = 0x100
360 /* Here's a limited reimplementation of printf. The reason for doing
361 * this is primarily to special case handling of doubles. We want
362 * locale independent formatting of doubles and we want to trim
363 * trailing zeros. This is handled by dtostr() above, and the code
364 * below handles everything else by calling snprintf() to do the
365 * formatting. This functionality is only for internal use and we
366 * only implement the formats we actually use.
368 void
369 _cairo_output_stream_vprintf (cairo_output_stream_t *stream,
370 const char *fmt, va_list ap)
372 #define SINGLE_FMT_BUFFER_SIZE 32
373 char buffer[512], single_fmt[SINGLE_FMT_BUFFER_SIZE];
374 int single_fmt_length;
375 char *p;
376 const char *f, *start;
377 int length_modifier, width;
378 cairo_bool_t var_width;
380 if (stream->status)
381 return;
383 f = fmt;
384 p = buffer;
385 while (*f != '\0') {
386 if (p == buffer + sizeof (buffer)) {
387 _cairo_output_stream_write (stream, buffer, sizeof (buffer));
388 p = buffer;
391 if (*f != '%') {
392 *p++ = *f++;
393 continue;
396 start = f;
397 f++;
399 if (*f == '0')
400 f++;
402 var_width = FALSE;
403 if (*f == '*') {
404 var_width = TRUE;
405 f++;
408 while (isdigit (*f))
409 f++;
411 length_modifier = 0;
412 if (*f == 'l') {
413 length_modifier = LENGTH_MODIFIER_LONG;
414 f++;
417 /* The only format strings exist in the cairo implementation
418 * itself. So there's an internal consistency problem if any
419 * of them is larger than our format buffer size. */
420 single_fmt_length = f - start + 1;
421 assert (single_fmt_length + 1 <= SINGLE_FMT_BUFFER_SIZE);
423 /* Reuse the format string for this conversion. */
424 memcpy (single_fmt, start, single_fmt_length);
425 single_fmt[single_fmt_length] = '\0';
427 /* Flush contents of buffer before snprintf()'ing into it. */
428 _cairo_output_stream_write (stream, buffer, p - buffer);
430 /* We group signed and unsigned together in this switch, the
431 * only thing that matters here is the size of the arguments,
432 * since we're just passing the data through to sprintf(). */
433 switch (*f | length_modifier) {
434 case '%':
435 buffer[0] = *f;
436 buffer[1] = 0;
437 break;
438 case 'd':
439 case 'u':
440 case 'o':
441 case 'x':
442 case 'X':
443 if (var_width) {
444 width = va_arg (ap, int);
445 snprintf (buffer, sizeof buffer,
446 single_fmt, width, va_arg (ap, int));
447 } else {
448 snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int));
450 break;
451 case 'd' | LENGTH_MODIFIER_LONG:
452 case 'u' | LENGTH_MODIFIER_LONG:
453 case 'o' | LENGTH_MODIFIER_LONG:
454 case 'x' | LENGTH_MODIFIER_LONG:
455 case 'X' | LENGTH_MODIFIER_LONG:
456 if (var_width) {
457 width = va_arg (ap, int);
458 snprintf (buffer, sizeof buffer,
459 single_fmt, width, va_arg (ap, long int));
460 } else {
461 snprintf (buffer, sizeof buffer,
462 single_fmt, va_arg (ap, long int));
464 break;
465 case 's':
466 snprintf (buffer, sizeof buffer,
467 single_fmt, va_arg (ap, const char *));
468 break;
469 case 'f':
470 _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), FALSE);
471 break;
472 case 'g':
473 _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), TRUE);
474 break;
475 case 'c':
476 buffer[0] = va_arg (ap, int);
477 buffer[1] = 0;
478 break;
479 default:
480 ASSERT_NOT_REACHED;
482 p = buffer + strlen (buffer);
483 f++;
486 _cairo_output_stream_write (stream, buffer, p - buffer);
489 void
490 _cairo_output_stream_printf (cairo_output_stream_t *stream,
491 const char *fmt, ...)
493 va_list ap;
495 va_start (ap, fmt);
497 _cairo_output_stream_vprintf (stream, fmt, ap);
499 va_end (ap);
502 long
503 _cairo_output_stream_get_position (cairo_output_stream_t *stream)
505 return stream->position;
508 cairo_status_t
509 _cairo_output_stream_get_status (cairo_output_stream_t *stream)
511 return stream->status;
514 /* Maybe this should be a configure time option, so embedded targets
515 * don't have to pull in stdio. */
518 typedef struct _stdio_stream {
519 cairo_output_stream_t base;
520 FILE *file;
521 } stdio_stream_t;
523 static cairo_status_t
524 stdio_write (cairo_output_stream_t *base,
525 const unsigned char *data, unsigned int length)
527 stdio_stream_t *stream = (stdio_stream_t *) base;
529 if (fwrite (data, 1, length, stream->file) != length)
530 return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
532 return CAIRO_STATUS_SUCCESS;
535 static cairo_status_t
536 stdio_flush (cairo_output_stream_t *base)
538 stdio_stream_t *stream = (stdio_stream_t *) base;
540 fflush (stream->file);
542 if (ferror (stream->file))
543 return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
544 else
545 return CAIRO_STATUS_SUCCESS;
548 static cairo_status_t
549 stdio_close (cairo_output_stream_t *base)
551 cairo_status_t status;
552 stdio_stream_t *stream = (stdio_stream_t *) base;
554 status = stdio_flush (base);
556 fclose (stream->file);
558 return status;
561 cairo_output_stream_t *
562 _cairo_output_stream_create_for_file (FILE *file)
564 stdio_stream_t *stream;
566 if (file == NULL) {
567 _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
568 return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
571 stream = malloc (sizeof *stream);
572 if (stream == NULL) {
573 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
574 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
577 _cairo_output_stream_init (&stream->base, stdio_write, stdio_flush);
578 stream->file = file;
580 return &stream->base;
583 cairo_output_stream_t *
584 _cairo_output_stream_create_for_filename (const char *filename)
586 stdio_stream_t *stream;
587 FILE *file;
589 if (filename == NULL)
590 return _cairo_null_stream_create ();
592 file = fopen (filename, "wb");
593 if (file == NULL) {
594 switch (errno) {
595 case ENOMEM:
596 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
597 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
598 default:
599 _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
600 return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
604 stream = malloc (sizeof *stream);
605 if (stream == NULL) {
606 fclose (file);
607 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
608 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
611 _cairo_output_stream_init (&stream->base, stdio_write, stdio_close);
612 stream->file = file;
614 return &stream->base;
618 typedef struct _memory_stream {
619 cairo_output_stream_t base;
620 cairo_array_t array;
621 } memory_stream_t;
623 static cairo_status_t
624 memory_write (cairo_output_stream_t *base,
625 const unsigned char *data, unsigned int length)
627 memory_stream_t *stream = (memory_stream_t *) base;
629 return _cairo_array_append_multiple (&stream->array, data, length);
632 static cairo_status_t
633 memory_close (cairo_output_stream_t *base)
635 memory_stream_t *stream = (memory_stream_t *) base;
637 _cairo_array_fini (&stream->array);
639 return CAIRO_STATUS_SUCCESS;
642 cairo_output_stream_t *
643 _cairo_memory_stream_create (void)
645 memory_stream_t *stream;
647 stream = malloc (sizeof *stream);
648 if (stream == NULL) {
649 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
650 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
653 _cairo_output_stream_init (&stream->base, memory_write, memory_close);
654 _cairo_array_init (&stream->array, 1);
656 return &stream->base;
659 void
660 _cairo_memory_stream_copy (cairo_output_stream_t *base,
661 cairo_output_stream_t *dest)
663 memory_stream_t *stream = (memory_stream_t *) base;
665 if (dest->status)
666 return;
668 if (base->status) {
669 dest->status = base->status;
670 return;
673 _cairo_output_stream_write (dest,
674 _cairo_array_index (&stream->array, 0),
675 _cairo_array_num_elements (&stream->array));
679 _cairo_memory_stream_length (cairo_output_stream_t *base)
681 memory_stream_t *stream = (memory_stream_t *) base;
683 return _cairo_array_num_elements (&stream->array);
686 static cairo_status_t
687 null_write (cairo_output_stream_t *base,
688 const unsigned char *data, unsigned int length)
690 return CAIRO_STATUS_SUCCESS;
693 cairo_output_stream_t *
694 _cairo_null_stream_create (void)
696 cairo_output_stream_t *stream;
698 stream = malloc (sizeof *stream);
699 if (stream == NULL) {
700 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
701 return (cairo_output_stream_t *) &_cairo_output_stream_nil;
704 _cairo_output_stream_init (stream, null_write, NULL);
706 return stream;