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 "gfilterinputstream.h" 25 #include "ginputstream.h" 26 #include "gsimpleasyncresult.h" 27 #include "glibintl.h" 28 29 #include "gioalias.h" 30 31 /** 32 * SECTION:gfilterinputstream 33 * @short_description: Filter Input Stream 34 * @include: gio/gio.h 35 * 36 **/ 37 38 enum { 39 PROP_0, 40 PROP_BASE_STREAM, 41 PROP_CLOSE_BASE 42 }; 43 44 static void g_filter_input_stream_set_property (GObject *object, 45 guint prop_id, 46 const GValue *value, 47 GParamSpec *pspec); 48 49 static void g_filter_input_stream_get_property (GObject *object, 50 guint prop_id, 51 GValue *value, 52 GParamSpec *pspec); 53 static void g_filter_input_stream_finalize (GObject *object); 54 55 56 static gssize g_filter_input_stream_read (GInputStream *stream, 57 void *buffer, 58 gsize count, 59 GCancellable *cancellable, 60 GError **error); 61 static gssize g_filter_input_stream_skip (GInputStream *stream, 62 gsize count, 63 GCancellable *cancellable, 64 GError **error); 65 static gboolean g_filter_input_stream_close (GInputStream *stream, 66 GCancellable *cancellable, 67 GError **error); 68 static void g_filter_input_stream_read_async (GInputStream *stream, 69 void *buffer, 70 gsize count, 71 int io_priority, 72 GCancellable *cancellable, 73 GAsyncReadyCallback callback, 74 gpointer user_data); 75 static gssize g_filter_input_stream_read_finish (GInputStream *stream, 76 GAsyncResult *result, 77 GError **error); 78 static void g_filter_input_stream_skip_async (GInputStream *stream, 79 gsize count, 80 int io_priority, 81 GCancellable *cancellabl, 82 GAsyncReadyCallback callback, 83 gpointer datae); 84 static gssize g_filter_input_stream_skip_finish (GInputStream *stream, 85 GAsyncResult *result, 86 GError **error); 87 static void g_filter_input_stream_close_async (GInputStream *stream, 88 int io_priority, 89 GCancellable *cancellabl, 90 GAsyncReadyCallback callback, 91 gpointer data); 92 static gboolean g_filter_input_stream_close_finish (GInputStream *stream, 93 GAsyncResult *result, 94 GError **error); 95 96 G_DEFINE_TYPE (GFilterInputStream, g_filter_input_stream, G_TYPE_INPUT_STREAM) 97 98 #define GET_PRIVATE(inst) G_TYPE_INSTANCE_GET_PRIVATE (inst, \ 99 G_TYPE_FILTER_INPUT_STREAM, GFilterInputStreamPrivate) 100 101 typedef struct 102 { 103 gboolean close_base; 104 } GFilterInputStreamPrivate; 105 106 static void 107 g_filter_input_stream_class_init (GFilterInputStreamClass *klass) 108 { 109 GObjectClass *object_class; 110 GInputStreamClass *istream_class; 111 112 object_class = G_OBJECT_CLASS (klass); 113 object_class->get_property = g_filter_input_stream_get_property; 114 object_class->set_property = g_filter_input_stream_set_property; 115 object_class->finalize = g_filter_input_stream_finalize; 116 117 istream_class = G_INPUT_STREAM_CLASS (klass); 118 istream_class->read_fn = g_filter_input_stream_read; 119 istream_class->skip = g_filter_input_stream_skip; 120 istream_class->close_fn = g_filter_input_stream_close; 121 122 istream_class->read_async = g_filter_input_stream_read_async; 123 istream_class->read_finish = g_filter_input_stream_read_finish; 124 istream_class->skip_async = g_filter_input_stream_skip_async; 125 istream_class->skip_finish = g_filter_input_stream_skip_finish; 126 istream_class->close_async = g_filter_input_stream_close_async; 127 istream_class->close_finish = g_filter_input_stream_close_finish; 128 129 g_type_class_add_private (klass, sizeof (GFilterInputStreamPrivate)); 130 131 g_object_class_install_property (object_class, 132 PROP_BASE_STREAM, 133 g_param_spec_object ("base-stream", 134 P_("The Filter Base Stream"), 135 P_("The underlying base stream on which the io ops will be done."), 136 G_TYPE_INPUT_STREAM, 137 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | 138 G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); 139 140 g_object_class_install_property (object_class, 141 PROP_CLOSE_BASE, 142 g_param_spec_boolean ("close-base-stream", 143 P_("Close Base Stream"), 144 P_("If the base stream should be closed when the filter stream is closed."), 145 TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | 146 G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); 147 } 148 149 static void 150 g_filter_input_stream_set_property (GObject *object, 151 guint prop_id, 152 const GValue *value, 153 GParamSpec *pspec) 154 { 155 GFilterInputStream *filter_stream; 156 GObject *obj; 157 158 filter_stream = G_FILTER_INPUT_STREAM (object); 159 160 switch (prop_id) 161 { 162 case PROP_BASE_STREAM: 163 obj = g_value_dup_object (value); 164 filter_stream->base_stream = G_INPUT_STREAM (obj); 165 break; 166 167 case PROP_CLOSE_BASE: 168 g_filter_input_stream_set_close_base_stream (filter_stream, 169 g_value_get_boolean (value)); 170 break; 171 172 default: 173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 174 break; 175 } 176 177 } 178 179 static void 180 g_filter_input_stream_get_property (GObject *object, 181 guint prop_id, 182 GValue *value, 183 GParamSpec *pspec) 184 { 185 GFilterInputStream *filter_stream; 186 187 filter_stream = G_FILTER_INPUT_STREAM (object); 188 189 switch (prop_id) 190 { 191 case PROP_BASE_STREAM: 192 g_value_set_object (value, filter_stream->base_stream); 193 break; 194 195 case PROP_CLOSE_BASE: 196 g_value_set_boolean (value, GET_PRIVATE (filter_stream)->close_base); 197 break; 198 199 default: 200 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 201 break; 202 } 203 204 } 205 206 static void 207 g_filter_input_stream_finalize (GObject *object) 208 { 209 GFilterInputStream *stream; 210 211 stream = G_FILTER_INPUT_STREAM (object); 212 213 g_object_unref (stream->base_stream); 214 215 G_OBJECT_CLASS (g_filter_input_stream_parent_class)->finalize (object); 216 } 217 218 static void 219 g_filter_input_stream_init (GFilterInputStream *stream) 220 { 221 222 } 223 224 /** 225 * g_filter_input_stream_get_base_stream: 226 * @stream: a #GFilterInputStream. 227 * 228 * Gets the base stream for the filter stream. 229 * 230 * Returns: a #GInputStream. 231 **/ 232 GInputStream * 233 g_filter_input_stream_get_base_stream (GFilterInputStream *stream) 234 { 235 g_return_val_if_fail (G_IS_FILTER_INPUT_STREAM (stream), NULL); 236 237 return stream->base_stream; 238 } 239 240 /** 241 * g_filter_input_stream_get_close_base_stream: 242 * @stream: a #GFilterInputStream. 243 * 244 * Returns whether the base stream will be closed when @stream is 245 * closed. 246 * 247 * Return value: %TRUE if the base stream will be closed. 248 **/ 249 gboolean 250 g_filter_input_stream_get_close_base_stream (GFilterInputStream *stream) 251 { 252 g_return_val_if_fail (G_IS_FILTER_INPUT_STREAM (stream), FALSE); 253 254 return GET_PRIVATE (stream)->close_base; 255 } 256 257 /** 258 * g_filter_input_stream_set_close_base_stream: 259 * @stream: a #GFilterInputStream. 260 * @close_base: %TRUE to close the base stream. 261 * 262 * Sets whether the base stream will be closed when @stream is closed. 263 **/ 264 void 265 g_filter_input_stream_set_close_base_stream (GFilterInputStream *stream, 266 gboolean close_base) 267 { 268 GFilterInputStreamPrivate *priv; 269 270 g_return_if_fail (G_IS_FILTER_INPUT_STREAM (stream)); 271 272 close_base = !!close_base; 273 274 priv = GET_PRIVATE (stream); 275 276 if (priv->close_base != close_base) 277 { 278 priv->close_base = close_base; 279 g_object_notify (G_OBJECT (stream), "close-base-stream"); 280 } 281 } 282 283 static gssize 284 g_filter_input_stream_read (GInputStream *stream, 285 void *buffer, 286 gsize count, 287 GCancellable *cancellable, 288 GError **error) 289 { 290 GFilterInputStream *filter_stream; 291 GInputStream *base_stream; 292 gssize nread; 293 294 filter_stream = G_FILTER_INPUT_STREAM (stream); 295 base_stream = filter_stream->base_stream; 296 297 nread = g_input_stream_read (base_stream, 298 buffer, 299 count, 300 cancellable, 301 error); 302 303 return nread; 304 } 305 306 static gssize 307 g_filter_input_stream_skip (GInputStream *stream, 308 gsize count, 309 GCancellable *cancellable, 310 GError **error) 311 { 312 GFilterInputStream *filter_stream; 313 GInputStream *base_stream; 314 gssize nskipped; 315 316 filter_stream = G_FILTER_INPUT_STREAM (stream); 317 base_stream = filter_stream->base_stream; 318 319 nskipped = g_input_stream_skip (base_stream, 320 count, 321 cancellable, 322 error); 323 return nskipped; 324 } 325 326 static gboolean 327 g_filter_input_stream_close (GInputStream *stream, 328 GCancellable *cancellable, 329 GError **error) 330 { 331 gboolean res = TRUE; 332 333 if (GET_PRIVATE (stream)->close_base) 334 { 335 GFilterInputStream *filter_stream; 336 GInputStream *base_stream; 337 338 filter_stream = G_FILTER_INPUT_STREAM (stream); 339 base_stream = filter_stream->base_stream; 340 341 res = g_input_stream_close (base_stream, 342 cancellable, 343 error); 344 } 345 346 return res; 347 } 348 349 static void 350 g_filter_input_stream_read_async (GInputStream *stream, 351 void *buffer, 352 gsize count, 353 int io_priority, 354 GCancellable *cancellable, 355 GAsyncReadyCallback callback, 356 gpointer user_data) 357 { 358 GFilterInputStream *filter_stream; 359 GInputStream *base_stream; 360 361 filter_stream = G_FILTER_INPUT_STREAM (stream); 362 base_stream = filter_stream->base_stream; 363 364 g_input_stream_read_async (base_stream, 365 buffer, 366 count, 367 io_priority, 368 cancellable, 369 callback, 370 user_data); 371 } 372 373 static gssize 374 g_filter_input_stream_read_finish (GInputStream *stream, 375 GAsyncResult *result, 376 GError **error) 377 { 378 GFilterInputStream *filter_stream; 379 GInputStream *base_stream; 380 gssize nread; 381 382 filter_stream = G_FILTER_INPUT_STREAM (stream); 383 base_stream = filter_stream->base_stream; 384 385 nread = g_input_stream_read_finish (base_stream, 386 result, 387 error); 388 389 return nread; 390 } 391 392 static void 393 g_filter_input_stream_skip_async (GInputStream *stream, 394 gsize count, 395 int io_priority, 396 GCancellable *cancellable, 397 GAsyncReadyCallback callback, 398 gpointer user_data) 399 { 400 GFilterInputStream *filter_stream; 401 GInputStream *base_stream; 402 403 filter_stream = G_FILTER_INPUT_STREAM (stream); 404 base_stream = filter_stream->base_stream; 405 406 g_input_stream_skip_async (base_stream, 407 count, 408 io_priority, 409 cancellable, 410 callback, 411 user_data); 412 413 } 414 415 static gssize 416 g_filter_input_stream_skip_finish (GInputStream *stream, 417 GAsyncResult *result, 418 GError **error) 419 { 420 GFilterInputStream *filter_stream; 421 GInputStream *base_stream; 422 gssize nskipped; 423 424 filter_stream = G_FILTER_INPUT_STREAM (stream); 425 base_stream = filter_stream->base_stream; 426 427 nskipped = g_input_stream_skip_finish (base_stream, 428 result, 429 error); 430 431 return nskipped; 432 } 433 434 static void 435 g_filter_input_stream_close_ready (GObject *object, 436 GAsyncResult *result, 437 gpointer user_data) 438 { 439 GSimpleAsyncResult *simple = user_data; 440 GError *error = NULL; 441 442 g_input_stream_close_finish (G_INPUT_STREAM (object), result, &error); 443 444 if (error) 445 { 446 g_simple_async_result_set_from_error (simple, error); 447 g_error_free (error); 448 } 449 450 g_simple_async_result_complete (simple); 451 g_object_unref (simple); 452 } 453 454 static void 455 g_filter_input_stream_close_async (GInputStream *stream, 456 int io_priority, 457 GCancellable *cancellable, 458 GAsyncReadyCallback callback, 459 gpointer user_data) 460 { 461 GSimpleAsyncResult *simple; 462 463 simple = g_simple_async_result_new (G_OBJECT (stream), 464 callback, user_data, 465 g_filter_input_stream_close_async); 466 467 if (GET_PRIVATE (stream)->close_base) 468 { 469 GFilterInputStream *filter_stream = G_FILTER_INPUT_STREAM (stream); 470 471 g_input_stream_close_async (filter_stream->base_stream, 472 io_priority, cancellable, 473 g_filter_input_stream_close_ready, 474 g_object_ref (simple)); 475 } 476 else 477 /* do nothing */ 478 g_simple_async_result_complete_in_idle (simple); 479 480 g_object_unref (simple); 481 } 482 483 static gboolean 484 g_filter_input_stream_close_finish (GInputStream *stream, 485 GAsyncResult *result, 486 GError **error) 487 { 488 GSimpleAsyncResult *simple; 489 490 g_return_val_if_fail (g_simple_async_result_is_valid ( 491 result, G_OBJECT (stream), g_filter_input_stream_close_async), FALSE); 492 493 simple = G_SIMPLE_ASYNC_RESULT (result); 494 495 return !g_simple_async_result_propagate_error (simple, error); 496 } 497 498 #define __G_FILTER_INPUT_STREAM_C__ 499 #include "gioaliasdef.c" 500