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