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