Build test subdir after . Remove gdirectorymonitor.[ch]
[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 #define MIN_ARRAY_SIZE  16
45
46 struct _GMemoryOutputStreamPrivate {
47   
48   gpointer       data;
49   gsize          len;
50
51   goffset        pos;
52
53   GReallocFunc   realloc_fn;
54   GDestroyNotify destroy;
55 };
56
57 static void     g_memory_output_stream_finalize     (GObject      *object);
58
59 static gssize   g_memory_output_stream_write       (GOutputStream *stream,
60                                                     const void    *buffer,
61                                                     gsize          count,
62                                                     GCancellable  *cancellable,
63                                                     GError       **error);
64
65 static gboolean g_memory_output_stream_close       (GOutputStream  *stream,
66                                                     GCancellable   *cancellable,
67                                                     GError        **error);
68
69 static void     g_memory_output_stream_write_async  (GOutputStream        *stream,
70                                                      const void           *buffer,
71                                                      gsize                 count,
72                                                      int                   io_priority,
73                                                      GCancellable         *cancellable,
74                                                      GAsyncReadyCallback   callback,
75                                                      gpointer              data);
76 static gssize   g_memory_output_stream_write_finish (GOutputStream        *stream,
77                                                      GAsyncResult         *result,
78                                                      GError              **error);
79 static void     g_memory_output_stream_close_async  (GOutputStream        *stream,
80                                                      int                   io_priority,
81                                                      GCancellable         *cancellable,
82                                                      GAsyncReadyCallback   callback,
83                                                      gpointer              data);
84 static gboolean g_memory_output_stream_close_finish (GOutputStream        *stream,
85                                                      GAsyncResult         *result,
86                                                      GError              **error);
87
88 static void     g_memory_output_stream_seekable_iface_init (GSeekableIface  *iface);
89 static goffset  g_memory_output_stream_tell                (GSeekable       *seekable);
90 static gboolean g_memory_output_stream_can_seek            (GSeekable       *seekable);
91 static gboolean g_memory_output_stream_seek                (GSeekable       *seekable,
92                                                            goffset          offset,
93                                                            GSeekType        type,
94                                                            GCancellable    *cancellable,
95                                                            GError         **error);
96 static gboolean g_memory_output_stream_can_truncate        (GSeekable       *seekable);
97 static gboolean g_memory_output_stream_truncate            (GSeekable       *seekable,
98                                                            goffset          offset,
99                                                            GCancellable    *cancellable,
100                                                            GError         **error);
101
102 G_DEFINE_TYPE_WITH_CODE (GMemoryOutputStream, g_memory_output_stream, G_TYPE_OUTPUT_STREAM,
103                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
104                                                 g_memory_output_stream_seekable_iface_init))
105
106
107 static void
108 g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass)
109 {
110   GOutputStreamClass *ostream_class;
111   GObjectClass *gobject_class;
112
113   g_type_class_add_private (klass, sizeof (GMemoryOutputStreamPrivate));
114
115   gobject_class = G_OBJECT_CLASS (klass);
116   gobject_class->finalize = g_memory_output_stream_finalize;
117
118   ostream_class = G_OUTPUT_STREAM_CLASS (klass);
119
120   ostream_class->write_fn = g_memory_output_stream_write;
121   ostream_class->close_fn = g_memory_output_stream_close;
122   ostream_class->write_async  = g_memory_output_stream_write_async;
123   ostream_class->write_finish = g_memory_output_stream_write_finish;
124   ostream_class->close_async  = g_memory_output_stream_close_async;
125   ostream_class->close_finish = g_memory_output_stream_close_finish;
126 }
127
128 static void
129 g_memory_output_stream_finalize (GObject *object)
130 {
131   GMemoryOutputStream        *stream;
132   GMemoryOutputStreamPrivate *priv;
133
134   stream = G_MEMORY_OUTPUT_STREAM (object);
135   priv = stream->priv;
136   
137   if (priv->destroy)
138     priv->destroy (priv->data);
139     
140   if (G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize)
141     (*G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize) (object);
142 }
143
144 static void
145 g_memory_output_stream_seekable_iface_init (GSeekableIface *iface)
146 {
147   iface->tell         = g_memory_output_stream_tell;
148   iface->can_seek     = g_memory_output_stream_can_seek;
149   iface->seek         = g_memory_output_stream_seek;
150   iface->can_truncate = g_memory_output_stream_can_truncate;
151   iface->truncate_fn  = g_memory_output_stream_truncate;
152 }
153
154
155 static void
156 g_memory_output_stream_init (GMemoryOutputStream *stream)
157 {
158   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
159                                               G_TYPE_MEMORY_OUTPUT_STREAM,
160                                               GMemoryOutputStreamPrivate);
161 }
162
163 /**
164  * g_memory_output_stream_new:
165  * @data: pointer to a chunk of memory to use, or %NULL
166  * @len: the size of @data
167  * @realloc_fn: a function with realloc() semantics to be called when 
168  *     @data needs to be grown, or %NULL
169  * @destroy: a function to be called on @data when the stream is finalized,
170  *     or %NULL
171  *
172  * Creates a new #GMemoryOutputStream. 
173  *
174  * If @data is non-%NULL, the stream  will use that for its internal storage.
175  * If @realloc_fn is non-%NULL, it will be used for resizing the internal
176  * storage when necessary. To construct a fixed-size output stream, 
177  * pass %NULL as @realloc_fn.
178  * |[
179  * /&ast; a stream that can grow &ast;/
180  * stream = g_memory_output_stream_new (NULL, 0, realloc, free);
181  *
182  * /&ast; a fixed-size stream &ast;/
183  * data = malloc (200);
184  * stream2 = g_memory_output_stream_new (data, 200, NULL, free);
185  * ]|
186  *
187  * Return value: A newly created #GMemoryOutputStream object.
188  **/
189 GOutputStream *
190 g_memory_output_stream_new (gpointer       data,
191                             gsize          len,
192                             GReallocFunc   realloc_fn,
193                             GDestroyNotify destroy)
194 {
195   GOutputStream *stream;
196   GMemoryOutputStreamPrivate *priv;
197
198   stream = g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM, NULL);
199
200   priv = G_MEMORY_OUTPUT_STREAM (stream)->priv;
201
202   priv->data = data;
203   priv->len = len;
204   priv->realloc_fn = realloc_fn;
205   priv->destroy = destroy;
206
207   priv->pos = 0;
208
209   return stream;
210 }
211
212 /**
213  * g_memory_output_stream_get_data:
214  * @ostream: a #GMemoryOutputStream
215  *
216  * Gets any loaded data from the @ostream. 
217  *
218  * Note that the returned pointer may become invalid on the next 
219  * write or truncate operation on the stream. 
220  * 
221  * Returns: pointer to the stream's data
222  **/
223 gpointer
224 g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
225 {
226   g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
227
228   return ostream->priv->data;
229 }
230
231 /**
232  * g_memory_output_stream_get_size:
233  * @ostream: a #GMemoryOutputStream
234  *
235  * Gets the size of the loaded data from the @ostream.
236  *
237  * Note that the returned size may become invalid on the next
238  * write or truncate operation on the stream.
239  *
240  * Returns: the size of the stream's data
241  */
242 gsize
243 g_memory_output_stream_get_size (GMemoryOutputStream *ostream)
244 {
245   g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
246   
247   return ostream->priv->len;
248 }
249
250 static gboolean
251 array_check_boundary (GMemoryOutputStream  *stream,
252                       goffset               size,
253                       GError              **error)
254 {
255   if (size > G_MAXUINT)
256     {
257       g_set_error (error,
258                    G_IO_ERROR,
259                    G_IO_ERROR_FAILED,
260                    _("Reached maximum data array limit"));
261
262       return FALSE;
263     }
264
265   return TRUE;
266 }
267
268 static gboolean
269 array_resize (GMemoryOutputStream  *ostream,
270               gsize                 size,
271               gboolean              allow_partial,
272               GError              **error)
273 {
274   GMemoryOutputStreamPrivate *priv;
275   gpointer data;
276   gsize len;
277
278   priv = ostream->priv;
279
280   if (!array_check_boundary (ostream, size, error))
281     return FALSE;
282
283   if (priv->len == size)
284     return TRUE;
285
286   if (!priv->realloc_fn)
287     {
288       if (allow_partial &&
289           priv->pos < priv->len)
290         return TRUE; /* Short write */
291       
292       g_set_error (error,
293                    G_IO_ERROR,
294                    G_IO_ERROR_NO_SPACE,
295                    _("Memory output stream not resizable"));
296       return FALSE;
297     }
298
299   len = priv->len;
300   data = priv->realloc_fn (priv->data, size);
301
302   if (!data) 
303     {
304       if (allow_partial &&
305           priv->pos < priv->len)
306         return TRUE; /* Short write */
307       
308       g_set_error (error,
309                    G_IO_ERROR,
310                    G_IO_ERROR_NO_SPACE,
311                    _("Failed to resize memory output stream"));
312       return FALSE;
313     }
314
315   if (size > len)
316     memset (data + len, 0, size - len);
317
318   priv->data = data;
319   priv->len = size;
320   
321   return TRUE;
322 }
323
324 static gint
325 g_nearest_pow (gint num)
326 {
327   gint n = 1;
328
329   while (n < num)
330     n <<= 1;
331
332   return n;
333 }
334
335 static gssize
336 g_memory_output_stream_write (GOutputStream  *stream,
337                               const void     *buffer,
338                               gsize           count,
339                               GCancellable   *cancellable,
340                               GError        **error)
341 {
342   GMemoryOutputStream        *ostream;
343   GMemoryOutputStreamPrivate *priv;
344   guint8   *dest;
345   gsize new_size;
346
347   ostream = G_MEMORY_OUTPUT_STREAM (stream);
348   priv = ostream->priv;
349
350   if (count == 0)
351     return 0;
352
353   if (priv->pos + count > priv->len) 
354     {
355       /* At least enought to fit the write, rounded up
356          for greater than linear growth */
357       new_size = g_nearest_pow (priv->pos + count);
358       new_size = MAX (new_size, MIN_ARRAY_SIZE);
359       
360       if (!array_resize (ostream, new_size, TRUE, error))
361         return -1;
362     }
363
364   /* Make sure we handle short writes if the array_resize
365      only added part of the required memory */
366   count = MIN (count, priv->len - priv->pos);
367   
368   dest = priv->data + priv->pos;
369   memcpy (dest, buffer, count); 
370   priv->pos += count;
371
372   return count;
373 }
374
375 static gboolean
376 g_memory_output_stream_close (GOutputStream  *stream,
377                               GCancellable   *cancellable,
378                               GError        **error)
379 {
380   return TRUE;
381 }
382
383 static void
384 g_memory_output_stream_write_async (GOutputStream       *stream,
385                                     const void          *buffer,
386                                     gsize                count,
387                                     int                  io_priority,
388                                     GCancellable        *cancellable,
389                                     GAsyncReadyCallback  callback,
390                                     gpointer             data)
391 {
392   GSimpleAsyncResult *simple;
393   gssize nwritten;
394
395   nwritten = g_memory_output_stream_write (stream,
396                                            buffer,
397                                            count,
398                                            cancellable,
399                                            NULL);
400  
401
402   simple = g_simple_async_result_new (G_OBJECT (stream),
403                                       callback,
404                                       data,
405                                       g_memory_output_stream_write_async);
406   
407   g_simple_async_result_set_op_res_gssize (simple, nwritten); 
408   g_simple_async_result_complete_in_idle (simple);
409   g_object_unref (simple);
410 }
411
412 static gssize
413 g_memory_output_stream_write_finish (GOutputStream  *stream,
414                                      GAsyncResult   *result,
415                                      GError        **error)
416 {
417   GSimpleAsyncResult *simple;
418   gssize nwritten;
419
420   simple = G_SIMPLE_ASYNC_RESULT (result);
421   
422   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == 
423                   g_memory_output_stream_write_async);
424
425   nwritten = g_simple_async_result_get_op_res_gssize (simple);
426
427   return nwritten;
428 }
429
430 static void
431 g_memory_output_stream_close_async (GOutputStream       *stream,
432                                     int                  io_priority,
433                                     GCancellable        *cancellable,
434                                     GAsyncReadyCallback  callback,
435                                     gpointer             data)
436 {
437   GSimpleAsyncResult *simple;
438
439   simple = g_simple_async_result_new (G_OBJECT (stream),
440                                       callback,
441                                       data,
442                                       g_memory_output_stream_close_async);
443
444
445   /* will always return TRUE */
446   g_memory_output_stream_close (stream, cancellable, NULL);
447   
448   g_simple_async_result_complete_in_idle (simple);
449   g_object_unref (simple);
450 }
451
452 static gboolean
453 g_memory_output_stream_close_finish (GOutputStream  *stream,
454                                      GAsyncResult   *result,
455                                      GError        **error)
456 {
457   GSimpleAsyncResult *simple;
458
459   simple = G_SIMPLE_ASYNC_RESULT (result);
460
461   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == 
462                   g_memory_output_stream_close_async);
463
464   return TRUE;
465 }
466
467 static goffset
468 g_memory_output_stream_tell (GSeekable *seekable)
469 {
470   GMemoryOutputStream *stream;
471   GMemoryOutputStreamPrivate *priv;
472
473   stream = G_MEMORY_OUTPUT_STREAM (seekable);
474   priv = stream->priv;
475
476   return priv->pos;
477 }
478
479 static gboolean
480 g_memory_output_stream_can_seek (GSeekable *seekable)
481 {
482   return TRUE;
483 }
484
485 static gboolean
486 g_memory_output_stream_seek (GSeekable    *seekable,
487                             goffset        offset,
488                             GSeekType      type,
489                             GCancellable  *cancellable,
490                             GError       **error)
491 {
492   GMemoryOutputStream        *stream;
493   GMemoryOutputStreamPrivate *priv;
494   goffset absolute;
495
496   stream = G_MEMORY_OUTPUT_STREAM (seekable);
497   priv = stream->priv;
498
499   switch (type) 
500     {
501     case G_SEEK_CUR:
502       absolute = priv->pos + offset;
503       break;
504
505     case G_SEEK_SET:
506       absolute = offset;
507       break;
508
509     case G_SEEK_END:
510       absolute = priv->len + offset;
511       break;
512   
513     default:
514       g_set_error (error,
515                    G_IO_ERROR,
516                    G_IO_ERROR_INVALID_ARGUMENT,
517                    _("Invalid GSeekType supplied"));
518
519       return FALSE;
520     }
521
522   if (absolute < 0) 
523     {
524       g_set_error (error,
525                    G_IO_ERROR,
526                    G_IO_ERROR_INVALID_ARGUMENT,
527                    _("Invalid seek request"));
528       return FALSE;
529     }
530
531   if (!array_check_boundary (stream, absolute, error)) 
532     return FALSE;  
533
534   priv->pos = absolute;
535
536   return TRUE;
537 }
538
539 static gboolean
540 g_memory_output_stream_can_truncate (GSeekable *seekable)
541 {
542   GMemoryOutputStream *ostream;
543   GMemoryOutputStreamPrivate *priv;
544
545   ostream = G_MEMORY_OUTPUT_STREAM (seekable);
546   priv = ostream->priv;
547
548   return priv->realloc_fn != NULL;
549 }
550
551 static gboolean
552 g_memory_output_stream_truncate (GSeekable     *seekable,
553                                  goffset        offset,
554                                  GCancellable  *cancellable,
555                                  GError       **error)
556 {
557   GMemoryOutputStream *ostream;
558   GMemoryOutputStreamPrivate *priv;
559
560   ostream = G_MEMORY_OUTPUT_STREAM (seekable);
561   priv = ostream->priv;
562  
563   if (!array_resize (ostream, offset, FALSE, error))
564     return FALSE;
565
566   return TRUE;
567 }
568
569 #define __G_MEMORY_OUTPUT_STREAM_C__
570 #include "gioaliasdef.c"