LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-output-stream.c (source / functions) Found Hit Coverage
Test: app.info Lines: 291 0 0.0 %
Date: 2012-06-02 Functions: 29 0 0.0 %

       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                 : }

Generated by: LCOV version 1.7