Blame gdk-pixbuf/gdk-pixbuf-buffer-queue.c

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