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