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 | |
26 | struct _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 | **/ |
52 | GdkPixbufBufferQueue * |
53 | gdk_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 | **/ |
71 | gsize |
72 | gdk_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 | **/ |
88 | gsize |
89 | gdk_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 | */ |
103 | void |
104 | gdk_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 | **/ |
146 | void |
147 | gdk_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 | **/ |
167 | void |
168 | gdk_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 | **/ |
203 | GBytes * |
204 | gdk_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 | **/ |
262 | GBytes * |
263 | gdk_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 | **/ |
289 | GBytes * |
290 | gdk_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 | **/ |
314 | GBytes * |
315 | gdk_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 | **/ |
336 | GdkPixbufBufferQueue * |
337 | gdk_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 | **/ |
354 | void |
355 | gdk_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 | |