Coverage Report

Created: 2025-07-07 10:01

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