Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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