1/* GdkPixbuf library
2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006-2007 Benjamin Otte <otte@gnome.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "config.h"
21
22#include "gdk-pixbuf-buffer-queue-private.h"
23
24#include <string.h>
25
26struct _GdkPixbufBufferQueue
27{
28 GSList * first_buffer; /* pointer to first buffer */
29 GSList * last_buffer; /* pointer to last buffer (for fast appending) */
30 gsize size; /* amount of bytes in the queue */
31 gsize offset; /* amount of data already flushed out of the queue */
32
33 int ref_count;
34};
35
36/**
37 * GdkPixbufBufferQueue:
38 *
39 * A #GdkPixbufBufferQueue is a queue of continuous buffers that allows reading
40 * its data in chunks of pre-defined sizes. It is used to transform a data
41 * stream that was provided by buffers of random sizes to buffers of the right
42 * size.
43 */
44
45/**
46 * gdk_pixbuf_buffer_queue_new:
47 *
48 * Creates a new empty buffer queue.
49 *
50 * Returns: a new buffer queue. Use gdk_pixbuf_buffer_queue_unref () to free it.
51 **/
52GdkPixbufBufferQueue *
53gdk_pixbuf_buffer_queue_new (void)
54{
55 GdkPixbufBufferQueue *buffer_queue;
56
57 buffer_queue = g_new0 (GdkPixbufBufferQueue, 1);
58 buffer_queue->ref_count = 1;
59
60 return buffer_queue;
61}
62
63/**
64 * gdk_pixbuf_buffer_queue_get_size:
65 * @queue: a #GdkPixbufBufferQueue
66 *
67 * Returns the number of bytes currently in @queue.
68 *
69 * Returns: amount of bytes in @queue.
70 **/
71gsize
72gdk_pixbuf_buffer_queue_get_size (GdkPixbufBufferQueue *queue)
73{
74 g_return_val_if_fail (queue != NULL, 0);
75
76 return queue->size;
77}
78
79/**
80 * gdk_pixbuf_buffer_queue_get_offset:
81 * @queue: a #GdkPixbufBufferQueue
82 *
83 * Queries the amount of bytes that has already been pulled out of
84 * @queue using functions like gdk_pixbuf_buffer_queue_pull().
85 *
86 * Returns: Number of bytes that were already pulled from this queue.
87 **/
88gsize
89gdk_pixbuf_buffer_queue_get_offset (GdkPixbufBufferQueue * queue)
90{
91 g_return_val_if_fail (queue != NULL, 0);
92
93 return queue->offset;
94}
95
96/**
97 * gdk_pixbuf_buffer_queue_flush:
98 * @queue: a #GdkPixbufBufferQueue
99 * @n_bytes: amount of bytes to flush from the queue
100 *
101 * Removes the first @n_bytes bytes from the queue.
102 */
103void
104gdk_pixbuf_buffer_queue_flush (GdkPixbufBufferQueue *queue, gsize n_bytes)
105{
106 g_return_if_fail (queue != NULL);
107 g_return_if_fail (n_bytes <= queue->size);
108
109 queue->size -= n_bytes;
110 queue->offset += n_bytes;
111
112 while (n_bytes > 0)
113 {
114 GBytes *bytes;
115 gsize size;
116
117 bytes = queue->first_buffer->data;
118 size = g_bytes_get_size (bytes);
119
120 if (size <= n_bytes)
121 {
122 n_bytes -= size;
123 queue->first_buffer = g_slist_remove (list: queue->first_buffer, data: bytes);
124 }
125 else
126 {
127 queue->first_buffer->data = g_bytes_new_from_bytes (bytes,
128 offset: n_bytes,
129 length: size - n_bytes);
130 n_bytes = 0;
131 }
132 g_bytes_unref (bytes);
133 }
134
135 if (queue->first_buffer == NULL)
136 queue->last_buffer = NULL;
137}
138
139/**
140 * gdk_pixbuf_buffer_queue_clear:
141 * @queue: a #GdkPixbufBufferQueue
142 *
143 * Resets @queue into to initial state. All buffers it contains will be
144 * released and the offset will be reset to 0.
145 **/
146void
147gdk_pixbuf_buffer_queue_clear (GdkPixbufBufferQueue *queue)
148{
149 g_return_if_fail (queue != NULL);
150
151 g_slist_free_full (list: queue->first_buffer, free_func: (GDestroyNotify) g_bytes_unref);
152 queue->first_buffer = NULL;
153 queue->last_buffer = NULL;
154 queue->size = 0;
155 queue->offset = 0;
156}
157
158/**
159 * gdk_pixbuf_buffer_queue_push:
160 * @queue: a #GdkPixbufBufferQueue
161 * @bytes: #GBytes to append to @queue
162 *
163 * Appends the given @bytes to the buffers already in @queue. This function
164 * will take ownership of the given @buffer. Use g_bytes_ref () before
165 * calling this function to keep a reference.
166 **/
167void
168gdk_pixbuf_buffer_queue_push (GdkPixbufBufferQueue *queue,
169 GBytes *bytes)
170{
171 gsize size;
172
173 g_return_if_fail (queue != NULL);
174 g_return_if_fail (bytes != NULL);
175
176 size = g_bytes_get_size (bytes);
177 if (size == 0)
178 {
179 g_bytes_unref (bytes);
180 return;
181 }
182
183 queue->last_buffer = g_slist_append (list: queue->last_buffer, data: bytes);
184 if (queue->first_buffer == NULL)
185 queue->first_buffer = queue->last_buffer;
186 else
187 queue->last_buffer = queue->last_buffer->next;
188
189 queue->size += size;
190}
191
192/**
193 * gdk_pixbuf_buffer_queue_peek:
194 * @queue: a #GdkPixbufBufferQueue to read from
195 * @length: amount of bytes to peek
196 *
197 * Creates a new buffer with the first @length bytes from @queue, but unlike
198 * gdk_pixbuf_buffer_queue_pull(), does not remove them from @queue.
199 *
200 * Returns: NULL if the requested amount of data wasn't available or a new
201 * #GBytes. Use g_bytes_unref() after use.
202 **/
203GBytes *
204gdk_pixbuf_buffer_queue_peek (GdkPixbufBufferQueue *queue,
205 gsize length)
206{
207 GSList *g;
208 GBytes *result, *bytes;
209
210 g_return_val_if_fail (queue != NULL, NULL);
211
212 if (queue->size < length)
213 return NULL;
214
215 /* need to special case here, because the queue may be empty */
216 if (length == 0)
217 return g_bytes_new (NULL, size: 0);
218
219 g = queue->first_buffer;
220 bytes = g->data;
221 if (g_bytes_get_size (bytes) == length)
222 {
223 result = g_bytes_ref (bytes);
224 }
225 else if (g_bytes_get_size (bytes) > length)
226 {
227 result = g_bytes_new_from_bytes (bytes, offset: 0, length);
228 }
229 else
230 {
231 guchar *data;
232 gsize amount, offset;
233
234 data = g_malloc (n_bytes: length);
235
236 for (offset = 0; offset < length; offset += amount)
237 {
238 bytes = g->data;
239 amount = MIN (length - offset, g_bytes_get_size (bytes));
240 memcpy (dest: data + offset, src: g_bytes_get_data (bytes, NULL), n: amount);
241 g = g->next;
242 }
243
244 result = g_bytes_new_take (data, size: length);
245 }
246
247 return result;
248}
249
250/**
251 * gdk_pixbuf_buffer_queue_pull:
252 * @queue: a #GdkPixbufBufferQueue
253 * @length: amount of bytes to pull
254 *
255 * If enough data is still available in @queue, the first @length bytes are
256 * put into a new buffer and that buffer is returned. The @length bytes are
257 * removed from the head of the queue. If not enough data is available, %NULL
258 * is returned.
259 *
260 * Returns: a new #GBytes or %NULL
261 **/
262GBytes *
263gdk_pixbuf_buffer_queue_pull (GdkPixbufBufferQueue * queue, gsize length)
264{
265 GBytes *result;
266
267 g_return_val_if_fail (queue != NULL, NULL);
268
269 result = gdk_pixbuf_buffer_queue_peek (queue, length);
270 if (result == NULL)
271 return NULL;
272
273 gdk_pixbuf_buffer_queue_flush (queue, n_bytes: length);
274
275 return result;
276}
277
278/**
279 * gdk_pixbuf_buffer_queue_peek_buffer:
280 * @queue: a #GdkPixbufBufferQueue
281 *
282 * Gets the first buffer out of @queue and returns it. This function is
283 * equivalent to calling gdk_pixbuf_buffer_queue_peek() with the size of the
284 * first buffer in it.
285 *
286 * Returns: The first buffer in @queue or %NULL if @queue is empty. Use
287 * g_bytes_unref() after use.
288 **/
289GBytes *
290gdk_pixbuf_buffer_queue_peek_buffer (GdkPixbufBufferQueue * queue)
291{
292 GBytes *bytes;
293
294 g_return_val_if_fail (queue != NULL, NULL);
295
296 if (queue->first_buffer == NULL)
297 return NULL;
298
299 bytes = queue->first_buffer->data;
300
301 return g_bytes_ref (bytes);
302}
303
304/**
305 * gdk_pixbuf_buffer_queue_pull_buffer:
306 * @queue: a #GdkPixbufBufferQueue
307 *
308 * Pulls the first buffer out of @queue and returns it. This function is
309 * equivalent to calling gdk_pixbuf_buffer_queue_pull() with the size of the
310 * first buffer in it.
311 *
312 * Returns: The first buffer in @queue or %NULL if @queue is empty.
313 **/
314GBytes *
315gdk_pixbuf_buffer_queue_pull_buffer (GdkPixbufBufferQueue *queue)
316{
317 GBytes *bytes;
318
319 g_return_val_if_fail (queue != NULL, NULL);
320
321 bytes = gdk_pixbuf_buffer_queue_peek_buffer (queue);
322 if (bytes)
323 gdk_pixbuf_buffer_queue_flush (queue, n_bytes: g_bytes_get_size (bytes));
324
325 return bytes;
326}
327
328/**
329 * gdk_pixbuf_buffer_queue_ref:
330 * @queue: a #GdkPixbufBufferQueue
331 *
332 * increases the reference count of @queue by one.
333 *
334 * Returns: The passed in @queue.
335 **/
336GdkPixbufBufferQueue *
337gdk_pixbuf_buffer_queue_ref (GdkPixbufBufferQueue * queue)
338{
339 g_return_val_if_fail (queue != NULL, NULL);
340 g_return_val_if_fail (queue->ref_count > 0, NULL);
341
342 queue->ref_count++;
343 return queue;
344}
345
346/**
347 * gdk_pixbuf_buffer_queue_unref:
348 * @queue: a #GdkPixbufBufferQueue
349 *
350 * Decreases the reference count of @queue by one. If no reference
351 * to this buffer exists anymore, the buffer and the memory
352 * it manages are freed.
353 **/
354void
355gdk_pixbuf_buffer_queue_unref (GdkPixbufBufferQueue * queue)
356{
357 g_return_if_fail (queue != NULL);
358 g_return_if_fail (queue->ref_count > 0);
359
360 queue->ref_count--;
361 if (queue->ref_count > 0)
362 return;
363
364 gdk_pixbuf_buffer_queue_clear (queue);
365 g_free (mem: queue);
366}
367
368

source code of gtk/subprojects/gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-buffer-queue.c