[gdk-pixbuf/wip/otte/tga: 1/24] Add GdkPixbufBufferQueue



commit dfcc08a3ef402c8f3a1b3d11bb7e52a828cd6903
Author: Benjamin Otte <otte redhat com>
Date:   Sun Sep 20 05:18:47 2015 +0200

    Add GdkPixbufBufferQueue
    
    Taking heavy inspiration from Swfdec here.

 gdk-pixbuf/Makefile.am                       |    3 +-
 gdk-pixbuf/gdk-pixbuf-buffer-queue-private.h |   51 ++++
 gdk-pixbuf/gdk-pixbuf-buffer-queue.c         |  367 ++++++++++++++++++++++++++
 3 files changed, 420 insertions(+), 1 deletions(-)
---
diff --git a/gdk-pixbuf/Makefile.am b/gdk-pixbuf/Makefile.am
index 011efaf..8217fcd 100644
--- a/gdk-pixbuf/Makefile.am
+++ b/gdk-pixbuf/Makefile.am
@@ -150,7 +150,7 @@ libpixbufloader_xbm_la_LIBADD = $(module_libs)
 # The TGA loader
 #
 libstatic_pixbufloader_tga_la_SOURCES = io-tga.c
-libpixbufloader_tga_la_SOURCES = io-tga.c
+libpixbufloader_tga_la_SOURCES = io-tga.c gdk-pixbuf-buffer-queue.c
 libpixbufloader_tga_la_LDFLAGS = -avoid-version -module $(no_undefined)
 libpixbufloader_tga_la_LIBADD = $(module_libs)
 
@@ -549,6 +549,7 @@ libgdk_pixbufinclude_HEADERS =      \
 
 noinst_HEADERS =               \
        gdk-pixbuf-private.h    \
+       gdk-pixbuf-buffer-queue-private.h \
        gdk-pixbuf-scaled-anim.h \
        xpm-color-table.h
 
diff --git a/gdk-pixbuf/gdk-pixbuf-buffer-queue-private.h b/gdk-pixbuf/gdk-pixbuf-buffer-queue-private.h
new file mode 100644
index 0000000..3d82ca5
--- /dev/null
+++ b/gdk-pixbuf/gdk-pixbuf-buffer-queue-private.h
@@ -0,0 +1,51 @@
+/* GdkPixbuf library
+ * Copyright (C) 2003-2006 David Schleef <ds schleef org>
+ *              2005-2006 Eric Anholt <eric anholt net>
+ *              2006-2007 Benjamin Otte <otte gnome org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_PIXBUF_BUFFER_QUEUE_H__
+#define __GDK_PIXBUF_BUFFER_QUEUE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkPixbufBufferQueue GdkPixbufBufferQueue;
+
+GdkPixbufBufferQueue *  gdk_pixbuf_buffer_queue_new             (void);
+
+GdkPixbufBufferQueue *  gdk_pixbuf_buffer_queue_ref             (GdkPixbufBufferQueue   *queue);
+void                    gdk_pixbuf_buffer_queue_unref           (GdkPixbufBufferQueue   *queue);
+
+gsize                   gdk_pixbuf_buffer_queue_get_size        (GdkPixbufBufferQueue   *queue);
+gsize                   gdk_pixbuf_buffer_queue_get_offset      (GdkPixbufBufferQueue   *queue);
+
+void                    gdk_pixbuf_buffer_queue_flush           (GdkPixbufBufferQueue   *queue,
+                                                                 gsize                   n_bytes);
+void                    gdk_pixbuf_buffer_queue_clear           (GdkPixbufBufferQueue   *queue);
+void                    gdk_pixbuf_buffer_queue_push            (GdkPixbufBufferQueue   *queue,
+                                                                 GBytes                 *buffer);
+GBytes *                gdk_pixbuf_buffer_queue_pull            (GdkPixbufBufferQueue   *queue,
+                                                                 gsize                   length);
+GBytes *                gdk_pixbuf_buffer_queue_pull_buffer     (GdkPixbufBufferQueue   *queue);
+GBytes *                gdk_pixbuf_buffer_queue_peek            (GdkPixbufBufferQueue   *queue,
+                                                                 gsize                   length);
+GBytes *                gdk_pixbuf_buffer_queue_peek_buffer     (GdkPixbufBufferQueue   *queue);
+
+G_END_DECLS
+#endif
+
diff --git a/gdk-pixbuf/gdk-pixbuf-buffer-queue.c b/gdk-pixbuf/gdk-pixbuf-buffer-queue.c
new file mode 100644
index 0000000..1c4f007
--- /dev/null
+++ b/gdk-pixbuf/gdk-pixbuf-buffer-queue.c
@@ -0,0 +1,367 @@
+/* GdkPixbuf library
+ * Copyright (C) 2003-2006 David Schleef <ds schleef org>
+ *              2005-2006 Eric Anholt <eric anholt net>
+ *              2006-2007 Benjamin Otte <otte gnome org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gdk-pixbuf-buffer-queue-private.h"
+
+#include <string.h>
+
+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);
+}
+


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]