LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-output-stream.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 291 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 29 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* cairo-output-stream.c: Output stream abstraction
       2             :  *
       3             :  * Copyright © 2005 Red Hat, Inc
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or
       6             :  * modify it either under the terms of the GNU Lesser General Public
       7             :  * License version 2.1 as published by the Free Software Foundation
       8             :  * (the "LGPL") or, at your option, under the terms of the Mozilla
       9             :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      10             :  * notice, a recipient may use your version of this file under either
      11             :  * the MPL or the LGPL.
      12             :  *
      13             :  * You should have received a copy of the LGPL along with this library
      14             :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      15             :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      16             :  * You should have received a copy of the MPL along with this library
      17             :  * in the file COPYING-MPL-1.1
      18             :  *
      19             :  * The contents of this file are subject to the Mozilla Public License
      20             :  * Version 1.1 (the "License"); you may not use this file except in
      21             :  * compliance with the License. You may obtain a copy of the License at
      22             :  * http://www.mozilla.org/MPL/
      23             :  *
      24             :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      25             :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      26             :  * the specific language governing rights and limitations.
      27             :  *
      28             :  * The Original Code is the cairo graphics library.
      29             :  *
      30             :  * The Initial Developer of the Original Code is Red Hat, Inc.
      31             :  *
      32             :  * Author(s):
      33             :  *      Kristian Høgsberg <krh@redhat.com>
      34             :  */
      35             : 
      36             : #define _BSD_SOURCE /* for snprintf() */
      37             : #include "cairoint.h"
      38             : 
      39             : #include "cairo-output-stream-private.h"
      40             : #include "cairo-error-private.h"
      41             : #include "cairo-compiler-private.h"
      42             : 
      43             : #include <stdio.h>
      44             : #include <locale.h>
      45             : #include <errno.h>
      46             : 
      47             : /* Numbers printed with %f are printed with this number of significant
      48             :  * digits after the decimal.
      49             :  */
      50             : #define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
      51             : 
      52             : /* Numbers printed with %g are assumed to only have %CAIRO_FIXED_FRAC_BITS
      53             :  * bits of precision available after the decimal point.
      54             :  *
      55             :  * FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal
      56             :  * digits after the decimal point required to preserve the available
      57             :  * precision.
      58             :  *
      59             :  * The conversion is:
      60             :  *
      61             :  * <programlisting>
      62             :  * FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) )
      63             :  * </programlisting>
      64             :  *
      65             :  * We can replace ceil(x) with (int)(x+1) since x will never be an
      66             :  * integer for any likely value of %CAIRO_FIXED_FRAC_BITS.
      67             :  */
      68             : #define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1))
      69             : 
      70             : void
      71           0 : _cairo_output_stream_init (cairo_output_stream_t            *stream,
      72             :                            cairo_output_stream_write_func_t  write_func,
      73             :                            cairo_output_stream_flush_func_t  flush_func,
      74             :                            cairo_output_stream_close_func_t  close_func)
      75             : {
      76           0 :     stream->write_func = write_func;
      77           0 :     stream->flush_func = flush_func;
      78           0 :     stream->close_func = close_func;
      79           0 :     stream->position = 0;
      80           0 :     stream->status = CAIRO_STATUS_SUCCESS;
      81           0 :     stream->closed = FALSE;
      82           0 : }
      83             : 
      84             : cairo_status_t
      85           0 : _cairo_output_stream_fini (cairo_output_stream_t *stream)
      86             : {
      87           0 :     return _cairo_output_stream_close (stream);
      88             : }
      89             : 
      90             : const cairo_output_stream_t _cairo_output_stream_nil = {
      91             :     NULL, /* write_func */
      92             :     NULL, /* flush_func */
      93             :     NULL, /* close_func */
      94             :     0,    /* position */
      95             :     CAIRO_STATUS_NO_MEMORY,
      96             :     FALSE /* closed */
      97             : };
      98             : 
      99             : static const cairo_output_stream_t _cairo_output_stream_nil_write_error = {
     100             :     NULL, /* write_func */
     101             :     NULL, /* flush_func */
     102             :     NULL, /* close_func */
     103             :     0,    /* position */
     104             :     CAIRO_STATUS_WRITE_ERROR,
     105             :     FALSE /* closed */
     106             : };
     107             : 
     108             : typedef struct _cairo_output_stream_with_closure {
     109             :     cairo_output_stream_t        base;
     110             :     cairo_write_func_t           write_func;
     111             :     cairo_close_func_t           close_func;
     112             :     void                        *closure;
     113             : } cairo_output_stream_with_closure_t;
     114             : 
     115             : 
     116             : static cairo_status_t
     117           0 : closure_write (cairo_output_stream_t *stream,
     118             :                const unsigned char *data, unsigned int length)
     119             : {
     120           0 :     cairo_output_stream_with_closure_t *stream_with_closure =
     121             :         (cairo_output_stream_with_closure_t *) stream;
     122             : 
     123           0 :     if (stream_with_closure->write_func == NULL)
     124           0 :         return CAIRO_STATUS_SUCCESS;
     125             : 
     126           0 :     return stream_with_closure->write_func (stream_with_closure->closure,
     127             :                                             data, length);
     128             : }
     129             : 
     130             : static cairo_status_t
     131           0 : closure_close (cairo_output_stream_t *stream)
     132             : {
     133           0 :     cairo_output_stream_with_closure_t *stream_with_closure =
     134             :         (cairo_output_stream_with_closure_t *) stream;
     135             : 
     136           0 :     if (stream_with_closure->close_func != NULL)
     137           0 :         return stream_with_closure->close_func (stream_with_closure->closure);
     138             :     else
     139           0 :         return CAIRO_STATUS_SUCCESS;
     140             : }
     141             : 
     142             : cairo_output_stream_t *
     143           0 : _cairo_output_stream_create (cairo_write_func_t         write_func,
     144             :                              cairo_close_func_t         close_func,
     145             :                              void                       *closure)
     146             : {
     147             :     cairo_output_stream_with_closure_t *stream;
     148             : 
     149           0 :     stream = malloc (sizeof (cairo_output_stream_with_closure_t));
     150           0 :     if (unlikely (stream == NULL)) {
     151           0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     152           0 :         return (cairo_output_stream_t *) &_cairo_output_stream_nil;
     153             :     }
     154             : 
     155           0 :     _cairo_output_stream_init (&stream->base,
     156             :                                closure_write, NULL, closure_close);
     157           0 :     stream->write_func = write_func;
     158           0 :     stream->close_func = close_func;
     159           0 :     stream->closure = closure;
     160             : 
     161           0 :     return &stream->base;
     162             : }
     163             : 
     164             : cairo_output_stream_t *
     165           0 : _cairo_output_stream_create_in_error (cairo_status_t status)
     166             : {
     167             :     cairo_output_stream_t *stream;
     168             : 
     169             :     /* check for the common ones */
     170           0 :     if (status == CAIRO_STATUS_NO_MEMORY)
     171           0 :         return (cairo_output_stream_t *) &_cairo_output_stream_nil;
     172           0 :     if (status == CAIRO_STATUS_WRITE_ERROR)
     173           0 :         return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
     174             : 
     175           0 :     stream = malloc (sizeof (cairo_output_stream_t));
     176           0 :     if (unlikely (stream == NULL)) {
     177           0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     178           0 :         return (cairo_output_stream_t *) &_cairo_output_stream_nil;
     179             :     }
     180             : 
     181           0 :     _cairo_output_stream_init (stream, NULL, NULL, NULL);
     182           0 :     stream->status = status;
     183             : 
     184           0 :     return stream;
     185             : }
     186             : 
     187             : cairo_status_t
     188           0 : _cairo_output_stream_flush (cairo_output_stream_t *stream)
     189             : {
     190             :     cairo_status_t status;
     191             : 
     192           0 :     if (stream->closed)
     193           0 :         return stream->status;
     194             : 
     195           0 :     if (stream == &_cairo_output_stream_nil ||
     196             :         stream == &_cairo_output_stream_nil_write_error)
     197             :     {
     198           0 :         return stream->status;
     199             :     }
     200             : 
     201           0 :     if (stream->flush_func) {
     202           0 :         status = stream->flush_func (stream);
     203             :         /* Don't overwrite a pre-existing status failure. */
     204           0 :         if (stream->status == CAIRO_STATUS_SUCCESS)
     205           0 :             stream->status = status;
     206             :     }
     207             : 
     208           0 :     return stream->status;
     209             : }
     210             : 
     211             : cairo_status_t
     212           0 : _cairo_output_stream_close (cairo_output_stream_t *stream)
     213             : {
     214             :     cairo_status_t status;
     215             : 
     216           0 :     if (stream->closed)
     217           0 :         return stream->status;
     218             : 
     219           0 :     if (stream == &_cairo_output_stream_nil ||
     220             :         stream == &_cairo_output_stream_nil_write_error)
     221             :     {
     222           0 :         return stream->status;
     223             :     }
     224             : 
     225           0 :     if (stream->close_func) {
     226           0 :         status = stream->close_func (stream);
     227             :         /* Don't overwrite a pre-existing status failure. */
     228           0 :         if (stream->status == CAIRO_STATUS_SUCCESS)
     229           0 :             stream->status = status;
     230             :     }
     231             : 
     232           0 :     stream->closed = TRUE;
     233             : 
     234           0 :     return stream->status;
     235             : }
     236             : 
     237             : cairo_status_t
     238           0 : _cairo_output_stream_destroy (cairo_output_stream_t *stream)
     239             : {
     240             :     cairo_status_t status;
     241             : 
     242           0 :     assert (stream != NULL);
     243             : 
     244           0 :     if (stream == &_cairo_output_stream_nil ||
     245             :         stream == &_cairo_output_stream_nil_write_error)
     246             :     {
     247           0 :         return stream->status;
     248             :     }
     249             : 
     250           0 :     status = _cairo_output_stream_fini (stream);
     251           0 :     free (stream);
     252             : 
     253           0 :     return status;
     254             : }
     255             : 
     256             : void
     257           0 : _cairo_output_stream_write (cairo_output_stream_t *stream,
     258             :                             const void *data, size_t length)
     259             : {
     260           0 :     if (length == 0)
     261           0 :         return;
     262             : 
     263           0 :     if (stream->status)
     264           0 :         return;
     265             : 
     266           0 :     stream->status = stream->write_func (stream, data, length);
     267           0 :     stream->position += length;
     268             : }
     269             : 
     270             : void
     271           0 : _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
     272             :                                        const unsigned char *data,
     273             :                                        size_t length)
     274             : {
     275           0 :     const char hex_chars[] = "0123456789abcdef";
     276             :     char buffer[2];
     277             :     unsigned int i, column;
     278             : 
     279           0 :     if (stream->status)
     280           0 :         return;
     281             : 
     282           0 :     for (i = 0, column = 0; i < length; i++, column++) {
     283           0 :         if (column == 38) {
     284           0 :             _cairo_output_stream_write (stream, "\n", 1);
     285           0 :             column = 0;
     286             :         }
     287           0 :         buffer[0] = hex_chars[(data[i] >> 4) & 0x0f];
     288           0 :         buffer[1] = hex_chars[data[i] & 0x0f];
     289           0 :         _cairo_output_stream_write (stream, buffer, 2);
     290             :     }
     291             : }
     292             : 
     293             : /* Format a double in a locale independent way and trim trailing
     294             :  * zeros.  Based on code from Alex Larson <alexl@redhat.com>.
     295             :  * http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
     296             :  *
     297             :  * The code in the patch is copyright Red Hat, Inc under the LGPL, but
     298             :  * has been relicensed under the LGPL/MPL dual license for inclusion
     299             :  * into cairo (see COPYING). -- Kristian Høgsberg <krh@redhat.com>
     300             :  */
     301             : static void
     302           0 : _cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precision)
     303             : {
     304             :     struct lconv *locale_data;
     305             :     const char *decimal_point;
     306             :     int decimal_point_len;
     307             :     char *p;
     308             :     int decimal_len;
     309             :     int num_zeros, decimal_digits;
     310             : 
     311             :     /* Omit the minus sign from negative zero. */
     312           0 :     if (d == 0.0)
     313           0 :         d = 0.0;
     314             : 
     315             : #ifdef HAVE_LOCALECONV
     316           0 :     locale_data = localeconv ();
     317           0 :     decimal_point = locale_data->decimal_point;
     318           0 :     decimal_point_len = strlen (decimal_point);
     319             : #else
     320             :     decimal_point = ".";
     321             :     decimal_point_len = 1;
     322             : #endif
     323             : 
     324           0 :     assert (decimal_point_len != 0);
     325             : 
     326           0 :     if (limited_precision) {
     327           0 :         snprintf (buffer, size, "%.*f", FIXED_POINT_DECIMAL_DIGITS, d);
     328             :     } else {
     329             :         /* Using "%f" to print numbers less than 0.1 will result in
     330             :          * reduced precision due to the default 6 digits after the
     331             :          * decimal point.
     332             :          *
     333             :          * For numbers is < 0.1, we print with maximum precision and count
     334             :          * the number of zeros between the decimal point and the first
     335             :          * significant digit. We then print the number again with the
     336             :          * number of decimal places that gives us the required number of
     337             :          * significant digits. This ensures the number is correctly
     338             :          * rounded.
     339             :          */
     340           0 :         if (fabs (d) >= 0.1) {
     341           0 :             snprintf (buffer, size, "%f", d);
     342             :         } else {
     343           0 :             snprintf (buffer, size, "%.18f", d);
     344           0 :             p = buffer;
     345             : 
     346           0 :             if (*p == '+' || *p == '-')
     347           0 :                 p++;
     348             : 
     349           0 :             while (_cairo_isdigit (*p))
     350           0 :                 p++;
     351             : 
     352           0 :             if (strncmp (p, decimal_point, decimal_point_len) == 0)
     353           0 :                 p += decimal_point_len;
     354             : 
     355           0 :             num_zeros = 0;
     356           0 :             while (*p++ == '0')
     357           0 :                 num_zeros++;
     358             : 
     359           0 :             decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL;
     360             : 
     361           0 :             if (decimal_digits < 18)
     362           0 :                 snprintf (buffer, size, "%.*f", decimal_digits, d);
     363             :         }
     364             :     }
     365           0 :     p = buffer;
     366             : 
     367           0 :     if (*p == '+' || *p == '-')
     368           0 :         p++;
     369             : 
     370           0 :     while (_cairo_isdigit (*p))
     371           0 :         p++;
     372             : 
     373           0 :     if (strncmp (p, decimal_point, decimal_point_len) == 0) {
     374           0 :         *p = '.';
     375           0 :         decimal_len = strlen (p + decimal_point_len);
     376           0 :         memmove (p + 1, p + decimal_point_len, decimal_len);
     377           0 :         p[1 + decimal_len] = 0;
     378             : 
     379             :         /* Remove trailing zeros and decimal point if possible. */
     380           0 :         for (p = p + decimal_len; *p == '0'; p--)
     381           0 :             *p = 0;
     382             : 
     383           0 :         if (*p == '.') {
     384           0 :             *p = 0;
     385           0 :             p--;
     386             :         }
     387             :     }
     388           0 : }
     389             : 
     390             : enum {
     391             :     LENGTH_MODIFIER_LONG = 0x100
     392             : };
     393             : 
     394             : /* Here's a limited reimplementation of printf.  The reason for doing
     395             :  * this is primarily to special case handling of doubles.  We want
     396             :  * locale independent formatting of doubles and we want to trim
     397             :  * trailing zeros.  This is handled by dtostr() above, and the code
     398             :  * below handles everything else by calling snprintf() to do the
     399             :  * formatting.  This functionality is only for internal use and we
     400             :  * only implement the formats we actually use.
     401             :  */
     402             : void
     403           0 : _cairo_output_stream_vprintf (cairo_output_stream_t *stream,
     404             :                               const char *fmt, va_list ap)
     405             : {
     406             : #define SINGLE_FMT_BUFFER_SIZE 32
     407             :     char buffer[512], single_fmt[SINGLE_FMT_BUFFER_SIZE];
     408             :     int single_fmt_length;
     409             :     char *p;
     410             :     const char *f, *start;
     411             :     int length_modifier, width;
     412             :     cairo_bool_t var_width;
     413             : 
     414           0 :     if (stream->status)
     415           0 :         return;
     416             : 
     417           0 :     f = fmt;
     418           0 :     p = buffer;
     419           0 :     while (*f != '\0') {
     420           0 :         if (p == buffer + sizeof (buffer)) {
     421           0 :             _cairo_output_stream_write (stream, buffer, sizeof (buffer));
     422           0 :             p = buffer;
     423             :         }
     424             : 
     425           0 :         if (*f != '%') {
     426           0 :             *p++ = *f++;
     427           0 :             continue;
     428             :         }
     429             : 
     430           0 :         start = f;
     431           0 :         f++;
     432             : 
     433           0 :         if (*f == '0')
     434           0 :             f++;
     435             : 
     436           0 :         var_width = FALSE;
     437           0 :         if (*f == '*') {
     438           0 :             var_width = TRUE;
     439           0 :             f++;
     440             :         }
     441             : 
     442           0 :         while (_cairo_isdigit (*f))
     443           0 :             f++;
     444             : 
     445           0 :         length_modifier = 0;
     446           0 :         if (*f == 'l') {
     447           0 :             length_modifier = LENGTH_MODIFIER_LONG;
     448           0 :             f++;
     449             :         }
     450             : 
     451             :         /* The only format strings exist in the cairo implementation
     452             :          * itself. So there's an internal consistency problem if any
     453             :          * of them is larger than our format buffer size. */
     454           0 :         single_fmt_length = f - start + 1;
     455           0 :         assert (single_fmt_length + 1 <= SINGLE_FMT_BUFFER_SIZE);
     456             : 
     457             :         /* Reuse the format string for this conversion. */
     458           0 :         memcpy (single_fmt, start, single_fmt_length);
     459           0 :         single_fmt[single_fmt_length] = '\0';
     460             : 
     461             :         /* Flush contents of buffer before snprintf()'ing into it. */
     462           0 :         _cairo_output_stream_write (stream, buffer, p - buffer);
     463             : 
     464             :         /* We group signed and unsigned together in this switch, the
     465             :          * only thing that matters here is the size of the arguments,
     466             :          * since we're just passing the data through to sprintf(). */
     467           0 :         switch (*f | length_modifier) {
     468             :         case '%':
     469           0 :             buffer[0] = *f;
     470           0 :             buffer[1] = 0;
     471           0 :             break;
     472             :         case 'd':
     473             :         case 'u':
     474             :         case 'o':
     475             :         case 'x':
     476             :         case 'X':
     477           0 :             if (var_width) {
     478           0 :                 width = va_arg (ap, int);
     479           0 :                 snprintf (buffer, sizeof buffer,
     480             :                           single_fmt, width, va_arg (ap, int));
     481             :             } else {
     482           0 :                 snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int));
     483             :             }
     484           0 :             break;
     485             :         case 'd' | LENGTH_MODIFIER_LONG:
     486             :         case 'u' | LENGTH_MODIFIER_LONG:
     487             :         case 'o' | LENGTH_MODIFIER_LONG:
     488             :         case 'x' | LENGTH_MODIFIER_LONG:
     489             :         case 'X' | LENGTH_MODIFIER_LONG:
     490           0 :             if (var_width) {
     491           0 :                 width = va_arg (ap, int);
     492           0 :                 snprintf (buffer, sizeof buffer,
     493             :                           single_fmt, width, va_arg (ap, long int));
     494             :             } else {
     495           0 :                 snprintf (buffer, sizeof buffer,
     496             :                           single_fmt, va_arg (ap, long int));
     497             :             }
     498           0 :             break;
     499             :         case 's':
     500           0 :             snprintf (buffer, sizeof buffer,
     501             :                       single_fmt, va_arg (ap, const char *));
     502           0 :             break;
     503             :         case 'f':
     504           0 :             _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), FALSE);
     505           0 :             break;
     506             :         case 'g':
     507           0 :             _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), TRUE);
     508           0 :             break;
     509             :         case 'c':
     510           0 :             buffer[0] = va_arg (ap, int);
     511           0 :             buffer[1] = 0;
     512           0 :             break;
     513             :         default:
     514           0 :             ASSERT_NOT_REACHED;
     515             :         }
     516           0 :         p = buffer + strlen (buffer);
     517           0 :         f++;
     518             :     }
     519             : 
     520           0 :     _cairo_output_stream_write (stream, buffer, p - buffer);
     521             : }
     522             : 
     523             : void
     524           0 : _cairo_output_stream_printf (cairo_output_stream_t *stream,
     525             :                              const char *fmt, ...)
     526             : {
     527             :     va_list ap;
     528             : 
     529           0 :     va_start (ap, fmt);
     530             : 
     531           0 :     _cairo_output_stream_vprintf (stream, fmt, ap);
     532             : 
     533           0 :     va_end (ap);
     534           0 : }
     535             : 
     536             : long
     537           0 : _cairo_output_stream_get_position (cairo_output_stream_t *stream)
     538             : {
     539           0 :     return stream->position;
     540             : }
     541             : 
     542             : cairo_status_t
     543           0 : _cairo_output_stream_get_status (cairo_output_stream_t *stream)
     544             : {
     545           0 :     return stream->status;
     546             : }
     547             : 
     548             : /* Maybe this should be a configure time option, so embedded targets
     549             :  * don't have to pull in stdio. */
     550             : 
     551             : 
     552             : typedef struct _stdio_stream {
     553             :     cairo_output_stream_t        base;
     554             :     FILE                        *file;
     555             : } stdio_stream_t;
     556             : 
     557             : static cairo_status_t
     558           0 : stdio_write (cairo_output_stream_t *base,
     559             :              const unsigned char *data, unsigned int length)
     560             : {
     561           0 :     stdio_stream_t *stream = (stdio_stream_t *) base;
     562             : 
     563           0 :     if (fwrite (data, 1, length, stream->file) != length)
     564           0 :         return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
     565             : 
     566           0 :     return CAIRO_STATUS_SUCCESS;
     567             : }
     568             : 
     569             : static cairo_status_t
     570           0 : stdio_flush (cairo_output_stream_t *base)
     571             : {
     572           0 :     stdio_stream_t *stream = (stdio_stream_t *) base;
     573             : 
     574           0 :     fflush (stream->file);
     575             : 
     576           0 :     if (ferror (stream->file))
     577           0 :         return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
     578             :     else
     579           0 :         return CAIRO_STATUS_SUCCESS;
     580             : }
     581             : 
     582             : static cairo_status_t
     583           0 : stdio_close (cairo_output_stream_t *base)
     584             : {
     585             :     cairo_status_t status;
     586           0 :     stdio_stream_t *stream = (stdio_stream_t *) base;
     587             : 
     588           0 :     status = stdio_flush (base);
     589             : 
     590           0 :     fclose (stream->file);
     591             : 
     592           0 :     return status;
     593             : }
     594             : 
     595             : cairo_output_stream_t *
     596           0 : _cairo_output_stream_create_for_file (FILE *file)
     597             : {
     598             :     stdio_stream_t *stream;
     599             : 
     600           0 :     if (file == NULL) {
     601           0 :         _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
     602           0 :         return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
     603             :     }
     604             : 
     605           0 :     stream = malloc (sizeof *stream);
     606           0 :     if (unlikely (stream == NULL)) {
     607           0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     608           0 :         return (cairo_output_stream_t *) &_cairo_output_stream_nil;
     609             :     }
     610             : 
     611           0 :     _cairo_output_stream_init (&stream->base,
     612             :                                stdio_write, stdio_flush, stdio_flush);
     613           0 :     stream->file = file;
     614             : 
     615           0 :     return &stream->base;
     616             : }
     617             : 
     618             : cairo_output_stream_t *
     619           0 : _cairo_output_stream_create_for_filename (const char *filename)
     620             : {
     621             :     stdio_stream_t *stream;
     622             :     FILE *file;
     623             : 
     624           0 :     if (filename == NULL)
     625           0 :         return _cairo_null_stream_create ();
     626             : 
     627           0 :     file = fopen (filename, "wb");
     628           0 :     if (file == NULL) {
     629           0 :         switch (errno) {
     630             :         case ENOMEM:
     631           0 :             _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     632           0 :             return (cairo_output_stream_t *) &_cairo_output_stream_nil;
     633             :         default:
     634           0 :             _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
     635           0 :             return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
     636             :         }
     637             :     }
     638             : 
     639           0 :     stream = malloc (sizeof *stream);
     640           0 :     if (unlikely (stream == NULL)) {
     641           0 :         fclose (file);
     642           0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     643           0 :         return (cairo_output_stream_t *) &_cairo_output_stream_nil;
     644             :     }
     645             : 
     646           0 :     _cairo_output_stream_init (&stream->base,
     647             :                                stdio_write, stdio_flush, stdio_close);
     648           0 :     stream->file = file;
     649             : 
     650           0 :     return &stream->base;
     651             : }
     652             : 
     653             : 
     654             : typedef struct _memory_stream {
     655             :     cairo_output_stream_t       base;
     656             :     cairo_array_t               array;
     657             : } memory_stream_t;
     658             : 
     659             : static cairo_status_t
     660           0 : memory_write (cairo_output_stream_t *base,
     661             :               const unsigned char *data, unsigned int length)
     662             : {
     663           0 :     memory_stream_t *stream = (memory_stream_t *) base;
     664             : 
     665           0 :     return _cairo_array_append_multiple (&stream->array, data, length);
     666             : }
     667             : 
     668             : static cairo_status_t
     669           0 : memory_close (cairo_output_stream_t *base)
     670             : {
     671           0 :     memory_stream_t *stream = (memory_stream_t *) base;
     672             : 
     673           0 :     _cairo_array_fini (&stream->array);
     674             : 
     675           0 :     return CAIRO_STATUS_SUCCESS;
     676             : }
     677             : 
     678             : cairo_output_stream_t *
     679           0 : _cairo_memory_stream_create (void)
     680             : {
     681             :     memory_stream_t *stream;
     682             : 
     683           0 :     stream = malloc (sizeof *stream);
     684           0 :     if (unlikely (stream == NULL)) {
     685           0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     686           0 :         return (cairo_output_stream_t *) &_cairo_output_stream_nil;
     687             :     }
     688             : 
     689           0 :     _cairo_output_stream_init (&stream->base, memory_write, NULL, memory_close);
     690           0 :     _cairo_array_init (&stream->array, 1);
     691             : 
     692           0 :     return &stream->base;
     693             : }
     694             : 
     695             : cairo_status_t
     696           0 : _cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
     697             :                               unsigned char **data_out,
     698             :                               unsigned long *length_out)
     699             : {
     700             :     memory_stream_t *stream;
     701             :     cairo_status_t status;
     702             : 
     703           0 :     status = abstract_stream->status;
     704           0 :     if (unlikely (status))
     705           0 :         return _cairo_output_stream_destroy (abstract_stream);
     706             : 
     707           0 :     stream = (memory_stream_t *) abstract_stream;
     708             : 
     709           0 :     *length_out = _cairo_array_num_elements (&stream->array);
     710           0 :     *data_out = malloc (*length_out);
     711           0 :     if (unlikely (*data_out == NULL)) {
     712           0 :         status = _cairo_output_stream_destroy (abstract_stream);
     713           0 :         assert (status == CAIRO_STATUS_SUCCESS);
     714           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     715             :     }
     716           0 :     memcpy (*data_out, _cairo_array_index (&stream->array, 0), *length_out);
     717             : 
     718           0 :     return _cairo_output_stream_destroy (abstract_stream);
     719             : }
     720             : 
     721             : void
     722           0 : _cairo_memory_stream_copy (cairo_output_stream_t *base,
     723             :                            cairo_output_stream_t *dest)
     724             : {
     725           0 :     memory_stream_t *stream = (memory_stream_t *) base;
     726             : 
     727           0 :     if (dest->status)
     728           0 :         return;
     729             : 
     730           0 :     if (base->status) {
     731           0 :         dest->status = base->status;
     732           0 :         return;
     733             :     }
     734             : 
     735           0 :     _cairo_output_stream_write (dest,
     736           0 :                                 _cairo_array_index (&stream->array, 0),
     737           0 :                                 _cairo_array_num_elements (&stream->array));
     738             : }
     739             : 
     740             : int
     741           0 : _cairo_memory_stream_length (cairo_output_stream_t *base)
     742             : {
     743           0 :     memory_stream_t *stream = (memory_stream_t *) base;
     744             : 
     745           0 :     return _cairo_array_num_elements (&stream->array);
     746             : }
     747             : 
     748             : static cairo_status_t
     749           0 : null_write (cairo_output_stream_t *base,
     750             :             const unsigned char *data, unsigned int length)
     751             : {
     752           0 :     return CAIRO_STATUS_SUCCESS;
     753             : }
     754             : 
     755             : cairo_output_stream_t *
     756           0 : _cairo_null_stream_create (void)
     757             : {
     758             :     cairo_output_stream_t *stream;
     759             : 
     760           0 :     stream = malloc (sizeof *stream);
     761           0 :     if (unlikely (stream == NULL)) {
     762           0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     763           0 :         return (cairo_output_stream_t *) &_cairo_output_stream_nil;
     764             :     }
     765             : 
     766           0 :     _cairo_output_stream_init (stream, null_write, NULL, NULL);
     767             : 
     768           0 :     return stream;
     769             : }

Generated by: LCOV version 1.13