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