diff options
author | sanine <sanine.not@pm.me> | 2022-10-12 12:03:23 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2022-10-12 12:03:23 -0500 |
commit | 530ffd0b7d3c39757b20f00716e486b5caf89aff (patch) | |
tree | 76b35fdf57317038acf6b828871f6ae25fce2ebe /libs/cairo-1.16.0/util/cairo-script/cairo-script-file.c | |
parent | 3dbe9332e47c143a237db12440f134caebd1cfbe (diff) |
add cairo
Diffstat (limited to 'libs/cairo-1.16.0/util/cairo-script/cairo-script-file.c')
-rw-r--r-- | libs/cairo-1.16.0/util/cairo-script/cairo-script-file.c | 1109 |
1 files changed, 1109 insertions, 0 deletions
diff --git a/libs/cairo-1.16.0/util/cairo-script/cairo-script-file.c b/libs/cairo-1.16.0/util/cairo-script/cairo-script-file.c new file mode 100644 index 0000000..e7c5376 --- /dev/null +++ b/libs/cairo-1.16.0/util/cairo-script/cairo-script-file.c @@ -0,0 +1,1109 @@ +/* + * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "config.h" + +#include "cairo-script-private.h" + +#include <stdio.h> +#include <limits.h> /* INT_MAX */ +#include <string.h> +#include <zlib.h> + +#if HAVE_LZO +#include <lzo/lzo2a.h> +#endif + +#define CHUNK_SIZE 32768 + +#define OWN_STREAM 0x1 + +csi_status_t +csi_file_new (csi_t *ctx, + csi_object_t *obj, + const char *path, const char *mode) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->data = NULL; + file->type = STDIO; + file->flags = OWN_STREAM; + file->src = fopen (path, mode); + if (file->src == NULL) { + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND); + } + + file->data = _csi_alloc (ctx, CHUNK_SIZE); + if (file->data == NULL) { + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + file->bp = file->data; + file->rem = 0; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +csi_status_t +csi_file_new_for_stream (csi_t *ctx, + csi_object_t *obj, + FILE *stream) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->data = NULL; + file->type = STDIO; + file->flags = 0; + file->src = stream; + if (file->src == NULL) { + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND); + } + + file->data = _csi_alloc (ctx, CHUNK_SIZE); + if (file->data == NULL) { + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + file->bp = file->data; + file->rem = 0; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +csi_status_t +csi_file_new_for_bytes (csi_t *ctx, + csi_object_t *obj, + const char *bytes, + unsigned int length) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->type = BYTES; + file->src = (uint8_t *) bytes; + file->data = (uint8_t *) bytes; + file->bp = (uint8_t *) bytes; + file->rem = length; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +csi_status_t +csi_file_new_from_string (csi_t *ctx, + csi_object_t *obj, + csi_string_t *src) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (_csi_unlikely (file == NULL)) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + if (src->deflate) { + uLongf len = src->deflate; + csi_object_t tmp_obj; + csi_string_t *tmp_str; + csi_status_t status; + + status = csi_string_new (ctx, &tmp_obj, NULL, src->deflate); + if (_csi_unlikely (status)) + return status; + + tmp_str = tmp_obj.datum.string; + switch (src->method) { + case NONE: + default: + status = _csi_error (CAIRO_STATUS_NO_MEMORY); + break; + + case ZLIB: +#if HAVE_ZLIB + if (uncompress ((Bytef *) tmp_str->string, &len, + (Bytef *) src->string, src->len) != Z_OK) +#endif + status = _csi_error (CAIRO_STATUS_NO_MEMORY); + break; + case LZO: +#if HAVE_LZO + if (lzo2a_decompress ((lzo_bytep) src->string, src->len, + (lzo_bytep) tmp_str->string, &len, + NULL)) +#endif + status = _csi_error (CAIRO_STATUS_NO_MEMORY); + break; + } + if (_csi_unlikely (status)) { + csi_string_free (ctx, tmp_str); + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return status; + } + + file->src = tmp_str; + file->data = tmp_str->string; + file->rem = tmp_str->len; + } else { + file->src = src; src->base.ref++; + file->data = src->string; + file->rem = src->len; + } + file->type = BYTES; + file->bp = file->data; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +static csi_status_t +_csi_file_new_filter (csi_t *ctx, + csi_object_t *obj, + csi_object_t *src, + const csi_filter_funcs_t *funcs, + void *data) +{ + csi_file_t *file; + csi_object_t src_file; + csi_status_t status; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->type = FILTER; + file->data = data; + file->filter = funcs; + status = csi_object_as_file (ctx, src, &src_file); + if (status) { + csi_object_free (ctx, obj); + return status; + } + file->src = src_file.datum.file; + + return CAIRO_STATUS_SUCCESS; +} + + +#if 0 +csi_status_t +csi_file_new_from_stream (csi_t *ctx, + FILE *file, + csi_object_t **out) +{ + csi_file_t *obj; + + obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE); + if (obj == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + obj->type = STDIO; + obj->src = file; + obj->data = _csi_alloc (ctx, CHUNK_SIZE); + if (obj->data == NULL) { + csi_object_free (&obj->base); + return _csi_error (CAIRO_STATUS_UNDEFINED_FILENAME_ERROR); + } + obj->bp = obj->data; + obj->rem = 0; + + *out = &obj->base; + return CAIRO_STATUS_SUCCESS; +} + +static csi_object_t * +_csi_file_new_from_procedure (csi_t *ctx, csi_object_t *src) +{ + csi_file_t *obj; + + obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE); + if (obj == NULL) + return NULL; + + obj->type = PROCEDURE; + obj->src = csi_object_reference (src); + obj->data = NULL; + + return &obj->base; +} +#endif + +typedef struct _ascii85_decode_data { + uint8_t buf[CHUNK_SIZE]; + uint8_t *bp; + short bytes_available; + short eod; +} _ascii85_decode_data_t; + +static int +_getc_skip_whitespace (csi_file_t *src) +{ + int c; + + do switch ((c = csi_file_getc (src))) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: + continue; + + default: + return c; + } while (TRUE); + + return c; +} + +static void +_ascii85_decode (csi_file_t *file) +{ + _ascii85_decode_data_t *data = file->data; + unsigned int n; + + if (data->eod) + return; + + data->bp = data->buf; + + n = 0; + do { + unsigned int v = _getc_skip_whitespace (file->src); + if (v == 'z') { + data->buf[n+0] = 0; + data->buf[n+1] = 0; + data->buf[n+2] = 0; + data->buf[n+3] = 0; + } else if (v == '~') { + _getc_skip_whitespace (file->src); /* == '>' || IO_ERROR */ + data->eod = TRUE; + break; + } else if (v < '!' || v > 'u') { + /* IO_ERROR */ + data->eod = TRUE; + break; + } else { + unsigned int i; + + v -= '!'; + for (i = 1; i < 5; i++) { + int c = _getc_skip_whitespace (file->src); + if (c == '~') { /* short tuple */ + _getc_skip_whitespace (file->src); /* == '>' || IO_ERROR */ + data->eod = TRUE; + switch (i) { + case 0: + case 1: + /* IO_ERROR */ + break; + case 2: + v = v * (85*85*85) + 85*85*85 -1; + goto odd1; + case 3: + v = v * (85*85) + 85*85 -1; + goto odd2; + case 4: + v = v * 85 + 84; + data->buf[n+2] = v >> 8 & 0xff; +odd2: + data->buf[n+1] = v >> 16 & 0xff; +odd1: + data->buf[n+0] = v >> 24 & 0xff; + data->bytes_available = n + i - 1; + return; + } + break; + } + v = 85*v + c-'!'; + } + + data->buf[n+0] = v >> 24 & 0xff; + data->buf[n+1] = v >> 16 & 0xff; + data->buf[n+2] = v >> 8 & 0xff; + data->buf[n+3] = v >> 0 & 0xff; + } + n += 4; + } while (n < sizeof (data->buf) && data->eod == FALSE); + + data->bytes_available = n; +} + +static int +_ascii85_decode_getc (csi_file_t *file) +{ + _ascii85_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _ascii85_decode (file); + + if (data->bytes_available == 0) + return EOF; + } + + data->bytes_available--; + return *data->bp++; +} + +static void +_ascii85_decode_putc (csi_file_t *file, int c) +{ + _ascii85_decode_data_t *data = file->data; + data->bytes_available++; + data->bp--; +} + +static int +_ascii85_decode_read (csi_file_t *file, uint8_t *buf, int len) +{ + _ascii85_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _ascii85_decode (file); + + if (data->bytes_available == 0) + return 0; + } + + if (len > data->bytes_available) + len = data->bytes_available; + memcpy (buf, data->bp, len); + data->bp += len; + data->bytes_available -= len; + return len; +} + +csi_status_t +csi_file_new_ascii85_decode (csi_t *ctx, + csi_object_t *obj, + csi_dictionary_t *dict, + csi_object_t *src) +{ + static const csi_filter_funcs_t funcs = { + _ascii85_decode_getc, + _ascii85_decode_putc, + _ascii85_decode_read, + _csi_free, + }; + _ascii85_decode_data_t *data; + + data = _csi_alloc0 (ctx, sizeof (_ascii85_decode_data_t)); + if (data == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + return _csi_file_new_filter (ctx, obj, src, &funcs, data); +} + +#if HAVE_ZLIB +#include <zlib.h> + +typedef struct _deflate_decode_data { + z_stream zlib_stream; + + uint8_t in[CHUNK_SIZE]; + uint8_t out[CHUNK_SIZE]; + + int bytes_available; + uint8_t *bp; +} _deflate_decode_data_t; + +static void +_deflate_decode (csi_file_t *file) +{ + _deflate_decode_data_t *data = file->data; + uint8_t *bp; + int len; + + data->zlib_stream.next_out = data->out; + data->zlib_stream.avail_out = sizeof (data->out); + + bp = data->in; + len = sizeof (data->in); + if (data->zlib_stream.avail_in) { + memmove (data->in, + data->zlib_stream.next_in, + data->zlib_stream.avail_in); + len -= data->zlib_stream.avail_in; + bp += data->zlib_stream.avail_in; + } + + len = csi_file_read (file->src, bp, len); + + data->zlib_stream.next_in = data->in; + data->zlib_stream.avail_in += len; + + inflate (&data->zlib_stream, len == 0 ? Z_FINISH : Z_NO_FLUSH); + + data->bytes_available = data->zlib_stream.next_out - data->out; + data->bp = data->out; +} + +static int +_deflate_decode_getc (csi_file_t *file) +{ + _deflate_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _deflate_decode (file); + + if (data->bytes_available == 0) + return EOF; + } + + data->bytes_available--; + return *data->bp++; +} + +static void +_deflate_decode_putc (csi_file_t *file, int c) +{ + _deflate_decode_data_t *data = file->data; + data->bytes_available++; + data->bp--; +} + +static int +_deflate_decode_read (csi_file_t *file, uint8_t *buf, int len) +{ + _deflate_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _deflate_decode (file); + + if (data->bytes_available == 0) + return 0; + } + + if (len > (int) data->bytes_available) + len = data->bytes_available; + memcpy (buf, data->bp, len); + data->bp += len; + data->bytes_available -= len; + return len; +} + +static void +_deflate_destroy (csi_t *ctx, void *closure) +{ + _deflate_decode_data_t *data; + + data = closure; + + inflateEnd (&data->zlib_stream); + + _csi_free (ctx, data); +} + +csi_status_t +csi_file_new_deflate_decode (csi_t *ctx, + csi_object_t *obj, + csi_dictionary_t *dict, + csi_object_t *src) +{ + static const csi_filter_funcs_t funcs = { + _deflate_decode_getc, + _deflate_decode_putc, + _deflate_decode_read, + _deflate_destroy, + }; + _deflate_decode_data_t *data; + + data = _csi_alloc (ctx, sizeof (_deflate_decode_data_t)); + if (data == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + data->zlib_stream.zalloc = Z_NULL; + data->zlib_stream.zfree = Z_NULL; + data->zlib_stream.opaque = Z_NULL; + data->zlib_stream.next_in = data->in; + data->zlib_stream.avail_in = 0; + data->zlib_stream.next_out = data->out; + data->zlib_stream.avail_out = sizeof (data->out); + data->bytes_available = 0; + + if (inflateInit (&data->zlib_stream) != Z_OK) { + _csi_free (ctx, data); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + + return _csi_file_new_filter (ctx, obj, src, &funcs, data); +} +#endif + +#if 0 +static int +hex_value (int c) +{ + if (c < '0') + return EOF; + if (c <= '9') + return c - '0'; + c |= 32; + if (c < 'a') + return EOF; + if (c <= 'f') + return c - 'a' + 0xa; + return EOF; +} + +/* Adobe Type 1 Font Format book: p63 */ +typedef struct _decrypt_data { + uint8_t putback[32]; + uint8_t nputback; + csi_bool_t is_hexadecimal; + unsigned short R; + int eod; +} _decrypt_data_t; + +static uint8_t +_decrypt (unsigned short *R, uint8_t cypher) +{ +#define c1 52845 +#define c2 22719 + uint8_t plain; + + plain = cypher ^ (*R >> 8); + *R = (cypher + *R) * c1 + c2; + return plain; +#undef c1 +#undef c2 +} + +int +csi_decrypt (uint8_t *in, int length, + unsigned short salt, int binary, + uint8_t *out) +{ + const uint8_t * const end = in + length; + uint8_t *base = out; + + while (in < end) { + int c; + + if (! binary) { + int c_hi = -1, c_lo = 0; + + while (in < end && (c_hi = *in++)) { + switch (c_hi) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: + continue; + + default: + break; + } + } + if (c_hi < 0) + break; + + while (in < end && (c_lo = *in++)) { + switch (c_lo) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: + continue; + + default: + break; + } + } + + c = (hex_value (c_hi) << 4) | hex_value (c_lo); + } else + c = *in++; + + *out++ = _decrypt (&salt, c); + } + + return out - base; +} + +static uint8_t +_encrypt (unsigned short *R, uint8_t plain) +{ +#define c1 52845 +#define c2 22719 + uint8_t cypher; + + cypher = plain ^ (*R >> 8); + *R = (cypher + *R) * c1 + c2; + return cypher; +#undef c1 +#undef c2 +} + +int +csi_encrypt (uint8_t *in, int length, + unsigned short salt, int discard, int binary, + uint8_t *out) +{ + const char hex[]="0123456789abcdef"; + const uint8_t * const end = in + length; + uint8_t *base = out; + int col = 0; + + while (discard--) { + if (! binary) { + int c = _encrypt (&salt, ' '); + *out++ = hex[(c >> 4) & 0xf]; + *out++ = hex[(c >> 0) & 0xf]; + } else + *out++ = _encrypt (&salt, 0); + } + + while (in < end) { + int c; + + c = _encrypt (&salt, *in++); + if (! binary) { + if (col == 78) { + *out++ = '\n'; + col = 0; + } + *out++ = hex[(c >> 4) & 0xf]; + *out++ = hex[(c >> 0) & 0xf]; + col += 2; + } else + *out++ = c; + } + + return out - base; +} + +static int +_decrypt_getc (csi_file_t *file) +{ + _decrypt_data_t *data = file->data; + int c; + + if (data->nputback) + return data->putback[--data->nputback]; + + if (data->is_hexadecimal) { + int c_hi, c_lo; + + c_hi = _getc_skip_whitespace (file->src); + c_lo = _getc_skip_whitespace (file->src); + c = (hex_value (c_hi) << 4) | hex_value (c_lo); + } else + c = csi_file_getc (file->src); + + if (c == EOF) + return EOF; + + return _decrypt (&data->R, c); +} + +static void +_decrypt_putc (csi_file_t *file, int c) +{ + _decrypt_data_t *data; + + data = file->data; + + data->putback[data->nputback++] = c; +} + +csi_object_t * +csi_file_new_decrypt (csi_t *ctx, csi_object_t *src, int salt, int discard) +{ + csi_object_t *obj; + _decrypt_data_t *data; + int n; + + data = _csi_alloc0 (ctx, sizeof (_decrypt_data_t)); + if (data == NULL) + return NULL; + + data->R = salt; + + obj = _csi_file_new_filter (ctx, src, + _decrypt_getc, + _decrypt_putc, + NULL, + _csi_free, + data); + if (obj == NULL) + return NULL; + + /* XXX determine encoding, eexec only? */ + data->is_hexadecimal = salt != 4330; + for (n = 0; n < discard; n++) { + int c; + c = csi_file_getc (obj); + if (c == EOF) { + return obj; + } + } + return obj; +} +#endif + +csi_status_t +_csi_file_execute (csi_t *ctx, csi_file_t *obj) +{ + return _csi_scan_file (ctx, obj); +} + +int +csi_file_getc (csi_file_t *file) +{ + int c; + + if (_csi_unlikely (file->src == NULL)) + return EOF; + + switch (file->type) { + case STDIO: + if (_csi_likely (file->rem)) { + c = *file->bp++; + file->rem--; + } else { + file->rem = fread (file->bp = file->data, 1, CHUNK_SIZE, file->src); + case BYTES: + if (_csi_likely (file->rem)) { + c = *file->bp++; + file->rem--; + } else + c = EOF; + } + break; + + case PROCEDURE: +#if 0 + if (file->data == NULL) { + csi_status_t status; + csi_object_t *string; + +RERUN_PROCEDURE: + status = csi_object_execute (file->src); + if (status) + return EOF; + + string = csi_pop_operand (file->base.ctx); + if (string == NULL) + return EOF; + file->data = csi_object_as_file (file->base.ctx, string); + csi_object_free (string); + if (file->data == NULL) + return EOF; + } + c = csi_file_getc (file->data); + if (c == EOF) { + csi_object_free (file->data); + file->data = NULL; + goto RERUN_PROCEDURE; + } +#else + c = EOF; +#endif + break; + + case FILTER: + c = file->filter->filter_getc (file); + break; + + default: + c = EOF; + break; + } + + return c; +} + +int +csi_file_read (csi_file_t *file, void *buf, int len) +{ + int ret; + + if (file->src == NULL) + return 0; + + switch (file->type) { + case STDIO: + if (file->rem > 0) { + ret = len; + if (file->rem < ret) + ret = file->rem; + memcpy (buf, file->bp, ret); + file->bp += ret; + file->rem -= ret; + } else + ret = fread (buf, 1, len, file->src); + break; + + case BYTES: + if (file->rem > 0) { + ret = len; + if (file->rem < ret) + ret = file->rem; + memcpy (buf, file->bp, ret); + file->bp += ret; + file->rem -= ret; + } else + ret = 0; + break; + + case PROCEDURE: +#if 0 + if (file->data == NULL) { + csi_status_t status; + csi_object_t *string; + +RERUN_PROCEDURE: + status = csi_object_execute (file->src); + if (status) + return 0; + + string = csi_pop_operand (file->base.ctx); + if (string == NULL) + return 0; + file->data = csi_object_as_file (file->base.ctx, string); + csi_object_free (string); + if (file->data == NULL) + return 0; + } + ret = csi_file_read (file->data, buf, len); + if (ret == 0) { + csi_object_free (file->data); + file->data = NULL; + goto RERUN_PROCEDURE; + } +#else + ret = 0; +#endif + break; + + case FILTER: + ret = file->filter->filter_read (file, buf, len); + break; + + default: + ret = 0; + break; + } + + return ret; +} + +void +csi_file_putc (csi_file_t *file, int c) +{ + if (file->src == NULL) + return; + + switch ((int) file->type) { + case STDIO: + case BYTES: + file->bp--; + file->rem++; + break; + case FILTER: + file->filter->filter_putc (file, c); + break; + default: + break; + } +} + +void +csi_file_flush (csi_file_t *file) +{ + if (file->src == NULL) + return; + + switch ((int) file->type) { + case FILTER: /* need to eat EOD */ + while (csi_file_getc (file) != EOF) + ; + break; + default: + break; + } +} + +void +csi_file_close (csi_t *ctx, csi_file_t *file) +{ + if (file->src == NULL) + return; + + switch (file->type) { + case STDIO: + if (file->flags & OWN_STREAM) + fclose (file->src); + break; + case BYTES: + if (file->src != file->data) { + csi_string_t *src = file->src; + if (src != NULL && --src->base.ref == 0) + csi_string_free (ctx, src); + } + break; + case FILTER: + { + csi_file_t *src = file->src; + if (src != NULL && --src->base.ref == 0) + _csi_file_free (ctx, src); + } + break; + case PROCEDURE: + default: + break; + } + file->src = NULL; +} + +void +_csi_file_free (csi_t *ctx, csi_file_t *file) +{ + csi_file_flush (file); + /* XXX putback */ + csi_file_close (ctx, file); + + switch (file->type) { + case BYTES: + break; + case PROCEDURE: +#if 0 + csi_object_free (ctx, file->data); +#endif + break; + case STDIO: + _csi_free (ctx, file->data); + break; + case FILTER: + file->filter->filter_destroy (ctx, file->data); + break; + default: + break; + } + + _csi_slab_free (ctx, file, sizeof (csi_file_t)); +} + +csi_status_t +_csi_file_as_string (csi_t *ctx, + csi_file_t *file, + csi_object_t *obj) +{ + char *bytes; + unsigned int len; + unsigned int allocated; + csi_status_t status; + + allocated = 16384; + bytes = _csi_alloc (ctx, allocated); + if (bytes == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + len = 0; + do { + int ret; + + ret = csi_file_read (file, bytes + len, allocated - len); + if (ret == 0) + break; + + len += ret; + if (len + 1 > allocated / 2) { + char *newbytes; + int newlen; + + if (_csi_unlikely (allocated > INT_MAX / 2)) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + newlen = allocated * 2; + newbytes = _csi_realloc (ctx, bytes, newlen); + if (_csi_unlikely (newbytes == NULL)) { + _csi_free (ctx, bytes); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + bytes = newbytes; + allocated = newlen; + } + } while (TRUE); + + bytes[len] = '\0'; /* better safe than sorry! */ + status = csi_string_new_from_bytes (ctx, obj, bytes, len); + if (status) { + _csi_free (ctx, bytes); + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + |