Don't do pointer arithmetic on void * (#508602) Patch from Kazuki IWAMOTO
[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 "glibintl.h"
30
31 #include "gioalias.h"
32
33 /**
34  * SECTION:gmemoryinputstream
35  * @short_description: Streaming input operations on memory chunks
36  * @include: 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             gpointer user_data)
145 {
146   Chunk *chunk = data;
147
148   if (chunk->destroy)
149     chunk->destroy (chunk->data);
150
151   g_slice_free (Chunk, chunk);
152 }
153
154 static void
155 g_memory_input_stream_finalize (GObject *object)
156 {
157   GMemoryInputStream        *stream;
158   GMemoryInputStreamPrivate *priv;
159
160   stream = G_MEMORY_INPUT_STREAM (object);
161   priv = stream->priv;
162
163   g_slist_foreach (priv->chunks, free_chunk, NULL);
164   g_slist_free (priv->chunks);
165
166   if (G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize)
167     (*G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize) (object);
168 }
169
170 static void
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
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 GInputStream *
189 g_memory_input_stream_new (void)
190 {
191   GInputStream *stream;
192
193   stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
194
195   return stream;
196 }
197
198 /**
199  * g_memory_input_stream_new_from_data:
200  * @data: input data
201  * @len: length of the data, may be -1 if @data is a nul-terminated string
202  * @destroy: function that is called to free @data, or %NULL
203  *
204  * Creates a new #GMemoryInputStream with data in memory of a given size.
205  * 
206  * Returns: new #GInputStream read from @data of @len bytes.
207  **/
208 GInputStream *
209 g_memory_input_stream_new_from_data (const void     *data, 
210                                      gssize          len,
211                                      GDestroyNotify  destroy)
212 {
213   GInputStream *stream;
214
215   stream = g_memory_input_stream_new ();
216
217   g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
218                                   data, len, destroy);
219
220   return stream;
221 }
222
223 void
224 g_memory_input_stream_add_data (GMemoryInputStream *stream,
225                                 const void         *data,
226                                 gssize              len,
227                                 GDestroyNotify      destroy)
228 {
229   GMemoryInputStreamPrivate *priv;
230   Chunk *chunk;
231  
232   g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
233   g_return_if_fail (data != NULL);
234
235   priv = stream->priv;
236
237   if (len == -1)
238     len = strlen (data);
239   
240   chunk = g_slice_new (Chunk);
241   chunk->data = (guint8 *)data;
242   chunk->len = len;
243   chunk->destroy = destroy;
244
245   priv->chunks = g_slist_append (priv->chunks, chunk);
246   priv->len += chunk->len;
247 }
248
249 static gssize
250 g_memory_input_stream_read (GInputStream  *stream,
251                             void          *buffer,
252                             gsize          count,
253                             GCancellable  *cancellable,
254                             GError       **error)
255 {
256   GMemoryInputStream *memory_stream;
257   GMemoryInputStreamPrivate *priv;
258   GSList *l;
259   Chunk *chunk;
260   gsize offset, start, rest, size;
261
262   memory_stream = G_MEMORY_INPUT_STREAM (stream);
263   priv = memory_stream->priv;
264
265   count = MIN (count, priv->len - priv->pos);
266
267   offset = 0;
268   for (l = priv->chunks; l; l = l->next) 
269     {
270       chunk = (Chunk *)l->data;
271
272       if (offset + chunk->len > priv->pos)
273         break;
274
275       offset += chunk->len;
276     }
277   
278   start = priv->pos - offset;
279   rest = count;
280
281   for (; l && rest > 0; l = l->next)
282     {
283       chunk = (Chunk *)l->data;
284       size = MIN (rest, chunk->len - start);
285
286       memcpy ((guint8 *)buffer + (count - rest), chunk->data + start, size);
287       rest -= size;
288
289       start = 0;
290     }
291
292   priv->pos += count;
293
294   return count;
295 }
296
297 static gssize
298 g_memory_input_stream_skip (GInputStream  *stream,
299                             gsize          count,
300                             GCancellable  *cancellable,
301                             GError       **error)
302 {
303   GMemoryInputStream *memory_stream;
304   GMemoryInputStreamPrivate *priv;
305
306   memory_stream = G_MEMORY_INPUT_STREAM (stream);
307   priv = memory_stream->priv;
308
309   count = MIN (count, priv->len - priv->pos);
310   priv->pos += count;
311
312   return count;
313 }
314
315 static gboolean
316 g_memory_input_stream_close (GInputStream  *stream,
317                              GCancellable  *cancellable,
318                              GError       **error)
319 {
320   return TRUE;
321 }
322
323 static void
324 g_memory_input_stream_read_async (GInputStream        *stream,
325                                   void                *buffer,
326                                   gsize                count,
327                                   int                  io_priority,
328                                   GCancellable        *cancellable,
329                                   GAsyncReadyCallback  callback,
330                                   gpointer             user_data)
331 {
332   GSimpleAsyncResult *simple;
333   gssize nread;
334
335   nread = g_memory_input_stream_read (stream, buffer, count, cancellable, NULL);
336   simple = g_simple_async_result_new (G_OBJECT (stream),
337                                       callback,
338                                       user_data,
339                                       g_memory_input_stream_read_async);
340   g_simple_async_result_set_op_res_gssize (simple, nread);
341   g_simple_async_result_complete_in_idle (simple);
342   g_object_unref (simple);
343 }
344
345 static gssize
346 g_memory_input_stream_read_finish (GInputStream  *stream,
347                                    GAsyncResult  *result,
348                                    GError       **error)
349 {
350   GSimpleAsyncResult *simple;
351   gssize nread;
352
353   simple = G_SIMPLE_ASYNC_RESULT (result);
354   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_read_async);
355   
356   nread = g_simple_async_result_get_op_res_gssize (simple);
357   return nread;
358 }
359
360 static void
361 g_memory_input_stream_skip_async (GInputStream        *stream,
362                                   gsize                count,
363                                   int                  io_priority,
364                                   GCancellable        *cancellable,
365                                   GAsyncReadyCallback  callback,
366                                   gpointer             user_data)
367 {
368   GSimpleAsyncResult *simple;
369   gssize nskipped;
370
371   nskipped = g_memory_input_stream_skip (stream, count, cancellable, NULL);
372   simple = g_simple_async_result_new (G_OBJECT (stream),
373                                       callback,
374                                       user_data,
375                                       g_memory_input_stream_skip_async);
376   g_simple_async_result_set_op_res_gssize (simple, nskipped);
377   g_simple_async_result_complete_in_idle (simple);
378   g_object_unref (simple);
379 }
380
381 static gssize
382 g_memory_input_stream_skip_finish (GInputStream  *stream,
383                                    GAsyncResult  *result,
384                                    GError       **error)
385 {
386   GSimpleAsyncResult *simple;
387   gssize nskipped;
388
389   simple = G_SIMPLE_ASYNC_RESULT (result);
390   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_skip_async);
391   
392   nskipped = g_simple_async_result_get_op_res_gssize (simple);
393   return nskipped;
394 }
395
396 static void
397 g_memory_input_stream_close_async (GInputStream        *stream,
398                                    int                  io_priority,
399                                    GCancellable        *cancellable,
400                                    GAsyncReadyCallback  callback,
401                                    gpointer             user_data)
402 {
403   GSimpleAsyncResult *simple;
404   
405   simple = g_simple_async_result_new (G_OBJECT (stream),
406                                       callback,
407                                       user_data,
408                                       g_memory_input_stream_close_async);
409   g_simple_async_result_complete_in_idle (simple);
410   g_object_unref (simple);
411 }
412
413 static gboolean
414 g_memory_input_stream_close_finish (GInputStream  *stream,
415                                     GAsyncResult  *result,
416                                     GError       **error)
417 {
418   return TRUE;
419 }
420
421 static goffset
422 g_memory_input_stream_tell (GSeekable *seekable)
423 {
424   GMemoryInputStream *memory_stream;
425   GMemoryInputStreamPrivate *priv;
426
427   memory_stream = G_MEMORY_INPUT_STREAM (seekable);
428   priv = memory_stream->priv;
429
430   return priv->pos;
431 }
432
433 static
434 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
435 {
436   return TRUE;
437 }
438
439 static gboolean
440 g_memory_input_stream_seek (GSeekable     *seekable,
441                             goffset        offset,
442                             GSeekType      type,
443                             GCancellable  *cancellable,
444                             GError       **error)
445 {
446   GMemoryInputStream *memory_stream;
447   GMemoryInputStreamPrivate *priv;
448   goffset absolute;
449
450   memory_stream = G_MEMORY_INPUT_STREAM (seekable);
451   priv = memory_stream->priv;
452
453   switch (type) 
454     {
455     case G_SEEK_CUR:
456       absolute = priv->pos + offset;
457       break;
458
459     case G_SEEK_SET:
460       absolute = offset;
461       break;
462
463     case G_SEEK_END:
464       absolute = priv->len + offset;
465       break;
466   
467     default:
468       g_set_error (error,
469                    G_IO_ERROR,
470                    G_IO_ERROR_INVALID_ARGUMENT,
471                    _("Invalid GSeekType supplied"));
472
473       return FALSE;
474     }
475
476   if (absolute < 0 || absolute > priv->len)
477     {
478       g_set_error (error,
479                    G_IO_ERROR,
480                    G_IO_ERROR_INVALID_ARGUMENT,
481                    _("Invalid seek request"));
482       return FALSE;
483     }
484
485   priv->pos = absolute;
486
487   return TRUE;
488 }
489
490 static gboolean
491 g_memory_input_stream_can_truncate (GSeekable *seekable)
492 {
493   return FALSE;
494 }
495
496 static gboolean
497 g_memory_input_stream_truncate (GSeekable     *seekable,
498                                 goffset        offset,
499                                 GCancellable  *cancellable,
500                                 GError       **error)
501 {
502   g_set_error (error,
503                G_IO_ERROR,
504                G_IO_ERROR_NOT_SUPPORTED,
505                _("Cannot truncate GMemoryInputStream"));
506   return FALSE;
507 }
508
509 #define __G_MEMORY_INPUT_STREAM_C__
510 #include "gioaliasdef.c"