Subversion Repositories Scribus

Rev

Rev 14952 | Details | Compare with Previous | Last modification | View Log | RSS feed

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