1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Author: Christian Kellner <gicmo@gnome.org>
21 */
22
23 #include "config.h"
24 #include "gmemoryinputstream.h"
25 #include "ginputstream.h"
26 #include "gseekable.h"
27 #include "string.h"
28 #include "gsimpleasyncresult.h"
29 #include "gioerror.h"
30 #include "glibintl.h"
31
32 #include "gioalias.h"
33
34 /**
35 * SECTION:gmemoryinputstream
36 * @short_description: Streaming input operations on memory chunks
37 * @include: gio/gio.h
38 * @see_also: #GMemoryOutputStream
39 *
40 * #GMemoryInputStream is a class for using arbitrary
41 * memory chunks as input for GIO streaming input operations.
42 *
43 */
44
45 typedef struct _Chunk Chunk;
46
47 struct _Chunk {
48 guint8 *data;
49 gsize len;
50 GDestroyNotify destroy;
51 };
52
53 struct _GMemoryInputStreamPrivate {
54 GSList *chunks;
55 gsize len;
56 gsize pos;
57 };
58
59 static gssize g_memory_input_stream_read (GInputStream *stream,
60 void *buffer,
61 gsize count,
62 GCancellable *cancellable,
63 GError **error);
64 static gssize g_memory_input_stream_skip (GInputStream *stream,
65 gsize count,
66 GCancellable *cancellable,
67 GError **error);
68 static gboolean g_memory_input_stream_close (GInputStream *stream,
69 GCancellable *cancellable,
70 GError **error);
71 static void g_memory_input_stream_read_async (GInputStream *stream,
72 void *buffer,
73 gsize count,
74 int io_priority,
75 GCancellable *cancellable,
76 GAsyncReadyCallback callback,
77 gpointer user_data);
78 static gssize g_memory_input_stream_read_finish (GInputStream *stream,
79 GAsyncResult *result,
80 GError **error);
81 static void g_memory_input_stream_skip_async (GInputStream *stream,
82 gsize count,
83 int io_priority,
84 GCancellable *cancellabl,
85 GAsyncReadyCallback callback,
86 gpointer datae);
87 static gssize g_memory_input_stream_skip_finish (GInputStream *stream,
88 GAsyncResult *result,
89 GError **error);
90 static void g_memory_input_stream_close_async (GInputStream *stream,
91 int io_priority,
92 GCancellable *cancellabl,
93 GAsyncReadyCallback callback,
94 gpointer data);
95 static gboolean g_memory_input_stream_close_finish (GInputStream *stream,
96 GAsyncResult *result,
97 GError **error);
98
99 static void g_memory_input_stream_seekable_iface_init (GSeekableIface *iface);
100 static goffset g_memory_input_stream_tell (GSeekable *seekable);
101 static gboolean g_memory_input_stream_can_seek (GSeekable *seekable);
102 static gboolean g_memory_input_stream_seek (GSeekable *seekable,
103 goffset offset,
104 GSeekType type,
105 GCancellable *cancellable,
106 GError **error);
107 static gboolean g_memory_input_stream_can_truncate (GSeekable *seekable);
108 static gboolean g_memory_input_stream_truncate (GSeekable *seekable,
109 goffset offset,
110 GCancellable *cancellable,
111 GError **error);
112 static void g_memory_input_stream_finalize (GObject *object);
113
G_DEFINE_TYPE_WITH_CODE(GMemoryInputStream,g_memory_input_stream,G_TYPE_INPUT_STREAM,G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,g_memory_input_stream_seekable_iface_init))114 G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream, g_memory_input_stream, G_TYPE_INPUT_STREAM,
115 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
116 g_memory_input_stream_seekable_iface_init))
117
118
119 static void
120 g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
121 {
122 GObjectClass *object_class;
123 GInputStreamClass *istream_class;
124
125 g_type_class_add_private (klass, sizeof (GMemoryInputStreamPrivate));
126
127 object_class = G_OBJECT_CLASS (klass);
128 object_class->finalize = g_memory_input_stream_finalize;
129
130 istream_class = G_INPUT_STREAM_CLASS (klass);
131 istream_class->read_fn = g_memory_input_stream_read;
132 istream_class->skip = g_memory_input_stream_skip;
133 istream_class->close_fn = g_memory_input_stream_close;
134
135 istream_class->read_async = g_memory_input_stream_read_async;
136 istream_class->read_finish = g_memory_input_stream_read_finish;
137 istream_class->skip_async = g_memory_input_stream_skip_async;
138 istream_class->skip_finish = g_memory_input_stream_skip_finish;
139 istream_class->close_async = g_memory_input_stream_close_async;
140 istream_class->close_finish = g_memory_input_stream_close_finish;
141 }
142
143 static void
free_chunk(gpointer data,gpointer user_data)144 free_chunk (gpointer data,
145 gpointer user_data)
146 {
147 Chunk *chunk = data;
148
149 if (chunk->destroy)
150 chunk->destroy (chunk->data);
151
152 g_slice_free (Chunk, chunk);
153 }
154
155 static void
g_memory_input_stream_finalize(GObject * object)156 g_memory_input_stream_finalize (GObject *object)
157 {
158 GMemoryInputStream *stream;
159 GMemoryInputStreamPrivate *priv;
160
161 stream = G_MEMORY_INPUT_STREAM (object);
162 priv = stream->priv;
163
164 g_slist_foreach (priv->chunks, free_chunk, NULL);
165 g_slist_free (priv->chunks);
166
167 G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
168 }
169
170 static void
g_memory_input_stream_seekable_iface_init(GSeekableIface * iface)171 g_memory_input_stream_seekable_iface_init (GSeekableIface *iface)
172 {
173 iface->tell = g_memory_input_stream_tell;
174 iface->can_seek = g_memory_input_stream_can_seek;
175 iface->seek = g_memory_input_stream_seek;
176 iface->can_truncate = g_memory_input_stream_can_truncate;
177 iface->truncate_fn = g_memory_input_stream_truncate;
178 }
179
180 static void
g_memory_input_stream_init(GMemoryInputStream * stream)181 g_memory_input_stream_init (GMemoryInputStream *stream)
182 {
183 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
184 G_TYPE_MEMORY_INPUT_STREAM,
185 GMemoryInputStreamPrivate);
186 }
187
188 /**
189 * g_memory_input_stream_new:
190 *
191 * Creates a new empty #GMemoryInputStream.
192 *
193 * Returns: a new #GInputStream
194 */
195 GInputStream *
g_memory_input_stream_new(void)196 g_memory_input_stream_new (void)
197 {
198 GInputStream *stream;
199
200 stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
201
202 return stream;
203 }
204
205 /**
206 * g_memory_input_stream_new_from_data:
207 * @data: input data
208 * @len: length of the data, may be -1 if @data is a nul-terminated string
209 * @destroy: function that is called to free @data, or %NULL
210 *
211 * Creates a new #GMemoryInputStream with data in memory of a given size.
212 *
213 * Returns: new #GInputStream read from @data of @len bytes.
214 **/
215 GInputStream *
g_memory_input_stream_new_from_data(const void * data,gssize len,GDestroyNotify destroy)216 g_memory_input_stream_new_from_data (const void *data,
217 gssize len,
218 GDestroyNotify destroy)
219 {
220 GInputStream *stream;
221
222 stream = g_memory_input_stream_new ();
223
224 g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
225 data, len, destroy);
226
227 return stream;
228 }
229
230 /**
231 * g_memory_input_stream_add_data:
232 * @stream: a #GMemoryInputStream
233 * @data: input data
234 * @len: length of the data, may be -1 if @data is a nul-terminated string
235 * @destroy: function that is called to free @data, or %NULL
236 *
237 * Appends @data to data that can be read from the input stream
238 */
239 void
g_memory_input_stream_add_data(GMemoryInputStream * stream,const void * data,gssize len,GDestroyNotify destroy)240 g_memory_input_stream_add_data (GMemoryInputStream *stream,
241 const void *data,
242 gssize len,
243 GDestroyNotify destroy)
244 {
245 GMemoryInputStreamPrivate *priv;
246 Chunk *chunk;
247
248 g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
249 g_return_if_fail (data != NULL);
250
251 priv = stream->priv;
252
253 if (len == -1)
254 len = strlen (data);
255
256 chunk = g_slice_new (Chunk);
257 chunk->data = (guint8 *)data;
258 chunk->len = len;
259 chunk->destroy = destroy;
260
261 priv->chunks = g_slist_append (priv->chunks, chunk);
262 priv->len += chunk->len;
263 }
264
265 static gssize
g_memory_input_stream_read(GInputStream * stream,void * buffer,gsize count,GCancellable * cancellable,GError ** error)266 g_memory_input_stream_read (GInputStream *stream,
267 void *buffer,
268 gsize count,
269 GCancellable *cancellable,
270 GError **error)
271 {
272 GMemoryInputStream *memory_stream;
273 GMemoryInputStreamPrivate *priv;
274 GSList *l;
275 Chunk *chunk;
276 gsize offset, start, rest, size;
277
278 memory_stream = G_MEMORY_INPUT_STREAM (stream);
279 priv = memory_stream->priv;
280
281 count = MIN (count, priv->len - priv->pos);
282
283 offset = 0;
284 for (l = priv->chunks; l; l = l->next)
285 {
286 chunk = (Chunk *)l->data;
287
288 if (offset + chunk->len > priv->pos)
289 break;
290
291 offset += chunk->len;
292 }
293
294 start = priv->pos - offset;
295 rest = count;
296
297 for (; l && rest > 0; l = l->next)
298 {
299 chunk = (Chunk *)l->data;
300 size = MIN (rest, chunk->len - start);
301
302 memcpy ((guint8 *)buffer + (count - rest), chunk->data + start, size);
303 rest -= size;
304
305 start = 0;
306 }
307
308 priv->pos += count;
309
310 return count;
311 }
312
313 static gssize
g_memory_input_stream_skip(GInputStream * stream,gsize count,GCancellable * cancellable,GError ** error)314 g_memory_input_stream_skip (GInputStream *stream,
315 gsize count,
316 GCancellable *cancellable,
317 GError **error)
318 {
319 GMemoryInputStream *memory_stream;
320 GMemoryInputStreamPrivate *priv;
321
322 memory_stream = G_MEMORY_INPUT_STREAM (stream);
323 priv = memory_stream->priv;
324
325 count = MIN (count, priv->len - priv->pos);
326 priv->pos += count;
327
328 return count;
329 }
330
331 static gboolean
g_memory_input_stream_close(GInputStream * stream,GCancellable * cancellable,GError ** error)332 g_memory_input_stream_close (GInputStream *stream,
333 GCancellable *cancellable,
334 GError **error)
335 {
336 return TRUE;
337 }
338
339 static void
g_memory_input_stream_read_async(GInputStream * stream,void * buffer,gsize count,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)340 g_memory_input_stream_read_async (GInputStream *stream,
341 void *buffer,
342 gsize count,
343 int io_priority,
344 GCancellable *cancellable,
345 GAsyncReadyCallback callback,
346 gpointer user_data)
347 {
348 GSimpleAsyncResult *simple;
349 gssize nread;
350
351 nread = g_memory_input_stream_read (stream, buffer, count, cancellable, NULL);
352 simple = g_simple_async_result_new (G_OBJECT (stream),
353 callback,
354 user_data,
355 g_memory_input_stream_read_async);
356 g_simple_async_result_set_op_res_gssize (simple, nread);
357 g_simple_async_result_complete_in_idle (simple);
358 g_object_unref (simple);
359 }
360
361 static gssize
g_memory_input_stream_read_finish(GInputStream * stream,GAsyncResult * result,GError ** error)362 g_memory_input_stream_read_finish (GInputStream *stream,
363 GAsyncResult *result,
364 GError **error)
365 {
366 GSimpleAsyncResult *simple;
367 gssize nread;
368
369 simple = G_SIMPLE_ASYNC_RESULT (result);
370 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_read_async);
371
372 nread = g_simple_async_result_get_op_res_gssize (simple);
373 return nread;
374 }
375
376 static void
g_memory_input_stream_skip_async(GInputStream * stream,gsize count,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)377 g_memory_input_stream_skip_async (GInputStream *stream,
378 gsize count,
379 int io_priority,
380 GCancellable *cancellable,
381 GAsyncReadyCallback callback,
382 gpointer user_data)
383 {
384 GSimpleAsyncResult *simple;
385 gssize nskipped;
386
387 nskipped = g_memory_input_stream_skip (stream, count, cancellable, NULL);
388 simple = g_simple_async_result_new (G_OBJECT (stream),
389 callback,
390 user_data,
391 g_memory_input_stream_skip_async);
392 g_simple_async_result_set_op_res_gssize (simple, nskipped);
393 g_simple_async_result_complete_in_idle (simple);
394 g_object_unref (simple);
395 }
396
397 static gssize
g_memory_input_stream_skip_finish(GInputStream * stream,GAsyncResult * result,GError ** error)398 g_memory_input_stream_skip_finish (GInputStream *stream,
399 GAsyncResult *result,
400 GError **error)
401 {
402 GSimpleAsyncResult *simple;
403 gssize nskipped;
404
405 simple = G_SIMPLE_ASYNC_RESULT (result);
406 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_skip_async);
407
408 nskipped = g_simple_async_result_get_op_res_gssize (simple);
409 return nskipped;
410 }
411
412 static void
g_memory_input_stream_close_async(GInputStream * stream,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)413 g_memory_input_stream_close_async (GInputStream *stream,
414 int io_priority,
415 GCancellable *cancellable,
416 GAsyncReadyCallback callback,
417 gpointer user_data)
418 {
419 GSimpleAsyncResult *simple;
420
421 simple = g_simple_async_result_new (G_OBJECT (stream),
422 callback,
423 user_data,
424 g_memory_input_stream_close_async);
425 g_simple_async_result_complete_in_idle (simple);
426 g_object_unref (simple);
427 }
428
429 static gboolean
g_memory_input_stream_close_finish(GInputStream * stream,GAsyncResult * result,GError ** error)430 g_memory_input_stream_close_finish (GInputStream *stream,
431 GAsyncResult *result,
432 GError **error)
433 {
434 return TRUE;
435 }
436
437 static goffset
g_memory_input_stream_tell(GSeekable * seekable)438 g_memory_input_stream_tell (GSeekable *seekable)
439 {
440 GMemoryInputStream *memory_stream;
441 GMemoryInputStreamPrivate *priv;
442
443 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
444 priv = memory_stream->priv;
445
446 return priv->pos;
447 }
448
449 static
g_memory_input_stream_can_seek(GSeekable * seekable)450 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
451 {
452 return TRUE;
453 }
454
455 static gboolean
g_memory_input_stream_seek(GSeekable * seekable,goffset offset,GSeekType type,GCancellable * cancellable,GError ** error)456 g_memory_input_stream_seek (GSeekable *seekable,
457 goffset offset,
458 GSeekType type,
459 GCancellable *cancellable,
460 GError **error)
461 {
462 GMemoryInputStream *memory_stream;
463 GMemoryInputStreamPrivate *priv;
464 goffset absolute;
465
466 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
467 priv = memory_stream->priv;
468
469 switch (type)
470 {
471 case G_SEEK_CUR:
472 absolute = priv->pos + offset;
473 break;
474
475 case G_SEEK_SET:
476 absolute = offset;
477 break;
478
479 case G_SEEK_END:
480 absolute = priv->len + offset;
481 break;
482
483 default:
484 g_set_error_literal (error,
485 G_IO_ERROR,
486 G_IO_ERROR_INVALID_ARGUMENT,
487 _("Invalid GSeekType supplied"));
488
489 return FALSE;
490 }
491
492 if (absolute < 0 || absolute > priv->len)
493 {
494 g_set_error_literal (error,
495 G_IO_ERROR,
496 G_IO_ERROR_INVALID_ARGUMENT,
497 _("Invalid seek request"));
498 return FALSE;
499 }
500
501 priv->pos = absolute;
502
503 return TRUE;
504 }
505
506 static gboolean
g_memory_input_stream_can_truncate(GSeekable * seekable)507 g_memory_input_stream_can_truncate (GSeekable *seekable)
508 {
509 return FALSE;
510 }
511
512 static gboolean
g_memory_input_stream_truncate(GSeekable * seekable,goffset offset,GCancellable * cancellable,GError ** error)513 g_memory_input_stream_truncate (GSeekable *seekable,
514 goffset offset,
515 GCancellable *cancellable,
516 GError **error)
517 {
518 g_set_error_literal (error,
519 G_IO_ERROR,
520 G_IO_ERROR_NOT_SUPPORTED,
521 _("Cannot truncate GMemoryInputStream"));
522 return FALSE;
523 }
524
525 #define __G_MEMORY_INPUT_STREAM_C__
526 #include "gioaliasdef.c"
527