Added. Added. Added. Added.
[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
238   return stream;
239 }
240
241 /**
242  * g_memory_output_stream_set_free_data:
243  * @ostream:
244  * @free_data:
245  * 
246  **/
247 void
248 g_memory_output_stream_set_free_data (GMemoryOutputStream *ostream,
249                                       gboolean free_data)
250 {
251   GMemoryOutputStreamPrivate *priv;
252
253   g_return_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream));
254
255   priv = ostream->priv;
256
257   priv->free_data = free_data;
258 }
259
260 /**
261  * g_memory_output_stream_set_max_size:
262  * @ostream:
263  * @max_size:
264  * 
265  **/
266 void
267 g_memory_output_stream_set_max_size (GMemoryOutputStream *ostream,
268                                      guint                max_size)
269 {
270   GMemoryOutputStreamPrivate *priv;
271   
272   g_return_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream));
273
274   priv = ostream->priv;
275
276   priv->max_size = max_size;
277
278   if (priv->max_size > 0 &&
279       priv->max_size < priv->data->len) {
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
288   g_object_notify (G_OBJECT (ostream), "size-limit");
289 }
290
291 static void
292 g_memory_output_stream_set_property (GObject         *object,
293                                      guint            prop_id,
294                                      const GValue    *value,
295                                      GParamSpec      *pspec)
296 {
297   GMemoryOutputStream *ostream;
298   GMemoryOutputStreamPrivate *priv;
299   GByteArray *data;
300   guint       max_size;
301
302   ostream = G_MEMORY_OUTPUT_STREAM (object);
303   priv = ostream->priv;
304
305   switch (prop_id)
306     {
307     case PROP_DATA:
308
309       if (priv->data && priv->free_data) {
310         g_byte_array_free (priv->data, TRUE);
311       }
312
313       data = g_value_get_pointer (value);
314
315       if (data == NULL) {
316         data = g_byte_array_new (); 
317         priv->free_data = TRUE;
318       } else {
319         priv->free_data = FALSE;
320       }
321  
322       priv->data = data;
323       priv->pos  = 0;
324       g_object_notify (G_OBJECT (ostream), "data");
325       break;
326
327     case PROP_FREE_ARRAY:
328       priv->free_data = g_value_get_boolean (value);
329       break;
330
331     case PROP_SIZE_LIMIT:
332       max_size = g_value_get_uint (value);
333       g_memory_output_stream_set_max_size (ostream, max_size);
334       break;
335
336     default:
337       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
338       break;
339     }
340 }
341
342 static void
343 g_memory_output_stream_get_property (GObject    *object,
344                                      guint       prop_id,
345                                      GValue     *value,
346                                      GParamSpec *pspec)
347 {
348   GMemoryOutputStream *ostream;
349   GMemoryOutputStreamPrivate *priv;
350
351   ostream = G_MEMORY_OUTPUT_STREAM (object);
352   priv = ostream->priv;
353
354   switch (prop_id)
355     {
356     case PROP_DATA:
357       g_value_set_pointer (value, priv->data);
358       break;
359
360     case PROP_FREE_ARRAY:
361       g_value_set_boolean (value, priv->free_data);
362       break;
363
364     case PROP_SIZE_LIMIT:
365       g_value_set_uint (value, priv->max_size);
366       break;
367
368     default:
369       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370       break;
371     }
372 }
373
374 /**
375  * g_memory_output_stream_get_data:
376  * @ostream:
377  * 
378  * Returns: #GByteArray of the stream's data.
379  **/
380 GByteArray *
381 g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
382 {
383   g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
384
385   return ostream->priv->data;
386 }
387
388
389 static gboolean
390 array_check_boundary (GMemoryOutputStream  *stream,
391                       goffset               size,
392                       GError              **error)
393 {
394   GMemoryOutputStreamPrivate *priv;
395
396   priv = stream->priv;
397
398   if (! priv->max_size) {
399     return TRUE;
400   }
401
402   if (priv->max_size < size || size > G_MAXUINT) {
403
404     g_set_error (error,
405                  G_IO_ERROR,
406                  G_IO_ERROR_FAILED,
407                  "Reached maximum data array limit");
408
409     return FALSE;
410   }
411
412   return TRUE; 
413 }
414
415 static gssize
416 array_resize (GMemoryOutputStream  *stream,
417               goffset               size,
418               GError              **error)
419 {
420   GMemoryOutputStreamPrivate *priv;
421   guint old_len;
422
423   priv = stream->priv;
424
425   if (! array_check_boundary (stream, size, error)) 
426     return -1;
427   
428
429   if (priv->data->len == size) 
430     return priv->data->len - priv->pos;
431   
432
433   old_len = priv->data->len;
434   g_byte_array_set_size (priv->data, size);
435
436   if (size > old_len && priv->pos > old_len) 
437     memset (priv->data->data + priv->pos, 0, size - old_len);
438   
439
440   return priv->data->len - priv->pos;
441 }
442
443 static gssize
444 g_memory_output_stream_write (GOutputStream *stream,
445                               const void    *buffer,
446                               gsize          count,
447                               GCancellable  *cancellable,
448                               GError       **error)
449 {
450   GMemoryOutputStream        *ostream;
451   GMemoryOutputStreamPrivate *priv;
452   gsize     new_size;
453   gssize    n;
454   guint8   *dest;
455
456   ostream = G_MEMORY_OUTPUT_STREAM (stream);
457   priv = ostream->priv;
458
459   /* count < 0 is ensured by GOutputStream */
460
461   n = MIN (count, priv->data->len - priv->pos);
462
463   if (n < 1)
464     {
465       new_size = priv->pos + count;
466
467       if (priv->max_size > 0)
468         {
469           new_size = MIN (new_size, priv->max_size);
470         }
471
472       n = array_resize (ostream, new_size, error);
473
474       if (n == 0) 
475         {
476           g_set_error (error,
477                        G_IO_ERROR,
478                        G_IO_ERROR_FAILED,
479                        "Reached maximum data array limit");
480           return -1;
481         }
482       else if (n < 0)
483         {
484           return -1;
485         }
486     }
487
488   dest = priv->data->data + priv->pos;
489   memcpy (dest, buffer, n); 
490   priv->pos += n;
491
492   return n;
493 }
494
495 static gboolean
496 g_memory_output_stream_close (GOutputStream  *stream,
497                               GCancellable   *cancellable,
498                               GError        **error)
499 {
500   GMemoryOutputStream        *ostream;
501   GMemoryOutputStreamPrivate *priv;
502
503   ostream = G_MEMORY_OUTPUT_STREAM (stream);
504   priv = ostream->priv;
505
506   return TRUE;
507 }
508
509 static void
510 g_memory_output_stream_write_async  (GOutputStream        *stream,
511                                      const void           *buffer,
512                                      gsize                 count,
513                                      int                   io_priority,
514                                      GCancellable         *cancellable,
515                                      GAsyncReadyCallback   callback,
516                                      gpointer              data)
517 {
518   GSimpleAsyncResult *simple;
519   gssize nwritten;
520
521   nwritten = g_memory_output_stream_write (stream,
522                                            buffer,
523                                            count,
524                                            cancellable,
525                                            NULL);
526  
527
528   simple = g_simple_async_result_new (G_OBJECT (stream),
529                                       callback,
530                                       data,
531                                       g_memory_output_stream_write_async);
532   
533   g_simple_async_result_set_op_res_gssize (simple, nwritten); 
534   g_simple_async_result_complete_in_idle (simple);
535   g_object_unref (simple);
536
537 }
538
539 static gssize
540 g_memory_output_stream_write_finish (GOutputStream        *stream,
541                                      GAsyncResult         *result,
542                                      GError              **error)
543 {
544   GSimpleAsyncResult *simple;
545   gssize nwritten;
546
547   simple = G_SIMPLE_ASYNC_RESULT (result);
548   
549   g_assert (g_simple_async_result_get_source_tag (simple) == 
550             g_memory_output_stream_write_async);
551
552   nwritten = g_simple_async_result_get_op_res_gssize (simple);
553   return nwritten;
554 }
555
556 static void
557 g_memory_output_stream_close_async  (GOutputStream        *stream,
558                                      int                   io_priority,
559                                      GCancellable         *cancellable,
560                                      GAsyncReadyCallback   callback,
561                                      gpointer              data)
562 {
563   GSimpleAsyncResult *simple;
564
565   simple = g_simple_async_result_new (G_OBJECT (stream),
566                                       callback,
567                                       data,
568                                       g_memory_output_stream_close_async);
569
570
571   /* will always return TRUE */
572   g_memory_output_stream_close (stream, cancellable, NULL);
573   
574   g_simple_async_result_complete_in_idle (simple);
575   g_object_unref (simple);
576
577 }
578
579 static gboolean
580 g_memory_output_stream_close_finish (GOutputStream        *stream,
581                                      GAsyncResult         *result,
582                                      GError              **error)
583 {
584   GSimpleAsyncResult *simple;
585
586   simple = G_SIMPLE_ASYNC_RESULT (result);
587
588   g_assert (g_simple_async_result_get_source_tag (simple) == 
589             g_memory_output_stream_close_async);
590
591
592   return TRUE;
593 }
594
595 static goffset
596 g_memory_output_stream_tell (GSeekable  *seekable)
597 {
598   GMemoryOutputStream *stream;
599   GMemoryOutputStreamPrivate *priv;
600
601   stream = G_MEMORY_OUTPUT_STREAM (seekable);
602   priv = stream->priv;
603
604   return priv->pos;
605 }
606
607 static gboolean
608 g_memory_output_stream_can_seek (GSeekable *seekable)
609 {
610   return TRUE;
611 }
612
613 static gboolean
614 g_memory_output_stream_seek (GSeekable      *seekable,
615                             goffset          offset,
616                             GSeekType        type,
617                             GCancellable    *cancellable,
618                             GError         **error)
619 {
620   GMemoryOutputStream        *stream;
621   GMemoryOutputStreamPrivate *priv;
622   goffset absolute;
623
624   stream = G_MEMORY_OUTPUT_STREAM (seekable);
625   priv = stream->priv;
626
627   switch (type) {
628
629     case G_SEEK_CUR:
630       absolute = priv->pos + offset;
631       break;
632
633     case G_SEEK_SET:
634       absolute = offset;
635       break;
636
637     case G_SEEK_END:
638       absolute = priv->data->len + offset;
639       break;
640   
641     default:
642       g_set_error (error,
643                    G_IO_ERROR,
644                    G_IO_ERROR_INVALID_ARGUMENT,
645                    "Invalid GSeekType supplied");
646
647       return FALSE;
648   }
649
650   if (absolute < 0) {
651     g_set_error (error,
652                  G_IO_ERROR,
653                  G_IO_ERROR_INVALID_ARGUMENT,
654                  "Invalid seek request");
655     return FALSE;
656   }
657
658   if (! array_check_boundary (stream, absolute, error)) 
659     return FALSE;  
660
661   priv->pos = absolute;
662
663   return TRUE;
664 }
665
666 static gboolean
667 g_memory_output_stream_can_truncate (GSeekable *seekable)
668 {
669   return TRUE;
670 }
671
672 static gboolean
673 g_memory_output_stream_truncate (GSeekable      *seekable,
674                                  goffset         offset,
675                                  GCancellable   *cancellable,
676                                  GError         **error)
677 {
678   GMemoryOutputStream *ostream;
679   GMemoryOutputStreamPrivate *priv;
680
681   ostream = G_MEMORY_OUTPUT_STREAM (seekable);
682   priv = ostream->priv;
683  
684   if (array_resize (ostream, offset, error) < 0)
685       return FALSE;
686
687   return TRUE;
688 }
689
690 #define __G_MEMORY_OUTPUT_STREAM_C__
691 #include "gioaliasdef.c"
692
693 /* vim: ts=2 sw=2 et */