Coverage Report

Created: 2026-08-14 08:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cairo/src/cairo-output-stream.c
Line
Count
Source
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
637k
#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
2.27M
#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
546k
{
78
546k
    stream->write_func = write_func;
79
546k
    stream->flush_func = flush_func;
80
546k
    stream->close_func = close_func;
81
546k
    stream->position = 0;
82
546k
    stream->status = CAIRO_STATUS_SUCCESS;
83
546k
    stream->closed = FALSE;
84
546k
}
85
86
cairo_status_t
87
_cairo_output_stream_fini (cairo_output_stream_t *stream)
88
546k
{
89
546k
    return _cairo_output_stream_close (stream);
90
546k
}
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
2.64M
{
122
2.64M
    cairo_output_stream_with_closure_t *stream_with_closure =
123
2.64M
  (cairo_output_stream_with_closure_t *) stream;
124
125
2.64M
    if (stream_with_closure->write_func == NULL)
126
0
  return CAIRO_STATUS_SUCCESS;
127
128
2.64M
    return stream_with_closure->write_func (stream_with_closure->closure,
129
2.64M
              data, length);
130
2.64M
}
131
132
static cairo_status_t
133
closure_close (cairo_output_stream_t *stream)
134
832
{
135
832
    cairo_output_stream_with_closure_t *stream_with_closure =
136
832
  (cairo_output_stream_with_closure_t *) stream;
137
138
832
    if (stream_with_closure->close_func != NULL)
139
0
  return stream_with_closure->close_func (stream_with_closure->closure);
140
832
    else
141
832
  return CAIRO_STATUS_SUCCESS;
142
832
}
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
832
{
149
832
    cairo_output_stream_with_closure_t *stream;
150
151
832
    stream = _cairo_calloc (sizeof (cairo_output_stream_with_closure_t));
152
832
    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
832
    _cairo_output_stream_init (&stream->base,
158
832
             closure_write, NULL, closure_close);
159
832
    stream->write_func = write_func;
160
832
    stream->close_func = close_func;
161
832
    stream->closure = closure;
162
163
832
    return &stream->base;
164
832
}
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_calloc (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
546k
{
216
546k
    cairo_status_t status;
217
218
546k
    if (stream->closed)
219
0
  return stream->status;
220
221
546k
    if (stream == &_cairo_output_stream_nil ||
222
546k
  stream == &_cairo_output_stream_nil_write_error)
223
0
    {
224
0
  return stream->status;
225
0
    }
226
227
546k
    if (stream->close_func) {
228
546k
  status = stream->close_func (stream);
229
  /* Don't overwrite a pre-existing status failure. */
230
546k
  if (stream->status == CAIRO_STATUS_SUCCESS)
231
546k
      stream->status = status;
232
546k
    }
233
234
546k
    stream->closed = TRUE;
235
236
546k
    return stream->status;
237
546k
}
238
239
cairo_status_t
240
_cairo_output_stream_destroy (cairo_output_stream_t *stream)
241
546k
{
242
546k
    cairo_status_t status;
243
244
546k
    assert (stream != NULL);
245
246
546k
    if (stream == &_cairo_output_stream_nil ||
247
546k
  stream == &_cairo_output_stream_nil_write_error)
248
0
    {
249
0
  return stream->status;
250
0
    }
251
252
546k
    status = _cairo_output_stream_fini (stream);
253
546k
    free (stream);
254
255
546k
    return status;
256
546k
}
257
258
void
259
_cairo_output_stream_write (cairo_output_stream_t *stream,
260
          const void *data, size_t length)
261
54.1M
{
262
54.1M
    if (length == 0 || stream->status)
263
6.81M
  return;
264
265
47.2M
    if (stream->closed) {
266
0
  stream->status = CAIRO_STATUS_WRITE_ERROR;
267
0
  return;
268
0
    }
269
270
47.2M
    stream->status = stream->write_func (stream, data, length);
271
47.2M
    stream->position += length;
272
47.2M
}
273
274
void
275
_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
276
               const unsigned char *data,
277
               size_t length)
