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 "gmemoryinputstream.h" 25 #include "ginputstream.h" 26 #include "gseekable.h" 27 #include "string.h" 28 #include "gsimpleasyncresult.h" 29 #include "gioerror.h" 30 #include "glibintl.h" 31 32 #include "gioalias.h" 33 34 /** 35 * SECTION:gmemoryinputstream 36 * @short_description: Streaming input operations on memory chunks 37 * @include: gio/gio.h 38 * @see_also: #GMemoryOutputStream 39 * 40 * #GMemoryInputStream is a class for using arbitrary 41 * memory chunks as input for GIO streaming input operations. 42 * 43 */ 44 45 typedef struct _Chunk Chunk; 46 47 struct _Chunk { 48 guint8 *data; 49 gsize len; 50 GDestroyNotify destroy; 51 }; 52 53 struct _GMemoryInputStreamPrivate { 54 GSList *chunks; 55 gsize len; 56 gsize pos; 57 }; 58 59 static gssize g_memory_input_stream_read (GInputStream *stream, 60 void *buffer, 61 gsize count, 62 GCancellable *cancellable, 63 GError **error); 64 static gssize g_memory_input_stream_skip (GInputStream *stream, 65 gsize count, 66 GCancellable *cancellable, 67 GError **error); 68 static gboolean g_memory_input_stream_close (GInputStream *stream, 69 GCancellable *cancellable, 70 GError **error); 71 static void g_memory_input_stream_read_async (GInputStream *stream, 72 void *buffer, 73 gsize count, 74 int io_priority, 75 GCancellable *cancellable, 76 GAsyncReadyCallback callback, 77 gpointer user_data); 78 static gssize g_memory_input_stream_read_finish (GInputStream *stream, 79 GAsyncResult *result, 80 GError **error); 81 static void g_memory_input_stream_skip_async (GInputStream *stream, 82 gsize count, 83 int io_priority, 84 GCancellable *cancellabl, 85 GAsyncReadyCallback callback, 86 gpointer datae); 87 static gssize g_memory_input_stream_skip_finish (GInputStream *stream, 88 GAsyncResult *result, 89 GError **error); 90 static void g_memory_input_stream_close_async (GInputStream *stream, 91 int io_priority, 92 GCancellable *cancellabl, 93 GAsyncReadyCallback callback, 94 gpointer data); 95 static gboolean g_memory_input_stream_close_finish (GInputStream *stream, 96 GAsyncResult *result, 97 GError **error); 98 99 static void g_memory_input_stream_seekable_iface_init (GSeekableIface *iface); 100 static goffset g_memory_input_stream_tell (GSeekable *seekable); 101 static gboolean g_memory_input_stream_can_seek (GSeekable *seekable); 102 static gboolean g_memory_input_stream_seek (GSeekable *seekable, 103 goffset offset, 104 GSeekType type, 105 GCancellable *cancellable, 106 GError **error); 107 static gboolean g_memory_input_stream_can_truncate (GSeekable *seekable); 108 static gboolean g_memory_input_stream_truncate (GSeekable *seekable, 109 goffset offset, 110 GCancellable *cancellable, 111 GError **error); 112 static void g_memory_input_stream_finalize (GObject *object); 113 114 G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream, g_memory_input_stream, G_TYPE_INPUT_STREAM, 115 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE, 116 g_memory_input_stream_seekable_iface_init)) 117 118 119 static void 120 g_memory_input_stream_class_init (GMemoryInputStreamClass *klass) 121 { 122 GObjectClass *object_class; 123 GInputStreamClass *istream_class; 124 125 g_type_class_add_private (klass, sizeof (GMemoryInputStreamPrivate)); 126 127 object_class = G_OBJECT_CLASS (klass); 128 object_class->finalize = g_memory_input_stream_finalize; 129 130 istream_class = G_INPUT_STREAM_CLASS (klass); 131 istream_class->read_fn = g_memory_input_stream_read; 132 istream_class->skip = g_memory_input_stream_skip; 133 istream_class->close_fn = g_memory_input_stream_close; 134 135 istream_class->read_async = g_memory_input_stream_read_async; 136 istream_class->read_finish = g_memory_input_stream_read_finish; 137 istream_class->skip_async = g_memory_input_stream_skip_async; 138 istream_class->skip_finish = g_memory_input_stream_skip_finish; 139 istream_class->close_async = g_memory_input_stream_close_async; 140 istream_class->close_finish = g_memory_input_stream_close_finish; 141 } 142 143 static void 144 free_chunk (gpointer data, 145 gpointer user_data) 146 { 147 Chunk *chunk = data; 148 149 if (chunk->destroy) 150 chunk->destroy (chunk->data); 151 152 g_slice_free (Chunk, chunk); 153 } 154 155 static void 156 g_memory_input_stream_finalize (GObject *object) 157 { 158 GMemoryInputStream *stream; 159 GMemoryInputStreamPrivate *priv; 160 161 stream = G_MEMORY_INPUT_STREAM (object); 162 priv = stream->priv; 163 164 g_slist_foreach (priv->chunks, free_chunk, NULL); 165 g_slist_free (priv->chunks); 166 167 G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object); 168 } 169 170 static void 171 g_memory_input_stream_seekable_iface_init (GSeekableIface *iface) 172 { 173 iface->tell = g_memory_input_stream_tell; 174 iface->can_seek = g_memory_input_stream_can_seek; 175 iface->seek = g_memory_input_stream_seek; 176 iface->can_truncate = g_memory_input_stream_can_truncate; 177 iface->truncate_fn = g_memory_input_stream_truncate; 178 } 179 180 static void 181 g_memory_input_stream_init (GMemoryInputStream *stream) 182 { 183 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, 184 G_TYPE_MEMORY_INPUT_STREAM, 185 GMemoryInputStreamPrivate); 186 } 187 188 /** 189 * g_memory_input_stream_new: 190 * 191 * Creates a new empty #GMemoryInputStream. 192 * 193 * Returns: a new #GInputStream 194 */ 195 GInputStream * 196 g_memory_input_stream_new (void) 197 { 198 GInputStream *stream; 199 200 stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL); 201 202 return stream; 203 } 204 205 /** 206 * g_memory_input_stream_new_from_data: 207 * @data: input data 208 * @len: length of the data, may be -1 if @data is a nul-terminated string 209 * @destroy: function that is called to free @data, or %NULL 210 * 211 * Creates a new #GMemoryInputStream with data in memory of a given size. 212 * 213 * Returns: new #GInputStream read from @data of @len bytes. 214 **/ 215 GInputStream * 216 g_memory_input_stream_new_from_data (const void *data, 217 gssize len, 218 GDestroyNotify destroy) 219 { 220 GInputStream *stream; 221 222 stream = g_memory_input_stream_new (); 223 224 g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream), 225 data, len, destroy); 226 227 return stream; 228 } 229 230 /** 231 * g_memory_input_stream_add_data: 232 * @stream: a #GMemoryInputStream 233 * @data: input data 234 * @len: length of the data, may be -1 if @data is a nul-terminated string 235 * @destroy: function that is called to free @data, or %NULL 236 * 237 * Appends @data to data that can be read from the input stream 238 */ 239 void 240 g_memory_input_stream_add_data (GMemoryInputStream *stream, 241 const void *data, 242 gssize len, 243 GDestroyNotify destroy) 244 { 245 GMemoryInputStreamPrivate *priv; 246 Chunk *chunk; 247 248 g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream)); 249 g_return_if_fail (data != NULL); 250 251 priv = stream->priv; 252 253 if (len == -1) 254 len = strlen (data); 255 256 chunk = g_slice_new (Chunk); 257 chunk->data = (guint8 *)data; 258 chunk->len = len; 259 chunk->destroy = destroy; 260 261 priv->chunks = g_slist_append (priv->chunks, chunk); 262 priv->len += chunk->len; 263 } 264 265 static gssize 266 g_memory_input_stream_read (GInputStream *stream, 267 void *buffer, 268 gsize count, 269 GCancellable *cancellable, 270 GError **error) 271 { 272 GMemoryInputStream *memory_stream; 273 GMemoryInputStreamPrivate *priv; 274 GSList *l; 275 Chunk *chunk; 276 gsize offset, start, rest, size; 277 278 memory_stream = G_MEMORY_INPUT_STREAM (stream); 279 priv = memory_stream->priv; 280 281 count = MIN (count, priv->len - priv->pos); 282 283 offset = 0; 284 for (l = priv->chunks; l; l = l->next) 285 { 286 chunk = (Chunk *)l->data; 287 288 if (offset + chunk->len > priv->pos) 289 break; 290 291 offset += chunk->len; 292 } 293 294 start = priv->pos - offset; 295 rest = count; 296 297 for (; l && rest > 0; l = l->next) 298 { 299 chunk = (Chunk *)l->data; 300 size = MIN (rest, chunk->len - start); 301 302 memcpy ((guint8 *)buffer + (count - rest), chunk->data + start, size); 303 rest -= size; 304 305 start = 0; 306 } 307 308 priv->pos += count; 309 310 return count; 311 } 312 313 static gssize 314 g_memory_input_stream_skip (GInputStream *stream, 315 gsize count, 316 GCancellable *cancellable, 317 GError **error) 318 { 319 GMemoryInputStream *memory_stream; 320 GMemoryInputStreamPrivate *priv; 321 322 memory_stream = G_MEMORY_INPUT_STREAM (stream); 323 priv = memory_stream->priv; 324 325 count = MIN (count, priv->len - priv->pos); 326 priv->pos += count; 327 328 return count; 329 } 330 331 static gboolean 332 g_memory_input_stream_close (GInputStream *stream, 333 GCancellable *cancellable, 334 GError **error) 335 { 336 return TRUE; 337 } 338 339 static void 340 g_memory_input_stream_read_async (GInputStream *stream, 341 void *buffer, 342 gsize count, 343 int io_priority, 344 GCancellable *cancellable, 345 GAsyncReadyCallback callback, 346 gpointer user_data) 347 { 348 GSimpleAsyncResult *simple; 349 gssize nread; 350 351 nread = g_memory_input_stream_read (stream, buffer, count, cancellable, NULL); 352 simple = g_simple_async_result_new (G_OBJECT (stream), 353 callback, 354 user_data, 355 g_memory_input_stream_read_async); 356 g_simple_async_result_set_op_res_gssize (simple, nread); 357 g_simple_async_result_complete_in_idle (simple); 358 g_object_unref (simple); 359 } 360 361 static gssize 362 g_memory_input_stream_read_finish (GInputStream *stream, 363 GAsyncResult *result, 364 GError **error) 365 { 366 GSimpleAsyncResult *simple; 367 gssize nread; 368 369 simple = G_SIMPLE_ASYNC_RESULT (result); 370 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_read_async); 371 372 nread = g_simple_async_result_get_op_res_gssize (simple); 373 return nread; 374 } 375 376 static void 377 g_memory_input_stream_skip_async (GInputStream *stream, 378 gsize count, 379 int io_priority, 380 GCancellable *cancellable, 381 GAsyncReadyCallback callback, 382 gpointer user_data) 383 { 384 GSimpleAsyncResult *simple; 385 gssize nskipped; 386 387 nskipped = g_memory_input_stream_skip (stream, count, cancellable, NULL); 388 simple = g_simple_async_result_new (G_OBJECT (stream), 389 callback, 390 user_data, 391 g_memory_input_stream_skip_async); 392 g_simple_async_result_set_op_res_gssize (simple, nskipped); 393 g_simple_async_result_complete_in_idle (simple); 394 g_object_unref (simple); 395 } 396 397 static gssize 398 g_memory_input_stream_skip_finish (GInputStream *stream, 399 GAsyncResult *result, 400 GError **error) 401 { 402 GSimpleAsyncResult *simple; 403 gssize nskipped; 404 405 simple = G_SIMPLE_ASYNC_RESULT (result); 406 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_skip_async); 407 408 nskipped = g_simple_async_result_get_op_res_gssize (simple); 409 return nskipped; 410 } 411 412 static void 413 g_memory_input_stream_close_async (GInputStream *stream, 414 int io_priority, 415 GCancellable *cancellable, 416 GAsyncReadyCallback callback, 417 gpointer user_data) 418 { 419 GSimpleAsyncResult *simple; 420 421 simple = g_simple_async_result_new (G_OBJECT (stream), 422 callback, 423 user_data, 424 g_memory_input_stream_close_async); 425 g_simple_async_result_complete_in_idle (simple); 426 g_object_unref (simple); 427 } 428 429 static gboolean 430 g_memory_input_stream_close_finish (GInputStream *stream, 431 GAsyncResult *result, 432 GError **error) 433 { 434 return TRUE; 435 } 436 437 static goffset 438 g_memory_input_stream_tell (GSeekable *seekable) 439 { 440 GMemoryInputStream *memory_stream; 441 GMemoryInputStreamPrivate *priv; 442 443 memory_stream = G_MEMORY_INPUT_STREAM (seekable); 444 priv = memory_stream->priv; 445 446 return priv->pos; 447 } 448 449 static 450 gboolean g_memory_input_stream_can_seek (GSeekable *seekable) 451 { 452 return TRUE; 453 } 454 455 static gboolean 456 g_memory_input_stream_seek (GSeekable *seekable, 457 goffset offset, 458 GSeekType type, 459 GCancellable *cancellable, 460 GError **error) 461 { 462 GMemoryInputStream *memory_stream; 463 GMemoryInputStreamPrivate *priv; 464 goffset absolute; 465 466 memory_stream = G_MEMORY_INPUT_STREAM (seekable); 467 priv = memory_stream->priv; 468 469 switch (type) 470 { 471 case G_SEEK_CUR: 472 absolute = priv->pos + offset; 473 break; 474 475 case G_SEEK_SET: 476 absolute = offset; 477 break; 478 479 case G_SEEK_END: 480 absolute = priv->len + offset; 481 break; 482 483 default: 484 g_set_error_literal (error, 485 G_IO_ERROR, 486 G_IO_ERROR_INVALID_ARGUMENT, 487 _("Invalid GSeekType supplied")); 488 489 return FALSE; 490 } 491 492 if (absolute < 0 || absolute > priv->len) 493 { 494 g_set_error_literal (error, 495 G_IO_ERROR, 496 G_IO_ERROR_INVALID_ARGUMENT, 497 _("Invalid seek request")); 498 return FALSE; 499 } 500 501 priv->pos = absolute; 502 503 return TRUE; 504 } 505 506 static gboolean 507 g_memory_input_stream_can_truncate (GSeekable *seekable) 508 { 509 return FALSE; 510 } 511 512 static gboolean 513 g_memory_input_stream_truncate (GSeekable *seekable, 514 goffset offset, 515 GCancellable *cancellable, 516 GError **error) 517 { 518 g_set_error_literal (error, 519 G_IO_ERROR, 520 G_IO_ERROR_NOT_SUPPORTED, 521 _("Cannot truncate GMemoryInputStream")); 522 return FALSE; 523 } 524 525 #define __G_MEMORY_INPUT_STREAM_C__ 526 #include "gioaliasdef.c" 527