gio: use GPollable* to implement fallback read_async/write_async
[platform/upstream/glib.git] / gio / gmemoryinputstream.c
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 "gpollableinputstream.h"
26 #include "ginputstream.h"
27 #include "gseekable.h"
28 #include "string.h"
29 #include "gsimpleasyncresult.h"
30 #include "gioerror.h"
31 #include "glibintl.h"
32
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  * As of GLib 2.34, #GMemoryInputStream implements
44  * #GPollableInputStream.
45  */
46
47 typedef struct _Chunk Chunk;
48
49 struct _Chunk {
50   guint8         *data;
51   gsize           len;
52   GDestroyNotify  destroy;
53 };
54
55 struct _GMemoryInputStreamPrivate {
56   GSList *chunks;
57   gsize   len;
58   gsize   pos;
59 };
60
61 static gssize   g_memory_input_stream_read         (GInputStream         *stream,
62                                                     void                 *buffer,
63                                                     gsize                 count,
64                                                     GCancellable         *cancellable,
65                                                     GError              **error);
66 static gssize   g_memory_input_stream_skip         (GInputStream         *stream,
67                                                     gsize                 count,
68                                                     GCancellable         *cancellable,
69                                                     GError              **error);
70 static gboolean g_memory_input_stream_close        (GInputStream         *stream,
71                                                     GCancellable         *cancellable,
72                                                     GError              **error);
73 static void     g_memory_input_stream_skip_async   (GInputStream         *stream,
74                                                     gsize                 count,
75                                                     int                   io_priority,
76                                                     GCancellable         *cancellabl,
77                                                     GAsyncReadyCallback   callback,
78                                                     gpointer              datae);
79 static gssize   g_memory_input_stream_skip_finish  (GInputStream         *stream,
80                                                     GAsyncResult         *result,
81                                                     GError              **error);
82 static void     g_memory_input_stream_close_async  (GInputStream         *stream,
83                                                     int                   io_priority,
84                                                     GCancellable         *cancellabl,
85                                                     GAsyncReadyCallback   callback,
86                                                     gpointer              data);
87 static gboolean g_memory_input_stream_close_finish (GInputStream         *stream,
88                                                     GAsyncResult         *result,
89                                                     GError              **error);
90
91 static void     g_memory_input_stream_seekable_iface_init (GSeekableIface  *iface);
92 static goffset  g_memory_input_stream_tell                (GSeekable       *seekable);
93 static gboolean g_memory_input_stream_can_seek            (GSeekable       *seekable);
94 static gboolean g_memory_input_stream_seek                (GSeekable       *seekable,
95                                                            goffset          offset,
96                                                            GSeekType        type,
97                                                            GCancellable    *cancellable,
98                                                            GError         **error);
99 static gboolean g_memory_input_stream_can_truncate        (GSeekable       *seekable);
100 static gboolean g_memory_input_stream_truncate            (GSeekable       *seekable,
101                                                            goffset          offset,
102                                                            GCancellable    *cancellable,
103                                                            GError         **error);
104
105 static void     g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface);
106 static gboolean g_memory_input_stream_is_readable         (GPollableInputStream *stream);
107 static GSource *g_memory_input_stream_create_source       (GPollableInputStream *stream,
108                                                            GCancellable          *cancellable);
109
110 static void     g_memory_input_stream_finalize            (GObject         *object);
111
112 G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream, g_memory_input_stream, G_TYPE_INPUT_STREAM,
113                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
114                                                 g_memory_input_stream_seekable_iface_init);
115                          G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
116                                                 g_memory_input_stream_pollable_iface_init);
117                          )
118
119
120 static void
121 g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
122 {
123   GObjectClass *object_class;
124   GInputStreamClass *istream_class;
125
126   g_type_class_add_private (klass, sizeof (GMemoryInputStreamPrivate));
127
128   object_class = G_OBJECT_CLASS (klass);
129   object_class->finalize     = g_memory_input_stream_finalize;
130   
131   istream_class = G_INPUT_STREAM_CLASS (klass);
132   istream_class->read_fn  = g_memory_input_stream_read;
133   istream_class->skip  = g_memory_input_stream_skip;
134   istream_class->close_fn = g_memory_input_stream_close;
135
136   istream_class->skip_async  = g_memory_input_stream_skip_async;
137   istream_class->skip_finish  = g_memory_input_stream_skip_finish;
138   istream_class->close_async = g_memory_input_stream_close_async;
139   istream_class->close_finish = g_memory_input_stream_close_finish;
140 }
141
142 static void
143 free_chunk (gpointer data)
144 {
145   Chunk *chunk = data;
146
147   if (chunk->destroy)
148     chunk->destroy (chunk->data);
149
150   g_slice_free (Chunk, chunk);
151 }
152
153 static void
154 g_memory_input_stream_finalize (GObject *object)
155 {
156   GMemoryInputStream        *stream;
157   GMemoryInputStreamPrivate *priv;
158
159   stream = G_MEMORY_INPUT_STREAM (object);
160   priv = stream->priv;
161
162   g_slist_free_full (priv->chunks, free_chunk);
163
164   G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
165 }
166
167 static void
168 g_memory_input_stream_seekable_iface_init (GSeekableIface *iface)
169 {
170   iface->tell         = g_memory_input_stream_tell;
171   iface->can_seek     = g_memory_input_stream_can_seek;
172   iface->seek         = g_memory_input_stream_seek;
173   iface->can_truncate = g_memory_input_stream_can_truncate;
174   iface->truncate_fn  = g_memory_input_stream_truncate;
175 }
176
177 static void
178 g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface)
179 {
180   iface->is_readable   = g_memory_input_stream_is_readable;
181   iface->create_source = g_memory_input_stream_create_source;
182 }
183
184 static void
185 g_memory_input_stream_init (GMemoryInputStream *stream)
186 {
187   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
188                                               G_TYPE_MEMORY_INPUT_STREAM,
189                                               GMemoryInputStreamPrivate);
190 }
191
192 /**
193  * g_memory_input_stream_new:
194  *
195  * Creates a new empty #GMemoryInputStream. 
196  *
197  * Returns: a new #GInputStream
198  */
199 GInputStream *
200 g_memory_input_stream_new (void)
201 {
202   GInputStream *stream;
203
204   stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
205
206   return stream;
207 }
208
209 /**
210  * g_memory_input_stream_new_from_data:
211  * @data: (array length=len) (element-type guint8) (transfer full): input data
212  * @len: length of the data, may be -1 if @data is a nul-terminated string
213  * @destroy: (allow-none): function that is called to free @data, or %NULL
214  *
215  * Creates a new #GMemoryInputStream with data in memory of a given size.
216  * 
217  * Returns: new #GInputStream read from @data of @len bytes.
218  **/
219 GInputStream *
220 g_memory_input_stream_new_from_data (const void     *data, 
221                                      gssize          len,
222                                      GDestroyNotify  destroy)
223 {
224   GInputStream *stream;
225
226   stream = g_memory_input_stream_new ();
227
228   g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
229                                   data, len, destroy);
230
231   return stream;
232 }
233
234 /**
235  * g_memory_input_stream_add_data:
236  * @stream: a #GMemoryInputStream
237  * @data: (array length=len) (element-type guint8) (transfer full): input data
238  * @len: length of the data, may be -1 if @data is a nul-terminated string
239  * @destroy: (allow-none): function that is called to free @data, or %NULL
240  *
241  * Appends @data to data that can be read from the input stream
242  */
243 void
244 g_memory_input_stream_add_data (GMemoryInputStream *stream,
245                                 const void         *data,
246                                 gssize              len,
247                                 GDestroyNotify      destroy)
248 {
249   GMemoryInputStreamPrivate *priv;
250   Chunk *chunk;
251  
252   g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
253   g_return_if_fail (data != NULL);
254
255   priv = stream->priv;
256
257   if (len == -1)
258     len = strlen (data);
259   
260   chunk = g_slice_new (Chunk);
261   chunk->data = (guint8 *)data;
262   chunk->len = len;
263   chunk->destroy = destroy;
264
265   priv->chunks = g_slist_append (priv->chunks, chunk);
266   priv->len += chunk->len;
267 }
268
269 static gssize
270 g_memory_input_stream_read (GInputStream  *stream,
271                             void          *buffer,
272                             gsize          count,
273                             GCancellable  *cancellable,
274                             GError       **error)
275 {
276   GMemoryInputStream *memory_stream;
277   GMemoryInputStreamPrivate *priv;
278   GSList *l;
279   Chunk *chunk;
280   gsize offset, start, rest, size;
281
282   memory_stream = G_MEMORY_INPUT_STREAM (stream);
283   priv = memory_stream->priv;
284
285   count = MIN (count, priv->len - priv->pos);
286
287   offset = 0;
288   for (l = priv->chunks; l; l = l->next) 
289     {
290       chunk = (Chunk *)l->data;
291
292       if (offset + chunk->len > priv->pos)
293         break;
294
295       offset += chunk->len;
296     }
297   
298   start = priv->pos - offset;
299   rest = count;
300
301   for (; l && rest > 0; l = l->next)
302     {
303       chunk = (Chunk *)l->data;
304       size = MIN (rest, chunk->len - start);
305
306       memcpy ((guint8 *)buffer + (count - rest), chunk->data + start, size);
307       rest -= size;
308
309       start = 0;
310     }
311
312   priv->pos += count;
313
314   return count;
315 }
316
317 static gssize
318 g_memory_input_stream_skip (GInputStream  *stream,
319                             gsize          count,
320                             GCancellable  *cancellable,
321                             GError       **error)
322 {
323   GMemoryInputStream *memory_stream;
324   GMemoryInputStreamPrivate *priv;
325
326   memory_stream = G_MEMORY_INPUT_STREAM (stream);
327   priv = memory_stream->priv;
328
329   count = MIN (count, priv->len - priv->pos);
330   priv->pos += count;
331
332   return count;
333 }
334
335 static gboolean
336 g_memory_input_stream_close (GInputStream  *stream,
337                              GCancellable  *cancellable,
338                              GError       **error)
339 {
340   return TRUE;
341 }
342
343 static void
344 g_memory_input_stream_skip_async (GInputStream        *stream,
345                                   gsize                count,
346                                   int                  io_priority,
347                                   GCancellable        *cancellable,
348                                   GAsyncReadyCallback  callback,
349                                   gpointer             user_data)
350 {
351   GSimpleAsyncResult *simple;
352   gssize nskipped;
353
354   nskipped = g_input_stream_skip (stream, count, cancellable, NULL);
355   simple = g_simple_async_result_new (G_OBJECT (stream),
356                                       callback,
357                                       user_data,
358                                       g_memory_input_stream_skip_async);
359   g_simple_async_result_set_op_res_gssize (simple, nskipped);
360   g_simple_async_result_complete_in_idle (simple);
361   g_object_unref (simple);
362 }
363
364 static gssize
365 g_memory_input_stream_skip_finish (GInputStream  *stream,
366                                    GAsyncResult  *result,
367                                    GError       **error)
368 {
369   GSimpleAsyncResult *simple;
370   gssize nskipped;
371
372   simple = G_SIMPLE_ASYNC_RESULT (result);
373   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_skip_async);
374   
375   nskipped = g_simple_async_result_get_op_res_gssize (simple);
376   return nskipped;
377 }
378
379 static void
380 g_memory_input_stream_close_async (GInputStream        *stream,
381                                    int                  io_priority,
382                                    GCancellable        *cancellable,
383                                    GAsyncReadyCallback  callback,
384                                    gpointer             user_data)
385 {
386   GSimpleAsyncResult *simple;
387   
388   simple = g_simple_async_result_new (G_OBJECT (stream),
389                                       callback,
390                                       user_data,
391                                       g_memory_input_stream_close_async);
392   g_simple_async_result_complete_in_idle (simple);
393   g_object_unref (simple);
394 }
395
396 static gboolean
397 g_memory_input_stream_close_finish (GInputStream  *stream,
398                                     GAsyncResult  *result,
399                                     GError       **error)
400 {
401   return TRUE;
402 }
403
404 static goffset
405 g_memory_input_stream_tell (GSeekable *seekable)
406 {
407   GMemoryInputStream *memory_stream;
408   GMemoryInputStreamPrivate *priv;
409
410   memory_stream = G_MEMORY_INPUT_STREAM (seekable);
411   priv = memory_stream->priv;
412
413   return priv->pos;
414 }
415
416 static
417 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
418 {
419   return TRUE;
420 }
421
422 static gboolean
423 g_memory_input_stream_seek (GSeekable     *seekable,
424                             goffset        offset,
425                             GSeekType      type,
426                             GCancellable  *cancellable,
427                             GError       **error)
428 {
429   GMemoryInputStream *memory_stream;
430   GMemoryInputStreamPrivate *priv;
431   goffset absolute;
432
433   memory_stream = G_MEMORY_INPUT_STREAM (seekable);
434   priv = memory_stream->priv;
435
436   switch (type) 
437     {
438     case G_SEEK_CUR:
439       absolute = priv->pos + offset;
440       break;
441
442     case G_SEEK_SET:
443       absolute = offset;
444       break;
445
446     case G_SEEK_END:
447       absolute = priv->len + offset;
448       break;
449   
450     default:
451       g_set_error_literal (error,
452                            G_IO_ERROR,
453                            G_IO_ERROR_INVALID_ARGUMENT,
454                            _("Invalid GSeekType supplied"));
455
456       return FALSE;
457     }
458
459   if (absolute < 0 || absolute > priv->len)
460     {
461       g_set_error_literal (error,
462                            G_IO_ERROR,
463                            G_IO_ERROR_INVALID_ARGUMENT,
464                            _("Invalid seek request"));
465       return FALSE;
466     }
467
468   priv->pos = absolute;
469
470   return TRUE;
471 }
472
473 static gboolean
474 g_memory_input_stream_can_truncate (GSeekable *seekable)
475 {
476   return FALSE;
477 }
478
479 static gboolean
480 g_memory_input_stream_truncate (GSeekable     *seekable,
481                                 goffset        offset,
482                                 GCancellable  *cancellable,
483                                 GError       **error)
484 {
485   g_set_error_literal (error,
486                        G_IO_ERROR,
487                        G_IO_ERROR_NOT_SUPPORTED,
488                        _("Cannot truncate GMemoryInputStream"));
489   return FALSE;
490 }
491
492 static gboolean
493 g_memory_input_stream_is_readable (GPollableInputStream *stream)
494 {
495   return TRUE;
496 }
497
498 static GSource *
499 g_memory_input_stream_create_source (GPollableInputStream *stream,
500                                      GCancellable         *cancellable)
501 {
502   GSource *base_source, *pollable_source;
503
504   base_source = g_timeout_source_new (0);
505   pollable_source = g_pollable_source_new_full (stream, base_source,
506                                                 cancellable);
507   g_source_unref (base_source);
508
509   return pollable_source;
510 }