278
0
{
279
0
    const char hex_chars[] = "0123456789abcdef";
280
0
    char buffer[2];
281
0
    unsigned int i, column;
282
283
0
    for (i = 0, column = 0; i < length; i++, column++) {
284
0
  if (column == 38) {
285
0
      _cairo_output_stream_write (stream, "\n", 1);
286
0
      column = 0;
287
0
  }
288
0
  buffer[0] = hex_chars[(data[i] >> 4) & 0x0f];
289
0
  buffer[1] = hex_chars[data[i] & 0x0f];
290
0
  _cairo_output_stream_write (stream, buffer, 2);
291
0
    }
292
0
}
293
294
/* Format a double in a locale independent way and trim trailing
295
 * zeros.  Based on code from Alex Larson <alexl@redhat.com>.
296
 * https://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
297
 *
298
 * The code in the patch is copyright Red Hat, Inc under the LGPL, but
299
 * has been relicensed under the LGPL/MPL dual license for inclusion
300
 * into cairo (see COPYING). -- Kristian Høgsberg <krh@redhat.com>
301
 */
302
static void
303
_cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precision)
304
4.22M
{
305
4.22M
    const char *decimal_point;
306
4.22M
    int decimal_point_len;
307
4.22M
    char *p;
308
4.22M
    int decimal_len;
309
4.22M
    int num_zeros, decimal_digits;
310
311
    /* Omit the minus sign from negative zero. */
312
4.22M
    if (d == 0.0)
313
572k
  d = 0.0;
314
315
4.22M
    decimal_point = _cairo_get_locale_decimal_point ();
316
4.22M
    decimal_point_len = strlen (decimal_point);
317
318
4.22M
    assert (decimal_point_len != 0);
319
320
4.22M
    if (limited_precision) {
321
2.27M
  snprintf (buffer, size, "%.*f", FIXED_POINT_DECIMAL_DIGITS, d);
322
2.27M
    } else {
323
  /* Using "%f" to print numbers less than 0.1 will result in
324
   * reduced precision due to the default 6 digits after the
325
   * decimal point.
326
   *
327
   * For numbers is < 0.1, we print with maximum precision and count
328
   * the number of zeros between the decimal point and the first
329
   * significant digit. We then print the number again with the
330
   * number of decimal places that gives us the required number of
331
   * significant digits. This ensures the number is correctly
332
   * rounded.
333
   */
334
1.95M
  if (fabs (d) >= 0.1) {
335
1.31M
      snprintf (buffer, size, "%f", d);
336
1.31M
  } else {
337
637k
      snprintf (buffer, size, "%.18f", d);
338
637k
      p = buffer;
339
340
637k
      if (*p == '+' || *p == '-')
341
3.86k
    p++;
342
343
1.27M
      while (_cairo_isdigit (*p))
344
637k
    p++;
345
346
637k
      if (strncmp (p, decimal_point, decimal_point_len) == 0)
347
637k
    p += decimal_point_len;
348
349
637k
      num_zeros = 0;
350
10.9M
      while (*p++ == '0')
351
10.3M
    num_zeros++;
352
353
637k
      decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL;
354
355
637k
      if (decimal_digits < 18)
356
68.3k
    snprintf (buffer, size, "%.*f", decimal_digits, d);
357
637k
  }
358
1.95M
    }
359
4.22M
    p = buffer;
360
361
4.22M
    if (*p == '+' || *p == '-')
362
310k
  p++;
363
364
13.2M
    while (_cairo_isdigit (*p))
365
9.05M
  p++;
366
367
4.22M
    if (strncmp (p, decimal_point, decimal_point_len) == 0) {
368
4.22M
  *p = '.';
369
4.22M
  decimal_len = strlen (p + decimal_point_len);
370
4.22M
  memmove (p + 1, p + decimal_point_len, decimal_len);
371
4.22M
  p[1 + decimal_len] = 0;
372
373
  /* Remove trailing zeros and decimal point if possible. */
374
17.7M
  for (p = p + decimal_len; *p == '0'; p--)
375
13.5M
      *p = 0;
376
377
4.22M
  if (*p == '.') {
378
955k
      *p = 0;
379
955k
      p--;
380
955k
  }
381
4.22M
    }
382
4.22M
}
383
384
enum {
385
    LENGTH_MODIFIER_LONG = 0x100,
386
    LENGTH_MODIFIER_LONG_LONG = 0x200
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
12.2M
{
401
12.2M
#define SINGLE_FMT_BUFFER_SIZE 32
402
12.2M
    char buffer[512], single_fmt[SINGLE_FMT_BUFFER_SIZE];
403
12.2M
    int single_fmt_length;
404
12.2M
    char *p;
405
12.2M
    const char *f, *start;
406
12.2M
    int length_modifier, width;
407
12.2M
    cairo_bool_t var_width;
408
409
12.2M
    f = fmt;
410
12.2M
    p = buffer;
411
64.5M
    while (*f != '\0') {
412
52.3M
  if (p == buffer + sizeof (buffer)) {
413
0
      _cairo_output_stream_write (stream, buffer, sizeof (buffer));
414
0
      p = buffer;
415
0
  }
416
417
52.3M
  if (*f != '%') {
418
39.2M
      *p++ = *f++;
419
39.2M
      continue;
420
39.2M
  }
421
422
13.1M
  start = f;
423
13.1M
  f++;
424
425
13.1M
  if (*f == '0')
426
1.17M
      f++;
427
428
13.1M
        var_width = FALSE;
429
13.1M
        if (*f == '*') {
430
909k
            var_width = TRUE;
431
909k
      f++;
432
909k
        }
433
434
13.3M
  while (_cairo_isdigit (*f))
435
262k
      f++;
436
437
13.1M
  length_modifier = 0;
438
13.1M
  if (*f == 'l') {
439
91.7k
      length_modifier = LENGTH_MODIFIER_LONG;
440
91.7k
      f++;
441
91.7k
      if (*f == 'l') {
442
53.5k
    length_modifier = LENGTH_MODIFIER_LONG_LONG;
443
53.5k
    f++;
444
53.5k
      }
445
91.7k
  }
446
447
  /* The only format strings exist in the cairo implementation
448
   * itself. So there's an internal consistency problem if any
449
   * of them is larger than our format buffer size. */
450
13.1M
  single_fmt_length = f - start + 1;
451
13.1M
  assert (single_fmt_length + 1 <= SINGLE_FMT_BUFFER_SIZE);
452
453
  /* Reuse the format string for this conversion. */
454
13.1M
  memcpy (single_fmt, start, single_fmt_length);
455
13.1M
  single_fmt[single_fmt_length] = '\0';
456
457
  /* Flush contents of buffer before snprintf()'ing into it. */
458
13.1M
  _cairo_output_stream_write (stream, buffer, p - buffer);
459
460
  /* We group signed and unsigned together in this switch, the
461
   * only thing that matters here is the size of the arguments,
462
   * since we're just passing the data through to sprintf(). */
463
13.1M
  switch (*f | length_modifier) {
464
10.5k
  case '%':
465
10.5k
      buffer[0] = *f;
466
10.5k
      buffer[1] = 0;
467
10.5k
      break;
468
3.74M
  case 'd':
469
3.75M
  case 'u':
470
3.78M
  case 'o':
471
4.92M
  case 'x':
472
4.92M
  case 'X':
473
4.92M
            if (var_width) {
474
909k
                width = va_arg (ap, int);
475
909k
                snprintf (buffer, sizeof buffer,
476
909k
                          single_fmt, width, va_arg (ap, int));
477
4.01M
            } else {
478
4.01M
                snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int));
479
4.01M
            }
480
4.92M
      break;
481
33.0k
  case 'd' | LENGTH_MODIFIER_LONG:
482
38.1k
  case 'u' | LENGTH_MODIFIER_LONG:
483
38.1k
  case 'o' | LENGTH_MODIFIER_LONG:
484
38.1k
  case 'x' | LENGTH_MODIFIER_LONG:
485
38.1k
  case 'X' | LENGTH_MODIFIER_LONG:
486
38.1k
            if (var_width) {
487
0
                width = va_arg (ap, int);
488
0
                snprintf (buffer, sizeof buffer,
489
0
                          single_fmt, width, va_arg (ap, long int));
490
38.1k
            } else {
491
38.1k
                snprintf (buffer, sizeof buffer,
492
38.1k
                          single_fmt, va_arg (ap, long int));
493
38.1k
            }
494
38.1k
      break;
495
53.5k
  case 'd' | LENGTH_MODIFIER_LONG_LONG:
496
53.5k
  case 'u' | LENGTH_MODIFIER_LONG_LONG:
497
53.5k
  case 'o' | LENGTH_MODIFIER_LONG_LONG:
498
53.5k
  case 'x' | LENGTH_MODIFIER_LONG_LONG:
499
53.5k
  case 'X' | LENGTH_MODIFIER_LONG_LONG:
500
53.5k
      if (var_width) {
501
0
    width = va_arg (ap, int);
502
0
    snprintf (buffer, sizeof buffer,
503
0
        single_fmt, width, va_arg (ap, long long int));
504
53.5k
      } else {
505
53.5k
    snprintf (buffer, sizeof buffer,
506
53.5k
        single_fmt, va_arg (ap, long long int));
507
53.5k
      }
508
53.5k
      break;
509
819k
  case 's': {
510
      /* Write out strings as they may be larger than the buffer. */
511
819k
      const char *s = va_arg (ap, const char *);
512
819k
      int len = strlen(s);
513
819k
      _cairo_output_stream_write (stream, s, len);
514
819k
      buffer[0] = 0;
515
819k
      }
516
819k
      break;
517
1.95M
  case 'f':
518
1.95M
      _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), FALSE);
