gio/ docs/reference/gio Merged gio-standalone into glib.
[platform/upstream/glib.git] / gio / gmemoryoutputstream.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 "gmemoryoutputstream.h"
25 #include "goutputstream.h"
26 #include "gseekable.h"
27 #include "gsimpleasyncresult.h"
28 #include "string.h"
29 #include "glibintl.h"
30
31 struct _GMemoryOutputStreamPrivate {
32   
33   GByteArray *data;
34   goffset     pos;
35
36   guint       max_size;
37   guint       free_data : 1;
38 };
39
40 enum {
41   PROP_0,
42   PROP_DATA,
43   PROP_FREE_ARRAY,
44   PROP_SIZE_LIMIT
45 };
46
47 static void     g_memory_output_stream_finalize     (GObject         *object);
48
49 static void     g_memory_output_stream_set_property (GObject      *object,
50                                                      guint         prop_id,
51                                                      const GValue *value,
52                                                      GParamSpec   *pspec);
53
54 static void     g_memory_output_stream_get_property (GObject    *object,
55                                                      guint       prop_id,
56                                                      GValue     *value,
57                                                      GParamSpec *pspec);
58
59 static gssize   g_memory_output_stream_write       (GOutputStream *stream,
60                                                     const void    *buffer,
61                                                     gsize          count,
62                                                     GCancellable  *cancellable,
63                                                     GError       **error);
64
65 static gboolean g_memory_output_stream_close       (GOutputStream  *stream,
66                                                     GCancellable   *cancellable,
67                                                     GError        **error);
68
69 static void     g_memory_output_stream_write_async  (GOutputStream        *stream,
70                                                      const void           *buffer,
71                                                      gsize                 count,
72                                                      int                   io_priority,
73                                                      GCancellable         *cancellable,
74                                                      GAsyncReadyCallback   callback,
75                                                      gpointer              data);
76 static gssize   g_memory_output_stream_write_finish (GOutputStream        *stream,
77                                                      GAsyncResult         *result,
78                                                      GError              **error);
79 static void     g_memory_output_stream_close_async  (GOutputStream        *stream,
80                                                      int                   io_priority,
81                                                      GCancellable         *cancellable,
82                                                      GAsyncReadyCallback   callback,
83                                                      gpointer              data);
84 static gboolean g_memory_output_stream_close_finish (GOutputStream        *stream,
85                                                      GAsyncResult         *result,
86                                                      GError              **error);
87
88 static void     g_memory_output_stream_seekable_iface_init (GSeekableIface  *iface);
89 static goffset  g_memory_output_stream_tell                (GSeekable       *seekable);
90 static gboolean g_memory_output_stream_can_seek            (GSeekable       *seekable);
91 static gboolean g_memory_output_stream_seek                (GSeekable       *seekable,
92                                                            goffset          offset,
93                                                            GSeekType        type,
94                                                            GCancellable    *cancellable,
95                                                            GError         **error);
96 static gboolean g_memory_output_stream_can_truncate        (GSeekable       *seekable);
97 static gboolean g_memory_output_stream_truncate            (GSeekable       *seekable,
98                                                            goffset          offset,
99                                                            GCancellable    *cancellable,
100                                                            GError         **error);
101
102 G_DEFINE_TYPE_WITH_CODE (GMemoryOutputStream, g_memory_output_stream, G_TYPE_OUTPUT_STREAM,
103                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
104                                                 g_memory_output_stream_seekable_iface_init))
105
106
107 static void
108 g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass)
109 {
110   GOutputStreamClass *ostream_class;
111   GObjectClass *gobject_class;
112
113   g_type_class_add_private (klass, sizeof (GMemoryOutputStreamPrivate));
114
115   gobject_class = G_OBJECT_CLASS (klass);
116   gobject_class->finalize = g_memory_output_stream_finalize;
117   gobject_class->get_property = g_memory_output_stream_get_property;
118   gobject_class->set_property = g_memory_output_stream_set_property;
119
120   ostream_class = G_OUTPUT_STREAM_CLASS (klass);
121
122   ostream_class->write = g_memory_output_stream_write;
123   ostream_class->close = g_memory_output_stream_close;
124   ostream_class->write_async  = g_memory_output_stream_write_async;
125   ostream_class->write_finish = g_memory_output_stream_write_finish;
126   ostream_class->close_async  = g_memory_output_stream_close_async;
127   ostream_class->close_finish = g_memory_output_stream_close_finish;
128
129   g_object_class_install_property (gobject_class,
130                                    PROP_DATA,
131                                    g_param_spec_pointer ("data",
132                                                          P_("Data byte array"),
133                                                          P_("The byte array used as internal storage."),
134                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | 
135                                                          G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
136
137   g_object_class_install_property (gobject_class,
138                                    PROP_FREE_ARRAY,
139                                    g_param_spec_boolean ("free-array",
140                                                          P_("Free array data"),
141                                                          P_("Wether or not the interal array should be free on close."),
142                                                          FALSE,
143                                                          G_PARAM_READWRITE |
144                                                          G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
145   g_object_class_install_property (gobject_class,
146                                    PROP_SIZE_LIMIT,
147                                    g_param_spec_uint ("size-limit",
148                                                       P_("Limit"),
149                                                       P_("Maximum amount of bytes that can be written to the stream."),
150                                                       0,
151                                                       G_MAXUINT,
152                                                       0,
153                                                       G_PARAM_READWRITE |
154                                                       G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
155
156
157 }
158
159 static void
160 g_memory_output_stream_finalize (GObject *object)
161 {
162   GMemoryOutputStream        *stream;
163
164   stream = G_MEMORY_OUTPUT_STREAM (object);
165   
166   if (stream->priv->free_data)
167     g_byte_array_free (stream->priv->data, TRUE);
168     
169   if (G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize)
170     (*G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize) (object);
171 }
172
173 static void
174 g_memory_output_stream_seekable_iface_init (GSeekableIface *iface)
175 {
176   iface->tell         = g_memory_output_stream_tell;
177   iface->can_seek     = g_memory_output_stream_can_seek;
178   iface->seek         = g_memory_output_stream_seek;
179   iface->can_truncate = g_memory_output_stream_can_truncate;
180   iface->truncate     = g_memory_output_stream_truncate;
181 }
182
183
184 static void
185 g_memory_output_stream_init (GMemoryOutputStream *stream)
186 {
187   GMemoryOutputStreamPrivate *priv;
188
189   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
190                                               G_TYPE_MEMORY_OUTPUT_STREAM,
191                                               GMemoryOutputStreamPrivate);
192
193   priv = stream->priv;
194   priv->data = NULL; 
195 }
196
197 /**
198  * g_memory_output_stream_new:
199  * @data: a #GByteArray.
200  *
201  * Creates a new #GMemoryOutputStream. If @data is non-%NULL it will use
202  * that for its internal storage otherwise it will create a new #GByteArray.
203  * In both cases the internal #GByteArray can later be accessed through the 
204  * "data" property.
205  *
206  * Note: The new stream will not take ownership of the supplied
207  * @data so you have to free it yourself after use or explicitly
208  * ask for it be freed on close by setting the "free-array" 
209  * property to $TRUE.
210  *
211  * Return value: A newly created #GMemoryOutputStream object.
212  **/
213 GOutputStream *
214 g_memory_output_stream_new (GByteArray *data)
215 {
216   GOutputStream *stream;
217
218   if (data == NULL) {
219     stream = g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM, NULL);
220   } else {
221     stream = g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM,
222                            "data", data,
223                            NULL);
224   }
225
226   return stream;
227 }
228
229 /**
230  * g_memory_output_stream_set_free_data:
231  * @ostream:
232  * @free_data:
233  * 
234  **/
235 void
236 g_memory_output_stream_set_free_data (GMemoryOutputStream *ostream,
237                                       gboolean free_data)
238 {
239   GMemoryOutputStreamPrivate *priv;
240
241   g_return_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream));
242
243   priv = ostream->priv;
244
245   priv->free_data = free_data;
246 }
247
248 /**
249  * g_memory_output_stream_set_max_size:
250  * @ostream:
251  * @max_size:
252  * 
253  **/
254 void
255 g_memory_output_stream_set_max_size (GMemoryOutputStream *ostream,
256                                      guint                max_size)
257 {
258   GMemoryOutputStreamPrivate *priv;
259   
260   g_return_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream));
261
262   priv = ostream->priv;
263
264   priv->max_size = max_size;
265
266   if (priv->max_size > 0 &&
267       priv->max_size < priv->data->len) {
268
269     g_byte_array_set_size (priv->data, priv->max_size);
270
271     if (priv->pos > priv->max_size) {
272       priv->pos = priv->max_size;
273     }
274   }
275
276   g_object_notify (G_OBJECT (ostream), "size-limit");
277 }
278
279 static void
280 g_memory_output_stream_set_property (GObject         *object,
281                                      guint            prop_id,
282                                      const GValue    *value,
283                                      GParamSpec      *pspec)
284 {
285   GMemoryOutputStream *ostream;
286   GMemoryOutputStreamPrivate *priv;
287   GByteArray *data;
288   guint       max_size;
289
290   ostream = G_MEMORY_OUTPUT_STREAM (object);
291   priv = ostream->priv;
292
293   switch (prop_id)
294     {
295     case PROP_DATA:
296
297       if (priv->data && priv->free_data) {
298         g_byte_array_free (priv->data, TRUE);
299       }
300
301       data = g_value_get_pointer (value);
302
303       if (data == NULL) {
304         data = g_byte_array_new (); 
305         priv->free_data = TRUE;
306       } else {
307         priv->free_data = FALSE;
308       }
309  
310       priv->data = data;
311       priv->pos  = 0;
312       g_object_notify (G_OBJECT (ostream), "data");
313       break;
314
315     case PROP_FREE_ARRAY:
316       priv->free_data = g_value_get_boolean (value);
317       break;
318
319     case PROP_SIZE_LIMIT:
320       max_size = g_value_get_uint (value);
321       g_memory_output_stream_set_max_size (ostream, max_size);
322       break;
323
324     default:
325       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326       break;
327     }
328 }
329
330 static void
331 g_memory_output_stream_get_property (GObject    *object,
332                                      guint       prop_id,
333                                      GValue     *value,
334                                      GParamSpec *pspec)
335 {
336   GMemoryOutputStream *ostream;
337   GMemoryOutputStreamPrivate *priv;
338
339   ostream = G_MEMORY_OUTPUT_STREAM (object);
340   priv = ostream->priv;
341
342   switch (prop_id)
343     {
344     case PROP_DATA:
345       g_value_set_pointer (value, priv->data);
346       break;
347
348     case PROP_FREE_ARRAY:
349       g_value_set_boolean (value, priv->free_data);
350       break;
351
352     case PROP_SIZE_LIMIT:
353       g_value_set_uint (value, priv->max_size);
354       break;
355
356     default:
357       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
358       break;
359     }
360 }
361
362 /**
363  * g_memory_output_stream_get_data:
364  * @ostream:
365  * 
366  * Returns: #GByteArray of the stream's data.
367  **/
368 GByteArray *
369 g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
370 {
371   g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
372
373   return ostream->priv->data;
374 }
375
376
377 static gboolean
378 array_check_boundary (GMemoryOutputStream  *stream,
379                       goffset               size,
380                       GError              **error)
381 {
382   GMemoryOutputStreamPrivate *priv;
383
384   priv = stream->priv;
385
386   if (! priv->max_size) {
387     return TRUE;
388   }
389
390   if (priv->max_size < size || size > G_MAXUINT) {
391
392     g_set_error (error,
393                  G_IO_ERROR,
394                  G_IO_ERROR_FAILED,
395                  "Reached maximum data array limit");
396
397     return FALSE;
398   }
399
400   return TRUE; 
401 }
402
403 static gssize
404 array_resize (GMemoryOutputStream  *stream,
405               goffset               size,
406               GError              **error)
407 {
408   GMemoryOutputStreamPrivate *priv;
409   guint old_len;
410
411   priv = stream->priv;
412
413   if (! array_check_boundary (stream, size, error)) 
414     return -1;
415   
416
417   if (priv->data->len == size) 
418     return priv->data->len - priv->pos;
419   
420
421   old_len = priv->data->len;
422   g_byte_array_set_size (priv->data, size);
423
424   if (size > old_len && priv->pos > old_len) 
425     memset (priv->data->data + priv->pos, 0, size - old_len);
426   
427
428   return priv->data->len - priv->pos;
429 }
430
431 static gssize
432 g_memory_output_stream_write (GOutputStream *stream,
433                               const void    *buffer,
434                               gsize          count,
435                               GCancellable  *cancellable,
436                               GError       **error)
437 {
438   GMemoryOutputStream        *ostream;
439   GMemoryOutputStreamPrivate *priv;
440   gsize     new_size;
441   gssize    n;
442   guint8   *dest;
443
444   ostream = G_MEMORY_OUTPUT_STREAM (stream);
445   priv = ostream->priv;
446
447   /* count < 0 is ensured by GOutputStream */
448
449   n = MIN (count, priv->data->len - priv->pos);
450
451   if (n < 1)
452     {
453       new_size = priv->pos + count;
454
455       if (priv->max_size > 0)
456         {
457           new_size = MIN (new_size, priv->max_size);
458         }
459
460       n = array_resize (ostream, new_size, error);
461
462       if (n == 0) 
463         {
464           g_set_error (error,
465                        G_IO_ERROR,
466                        G_IO_ERROR_FAILED,
467                        "Reached maximum data array limit");
468           return -1;
469         }
470       else if (n < 0)
471         {
472           return -1;
473         }
474     }
475
476   dest = priv->data->data + priv->pos;
477   memcpy (dest, buffer, n); 
478   priv->pos += n;
479
480   return n;
481 }
482
483 static gboolean
484 g_memory_output_stream_close (GOutputStream  *stream,
485                               GCancellable   *cancellable,
486                               GError        **error)
487 {
488   GMemoryOutputStream        *ostream;
489   GMemoryOutputStreamPrivate *priv;
490
491   ostream = G_MEMORY_OUTPUT_STREAM (stream);
492   priv = ostream->priv;
493
494   return TRUE;
495 }
496
497 static void
498 g_memory_output_stream_write_async  (GOutputStream        *stream,
499                                      const void           *buffer,
500                                      gsize                 count,
501                                      int                   io_priority,
502                                      GCancellable         *cancellable,
503                                      GAsyncReadyCallback   callback,
504                                      gpointer              data)
505 {
506   GSimpleAsyncResult *simple;
507   gssize nwritten;
508
509   nwritten = g_memory_output_stream_write (stream,
510                                            buffer,
511                                            count,
512                                            cancellable,
513                                            NULL);
514  
515
516   simple = g_simple_async_result_new (G_OBJECT (stream),
517                                       callback,
518                                       data,
519                                       g_memory_output_stream_write_async);
520   
521   g_simple_async_result_set_op_res_gssize (simple, nwritten); 
522   g_simple_async_result_complete_in_idle (simple);
523   g_object_unref (simple);
524
525 }
526
527 static gssize
528 g_memory_output_stream_write_finish (GOutputStream        *stream,
529                                      GAsyncResult         *result,
530                                      GError              **error)
531 {
532   GSimpleAsyncResult *simple;
533   gssize nwritten;
534
535   simple = G_SIMPLE_ASYNC_RESULT (result);
536   
537   g_assert (g_simple_async_result_get_source_tag (simple) == 
538             g_memory_output_stream_write_async);
539
540   nwritten = g_simple_async_result_get_op_res_gssize (simple);
541   return nwritten;
542 }
543
544 static void
545 g_memory_output_stream_close_async  (GOutputStream        *stream,
546                                      int                   io_priority,
547                                      GCancellable         *cancellable,
548                                      GAsyncReadyCallback   callback,
549                                      gpointer              data)
550 {
551   GSimpleAsyncResult *simple;
552
553   simple = g_simple_async_result_new (G_OBJECT (stream),
554                                       callback,
555                                       data,
556                                       g_memory_output_stream_close_async);
557
558
559   /* will always return TRUE */
560   g_memory_output_stream_close (stream, cancellable, NULL);
561   
562   g_simple_async_result_complete_in_idle (simple);
563   g_object_unref (simple);
564
565 }
566
567 static gboolean
568 g_memory_output_stream_close_finish (GOutputStream        *stream,
569                                      GAsyncResult         *result,
570                                      GError              **error)
571 {
572   GSimpleAsyncResult *simple;
573
574   simple = G_SIMPLE_ASYNC_RESULT (result);
575
576   g_assert (g_simple_async_result_get_source_tag (simple) == 
577             g_memory_output_stream_close_async);
578
579
580   return TRUE;
581 }
582
583 static goffset
584 g_memory_output_stream_tell (GSeekable  *seekable)
585 {
586   GMemoryOutputStream *stream;
587   GMemoryOutputStreamPrivate *priv;
588
589   stream = G_MEMORY_OUTPUT_STREAM (seekable);
590   priv = stream->priv;
591
592   return priv->pos;
593 }
594
595 static gboolean
596 g_memory_output_stream_can_seek (GSeekable *seekable)
597 {
598   return TRUE;
599 }
600
601 static gboolean
602 g_memory_output_stream_seek (GSeekable      *seekable,
603                             goffset          offset,
604                             GSeekType        type,
605                             GCancellable    *cancellable,
606                             GError         **error)
607 {
608   GMemoryOutputStream        *stream;
609   GMemoryOutputStreamPrivate *priv;
610   goffset absolute;
611
612   stream = G_MEMORY_OUTPUT_STREAM (seekable);
613   priv = stream->priv;
614
615   switch (type) {
616
617     case G_SEEK_CUR:
618       absolute = priv->pos + offset;
619       break;
620
621     case G_SEEK_SET:
622       absolute = offset;
623       break;
624
625     case G_SEEK_END:
626       absolute = priv->data->len + offset;
627       break;
628   
629     default:
630       g_set_error (error,
631                    G_IO_ERROR,
632                    G_IO_ERROR_INVALID_ARGUMENT,
633                    "Invalid GSeekType supplied");
634
635       return FALSE;
636   }
637
638   if (absolute < 0) {
639     g_set_error (error,
640                  G_IO_ERROR,
641                  G_IO_ERROR_INVALID_ARGUMENT,
642                  "Invalid seek request");
643     return FALSE;
644   }
645
646   if (! array_check_boundary (stream, absolute, error)) 
647     return FALSE;  
648
649   priv->pos = absolute;
650
651   return TRUE;
652 }
653
654 static gboolean
655 g_memory_output_stream_can_truncate (GSeekable *seekable)
656 {
657   return TRUE;
658 }
659
660 static gboolean
661 g_memory_output_stream_truncate (GSeekable      *seekable,
662                                  goffset         offset,
663                                  GCancellable   *cancellable,
664                                  GError         **error)
665 {
666   GMemoryOutputStream *ostream;
667   GMemoryOutputStreamPrivate *priv;
668
669   ostream = G_MEMORY_OUTPUT_STREAM (seekable);
670   priv = ostream->priv;
671  
672   if (array_resize (ostream, offset, error) < 0)
673       return FALSE;
674
675   return TRUE;
676 }
677
678 /* vim: ts=2 sw=2 et */