• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
G_DEFINE_TYPE_WITH_CODE(GMemoryInputStream,g_memory_input_stream,G_TYPE_INPUT_STREAM,G_ADD_PRIVATE (GMemoryInputStream)G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,g_memory_input_stream_seekable_iface_init);G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,g_memory_input_stream_pollable_iface_init);)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
g_memory_input_stream_finalize(GObject * object)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
g_memory_input_stream_seekable_iface_init(GSeekableIface * iface)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
g_memory_input_stream_pollable_iface_init(GPollableInputStreamInterface * iface)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
g_memory_input_stream_init(GMemoryInputStream * stream)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 *
g_memory_input_stream_new(void)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 *
g_memory_input_stream_new_from_data(const void * data,gssize len,GDestroyNotify destroy)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 *
g_memory_input_stream_new_from_bytes(GBytes * bytes)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
g_memory_input_stream_add_data(GMemoryInputStream * stream,const void * data,gssize len,GDestroyNotify destroy)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
g_memory_input_stream_add_bytes(GMemoryInputStream * stream,GBytes * bytes)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
g_memory_input_stream_read(GInputStream * stream,void * buffer,gsize count,GCancellable * cancellable,GError ** error)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
g_memory_input_stream_skip(GInputStream * stream,gsize count,GCancellable * cancellable,GError ** error)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
g_memory_input_stream_close(GInputStream * stream,GCancellable * cancellable,GError ** error)361 g_memory_input_stream_close (GInputStream  *stream,
362                              GCancellable  *cancellable,
363                              GError       **error)
364 {
365   return TRUE;
366 }
367 
368 static void
g_memory_input_stream_skip_async(GInputStream * stream,gsize count,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)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
g_memory_input_stream_skip_finish(GInputStream * stream,GAsyncResult * result,GError ** error)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
g_memory_input_stream_close_async(GInputStream * stream,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)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
g_memory_input_stream_close_finish(GInputStream * stream,GAsyncResult * result,GError ** error)417 g_memory_input_stream_close_finish (GInputStream  *stream,
418                                     GAsyncResult  *result,
419                                     GError       **error)
420 {
421   return TRUE;
422 }
423 
424 static goffset
g_memory_input_stream_tell(GSeekable * seekable)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
g_memory_input_stream_can_seek(GSeekable * seekable)437 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
438 {
439   return TRUE;
440 }
441 
442 static gboolean
g_memory_input_stream_seek(GSeekable * seekable,goffset offset,GSeekType type,GCancellable * cancellable,GError ** error)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 || (gsize) 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
g_memory_input_stream_can_truncate(GSeekable * seekable)494 g_memory_input_stream_can_truncate (GSeekable *seekable)
495 {
496   return FALSE;
497 }
498 
499 static gboolean
g_memory_input_stream_truncate(GSeekable * seekable,goffset offset,GCancellable * cancellable,GError ** error)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
g_memory_input_stream_is_readable(GPollableInputStream * stream)513 g_memory_input_stream_is_readable (GPollableInputStream *stream)
514 {
515   return TRUE;
516 }
517 
518 static GSource *
g_memory_input_stream_create_source(GPollableInputStream * stream,GCancellable * cancellable)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 }
531