519
1.95M
      break;
520
2.27M
  case 'g':
521
2.27M
      _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), TRUE);
522
2.27M
      break;
523
3.04M
  case 'c':
524
3.04M
      buffer[0] = va_arg (ap, int);
525
3.04M
      buffer[1] = 0;
526
3.04M
      break;
527
0
  default:
528
0
      ASSERT_NOT_REACHED;
529
13.1M
  }
530
13.1M
  p = buffer + strlen (buffer);
531
13.1M
  f++;
532
13.1M
    }
533
534
12.2M
    _cairo_output_stream_write (stream, buffer, p - buffer);
535
12.2M
}
536
537
void
538
_cairo_output_stream_printf (cairo_output_stream_t *stream,
539
           const char *fmt, ...)
540
12.2M
{
541
12.2M
    va_list ap;
542
543
12.2M
    va_start (ap, fmt);
544
545
12.2M
    _cairo_output_stream_vprintf (stream, fmt, ap);
546
547
12.2M
    va_end (ap);
548
12.2M
}
549
550
/* Matrix elements that are smaller than the value of the largest element * MATRIX_ROUNDING_TOLERANCE
551
 * are rounded down to zero. */
552
91.3k
#define MATRIX_ROUNDING_TOLERANCE 1e-12
553
554
void
555
_cairo_output_stream_print_matrix (cairo_output_stream_t *stream,
556
           const cairo_matrix_t  *matrix)
