/* GdkPixbuf library * Copyright (C) 2003-2006 David Schleef * 2005-2006 Eric Anholt * 2006-2007 Benjamin Otte * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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, see . */ #include "config.h" #include "gdk-pixbuf-buffer-queue-private.h" #include struct _GdkPixbufBufferQueue { GSList * first_buffer; /* pointer to first buffer */ GSList * last_buffer; /* pointer to last buffer (for fast appending) */ gsize size; /* amount of bytes in the queue */ gsize offset; /* amount of data already flushed out of the queue */ int ref_count; }; /** * GdkPixbufBufferQueue: * * A #GdkPixbufBufferQueue is a queue of continuous buffers that allows reading * its data in chunks of pre-defined sizes. It is used to transform a data * stream that was provided by buffers of random sizes to buffers of the right * size. */ /** * gdk_pixbuf_buffer_queue_new: * * Creates a new empty buffer queue. * * Returns: a new buffer queue. Use gdk_pixbuf_buffer_queue_unref () to free it. **/ GdkPixbufBufferQueue * gdk_pixbuf_buffer_queue_new (void) { GdkPixbufBufferQueue *buffer_queue; buffer_queue = g_new0 (GdkPixbufBufferQueue, 1); buffer_queue->ref_count = 1; return buffer_queue; } /** * gdk_pixbuf_buffer_queue_get_size: * @queue: a #GdkPixbufBufferQueue * * Returns the number of bytes currently in @queue. * * Returns: amount of bytes in @queue. **/ gsize gdk_pixbuf_buffer_queue_get_size (GdkPixbufBufferQueue *queue) { g_return_val_if_fail (queue != NULL, 0); return queue->size; } /** * gdk_pixbuf_buffer_queue_get_offset: * @queue: a #GdkPixbufBufferQueue * * Queries the amount of bytes that has already been pulled out of * @queue using functions like gdk_pixbuf_buffer_queue_pull(). * * Returns: Number of bytes that were already pulled from this queue. **/ gsize gdk_pixbuf_buffer_queue_get_offset (GdkPixbufBufferQueue * queue) { g_return_val_if_fail (queue != NULL, 0); return queue->offset; } /** * gdk_pixbuf_buffer_queue_flush: * @queue: a #GdkPixbufBufferQueue * @n_bytes: amount of bytes to flush from the queue * * Removes the first @n_bytes bytes from the queue. */ void gdk_pixbuf_buffer_queue_flush (GdkPixbufBufferQueue *queue, gsize n_bytes) { g_return_if_fail (queue != NULL); g_return_if_fail (n_bytes <= queue->size); queue->size -= n_bytes; queue->offset += n_bytes; while (n_bytes > 0) { GBytes *bytes; gsize size; bytes = queue->first_buffer->data; size = g_bytes_get_size (bytes); if (size <= n_bytes) { n_bytes -= size; queue->first_buffer = g_slist_remove (queue->first_buffer, bytes); } else { queue->first_buffer->data = g_bytes_new_from_bytes (bytes, n_bytes, size - n_bytes); n_bytes = 0; } g_bytes_unref (bytes); } if (queue->first_buffer == NULL) queue->last_buffer = NULL; } /** * gdk_pixbuf_buffer_queue_clear: * @queue: a #GdkPixbufBufferQueue * * Resets @queue into to initial state. All buffers it contains will be * released and the offset will be reset to 0. **/ void gdk_pixbuf_buffer_queue_clear (GdkPixbufBufferQueue *queue) { g_return_if_fail (queue != NULL); g_slist_free_full (queue->first_buffer, (GDestroyNotify) g_bytes_unref); queue->first_buffer = NULL; queue->last_buffer = NULL; queue->size = 0; queue->offset = 0; } /** * gdk_pixbuf_buffer_queue_push: * @queue: a #GdkPixbufBufferQueue * @bytes: #GBytes to append to @queue * * Appends the given @bytes to the buffers already in @queue. This function * will take ownership of the given @buffer. Use g_bytes_ref () before * calling this function to keep a reference. **/ void gdk_pixbuf_buffer_queue_push (GdkPixbufBufferQueue *queue, GBytes *bytes) { gsize size; g_return_if_fail (queue != NULL); g_return_if_fail (bytes != NULL); size = g_bytes_get_size (bytes); if (size == 0) { g_bytes_unref (bytes); return; } queue->last_buffer = g_slist_append (queue->last_buffer, bytes); if (queue->first_buffer == NULL) queue->first_buffer = queue->last_buffer; else queue->last_buffer = queue->last_buffer->next; queue->size += size; } /** * gdk_pixbuf_buffer_queue_peek: * @queue: a #GdkPixbufBufferQueue to read from * @length: amount of bytes to peek * * Creates a new buffer with the first @length bytes from @queue, but unlike * gdk_pixbuf_buffer_queue_pull(), does not remove them from @queue. * * Returns: NULL if the requested amount of data wasn't available or a new * #GBytes. Use g_bytes_unref() after use. **/ GBytes * gdk_pixbuf_buffer_queue_peek (GdkPixbufBufferQueue *queue, gsize length) { GSList *g; GBytes *result, *bytes; g_return_val_if_fail (queue != NULL, NULL); if (queue->size < length) return NULL; /* need to special case here, because the queue may be empty */ if (length == 0) return g_bytes_new (NULL, 0); g = queue->first_buffer; bytes = g->data; if (g_bytes_get_size (bytes) == length) { result = g_bytes_ref (bytes); } else if (g_bytes_get_size (bytes) > length) { result = g_bytes_new_from_bytes (bytes, 0, length); } else { guchar *data; gsize amount, offset; data = g_malloc (length); for (offset = 0; offset < length; offset += amount) { bytes = g->data; amount = MIN (length - offset, g_bytes_get_size (bytes)); memcpy (data + offset, g_bytes_get_data (bytes, NULL), amount); g = g->next; } result = g_bytes_new_take (data, length); } return result; } /** * gdk_pixbuf_buffer_queue_pull: * @queue: a #GdkPixbufBufferQueue * @length: amount of bytes to pull * * If enough data is still available in @queue, the first @length bytes are * put into a new buffer and that buffer is returned. The @length bytes are * removed from the head of the queue. If not enough data is available, %NULL * is returned. * * Returns: a new #GBytes or %NULL **/ GBytes * gdk_pixbuf_buffer_queue_pull (GdkPixbufBufferQueue * queue, gsize length) { GBytes *result; g_return_val_if_fail (queue != NULL, NULL); result = gdk_pixbuf_buffer_queue_peek (queue, length); if (result == NULL) return NULL; gdk_pixbuf_buffer_queue_flush (queue, length); return result; } /** * gdk_pixbuf_buffer_queue_peek_buffer: * @queue: a #GdkPixbufBufferQueue * * Gets the first buffer out of @queue and returns it. This function is * equivalent to calling gdk_pixbuf_buffer_queue_peek() with the size of the * first buffer in it. * * Returns: The first buffer in @queue or %NULL if @queue is empty. Use * g_bytes_unref() after use. **/ GBytes * gdk_pixbuf_buffer_queue_peek_buffer (GdkPixbufBufferQueue * queue) { GBytes *bytes; g_return_val_if_fail (queue != NULL, NULL); if (queue->first_buffer == NULL) return NULL; bytes = queue->first_buffer->data; return g_bytes_ref (bytes); } /** * gdk_pixbuf_buffer_queue_pull_buffer: * @queue: a #GdkPixbufBufferQueue * * Pulls the first buffer out of @queue and returns it. This function is * equivalent to calling gdk_pixbuf_buffer_queue_pull() with the size of the * first buffer in it. * * Returns: The first buffer in @queue or %NULL if @queue is empty. **/ GBytes * gdk_pixbuf_buffer_queue_pull_buffer (GdkPixbufBufferQueue *queue) { GBytes *bytes; g_return_val_if_fail (queue != NULL, NULL); bytes = gdk_pixbuf_buffer_queue_peek_buffer (queue); if (bytes) gdk_pixbuf_buffer_queue_flush (queue, g_bytes_get_size (bytes)); return bytes; } /** * gdk_pixbuf_buffer_queue_ref: * @queue: a #GdkPixbufBufferQueue * * increases the reference count of @queue by one. * * Returns: The passed in @queue. **/ GdkPixbufBufferQueue * gdk_pixbuf_buffer_queue_ref (GdkPixbufBufferQueue * queue) { g_return_val_if_fail (queue != NULL, NULL); g_return_val_if_fail (queue->ref_count > 0, NULL); queue->ref_count++; return queue; } /** * gdk_pixbuf_buffer_queue_unref: * @queue: a #GdkPixbufBufferQueue * * Decreases the reference count of @queue by one. If no reference * to this buffer exists anymore, the buffer and the memory * it manages are freed. **/ void gdk_pixbuf_buffer_queue_unref (GdkPixbufBufferQueue * queue) { g_return_if_fail (queue != NULL); g_return_if_fail (queue->ref_count > 0); queue->ref_count--; if (queue->ref_count > 0) return; gdk_pixbuf_buffer_queue_clear (queue); g_free (queue); }