Logo Search packages:      
Sourcecode: cairo version File versions  Download package

cairo-script-file.c

/*
 * 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 "cairo-script-private.h"

#include <stdio.h>
#include <limits.h> /* INT_MAX */
#include <string.h>
#include <zlib.h>

#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;
      if (uncompress ((Bytef *) tmp_str->string, &len,
                  (Bytef *) src->string, src->len) != Z_OK)
      {
          csi_string_free (ctx, tmp_str);
          _csi_slab_free (ctx, file, sizeof (csi_file_t));
          return _csi_error (CAIRO_STATUS_NO_MEMORY);
      }

      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

00271 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;

    len = 0;
    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;
}


Generated by  Doxygen 1.6.0   Back to index