557
91.3k
{
558
91.3k
    cairo_matrix_t m;
559
91.3k
    double s, e;
560
561
91.3k
    m = *matrix;
562
91.3k
    s = fabs (m.xx);
563
91.3k
    if (fabs (m.xy) > s)
564
576
  s = fabs (m.xy);
565
91.3k
    if (fabs (m.yx) > s)
566
141
  s = fabs (m.yx);
567
91.3k
    if (fabs (m.yy) > s)
568
27.1k
  s = fabs (m.yy);
569
570
91.3k
    e = s * MATRIX_ROUNDING_TOLERANCE;
571
91.3k
    if (fabs(m.xx) < e)
572
467
  m.xx = 0;
573
91.3k
    if (fabs(m.xy) < e)
574
90.6k
  m.xy = 0;
575
91.3k
    if (fabs(m.yx) < e)
576
90.6k
  m.yx = 0;
577
91.3k
    if (fabs(m.yy) < e)
578
340
  m.yy = 0;
579
91.3k
    if (fabs(m.x0) < e)
580
15.5k
  m.x0 = 0;
581
91.3k
    if (fabs(m.y0) < e)
582
14.8k
  m.y0 = 0;
583
584
91.3k
    _cairo_output_stream_printf (stream,
585
91.3k
         "%f %f %f %f %f %f",
586
91.3k
         m.xx, m.yx, m.xy, m.yy, m.x0, m.y0);
587
91.3k
}
588
589
long long
590
_cairo_output_stream_get_position (cairo_output_stream_t *stream)
591
340k
{
592
340k
    return stream->position;
593
340k
}
594
595
cairo_status_t
596
_cairo_output_stream_get_status (cairo_output_stream_t *stream)
597
48.6M
{
598
48.6M
    return stream->status;
599
48.6M
}
600
601
/* Maybe this should be a configure time option, so embedded targets
602
 * don't have to pull in stdio. */
