X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgmemoryoutputstream.c;h=9c83b7db64bf298a4962628ac4d2d6bcc2274678;hb=cea9de93c8838099661f5b54462f9c4b6410bfc9;hp=07d7db2c3085fe13dc24f1831074f69d3c8a04c2;hpb=32747def4bb4cce7cfc4f0f8ba8560392ec9ad3d;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gmemoryoutputstream.c b/gio/gmemoryoutputstream.c index 07d7db2..9c83b7d 100644 --- a/gio/gmemoryoutputstream.c +++ b/gio/gmemoryoutputstream.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Authors: * Christian Kellner @@ -42,8 +40,8 @@ * #GMemoryOutputStream is a class for using arbitrary * memory chunks as output for GIO streaming output operations. * - * As of GLib 2.34, #GMemoryOutputStream implements - * #GPollableOutputStream. + * As of GLib 2.34, #GMemoryOutputStream trivially implements + * #GPollableOutputStream: it always polls as ready. */ #define MIN_ARRAY_SIZE 16 @@ -57,8 +55,8 @@ enum { PROP_DESTROY_FUNCTION }; -struct _GMemoryOutputStreamPrivate { - +struct _GMemoryOutputStreamPrivate +{ gpointer data; /* Write buffer */ gsize len; /* Current length of the data buffer. Can change with resizing. */ gsize valid_len; /* The part of data that has been written to */ @@ -114,7 +112,7 @@ static gboolean g_memory_output_stream_truncate (GSeekable *see static gboolean g_memory_output_stream_is_writable (GPollableOutputStream *stream); static GSource *g_memory_output_stream_create_source (GPollableOutputStream *stream, - GCancellable *cancellable); + GCancellable *cancellable); static void g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface); @@ -325,7 +323,7 @@ g_memory_output_stream_seekable_iface_init (GSeekableIface *iface) static void g_memory_output_stream_init (GMemoryOutputStream *stream) { - stream->priv = g_memory_output_stream_get_private (stream); + stream->priv = g_memory_output_stream_get_instance_private (stream); stream->priv->pos = 0; stream->priv->valid_len = 0; } @@ -341,24 +339,47 @@ g_memory_output_stream_init (GMemoryOutputStream *stream) * * Creates a new #GMemoryOutputStream. * - * If @data is non-%NULL, the stream will use that for its internal storage. + * In most cases this is not the function you want. See + * g_memory_output_stream_new_resizable() instead. + * + * If @data is non-%NULL, the stream will use that for its internal storage. + * * If @realloc_fn is non-%NULL, it will be used for resizing the internal - * storage when necessary. To construct a fixed-size output stream, - * pass %NULL as @realloc_fn. + * storage when necessary and the stream will be considered resizable. + * In that case, the stream will start out being (conceptually) empty. + * @size is used only as a hint for how big @data is. Specifically, + * seeking to the end of a newly-created stream will seek to zero, not + * @size. Seeking past the end of the stream and then writing will + * introduce a zero-filled gap. + * + * If @realloc_fn is %NULL then the stream is fixed-sized. Seeking to + * the end will seek to @size exactly. Writing past the end will give + * an 'out of space' error. Attempting to seek past the end will fail. + * Unlike the resizable case, seeking to an offset within the stream and + * writing will preserve the bytes passed in as @data before that point + * and will return them as part of g_memory_output_stream_steal_data(). + * If you intend to seek you should probably therefore ensure that @data + * is properly initialised. * - * |[ - * /* a stream that can grow */ + * It is probably only meaningful to provide @data and @size in the case + * that you want a fixed-sized stream. Put another way: if @realloc_fn + * is non-%NULL then it makes most sense to give @data as %NULL and + * @size as 0 (allowing #GMemoryOutputStream to do the initial + * allocation for itself). + * + * |[ + * // a stream that can grow * stream = g_memory_output_stream_new (NULL, 0, realloc, free); * - * /* another stream that can grow */ + * // another stream that can grow * stream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free); * - * /* a fixed-size stream */ + * // a fixed-size stream * data = malloc (200); * stream3 = g_memory_output_stream_new (data, 200, NULL, free); * ]| * - * Return value: A newly created #GMemoryOutputStream object. + * Returns: A newly created #GMemoryOutputStream object. **/ GOutputStream * g_memory_output_stream_new (gpointer data, @@ -416,16 +437,20 @@ g_memory_output_stream_get_data (GMemoryOutputStream *ostream) * @ostream: a #GMemoryOutputStream * * Gets the size of the currently allocated data area (available from - * g_memory_output_stream_get_data()). If the stream isn't - * growable (no realloc was passed to g_memory_output_stream_new()) then - * this is the maximum size of the stream and further writes - * will return %G_IO_ERROR_NO_SPACE. + * g_memory_output_stream_get_data()). + * + * You probably don't want to use this function on resizable streams. + * See g_memory_output_stream_get_data_size() instead. For resizable + * streams the size returned by this function is an implementation + * detail and may be change at any time in response to operations on the + * stream. * - * Note that for growable streams the returned size may become invalid on - * the next write or truncate operation on the stream. + * If the stream is fixed-sized (ie: no realloc was passed to + * g_memory_output_stream_new()) then this is the maximum size of the + * stream and further writes will return %G_IO_ERROR_NO_SPACE. * - * If you want the number of bytes currently written to the stream, use - * g_memory_output_stream_get_data_size(). + * In any case, if you want the number of bytes currently written to the + * stream, use g_memory_output_stream_get_data_size(). * * Returns: the number of bytes allocated for the data buffer */ @@ -441,9 +466,8 @@ g_memory_output_stream_get_size (GMemoryOutputStream *ostream) * g_memory_output_stream_get_data_size: * @ostream: a #GMemoryOutputStream * - * Returns the number of bytes from the start up - * to including the last byte written in the stream - * that has not been truncated away. + * Returns the number of bytes from the start up to including the last + * byte written in the stream that has not been truncated away. * * Returns: the number of bytes written to the stream * @@ -506,11 +530,11 @@ g_memory_output_stream_steal_as_bytes (GMemoryOutputStream *ostream) g_return_val_if_fail (g_output_stream_is_closed (G_OUTPUT_STREAM (ostream)), NULL); result = g_bytes_new_with_free_func (ostream->priv->data, - ostream->priv->valid_len, - ostream->priv->destroy, - ostream->priv->data); + ostream->priv->valid_len, + ostream->priv->destroy, + ostream->priv->data); ostream->priv->data = NULL; - + return result; } @@ -606,10 +630,14 @@ g_memory_output_stream_write (GOutputStream *stream, if (priv->pos + count > priv->len) { - /* At least enought to fit the write, rounded up - for greater than linear growth. - TODO: This wastes a lot of memory at large stream sizes. - Figure out a more rational allocation strategy. */ + /* At least enough to fit the write, rounded up for greater than + * linear growth. + * + * Assuming that we're using something like realloc(), the kernel + * will overcommit memory to us, so doubling the size each time + * will keep the number of realloc calls low without wasting too + * much memory. + */ new_size = g_nearest_pow (priv->pos + count); /* Check for overflow again. We have only checked if pos + count > G_MAXSIZE, but it only catches the case of writing @@ -678,7 +706,7 @@ g_memory_output_stream_close_finish (GOutputStream *stream, GAsyncResult *result, GError **error) { - g_return_val_if_fail (g_task_is_valid (result, stream), -1); + g_return_val_if_fail (g_task_is_valid (result, stream), FALSE); return g_task_propagate_boolean (G_TASK (result), error); } @@ -703,10 +731,10 @@ g_memory_output_stream_can_seek (GSeekable *seekable) static gboolean g_memory_output_stream_seek (GSeekable *seekable, - goffset offset, - GSeekType type, - GCancellable *cancellable, - GError **error) + goffset offset, + GSeekType type, + GCancellable *cancellable, + GError **error) { GMemoryOutputStream *stream; GMemoryOutputStreamPrivate *priv; @@ -726,7 +754,14 @@ g_memory_output_stream_seek (GSeekable *seekable, break; case G_SEEK_END: - absolute = priv->len + offset; + /* For resizable streams, we consider the end to be the data + * length. For fixed-sized streams, we consider the end to be the + * size of the buffer. + */ + if (priv->realloc_fn) + absolute = priv->valid_len + offset; + else + absolute = priv->len + offset; break; default: @@ -747,7 +782,13 @@ g_memory_output_stream_seek (GSeekable *seekable, return FALSE; } - if (absolute > priv->len) + /* Can't seek past the end of a fixed-size stream. + * + * Note: seeking to the non-existent byte at the end of a fixed-sized + * stream is valid (eg: a 1-byte fixed sized stream can have position + * 0 or 1). Therefore '>' is what we want. + * */ + if (priv->realloc_fn == NULL && absolute > priv->len) { g_set_error_literal (error, G_IO_ERROR, @@ -770,6 +811,7 @@ g_memory_output_stream_can_truncate (GSeekable *seekable) ostream = G_MEMORY_OUTPUT_STREAM (seekable); priv = ostream->priv; + /* We do not allow truncation of fixed-sized streams */ return priv->realloc_fn != NULL; } @@ -784,6 +826,8 @@ g_memory_output_stream_truncate (GSeekable *seekable, if (!array_resize (ostream, offset, FALSE, error)) return FALSE; + ostream->priv->valid_len = offset; + return TRUE; } @@ -795,13 +839,12 @@ g_memory_output_stream_is_writable (GPollableOutputStream *stream) static GSource * g_memory_output_stream_create_source (GPollableOutputStream *stream, - GCancellable *cancellable) + GCancellable *cancellable) { GSource *base_source, *pollable_source; base_source = g_timeout_source_new (0); - pollable_source = g_pollable_source_new_full (stream, base_source, - cancellable); + pollable_source = g_pollable_source_new_full (stream, base_source, cancellable); g_source_unref (base_source); return pollable_source;