Rev 1892 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1892 | serge | 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 |
||
34 | */ |
||
35 | |||
3959 | Serge | 36 | |
37 | //#define _BSD_SOURCE /* for snprintf() */ |
||
1892 | serge | 38 | #include "cairoint.h" |
39 | |||
40 | #include "cairo-output-stream-private.h" |
||
3959 | Serge | 41 | |
42 | #include "cairo-array-private.h" |
||
1892 | serge | 43 | #include "cairo-error-private.h" |
44 | #include "cairo-compiler-private.h" |
||
45 | |||
46 | #include |
||
47 | #include |
||
48 | #include |
||
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 | * |
||
65 | * FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) ) |
||
66 | * |
||
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 |
||
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 |
||
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) { |
||
3959 | Serge | 325 | snprintf (buffer, size, "%.*f", FIXED_POINT_DECIMAL_DIGITS, d); |
1892 | serge | 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 | }=>>>> |