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