603
604
605
typedef struct _stdio_stream {
606
    cairo_output_stream_t  base;
607
    FILE      *file;
608
} stdio_stream_t;
609
610
static cairo_status_t
611
stdio_write (cairo_output_stream_t *base,
612
       const unsigned char *data, unsigned int length)
613
2.23M
{
614
2.23M
    stdio_stream_t *stream = (stdio_stream_t *) base;
615
616
2.23M
    if (fwrite (data, 1, length, stream->file) != length)
617
0
  return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
618
619
2.23M
    return CAIRO_STATUS_SUCCESS;
620
2.23M
}
621
622
static cairo_status_t
623
stdio_flush (cairo_output_stream_t *base)
624
1.68k
{
625
1.68k
    stdio_stream_t *stream = (stdio_stream_t *) base;
626
627
1.68k
    fflush (stream->file);
628
629
1.68k
    if (ferror (stream->file))
630
0
  return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
631
1.68k
    else
632
1.68k
  return CAIRO_STATUS_SUCCESS;
633
1.68k
}
634
635
static cairo_status_t
636
stdio_close (cairo_output_stream_t *base)
637
1.68k
{
638
1.68k
    cairo_status_t status;
639
1.68k
    stdio_stream_t *stream = (stdio_stream_t *) base;
640
641
1.68k
    status = stdio_flush (base);
642
643
1.68k
    fclose (stream->file);
644
645
1.68k
    return status;
646
1.68k
}
647
648
cairo_output_stream_t *
649
_cairo_output_stream_create_for_file (FILE *file)
650
0
{
651
0
    stdio_stream_t *stream;
652
653
0
    if (file == NULL) {
654
0
  _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
655
0
  return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
656
0
    }
657
658
0
    stream = _cairo_calloc (sizeof *stream);
659
0
    if (unlikely (stream == NULL)) {
660
0
  _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
661
0
  return (cairo_output_stream_t *) &_cairo_output_stream_nil;
662
0
    }
663
664
0
    _cairo_output_stream_init (&stream->base,
665
0
             stdio_write, stdio_flush, stdio_flush);
666
0
    stream->file = file;
667
668
0
    return &stream->base;
669
0
}
670
671
cairo_output_stream_t *
672
_cairo_output_stream_create_for_filename (const char *filename)
673
1.68k
{
674
1.68k
    stdio_stream_t *stream;
675
1.68k
    FILE *file;
676
1.68k
    cairo_status_t status;
677
678
1.68k
    if (filename == NULL)
679
0
  return _cairo_null_stream_create ();
680
681
1.68k
    status = _cairo_fopen (filename, "wb", &file);
682
683
1.68k
    if (status != CAIRO_STATUS_SUCCESS)
684
0
  return _cairo_output_stream_create_in_error (status);
685
686
1.68k
    if (file == NULL) {
687
0
  switch (errno) {
688
0
  case ENOMEM:
689
0
      _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
690
0
      return (cairo_output_stream_t *) &_cairo_output_stream_nil;
691
0
  default:
692
0
      _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
693
0
      return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
694
0
  }
695
0
    }
696
697
1.68k
    stream = _cairo_calloc (sizeof *stream);
698
1.68k
    if (unlikely (stream == NULL)) {
699
0
  fclose (file);
700
0
  _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
701
0
  return (cairo_output_stream_t *) &_cairo_output_stream_nil;
702
0
    }
703
704
1.68k
    _cairo_output_stream_init (&stream->base,
705
1.68k
             stdio_write, stdio_flush, stdio_close);
706
1.68k
    stream->file = file;
707
708
1.68k
    return &stream->base;
709
1.68k
}
710
711
712
typedef struct _memory_stream {
713
    cairo_output_stream_t base;
714
    cairo_array_t   array;
715
} memory_stream_t;
716
717
static cairo_status_t
718
memory_write (cairo_output_stream_t *base,
719
        const unsigned char *data, unsigned int length)
