static void
_csi_fini (csi_t *ctx)
{
    if (! ctx->finished)
	_csi_finish (ctx);

    if (ctx->free_array != NULL)
	csi_array_free (ctx, ctx->free_array);
    if (ctx->free_dictionary != NULL)
	csi_dictionary_free (ctx, ctx->free_dictionary);
    if (ctx->free_string != NULL)
	csi_string_free (ctx, ctx->free_string);

    _csi_slab_fini (ctx);
    _csi_perm_fini (ctx);
}
static void
_csi_fini (csi_t *ctx)
{
    _csi_stack_fini (ctx, &ctx->ostack);
    _csi_stack_fini (ctx, &ctx->dstack);
    _csi_scanner_fini (ctx, &ctx->scanner);

    _csi_hash_table_fini (&ctx->strings);

    if (ctx->free_array != NULL)
	csi_array_free (ctx, ctx->free_array);
    if (ctx->free_dictionary != NULL)
	csi_dictionary_free (ctx, ctx->free_dictionary);
    if (ctx->free_string != NULL)
	csi_string_free (ctx, ctx->free_string);

    _csi_slab_fini (ctx);
    _csi_perm_fini (ctx);
}
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;
}