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