1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 *
20 * Authors:
21 * Christian Kellner <gicmo@gnome.org>
22 * Krzysztof KosiĆski <tweenk.pl@gmail.com>
23 */
24
25 #include "config.h"
26 #include "gmemoryoutputstream.h"
27 #include "goutputstream.h"
28 #include "gpollableoutputstream.h"
29 #include "gseekable.h"
30 #include "gtask.h"
31 #include "gioerror.h"
32 #include "string.h"
33 #include "glibintl.h"
34 #include "gutilsprivate.h"
35
36
37 /**
38 * GMemoryOutputStream:
39 *
40 * `GMemoryOutputStream` is a class for using arbitrary
41 * memory chunks as output for GIO streaming output operations.
42 *
43 * As of GLib 2.34, `GMemoryOutputStream` trivially implements
44 * [iface@Gio.PollableOutputStream]: it always polls as ready.
45 */
46
47 #define MIN_ARRAY_SIZE 16
48
49 enum {
50 PROP_0,
51 PROP_DATA,
52 PROP_SIZE,
53 PROP_DATA_SIZE,
54 PROP_REALLOC_FUNCTION,
55 PROP_DESTROY_FUNCTION
56 };
57
58 struct _GMemoryOutputStreamPrivate
59 {
60 gpointer data; /* Write buffer */
61 gsize len; /* Current length of the data buffer. Can change with resizing. */
62 gsize valid_len; /* The part of data that has been written to */
63 gsize pos; /* Current position in the stream. Distinct from valid_len,
64 because the stream is seekable. */
65
66 GReallocFunc realloc_fn;
67 GDestroyNotify destroy;
68 };
69
70 static void g_memory_output_stream_set_property (GObject *object,
71 guint prop_id,
72 const GValue *value,
73 GParamSpec *pspec);
74 static void g_memory_output_stream_get_property (GObject *object,
75 guint prop_id,
76 GValue *value,
77 GParamSpec *pspec);
78 static void g_memory_output_stream_finalize (GObject *object);
79
80 static gssize g_memory_output_stream_write (GOutputStream *stream,
81 const void *buffer,
82 gsize count,
83 GCancellable *cancellable,
84 GError **error);
85
86 static gboolean g_memory_output_stream_close (GOutputStream *stream,
87 GCancellable *cancellable,
88 GError **error);
89
90 static void g_memory_output_stream_close_async (GOutputStream *stream,
91 int io_priority,
92 GCancellable *cancellable,
93 GAsyncReadyCallback callback,
94 gpointer data);
95 static gboolean g_memory_output_stream_close_finish (GOutputStream *stream,
96 GAsyncResult *result,
97 GError **error);
98
99 static void g_memory_output_stream_seekable_iface_init (GSeekableIface *iface);
100 static goffset g_memory_output_stream_tell (GSeekable *seekable);
101 static gboolean g_memory_output_stream_can_seek (GSeekable *seekable);
102 static gboolean g_memory_output_stream_seek (GSeekable *seekable,
103 goffset offset,
104 GSeekType type,
105 GCancellable *cancellable,
106 GError **error);
107 static gboolean g_memory_output_stream_can_truncate (GSeekable *seekable);
108 static gboolean g_memory_output_stream_truncate (GSeekable *seekable,
109 goffset offset,
110 GCancellable *cancellable,
111 GError **error);
112
113 static gboolean g_memory_output_stream_is_writable (GPollableOutputStream *stream);
114 static GSource *g_memory_output_stream_create_source (GPollableOutputStream *stream,
115 GCancellable *cancellable);
116
117 static void g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);
118
119 G_DEFINE_TYPE_WITH_CODE (GMemoryOutputStream, g_memory_output_stream, G_TYPE_OUTPUT_STREAM,
120 G_ADD_PRIVATE (GMemoryOutputStream)
121 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
122 g_memory_output_stream_seekable_iface_init);
123 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
124 g_memory_output_stream_pollable_iface_init))
125
126
127 static void
128 g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass)
129 {
130 GOutputStreamClass *ostream_class;
131 GObjectClass *gobject_class;
132
133 gobject_class = G_OBJECT_CLASS (klass);
134 gobject_class->set_property = g_memory_output_stream_set_property;
135 gobject_class->get_property = g_memory_output_stream_get_property;
136 gobject_class->finalize = g_memory_output_stream_finalize;
137
138 ostream_class = G_OUTPUT_STREAM_CLASS (klass);
139
140 ostream_class->write_fn = g_memory_output_stream_write;
141 ostream_class->close_fn = g_memory_output_stream_close;
142 ostream_class->close_async = g_memory_output_stream_close_async;
143 ostream_class->close_finish = g_memory_output_stream_close_finish;
144
145 /**
146 * GMemoryOutputStream:data:
147 *
148 * Pointer to buffer where data will be written.
149 *
150 * Since: 2.24
151 **/
152 g_object_class_install_property (gobject_class,
153 PROP_DATA,
154 g_param_spec_pointer ("data", NULL, NULL,
155 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
156 G_PARAM_STATIC_STRINGS));
157
158 /**
159 * GMemoryOutputStream:size:
160 *
161 * Current size of the data buffer.
162 *
163 * Since: 2.24
164 **/
165 g_object_class_install_property (gobject_class,
166 PROP_SIZE,
167 g_param_spec_ulong ("size", NULL, NULL,
168 0, G_MAXULONG, 0,
169 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
170 G_PARAM_STATIC_STRINGS));
171
172 /**
173 * GMemoryOutputStream:data-size:
174 *
175 * Size of data written to the buffer.
176 *
177 * Since: 2.24
178 **/
179 g_object_class_install_property (gobject_class,
180 PROP_DATA_SIZE,
181 g_param_spec_ulong ("data-size", NULL, NULL,
182 0, G_MAXULONG, 0,
183 G_PARAM_READABLE |
184 G_PARAM_STATIC_STRINGS));
185
186 /**
187 * GMemoryOutputStream:realloc-function: (skip)
188 *
189 * Function with realloc semantics called to enlarge the buffer.
190 *
191 * Since: 2.24
192 **/
193 g_object_class_install_property (gobject_class,
194 PROP_REALLOC_FUNCTION,
195 g_param_spec_pointer ("realloc-function", NULL, NULL,
196 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
197 G_PARAM_STATIC_STRINGS));
198
199 /**
200 * GMemoryOutputStream:destroy-function: (skip)
201 *
202 * Function called with the buffer as argument when the stream is destroyed.
203 *
204 * Since: 2.24
205 **/
206 g_object_class_install_property (gobject_class,
207 PROP_DESTROY_FUNCTION,
208 g_param_spec_pointer ("destroy-function", NULL, NULL,
209 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
210 G_PARAM_STATIC_STRINGS));
211 }
212
213 static void
214 g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
215 {
216 iface->is_writable = g_memory_output_stream_is_writable;
217 iface->create_source = g_memory_output_stream_create_source;
218 }
219
220 static void
221 g_memory_output_stream_set_property (GObject *object,
222 guint prop_id,
223 const GValue *value,
224 GParamSpec *pspec)
225 {
226 GMemoryOutputStream *stream;
227 GMemoryOutputStreamPrivate *priv;
228
229 stream = G_MEMORY_OUTPUT_STREAM (object);
230 priv = stream->priv;
231
232 switch (prop_id)
233 {
234 case PROP_DATA:
235 priv->data = g_value_get_pointer (value);
236 break;
237 case PROP_SIZE:
238 priv->len = g_value_get_ulong (value);
239 break;
240 case PROP_REALLOC_FUNCTION:
241 priv->realloc_fn = g_value_get_pointer (value);
242 break;
243 case PROP_DESTROY_FUNCTION:
244 priv->destroy = g_value_get_pointer (value);
245 break;
246 default:
247 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248 break;
249 }
250 }
251
252 static void
253 g_memory_output_stream_get_property (GObject *object,
254 guint prop_id,
255 GValue *value,
256 GParamSpec *pspec)
257 {
258 GMemoryOutputStream *stream;
259 GMemoryOutputStreamPrivate *priv;
260
261 stream = G_MEMORY_OUTPUT_STREAM (object);
262 priv = stream->priv;
263
264 switch (prop_id)
265 {
266 case PROP_DATA:
267 g_value_set_pointer (value, priv->data);
268 break;
269 case PROP_SIZE:
270 g_value_set_ulong (value, priv->len);
271 break;
272 case PROP_DATA_SIZE:
273 g_value_set_ulong (value, priv->valid_len);
274 break;
275 case PROP_REALLOC_FUNCTION:
276 g_value_set_pointer (value, priv->realloc_fn);
277 break;
278 case PROP_DESTROY_FUNCTION:
279 g_value_set_pointer (value, priv->destroy);
280 break;
281 default:
282 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
283 break;
284 }
285 }
286
287 static void
288 g_memory_output_stream_finalize (GObject *object)
289 {
290 GMemoryOutputStream *stream;
291 GMemoryOutputStreamPrivate *priv;
292
293 stream = G_MEMORY_OUTPUT_STREAM (object);
294 priv = stream->priv;
295
296 if (priv->destroy)
297 priv->destroy (priv->data);
298
299 G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize (object);
300 }
301
302 static void
303 g_memory_output_stream_seekable_iface_init (GSeekableIface *iface)
304 {
305 iface->tell = g_memory_output_stream_tell;
306 iface->can_seek = g_memory_output_stream_can_seek;
307 iface->seek = g_memory_output_stream_seek;
308 iface->can_truncate = g_memory_output_stream_can_truncate;
309 iface->truncate_fn = g_memory_output_stream_truncate;
310 }
311
312
313 static void
314 g_memory_output_stream_init (GMemoryOutputStream *stream)
315 {
316 stream->priv = g_memory_output_stream_get_instance_private (stream);
317 stream->priv->pos = 0;
318 stream->priv->valid_len = 0;
319 }
320
321 /**
322 * g_memory_output_stream_new: (skip)
323 * @data: (nullable): pointer to a chunk of memory to use, or %NULL
324 * @size: the size of @data
325 * @realloc_function: (nullable): a function with realloc() semantics (like g_realloc())
326 * to be called when @data needs to be grown, or %NULL
327 * @destroy_function: (nullable): a function to be called on @data when the stream is
328 * finalized, or %NULL
329 *
330 * Creates a new #GMemoryOutputStream.
331 *
332 * In most cases this is not the function you want. See
333 * g_memory_output_stream_new_resizable() instead.
334 *
335 * If @data is non-%NULL, the stream will use that for its internal storage.
336 *
337 * If @realloc_fn is non-%NULL, it will be used for resizing the internal
338 * storage when necessary and the stream will be considered resizable.
339 * In that case, the stream will start out being (conceptually) empty.
340 * @size is used only as a hint for how big @data is. Specifically,
341 * seeking to the end of a newly-created stream will seek to zero, not
342 * @size. Seeking past the end of the stream and then writing will
343 * introduce a zero-filled gap.
344 *
345 * If @realloc_fn is %NULL then the stream is fixed-sized. Seeking to
346 * the end will seek to @size exactly. Writing past the end will give
347 * an 'out of space' error. Attempting to seek past the end will fail.
348 * Unlike the resizable case, seeking to an offset within the stream and
349 * writing will preserve the bytes passed in as @data before that point
350 * and will return them as part of g_memory_output_stream_steal_data().
351 * If you intend to seek you should probably therefore ensure that @data
352 * is properly initialised.
353 *
354 * It is probably only meaningful to provide @data and @size in the case
355 * that you want a fixed-sized stream. Put another way: if @realloc_fn
356 * is non-%NULL then it makes most sense to give @data as %NULL and
357 * @size as 0 (allowing #GMemoryOutputStream to do the initial
358 * allocation for itself).
359 *
360 * |[<!-- language="C" -->
361 * // a stream that can grow
362 * stream = g_memory_output_stream_new (NULL, 0, realloc, free);
363 *
364 * // another stream that can grow
365 * stream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
366 *
367 * // a fixed-size stream
368 * data = malloc (200);
369 * stream3 = g_memory_output_stream_new (data, 200, NULL, free);
370 * ]|
371 *
372 * Returns: A newly created #GMemoryOutputStream object.
373 **/
374 GOutputStream *
375 g_memory_output_stream_new (gpointer data,
376 gsize size,
377 GReallocFunc realloc_function,
378 GDestroyNotify destroy_function)
379 {
380 GOutputStream *stream;
381
382 stream = g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM,
383 "data", data,
384 "size", size,
385 "realloc-function", realloc_function,
386 "destroy-function", destroy_function,
387 NULL);
388
389 return stream;
390 }
391
392 /**
393 * g_memory_output_stream_new_resizable:
394 *
395 * Creates a new #GMemoryOutputStream, using g_realloc() and g_free()
396 * for memory allocation.
397 *
398 * Since: 2.36
399 */
400 GOutputStream *
401 g_memory_output_stream_new_resizable (void)
402 {
403 return g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
404 }
405
406 /**
407 * g_memory_output_stream_get_data:
408 * @ostream: a #GMemoryOutputStream
409 *
410 * Gets any loaded data from the @ostream.
411 *
412 * Note that the returned pointer may become invalid on the next
413 * write or truncate operation on the stream.
414 *
415 * Returns: (transfer none): pointer to the stream's data, or %NULL if the data
416 * has been stolen
417 **/
418 gpointer
419 g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
420 {
421 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
422
423 return ostream->priv->data;
424 }
425
426 /**
427 * g_memory_output_stream_get_size:
428 * @ostream: a #GMemoryOutputStream
429 *
430 * Gets the size of the currently allocated data area (available from
431 * g_memory_output_stream_get_data()).
432 *
433 * You probably don't want to use this function on resizable streams.
434 * See g_memory_output_stream_get_data_size() instead. For resizable
435 * streams the size returned by this function is an implementation
436 * detail and may be change at any time in response to operations on the
437 * stream.
438 *
439 * If the stream is fixed-sized (ie: no realloc was passed to
440 * g_memory_output_stream_new()) then this is the maximum size of the
441 * stream and further writes will return %G_IO_ERROR_NO_SPACE.
442 *
443 * In any case, if you want the number of bytes currently written to the
444 * stream, use g_memory_output_stream_get_data_size().
445 *
446 * Returns: the number of bytes allocated for the data buffer
447 */
448 gsize
449 g_memory_output_stream_get_size (GMemoryOutputStream *ostream)
450 {
451 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
452
453 return ostream->priv->len;
454 }
455
456 /**
457 * g_memory_output_stream_get_data_size:
458 * @ostream: a #GMemoryOutputStream
459 *
460 * Returns the number of bytes from the start up to including the last
461 * byte written in the stream that has not been truncated away.
462 *
463 * Returns: the number of bytes written to the stream
464 *
465 * Since: 2.18
466 */
467 gsize
468 g_memory_output_stream_get_data_size (GMemoryOutputStream *ostream)
469 {
470 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
471
472 return ostream->priv->valid_len;
473 }
474
475 /**
476 * g_memory_output_stream_steal_data:
477 * @ostream: a #GMemoryOutputStream
478 *
479 * Gets any loaded data from the @ostream. Ownership of the data
480 * is transferred to the caller; when no longer needed it must be
481 * freed using the free function set in @ostream's
482 * #GMemoryOutputStream:destroy-function property.
483 *
484 * @ostream must be closed before calling this function.
485 *
486 * Returns: (transfer full): the stream's data, or %NULL if it has previously
487 * been stolen
488 *
489 * Since: 2.26
490 **/
491 gpointer
492 g_memory_output_stream_steal_data (GMemoryOutputStream *ostream)
493 {
494 gpointer data;
495
496 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
497 g_return_val_if_fail (g_output_stream_is_closed (G_OUTPUT_STREAM (ostream)), NULL);
498
499 data = ostream->priv->data;
500 ostream->priv->data = NULL;
501
502 return data;
503 }
504
505 /**
506 * g_memory_output_stream_steal_as_bytes:
507 * @ostream: a #GMemoryOutputStream
508 *
509 * Returns data from the @ostream as a #GBytes. @ostream must be
510 * closed before calling this function.
511 *
512 * Returns: (transfer full): the stream's data
513 *
514 * Since: 2.34
515 **/
516 GBytes *
517 g_memory_output_stream_steal_as_bytes (GMemoryOutputStream *ostream)
518 {
519 GBytes *result;
520
521 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
522 g_return_val_if_fail (g_output_stream_is_closed (G_OUTPUT_STREAM (ostream)), NULL);
523
524 result = g_bytes_new_with_free_func (ostream->priv->data,
525 ostream->priv->valid_len,
526 ostream->priv->destroy,
527 ostream->priv->data);
528 ostream->priv->data = NULL;
529
530 return result;
531 }
532
533 static gboolean
534 array_resize (GMemoryOutputStream *ostream,
535 gsize size,
536 gboolean allow_partial,
537 GError **error)
538 {
539 GMemoryOutputStreamPrivate *priv;
540 gpointer data;
541 gsize len;
542
543 priv = ostream->priv;
544
545 if (priv->len == size)
546 return TRUE;
547
548 if (!priv->realloc_fn)
549 {
550 if (allow_partial &&
551 priv->pos < priv->len)
552 return TRUE; /* Short write */
553
554 g_set_error_literal (error,
555 G_IO_ERROR,
556 G_IO_ERROR_NO_SPACE,
557 _("Memory output stream not resizable"));
558 return FALSE;
559 }
560
561 len = priv->len;
562 data = priv->realloc_fn (priv->data, size);
563
564 if (size > 0 && !data)
565 {
566 if (allow_partial &&
567 priv->pos < priv->len)
568 return TRUE; /* Short write */
569
570 g_set_error_literal (error,
571 G_IO_ERROR,
572 G_IO_ERROR_NO_SPACE,
573 _("Failed to resize memory output stream"));
574 return FALSE;
575 }
576
577 if (size > len)
578 memset ((guint8 *)data + len, 0, size - len);
579
580 priv->data = data;
581 priv->len = size;
582
583 if (priv->len < priv->valid_len)
584 priv->valid_len = priv->len;
585
586 return TRUE;
587 }
588
589 static gssize
590 g_memory_output_stream_write (GOutputStream *stream,
591 const void *buffer,
592 gsize count,
593 GCancellable *cancellable,
594 GError **error)
595 {
596 GMemoryOutputStream *ostream;
597 GMemoryOutputStreamPrivate *priv;
598 guint8 *dest;
599 gsize new_size;
600
601 ostream = G_MEMORY_OUTPUT_STREAM (stream);
602 priv = ostream->priv;
603
604 if (count == 0)
605 return 0;
606
607 /* Check for address space overflow, but only if the buffer is resizable.
608 Otherwise we just do a short write and don't worry. */
609 if (priv->realloc_fn && priv->pos + count < priv->pos)
610 goto overflow;
611
612 if (priv->pos + count > priv->len)
613 {
614 /* At least enough to fit the write, rounded up for greater than
615 * linear growth.
616 *
617 * Assuming that we're using something like realloc(), the kernel
618 * will overcommit memory to us, so doubling the size each time
619 * will keep the number of realloc calls low without wasting too
620 * much memory.
621 */
622 new_size = g_nearest_pow (priv->pos + count);
623 /* Check for overflow again. We have checked if
624 pos + count > G_MAXSIZE, but now check if g_nearest_pow () has
625 overflowed */
626 if (new_size == 0)
627 goto overflow;
628
629 new_size = MAX (new_size, MIN_ARRAY_SIZE);
630 if (!array_resize (ostream, new_size, TRUE, error))
631 return -1;
632 }
633
634 /* Make sure we handle short writes if the array_resize
635 only added part of the required memory */
636 count = MIN (count, priv->len - priv->pos);
637
638 dest = (guint8 *)priv->data + priv->pos;
639 memcpy (dest, buffer, count);
640 priv->pos += count;
641
642 if (priv->pos > priv->valid_len)
643 priv->valid_len = priv->pos;
644
645 return count;
646
647 overflow:
648 /* Overflow: buffer size would need to be bigger than G_MAXSIZE. */
649 g_set_error_literal (error,
650 G_IO_ERROR,
651 G_IO_ERROR_NO_SPACE,
652 _("Amount of memory required to process the write is "
653 "larger than available address space"));
654 return -1;
655 }
656
657 static gboolean
658 g_memory_output_stream_close (GOutputStream *stream,
659 GCancellable *cancellable,
660 GError **error)
661 {
662 return TRUE;
663 }
664
665 static void
666 g_memory_output_stream_close_async (GOutputStream *stream,
667 int io_priority,
668 GCancellable *cancellable,
669 GAsyncReadyCallback callback,
670 gpointer data)
671 {
672 GTask *task;
673
674 task = g_task_new (stream, cancellable, callback, data);
675 g_task_set_source_tag (task, g_memory_output_stream_close_async);
676
677 /* will always return TRUE */
678 g_memory_output_stream_close (stream, cancellable, NULL);
679
680 g_task_return_boolean (task, TRUE);
681 g_object_unref (task);
682 }
683
684 static gboolean
685 g_memory_output_stream_close_finish (GOutputStream *stream,
686 GAsyncResult *result,
687 GError **error)
688 {
689 g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
690
691 return g_task_propagate_boolean (G_TASK (result), error);
692 }
693
694 static goffset
695 g_memory_output_stream_tell (GSeekable *seekable)
696 {
697 GMemoryOutputStream *stream;
698 GMemoryOutputStreamPrivate *priv;
699
700 stream = G_MEMORY_OUTPUT_STREAM (seekable);
701 priv = stream->priv;
702
703 return priv->pos;
704 }
705
706 static gboolean
707 g_memory_output_stream_can_seek (GSeekable *seekable)
708 {
709 return TRUE;
710 }
711
712 static gboolean
713 g_memory_output_stream_seek (GSeekable *seekable,
714 goffset offset,
715 GSeekType type,
716 GCancellable *cancellable,
717 GError **error)
718 {
719 GMemoryOutputStream *stream;
720 GMemoryOutputStreamPrivate *priv;
721 goffset absolute;
722
723 stream = G_MEMORY_OUTPUT_STREAM (seekable);
724 priv = stream->priv;
725
726 switch (type)
727 {
728 case G_SEEK_CUR:
729 absolute = priv->pos + offset;
730 break;
731
732 case G_SEEK_SET:
733 absolute = offset;
734 break;
735
736 case G_SEEK_END:
737 /* For resizable streams, we consider the end to be the data
738 * length. For fixed-sized streams, we consider the end to be the
739 * size of the buffer.
740 */
741 if (priv->realloc_fn)
742 absolute = priv->valid_len + offset;
743 else
744 absolute = priv->len + offset;
745 break;
746
747 default:
748 g_set_error_literal (error,
749 G_IO_ERROR,
750 G_IO_ERROR_INVALID_ARGUMENT,
751 _("Invalid GSeekType supplied"));
752
753 return FALSE;
754 }
755
756 if (absolute < 0)
757 {
758 g_set_error_literal (error,
759 G_IO_ERROR,
760 G_IO_ERROR_INVALID_ARGUMENT,
761 _("Requested seek before the beginning of the stream"));
762 return FALSE;
763 }
764
765 /* Can't seek past the end of a fixed-size stream.
766 *
767 * Note: seeking to the non-existent byte at the end of a fixed-sized
768 * stream is valid (eg: a 1-byte fixed sized stream can have position
769 * 0 or 1). Therefore '>' is what we want.
770 * */
771 if (priv->realloc_fn == NULL && (gsize) absolute > priv->len)
772 {
773 g_set_error_literal (error,
774 G_IO_ERROR,
775 G_IO_ERROR_INVALID_ARGUMENT,
776 _("Requested seek beyond the end of the stream"));
777 return FALSE;
778 }
779
780 priv->pos = absolute;
781
782 return TRUE;
783 }
784
785 static gboolean
786 g_memory_output_stream_can_truncate (GSeekable *seekable)
787 {
788 GMemoryOutputStream *ostream;
789 GMemoryOutputStreamPrivate *priv;
790
791 ostream = G_MEMORY_OUTPUT_STREAM (seekable);
792 priv = ostream->priv;
793
794 /* We do not allow truncation of fixed-sized streams */
795 return priv->realloc_fn != NULL;
796 }
797
798 static gboolean
799 g_memory_output_stream_truncate (GSeekable *seekable,
800 goffset offset,
801 GCancellable *cancellable,
802 GError **error)
803 {
804 GMemoryOutputStream *ostream = G_MEMORY_OUTPUT_STREAM (seekable);
805
806 if (!array_resize (ostream, offset, FALSE, error))
807 return FALSE;
808
809 ostream->priv->valid_len = offset;
810
811 return TRUE;
812 }
813
814 static gboolean
815 g_memory_output_stream_is_writable (GPollableOutputStream *stream)
816 {
817 return TRUE;
818 }
819
820 static GSource *
821 g_memory_output_stream_create_source (GPollableOutputStream *stream,
822 GCancellable *cancellable)
823 {
824 GSource *base_source, *pollable_source;
825
826 base_source = g_timeout_source_new (0);
827 pollable_source = g_pollable_source_new_full (stream, base_source, cancellable);
828 g_source_unref (base_source);
829
830 return pollable_source;
831 }