Branch data Line data Source code
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 : 53242 : 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 : 15 : g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass)
129 : : {
130 : : GOutputStreamClass *ostream_class;
131 : : GObjectClass *gobject_class;
132 : :
133 : 15 : gobject_class = G_OBJECT_CLASS (klass);
134 : 15 : gobject_class->set_property = g_memory_output_stream_set_property;
135 : 15 : gobject_class->get_property = g_memory_output_stream_get_property;
136 : 15 : gobject_class->finalize = g_memory_output_stream_finalize;
137 : :
138 : 15 : ostream_class = G_OUTPUT_STREAM_CLASS (klass);
139 : :
140 : 15 : ostream_class->write_fn = g_memory_output_stream_write;
141 : 15 : ostream_class->close_fn = g_memory_output_stream_close;
142 : 15 : ostream_class->close_async = g_memory_output_stream_close_async;
143 : 15 : 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 : 15 : 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 : 15 : 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 : 15 : 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 : 15 : 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 : 15 : 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 : 15 : }
212 : :
213 : : static void
214 : 15 : g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
215 : : {
216 : 15 : iface->is_writable = g_memory_output_stream_is_writable;
217 : 15 : iface->create_source = g_memory_output_stream_create_source;
218 : 15 : }
219 : :
220 : : static void
221 : 4644 : 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 : 4644 : stream = G_MEMORY_OUTPUT_STREAM (object);
230 : 4644 : priv = stream->priv;
231 : :
232 : 4644 : switch (prop_id)
233 : : {
234 : 1161 : case PROP_DATA:
235 : 1161 : priv->data = g_value_get_pointer (value);
236 : 1161 : break;
237 : 1161 : case PROP_SIZE:
238 : 1161 : priv->len = g_value_get_ulong (value);
239 : 1161 : break;
240 : 1161 : case PROP_REALLOC_FUNCTION:
241 : 1161 : priv->realloc_fn = g_value_get_pointer (value);
242 : 1161 : break;
243 : 1161 : case PROP_DESTROY_FUNCTION:
244 : 1161 : priv->destroy = g_value_get_pointer (value);
245 : 1161 : break;
246 : 0 : default:
247 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248 : 0 : break;
249 : : }
250 : 4644 : }
251 : :
252 : : static void
253 : 10 : 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 : 10 : stream = G_MEMORY_OUTPUT_STREAM (object);
262 : 10 : priv = stream->priv;
263 : :
264 : 10 : switch (prop_id)
265 : : {
266 : 2 : case PROP_DATA:
267 : 2 : g_value_set_pointer (value, priv->data);
268 : 2 : break;
269 : 2 : case PROP_SIZE:
270 : 2 : g_value_set_ulong (value, priv->len);
271 : 2 : break;
272 : 2 : case PROP_DATA_SIZE:
273 : 2 : g_value_set_ulong (value, priv->valid_len);
274 : 2 : break;
275 : 2 : case PROP_REALLOC_FUNCTION:
276 : 2 : g_value_set_pointer (value, priv->realloc_fn);
277 : 2 : break;
278 : 2 : case PROP_DESTROY_FUNCTION:
279 : 2 : g_value_set_pointer (value, priv->destroy);
280 : 2 : break;
281 : 0 : default:
282 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
283 : 0 : break;
284 : : }
285 : 10 : }
286 : :
287 : : static void
288 : 1151 : g_memory_output_stream_finalize (GObject *object)
289 : : {
290 : : GMemoryOutputStream *stream;
291 : : GMemoryOutputStreamPrivate *priv;
292 : :
293 : 1151 : stream = G_MEMORY_OUTPUT_STREAM (object);
294 : 1151 : priv = stream->priv;
295 : :
296 : 1151 : if (priv->destroy)
297 : 1123 : priv->destroy (priv->data);
298 : :
299 : 1151 : G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize (object);
300 : 1151 : }
301 : :
302 : : static void
303 : 15 : g_memory_output_stream_seekable_iface_init (GSeekableIface *iface)
304 : : {
305 : 15 : iface->tell = g_memory_output_stream_tell;
306 : 15 : iface->can_seek = g_memory_output_stream_can_seek;
307 : 15 : iface->seek = g_memory_output_stream_seek;
308 : 15 : iface->can_truncate = g_memory_output_stream_can_truncate;
309 : 15 : iface->truncate_fn = g_memory_output_stream_truncate;
310 : 15 : }
311 : :
312 : :
313 : : static void
314 : 1161 : g_memory_output_stream_init (GMemoryOutputStream *stream)
315 : : {
316 : 1161 : stream->priv = g_memory_output_stream_get_instance_private (stream);
317 : 1161 : stream->priv->pos = 0;
318 : 1161 : stream->priv->valid_len = 0;
319 : 1161 : }
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 : 1155 : g_memory_output_stream_new (gpointer data,
376 : : gsize size,
377 : : GReallocFunc realloc_function,
378 : : GDestroyNotify destroy_function)
379 : : {
380 : : GOutputStream *stream;
381 : :
382 : 1155 : 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 : 1155 : 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 : 52 : g_memory_output_stream_new_resizable (void)
402 : : {
403 : 52 : 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 : 69 : g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
420 : : {
421 : 69 : g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
422 : :
423 : 69 : 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 : 1036 : g_memory_output_stream_get_size (GMemoryOutputStream *ostream)
450 : : {
451 : 1036 : g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
452 : :
453 : 1036 : 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 : 1088 : g_memory_output_stream_get_data_size (GMemoryOutputStream *ostream)
469 : : {
470 : 1088 : g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
471 : :
472 : 1088 : 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 : 31 : g_memory_output_stream_steal_data (GMemoryOutputStream *ostream)
493 : : {
494 : : gpointer data;
495 : :
496 : 31 : g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
497 : 31 : g_return_val_if_fail (g_output_stream_is_closed (G_OUTPUT_STREAM (ostream)), NULL);
498 : :
499 : 31 : data = ostream->priv->data;
500 : 31 : ostream->priv->data = NULL;
501 : :
502 : 31 : 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 : 15 : g_memory_output_stream_steal_as_bytes (GMemoryOutputStream *ostream)
518 : : {
519 : : GBytes *result;
520 : :
521 : 15 : g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
522 : 15 : g_return_val_if_fail (g_output_stream_is_closed (G_OUTPUT_STREAM (ostream)), NULL);
523 : :
524 : 15 : result = g_bytes_new_with_free_func (ostream->priv->data,
525 : 15 : ostream->priv->valid_len,
526 : 15 : ostream->priv->destroy,
527 : 15 : ostream->priv->data);
528 : 15 : ostream->priv->data = NULL;
529 : :
530 : 15 : return result;
531 : : }
532 : :
533 : : static gboolean
534 : 282 : 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 : 282 : priv = ostream->priv;
544 : :
545 : 282 : if (priv->len == size)
546 : 0 : return TRUE;
547 : :
548 : 282 : if (!priv->realloc_fn)
549 : : {
550 : 3 : if (allow_partial &&
551 : 3 : priv->pos < priv->len)
552 : 1 : return TRUE; /* Short write */
553 : :
554 : 2 : g_set_error_literal (error,
555 : : G_IO_ERROR,
556 : : G_IO_ERROR_NO_SPACE,
557 : : _("Memory output stream not resizable"));
558 : 2 : return FALSE;
559 : : }
560 : :
561 : 279 : len = priv->len;
562 : 279 : data = priv->realloc_fn (priv->data, size);
563 : :
564 : 279 : if (size > 0 && !data)
565 : : {
566 : 0 : if (allow_partial &&
567 : 0 : priv->pos < priv->len)
568 : 0 : return TRUE; /* Short write */
569 : :
570 : 0 : g_set_error_literal (error,
571 : : G_IO_ERROR,
572 : : G_IO_ERROR_NO_SPACE,
573 : : _("Failed to resize memory output stream"));
574 : 0 : return FALSE;
575 : : }
576 : :
577 : 279 : if (size > len)
578 : 274 : memset ((guint8 *)data + len, 0, size - len);
579 : :
580 : 279 : priv->data = data;
581 : 279 : priv->len = size;
582 : :
583 : 279 : if (priv->len < priv->valid_len)
584 : 3 : priv->valid_len = priv->len;
585 : :
586 : 279 : return TRUE;
587 : : }
588 : :
589 : : static gssize
590 : 25283 : 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 : 25283 : ostream = G_MEMORY_OUTPUT_STREAM (stream);
602 : 25283 : priv = ostream->priv;
603 : :
604 : 25283 : if (count == 0)
605 : 0 : 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 : 25283 : if (priv->realloc_fn && priv->pos + count < priv->pos)
610 : 0 : goto overflow;
611 : :
612 : 25283 : 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 : 274 : 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 : 274 : if (new_size == 0)
627 : 0 : goto overflow;
628 : :
629 : 274 : new_size = MAX (new_size, MIN_ARRAY_SIZE);
630 : 274 : if (!array_resize (ostream, new_size, TRUE, error))
631 : 2 : return -1;
632 : : }
633 : :
634 : : /* Make sure we handle short writes if the array_resize
635 : : only added part of the required memory */
636 : 25281 : count = MIN (count, priv->len - priv->pos);
637 : :
638 : 25281 : dest = (guint8 *)priv->data + priv->pos;
639 : 25281 : memcpy (dest, buffer, count);
640 : 25281 : priv->pos += count;
641 : :
642 : 25281 : if (priv->pos > priv->valid_len)
643 : 25275 : priv->valid_len = priv->pos;
644 : :
645 : 25281 : return count;
646 : :
647 : 0 : overflow:
648 : : /* Overflow: buffer size would need to be bigger than G_MAXSIZE. */
649 : 0 : 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 : 0 : return -1;
655 : : }
656 : :
657 : : static gboolean
658 : 1151 : g_memory_output_stream_close (GOutputStream *stream,
659 : : GCancellable *cancellable,
660 : : GError **error)
661 : : {
662 : 1151 : return TRUE;
663 : : }
664 : :
665 : : static void
666 : 8 : 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 : 8 : task = g_task_new (stream, cancellable, callback, data);
675 : 8 : g_task_set_source_tag (task, g_memory_output_stream_close_async);
676 : :
677 : : /* will always return TRUE */
678 : 8 : g_memory_output_stream_close (stream, cancellable, NULL);
679 : :
680 : 8 : g_task_return_boolean (task, TRUE);
681 : 8 : g_object_unref (task);
682 : 8 : }
683 : :
684 : : static gboolean
685 : 8 : g_memory_output_stream_close_finish (GOutputStream *stream,
686 : : GAsyncResult *result,
687 : : GError **error)
688 : : {
689 : 8 : g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
690 : :
691 : 8 : return g_task_propagate_boolean (G_TASK (result), error);
692 : : }
693 : :
694 : : static goffset
695 : 8226 : g_memory_output_stream_tell (GSeekable *seekable)
696 : : {
697 : : GMemoryOutputStream *stream;
698 : : GMemoryOutputStreamPrivate *priv;
699 : :
700 : 8226 : stream = G_MEMORY_OUTPUT_STREAM (seekable);
701 : 8226 : priv = stream->priv;
702 : :
703 : 8226 : return priv->pos;
704 : : }
705 : :
706 : : static gboolean
707 : 1026 : g_memory_output_stream_can_seek (GSeekable *seekable)
708 : : {
709 : 1026 : return TRUE;
710 : : }
711 : :
712 : : static gboolean
713 : 7185 : 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 : 7185 : stream = G_MEMORY_OUTPUT_STREAM (seekable);
724 : 7185 : priv = stream->priv;
725 : :
726 : 7185 : switch (type)
727 : : {
728 : 3080 : case G_SEEK_CUR:
729 : 3080 : absolute = priv->pos + offset;
730 : 3080 : break;
731 : :
732 : 1028 : case G_SEEK_SET:
733 : 1028 : absolute = offset;
734 : 1028 : break;
735 : :
736 : 3077 : 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 : 3077 : if (priv->realloc_fn)
742 : 3072 : absolute = priv->valid_len + offset;
743 : : else
744 : 5 : absolute = priv->len + offset;
745 : 3077 : break;
746 : :
747 : 0 : default:
748 : 0 : g_set_error_literal (error,
749 : : G_IO_ERROR,
750 : : G_IO_ERROR_INVALID_ARGUMENT,
751 : : _("Invalid GSeekType supplied"));
752 : :
753 : 0 : return FALSE;
754 : : }
755 : :
756 : 7185 : if (absolute < 0)
757 : : {
758 : 1024 : 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 : 1024 : 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 : 6161 : if (priv->realloc_fn == NULL && (gsize) absolute > priv->len)
772 : : {
773 : 3 : 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 : 3 : return FALSE;
778 : : }
779 : :
780 : 6158 : priv->pos = absolute;
781 : :
782 : 6158 : return TRUE;
783 : : }
784 : :
785 : : static gboolean
786 : 4 : g_memory_output_stream_can_truncate (GSeekable *seekable)
787 : : {
788 : : GMemoryOutputStream *ostream;
789 : : GMemoryOutputStreamPrivate *priv;
790 : :
791 : 4 : ostream = G_MEMORY_OUTPUT_STREAM (seekable);
792 : 4 : priv = ostream->priv;
793 : :
794 : : /* We do not allow truncation of fixed-sized streams */
795 : 4 : return priv->realloc_fn != NULL;
796 : : }
797 : :
798 : : static gboolean
799 : 8 : g_memory_output_stream_truncate (GSeekable *seekable,
800 : : goffset offset,
801 : : GCancellable *cancellable,
802 : : GError **error)
803 : : {
804 : 8 : GMemoryOutputStream *ostream = G_MEMORY_OUTPUT_STREAM (seekable);
805 : :
806 : 8 : if (!array_resize (ostream, offset, FALSE, error))
807 : 0 : return FALSE;
808 : :
809 : 8 : ostream->priv->valid_len = offset;
810 : :
811 : 8 : return TRUE;
812 : : }
813 : :
814 : : static gboolean
815 : 47 : g_memory_output_stream_is_writable (GPollableOutputStream *stream)
816 : : {
817 : 47 : return TRUE;
818 : : }
819 : :
820 : : static GSource *
821 : 0 : g_memory_output_stream_create_source (GPollableOutputStream *stream,
822 : : GCancellable *cancellable)
823 : : {
824 : : GSource *base_source, *pollable_source;
825 : :
826 : 0 : base_source = g_timeout_source_new (0);
827 : 0 : pollable_source = g_pollable_source_new_full (stream, base_source, cancellable);
828 : 0 : g_source_unref (base_source);
829 : :
830 : 0 : return pollable_source;
831 : : }
|