720
629k
{
721
629k
    memory_stream_t *stream = (memory_stream_t *) base;
722
723
629k
    return _cairo_array_append_multiple (&stream->array, data, length);
724
629k
}
725
726
static cairo_status_t
727
memory_close (cairo_output_stream_t *base)
728
17.9k
{
729
17.9k
    memory_stream_t *stream = (memory_stream_t *) base;
730
731
17.9k
    _cairo_array_fini (&stream->array);
732
733
17.9k
    return CAIRO_STATUS_SUCCESS;
734
17.9k
}
735
736
cairo_output_stream_t *
737
_cairo_memory_stream_create (void)
738
17.9k
{
739
17.9k
    memory_stream_t *stream;
740
741
17.9k
    stream = _cairo_calloc (sizeof *stream);
742
17.9k
    if (unlikely (stream == NULL)) {
743
0
  _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
744
0
  return (cairo_output_stream_t *) &_cairo_output_stream_nil;
745
0
    }
746
747
17.9k
    _cairo_output_stream_init (&stream->base, memory_write, NULL, memory_close);
748
17.9k
    _cairo_array_init (&stream->array, 1);
749
750
17.9k
    return &stream->base;
751
17.9k
}
752
753
cairo_status_t
754
_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
755
            unsigned char **data_out,
756
            unsigned long *length_out)
757
2.07k
{
758
2.07k
    memory_stream_t *stream;
759
2.07k
    cairo_status_t status;
760
761
2.07k
    status = abstract_stream->status;
762
2.07k
    if (unlikely (status))
763
0
  return _cairo_output_stream_destroy (abstract_stream);
764
765
2.07k
    stream = (memory_stream_t *) abstract_stream;
766
767
2.07k
    *length_out = _cairo_array_num_elements (&stream->array);
768
2.07k
    *data_out = _cairo_calloc (*length_out);
769
2.07k
    if (unlikely (*data_out == NULL)) {
770
0
  status = _cairo_output_stream_destroy (abstract_stream);
771
0
  assert (status == CAIRO_STATUS_SUCCESS);
772
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
773
0
    }
774
2.07k
    memcpy (*data_out, _cairo_array_index (&stream->array, 0), *length_out);
775
776
2.07k
    return _cairo_output_stream_destroy (abstract_stream);
777
2.07k
}
778
779
void
780
_cairo_memory_stream_copy (cairo_output_stream_t *base,
781
         cairo_output_stream_t *dest)
782
15.8k
{
783
15.8k
    memory_stream_t *stream = (memory_stream_t *) base;
784
785
15.8k
    if (base->status) {
786
0
  dest->status = base->status;
787
0
  return;
788
0
    }
789
790
15.8k
    _cairo_output_stream_write (dest,
791
15.8k
        _cairo_array_index (&stream->array, 0),
792
15.8k
        _cairo_array_num_elements (&stream->array));
793
15.8k
}
794
795
int
796
_cairo_memory_stream_length (cairo_output_stream_t *base)
797
7.99k
{
798
7.99k
    memory_stream_t *stream = (memory_stream_t *) base;
799
800
7.99k
    return _cairo_array_num_elements (&stream->array);
801
7.99k
}
802
803
static cairo_status_t
804
null_write (cairo_output_stream_t *base,
805
      const unsigned char *data, unsigned int length)
806
0
{
807
0
    return CAIRO_STATUS_SUCCESS;
808
0
}
809
810
cairo_output_stream_t *
811
_cairo_null_stream_create (void)
812
0
{
813
0
    cairo_output_stream_t *stream;
814
815
0
    stream = _cairo_calloc (sizeof *stream);
816
0
    if (unlikely (stream == NULL)) {
817
0
  _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
818
0
  return (cairo_output_stream_t *) &_cairo_output_stream_nil;
819
0
    }
820
821
0
    _cairo_output_stream_init (stream, null_write, NULL, NULL);
822
823
0
    return stream;
824
0
}