|
Packit |
ae235b |
/* GIO - GLib Input, Output and Streaming Library
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* This library is free software; you can redistribute it and/or
|
|
Packit |
ae235b |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
ae235b |
* License as published by the Free Software Foundation; either
|
|
Packit |
ae235b |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
ae235b |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
ae235b |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
ae235b |
* Lesser General Public License for more details.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* You should have received a copy of the GNU Lesser General
|
|
Packit |
ae235b |
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Author: Christian Kellner <gicmo@gnome.org>
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#include "config.h"
|
|
Packit |
ae235b |
#include "gbufferedoutputstream.h"
|
|
Packit |
ae235b |
#include "goutputstream.h"
|
|
Packit |
ae235b |
#include "gseekable.h"
|
|
Packit |
ae235b |
#include "gtask.h"
|
|
Packit |
ae235b |
#include "string.h"
|
|
Packit |
ae235b |
#include "gioerror.h"
|
|
Packit |
ae235b |
#include "glibintl.h"
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/**
|
|
Packit |
ae235b |
* SECTION:gbufferedoutputstream
|
|
Packit |
ae235b |
* @short_description: Buffered Output Stream
|
|
Packit |
ae235b |
* @include: gio/gio.h
|
|
Packit |
ae235b |
* @see_also: #GFilterOutputStream, #GOutputStream
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Buffered output stream implements #GFilterOutputStream and provides
|
|
Packit |
ae235b |
* for buffered writes.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* By default, #GBufferedOutputStream's buffer size is set at 4 kilobytes.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* To create a buffered output stream, use g_buffered_output_stream_new(),
|
|
Packit |
ae235b |
* or g_buffered_output_stream_new_sized() to specify the buffer's size
|
|
Packit |
ae235b |
* at construction.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* To get the size of a buffer within a buffered input stream, use
|
|
Packit |
ae235b |
* g_buffered_output_stream_get_buffer_size(). To change the size of a
|
|
Packit |
ae235b |
* buffered output stream's buffer, use
|
|
Packit |
ae235b |
* g_buffered_output_stream_set_buffer_size(). Note that the buffer's
|
|
Packit |
ae235b |
* size cannot be reduced below the size of the data within the buffer.
|
|
Packit |
ae235b |
**/
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#define DEFAULT_BUFFER_SIZE 4096
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
struct _GBufferedOutputStreamPrivate {
|
|
Packit |
ae235b |
guint8 *buffer;
|
|
Packit |
ae235b |
gsize len;
|
|
Packit |
ae235b |
goffset pos;
|
|
Packit |
ae235b |
gboolean auto_grow;
|
|
Packit |
ae235b |
};
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
enum {
|
|
Packit |
ae235b |
PROP_0,
|
|
Packit |
ae235b |
PROP_BUFSIZE,
|
|
Packit |
ae235b |
PROP_AUTO_GROW
|
|
Packit |
ae235b |
};
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void g_buffered_output_stream_set_property (GObject *object,
|
|
Packit |
ae235b |
guint prop_id,
|
|
Packit |
ae235b |
const GValue *value,
|
|
Packit |
ae235b |
GParamSpec *pspec);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void g_buffered_output_stream_get_property (GObject *object,
|
|
Packit |
ae235b |
guint prop_id,
|
|
Packit |
ae235b |
GValue *value,
|
|
Packit |
ae235b |
GParamSpec *pspec);
|
|
Packit |
ae235b |
static void g_buffered_output_stream_finalize (GObject *object);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gssize g_buffered_output_stream_write (GOutputStream *stream,
|
|
Packit |
ae235b |
const void *buffer,
|
|
Packit |
ae235b |
gsize count,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error);
|
|
Packit |
ae235b |
static gboolean g_buffered_output_stream_flush (GOutputStream *stream,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error);
|
|
Packit |
ae235b |
static gboolean g_buffered_output_stream_close (GOutputStream *stream,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void g_buffered_output_stream_flush_async (GOutputStream *stream,
|
|
Packit |
ae235b |
int io_priority,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GAsyncReadyCallback callback,
|
|
Packit |
ae235b |
gpointer data);
|
|
Packit |
ae235b |
static gboolean g_buffered_output_stream_flush_finish (GOutputStream *stream,
|
|
Packit |
ae235b |
GAsyncResult *result,
|
|
Packit |
ae235b |
GError **error);
|
|
Packit |
ae235b |
static void g_buffered_output_stream_close_async (GOutputStream *stream,
|
|
Packit |
ae235b |
int io_priority,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GAsyncReadyCallback callback,
|
|
Packit |
ae235b |
gpointer data);
|
|
Packit |
ae235b |
static gboolean g_buffered_output_stream_close_finish (GOutputStream *stream,
|
|
Packit |
ae235b |
GAsyncResult *result,
|
|
Packit |
ae235b |
GError **error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void g_buffered_output_stream_seekable_iface_init (GSeekableIface *iface);
|
|
Packit |
ae235b |
static goffset g_buffered_output_stream_tell (GSeekable *seekable);
|
|
Packit |
ae235b |
static gboolean g_buffered_output_stream_can_seek (GSeekable *seekable);
|
|
Packit |
ae235b |
static gboolean g_buffered_output_stream_seek (GSeekable *seekable,
|
|
Packit |
ae235b |
goffset offset,
|
|
Packit |
ae235b |
GSeekType type,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error);
|
|
Packit |
ae235b |
static gboolean g_buffered_output_stream_can_truncate (GSeekable *seekable);
|
|
Packit |
ae235b |
static gboolean g_buffered_output_stream_truncate (GSeekable *seekable,
|
|
Packit |
ae235b |
goffset offset,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
G_DEFINE_TYPE_WITH_CODE (GBufferedOutputStream,
|
|
Packit |
ae235b |
g_buffered_output_stream,
|
|
Packit |
ae235b |
G_TYPE_FILTER_OUTPUT_STREAM,
|
|
Packit |
ae235b |
G_ADD_PRIVATE (GBufferedOutputStream)
|
|
Packit |
ae235b |
G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
|
|
Packit |
ae235b |
g_buffered_output_stream_seekable_iface_init))
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_buffered_output_stream_class_init (GBufferedOutputStreamClass *klass)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GObjectClass *object_class;
|
|
Packit |
ae235b |
GOutputStreamClass *ostream_class;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
object_class = G_OBJECT_CLASS (klass);
|
|
Packit |
ae235b |
object_class->get_property = g_buffered_output_stream_get_property;
|
|
Packit |
ae235b |
object_class->set_property = g_buffered_output_stream_set_property;
|
|
Packit |
ae235b |
object_class->finalize = g_buffered_output_stream_finalize;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
ostream_class = G_OUTPUT_STREAM_CLASS (klass);
|
|
Packit |
ae235b |
ostream_class->write_fn = g_buffered_output_stream_write;
|
|
Packit |
ae235b |
ostream_class->flush = g_buffered_output_stream_flush;
|
|
Packit |
ae235b |
ostream_class->close_fn = g_buffered_output_stream_close;
|
|
Packit |
ae235b |
ostream_class->flush_async = g_buffered_output_stream_flush_async;
|
|
Packit |
ae235b |
ostream_class->flush_finish = g_buffered_output_stream_flush_finish;
|
|
Packit |
ae235b |
ostream_class->close_async = g_buffered_output_stream_close_async;
|
|
Packit |
ae235b |
ostream_class->close_finish = g_buffered_output_stream_close_finish;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_object_class_install_property (object_class,
|
|
Packit |
ae235b |
PROP_BUFSIZE,
|
|
Packit |
ae235b |
g_param_spec_uint ("buffer-size",
|
|
Packit |
ae235b |
P_("Buffer Size"),
|
|
Packit |
ae235b |
P_("The size of the backend buffer"),
|
|
Packit |
ae235b |
1,
|
|
Packit |
ae235b |
G_MAXUINT,
|
|
Packit |
ae235b |
DEFAULT_BUFFER_SIZE,
|
|
Packit |
ae235b |
G_PARAM_READWRITE|G_PARAM_CONSTRUCT|
|
|
Packit |
ae235b |
G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_object_class_install_property (object_class,
|
|
Packit |
ae235b |
PROP_AUTO_GROW,
|
|
Packit |
ae235b |
g_param_spec_boolean ("auto-grow",
|
|
Packit |
ae235b |
P_("Auto-grow"),
|
|
Packit |
ae235b |
P_("Whether the buffer should automatically grow"),
|
|
Packit |
ae235b |
FALSE,
|
|
Packit |
ae235b |
G_PARAM_READWRITE|
|
|
Packit |
ae235b |
G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/**
|
|
Packit |
ae235b |
* g_buffered_output_stream_get_buffer_size:
|
|
Packit |
ae235b |
* @stream: a #GBufferedOutputStream.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Gets the size of the buffer in the @stream.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Returns: the current size of the buffer.
|
|
Packit |
ae235b |
**/
|
|
Packit |
ae235b |
gsize
|
|
Packit |
ae235b |
g_buffered_output_stream_get_buffer_size (GBufferedOutputStream *stream)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_return_val_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream), -1);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return stream->priv->len;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/**
|
|
Packit |
ae235b |
* g_buffered_output_stream_set_buffer_size:
|
|
Packit |
ae235b |
* @stream: a #GBufferedOutputStream.
|
|
Packit |
ae235b |
* @size: a #gsize.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Sets the size of the internal buffer to @size.
|
|
Packit |
ae235b |
**/
|
|
Packit |
ae235b |
void
|
|
Packit |
ae235b |
g_buffered_output_stream_set_buffer_size (GBufferedOutputStream *stream,
|
|
Packit |
ae235b |
gsize size)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStreamPrivate *priv;
|
|
Packit |
ae235b |
guint8 *buffer;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
priv = stream->priv;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (size == priv->len)
|
|
Packit |
ae235b |
return;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (priv->buffer)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
size = MAX (size, priv->pos);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
buffer = g_malloc (size);
|
|
Packit |
ae235b |
memcpy (buffer, priv->buffer, priv->pos);
|
|
Packit |
ae235b |
g_free (priv->buffer);
|
|
Packit |
ae235b |
priv->buffer = buffer;
|
|
Packit |
ae235b |
priv->len = size;
|
|
Packit |
ae235b |
/* Keep old pos */
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
priv->buffer = g_malloc (size);
|
|
Packit |
ae235b |
priv->len = size;
|
|
Packit |
ae235b |
priv->pos = 0;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_object_notify (G_OBJECT (stream), "buffer-size");
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/**
|
|
Packit |
ae235b |
* g_buffered_output_stream_get_auto_grow:
|
|
Packit |
ae235b |
* @stream: a #GBufferedOutputStream.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Checks if the buffer automatically grows as data is added.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Returns: %TRUE if the @stream's buffer automatically grows,
|
|
Packit |
ae235b |
* %FALSE otherwise.
|
|
Packit |
ae235b |
**/
|
|
Packit |
ae235b |
gboolean
|
|
Packit |
ae235b |
g_buffered_output_stream_get_auto_grow (GBufferedOutputStream *stream)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_return_val_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream), FALSE);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return stream->priv->auto_grow;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/**
|
|
Packit |
ae235b |
* g_buffered_output_stream_set_auto_grow:
|
|
Packit |
ae235b |
* @stream: a #GBufferedOutputStream.
|
|
Packit |
ae235b |
* @auto_grow: a #gboolean.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Sets whether or not the @stream's buffer should automatically grow.
|
|
Packit |
ae235b |
* If @auto_grow is true, then each write will just make the buffer
|
|
Packit |
ae235b |
* larger, and you must manually flush the buffer to actually write out
|
|
Packit |
ae235b |
* the data to the underlying stream.
|
|
Packit |
ae235b |
**/
|
|
Packit |
ae235b |
void
|
|
Packit |
ae235b |
g_buffered_output_stream_set_auto_grow (GBufferedOutputStream *stream,
|
|
Packit |
ae235b |
gboolean auto_grow)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStreamPrivate *priv;
|
|
Packit |
ae235b |
g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream));
|
|
Packit |
ae235b |
priv = stream->priv;
|
|
Packit |
ae235b |
auto_grow = auto_grow != FALSE;
|
|
Packit |
ae235b |
if (priv->auto_grow != auto_grow)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
priv->auto_grow = auto_grow;
|
|
Packit |
ae235b |
g_object_notify (G_OBJECT (stream), "auto-grow");
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_buffered_output_stream_set_property (GObject *object,
|
|
Packit |
ae235b |
guint prop_id,
|
|
Packit |
ae235b |
const GValue *value,
|
|
Packit |
ae235b |
GParamSpec *pspec)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStream *stream;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
stream = G_BUFFERED_OUTPUT_STREAM (object);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
switch (prop_id)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
case PROP_BUFSIZE:
|
|
Packit |
ae235b |
g_buffered_output_stream_set_buffer_size (stream, g_value_get_uint (value));
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case PROP_AUTO_GROW:
|
|
Packit |
ae235b |
g_buffered_output_stream_set_auto_grow (stream, g_value_get_boolean (value));
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
default:
|
|
Packit |
ae235b |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_buffered_output_stream_get_property (GObject *object,
|
|
Packit |
ae235b |
guint prop_id,
|
|
Packit |
ae235b |
GValue *value,
|
|
Packit |
ae235b |
GParamSpec *pspec)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStream *buffered_stream;
|
|
Packit |
ae235b |
GBufferedOutputStreamPrivate *priv;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
buffered_stream = G_BUFFERED_OUTPUT_STREAM (object);
|
|
Packit |
ae235b |
priv = buffered_stream->priv;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
switch (prop_id)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
case PROP_BUFSIZE:
|
|
Packit |
ae235b |
g_value_set_uint (value, priv->len);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case PROP_AUTO_GROW:
|
|
Packit |
ae235b |
g_value_set_boolean (value, priv->auto_grow);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
default:
|
|
Packit |
ae235b |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_buffered_output_stream_finalize (GObject *object)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStream *stream;
|
|
Packit |
ae235b |
GBufferedOutputStreamPrivate *priv;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
stream = G_BUFFERED_OUTPUT_STREAM (object);
|
|
Packit |
ae235b |
priv = stream->priv;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_free (priv->buffer);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
G_OBJECT_CLASS (g_buffered_output_stream_parent_class)->finalize (object);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_buffered_output_stream_init (GBufferedOutputStream *stream)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
stream->priv = g_buffered_output_stream_get_instance_private (stream);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_buffered_output_stream_seekable_iface_init (GSeekableIface *iface)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
iface->tell = g_buffered_output_stream_tell;
|
|
Packit |
ae235b |
iface->can_seek = g_buffered_output_stream_can_seek;
|
|
Packit |
ae235b |
iface->seek = g_buffered_output_stream_seek;
|
|
Packit |
ae235b |
iface->can_truncate = g_buffered_output_stream_can_truncate;
|
|
Packit |
ae235b |
iface->truncate_fn = g_buffered_output_stream_truncate;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/**
|
|
Packit |
ae235b |
* g_buffered_output_stream_new:
|
|
Packit |
ae235b |
* @base_stream: a #GOutputStream.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Creates a new buffered output stream for a base stream.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Returns: a #GOutputStream for the given @base_stream.
|
|
Packit |
ae235b |
**/
|
|
Packit |
ae235b |
GOutputStream *
|
|
Packit |
ae235b |
g_buffered_output_stream_new (GOutputStream *base_stream)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GOutputStream *stream;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
stream = g_object_new (G_TYPE_BUFFERED_OUTPUT_STREAM,
|
|
Packit |
ae235b |
"base-stream", base_stream,
|
|
Packit |
ae235b |
NULL);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return stream;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/**
|
|
Packit |
ae235b |
* g_buffered_output_stream_new_sized:
|
|
Packit |
ae235b |
* @base_stream: a #GOutputStream.
|
|
Packit |
ae235b |
* @size: a #gsize.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Creates a new buffered output stream with a given buffer size.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Returns: a #GOutputStream with an internal buffer set to @size.
|
|
Packit |
ae235b |
**/
|
|
Packit |
ae235b |
GOutputStream *
|
|
Packit |
ae235b |
g_buffered_output_stream_new_sized (GOutputStream *base_stream,
|
|
Packit |
ae235b |
gsize size)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GOutputStream *stream;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
stream = g_object_new (G_TYPE_BUFFERED_OUTPUT_STREAM,
|
|
Packit |
ae235b |
"base-stream", base_stream,
|
|
Packit |
ae235b |
"buffer-size", size,
|
|
Packit |
ae235b |
NULL);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return stream;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
flush_buffer (GBufferedOutputStream *stream,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStreamPrivate *priv;
|
|
Packit |
ae235b |
GOutputStream *base_stream;
|
|
Packit |
ae235b |
gboolean res;
|
|
Packit |
ae235b |
gsize bytes_written;
|
|
Packit |
ae235b |
gsize count;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
priv = stream->priv;
|
|
Packit |
ae235b |
bytes_written = 0;
|
|
Packit |
ae235b |
base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), FALSE);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
res = g_output_stream_write_all (base_stream,
|
|
Packit |
ae235b |
priv->buffer,
|
|
Packit |
ae235b |
priv->pos,
|
|
Packit |
ae235b |
&bytes_written,
|
|
Packit |
ae235b |
cancellable,
|
|
Packit |
ae235b |
error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
count = priv->pos - bytes_written;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (count > 0)
|
|
Packit |
ae235b |
memmove (priv->buffer, priv->buffer + bytes_written, count);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
priv->pos -= bytes_written;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return res;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gssize
|
|
Packit |
ae235b |
g_buffered_output_stream_write (GOutputStream *stream,
|
|
Packit |
ae235b |
const void *buffer,
|
|
Packit |
ae235b |
gsize count,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStream *bstream;
|
|
Packit |
ae235b |
GBufferedOutputStreamPrivate *priv;
|
|
Packit |
ae235b |
gboolean res;
|
|
Packit |
ae235b |
gsize n;
|
|
Packit |
ae235b |
gsize new_size;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
bstream = G_BUFFERED_OUTPUT_STREAM (stream);
|
|
Packit |
ae235b |
priv = bstream->priv;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
n = priv->len - priv->pos;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (priv->auto_grow && n < count)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
new_size = MAX (priv->len * 2, priv->len + count);
|
|
Packit |
ae235b |
g_buffered_output_stream_set_buffer_size (bstream, new_size);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else if (n == 0)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
res = flush_buffer (bstream, cancellable, error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (res == FALSE)
|
|
Packit |
ae235b |
return -1;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
n = priv->len - priv->pos;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
count = MIN (count, n);
|
|
Packit |
ae235b |
memcpy (priv->buffer + priv->pos, buffer, count);
|
|
Packit |
ae235b |
priv->pos += count;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return count;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_buffered_output_stream_flush (GOutputStream *stream,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStream *bstream;
|
|
Packit |
ae235b |
GOutputStream *base_stream;
|
|
Packit |
ae235b |
gboolean res;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
bstream = G_BUFFERED_OUTPUT_STREAM (stream);
|
|
Packit |
ae235b |
base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
res = flush_buffer (bstream, cancellable, error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (res == FALSE)
|
|
Packit |
ae235b |
return FALSE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
res = g_output_stream_flush (base_stream, cancellable, error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return res;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_buffered_output_stream_close (GOutputStream *stream,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStream *bstream;
|
|
Packit |
ae235b |
GOutputStream *base_stream;
|
|
Packit |
ae235b |
gboolean res;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
bstream = G_BUFFERED_OUTPUT_STREAM (stream);
|
|
Packit |
ae235b |
base_stream = G_FILTER_OUTPUT_STREAM (bstream)->base_stream;
|
|
Packit |
ae235b |
res = flush_buffer (bstream, cancellable, error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (g_filter_output_stream_get_close_base_stream (G_FILTER_OUTPUT_STREAM (stream)))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* report the first error but still close the stream */
|
|
Packit |
ae235b |
if (res)
|
|
Packit |
ae235b |
res = g_output_stream_close (base_stream, cancellable, error);
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
g_output_stream_close (base_stream, cancellable, NULL);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return res;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static goffset
|
|
Packit |
ae235b |
g_buffered_output_stream_tell (GSeekable *seekable)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStream *bstream;
|
|
Packit |
ae235b |
GBufferedOutputStreamPrivate *priv;
|
|
Packit |
ae235b |
GOutputStream *base_stream;
|
|
Packit |
ae235b |
GSeekable *base_stream_seekable;
|
|
Packit |
ae235b |
goffset base_offset;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
bstream = G_BUFFERED_OUTPUT_STREAM (seekable);
|
|
Packit |
ae235b |
priv = bstream->priv;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
|
|
Packit |
ae235b |
if (!G_IS_SEEKABLE (base_stream))
|
|
Packit |
ae235b |
return 0;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
base_stream_seekable = G_SEEKABLE (base_stream);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
base_offset = g_seekable_tell (base_stream_seekable);
|
|
Packit |
ae235b |
return base_offset + priv->pos;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_buffered_output_stream_can_seek (GSeekable *seekable)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GOutputStream *base_stream;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
|
|
Packit |
ae235b |
return G_IS_SEEKABLE (base_stream) && g_seekable_can_seek (G_SEEKABLE (base_stream));
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_buffered_output_stream_seek (GSeekable *seekable,
|
|
Packit |
ae235b |
goffset offset,
|
|
Packit |
ae235b |
GSeekType type,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStream *bstream;
|
|
Packit |
ae235b |
GOutputStream *base_stream;
|
|
Packit |
ae235b |
GSeekable *base_stream_seekable;
|
|
Packit |
ae235b |
gboolean flushed;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
bstream = G_BUFFERED_OUTPUT_STREAM (seekable);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
|
|
Packit |
ae235b |
if (!G_IS_SEEKABLE (base_stream))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
Packit |
ae235b |
_("Seek not supported on base stream"));
|
|
Packit |
ae235b |
return FALSE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
base_stream_seekable = G_SEEKABLE (base_stream);
|
|
Packit |
ae235b |
flushed = flush_buffer (bstream, cancellable, error);
|
|
Packit |
ae235b |
if (!flushed)
|
|
Packit |
ae235b |
return FALSE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return g_seekable_seek (base_stream_seekable, offset, type, cancellable, error);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_buffered_output_stream_can_truncate (GSeekable *seekable)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GOutputStream *base_stream;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
|
|
Packit |
ae235b |
return G_IS_SEEKABLE (base_stream) && g_seekable_can_truncate (G_SEEKABLE (base_stream));
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_buffered_output_stream_truncate (GSeekable *seekable,
|
|
Packit |
ae235b |
goffset offset,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStream *bstream;
|
|
Packit |
ae235b |
GOutputStream *base_stream;
|
|
Packit |
ae235b |
GSeekable *base_stream_seekable;
|
|
Packit |
ae235b |
gboolean flushed;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
bstream = G_BUFFERED_OUTPUT_STREAM (seekable);
|
|
Packit |
ae235b |
base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
|
|
Packit |
ae235b |
if (!G_IS_SEEKABLE (base_stream))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
Packit |
ae235b |
_("Truncate not supported on base stream"));
|
|
Packit |
ae235b |
return FALSE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
base_stream_seekable = G_SEEKABLE (base_stream);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
flushed = flush_buffer (bstream, cancellable, error);
|
|
Packit |
ae235b |
if (!flushed)
|
|
Packit |
ae235b |
return FALSE;
|
|
Packit |
ae235b |
return g_seekable_truncate (base_stream_seekable, offset, cancellable, error);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* ************************** */
|
|
Packit |
ae235b |
/* Async stuff implementation */
|
|
Packit |
ae235b |
/* ************************** */
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* TODO: This should be using the base class async ops, not threads */
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
typedef struct {
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
guint flush_stream : 1;
|
|
Packit |
ae235b |
guint close_stream : 1;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
} FlushData;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
free_flush_data (gpointer data)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_slice_free (FlushData, data);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* This function is used by all three (i.e.
|
|
Packit |
ae235b |
* _write, _flush, _close) functions since
|
|
Packit |
ae235b |
* all of them will need to flush the buffer
|
|
Packit |
ae235b |
* and so closing and writing is just a special
|
|
Packit |
ae235b |
* case of flushing + some addition stuff */
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
flush_buffer_thread (GTask *task,
|
|
Packit |
ae235b |
gpointer object,
|
|
Packit |
ae235b |
gpointer task_data,
|
|
Packit |
ae235b |
GCancellable *cancellable)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GBufferedOutputStream *stream;
|
|
Packit |
ae235b |
GOutputStream *base_stream;
|
|
Packit |
ae235b |
FlushData *fdata;
|
|
Packit |
ae235b |
gboolean res;
|
|
Packit |
ae235b |
GError *error = NULL;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
stream = G_BUFFERED_OUTPUT_STREAM (object);
|
|
Packit |
ae235b |
fdata = task_data;
|
|
Packit |
ae235b |
base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
res = flush_buffer (stream, cancellable, &error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* if flushing the buffer didn't work don't even bother
|
|
Packit |
ae235b |
* to flush the stream but just report that error */
|
|
Packit |
ae235b |
if (res && fdata->flush_stream)
|
|
Packit |
ae235b |
res = g_output_stream_flush (base_stream, cancellable, &error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (fdata->close_stream)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* if flushing the buffer or the stream returned
|
|
Packit |
ae235b |
* an error report that first error but still try
|
|
Packit |
ae235b |
* close the stream */
|
|
Packit |
ae235b |
if (g_filter_output_stream_get_close_base_stream (G_FILTER_OUTPUT_STREAM (stream)))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
if (res == FALSE)
|
|
Packit |
ae235b |
g_output_stream_close (base_stream, cancellable, NULL);
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
res = g_output_stream_close (base_stream, cancellable, &error);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (res == FALSE)
|
|
Packit |
ae235b |
g_task_return_error (task, error);
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
g_task_return_boolean (task, TRUE);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_buffered_output_stream_flush_async (GOutputStream *stream,
|
|
Packit |
ae235b |
int io_priority,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GAsyncReadyCallback callback,
|
|
Packit |
ae235b |
gpointer data)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GTask *task;
|
|
Packit |
ae235b |
FlushData *fdata;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
fdata = g_slice_new (FlushData);
|
|
Packit |
ae235b |
fdata->flush_stream = TRUE;
|
|
Packit |
ae235b |
fdata->close_stream = FALSE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
task = g_task_new (stream, cancellable, callback, data);
|
|
Packit |
ae235b |
g_task_set_source_tag (task, g_buffered_output_stream_flush_async);
|
|
Packit |
ae235b |
g_task_set_task_data (task, fdata, free_flush_data);
|
|
Packit |
ae235b |
g_task_set_priority (task, io_priority);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_task_run_in_thread (task, flush_buffer_thread);
|
|
Packit |
ae235b |
g_object_unref (task);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_buffered_output_stream_flush_finish (GOutputStream *stream,
|
|
Packit |
ae235b |
GAsyncResult *result,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return g_task_propagate_boolean (G_TASK (result), error);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_buffered_output_stream_close_async (GOutputStream *stream,
|
|
Packit |
ae235b |
int io_priority,
|
|
Packit |
ae235b |
GCancellable *cancellable,
|
|
Packit |
ae235b |
GAsyncReadyCallback callback,
|
|
Packit |
ae235b |
gpointer data)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GTask *task;
|
|
Packit |
ae235b |
FlushData *fdata;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
fdata = g_slice_new (FlushData);
|
|
Packit |
ae235b |
fdata->close_stream = TRUE;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
task = g_task_new (stream, cancellable, callback, data);
|
|
Packit |
ae235b |
g_task_set_source_tag (task, g_buffered_output_stream_close_async);
|
|
Packit |
ae235b |
g_task_set_task_data (task, fdata, free_flush_data);
|
|
Packit |
ae235b |
g_task_set_priority (task, io_priority);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_task_run_in_thread (task, flush_buffer_thread);
|
|
Packit |
ae235b |
g_object_unref (task);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_buffered_output_stream_close_finish (GOutputStream *stream,
|
|
Packit |
ae235b |
GAsyncResult *result,
|
|
Packit |
ae235b |
GError **error)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return g_task_propagate_boolean (G_TASK (result), error);
|
|
Packit |
ae235b |
}
|